From fbd17c8dafeefac788f4bc1c41045726825f513f Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Mon, 3 Jan 2000 19:19:48 +0000 Subject: simple mods to add msrpc pipe redirection. default behaviour: fall back to using internal msrpc code in smbd. (This used to be commit 8976e26d46cb991710bc77463f7f928ac00dd4d8) --- source3/Makefile.in | 6 +- source3/configure.developer | 2 +- source3/include/client.h | 15 - source3/include/ntdomain.h | 4 + source3/include/proto.h | 118 +++- source3/include/rpc_creds.h | 92 ++++ source3/include/smb.h | 61 +++ source3/lib/doscalls.c | 2 +- source3/lib/msrpc-client.c | 400 ++++++++++++++ source3/lib/msrpc_use.c | 328 +++++++++++ source3/lib/util.c | 15 + source3/lib/util_array.c | 194 +++++++ source3/lib/util_sid.c | 290 +++++++++- source3/lib/util_sock.c | 100 ++++ source3/libsmb/pwd_cache.c | 54 ++ source3/passdb/passdb.c | 257 ++------- source3/rpc_parse/parse_creds.c | 578 ++++++++++++++++++++ source3/rpc_parse/parse_prs.c | 24 + source3/rpc_server/srv_pipe.c | 1037 ++--------------------------------- source3/rpc_server/srv_pipe_hnd.c | 51 +- source3/rpc_server/srv_pipe_srv.c | 1077 +++++++++++++++++++++++++++++++++++++ source3/smbd/ipc.c | 31 +- source3/smbd/pipes.c | 20 +- source3/smbd/server.c | 25 +- 24 files changed, 3542 insertions(+), 1239 deletions(-) create mode 100644 source3/include/rpc_creds.h create mode 100644 source3/lib/msrpc-client.c create mode 100644 source3/lib/msrpc_use.c create mode 100644 source3/lib/util_array.c create mode 100644 source3/rpc_parse/parse_creds.c create mode 100644 source3/rpc_server/srv_pipe_srv.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 00eeeb6797..acf7c02c21 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -96,7 +96,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/signal.o lib/slprintf.o lib/system.o lib/doscalls.o lib/time.o \ lib/ufc.o lib/genrand.o lib/username.o lib/access.o lib/smbrun.o \ lib/bitmap.o lib/crc32.o lib/snprintf.o \ - lib/util_str.o lib/util_sid.o \ + lib/util_array.o lib/util_str.o lib/util_sid.o \ lib/util_unistr.o lib/util_file.o \ lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o lib/fnmatch.o \ tdb/tdb.o @@ -116,7 +116,7 @@ RPC_SERVER_OBJ = rpc_server/srv_lsa.o \ rpc_server/srv_pipe_hnd.o rpc_server/srv_reg.o \ rpc_server/srv_samr.o rpc_server/srv_srvsvc.o \ rpc_server/srv_util.o rpc_server/srv_wkssvc.o \ - rpc_server/srv_pipe.o + rpc_server/srv_pipe_srv.o rpc_server/srv_pipe.o RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_misc.o \ rpc_parse/parse_net.o rpc_parse/parse_prs.o \ @@ -148,6 +148,8 @@ SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/message.o smbd/nttrans.o smbd/pipes.o smbd/predict.o \ smbd/$(QUOTAOBJS) smbd/reply.o smbd/trans2.o smbd/uid.o \ smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o smbd/blocking.o \ + lib/msrpc-client.o lib/msrpc_use.o \ + rpc_parse/parse_creds.o \ smbd/process.o smbd/oplock.o smbd/service.o smbd/error.o PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/printing.o \ diff --git a/source3/configure.developer b/source3/configure.developer index 91fc5021d9..662650e4d4 100755 --- a/source3/configure.developer +++ b/source3/configure.developer @@ -1,3 +1,3 @@ #!/bin/sh -export CFLAGS="-g -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align" +export CFLAGS="-g -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -DDEBUG_PASSWORD" ./configure diff --git a/source3/include/client.h b/source3/include/client.h index 15ba66e3e1..2a780ece26 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -56,21 +56,6 @@ struct print_job_info time_t t; }; -struct pwd_info -{ - BOOL null_pwd; - BOOL cleartext; - BOOL crypted; - - fstring password; - - uchar smb_lm_pwd[16]; - uchar smb_nt_pwd[16]; - - uchar smb_lm_owf[24]; - uchar smb_nt_owf[24]; -}; - struct cli_state { int port; int fd; diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index d066ef3e36..07d06656c0 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -131,6 +131,10 @@ typedef struct pipes_struct /* When replying to an SMBtrans, this is the maximum amount of data that can be sent in the initial reply. */ int max_trans_reply; + + /* remote, server-side rpc redirection */ + struct msrpc_state *m; + } pipes_struct; struct api_struct diff --git a/source3/include/proto.h b/source3/include/proto.h index 92a57c0950..bb1d5477df 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -70,6 +70,7 @@ int dos_mkdir(char *dname,mode_t mode); int dos_rmdir(char *dname); int dos_chdir(char *dname); int dos_utime(char *fname,struct utimbuf *times); +int copy_reg(char *source, const char *dest); int dos_rename(char *from, char *to); int dos_chmod(char *fname,mode_t mode); char *dos_getwd(char *unix_path); @@ -125,6 +126,36 @@ void initialize_multibyte_vectors( int client_codepage); void mdfour(unsigned char *out, unsigned char *in, int n); +/*The following definitions come from lib/msrpc-client.c */ + +BOOL receive_msrpc(int fd, prs_struct *data, unsigned int timeout); +BOOL msrpc_send(int fd, prs_struct *ps); +BOOL msrpc_receive(int fd, prs_struct *ps); +BOOL msrpc_connect(struct msrpc_state *msrpc, const char *pipe_name); +void msrpc_init_creds(struct msrpc_state *msrpc, const struct user_creds *usr); +void msrpc_close_socket(struct msrpc_state *msrpc); +void msrpc_sockopt(struct msrpc_state *msrpc, char *options); +BOOL msrpc_connect_auth(struct msrpc_state *msrpc, + const char* pipename, + const struct user_creds *usr); +struct msrpc_state *msrpc_initialise(struct msrpc_state *msrpc); +void msrpc_shutdown(struct msrpc_state *msrpc); +BOOL msrpc_establish_connection(struct msrpc_state *msrpc, + const char *pipe_name); + +/*The following definitions come from lib/msrpc_use.c */ + +void init_msrpc_use(void); +void free_msrpc_use(void); +struct msrpc_state *msrpc_use_add(const char* pipe_name, + const struct user_creds *usr_creds, + BOOL redir); +BOOL msrpc_use_del(const char* pipe_name, + const struct user_creds *usr_creds, + BOOL force_close, + BOOL *connection_closed); +void msrpc_net_use_enum(uint32 *num_cons, struct use_info ***use); + /*The following definitions come from lib/pidfile.c */ pid_t pidfile_pid(char *name); @@ -234,6 +265,7 @@ void putip(void *dest,void *src); char *dns_to_netbios_name(char *dns_name); int name_mangle( char *In, char *Out, char name_type ); BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf); +int file_rename(char *from, char *to); time_t file_modtime(char *fname); BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st); SMB_OFF_T get_file_size(char *file_name); @@ -310,6 +342,23 @@ void *memdup(void *p, size_t size); char *myhostname(void); char *lock_path(char *name); +/*The following definitions come from lib/util_array.c */ + +void free_void_array(uint32 num_entries, void **entries, + void(free_item)(void*)); +void* add_copy_to_array(uint32 *len, void ***array, const void *item, + void*(item_dup)(const void*), BOOL alloc_anyway); +void* add_item_to_array(uint32 *len, void ***array, void *item); +void free_use_info_array(uint32 num_entries, struct use_info **entries); +struct use_info* add_use_info_to_array(uint32 *len, struct use_info ***array, + const struct use_info *name); +void free_char_array(uint32 num_entries, char **entries); +char* add_chars_to_array(uint32 *len, char ***array, const char *name); +void free_uint32_array(uint32 num_entries, uint32 **entries); +uint32* add_uint32s_to_array(uint32 *len, uint32 ***array, const uint32 *name); +void free_sid_array(uint32 num_entries, DOM_SID **entries); +DOM_SID* add_sid_to_array(uint32 *len, DOM_SID ***array, const DOM_SID *sid); + /*The following definitions come from lib/util_file.c */ BOOL do_file_lock(int fd, int waitsecs, int type); @@ -345,11 +394,14 @@ char *sid_to_string(fstring sidstr_out, DOM_SID *sid); BOOL string_to_sid(DOM_SID *sidout, char *sidstr); BOOL sid_append_rid(DOM_SID *sid, uint32 rid); BOOL sid_split_rid(DOM_SID *sid, uint32 *rid); -void sid_copy(DOM_SID *dst, DOM_SID *src); +void sid_copy(DOM_SID *dst, const DOM_SID *src); DOM_SID *sid_dup(DOM_SID *src); BOOL sid_linearize(char *outbuf, size_t len, DOM_SID *sid); BOOL sid_equal(DOM_SID *sid1, DOM_SID *sid2); size_t sid_size(DOM_SID *sid); +BOOL read_sid(char *sam_name, DOM_SID *sid); +BOOL write_sid(char *sam_name, DOM_SID *sid); +BOOL create_new_sid(DOM_SID *sid); /*The following definitions come from lib/util_sock.c */ @@ -374,6 +426,9 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout); void reset_globals_after_fork(void); char *client_name(int fd); char *client_addr(int fd); +int open_pipe_sock(char *path); +int create_pipe_socket(char *dir, int dir_perms, + char *path, int path_perms); /*The following definitions come from lib/util_str.c */ @@ -645,6 +700,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, void pwd_init(struct pwd_info *pwd); void pwd_obfuscate_key(struct pwd_info *pwd, uint32 int_key, char *str_key); +BOOL pwd_compare(struct pwd_info *pwd1, struct pwd_info *pwd2); void pwd_read(struct pwd_info *pwd, char *passwd_report, BOOL do_encrypt); void pwd_set_nullpwd(struct pwd_info *pwd); void pwd_set_cleartext(struct pwd_info *pwd, char *clr); @@ -684,7 +740,8 @@ char *smb_errstr(char *inbuf); void unexpected_packet(struct packet_struct *p); void clear_unexpected(time_t t); -struct packet_struct *receive_unexpected(enum packet_type packet_type, int id, char *mailslot_name); +struct packet_struct *receive_unexpected(enum packet_type packet_type, int id, + char *mailslot_name); /*The following definitions come from locking/locking.c */ @@ -1355,7 +1412,7 @@ void pdb_set_last_set_time(char *p, int max_len, time_t t); void pdb_sethexpwd(char *p, unsigned char *pwd, uint16 acct_ctrl); BOOL pdb_gethexpwd(char *p, unsigned char *pwd); BOOL pdb_name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid); -BOOL pdb_generate_sam_sid(void); +BOOL pdb_generate_sam_sid(char *domain_name, DOM_SID *sid); uid_t pdb_user_rid_to_uid(uint32 user_rid); gid_t pdb_user_rid_to_gid(uint32 user_rid); uint32 pdb_uid_to_user_rid(uid_t uid); @@ -1581,6 +1638,45 @@ BOOL do_wks_query_info(struct cli_state *cli, char *server_name, uint32 switch_value, WKS_INFO_100 *wks100); +/*The following definitions come from rpc_parse/parse_creds.c */ + +BOOL make_creds_unix(CREDS_UNIX *r_u, const char* user_name, + const char* requested_name, + const char* real_name, + BOOL guest); +BOOL creds_io_unix(char *desc, CREDS_UNIX *r_u, prs_struct *ps, int depth); +void creds_free_unix(CREDS_UNIX *r_u); +BOOL make_creds_unix_sec(CREDS_UNIX_SEC *r_u, + uint32 uid, uint32 gid, uint32 num_grps, gid_t *grps); +BOOL creds_io_unix_sec(char *desc, CREDS_UNIX_SEC *r_u, prs_struct *ps, int depth); +void creds_free_unix_sec(CREDS_UNIX_SEC *r_u); +BOOL make_creds_nt_sec(CREDS_NT_SEC *r_u, + DOM_SID *sid, uint32 num_grps, uint32 *grps); +BOOL creds_io_nt_sec(char *desc, CREDS_NT_SEC *r_u, prs_struct *ps, int depth); +void creds_free_nt_sec(CREDS_NT_SEC *r_u); +BOOL creds_io_pwd_info(char *desc, struct pwd_info *pwd, prs_struct *ps, int depth); +BOOL creds_io_nt(char *desc, CREDS_NT *r_u, prs_struct *ps, int depth); +void creds_free_nt(CREDS_NT *r_u); +BOOL creds_io_hybrid(char *desc, CREDS_HYBRID *r_u, prs_struct *ps, int depth); +void copy_unix_creds(CREDS_UNIX *to, const CREDS_UNIX *from); +void copy_nt_sec_creds(CREDS_NT_SEC *to, const CREDS_NT_SEC *from); +void copy_unix_sec_creds(CREDS_UNIX_SEC *to, const CREDS_UNIX_SEC *from); +void copy_nt_creds(struct ntuser_creds *to, + const struct ntuser_creds *from); +void copy_user_creds(struct user_creds *to, + const struct user_creds *from); +void free_user_creds(struct user_creds *creds); +BOOL creds_io_cmd(char *desc, CREDS_CMD *r_u, prs_struct *ps, int depth); +BOOL create_ntuser_creds( prs_struct *ps, + const char* name, + uint16 version, uint16 command, + const struct ntuser_creds *ntu, + BOOL reuse); +BOOL create_user_creds( prs_struct *ps, + const char* name, + uint16 version, uint16 command, + const struct user_creds *usr); + /*The following definitions come from rpc_parse/parse_lsa.c */ void init_lsa_trans_name(LSA_TRANS_NAME *trn, UNISTR2 *uni_name, @@ -1769,6 +1865,7 @@ BOOL net_io_r_sam_logoff(char *desc, NET_R_SAM_LOGOFF *r_l, prs_struct *ps, int void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name); BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io); +BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout); void prs_mem_free(prs_struct *ps); void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic); char *prs_take_memory(prs_struct *ps, uint32 *psize); @@ -2245,10 +2342,10 @@ BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data); /*The following definitions come from rpc_server/srv_pipe.c */ -BOOL create_next_pdu(pipes_struct *p); -BOOL rpc_command(pipes_struct *p, char *input_data, int data_len); -BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, - prs_struct *rpc_in); +BOOL readwrite_pipe(pipes_struct *p, char *data, int len, + char **rdata, int *rlen); +ssize_t write_pipe(pipes_struct *p, char *data, size_t n); +int read_pipe(pipes_struct *p, char *data, int n); /*The following definitions come from rpc_server/srv_pipe_hnd.c */ @@ -2266,6 +2363,13 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn); pipes_struct *get_rpc_pipe_p(char *buf, int where); pipes_struct *get_rpc_pipe(int pnum); +/*The following definitions come from rpc_server/srv_pipe_srv.c */ + +BOOL create_next_pdu(pipes_struct *p); +BOOL rpc_command(pipes_struct *p, char *input_data, int data_len); +BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, + prs_struct *rpc_in); + /*The following definitions come from rpc_server/srv_reg.c */ BOOL api_reg_rpc(pipes_struct *p, prs_struct *data); diff --git a/source3/include/rpc_creds.h b/source3/include/rpc_creds.h new file mode 100644 index 0000000000..c389c64d1d --- /dev/null +++ b/source3/include/rpc_creds.h @@ -0,0 +1,92 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB parameters and setup + Copyright (C) Andrew Tridgell 1992-1999 + Copyright (C) Luke Kenneth Casson Leighton 1996-1999 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _RPC_CREDS_H /* _RPC_CREDS_H */ +#define _RPC_CREDS_H + +typedef struct ntuser_creds +{ + fstring user_name; + fstring domain; + struct pwd_info pwd; + + uint32 ntlmssp_flags; + +} CREDS_NT; + +typedef struct unixuser_creds +{ + fstring user_name; + fstring requested_name; + fstring real_name; + BOOL guest; + +} CREDS_UNIX; + +typedef struct unixsec_creds +{ + uint32 uid; + uint32 gid; + int num_grps; + uint32 *grps; + +} CREDS_UNIX_SEC; + +typedef struct ntsec_creds +{ + DOM_SID sid; + uint32 num_grps; + uint32 *grp_rids; + +} CREDS_NT_SEC; + +typedef struct user_creds +{ + BOOL reuse; + uint32 ptr_ntc; + uint32 ptr_uxc; + uint32 ptr_nts; + uint32 ptr_uxs; + + CREDS_NT ntc; + CREDS_UNIX uxc; + + CREDS_NT_SEC nts; + CREDS_UNIX_SEC uxs; + + +} CREDS_HYBRID; + +typedef struct cred_command +{ + uint16 version; + uint16 command; + + fstring name; + + uint32 ptr_creds; + CREDS_HYBRID *cred; + +} CREDS_CMD; + +#endif /* _RPC_CREDS_H */ + diff --git a/source3/include/smb.h b/source3/include/smb.h index ec1aaf2273..7b4e80ed4b 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -438,6 +438,14 @@ struct sam_disp_info char *full_name; /* user's full name string */ }; +struct use_info +{ + BOOL connected; + char *srv_name; + char *user_name; + char *domain; +}; + #define MAXSUBAUTHS 15 /* max sub authorities in a SID */ /* DOM_SID - security id */ @@ -1768,6 +1776,59 @@ struct nmb_name { unsigned int name_type; }; +#define AGENT_CMD_CON 0 +#define AGENT_CMD_CON_ANON 2 +#define AGENT_CMD_CON_REUSE 1 + +struct pwd_info +{ + BOOL null_pwd; + BOOL cleartext; + BOOL crypted; + + fstring password; + + uchar smb_lm_pwd[16]; + uchar smb_nt_pwd[16]; + + uchar smb_lm_owf[24]; + uchar smb_nt_owf[128]; + size_t nt_owf_len; + + uchar lm_cli_chal[8]; + uchar nt_cli_chal[128]; + size_t nt_cli_chal_len; + + uchar sess_key[16]; +}; + +#include "rpc_creds.h" + +struct ntdom_info +{ + unsigned char sess_key[16]; /* Current session key. */ + unsigned char ntlmssp_hash[258]; /* ntlmssp data. */ + uint32 ntlmssp_cli_flgs; /* ntlmssp client flags */ + uint32 ntlmssp_srv_flgs; /* ntlmssp server flags */ + uint32 ntlmssp_seq_num; /* ntlmssp sequence number */ + DOM_CRED clnt_cred; /* Client credential. */ + + int max_recv_frag; + int max_xmit_frag; +}; + +struct msrpc_state +{ + fstring pipe_name; + struct user_creds usr; + struct ntdom_info nt; + + int fd; + BOOL redirect; + BOOL initialised; + char *inbuf; + char *outbuf; +}; #include "client.h" #include "rpcclient.h" diff --git a/source3/lib/doscalls.c b/source3/lib/doscalls.c index e6f9d19879..1d459898b5 100644 --- a/source3/lib/doscalls.c +++ b/source3/lib/doscalls.c @@ -158,7 +158,7 @@ int dos_utime(char *fname,struct utimbuf *times) **********************************************************/ -static int copy_reg(char *source, const char *dest) +int copy_reg(char *source, const char *dest) { SMB_STRUCT_STAT source_stats; int ifd; diff --git a/source3/lib/msrpc-client.c b/source3/lib/msrpc-client.c new file mode 100644 index 0000000000..051a051093 --- /dev/null +++ b/source3/lib/msrpc-client.c @@ -0,0 +1,400 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB msrpcent generic functions + Copyright (C) Andrew Tridgell 1994-1999 + Copyright (C) Luke Kenneth Casson Leighton 1996-1999 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define NO_SYSLOG + +#include "includes.h" + +extern int DEBUGLEVEL; + +/**************************************************************************** + read an msrpc pdu from a fd. + The timeout is in milliseconds. +****************************************************************************/ +BOOL receive_msrpc(int fd, prs_struct *data, unsigned int timeout) +{ + BOOL ok; + size_t len; + RPC_HDR hdr; + + prs_init(data, 0, 4, True); + + ok = prs_read(data, fd, 16, timeout); + + if (!ok) + { + prs_mem_free(data); + return False; + } + + if (!smb_io_rpc_hdr("hdr", &hdr, data, 0)) + { + prs_mem_free(data); + return False; + } + + len = hdr.frag_len - 16; + if (len > 0) + { + ok = prs_read(data, fd, hdr.frag_len, 0); + if (!ok) + { + prs_mem_free(data); + return False; + } + data->data_offset = hdr.frag_len; + return True; + } + + prs_mem_free(data); + return False; +} + +/**************************************************************************** + send an smb to a fd and re-establish if necessary +****************************************************************************/ +BOOL msrpc_send(int fd, prs_struct *ps) +{ + size_t len = ps != NULL ? ps->buffer_size : 0; + size_t nwritten=0; + ssize_t ret; + char *outbuf = ps->data_p; + + DEBUG(10,("msrpc_send_prs: data: %p len %d\n", outbuf, len)); + dbgflush(); + + dump_data(10, outbuf, len); + + while (nwritten < len) + { + ret = write_socket(fd,outbuf+nwritten,len - nwritten); + if (ret <= 0) + { + DEBUG(0,("Error writing %d msrpc bytes. %d.\n", + len,ret)); + prs_mem_free(ps); + return False; + } + nwritten += ret; + } + + prs_mem_free(ps); + return True; +} + +/**************************************************************************** + receive msrpc packet +****************************************************************************/ +BOOL msrpc_receive(int fd, prs_struct *ps) +{ + int len; + + DEBUG(10,("msrpc_receive: %d\n", __LINE__)); + + if (!receive_msrpc(fd, ps, 0)) + { + return False; + } + + len = ps->buffer_size; + + if (ps->data_p == NULL || len <= 0) + { + return False; + } + + dump_data(10, ps->data_p, len); + + DEBUG(10,("msrpc_receive: len %d\n", len)); + + return True; +} + +/**************************************************************************** +open the msrpcent sockets +****************************************************************************/ +BOOL msrpc_connect(struct msrpc_state *msrpc, const char *pipe_name) +{ + fstring path; + slprintf(path, sizeof(path)-1, "%s/.msrpc/%s", LOCKDIR, pipe_name); + + fstrcpy(msrpc->pipe_name, pipe_name); + + msrpc->fd = open_pipe_sock(path); + + if (msrpc->fd == -1) + { + return False; + } + + return True; +} + + +/**************************************************************************** +initialise a msrpcent structure +****************************************************************************/ +void msrpc_init_creds(struct msrpc_state *msrpc, const struct user_creds *usr) +{ + copy_user_creds(&msrpc->usr, usr); +} + +/**************************************************************************** +close the socket descriptor +****************************************************************************/ +void msrpc_close_socket(struct msrpc_state *msrpc) +{ + if (msrpc->fd != -1) + { + close(msrpc->fd); + } + msrpc->fd = -1; +} + + +/**************************************************************************** +set socket options on a open connection +****************************************************************************/ +void msrpc_sockopt(struct msrpc_state *msrpc, char *options) +{ + set_socket_options(msrpc->fd, options); +} + + +static BOOL msrpc_authenticate(struct msrpc_state *msrpc, + const struct user_creds *usr) +{ + struct msrpc_state msrpc_redir; + + int sock = msrpc->fd; + char *data; + prs_struct ps; + uint32 len; + char *in = msrpc->inbuf; + char *out = msrpc->outbuf; + uint16 command; + + command = usr != NULL ? AGENT_CMD_CON : AGENT_CMD_CON_ANON; + + if (!create_user_creds(&ps, msrpc->pipe_name, 0x0, command, usr)) + { + DEBUG(0,("could not parse credentials\n")); + close(sock); + return False; + } + + len = ps.data_offset; + data = ps.data_p; + + SIVAL(data, 0, len); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("data len: %d\n", len)); + dump_data(100, data, len); +#endif + + if (write(sock, data, len) <= 0) + { + DEBUG(0,("write failed\n")); + return False; + } + + if (msrpc->redirect) + { + len = read(sock, &msrpc_redir, sizeof(msrpc_redir)); + + if (len != sizeof(msrpc_redir)) + { + DEBUG(0,("read failed\n")); + return False; + } + + memcpy(msrpc, &msrpc_redir, sizeof(msrpc_redir)); + msrpc->inbuf = in; + msrpc->outbuf = out; + msrpc->fd = sock; + msrpc->usr.reuse = False; + } + else + { + uint32 status; + len = read(sock, &status, sizeof(status)); + + return len == sizeof(status) && status == 0x0; + } + return True; +} + +static BOOL msrpc_init_redirect(struct msrpc_state *msrpc, + const char* pipe_name, + const struct user_creds *usr) +{ + int sock; + fstring path; + + slprintf(path, sizeof(path)-1, "/tmp/.msrpc/.%s/agent", pipe_name); + + sock = open_pipe_sock(path); + + if (sock < 0) + { + return False; + } + + msrpc->fd = sock; + + if (!msrpc_authenticate(msrpc, usr)) + { + DEBUG(0,("authenticate failed\n")); + close(msrpc->fd); + msrpc->fd = -1; + return False; + } + + return True; +} + +BOOL msrpc_connect_auth(struct msrpc_state *msrpc, + const char* pipename, + const struct user_creds *usr) +{ + ZERO_STRUCTP(msrpc); + if (!msrpc_initialise(msrpc)) + { + DEBUG(0,("unable to initialise msrpcent connection.\n")); + return False; + } + + msrpc_init_creds(msrpc, usr); + + if (!msrpc_establish_connection(msrpc, pipename)) + { + msrpc_shutdown(msrpc); + return False; + } + + return True; +} + +/**************************************************************************** +initialise a msrpcent structure +****************************************************************************/ +struct msrpc_state *msrpc_initialise(struct msrpc_state *msrpc) +{ + if (!msrpc) { + msrpc = (struct msrpc_state *)malloc(sizeof(*msrpc)); + if (!msrpc) + return NULL; + ZERO_STRUCTP(msrpc); + } + + if (msrpc->initialised) { + msrpc_shutdown(msrpc); + } + + ZERO_STRUCTP(msrpc); + + msrpc->fd = -1; + msrpc->outbuf = (char *)malloc(CLI_BUFFER_SIZE+4); + msrpc->inbuf = (char *)malloc(CLI_BUFFER_SIZE+4); + if (!msrpc->outbuf || !msrpc->inbuf) + { + return False; + } + + msrpc->initialised = 1; + msrpc_init_creds(msrpc, NULL); + + return msrpc; +} + + +/**************************************************************************** +shutdown a msrpcent structure +****************************************************************************/ +void msrpc_shutdown(struct msrpc_state *msrpc) +{ + DEBUG(10,("msrpc_shutdown\n")); + if (msrpc->outbuf) + { + free(msrpc->outbuf); + } + if (msrpc->inbuf) + { + free(msrpc->inbuf); + } + msrpc_close_socket(msrpc); + memset(msrpc, 0, sizeof(*msrpc)); +} + +/**************************************************************************** +establishes a connection right up to doing tconX, reading in a password. +****************************************************************************/ +BOOL msrpc_establish_connection(struct msrpc_state *msrpc, + const char *pipe_name) +{ + DEBUG(5,("msrpc_establish_connection: connecting to %s (%s) - %s\n", + pipe_name, + msrpc->usr.ntc.user_name, msrpc->usr.ntc.domain)); + + /* establish connection */ + + if ((!msrpc->initialised)) + { + return False; + } + + if (msrpc->fd == -1 && msrpc->redirect) + { + if (msrpc_init_redirect(msrpc, pipe_name, &msrpc->usr)) + { + DEBUG(10,("msrpc_establish_connection: redirected OK\n")); + return True; + } + else + { + DEBUG(10,("redirect FAILED\n")); + return False; + } + } + if (msrpc->fd == -1) + { + if (!msrpc_connect(msrpc, pipe_name)) + { + DEBUG(1,("msrpc_establish_connection: failed %s)\n", + pipe_name)); + + return False; + } + } + + if (!msrpc_authenticate(msrpc, &msrpc->usr)) + { + DEBUG(0,("authenticate failed\n")); + close(msrpc->fd); + msrpc->fd = -1; + return False; + } + + return True; +} + diff --git a/source3/lib/msrpc_use.c b/source3/lib/msrpc_use.c new file mode 100644 index 0000000000..c755a35fb4 --- /dev/null +++ b/source3/lib/msrpc_use.c @@ -0,0 +1,328 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB client generic functions + Copyright (C) Andrew Tridgell 1994-1999 + Copyright (C) Luke Kenneth Casson Leighton 1996-1999 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define NO_SYSLOG + +#include "includes.h" +#include "trans2.h" + +extern int DEBUGLEVEL; +extern pstring scope; +extern pstring global_myname; + +struct msrpc_use +{ + struct msrpc_state *cli; + uint32 num_users; +}; + +static struct msrpc_use **msrpcs = NULL; +uint32 num_msrpcs = 0; + +/**************************************************************************** +terminate client connection +****************************************************************************/ +static void msrpc_use_free(struct msrpc_use *cli) +{ + if (cli->cli != NULL) + { + if (cli->cli->initialised) + { + msrpc_shutdown(cli->cli); + } + free(cli->cli); + } + + free(cli); +} + +/**************************************************************************** +free a client array +****************************************************************************/ +static void free_msrpc_array(uint32 num_entries, struct msrpc_use **entries) +{ + void(*fn)(void*) = (void(*)(void*))&msrpc_use_free; + free_void_array(num_entries, (void**)entries, *fn); +} + +/**************************************************************************** +add a client state to the array +****************************************************************************/ +static struct msrpc_use* add_msrpc_to_array(uint32 *len, + struct msrpc_use ***array, + struct msrpc_use *cli) +{ + int i; + for (i = 0; i < num_msrpcs; i++) + { + if (msrpcs[i] == NULL) + { + msrpcs[i] = cli; + return cli; + } + } + + return (struct msrpc_use*)add_item_to_array(len, + (void***)array, (void*)cli); + +} + +/**************************************************************************** +initiate client array +****************************************************************************/ +void init_msrpc_use(void) +{ + msrpcs = NULL; + num_msrpcs = 0; +} + +/**************************************************************************** +terminate client array +****************************************************************************/ +void free_msrpc_use(void) +{ + free_msrpc_array(num_msrpcs, msrpcs); + init_msrpc_use(); +} + +/**************************************************************************** +find client state. server name, user name, domain name and password must all +match. +****************************************************************************/ +static struct msrpc_use *msrpc_find(const char* pipe_name, + const struct user_creds *usr_creds) +{ + int i; + struct user_creds null_usr; + + if (usr_creds == NULL) + { + copy_user_creds(&null_usr, usr_creds); + usr_creds = &null_usr; + } + + DEBUG(10,("msrpc_find: %s %s %s\n", + pipe_name, + usr_creds->ntc.user_name, + usr_creds->ntc.domain)); + + for (i = 0; i < num_msrpcs; i++) + { + char *msrpc_name = NULL; + struct msrpc_use *c = msrpcs[i]; + + if (c == NULL) continue; + + msrpc_name = c->cli->pipe_name; + + DEBUG(10,("msrpc_find[%d]: %s %s %s\n", + i, msrpc_name, + c->cli->usr.ntc.user_name, + c->cli->usr.ntc.domain)); + + if (!strequal(msrpc_name, pipe_name)) + { + continue; + } + if (!strequal(usr_creds->ntc.user_name, c->cli->usr.ntc.user_name)) + { + continue; + } + if (!usr_creds->reuse && + !pwd_compare(&usr_creds->ntc.pwd, &c->cli->usr.ntc.pwd)) + { + DEBUG(100,("password doesn't match\n")); + continue; + } + if (usr_creds->ntc.domain[0] == 0) + { + return c; + } + if (strequal(usr_creds->ntc.domain, c->cli->usr.ntc.domain)) + { + return c; + } + } + + return NULL; +} + +/**************************************************************************** +create a new client state from user credentials +****************************************************************************/ +static struct msrpc_use *msrpc_use_get(const char* pipe_name, + const struct user_creds *usr_creds) +{ + struct msrpc_use *cli = (struct msrpc_use*)malloc(sizeof(*cli)); + + if (cli == NULL) + { + return NULL; + } + + memset(cli, 0, sizeof(*cli)); + + cli->cli = msrpc_initialise(NULL); + + if (cli->cli == NULL) + { + return NULL; + } + + msrpc_init_creds(cli->cli, usr_creds); + + return cli; +} + +/**************************************************************************** +init client state +****************************************************************************/ +struct msrpc_state *msrpc_use_add(const char* pipe_name, + const struct user_creds *usr_creds, + BOOL redir) +{ + struct msrpc_use *cli; + DEBUG(10,("msrpc_use_add: %s redir: %s\n", pipe_name, BOOLSTR(redir))); + + cli = msrpc_find(pipe_name, usr_creds); + + if (cli != NULL) + { + cli->num_users++; + return cli->cli; + } + + /* reuse an existing connection requested, and one was not found */ + if (usr_creds != NULL && usr_creds->reuse && !redir) + { + DEBUG(0,("msrpc_use_add: reuse requested, but one not found\n")); + return False; + } + + /* + * allocate + */ + + cli = msrpc_use_get(pipe_name, usr_creds); + cli->cli->redirect = redir; + + if (!msrpc_establish_connection(cli->cli, pipe_name)) + { + DEBUG(0,("msrpc_use_add: connection failed\n")); + cli->cli = NULL; + msrpc_use_free(cli); + return NULL; + } + + add_msrpc_to_array(&num_msrpcs, &msrpcs, cli); + cli->num_users++; + + return cli->cli; +} + +/**************************************************************************** +delete a client state +****************************************************************************/ +BOOL msrpc_use_del(const char* pipe_name, + const struct user_creds *usr_creds, + BOOL force_close, + BOOL *connection_closed) +{ + int i; + + DEBUG(10,("msrpc_net_use_del: %s. force close: %s\n", + pipe_name, BOOLSTR(force_close))); + + if (connection_closed != NULL) + { + *connection_closed = False; + } + + for (i = 0; i < num_msrpcs; i++) + { + char *msrpc_name = NULL; + + if (msrpcs[i] == NULL) continue; + if (msrpcs[i]->cli == NULL) continue; + + msrpc_name = msrpcs[i]->cli->pipe_name; + + if (!strequal(msrpc_name, pipe_name)) continue; + + if (strequal(usr_creds->ntc.user_name, + msrpcs[i]->cli->usr.ntc.user_name) && + strequal(usr_creds->ntc.domain, + msrpcs[i]->cli->usr.ntc.domain)) + { + /* decrement number of users */ + msrpcs[i]->num_users--; + + DEBUG(10,("idx: %i num_users now: %d\n", + i, msrpcs[i]->num_users)); + + if (force_close || msrpcs[i]->num_users == 0) + { + msrpc_use_free(msrpcs[i]); + msrpcs[i] = NULL; + if (connection_closed != NULL) + { + *connection_closed = True; + } + } + return True; + } + } + + return False; +} + +/**************************************************************************** +enumerate client states +****************************************************************************/ +void msrpc_net_use_enum(uint32 *num_cons, struct use_info ***use) +{ + int i; + + *num_cons = 0; + *use = NULL; + + for (i = 0; i < num_msrpcs; i++) + { + struct use_info item; + + ZERO_STRUCT(item); + + if (msrpcs[i] == NULL) continue; + + item.connected = msrpcs[i]->cli != NULL ? True : False; + + if (item.connected) + { + item.srv_name = msrpcs[i]->cli->pipe_name; + item.user_name = msrpcs[i]->cli->usr.ntc.user_name; + item.domain = msrpcs[i]->cli->usr.ntc.domain; + } + + add_use_info_to_array(num_cons, use, &item); + } +} + diff --git a/source3/lib/util.c b/source3/lib/util.c index 0ad14ad3ae..1a893c52ce 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -357,6 +357,21 @@ BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf) return(S_ISREG(sbuf->st_mode)); } +/******************************************************************* + rename a unix file +********************************************************************/ +int file_rename(char *from, char *to) +{ + int rcode = rename (from, to); + + if (errno == EXDEV) + { + /* Rename across filesystems needed. */ + rcode = copy_reg (from, to); + } + return rcode; +} + /******************************************************************* check a files mod time ********************************************************************/ diff --git a/source3/lib/util_array.c b/source3/lib/util_array.c new file mode 100644 index 0000000000..567c170834 --- /dev/null +++ b/source3/lib/util_array.c @@ -0,0 +1,194 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1999 + Copyright (C) Luke Kenneth Casson Leighton 1996-1999 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +void free_void_array(uint32 num_entries, void **entries, + void(free_item)(void*)) +{ + uint32 i; + if (entries != NULL) + { + for (i = 0; i < num_entries; i++) + { + if (entries[i] != NULL) + { + free_item(entries[i]); + } + } + free(entries); + } +} + +void* add_copy_to_array(uint32 *len, void ***array, const void *item, + void*(item_dup)(const void*), BOOL alloc_anyway) +{ + void* copy = NULL; + if (len == NULL || array == NULL) + { + return NULL; + } + + if (item != NULL || alloc_anyway) + { + copy = item_dup(item); + return add_item_to_array(len, array, copy); + } + return copy; +} + +void* add_item_to_array(uint32 *len, void ***array, void *item) +{ + if (len == NULL || array == NULL) + { + return NULL; + } + + (*array) = (void**)Realloc((*array), ((*len)+1)*sizeof((*array)[0])); + + if ((*array) != NULL) + { + (*array)[(*len)] = item; + (*len)++; + return item; + } + return NULL; +} + +static void use_info_free(struct use_info *item) +{ + if (item != NULL) + { + if (item->srv_name != NULL) + { + free(item->srv_name); + } + if (item->user_name != NULL) + { + free(item->user_name); + } + if (item->domain != NULL) + { + free(item->domain); + } + free(item); + } +} + +static struct use_info *use_info_dup(const struct use_info *from) +{ + if (from != NULL) + { + struct use_info *copy = (struct use_info *) + malloc(sizeof(struct use_info)); + if (copy != NULL) + { + ZERO_STRUCTP(copy); + copy->connected = from->connected; + if (from->srv_name != NULL) + { + copy->srv_name = strdup(from->srv_name ); + } + if (from->user_name != NULL) + { + copy->user_name = strdup(from->user_name); + } + if (from->domain != NULL) + { + copy->domain = strdup(from->domain ); + } + } + return copy; + } + return NULL; +} + +void free_use_info_array(uint32 num_entries, struct use_info **entries) +{ + void(*fn)(void*) = (void(*)(void*))&use_info_free; + free_void_array(num_entries, (void**)entries, *fn); +} + +struct use_info* add_use_info_to_array(uint32 *len, struct use_info ***array, + const struct use_info *name) +{ + void*(*fn)(const void*) = (void*(*)(const void*))&use_info_dup; + return (struct use_info*)add_copy_to_array(len, + (void***)array, (const void*)name, *fn, False); + +} + +void free_char_array(uint32 num_entries, char **entries) +{ + void(*fn)(void*) = (void(*)(void*))&free; + free_void_array(num_entries, (void**)entries, *fn); +} + +char* add_chars_to_array(uint32 *len, char ***array, const char *name) +{ + void*(*fn)(const void*) = (void*(*)(const void*))&strdup; + return (char*)add_copy_to_array(len, + (void***)array, (const void*)name, *fn, False); + +} + +static uint32 *uint32_dup(const uint32* from) +{ + if (from != NULL) + { + uint32 *copy = (uint32 *)malloc(sizeof(uint32)); + if (copy != NULL) + { + memcpy(copy, from, sizeof(*copy)); + } + return copy; + } + return NULL; +} + +void free_uint32_array(uint32 num_entries, uint32 **entries) +{ + void(*fn)(void*) = (void(*)(void*))&free; + free_void_array(num_entries, (void**)entries, *fn); +} + +uint32* add_uint32s_to_array(uint32 *len, uint32 ***array, const uint32 *name) +{ + void*(*fn)(const void*) = (void*(*)(const void*))&uint32_dup; + return (uint32*)add_copy_to_array(len, + (void***)array, (const void*)name, *fn, False); + +} + +void free_sid_array(uint32 num_entries, DOM_SID **entries) +{ + void(*fn)(void*) = (void(*)(void*))&free; + free_void_array(num_entries, (void**)entries, *fn); +} + +DOM_SID* add_sid_to_array(uint32 *len, DOM_SID ***array, const DOM_SID *sid) +{ + void*(*fn)(const void*) = (void*(*)(const void*))&sid_dup; + return (DOM_SID*)add_copy_to_array(len, + (void***)array, (const void*)sid, *fn, False); +} + diff --git a/source3/lib/util_sid.c b/source3/lib/util_sid.c index 9e5154d259..f2f7b3c8ae 100644 --- a/source3/lib/util_sid.c +++ b/source3/lib/util_sid.c @@ -335,7 +335,7 @@ BOOL sid_split_rid(DOM_SID *sid, uint32 *rid) Copies a sid *****************************************************************/ -void sid_copy(DOM_SID *dst, DOM_SID *src) +void sid_copy(DOM_SID *dst, const DOM_SID *src) { int i; @@ -424,3 +424,291 @@ size_t sid_size(DOM_SID *sid) return sid->num_auths * sizeof(uint32) + 8; } + +static BOOL read_sid_from_file(int fd, char *sid_file, DOM_SID *sid) +{ + fstring fline; + fstring sid_str; + + memset(fline, '\0', sizeof(fline)); + + if (read(fd, fline, sizeof(fline) -1 ) < 0) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Convert to the machine SID. + */ + + fline[sizeof(fline)-1] = '\0'; + if (!string_to_sid(sid, fline)) { + DEBUG(0,("unable to read sid.\n")); + return False; + } + + sid_to_string(sid_str, sid); + DEBUG(5,("read_sid_from_file: sid %s\n", sid_str)); + + return True; +} + +/**************************************************************************** + Generate the global machine sid. Look for the DOMAINNAME.SID file first, if + not found then look in smb.conf and use it to create the DOMAINNAME.SID file. +****************************************************************************/ +BOOL read_sid(char *sam_name, DOM_SID *sid) +{ + int fd; + char *p; + pstring sid_file; + fstring file_name; + SMB_STRUCT_STAT st; + + pstrcpy(sid_file, lp_smb_passwd_file()); + + DEBUG(10,("read_sid: Domain: %s\n", sam_name)); + + if (sid_file[0] == 0) + { + DEBUG(0,("cannot find smb passwd file\n")); + return False; + } + + p = strrchr(sid_file, '/'); + if (p != NULL) + { + *++p = '\0'; + } + + if (!directory_exist(sid_file, NULL)) + { + if (mkdir(sid_file, 0700) != 0) + { + DEBUG(0,("can't create private directory %s : %s\n", + sid_file, strerror(errno))); + return False; + } + } + + slprintf(file_name, sizeof(file_name)-1, "%s.SID", sam_name); + strupper(file_name); + pstrcat(sid_file, file_name); + + if ((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) { + DEBUG(0,("unable to open or create file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Check if the file contains data. + */ + + if (sys_fstat(fd, &st) < 0) { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (st.st_size == 0) + { + close(fd); + return False; + } + + /* + * We have a valid SID - read it. + */ + + if (!read_sid_from_file(fd, sid_file, sid)) + { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + close(fd); + return True; +} + + +/**************************************************************************** + Generate the global machine sid. Look for the DOMAINNAME.SID file first, if + not found then look in smb.conf and use it to create the DOMAINNAME.SID file. +****************************************************************************/ +BOOL write_sid(char *sam_name, DOM_SID *sid) +{ + int fd; + char *p; + pstring sid_file; + fstring sid_string; + fstring file_name; + SMB_STRUCT_STAT st; + + pstrcpy(sid_file, lp_smb_passwd_file()); + sid_to_string(sid_string, sid); + + DEBUG(10,("write_sid: Domain: %s SID: %s\n", sam_name, sid_string)); + fstrcat(sid_string, "\n"); + + if (sid_file[0] == 0) + { + DEBUG(0,("cannot find smb passwd file\n")); + return False; + } + + p = strrchr(sid_file, '/'); + if (p != NULL) + { + *++p = '\0'; + } + + if (!directory_exist(sid_file, NULL)) { + if (mkdir(sid_file, 0700) != 0) { + DEBUG(0,("can't create private directory %s : %s\n", + sid_file, strerror(errno))); + return False; + } + } + + slprintf(file_name, sizeof(file_name)-1, "%s.SID", sam_name); + strupper(file_name); + pstrcat(sid_file, file_name); + + if ((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) { + DEBUG(0,("unable to open or create file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Check if the file contains data. + */ + + if (sys_fstat(fd, &st) < 0) { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (st.st_size > 0) + { + /* + * We have a valid SID already. + */ + close(fd); + DEBUG(0,("SID file %s already exists\n", sid_file)); + return False; + } + + if (!do_file_lock(fd, 60, F_WRLCK)) + { + DEBUG(0,("unable to lock file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + /* + * At this point we have a blocking lock on the SID + * file - check if in the meantime someone else wrote + * SID data into the file. If so - they were here first, + * use their data. + */ + + if (sys_fstat(fd, &st) < 0) + { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (st.st_size > 0) + { + /* + * Unlock as soon as possible to reduce + * contention on the exclusive lock. + */ + do_file_lock(fd, 60, F_UNLCK); + + /* + * We have a valid SID already. + */ + + DEBUG(0,("SID file %s already exists\n", sid_file)); + close(fd); + return False; + } + + /* + * The file is still empty and we have an exlusive lock on it. + * Write out out SID data into the file. + */ + + if (fchmod(fd, 0644) < 0) + { + DEBUG(0,("unable to set correct permissions on file %s. \ +Error was %s\n", sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (write(fd, sid_string, strlen(sid_string)) != strlen(sid_string)) + { + DEBUG(0,("unable to write file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + /* + * Unlock & exit. + */ + + do_file_lock(fd, 60, F_UNLCK); + close(fd); + return True; +} + +/**************************************************************************** +create a random SID. +****************************************************************************/ +BOOL create_new_sid(DOM_SID *sid) +{ + uchar raw_sid_data[12]; + fstring sid_string; + int i; + + /* + * Generate the new sid data & turn it into a string. + */ + generate_random_buffer(raw_sid_data, 12, True); + + fstrcpy(sid_string, "S-1-5-21"); + for(i = 0; i < 3; i++) + { + fstring tmp_string; + slprintf(tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4)); + fstrcat(sid_string, tmp_string); + } + + fstrcat(sid_string, "\n"); + + /* + * Ensure our new SID is valid. + */ + + if (!string_to_sid(sid, sid_string)) + { + DEBUG(0,("unable to generate machine SID.\n")); + return False; + } + + return True; +} + diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 77ba4a7f4c..3a09c52a7a 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -1041,3 +1041,103 @@ char *client_addr(int fd) global_client_addr_done = True; return addr_buf; } + +/******************************************************************* + opens and connects to a unix pipe socket + ******************************************************************/ +int open_pipe_sock(char *path) +{ + int sock; + struct sockaddr_un sa; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + + if (sock < 0) + { + DEBUG(0, ("unix socket open failed\n")); + return sock; + } + + ZERO_STRUCT(sa); + sa.sun_family = AF_UNIX; + safe_strcpy(sa.sun_path, path, sizeof(sa.sun_path)-1); + + DEBUG(10, ("socket open succeeded. file name: %s\n", sa.sun_path)); + + if (connect(sock, (struct sockaddr*) &sa, sizeof(sa)) < 0) + { + DEBUG(0,("socket connect to %s failed\n", sa.sun_path)); + close(sock); + return -1; + } + + return sock; +} + +int create_pipe_socket(char *dir, int dir_perms, + char *path, int path_perms) +{ + int s; + struct sockaddr_un sa; + + DEBUG(0,("create_pipe_socket: %s %d %s %d\n", + dir, dir_perms, path, path_perms)); + + DEBUG(0,("*** RACE CONDITION. PLEASE SOMEONE EXAMINE create_pipe_Socket AND FIX IT ***\n")); + + mkdir(dir, dir_perms); + + if (chmod(dir, dir_perms) < 0) + { + DEBUG(0, ("chmod on %s failed\n", dir)); + return -1; + } + + if (!remove(path)) + { + DEBUG(0, ("remove on %s failed\n", path)); + } + + /* start listening on unix socket */ + s = socket(AF_UNIX, SOCK_STREAM, 0); + + if (s < 0) + { + DEBUG(0, ("socket open failed\n")); + return -1; + } + + ZERO_STRUCT(sa); + sa.sun_family = AF_UNIX; + safe_strcpy(sa.sun_path, path, sizeof(sa.sun_path)-1); + + if (bind(s, (struct sockaddr*) &sa, sizeof(sa)) < 0) + { + DEBUG(0, ("socket bind to %s failed\n", sa.sun_path)); + close(s); + remove(path); + return -1; + } + + if (s == -1) + { + DEBUG(0,("bind failed\n")); + remove(path); + return -1; + } + + if (path_perms != 0) + { + chmod(path, path_perms); + } + + if (listen(s, 5) == -1) + { + DEBUG(0,("listen failed\n")); + return -1; + } + + DEBUG(5,("unix socket opened: %s\n", path)); + + return s; +} diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c index 94b60d3ff0..4f02c42efb 100644 --- a/source3/libsmb/pwd_cache.c +++ b/source3/libsmb/pwd_cache.c @@ -61,6 +61,60 @@ void pwd_obfuscate_key(struct pwd_info *pwd, uint32 int_key, char *str_key) { } +/**************************************************************************** +compares two passwords. hmm, not as trivial as expected. hmm. +****************************************************************************/ +BOOL pwd_compare(struct pwd_info *pwd1, struct pwd_info *pwd2) +{ + pwd_deobfuscate(pwd1); + pwd_deobfuscate(pwd2); + if (pwd1->cleartext && pwd2->cleartext) + { + if (strequal(pwd1->password, pwd2->password)) + { + pwd_obfuscate(pwd1); + pwd_obfuscate(pwd2); + return True; + } + } + if (pwd1->null_pwd && pwd2->null_pwd) + { + pwd_obfuscate(pwd1); + pwd_obfuscate(pwd2); + return True; + } + + if (!pwd1->null_pwd && !pwd2->null_pwd && + !pwd1->cleartext && !pwd2->cleartext) + { +#ifdef DEBUG_PASSWORD + DEBUG(100,("pwd compare: nt#\n")); + dump_data(100, pwd1->smb_nt_pwd, 16); + dump_data(100, pwd2->smb_nt_pwd, 16); +#endif + if (memcmp(pwd1->smb_nt_pwd, pwd2->smb_nt_pwd, 16) == 0) + { + pwd_obfuscate(pwd1); + pwd_obfuscate(pwd2); + return True; + } +#ifdef DEBUG_PASSWORD + DEBUG(100,("pwd compare: lm#\n")); + dump_data(100, pwd1->smb_lm_pwd, 16); + dump_data(100, pwd2->smb_lm_pwd, 16); +#endif + if (memcmp(pwd1->smb_lm_pwd, pwd2->smb_lm_pwd, 16) == 0) + { + pwd_obfuscate(pwd1); + pwd_obfuscate(pwd2); + return True; + } + } + pwd_obfuscate(pwd1); + pwd_obfuscate(pwd2); + return False; +} + /**************************************************************************** reads a password ****************************************************************************/ diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index c0a20f3420..f6502c238c 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -788,52 +788,32 @@ BOOL pdb_name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid) } /**************************************************************************** - Read the machine SID from a file. + Generate the global machine sid. Look for the DOMAINNAME.SID file first, if + not found then look in smb.conf and use it to create the DOMAINNAME.SID file. ****************************************************************************/ - -static BOOL read_sid_from_file(int fd, char *sid_file) -{ - fstring fline; - - memset(fline, '\0', sizeof(fline)); - - if(read(fd, fline, sizeof(fline) -1 ) < 0) { - DEBUG(0,("unable to read file %s. Error was %s\n", - sid_file, strerror(errno) )); - return False; - } - - /* - * Convert to the machine SID. - */ - - fline[sizeof(fline)-1] = '\0'; - if(!string_to_sid( &global_sam_sid, fline)) { - DEBUG(0,("unable to generate machine SID.\n")); - return False; - } - - return True; -} - -/**************************************************************************** - Generate the global machine sid. Look for the MACHINE.SID file first, if - not found then look in smb.conf and use it to create the MACHINE.SID file. -****************************************************************************/ -BOOL pdb_generate_sam_sid(void) +BOOL pdb_generate_sam_sid(char *domain_name, DOM_SID *sid) { - int fd; char *p; pstring sid_file; - fstring sid_string; - SMB_STRUCT_STAT st; - BOOL overwrite_bad_sid = False; + pstring machine_sid_file; + fstring file_name; - generate_wellknown_sids(); + if (sid == NULL) + { + sid = &global_sam_sid; + } pstrcpy(sid_file, lp_smb_passwd_file()); + + if (sid_file[0] == 0) + { + DEBUG(0,("cannot find smb passwd file\n")); + return False; + } + p = strrchr(sid_file, '/'); - if(p != NULL) { + if (p != NULL) + { *++p = '\0'; } @@ -845,180 +825,55 @@ BOOL pdb_generate_sam_sid(void) } } - pstrcat(sid_file, "MACHINE.SID"); + pstrcpy(machine_sid_file, sid_file); + pstrcat(machine_sid_file, "MACHINE.SID"); + + slprintf(file_name, sizeof(file_name)-1, "%s.SID", domain_name); + strupper(file_name); + pstrcat(sid_file, file_name); - if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) { - DEBUG(0,("unable to open or create file %s. Error was %s\n", - sid_file, strerror(errno) )); - return False; - } - - /* - * Check if the file contains data. - */ - - if(sys_fstat( fd, &st) < 0) { - DEBUG(0,("unable to stat file %s. Error was %s\n", - sid_file, strerror(errno) )); - close(fd); - return False; - } - - if(st.st_size > 0) { - /* - * We have a valid SID - read it. - */ - if(!read_sid_from_file( fd, sid_file)) { - DEBUG(0,("unable to read file %s. Error was %s\n", - sid_file, strerror(errno) )); - close(fd); + if (file_exist(machine_sid_file, NULL)) + { + if (file_exist(sid_file, NULL)) + { + DEBUG(0,("both %s and %s exist when only one should, unable to continue\n", + machine_sid_file, sid_file)); return False; } - - /* - * JRA. Reversed the sense of this test now that I have - * actually done this test *personally*. One more reason - * to never trust third party information you have not - * independently verified.... sigh. JRA. - */ - - if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) { - /* - * Fix and re-write... - */ - overwrite_bad_sid = True; - global_sam_sid.sub_auths[0] = 21; - DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \ -detected - re-writing to be decimal 21 instead.\n" )); - sid_to_string(sid_string, &global_sam_sid); - if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) { - DEBUG(0,("unable to seek file file %s. Error was %s\n", - sid_file, strerror(errno) )); - close(fd); - return False; - } - } else { - close(fd); - return True; + if (file_rename(machine_sid_file, sid_file)) + { + DEBUG(0,("could not rename %s to %s. Error was %s\n", + machine_sid_file, sid_file, strerror(errno))); + return False; } - } else { - /* - * The file contains no data - we need to generate our - * own sid. - * Generate the new sid data & turn it into a string. - */ - int i; - uchar raw_sid_data[12]; - DOM_SID mysid; - - memset((char *)&mysid, '\0', sizeof(DOM_SID)); - mysid.sid_rev_num = 1; - mysid.id_auth[5] = 5; - mysid.num_auths = 0; - mysid.sub_auths[mysid.num_auths++] = 21; - - generate_random_buffer( raw_sid_data, 12, True); - for( i = 0; i < 3; i++) - mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4); - - sid_to_string(sid_string, &mysid); - } - - fstrcat(sid_string, "\n"); - - /* - * Ensure our new SID is valid. - */ + } - if(!string_to_sid( &global_sam_sid, sid_string)) { - DEBUG(0,("unable to generate machine SID.\n")); - return False; - } + /* attempt to read the SID from the file */ + if (read_sid(domain_name, sid)) + { + return True; + } - /* - * Do an exclusive blocking lock on the file. - */ - - if(!do_file_lock( fd, 60, F_WRLCK)) { - DEBUG(0,("unable to lock file %s. Error was %s\n", - sid_file, strerror(errno) )); - close(fd); + if (!create_new_sid(sid)) + { return False; - } - - if(!overwrite_bad_sid) { - /* - * At this point we have a blocking lock on the SID - * file - check if in the meantime someone else wrote - * SID data into the file. If so - they were here first, - * use their data. - */ - - if(sys_fstat( fd, &st) < 0) { - DEBUG(0,("unable to stat file %s. Error was %s\n", - sid_file, strerror(errno) )); - close(fd); - return False; - } - - if(st.st_size > 0) { - /* - * Unlock as soon as possible to reduce - * contention on the exclusive lock. - */ - do_file_lock( fd, 60, F_UNLCK); - - /* - * We have a valid SID - read it. - */ - - if(!read_sid_from_file( fd, sid_file)) { - DEBUG(0,("unable to read file %s. Error was %s\n", - sid_file, strerror(errno) )); - close(fd); - return False; - } - close(fd); - return True; - } } - - /* - * The file is still empty and we have an exlusive lock on it, - * or we're fixing an earlier mistake. - * Write out out SID data into the file. - */ + /* attempt to read the SID from the file */ + if (!write_sid(domain_name, sid)) + { + return True; + } + + /* during the attempt to write, someone else wrote? */ - /* - * Use chmod here as some (strange) UNIX's don't - * have fchmod. JRA. - */ - - if(chmod(sid_file, 0644) < 0) { - DEBUG(0,("unable to set correct permissions on file %s. \ -Error was %s\n", sid_file, strerror(errno) )); - do_file_lock( fd, 60, F_UNLCK); - close(fd); - return False; - } - - if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) { - DEBUG(0,("unable to write file %s. Error was %s\n", - sid_file, strerror(errno) )); - do_file_lock( fd, 60, F_UNLCK); - close(fd); - return False; - } - - /* - * Unlock & exit. - */ - - do_file_lock( fd, 60, F_UNLCK); - close(fd); + /* attempt to read the SID from the file */ + if (read_sid(domain_name, sid)) + { + return True; + } + return True; } - /******************************************************************* Converts NT user RID to a UNIX uid. ********************************************************************/ diff --git a/source3/rpc_parse/parse_creds.c b/source3/rpc_parse/parse_creds.c new file mode 100644 index 0000000000..74dac2f011 --- /dev/null +++ b/source3/rpc_parse/parse_creds.c @@ -0,0 +1,578 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tgrpsgell 1992-1999, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1999, + * Copyright (C) Paul Ashton 1997-1999. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambgrpsge, MA 02139, USA. + */ + + +#include "includes.h" + +extern int DEBUGLEVEL; + + +/******************************************************************* +makes a CREDS_UNIX structure. +********************************************************************/ +BOOL make_creds_unix(CREDS_UNIX *r_u, const char* user_name, + const char* requested_name, + const char* real_name, + BOOL guest) +{ + if (r_u == NULL) return False; + + DEBUG(5,("make_creds_unix\n")); + + fstrcpy(r_u->user_name , user_name); + fstrcpy(r_u->requested_name, requested_name); + fstrcpy(r_u->real_name , real_name); + r_u->guest = guest; + + return True; +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_unix(char *desc, CREDS_UNIX *r_u, prs_struct *ps, int depth) +{ + if (r_u == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_unix"); + depth++; + + prs_align(ps); + prs_string("user_name", ps, depth, r_u->user_name, strlen(r_u->user_name), sizeof(r_u->user_name)); + prs_align(ps); + prs_string("requested_name", ps, depth, r_u->requested_name, strlen(r_u->requested_name), sizeof(r_u->requested_name)); + prs_align(ps); + prs_string("real_name", ps, depth, r_u->real_name, strlen(r_u->real_name), sizeof(r_u->real_name)); + prs_align(ps); + prs_uint32("guest", ps, depth, &(r_u->guest)); + return True; +} + + +/******************************************************************* +frees a structure. +********************************************************************/ +void creds_free_unix(CREDS_UNIX *r_u) +{ +} + +/******************************************************************* +makes a CREDS_UNIX_SEC structure. +********************************************************************/ +BOOL make_creds_unix_sec(CREDS_UNIX_SEC *r_u, + uint32 uid, uint32 gid, uint32 num_grps, gid_t *grps) +{ + int i; + if (r_u == NULL) return False; + + DEBUG(5,("make_creds_unix_sec\n")); + + r_u->uid = uid; + r_u->gid = gid; + r_u->num_grps = num_grps; + r_u->grps = (uint32*)Realloc(NULL, sizeof(r_u->grps[0]) * + r_u->num_grps); + if (r_u->grps == NULL && num_grps != 0) + { + return False; + } + for (i = 0; i < num_grps; i++) + { + r_u->grps[i] = (gid_t)grps[i]; + } + + return True; +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_unix_sec(char *desc, CREDS_UNIX_SEC *r_u, prs_struct *ps, int depth) +{ + uint32 i; + + if (r_u == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_unix_sec"); + depth++; + + prs_align(ps); + + prs_uint32("uid", ps, depth, &(r_u->uid)); + prs_uint32("gid", ps, depth, &(r_u->gid)); + prs_uint32("num_grps", ps, depth, &(r_u->num_grps)); + if (r_u->num_grps != 0) + { + r_u->grps = (uint32*)Realloc(r_u->grps, + sizeof(r_u->grps[0]) * + r_u->num_grps); + if (r_u->grps == NULL) + { + creds_free_unix_sec(r_u); + return False; + } + } + for (i = 0; i < r_u->num_grps; i++) + { + prs_uint32("", ps, depth, &(r_u->grps[i])); + } + return True; +} + + +/******************************************************************* +frees a structure. +********************************************************************/ +void creds_free_unix_sec(CREDS_UNIX_SEC *r_u) +{ + if (r_u->grps != NULL) + { + free(r_u->grps); + r_u->grps = NULL; + } +} + +/******************************************************************* +makes a CREDS_NT_SEC structure. +********************************************************************/ +BOOL make_creds_nt_sec(CREDS_NT_SEC *r_u, + DOM_SID *sid, uint32 num_grps, uint32 *grps) +{ + int i; + if (r_u == NULL) return False; + + DEBUG(5,("make_creds_unix_sec\n")); + + sid_copy(&r_u->sid, sid); + r_u->num_grps = num_grps; + r_u->grp_rids = (uint32*)Realloc(NULL, sizeof(r_u->grp_rids[0]) * + r_u->num_grps); + + if (r_u->grp_rids == NULL && num_grps != 0) + { + return False; + } + for (i = 0; i < num_grps; i++) + { + r_u->grp_rids[i] = grps[i]; + } + + return True; +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_nt_sec(char *desc, CREDS_NT_SEC *r_u, prs_struct *ps, int depth) +{ + int i; + if (r_u == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_nt"); + depth++; + + prs_align(ps); + + smb_io_dom_sid ("sid", &r_u->sid, ps, depth); + prs_align(ps); + + prs_uint32("num_grps", ps, depth, &(r_u->num_grps)); + if (r_u->num_grps != 0) + { + r_u->grp_rids = (uint32*)Realloc(r_u->grp_rids, + sizeof(r_u->grp_rids[0]) * + r_u->num_grps); + if (r_u->grp_rids == NULL) + { + creds_free_nt_sec(r_u); + return False; + } + } + for (i = 0; i < r_u->num_grps; i++) + { + prs_uint32("", ps, depth, &(r_u->grp_rids[i])); + } + + return True; +} + +/******************************************************************* +frees a structure. +********************************************************************/ +void creds_free_nt_sec(CREDS_NT_SEC *r_u) +{ + if (r_u->grp_rids != NULL) + { + free(r_u->grp_rids); + r_u->grp_rids = NULL; + } +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_pwd_info(char *desc, struct pwd_info *pwd, prs_struct *ps, int depth) +{ + if (pwd == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_pwd_info"); + depth++; + + prs_align(ps); + + prs_uint32("nullpwd", ps, depth, &(pwd->null_pwd)); + if (pwd->null_pwd) + { + return True; + } + + prs_uint32("cleartext", ps, depth, &(pwd->cleartext)); + if (pwd->cleartext) + { + prs_string("password", ps, depth, pwd->password, strlen(pwd->password), sizeof(pwd->password)); + prs_align(ps); + return True; + } + prs_uint32("crypted", ps, depth, &(pwd->crypted)); + + prs_uint8s(False, "smb_lm_pwd", ps, depth, (char*)&pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd)); + prs_align(ps); + prs_uint8s(False, "smb_nt_pwd", ps, depth, (char*)&pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd)); + prs_align(ps); + + prs_uint8s(False, "smb_lm_owf", ps, depth, (char*)&pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf)); + prs_align(ps); + prs_uint32("nt_owf_len", ps, depth, &(pwd->nt_owf_len)); + if (pwd->nt_owf_len > sizeof(pwd->smb_nt_owf)) + { + return False; + } + prs_uint8s(False, "smb_nt_owf", ps, depth, (char*)&pwd->smb_nt_owf, pwd->nt_owf_len); + prs_align(ps); + + prs_uint8s(False, "lm_cli_chal", ps, depth, (char*)&pwd->lm_cli_chal, sizeof(pwd->lm_cli_chal)); + prs_align(ps); + prs_uint32("nt_cli_chal_len", ps, depth, &(pwd->nt_cli_chal_len)); + + if (pwd->nt_cli_chal_len > sizeof(pwd->nt_cli_chal)) + { + return False; + } + prs_uint8s(False, "nt_cli_chal", ps, depth, (char*)&pwd->nt_cli_chal, pwd->nt_cli_chal_len); + prs_align(ps); + + return True; +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_nt(char *desc, CREDS_NT *r_u, prs_struct *ps, int depth) +{ + if (r_u == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_nt"); + depth++; + + prs_align(ps); + + /* lkclXXXX CHEAT!!!!!!!! */ + prs_string("user_name", ps, depth, r_u->user_name, strlen(r_u->user_name), sizeof(r_u->user_name)); + prs_align(ps); + prs_string("domain", ps, depth, r_u->domain, strlen(r_u->domain), sizeof(r_u->domain)); + prs_align(ps); + + creds_io_pwd_info("pwd", &r_u->pwd, ps, depth); + prs_align(ps); + + prs_uint32("ntlmssp", ps, depth, &(r_u->ntlmssp_flags)); + + return True; +} + +/******************************************************************* +frees a structure. +********************************************************************/ +void creds_free_nt(CREDS_NT *r_u) +{ +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_hybrid(char *desc, CREDS_HYBRID *r_u, prs_struct *ps, int depth) +{ + if (r_u == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_hybrid"); + depth++; + + prs_align(ps); + + prs_uint32("reuse", ps, depth, &(r_u->reuse)); + prs_uint32("ptr_ntc", ps, depth, &(r_u->ptr_ntc)); + prs_uint32("ptr_uxc", ps, depth, &(r_u->ptr_uxc)); + prs_uint32("ptr_nts", ps, depth, &(r_u->ptr_nts)); + prs_uint32("ptr_uxs", ps, depth, &(r_u->ptr_uxs)); + if (r_u->ptr_ntc != 0) + { + if (!creds_io_nt ("ntc", &r_u->ntc, ps, depth)) return False; + } + if (r_u->ptr_uxc != 0) + { + if (!creds_io_unix("uxc", &r_u->uxc, ps, depth)) return False; + } + if (r_u->ptr_nts != 0) + { + if (!creds_io_nt_sec ("nts", &r_u->nts, ps, depth)) return False; + } + if (r_u->ptr_uxs != 0) + { + if (!creds_io_unix_sec("uxs", &r_u->uxs, ps, depth)) return False; + } + return True; +} + +void copy_unix_creds(CREDS_UNIX *to, const CREDS_UNIX *from) +{ + if (from == NULL) + { + to->user_name[0] = 0; + return; + } + fstrcpy(to->user_name, from->user_name); +}; + +void copy_nt_sec_creds(CREDS_NT_SEC *to, const CREDS_NT_SEC *from) +{ + if (from == NULL) + { + ZERO_STRUCTP(to); + return; + } + sid_copy(&to->sid, &from->sid); + to->num_grps = 0; + to->grp_rids = NULL; + + if (from->num_grps != 0) + { + size_t size = from->num_grps * sizeof(from->grp_rids[0]); + to->grp_rids = (uint32*)malloc(size); + if (to->grp_rids == NULL) + { + return; + } + to->num_grps = from->num_grps; + memcpy(to->grp_rids, from->grp_rids, size); + } +}; + +void copy_unix_sec_creds(CREDS_UNIX_SEC *to, const CREDS_UNIX_SEC *from) +{ + if (from == NULL) + { + to->uid = -1; + to->gid = -1; + to->num_grps = 0; + to->grps = NULL; + return; + } + to->uid = from->uid; + to->gid = from->gid; + to->num_grps = 0; + to->grps = NULL; + + if (from->num_grps != 0) + { + size_t size = from->num_grps * sizeof(from->grps[0]); + to->grps = (uint32*)malloc(size); + if (to->grps == NULL) + { + return; + } + to->num_grps = from->num_grps; + memcpy(to->grps, from->grps, size); + } +}; + +void copy_nt_creds(struct ntuser_creds *to, + const struct ntuser_creds *from) +{ + if (from == NULL) + { + DEBUG(10,("copy_nt_creds: null creds\n")); + to->domain[0] = 0; + to->user_name[0] = 0; + pwd_set_nullpwd(&to->pwd); + to->ntlmssp_flags = 0; + + return; + } + safe_strcpy(to->domain , from->domain , sizeof(from->domain )-1); + safe_strcpy(to->user_name, from->user_name, sizeof(from->user_name)-1); + memcpy(&to->pwd, &from->pwd, sizeof(from->pwd)); + to->ntlmssp_flags = from->ntlmssp_flags; +}; + +void copy_user_creds(struct user_creds *to, + const struct user_creds *from) +{ + ZERO_STRUCTP(to); + if (from == NULL) + { + to->ptr_ntc = 0; + to->ptr_uxc = 0; + to->ptr_nts = 0; + to->ptr_uxs = 0; + copy_nt_creds(&to->ntc, NULL); + copy_unix_creds(&to->uxc, NULL); + copy_nt_sec_creds(&to->nts, NULL); + copy_unix_sec_creds(&to->uxs, NULL); + to->reuse = False; + return; + } + to->ptr_nts = from->ptr_nts; + to->ptr_uxs = from->ptr_uxs; + to->ptr_ntc = from->ptr_ntc; + to->ptr_uxc = from->ptr_uxc; + if (to->ptr_ntc != 0) + { + copy_nt_creds(&to->ntc, &from->ntc); + } + if (to->ptr_uxc != 0) + { + copy_unix_creds(&to->uxc, &from->uxc); + } + if (to->ptr_nts != 0) + { + copy_nt_sec_creds(&to->nts, &from->nts); + } + if (to->ptr_uxs != 0) + { + copy_unix_sec_creds(&to->uxs, &from->uxs); + } + to->reuse = from->reuse; +}; + +void free_user_creds(struct user_creds *creds) +{ + creds_free_unix(&creds->uxc); + creds_free_nt (&creds->ntc); + creds_free_unix_sec(&creds->uxs); + creds_free_nt_sec (&creds->nts); +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ +BOOL creds_io_cmd(char *desc, CREDS_CMD *r_u, prs_struct *ps, int depth) +{ + if (r_u == NULL) return False; + + prs_debug(ps, depth, desc, "creds_io_cmd"); + depth++; + + prs_align(ps); + + prs_uint16("version", ps, depth, &(r_u->version)); + prs_uint16("command", ps, depth, &(r_u->command)); + + prs_string("name ", ps, depth, r_u->name, strlen(r_u->name), sizeof(r_u->name)); + prs_align(ps); + + prs_uint32("ptr_creds", ps, depth, &(r_u->ptr_creds)); + if (r_u->ptr_creds != 0) + { + if (!creds_io_hybrid("creds", r_u->cred, ps, depth)) + { + return False; + } + } + + + return True; +} + + +BOOL create_ntuser_creds( prs_struct *ps, + const char* name, + uint16 version, uint16 command, + const struct ntuser_creds *ntu, + BOOL reuse) +{ + CREDS_CMD cmd; + struct user_creds usr; + + ZERO_STRUCT(cmd); + ZERO_STRUCT(usr); + + DEBUG(10,("create_user_creds: %s %d %d\n", + name, version, command)); + + usr.reuse = reuse; + + fstrcpy(cmd.name, name); + cmd.version = version; + cmd.command = command; + cmd.ptr_creds = ntu != NULL ? 1 : 0; + cmd.cred = &usr; + + if (ntu != NULL) + { + copy_nt_creds(&usr.ntc, ntu); + usr.ptr_ntc = 1; + } + else + { + usr.ptr_ntc = 0; + } + + prs_init(ps, 1024, 4, False); + + ps->data_offset = 4; + return creds_io_cmd("creds", &cmd, ps, 0); +} + +BOOL create_user_creds( prs_struct *ps, + const char* name, + uint16 version, uint16 command, + const struct user_creds *usr) +{ + CREDS_CMD cmd; + + ZERO_STRUCT(cmd); + + DEBUG(10,("create_user_creds: %s %d %d\n", + name, version, command)); + + fstrcpy(cmd.name, name); + cmd.version = version; + cmd.command = command; + cmd.ptr_creds = usr != NULL ? 1 : 0; + cmd.cred = usr; + + prs_init(ps, 1024, 4, False); + + ps->data_offset = 4; + return creds_io_cmd("creds", &cmd, ps, 0); +} diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c index f5f4eb67b8..6bb07c5f64 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/rpc_parse/parse_prs.c @@ -64,6 +64,30 @@ BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io) return True; } +/******************************************************************* + read from a socket into memory. + ********************************************************************/ +BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout) +{ + BOOL ok; + size_t prev_size = ps->buffer_size; + if (!prs_grow(ps, len)) + { + return False; + } + + if (timeout > 0) + { + ok = (read_with_timeout(fd, &ps->data_p[prev_size], + len, len,timeout) == len); + } + else + { + ok = (read_data(fd, &ps->data_p[prev_size], len) == len); + } + return ok; +} + /******************************************************************* Delete the memory in a parse structure - if we own it. ********************************************************************/ diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 236558ba70..98c3e90c06 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -1,3 +1,4 @@ + /* * Unix SMB/Netbios implementation. * Version 1.9. @@ -5,7 +6,6 @@ * Copyright (C) Andrew Tridgell 1992-1998 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, * Copyright (C) Paul Ashton 1997-1998. - * Copyright (C) Jeremy Allison 1999. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,1035 +43,78 @@ extern int DEBUGLEVEL; -static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len) -{ - unsigned char *hash = p->ntlmssp_hash; - unsigned char index_i = hash[256]; - unsigned char index_j = hash[257]; - int ind; - - for( ind = 0; ind < len; ind++) { - unsigned char tc; - unsigned char t; - - index_i++; - index_j += hash[index_i]; - - tc = hash[index_i]; - hash[index_i] = hash[index_j]; - hash[index_j] = tc; - - t = hash[index_i] + hash[index_j]; - data[ind] = data[ind] ^ hash[t]; - } - - hash[256] = index_i; - hash[257] = index_j; -} - /******************************************************************* - Generate the next PDU to be returned from the data in p->rdata. - We cheat here as this function doesn't handle the special auth - footers of the authenticated bind response reply. + entry point from msrpc to smb. adds data received to pdu; checks + pdu; hands pdu off to msrpc, which gets a pdu back (except in the + case of the RPC_BINDCONT pdu). ********************************************************************/ - -BOOL create_next_pdu(pipes_struct *p) -{ - RPC_HDR_RESP hdr_resp; - BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SIGN); - BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SEAL); - uint32 data_len; - uint32 data_space_available; - uint32 data_len_left; - prs_struct outgoing_pdu; - char *data; - char *data_from; - uint32 data_pos; - - memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); - - /* Change the incoming request header to a response. */ - p->hdr.pkt_type = RPC_RESPONSE; - - /* Set up rpc header flags. */ - if (p->data_sent_length == 0) - p->hdr.flags = RPC_FLG_FIRST; - else - p->hdr.flags = 0; - - /* - * Work out how much we can fit in a sigle PDU. - */ - - data_space_available = sizeof(p->current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; - if(p->ntlmssp_auth_validated) - data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN); - - /* - * The amount we send is the minimum of the available - * space and the amount left to send. - */ - - data_len_left = prs_offset(&p->rdata) - p->data_sent_length; - - /* - * Ensure there really is data left to send. - */ - - if(!data_len_left) { - DEBUG(0,("create_next_pdu: no data left to send !\n")); - return False; - } - - data_len = MIN(data_len_left, data_space_available); - - /* - * Set up the alloc hint. This should be the data left to - * send. - */ - - hdr_resp.alloc_hint = data_len_left; - - /* - * Set up the header lengths. - */ - - if (p->ntlmssp_auth_validated) { - p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + - RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN; - p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN; - } else { - p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len; - p->hdr.auth_len = 0; - } - - /* - * Work out if this PDU will be the last. - */ - - if(p->data_sent_length + data_len >= prs_offset(&p->rdata)) - p->hdr.flags |= RPC_FLG_LAST; - - /* - * Init the parse struct to point at the outgoing - * data. - */ - - prs_init( &outgoing_pdu, 0, 4, MARSHALL); - prs_give_memory( &outgoing_pdu, (char *)p->current_pdu, sizeof(p->current_pdu), False); - - /* Store the header in the data stream. */ - if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) { - DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR.\n")); - return False; - } - - if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) { - DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_RESP.\n")); - return False; - } - - /* Store the current offset. */ - data_pos = prs_offset(&outgoing_pdu); - - /* Copy the data into the PDU. */ - data_from = prs_data_p(&p->rdata) + p->data_sent_length; - - if(!prs_append_data(&outgoing_pdu, data_from, data_len)) { - DEBUG(0,("create_next_pdu: failed to copy %u bytes of data.\n", (unsigned int)data_len)); - return False; - } - - /* - * Set data to point to where we copied the data into. - */ - - data = prs_data_p(&outgoing_pdu) + data_pos; - - if (p->hdr.auth_len > 0) { - uint32 crc32 = 0; - - DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n", - BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, p->hdr.auth_len)); - - if (auth_seal) { - crc32 = crc32_calc_buffer(data, data_len); - NTLMSSPcalc_p(p, (uchar*)data, data_len); - } - - if (auth_seal || auth_verify) { - RPC_HDR_AUTH auth_info; - - init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, - (auth_verify ? RPC_HDR_AUTH_LEN : 0), (auth_verify ? 1 : 0)); - if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) { - DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n")); - return False; - } - } - - if (auth_verify) { - RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; - char *auth_data = prs_data_p(&outgoing_pdu); - - p->ntlmssp_seq_num++; - init_rpc_auth_ntlmssp_chk(&ntlmssp_chk, NTLMSSP_SIGN_VERSION, - crc32, p->ntlmssp_seq_num++); - auth_data = prs_data_p(&outgoing_pdu) + prs_offset(&outgoing_pdu) + 4; - if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, &outgoing_pdu, 0)) { - DEBUG(0,("create_next_pdu: failed to marshall RPC_AUTH_NTLMSSP_CHK.\n")); - return False; - } - NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4); - } - } - - /* - * Setup the counts for this PDU. - */ - - p->data_sent_length += data_len; - p->current_pdu_len = p->hdr.frag_len; - p->current_pdu_sent = 0; - - return True; -} - -/******************************************************************* - Process an NTLMSSP authentication response. - If this function succeeds, the user has been authenticated - and their domain, name and calling workstation stored in - the pipe struct. - The initial challenge is stored in p->challenge. - *******************************************************************/ - -static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlmssp_resp) +BOOL readwrite_pipe(pipes_struct *p, char *data, int len, + char **rdata, int *rlen) { - uchar lm_owf[24]; - uchar nt_owf[24]; - fstring user_name; - fstring unix_user_name; - fstring domain; - fstring wks; - BOOL guest_user = False; - struct smb_passwd *smb_pass = NULL; - struct passwd *pass = NULL; - uchar null_smb_passwd[16]; - uchar *smb_passwd_ptr = NULL; - - DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n")); - - memset(p->user_name, '\0', sizeof(p->user_name)); - memset(p->unix_user_name, '\0', sizeof(p->unix_user_name)); - memset(p->domain, '\0', sizeof(p->domain)); - memset(p->wks, '\0', sizeof(p->wks)); - - /* - * Setup an empty password for a guest user. - */ - - memset(null_smb_passwd,0,16); - - /* - * We always negotiate UNICODE. - */ - - if (IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_UNICODE)) { - fstrcpy(user_name, dos_unistrn2((uint16*)ntlmssp_resp->user, ntlmssp_resp->hdr_usr.str_str_len/2)); - fstrcpy(domain, dos_unistrn2((uint16*)ntlmssp_resp->domain, ntlmssp_resp->hdr_domain.str_str_len/2)); - fstrcpy(wks, dos_unistrn2((uint16*)ntlmssp_resp->wks, ntlmssp_resp->hdr_wks.str_str_len/2)); - } else { - fstrcpy(user_name, ntlmssp_resp->user); - fstrcpy(domain, ntlmssp_resp->domain); - fstrcpy(wks, ntlmssp_resp->wks); - } - - DEBUG(5,("user: %s domain: %s wks: %s\n", user_name, domain, wks)); - - memcpy(lm_owf, ntlmssp_resp->lm_resp, sizeof(lm_owf)); - memcpy(nt_owf, ntlmssp_resp->nt_resp, sizeof(nt_owf)); - -#ifdef DEBUG_PASSWORD - DEBUG(100,("lm, nt owfs, chal\n")); - dump_data(100, (char *)lm_owf, sizeof(lm_owf)); - dump_data(100, (char *)nt_owf, sizeof(nt_owf)); - dump_data(100, (char *)p->challenge, 8); -#endif - - /* - * Allow guest access. Patch from Shirish Kalele . - */ - - if((strlen(user_name) == 0) && (ntlmssp_resp->hdr_lm_resp.str_str_len==0) && - (ntlmssp_resp->hdr_nt_resp.str_str_len==0)) { - - guest_user = True; - - fstrcpy(unix_user_name, lp_guestaccount(-1)); - DEBUG(100,("Null user in NTLMSSP verification. Using guest = %s\n", unix_user_name)); - - smb_passwd_ptr = null_smb_passwd; - - } else { - - /* - * Pass the user through the NT -> unix user mapping - * function. - */ - - fstrcpy(unix_user_name, user_name); - (void)map_username(unix_user_name); - - /* - * Do the length checking only if user is not NULL. - */ - - if (ntlmssp_resp->hdr_lm_resp.str_str_len == 0) - return False; - if (ntlmssp_resp->hdr_nt_resp.str_str_len == 0) - return False; - if (ntlmssp_resp->hdr_usr.str_str_len == 0) - return False; - if (ntlmssp_resp->hdr_domain.str_str_len == 0) - return False; - if (ntlmssp_resp->hdr_wks.str_str_len == 0) - return False; - - } - - /* - * Find the user in the unix password db. - */ - - if(!(pass = Get_Pwnam(unix_user_name,True))) { - DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",unix_user_name)); - return(False); - } - - if(!guest_user) { - - become_root(True); - - if(!(p->ntlmssp_auth_validated = pass_check_smb(unix_user_name, domain, - (uchar*)p->challenge, lm_owf, nt_owf, NULL))) { - DEBUG(1,("api_pipe_ntlmssp_verify: User %s\\%s from machine %s \ -failed authentication on named pipe %s.\n", domain, unix_user_name, wks, p->name )); - unbecome_root(True); - return False; - } - - if(!(smb_pass = getsmbpwnam(unix_user_name))) { - DEBUG(1,("api_pipe_ntlmssp_verify: Cannot find user %s in smb passwd database.\n", - unix_user_name)); - unbecome_root(True); - return False; - } - - unbecome_root(True); - - if (smb_pass == NULL) { - DEBUG(1,("api_pipe_ntlmssp_verify: Couldn't find user '%s' in smb_passwd file.\n", - unix_user_name)); - return(False); - } - - /* Quit if the account was disabled. */ - if((smb_pass->acct_ctrl & ACB_DISABLED) || !smb_pass->smb_passwd) { - DEBUG(1,("Account for user '%s' was disabled.\n", unix_user_name)); - return(False); - } - - if(!smb_pass->smb_nt_passwd) { - DEBUG(1,("Account for user '%s' has no NT password hash.\n", unix_user_name)); - return(False); - } - - smb_passwd_ptr = smb_pass->smb_passwd; - } - - /* - * Set up the sign/seal data. - */ + DEBUG(10,("rpc_to_smb_readwrite: len %d\n", len)); + if (write(p->m->fd, data, len) != len) { - uchar p24[24]; - NTLMSSPOWFencrypt(smb_passwd_ptr, lm_owf, p24); - { - unsigned char j = 0; - int ind; - - unsigned char k2[8]; - - memcpy(k2, p24, 5); - k2[5] = 0xe5; - k2[6] = 0x38; - k2[7] = 0xb0; - - for (ind = 0; ind < 256; ind++) - p->ntlmssp_hash[ind] = (unsigned char)ind; - - for( ind = 0; ind < 256; ind++) { - unsigned char tc; - - j += (p->ntlmssp_hash[ind] + k2[ind%8]); - - tc = p->ntlmssp_hash[ind]; - p->ntlmssp_hash[ind] = p->ntlmssp_hash[j]; - p->ntlmssp_hash[j] = tc; - } - - p->ntlmssp_hash[256] = 0; - p->ntlmssp_hash[257] = 0; - } -/* NTLMSSPhash(p->ntlmssp_hash, p24); */ - p->ntlmssp_seq_num = 0; - - } - - fstrcpy(p->user_name, user_name); - fstrcpy(p->unix_user_name, unix_user_name); - fstrcpy(p->domain, domain); - fstrcpy(p->wks, wks); - - /* - * Store the UNIX credential data (uid/gid pair) in the pipe structure. - */ - - p->uid = pass->pw_uid; - p->gid = pass->pw_gid; - - p->ntlmssp_auth_validated = True; - return True; -} - -/******************************************************************* - The switch table for the pipe names and the functions to handle them. - *******************************************************************/ - -struct api_cmd -{ - char * pipe_clnt_name; - char * pipe_srv_name; - BOOL (*fn) (pipes_struct *, prs_struct *); -}; - -static struct api_cmd api_fd_commands[] = -{ - { "lsarpc", "lsass", api_ntlsa_rpc }, - { "samr", "lsass", api_samr_rpc }, - { "srvsvc", "ntsvcs", api_srvsvc_rpc }, - { "wkssvc", "ntsvcs", api_wkssvc_rpc }, - { "NETLOGON", "lsass", api_netlog_rpc }, -#if DISABLED_IN_2_0 - { "winreg", "winreg", api_reg_rpc }, -#endif - { NULL, NULL, NULL } -}; - -/******************************************************************* - This is the client reply to our challenge for an authenticated - bind request. The challenge we sent is in p->challenge. -*******************************************************************/ - -static BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *pd) -{ - RPC_HDR_AUTHA autha_info; - RPC_AUTH_VERIFIER auth_verifier; - RPC_AUTH_NTLMSSP_RESP ntlmssp_resp; - - DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__)); - - if (p->hdr.auth_len == 0) { - DEBUG(0,("api_pipe_bind_auth_resp: No auth field sent !\n")); - return False; - } - - /* - * Decode the authentication verifier response. - */ - - if(!smb_io_rpc_hdr_autha("", &autha_info, pd, 0)) { - DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_HDR_AUTHA failed.\n")); - return False; - } - - if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != NTLMSSP_AUTH_LEVEL) { - DEBUG(0,("api_pipe_bind_auth_resp: incorrect auth type (%d) or level (%d).\n", - (int)autha_info.auth_type, (int)autha_info.auth_level )); return False; } - if(!smb_io_rpc_auth_verifier("", &auth_verifier, pd, 0)) { - DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_AUTH_VERIFIER failed.\n")); - return False; - } - - /* - * Ensure this is a NTLMSSP_AUTH packet type. - */ - - if (!rpc_auth_verifier_chk(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH)) { - DEBUG(0,("api_pipe_bind_auth_resp: rpc_auth_verifier_chk failed.\n")); - return False; - } - - if(!smb_io_rpc_auth_ntlmssp_resp("", &ntlmssp_resp, pd, 0)) { - DEBUG(0,("api_pipe_bind_auth_resp: Failed to unmarshall RPC_AUTH_NTLMSSP_RESP.\n")); - return False; - } - - /* - * The following call actually checks the challenge/response data. - * for correctness against the given DOMAIN\user name. - */ - - if (!api_pipe_ntlmssp_verify(p, &ntlmssp_resp)) - return False; - - return True; -} - -/******************************************************************* - Marshall a bind_nak pdu. -*******************************************************************/ - -static BOOL setup_bind_nak(pipes_struct *p, prs_struct *pd) -{ - prs_struct outgoing_rpc; - RPC_HDR nak_hdr; - uint16 zero = 0; - - /* - * Marshall directly into the outgoing PDU space. We - * must do this as we need to set to the bind response - * header and are never sending more than one PDU here. - */ - - prs_init( &outgoing_rpc, 0, 4, MARSHALL); - prs_give_memory( &outgoing_rpc, (char *)p->current_pdu, sizeof(p->current_pdu), False); - - - /* - * Initialize a bind_nak header. - */ - - init_rpc_hdr(&nak_hdr, RPC_BINDNACK, RPC_FLG_FIRST | RPC_FLG_LAST, - p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0); - - /* - * Marshall the header into the outgoing PDU. - */ - - if(!smb_io_rpc_hdr("", &nak_hdr, &outgoing_rpc, 0)) { - DEBUG(0,("setup_bind_nak: marshalling of RPC_HDR failed.\n")); + if ((*rlen) == 0) + { return False; } - /* - * Now add the reject reason. - */ - - if(!prs_uint16("reject code", &outgoing_rpc, 0, &zero)) - return False; - - p->data_sent_length = 0; - p->current_pdu_len = prs_offset(&outgoing_rpc); - p->current_pdu_sent = 0; - - return True; -} - -/******************************************************************* - Respond to a pipe bind request. -*******************************************************************/ - -static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd) -{ - RPC_HDR_BA hdr_ba; - RPC_HDR_RB hdr_rb; - RPC_HDR_AUTH auth_info; - uint16 assoc_gid; - fstring ack_pipe_name; - prs_struct out_hdr_ba; - prs_struct out_auth; - prs_struct outgoing_rpc; - int i = 0; - int auth_len = 0; - - p->ntlmssp_auth_requested = False; - - DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__)); - - /* - * Try and find the correct pipe name to ensure - * that this is a pipe name we support. - */ - - for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) { - if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && - api_fd_commands[i].fn != NULL) { - DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n", - api_fd_commands[i].pipe_clnt_name, - api_fd_commands[i].pipe_srv_name)); - fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name); - break; - } - } - - if (api_fd_commands[i].fn == NULL) { - DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n", - p->name )); - if(!setup_bind_nak(p, pd)) - return False; - return True; - } - - /* decode the bind request */ - if(!smb_io_rpc_hdr_rb("", &hdr_rb, pd, 0)) { - DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_RB struct.\n")); + (*rdata) = (char*)Realloc((*rdata), (*rlen)); + if ((*rdata) == NULL) + { return False; } - - /* - * Check if this is an authenticated request. - */ - - if (p->hdr.auth_len != 0) { - RPC_AUTH_VERIFIER auth_verifier; - RPC_AUTH_NTLMSSP_NEG ntlmssp_neg; - - /* - * Decode the authentication verifier. - */ - - if(!smb_io_rpc_hdr_auth("", &auth_info, pd, 0)) { - DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n")); - return False; - } - - /* - * We only support NTLMSSP_AUTH_TYPE requests. - */ - - if(auth_info.auth_type != NTLMSSP_AUTH_TYPE) { - DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n", - auth_info.auth_type )); - return False; - } - - if(!smb_io_rpc_auth_verifier("", &auth_verifier, pd, 0)) { - DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n")); - return False; - } - - if(!strequal(auth_verifier.signature, "NTLMSSP")) { - DEBUG(0,("api_pipe_bind_req: auth_verifier.signature != NTLMSSP\n")); - return False; - } - - if(auth_verifier.msg_type != NTLMSSP_NEGOTIATE) { - DEBUG(0,("api_pipe_bind_req: auth_verifier.msg_type (%d) != NTLMSSP_NEGOTIATE\n", - auth_verifier.msg_type)); - return False; - } - - if(!smb_io_rpc_auth_ntlmssp_neg("", &ntlmssp_neg, pd, 0)) { - DEBUG(0,("api_pipe_bind_req: Failed to unmarshall RPC_AUTH_NTLMSSP_NEG.\n")); - return False; - } - - p->ntlmssp_chal_flags = SMBD_NTLMSSP_NEG_FLAGS; - p->ntlmssp_auth_requested = True; - } - - /* name has to be \PIPE\xxxxx */ - fstrcpy(ack_pipe_name, "\\PIPE\\"); - fstrcat(ack_pipe_name, p->pipe_srv_name); - - DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__)); - - /* - * Marshall directly into the outgoing PDU space. We - * must do this as we need to set to the bind response - * header and are never sending more than one PDU here. - */ - - prs_init( &outgoing_rpc, 0, 4, MARSHALL); - prs_give_memory( &outgoing_rpc, (char *)p->current_pdu, sizeof(p->current_pdu), False); - - /* - * Setup the memory to marshall the ba header, and the - * auth footers. - */ - - if(!prs_init(&out_hdr_ba, 1024, 4, MARSHALL)) { - DEBUG(0,("api_pipe_bind_req: malloc out_hdr_ba failed.\n")); + (*rlen) = read(p->m->fd, (*rdata), (*rlen)); + if ((*rlen) < 0) + { return False; } - - if(!prs_init(&out_auth, 1024, 4, MARSHALL)) { - DEBUG(0,("pi_pipe_bind_req: malloc out_auth failed.\n")); - prs_mem_free(&out_hdr_ba); + (*rdata) = (char*)Realloc((*rdata), (*rlen)); + if ((*rdata) == NULL) + { return False; } - - if (p->ntlmssp_auth_requested) - assoc_gid = 0x7a77; - else - assoc_gid = hdr_rb.bba.assoc_gid; - - /* - * Create the bind response struct. - */ - - init_rpc_hdr_ba(&hdr_ba, - hdr_rb.bba.max_tsize, - hdr_rb.bba.max_rsize, - assoc_gid, - ack_pipe_name, - 0x1, 0x0, 0x0, - &hdr_rb.transfer); - - /* - * and marshall it. - */ - - if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) { - DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n")); - goto err_exit; - } - - /* - * Now the authentication. - */ - - if (p->ntlmssp_auth_requested) { - RPC_AUTH_VERIFIER auth_verifier; - RPC_AUTH_NTLMSSP_CHAL ntlmssp_chal; - - generate_random_buffer(p->challenge, 8, False); - - /*** Authentication info ***/ - - init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1); - if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) { - DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n")); - goto err_exit; - } - - /*** NTLMSSP verifier ***/ - - init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_CHALLENGE); - if(!smb_io_rpc_auth_verifier("", &auth_verifier, &out_auth, 0)) { - DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_VERIFIER failed.\n")); - goto err_exit; - } - - /* NTLMSSP challenge ***/ - - init_rpc_auth_ntlmssp_chal(&ntlmssp_chal, p->ntlmssp_chal_flags, p->challenge); - if(!smb_io_rpc_auth_ntlmssp_chal("", &ntlmssp_chal, &out_auth, 0)) { - DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_NTLMSSP_CHAL failed.\n")); - goto err_exit; - } - - /* Auth len in the rpc header doesn't include auth_header. */ - auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN; - } - - /* - * Create the header, now we know the length. - */ - - init_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST, - p->hdr.call_id, - RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth), - auth_len); - - /* - * Marshall the header into the outgoing PDU. - */ - - if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) { - DEBUG(0,("pi_pipe_bind_req: marshalling of RPC_HDR failed.\n")); - goto err_exit; - } - - /* - * Now add the RPC_HDR_BA and any auth needed. - */ - - if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) { - DEBUG(0,("api_pipe_bind_req: append of RPC_HDR_BA failed.\n")); - goto err_exit; - } - - if(p->ntlmssp_auth_requested && !prs_append_prs_data( &outgoing_rpc, &out_auth)) { - DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n")); - goto err_exit; - } - - /* - * Setup the lengths for the initial reply. - */ - - p->data_sent_length = 0; - p->current_pdu_len = prs_offset(&outgoing_rpc); - p->current_pdu_sent = 0; - - prs_mem_free(&out_hdr_ba); - prs_mem_free(&out_auth); - return True; - - err_exit: - - prs_mem_free(&out_hdr_ba); - prs_mem_free(&out_auth); - return False; } /**************************************************************************** - Deal with sign & seal processing on an RPC request. -****************************************************************************/ - -static BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in) + writes data to a pipe. + ****************************************************************************/ +ssize_t write_pipe(pipes_struct *p, char *data, size_t n) { - /* - * We always negotiate the following two bits.... - */ - BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SIGN); - BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SEAL); - int data_len; - int auth_len; - uint32 old_offset; - uint32 crc32 = 0; - - auth_len = p->hdr.auth_len; + DEBUG(6,("write_pipe: %x", p->pnum)); + DEBUG(6,("name: %s open: %s len: %d", + p->name, BOOLSTR(p->open), n)); - if ((auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) && auth_verify) { - DEBUG(0,("api_pipe_auth_process: Incorrect auth_len %d.\n", auth_len )); - return False; - } - - /* - * The following is that length of the data we must verify or unseal. - * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN - * preceeding the auth_data. - */ - - data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - - (auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len; - - DEBUG(5,("api_pipe_auth_process: sign: %s seal: %s data %d auth %d\n", - BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len)); - - if (auth_seal) { - char *data = prs_data_p(rpc_in) + RPC_HEADER_LEN + RPC_HDR_REQ_LEN; - NTLMSSPcalc_p(p, (uchar*)data, data_len); - crc32 = crc32_calc_buffer(data, data_len); - } - - old_offset = prs_offset(rpc_in); - - if (auth_seal || auth_verify) { - RPC_HDR_AUTH auth_info; - - if(!prs_set_offset(rpc_in, old_offset + data_len)) { - DEBUG(0,("api_pipe_auth_process: cannot move offset to %u.\n", - (unsigned int)old_offset + data_len )); - return False; - } - - if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) { - DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_HDR_AUTH.\n")); - return False; - } - } + dump_data(50, data, n); - if (auth_verify) { - RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; - char *req_data = prs_data_p(rpc_in) + prs_offset(rpc_in) + 4; - - DEBUG(5,("api_pipe_auth_process: auth %d\n", prs_offset(rpc_in) + 4)); - - /* - * Ensure we have RPC_AUTH_NTLMSSP_CHK_LEN - 4 more bytes in the - * incoming buffer. - */ - if(prs_mem_get(rpc_in, RPC_AUTH_NTLMSSP_CHK_LEN - 4) == NULL) { - DEBUG(0,("api_pipe_auth_process: missing %d bytes in buffer.\n", - RPC_AUTH_NTLMSSP_CHK_LEN - 4 )); - return False; - } - - NTLMSSPcalc_p(p, (uchar*)req_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4); - if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, rpc_in, 0)) { - DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_AUTH_NTLMSSP_CHK.\n")); - return False; - } - - if (!rpc_auth_ntlmssp_chk(&ntlmssp_chk, crc32, p->ntlmssp_seq_num)) { - DEBUG(0,("api_pipe_auth_process: NTLMSSP check failed.\n")); - return False; - } - } - - /* - * Return the current pointer to the data offset. - */ - - if(!prs_set_offset(rpc_in, old_offset)) { - DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n", - (unsigned int)old_offset )); - return False; - } - - return True; + return write(p->m->fd, data, n); } -/**************************************************************************** - Find the correct RPC function to call for this request. - If the pipe is authenticated then become the correct UNIX user - before doing the call. -****************************************************************************/ - -static BOOL api_pipe_request(pipes_struct *p, prs_struct *rpc_in) -{ - int i = 0; - BOOL ret = False; - BOOL changed_user_id = False; - - if (p->ntlmssp_auth_validated) { - if (!api_pipe_auth_process(p, rpc_in)) - return False; - - if(!become_authenticated_pipe_user(p)) - return False; - - changed_user_id = True; - } - - for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) { - if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && - api_fd_commands[i].fn != NULL) { - DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name)); - ret = api_fd_commands[i].fn(p, rpc_in); - } - } - - if(changed_user_id) - unbecome_authenticated_pipe_user(p); - - return ret; -} /**************************************************************************** - This function is the entry point to processing a DCE/RPC request. - All the data for the request (including RPC headers and authentication - verifiers) must be linearized in the input_data buffer, with a length - of data_len. + reads data from a pipe. - The output is placed into the pipes_struct, and handed back to the - client on demand. -****************************************************************************/ + headers are interspersed with the data at regular intervals. by the time + this function is called, the start of the data could possibly have been + read by an SMBtrans (file_offset != 0). -BOOL rpc_command(pipes_struct *p, char *input_data, int data_len) + ****************************************************************************/ +int read_pipe(pipes_struct *p, char *data, int n) { - prs_struct rpc_in; - BOOL reply = False; - - if (input_data == NULL) - return False; - - prs_init(&rpc_in, 0, 4, UNMARSHALL); - - /* - * Hand the data to the prs_struct, but don't let - * it own it. - */ - prs_give_memory( &rpc_in, input_data, (uint32)data_len, False); + DEBUG(6,("read_pipe: %x name: %s open: %s len: %d", + p->pnum, p->name, BOOLSTR(p->open), n)); - /* Unmarshall the rpc header */ - if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { - DEBUG(0,("rpc_command: failed to unmarshall RPC_HDR.\n")); - return False; - } - - /* - * Create the response data buffer. - */ - - if(!pipe_init_outgoing_data(p)) { - DEBUG(0,("rpc_command: failed to unmarshall RPC_HDR.\n")); - return False; - } - - switch (p->hdr.pkt_type) { - case RPC_BIND: - reply = api_pipe_bind_req(p, &rpc_in); - break; - case RPC_REQUEST: - if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) { - /* authentication _was_ requested - and it failed. sorry, no deal! - */ - DEBUG(0,("rpc_command: RPC request received on pipe %s where \ -authentication failed. Denying the request.\n", p->name)); - reply = False; - } else { - /* read the RPC request header */ - if(!smb_io_rpc_hdr_req("req", &p->hdr_req, &rpc_in, 0)) { - DEBUG(0,("rpc_command: failed to unmarshall RPC_HDR_REQ.\n")); - return False; - } - reply = api_pipe_request(p, &rpc_in); - } - break; - case RPC_BINDRESP: /* not the real name! */ - reply = api_pipe_bind_auth_resp(p, &rpc_in); - break; + if (!p || !p->open) + { + DEBUG(6,("pipe not open\n")); + return -1; } - if (!reply) - DEBUG(3,("rpc_command: DCE/RPC fault should be sent here\n")); - - return reply; + return read(p->m->fd, data, n); } - -/******************************************************************* - Calls the underlying RPC function for a named pipe. - ********************************************************************/ - -BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, - prs_struct *rpc_in) -{ - int fn_num; - - /* interpret the command */ - DEBUG(4,("api_rpcTNP: %s op 0x%x - ", rpc_name, p->hdr_req.opnum)); - - for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++) { - if (api_rpc_cmds[fn_num].opnum == p->hdr_req.opnum && api_rpc_cmds[fn_num].fn != NULL) { - DEBUG(3,("api_rpc_command: %s\n", api_rpc_cmds[fn_num].name)); - break; - } - } - - if (api_rpc_cmds[fn_num].name == NULL) { - DEBUG(4, ("unknown\n")); - return False; - } - - /* do the actual command */ - if(!api_rpc_cmds[fn_num].fn(p->vuid, rpc_in, &p->rdata)) { - DEBUG(0,("api_rpcTNP: %s: failed.\n", rpc_name)); - prs_mem_free(&p->rdata); - return False; - } - - DEBUG(5,("api_rpcTNP: called %s successfully\n", rpc_name)); - - return True; -} diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index b21b768a6e..46beba6316 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -113,10 +113,44 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, int i; pipes_struct *p; static int next_pipe; + struct msrpc_state *m = NULL; + user_struct *vuser = get_valid_user_struct(vuid); + struct user_creds usr; + + ZERO_STRUCT(usr); DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n", pipe_name, pipes_open)); + if (vuser == NULL) + { + DEBUG(4,("invalid vuid %d\n", vuid)); + return NULL; + } + + /* set up unix credentials from the smb side, to feed over the pipe */ + make_creds_unix(&usr.uxc, vuser->name, vuser->requested_name, + vuser->real_name, vuser->guest); + usr.ptr_uxc = 1; + make_creds_unix_sec(&usr.uxs, vuser->uid, vuser->gid, + vuser->n_groups, vuser->groups); + usr.ptr_uxs = 1; + + /* set up nt credentials from the smb side, to feed over the pipe */ + /* lkclXXXX todo! + make_creds_nt(&usr.ntc); + make_creds_nt_sec(&usr.nts); + */ + + become_root(False); /* to connect to pipe */ + m = msrpc_use_add(pipe_name, &usr, False); + unbecome_root(False); + + if (m == NULL) + { + DEBUG(10,("open pipes: msrpc redirect failed - go local.\n")); + } + /* not repeating pipe numbers makes it easier to track things in log files and prevents client bugs where pipe numbers are reused over connection restarts */ @@ -160,6 +194,8 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, p->priority = 0; p->conn = conn; p->vuid = vuid; + + p->m = m; p->max_trans_reply = 0; @@ -201,7 +237,7 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n) { - DEBUG(6,("write_pipe: %x", p->pnum)); + DEBUG(6,("write_to_pipe: %x", p->pnum)); DEBUG(6,("name: %s open: %s len: %d", p->name, BOOLSTR(p->open), (int)n)); @@ -372,6 +408,19 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn) DEBUG(4,("closed pipe name %s pnum=%x (pipes_open=%d)\n", p->name, p->pnum, pipes_open)); + if (p->m != NULL) + { + DEBUG(4,("closed msrpc redirect: ")); + if (msrpc_use_del(p->m->pipe_name, &p->m->usr, False, NULL)) + { + DEBUG(4,("OK\n")); + } + else + { + DEBUG(4,("FAILED\n")); + } + } + DLIST_REMOVE(Pipes, p); ZERO_STRUCTP(p); diff --git a/source3/rpc_server/srv_pipe_srv.c b/source3/rpc_server/srv_pipe_srv.c new file mode 100644 index 0000000000..236558ba70 --- /dev/null +++ b/source3/rpc_server/srv_pipe_srv.c @@ -0,0 +1,1077 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, + * Copyright (C) Paul Ashton 1997-1998. + * Copyright (C) Jeremy Allison 1999. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this module apparently provides an implementation of DCE/RPC over a + * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC + * documentation are available (in on-line form) from the X-Open group. + * + * this module should provide a level of abstraction between SMB + * and DCE/RPC, while minimising the amount of mallocs, unnecessary + * data copies, and network traffic. + * + * in this version, which takes a "let's learn what's going on and + * get something running" approach, there is additional network + * traffic generated, but the code should be easier to understand... + * + * ... if you read the docs. or stare at packets for weeks on end. + * + */ + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len) +{ + unsigned char *hash = p->ntlmssp_hash; + unsigned char index_i = hash[256]; + unsigned char index_j = hash[257]; + int ind; + + for( ind = 0; ind < len; ind++) { + unsigned char tc; + unsigned char t; + + index_i++; + index_j += hash[index_i]; + + tc = hash[index_i]; + hash[index_i] = hash[index_j]; + hash[index_j] = tc; + + t = hash[index_i] + hash[index_j]; + data[ind] = data[ind] ^ hash[t]; + } + + hash[256] = index_i; + hash[257] = index_j; +} + +/******************************************************************* + Generate the next PDU to be returned from the data in p->rdata. + We cheat here as this function doesn't handle the special auth + footers of the authenticated bind response reply. + ********************************************************************/ + +BOOL create_next_pdu(pipes_struct *p) +{ + RPC_HDR_RESP hdr_resp; + BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SIGN); + BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SEAL); + uint32 data_len; + uint32 data_space_available; + uint32 data_len_left; + prs_struct outgoing_pdu; + char *data; + char *data_from; + uint32 data_pos; + + memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); + + /* Change the incoming request header to a response. */ + p->hdr.pkt_type = RPC_RESPONSE; + + /* Set up rpc header flags. */ + if (p->data_sent_length == 0) + p->hdr.flags = RPC_FLG_FIRST; + else + p->hdr.flags = 0; + + /* + * Work out how much we can fit in a sigle PDU. + */ + + data_space_available = sizeof(p->current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; + if(p->ntlmssp_auth_validated) + data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN); + + /* + * The amount we send is the minimum of the available + * space and the amount left to send. + */ + + data_len_left = prs_offset(&p->rdata) - p->data_sent_length; + + /* + * Ensure there really is data left to send. + */ + + if(!data_len_left) { + DEBUG(0,("create_next_pdu: no data left to send !\n")); + return False; + } + + data_len = MIN(data_len_left, data_space_available); + + /* + * Set up the alloc hint. This should be the data left to + * send. + */ + + hdr_resp.alloc_hint = data_len_left; + + /* + * Set up the header lengths. + */ + + if (p->ntlmssp_auth_validated) { + p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + + RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN; + p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN; + } else { + p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len; + p->hdr.auth_len = 0; + } + + /* + * Work out if this PDU will be the last. + */ + + if(p->data_sent_length + data_len >= prs_offset(&p->rdata)) + p->hdr.flags |= RPC_FLG_LAST; + + /* + * Init the parse struct to point at the outgoing + * data. + */ + + prs_init( &outgoing_pdu, 0, 4, MARSHALL); + prs_give_memory( &outgoing_pdu, (char *)p->current_pdu, sizeof(p->current_pdu), False); + + /* Store the header in the data stream. */ + if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) { + DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR.\n")); + return False; + } + + if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) { + DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_RESP.\n")); + return False; + } + + /* Store the current offset. */ + data_pos = prs_offset(&outgoing_pdu); + + /* Copy the data into the PDU. */ + data_from = prs_data_p(&p->rdata) + p->data_sent_length; + + if(!prs_append_data(&outgoing_pdu, data_from, data_len)) { + DEBUG(0,("create_next_pdu: failed to copy %u bytes of data.\n", (unsigned int)data_len)); + return False; + } + + /* + * Set data to point to where we copied the data into. + */ + + data = prs_data_p(&outgoing_pdu) + data_pos; + + if (p->hdr.auth_len > 0) { + uint32 crc32 = 0; + + DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n", + BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, p->hdr.auth_len)); + + if (auth_seal) { + crc32 = crc32_calc_buffer(data, data_len); + NTLMSSPcalc_p(p, (uchar*)data, data_len); + } + + if (auth_seal || auth_verify) { + RPC_HDR_AUTH auth_info; + + init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, + (auth_verify ? RPC_HDR_AUTH_LEN : 0), (auth_verify ? 1 : 0)); + if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) { + DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n")); + return False; + } + } + + if (auth_verify) { + RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; + char *auth_data = prs_data_p(&outgoing_pdu); + + p->ntlmssp_seq_num++; + init_rpc_auth_ntlmssp_chk(&ntlmssp_chk, NTLMSSP_SIGN_VERSION, + crc32, p->ntlmssp_seq_num++); + auth_data = prs_data_p(&outgoing_pdu) + prs_offset(&outgoing_pdu) + 4; + if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, &outgoing_pdu, 0)) { + DEBUG(0,("create_next_pdu: failed to marshall RPC_AUTH_NTLMSSP_CHK.\n")); + return False; + } + NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4); + } + } + + /* + * Setup the counts for this PDU. + */ + + p->data_sent_length += data_len; + p->current_pdu_len = p->hdr.frag_len; + p->current_pdu_sent = 0; + + return True; +} + +/******************************************************************* + Process an NTLMSSP authentication response. + If this function succeeds, the user has been authenticated + and their domain, name and calling workstation stored in + the pipe struct. + The initial challenge is stored in p->challenge. + *******************************************************************/ + +static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlmssp_resp) +{ + uchar lm_owf[24]; + uchar nt_owf[24]; + fstring user_name; + fstring unix_user_name; + fstring domain; + fstring wks; + BOOL guest_user = False; + struct smb_passwd *smb_pass = NULL; + struct passwd *pass = NULL; + uchar null_smb_passwd[16]; + uchar *smb_passwd_ptr = NULL; + + DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n")); + + memset(p->user_name, '\0', sizeof(p->user_name)); + memset(p->unix_user_name, '\0', sizeof(p->unix_user_name)); + memset(p->domain, '\0', sizeof(p->domain)); + memset(p->wks, '\0', sizeof(p->wks)); + + /* + * Setup an empty password for a guest user. + */ + + memset(null_smb_passwd,0,16); + + /* + * We always negotiate UNICODE. + */ + + if (IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_UNICODE)) { + fstrcpy(user_name, dos_unistrn2((uint16*)ntlmssp_resp->user, ntlmssp_resp->hdr_usr.str_str_len/2)); + fstrcpy(domain, dos_unistrn2((uint16*)ntlmssp_resp->domain, ntlmssp_resp->hdr_domain.str_str_len/2)); + fstrcpy(wks, dos_unistrn2((uint16*)ntlmssp_resp->wks, ntlmssp_resp->hdr_wks.str_str_len/2)); + } else { + fstrcpy(user_name, ntlmssp_resp->user); + fstrcpy(domain, ntlmssp_resp->domain); + fstrcpy(wks, ntlmssp_resp->wks); + } + + DEBUG(5,("user: %s domain: %s wks: %s\n", user_name, domain, wks)); + + memcpy(lm_owf, ntlmssp_resp->lm_resp, sizeof(lm_owf)); + memcpy(nt_owf, ntlmssp_resp->nt_resp, sizeof(nt_owf)); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("lm, nt owfs, chal\n")); + dump_data(100, (char *)lm_owf, sizeof(lm_owf)); + dump_data(100, (char *)nt_owf, sizeof(nt_owf)); + dump_data(100, (char *)p->challenge, 8); +#endif + + /* + * Allow guest access. Patch from Shirish Kalele . + */ + + if((strlen(user_name) == 0) && (ntlmssp_resp->hdr_lm_resp.str_str_len==0) && + (ntlmssp_resp->hdr_nt_resp.str_str_len==0)) { + + guest_user = True; + + fstrcpy(unix_user_name, lp_guestaccount(-1)); + DEBUG(100,("Null user in NTLMSSP verification. Using guest = %s\n", unix_user_name)); + + smb_passwd_ptr = null_smb_passwd; + + } else { + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + fstrcpy(unix_user_name, user_name); + (void)map_username(unix_user_name); + + /* + * Do the length checking only if user is not NULL. + */ + + if (ntlmssp_resp->hdr_lm_resp.str_str_len == 0) + return False; + if (ntlmssp_resp->hdr_nt_resp.str_str_len == 0) + return False; + if (ntlmssp_resp->hdr_usr.str_str_len == 0) + return False; + if (ntlmssp_resp->hdr_domain.str_str_len == 0) + return False; + if (ntlmssp_resp->hdr_wks.str_str_len == 0) + return False; + + } + + /* + * Find the user in the unix password db. + */ + + if(!(pass = Get_Pwnam(unix_user_name,True))) { + DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",unix_user_name)); + return(False); + } + + if(!guest_user) { + + become_root(True); + + if(!(p->ntlmssp_auth_validated = pass_check_smb(unix_user_name, domain, + (uchar*)p->challenge, lm_owf, nt_owf, NULL))) { + DEBUG(1,("api_pipe_ntlmssp_verify: User %s\\%s from machine %s \ +failed authentication on named pipe %s.\n", domain, unix_user_name, wks, p->name )); + unbecome_root(True); + return False; + } + + if(!(smb_pass = getsmbpwnam(unix_user_name))) { + DEBUG(1,("api_pipe_ntlmssp_verify: Cannot find user %s in smb passwd database.\n", + unix_user_name)); + unbecome_root(True); + return False; + } + + unbecome_root(True); + + if (smb_pass == NULL) { + DEBUG(1,("api_pipe_ntlmssp_verify: Couldn't find user '%s' in smb_passwd file.\n", + unix_user_name)); + return(False); + } + + /* Quit if the account was disabled. */ + if((smb_pass->acct_ctrl & ACB_DISABLED) || !smb_pass->smb_passwd) { + DEBUG(1,("Account for user '%s' was disabled.\n", unix_user_name)); + return(False); + } + + if(!smb_pass->smb_nt_passwd) { + DEBUG(1,("Account for user '%s' has no NT password hash.\n", unix_user_name)); + return(False); + } + + smb_passwd_ptr = smb_pass->smb_passwd; + } + + /* + * Set up the sign/seal data. + */ + + { + uchar p24[24]; + NTLMSSPOWFencrypt(smb_passwd_ptr, lm_owf, p24); + { + unsigned char j = 0; + int ind; + + unsigned char k2[8]; + + memcpy(k2, p24, 5); + k2[5] = 0xe5; + k2[6] = 0x38; + k2[7] = 0xb0; + + for (ind = 0; ind < 256; ind++) + p->ntlmssp_hash[ind] = (unsigned char)ind; + + for( ind = 0; ind < 256; ind++) { + unsigned char tc; + + j += (p->ntlmssp_hash[ind] + k2[ind%8]); + + tc = p->ntlmssp_hash[ind]; + p->ntlmssp_hash[ind] = p->ntlmssp_hash[j]; + p->ntlmssp_hash[j] = tc; + } + + p->ntlmssp_hash[256] = 0; + p->ntlmssp_hash[257] = 0; + } +/* NTLMSSPhash(p->ntlmssp_hash, p24); */ + p->ntlmssp_seq_num = 0; + + } + + fstrcpy(p->user_name, user_name); + fstrcpy(p->unix_user_name, unix_user_name); + fstrcpy(p->domain, domain); + fstrcpy(p->wks, wks); + + /* + * Store the UNIX credential data (uid/gid pair) in the pipe structure. + */ + + p->uid = pass->pw_uid; + p->gid = pass->pw_gid; + + p->ntlmssp_auth_validated = True; + return True; +} + +/******************************************************************* + The switch table for the pipe names and the functions to handle them. + *******************************************************************/ + +struct api_cmd +{ + char * pipe_clnt_name; + char * pipe_srv_name; + BOOL (*fn) (pipes_struct *, prs_struct *); +}; + +static struct api_cmd api_fd_commands[] = +{ + { "lsarpc", "lsass", api_ntlsa_rpc }, + { "samr", "lsass", api_samr_rpc }, + { "srvsvc", "ntsvcs", api_srvsvc_rpc }, + { "wkssvc", "ntsvcs", api_wkssvc_rpc }, + { "NETLOGON", "lsass", api_netlog_rpc }, +#if DISABLED_IN_2_0 + { "winreg", "winreg", api_reg_rpc }, +#endif + { NULL, NULL, NULL } +}; + +/******************************************************************* + This is the client reply to our challenge for an authenticated + bind request. The challenge we sent is in p->challenge. +*******************************************************************/ + +static BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *pd) +{ + RPC_HDR_AUTHA autha_info; + RPC_AUTH_VERIFIER auth_verifier; + RPC_AUTH_NTLMSSP_RESP ntlmssp_resp; + + DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__)); + + if (p->hdr.auth_len == 0) { + DEBUG(0,("api_pipe_bind_auth_resp: No auth field sent !\n")); + return False; + } + + /* + * Decode the authentication verifier response. + */ + + if(!smb_io_rpc_hdr_autha("", &autha_info, pd, 0)) { + DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_HDR_AUTHA failed.\n")); + return False; + } + + if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != NTLMSSP_AUTH_LEVEL) { + DEBUG(0,("api_pipe_bind_auth_resp: incorrect auth type (%d) or level (%d).\n", + (int)autha_info.auth_type, (int)autha_info.auth_level )); + return False; + } + + if(!smb_io_rpc_auth_verifier("", &auth_verifier, pd, 0)) { + DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_AUTH_VERIFIER failed.\n")); + return False; + } + + /* + * Ensure this is a NTLMSSP_AUTH packet type. + */ + + if (!rpc_auth_verifier_chk(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH)) { + DEBUG(0,("api_pipe_bind_auth_resp: rpc_auth_verifier_chk failed.\n")); + return False; + } + + if(!smb_io_rpc_auth_ntlmssp_resp("", &ntlmssp_resp, pd, 0)) { + DEBUG(0,("api_pipe_bind_auth_resp: Failed to unmarshall RPC_AUTH_NTLMSSP_RESP.\n")); + return False; + } + + /* + * The following call actually checks the challenge/response data. + * for correctness against the given DOMAIN\user name. + */ + + if (!api_pipe_ntlmssp_verify(p, &ntlmssp_resp)) + return False; + + return True; +} + +/******************************************************************* + Marshall a bind_nak pdu. +*******************************************************************/ + +static BOOL setup_bind_nak(pipes_struct *p, prs_struct *pd) +{ + prs_struct outgoing_rpc; + RPC_HDR nak_hdr; + uint16 zero = 0; + + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + + prs_init( &outgoing_rpc, 0, 4, MARSHALL); + prs_give_memory( &outgoing_rpc, (char *)p->current_pdu, sizeof(p->current_pdu), False); + + + /* + * Initialize a bind_nak header. + */ + + init_rpc_hdr(&nak_hdr, RPC_BINDNACK, RPC_FLG_FIRST | RPC_FLG_LAST, + p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0); + + /* + * Marshall the header into the outgoing PDU. + */ + + if(!smb_io_rpc_hdr("", &nak_hdr, &outgoing_rpc, 0)) { + DEBUG(0,("setup_bind_nak: marshalling of RPC_HDR failed.\n")); + return False; + } + + /* + * Now add the reject reason. + */ + + if(!prs_uint16("reject code", &outgoing_rpc, 0, &zero)) + return False; + + p->data_sent_length = 0; + p->current_pdu_len = prs_offset(&outgoing_rpc); + p->current_pdu_sent = 0; + + return True; +} + +/******************************************************************* + Respond to a pipe bind request. +*******************************************************************/ + +static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd) +{ + RPC_HDR_BA hdr_ba; + RPC_HDR_RB hdr_rb; + RPC_HDR_AUTH auth_info; + uint16 assoc_gid; + fstring ack_pipe_name; + prs_struct out_hdr_ba; + prs_struct out_auth; + prs_struct outgoing_rpc; + int i = 0; + int auth_len = 0; + + p->ntlmssp_auth_requested = False; + + DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__)); + + /* + * Try and find the correct pipe name to ensure + * that this is a pipe name we support. + */ + + for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) { + if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && + api_fd_commands[i].fn != NULL) { + DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n", + api_fd_commands[i].pipe_clnt_name, + api_fd_commands[i].pipe_srv_name)); + fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name); + break; + } + } + + if (api_fd_commands[i].fn == NULL) { + DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n", + p->name )); + if(!setup_bind_nak(p, pd)) + return False; + return True; + } + + /* decode the bind request */ + if(!smb_io_rpc_hdr_rb("", &hdr_rb, pd, 0)) { + DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_RB struct.\n")); + return False; + } + + /* + * Check if this is an authenticated request. + */ + + if (p->hdr.auth_len != 0) { + RPC_AUTH_VERIFIER auth_verifier; + RPC_AUTH_NTLMSSP_NEG ntlmssp_neg; + + /* + * Decode the authentication verifier. + */ + + if(!smb_io_rpc_hdr_auth("", &auth_info, pd, 0)) { + DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n")); + return False; + } + + /* + * We only support NTLMSSP_AUTH_TYPE requests. + */ + + if(auth_info.auth_type != NTLMSSP_AUTH_TYPE) { + DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n", + auth_info.auth_type )); + return False; + } + + if(!smb_io_rpc_auth_verifier("", &auth_verifier, pd, 0)) { + DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n")); + return False; + } + + if(!strequal(auth_verifier.signature, "NTLMSSP")) { + DEBUG(0,("api_pipe_bind_req: auth_verifier.signature != NTLMSSP\n")); + return False; + } + + if(auth_verifier.msg_type != NTLMSSP_NEGOTIATE) { + DEBUG(0,("api_pipe_bind_req: auth_verifier.msg_type (%d) != NTLMSSP_NEGOTIATE\n", + auth_verifier.msg_type)); + return False; + } + + if(!smb_io_rpc_auth_ntlmssp_neg("", &ntlmssp_neg, pd, 0)) { + DEBUG(0,("api_pipe_bind_req: Failed to unmarshall RPC_AUTH_NTLMSSP_NEG.\n")); + return False; + } + + p->ntlmssp_chal_flags = SMBD_NTLMSSP_NEG_FLAGS; + p->ntlmssp_auth_requested = True; + } + + /* name has to be \PIPE\xxxxx */ + fstrcpy(ack_pipe_name, "\\PIPE\\"); + fstrcat(ack_pipe_name, p->pipe_srv_name); + + DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__)); + + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + + prs_init( &outgoing_rpc, 0, 4, MARSHALL); + prs_give_memory( &outgoing_rpc, (char *)p->current_pdu, sizeof(p->current_pdu), False); + + /* + * Setup the memory to marshall the ba header, and the + * auth footers. + */ + + if(!prs_init(&out_hdr_ba, 1024, 4, MARSHALL)) { + DEBUG(0,("api_pipe_bind_req: malloc out_hdr_ba failed.\n")); + return False; + } + + if(!prs_init(&out_auth, 1024, 4, MARSHALL)) { + DEBUG(0,("pi_pipe_bind_req: malloc out_auth failed.\n")); + prs_mem_free(&out_hdr_ba); + return False; + } + + if (p->ntlmssp_auth_requested) + assoc_gid = 0x7a77; + else + assoc_gid = hdr_rb.bba.assoc_gid; + + /* + * Create the bind response struct. + */ + + init_rpc_hdr_ba(&hdr_ba, + hdr_rb.bba.max_tsize, + hdr_rb.bba.max_rsize, + assoc_gid, + ack_pipe_name, + 0x1, 0x0, 0x0, + &hdr_rb.transfer); + + /* + * and marshall it. + */ + + if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) { + DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n")); + goto err_exit; + } + + /* + * Now the authentication. + */ + + if (p->ntlmssp_auth_requested) { + RPC_AUTH_VERIFIER auth_verifier; + RPC_AUTH_NTLMSSP_CHAL ntlmssp_chal; + + generate_random_buffer(p->challenge, 8, False); + + /*** Authentication info ***/ + + init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1); + if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) { + DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n")); + goto err_exit; + } + + /*** NTLMSSP verifier ***/ + + init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_CHALLENGE); + if(!smb_io_rpc_auth_verifier("", &auth_verifier, &out_auth, 0)) { + DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_VERIFIER failed.\n")); + goto err_exit; + } + + /* NTLMSSP challenge ***/ + + init_rpc_auth_ntlmssp_chal(&ntlmssp_chal, p->ntlmssp_chal_flags, p->challenge); + if(!smb_io_rpc_auth_ntlmssp_chal("", &ntlmssp_chal, &out_auth, 0)) { + DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_NTLMSSP_CHAL failed.\n")); + goto err_exit; + } + + /* Auth len in the rpc header doesn't include auth_header. */ + auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN; + } + + /* + * Create the header, now we know the length. + */ + + init_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST, + p->hdr.call_id, + RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth), + auth_len); + + /* + * Marshall the header into the outgoing PDU. + */ + + if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) { + DEBUG(0,("pi_pipe_bind_req: marshalling of RPC_HDR failed.\n")); + goto err_exit; + } + + /* + * Now add the RPC_HDR_BA and any auth needed. + */ + + if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) { + DEBUG(0,("api_pipe_bind_req: append of RPC_HDR_BA failed.\n")); + goto err_exit; + } + + if(p->ntlmssp_auth_requested && !prs_append_prs_data( &outgoing_rpc, &out_auth)) { + DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n")); + goto err_exit; + } + + /* + * Setup the lengths for the initial reply. + */ + + p->data_sent_length = 0; + p->current_pdu_len = prs_offset(&outgoing_rpc); + p->current_pdu_sent = 0; + + prs_mem_free(&out_hdr_ba); + prs_mem_free(&out_auth); + + return True; + + err_exit: + + prs_mem_free(&out_hdr_ba); + prs_mem_free(&out_auth); + return False; +} + +/**************************************************************************** + Deal with sign & seal processing on an RPC request. +****************************************************************************/ + +static BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in) +{ + /* + * We always negotiate the following two bits.... + */ + BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SIGN); + BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SEAL); + int data_len; + int auth_len; + uint32 old_offset; + uint32 crc32 = 0; + + auth_len = p->hdr.auth_len; + + if ((auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) && auth_verify) { + DEBUG(0,("api_pipe_auth_process: Incorrect auth_len %d.\n", auth_len )); + return False; + } + + /* + * The following is that length of the data we must verify or unseal. + * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN + * preceeding the auth_data. + */ + + data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - + (auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len; + + DEBUG(5,("api_pipe_auth_process: sign: %s seal: %s data %d auth %d\n", + BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len)); + + if (auth_seal) { + char *data = prs_data_p(rpc_in) + RPC_HEADER_LEN + RPC_HDR_REQ_LEN; + NTLMSSPcalc_p(p, (uchar*)data, data_len); + crc32 = crc32_calc_buffer(data, data_len); + } + + old_offset = prs_offset(rpc_in); + + if (auth_seal || auth_verify) { + RPC_HDR_AUTH auth_info; + + if(!prs_set_offset(rpc_in, old_offset + data_len)) { + DEBUG(0,("api_pipe_auth_process: cannot move offset to %u.\n", + (unsigned int)old_offset + data_len )); + return False; + } + + if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) { + DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_HDR_AUTH.\n")); + return False; + } + } + + if (auth_verify) { + RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; + char *req_data = prs_data_p(rpc_in) + prs_offset(rpc_in) + 4; + + DEBUG(5,("api_pipe_auth_process: auth %d\n", prs_offset(rpc_in) + 4)); + + /* + * Ensure we have RPC_AUTH_NTLMSSP_CHK_LEN - 4 more bytes in the + * incoming buffer. + */ + if(prs_mem_get(rpc_in, RPC_AUTH_NTLMSSP_CHK_LEN - 4) == NULL) { + DEBUG(0,("api_pipe_auth_process: missing %d bytes in buffer.\n", + RPC_AUTH_NTLMSSP_CHK_LEN - 4 )); + return False; + } + + NTLMSSPcalc_p(p, (uchar*)req_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4); + if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, rpc_in, 0)) { + DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_AUTH_NTLMSSP_CHK.\n")); + return False; + } + + if (!rpc_auth_ntlmssp_chk(&ntlmssp_chk, crc32, p->ntlmssp_seq_num)) { + DEBUG(0,("api_pipe_auth_process: NTLMSSP check failed.\n")); + return False; + } + } + + /* + * Return the current pointer to the data offset. + */ + + if(!prs_set_offset(rpc_in, old_offset)) { + DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n", + (unsigned int)old_offset )); + return False; + } + + return True; +} + +/**************************************************************************** + Find the correct RPC function to call for this request. + If the pipe is authenticated then become the correct UNIX user + before doing the call. +****************************************************************************/ + +static BOOL api_pipe_request(pipes_struct *p, prs_struct *rpc_in) +{ + int i = 0; + BOOL ret = False; + BOOL changed_user_id = False; + + if (p->ntlmssp_auth_validated) { + if (!api_pipe_auth_process(p, rpc_in)) + return False; + + if(!become_authenticated_pipe_user(p)) + return False; + + changed_user_id = True; + } + + for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) { + if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && + api_fd_commands[i].fn != NULL) { + DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name)); + ret = api_fd_commands[i].fn(p, rpc_in); + } + } + + if(changed_user_id) + unbecome_authenticated_pipe_user(p); + + return ret; +} + +/**************************************************************************** + This function is the entry point to processing a DCE/RPC request. + All the data for the request (including RPC headers and authentication + verifiers) must be linearized in the input_data buffer, with a length + of data_len. + + The output is placed into the pipes_struct, and handed back to the + client on demand. +****************************************************************************/ + +BOOL rpc_command(pipes_struct *p, char *input_data, int data_len) +{ + prs_struct rpc_in; + BOOL reply = False; + + if (input_data == NULL) + return False; + + prs_init(&rpc_in, 0, 4, UNMARSHALL); + + /* + * Hand the data to the prs_struct, but don't let + * it own it. + */ + prs_give_memory( &rpc_in, input_data, (uint32)data_len, False); + + /* Unmarshall the rpc header */ + if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { + DEBUG(0,("rpc_command: failed to unmarshall RPC_HDR.\n")); + return False; + } + + /* + * Create the response data buffer. + */ + + if(!pipe_init_outgoing_data(p)) { + DEBUG(0,("rpc_command: failed to unmarshall RPC_HDR.\n")); + return False; + } + + switch (p->hdr.pkt_type) { + case RPC_BIND: + reply = api_pipe_bind_req(p, &rpc_in); + break; + case RPC_REQUEST: + if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) { + /* authentication _was_ requested + and it failed. sorry, no deal! + */ + DEBUG(0,("rpc_command: RPC request received on pipe %s where \ +authentication failed. Denying the request.\n", p->name)); + reply = False; + } else { + /* read the RPC request header */ + if(!smb_io_rpc_hdr_req("req", &p->hdr_req, &rpc_in, 0)) { + DEBUG(0,("rpc_command: failed to unmarshall RPC_HDR_REQ.\n")); + return False; + } + reply = api_pipe_request(p, &rpc_in); + } + break; + case RPC_BINDRESP: /* not the real name! */ + reply = api_pipe_bind_auth_resp(p, &rpc_in); + break; + } + + if (!reply) + DEBUG(3,("rpc_command: DCE/RPC fault should be sent here\n")); + + return reply; +} + + +/******************************************************************* + Calls the underlying RPC function for a named pipe. + ********************************************************************/ + +BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, + prs_struct *rpc_in) +{ + int fn_num; + + /* interpret the command */ + DEBUG(4,("api_rpcTNP: %s op 0x%x - ", rpc_name, p->hdr_req.opnum)); + + for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++) { + if (api_rpc_cmds[fn_num].opnum == p->hdr_req.opnum && api_rpc_cmds[fn_num].fn != NULL) { + DEBUG(3,("api_rpc_command: %s\n", api_rpc_cmds[fn_num].name)); + break; + } + } + + if (api_rpc_cmds[fn_num].name == NULL) { + DEBUG(4, ("unknown\n")); + return False; + } + + /* do the actual command */ + if(!api_rpc_cmds[fn_num].fn(p->vuid, rpc_in, &p->rdata)) { + DEBUG(0,("api_rpcTNP: %s: failed.\n", rpc_name)); + prs_mem_free(&p->rdata); + return False; + } + + DEBUG(5,("api_rpcTNP: called %s successfully\n", rpc_name)); + + return True; +} diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 4e9418fa94..cb4127aee4 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -3154,11 +3154,20 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param, Start the first part of an RPC reply which began with an SMBtrans request. ****************************************************************************/ -static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p) +static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p, + char *redir_data, int redir_len) { - char *rdata = malloc(p->max_trans_reply); + char *rdata; int data_len; + if (redir_data != NULL) + { + send_trans_reply(outbuf, NULL, 0, redir_data, redir_len, + redir_len > p->max_trans_reply); + return True; + } + + rdata = malloc(p->max_trans_reply); if(rdata == NULL) { DEBUG(0,("api_rpc_trans_reply: malloc fail.\n")); return False; @@ -3284,11 +3293,23 @@ static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf, switch (subcommand) { case 0x26: - /* dce/rpc command */ - reply = rpc_command(p, data, tdscnt); + { + char *rdata = NULL; + int rlen = mdrcnt; + + if (p->m) + { + reply = readwrite_pipe(p, data, tdscnt, &rdata, &rlen); + } + else + { + /* dce/rpc command */ + reply = rpc_command(p, data, tdscnt); + } if (reply) - reply = api_rpc_trans_reply(outbuf, p); + reply = api_rpc_trans_reply(outbuf, p, rdata, rlen); break; + } case 0x53: /* Wait Named Pipe Handle state */ reply = api_WNPHS(outbuf, p, params, tpscnt); diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index 15f52c0af6..1a9ac1d7a4 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -129,7 +129,16 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) if (numtowrite == 0) nwritten = 0; else - nwritten = write_to_pipe(p, data, numtowrite); + { + if (p->m != NULL) + { + nwritten = write_pipe(p, data, numtowrite); + } + else + { + nwritten = write_to_pipe(p, data, numtowrite); + } + } if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) return (UNIXERROR(ERRDOS,ERRnoaccess)); @@ -207,7 +216,14 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) set_message(outbuf,12,0,True); data = smb_buf(outbuf); - nread = read_from_pipe(p, data, smb_maxcnt); + if (p->m != NULL) + { + nread = read_pipe(p, data, smb_maxcnt); + } + else + { + nread = read_from_pipe(p, data, smb_maxcnt); + } if (nread < 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 0d45f11693..716f555c65 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -501,6 +501,8 @@ static void usage(char *pname) ****************************************************************************/ int main(int argc,char *argv[]) { + fstring sam_name; + extern BOOL append_log; /* shall I run as a daemon */ BOOL is_daemon = False; @@ -680,11 +682,6 @@ static void usage(char *pname) fstrcpy(global_myworkgroup, lp_workgroup()); - if(!pdb_generate_sam_sid()) { - DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); - exit(1); - } - CatchSignal(SIGHUP,SIGNAL_CAST sig_hup); /* Setup the signals that allow the debug log level @@ -734,7 +731,23 @@ static void usage(char *pname) /* possibly reload the services file. */ reload_services(True); - + + /* obtain or create a SAM SID */ + if (lp_domain_logons()) + { + fstrcpy(sam_name, global_myworkgroup); + } + else + { + fstrcpy(sam_name, global_myname); + } + + if(!pdb_generate_sam_sid(sam_name, NULL)) + { + DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); + exit(1); + } + if (*lp_rootdir()) { if (sys_chroot(lp_rootdir()) == 0) DEBUG(2,("Changed root to %s\n", lp_rootdir())); -- cgit