diff options
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/include/includes.h | 4 | ||||
-rw-r--r-- | source3/include/msdfs.h | 12 | ||||
-rw-r--r-- | source3/include/nt_printing.h | 4 | ||||
-rw-r--r-- | source3/include/ntdomain.h | 84 | ||||
-rw-r--r-- | source3/include/proto.h | 56 | ||||
-rw-r--r-- | source3/include/smb.h | 4 | ||||
-rw-r--r-- | source3/msdfs/msdfs.c | 8 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe.c | 1099 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe_hnd.c | 539 | ||||
-rw-r--r-- | source3/smbd/ipc.c | 31 | ||||
-rw-r--r-- | source3/smbd/pipes.c | 47 |
12 files changed, 1679 insertions, 211 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 527e5b5300..cd7447502d 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -118,7 +118,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_srv.o rpc_server/srv_pipe.o \ + rpc_server/srv_pipe.o \ rpc_server/srv_spoolss.o rpc_server/srv_spoolss_nt.o RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_misc.o \ diff --git a/source3/include/includes.h b/source3/include/includes.h index d040dada7a..f77e1323d7 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -665,6 +665,8 @@ extern int errno; #include "nterr.h" +#include "msdfs.h" + #ifdef WITH_PROFILE #include "profile.h" #endif @@ -914,6 +916,4 @@ int setresgid(gid_t rgid, gid_t egid, gid_t sgid); #include <dlfcn.h> #endif -#include "msdfs.h" - #endif /* _INCLUDES_H */ diff --git a/source3/include/msdfs.h b/source3/include/msdfs.h index ea72c4c15f..0c2e3c14df 100644 --- a/source3/include/msdfs.h +++ b/source3/include/msdfs.h @@ -22,8 +22,6 @@ #ifndef _MSDFS_H #define _MSDFS_H -#ifdef MS_DFS - #define REFERRAL_TTL 600 /* Flags used in trans2 Get Referral reply */ @@ -46,6 +44,16 @@ struct junction_map struct referral* referral_list; }; +struct dfs_path +{ + pstring hostname; + pstring servicename; + pstring volumename; + pstring restofthepath; +}; + +#ifdef MS_DFS + #define RESOLVE_DFSPATH(name, conn, inbuf, outbuf) \ { if(((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES)) && \ dfs_redirect(name,conn)) \ diff --git a/source3/include/nt_printing.h b/source3/include/nt_printing.h index 22c837c748..99a427c32d 100644 --- a/source3/include/nt_printing.h +++ b/source3/include/nt_printing.h @@ -1,3 +1,6 @@ +#ifndef NT_PRINTING_H_ +#define NT_PRINTING_H_ + #define ORIENTATION 0x00000001L #define PAPERSIZE 0x00000002L #define PAPERLENGTH 0x00000004L @@ -235,3 +238,4 @@ typedef struct _form UNISTR2 name; } FORM; */ +#endif /* NT_PRINTING_H_ */ diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index 7f3d4b4950..46be965d70 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -24,10 +24,6 @@ #ifndef _NT_DOMAIN_H /* _NT_DOMAIN_H */ #define _NT_DOMAIN_H -/* - * A bunch of stuff that was put into smb.h - * in the NTDOM branch - it didn't belong there. - */ /* dce/rpc support */ #include "rpc_dce.h" @@ -35,8 +31,10 @@ /* miscellaneous structures / defines */ #include "rpc_misc.h" -/* security descriptor structures */ -#include "rpc_secdes.h" +/* + * A bunch of stuff that was put into smb.h + * in the NTDOM branch - it didn't belong there. + */ typedef struct _prs_struct { @@ -63,32 +61,8 @@ typedef struct _prs_struct #define MARSHALLING(ps) (!(ps)->io) #define UNMARSHALLING(ps) ((ps)->io) -typedef struct _input_data { - /* - * This is the current incoming pdu. The data here - * is collected via multiple writes until a complete - * pdu is seen, then the data is copied into the in_data - * structure. The maximum size of this is 64k (2 byte length). - */ - prs_struct in_pdu; - - /* - * The amount of data needed to complete the in_pdu. - * If this is zero, then we are at the start of a new - * pdu. - */ - uint32 in_pdu_needed_len; - - /* - * This is the collection of input data with all - * the rpc headers and auth footers removed. - * The maximum length of this is strictly enforced. - */ - prs_struct in_data; -} input_data; - typedef struct _output_data { - /* + /* * Raw RPC output data. This does not include RPC headers or footers. */ prs_struct rdata; @@ -96,7 +70,7 @@ typedef struct _output_data { /* The amount of data sent from the current rdata struct. */ uint32 data_sent_length; - /* + /* * The current PDU being returned. This inclues * headers, data and authentication footer. */ @@ -109,6 +83,37 @@ typedef struct _output_data { uint32 current_pdu_sent; } output_data; +typedef struct _input_data { + /* + * This is the current incoming pdu. The data here + * is collected via multiple writes until a complete + * pdu is seen, then the data is copied into the in_data + * structure. The maximum size of this is 0x1630 (MAX_PDU_FRAG_LEN). + */ + unsigned char current_in_pdu[MAX_PDU_FRAG_LEN]; + + /* + * The amount of data needed to complete the in_pdu. + * If this is zero, then we are at the start of a new + * pdu. + */ + uint32 pdu_needed_len; + + /* + * The amount of data received so far in the in_pdu. + * If this is zero, then we are at the start of a new + * pdu. + */ + uint32 pdu_received_len; + + /* + * This is the collection of input data with all + * the rpc headers and auth footers removed. + * The maximum length of this (1Mb) is strictly enforced. + */ + prs_struct data; +} input_data; + typedef struct pipes_struct { struct pipes_struct *next, *prev; @@ -145,6 +150,18 @@ typedef struct pipes_struct uid_t uid; gid_t gid; + /* + * Set to true when an RPC bind has been done on this pipe. + */ + + BOOL pipe_bound; + + /* + * Set to true when we should return fault PDU's for everything. + */ + + BOOL fault_state; + /* * Struct to deal with multiple pdu inputs. */ @@ -186,6 +203,9 @@ struct acct_info uint32 smb_userid; /* domain-relative RID */ }; +/* security descriptor structures */ +#include "rpc_secdes.h" + /* different dce/rpc pipes */ #include "rpc_lsa.h" #include "rpc_netlogon.h" diff --git a/source3/include/proto.h b/source3/include/proto.h index f10f006aeb..20a459120f 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -24,6 +24,7 @@ BOOL allow_access(char *deny_list,char *allow_list, BOOL check_access(int sock, char *allow_list, char *deny_list); /*The following definitions come from lib/bitmap.c */ + struct bitmap *bitmap_allocate(int n); BOOL bitmap_set(struct bitmap *bm, unsigned i); BOOL bitmap_clear(struct bitmap *bm, unsigned i); @@ -800,6 +801,35 @@ BOOL downgrade_share_oplock(files_struct *fsp); BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock); int share_mode_forall(SHAREMODE_FN(fn)); +/*The following definitions come from msdfs/msdfs.c */ + +void create_nondfs_path(char* pathname, struct dfs_path* pdp); +BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp); +BOOL dfs_redirect(char* pathname, connection_struct* conn); +BOOL dfs_findfirst_redirect(char* pathname, connection_struct* conn); +int setup_dfs_referral(char* pathname, int max_referral_level, + char** ppdata); +int dfs_path_error(char* inbuf, char* outbuf); +int setup_dfs_referral(char* pathname, int max_referral_level, + char** ppdata); +int unistr_to_dos(char* dst,uint16* src) ; + +/*The following definitions come from msdfs/msdfs_tdb.c */ + +BOOL msdfs_open(BOOL update); +BOOL add_junction_entry(struct junction_map* junction); +BOOL get_junction_entry(struct junction_map* junction); +BOOL isDfsShare(char* svc,char* vol); +void msdfs_close(); +void msdfs_end(); + +/*The following definitions come from msdfs/parse_dfs_map.c */ + +BOOL parse_referral(char* s, struct referral* ref); +void load_dfsmaps(); +BOOL load_dfsmap(char* fname, int snum); +void load_dfsmaps(); + /*The following definitions come from nmbd/asyncdns.c */ int asyncdns_fd(void); @@ -1244,6 +1274,7 @@ BOOL lp_nt_acl_support(void); BOOL lp_stat_cache(void); BOOL lp_allow_trusted_domains(void); BOOL lp_restrict_anonymous(void); +BOOL lp_host_msdfs(void); int lp_os_level(void); int lp_max_ttl(void); int lp_max_wins_ttl(void); @@ -1304,12 +1335,13 @@ char *lp_readlist(int ); char *lp_writelist(int ); char *lp_fstype(int ); char *lp_vfsobj(int ); -char *lp_dfsmap(int ); char *lp_mangled_map(int ); char *lp_veto_files(int ); char *lp_hide_files(int ); char *lp_veto_oplocks(int ); char *lp_driverlocation(int ); +char *lp_dfsmap(int ); +BOOL lp_dfsmap_loaded(int ); BOOL lp_preexec_close(int ); BOOL lp_rootpreexec_close(int ); BOOL lp_revalidate(int ); @@ -1368,6 +1400,7 @@ BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir); int lp_add_service(char *pszService, int iDefaultService); BOOL lp_add_printer(char *pszPrintername, int iDefaultService); BOOL lp_file_list_changed(void); +void set_dfsmap_loaded(int i,BOOL b); void *lp_local_ptr(int snum, void *ptr); BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue); BOOL lp_is_default(int snum, struct parm_struct *parm); @@ -2562,17 +2595,21 @@ BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data); /*The following definitions come from rpc_server/srv_pipe.c */ -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); +BOOL create_next_pdu(pipes_struct *p); +BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *rpc_in_p); +BOOL setup_fault_pdu(pipes_struct *p); +BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p); +BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in); +BOOL api_pipe_request(pipes_struct *p); +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_pipe_hnd.c */ void set_pipe_handle_offset(int max_open_files); void reset_chain_p(void); void init_rpc_pipe_hnd(void); -BOOL pipe_init_outgoing_data(output_data *out_data); +BOOL pipe_init_outgoing_data(output_data *o_data); pipes_struct *open_rpc_pipe_p(char *pipe_name, connection_struct *conn, uint16 vuid); ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n); @@ -2583,13 +2620,6 @@ 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/smb.h b/source3/include/smb.h index c330593b1a..447f2bd3a6 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1145,6 +1145,10 @@ struct bitmap { #define SMB_SUPPORT_SEARCH_BITS 0x0001 #define SMB_SHARE_IN_DFS 0x0002 +/* Named pipe write mode flags. Used in writeX calls. */ +#define PIPE_RAW_MODE 0x4 +#define PIPE_START_MESSAGE 0x8 + /* these are the constants used in the above call. */ /* DesiredAccess */ /* File Specific access rights. */ diff --git a/source3/msdfs/msdfs.c b/source3/msdfs/msdfs.c index ce1a94ee00..adb968db81 100644 --- a/source3/msdfs/msdfs.c +++ b/source3/msdfs/msdfs.c @@ -31,14 +31,6 @@ extern global_client_caps; #define VERSION3_REFERRAL_SIZE 0x22 #define REFERRAL_HEADER_SIZE 0x08 -struct dfs_path -{ - pstring hostname; - pstring servicename; - pstring volumename; - pstring restofthepath; -}; - void create_nondfs_path(char* pathname, struct dfs_path* pdp) { pstrcpy(pathname,pdp->volumename); diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index f8439de9a7..11822e7d03 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -1,4 +1,3 @@ - /* * Unix SMB/Netbios implementation. * Version 1.9. @@ -6,6 +5,7 @@ * 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,82 +43,1095 @@ 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; +} + /******************************************************************* - 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). + 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 readwrite_pipe(pipes_struct *p, char *data, int len, - char **rdata, int *rlen) + +BOOL create_next_pdu(pipes_struct *p) { - DEBUG(10,("rpc_to_smb_readwrite: len %d\n", len)); + 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; - if (write(p->m->fd, data, len) != len) - { + /* + * If we're in the fault state, keep returning fault PDU's until + * the pipe gets closed. JRA. + */ + + if(p->fault_state) { + setup_fault_pdu(p); + return True; + } + + 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->out_data.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->out_data.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->out_data.rdata) - p->out_data.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; } - if ((*rlen) == 0) - { + 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->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.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->out_data.current_pdu, sizeof(p->out_data.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; } - (*rdata) = (char*)Realloc((*rdata), (*rlen)); - if ((*rdata) == NULL) - { + 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; } - /* read a minimum of an rpc header, then wait for up to 10 seconds - * to read up to a maximum of the SMBtrans max data size + /* Store the current offset. */ + data_pos = prs_offset(&outgoing_pdu); + + /* Copy the data into the PDU. */ + data_from = prs_data_p(&p->out_data.rdata) + p->out_data.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->out_data.data_sent_length += data_len; + p->out_data.current_pdu_len = p->hdr.frag_len; + p->out_data.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. */ - (*rlen) = read_with_timeout(p->m->fd, (*rdata), 16, (*rlen), 10000); - if ((*rlen) < 0) + + 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 <kalele@veritas.com>. + */ + + 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 1 /* DISABLED_IN_2_0 JRATEST */ + { "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. +*******************************************************************/ + +BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *rpc_in_p) +{ + 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__)); + + /* + * Create the response data buffer. + */ + + if(!pipe_init_outgoing_data(&p->out_data)) { + DEBUG(0,("api_pipe_bind_auth_resp: failed to create outgoing buffer.\n")); return False; } - (*rdata) = (char*)Realloc((*rdata), (*rlen)); - if ((*rdata) == NULL) - { + + 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, rpc_in_p, 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, rpc_in_p, 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, rpc_in_p, 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; + + p->pipe_bound = True +; return True; } -/**************************************************************************** - writes data to a pipe. - ****************************************************************************/ -ssize_t write_pipe(pipes_struct *p, char *data, size_t n) +/******************************************************************* + Marshall a bind_nak pdu. +*******************************************************************/ + +static BOOL setup_bind_nak(pipes_struct *p) { - DEBUG(6,("write_pipe: %x", p->pnum)); - DEBUG(6,("name: %s open: %s len: %d", - p->name, BOOLSTR(p->open), n)); + prs_struct outgoing_rpc; + RPC_HDR nak_hdr; + uint16 zero = 0; + + /* Free any memory in the current return data buffer. */ + prs_mem_free(&p->out_data.rdata); + + /* + * 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->out_data.current_pdu, sizeof(p->out_data.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; - dump_data(50, data, n); + p->out_data.data_sent_length = 0; + p->out_data.current_pdu_len = prs_offset(&outgoing_rpc); + p->out_data.current_pdu_sent = 0; - return write(p->m->fd, data, n); + p->pipe_bound = False; + + return True; } +/******************************************************************* + Marshall a fault pdu. +*******************************************************************/ + +BOOL setup_fault_pdu(pipes_struct *p) +{ + prs_struct outgoing_pdu; + RPC_HDR fault_hdr; + RPC_HDR_RESP hdr_resp; + RPC_HDR_FAULT fault_resp; + + /* Free any memory in the current return data buffer. */ + prs_mem_free(&p->out_data.rdata); + + /* + * 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_pdu, 0, 4, MARSHALL); + prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False); + + /* + * Initialize a fault header. + */ + + init_rpc_hdr(&fault_hdr, RPC_FAULT, RPC_FLG_FIRST | RPC_FLG_LAST | RPC_FLG_NOCALL, + p->hdr.call_id, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_FAULT_LEN, 0); + + /* + * Initialize the HDR_RESP and FAULT parts of the PDU. + */ + + memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); + + fault_resp.status = 0x1c010002; + fault_resp.reserved = 0; + + /* + * Marshall the header into the outgoing PDU. + */ + + if(!smb_io_rpc_hdr("", &fault_hdr, &outgoing_pdu, 0)) { + DEBUG(0,("setup_fault_pdu: marshalling of RPC_HDR failed.\n")); + return False; + } + + if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) { + DEBUG(0,("setup_fault_pdu: failed to marshall RPC_HDR_RESP.\n")); + return False; + } + + if(!smb_io_rpc_hdr_fault("fault", &fault_resp, &outgoing_pdu, 0)) { + DEBUG(0,("setup_fault_pdu: failed to marshall RPC_HDR_FAULT.\n")); + return False; + } + + p->out_data.data_sent_length = 0; + p->out_data.current_pdu_len = prs_offset(&outgoing_pdu); + p->out_data.current_pdu_sent = 0; + + return True; +} + +/******************************************************************* + Respond to a pipe bind request. +*******************************************************************/ + +BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) +{ + 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; + enum RPC_PKT_TYPE reply_pkt_type; + + p->ntlmssp_auth_requested = False; + + DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__)); + + /* + * Create the response data buffer. + */ + + if(!pipe_init_outgoing_data(&p->out_data)) { + DEBUG(0,("api_pipe_bind_req: failed to create outgoing buffer.\n")); + return False; + } + + /* + * 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)) + return False; + return True; + } + + /* decode the bind request */ + if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_in_p, 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, rpc_in_p, 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, rpc_in_p, 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, rpc_in_p, 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; + } + + switch(p->hdr.pkt_type) { + case RPC_BIND: + /* name has to be \PIPE\xxxxx */ + fstrcpy(ack_pipe_name, "\\PIPE\\"); + fstrcat(ack_pipe_name, p->pipe_srv_name); + reply_pkt_type = RPC_BINDACK; + break; + case RPC_ALTCONT: + /* secondary address CAN be NULL + * as the specs say it's ignored. + * It MUST NULL to have the spoolss working. + */ + fstrcpy(ack_pipe_name,""); + reply_pkt_type = RPC_ALTCONTRESP; + break; + default: + return False; + } + + 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->out_data.current_pdu, sizeof(p->out_data.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, + MAX_PDU_FRAG_LEN, + MAX_PDU_FRAG_LEN, + 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, reply_pkt_type, 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; + } + + if(!p->ntlmssp_auth_requested) + p->pipe_bound = True; + + /* + * Setup the lengths for the initial reply. + */ + + p->out_data.data_sent_length = 0; + p->out_data.current_pdu_len = prs_offset(&outgoing_rpc); + p->out_data.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; +} /**************************************************************************** - reads data from a pipe. + Deal with sign & seal processing on an RPC request. +****************************************************************************/ + +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; - 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). + 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; + } - ****************************************************************************/ -int read_pipe(pipes_struct *p, char *data, int n) + 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. +****************************************************************************/ + +BOOL api_pipe_request(pipes_struct *p) { - DEBUG(6,("read_pipe: %x name: %s open: %s len: %d", - p->pnum, p->name, BOOLSTR(p->open), n)); + int i = 0; + BOOL ret = False; + BOOL changed_user_id = False; - if (!p || !p->open) - { - DEBUG(6,("pipe not open\n")); - return -1; + /* + * Create the response data buffer. + */ + + if(!pipe_init_outgoing_data(&p->out_data)) { + DEBUG(0,("api_pipe_request: failed to create outgoing buffer.\n")); + return False; } - return read_data(p->m->fd, data, n); + if (p->ntlmssp_auth_validated) { + + if(!become_authenticated_pipe_user(p)) { + prs_mem_free(&p->out_data.rdata); + 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, &p->in_data.data); + } + } + + if(changed_user_id) + unbecome_authenticated_pipe_user(p); + + return ret; } +/******************************************************************* + 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_rpcTNP: rpc command: %s\n", api_rpc_cmds[fn_num].name)); + break; + } + } + + if (api_rpc_cmds[fn_num].name == NULL) { + /* + * For an unknown RPC just return a fault PDU but + * return True to allow RPC's on the pipe to continue + * and not put the pipe into fault state. JRA. + */ + DEBUG(4, ("unknown\n")); + setup_fault_pdu(p); + return True; + } + + /* do the actual command */ + if(!api_rpc_cmds[fn_num].fn(p->vuid, rpc_in, &p->out_data.rdata)) { + DEBUG(0,("api_rpcTNP: %s: failed.\n", rpc_name)); + prs_mem_free(&p->out_data.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 32a804d5d5..c63390c35f 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -1,4 +1,3 @@ - /* * Unix SMB/Netbios implementation. * Version 1.9. @@ -78,67 +77,61 @@ void init_rpc_pipe_hnd(void) Initialise an outgoing packet. ****************************************************************************/ -BOOL pipe_init_outgoing_data(output_data *out_data) +BOOL pipe_init_outgoing_data(output_data *o_data) { - memset(out_data->current_pdu, '\0', sizeof(out_data->current_pdu)); + memset(o_data->current_pdu, '\0', sizeof(o_data->current_pdu)); /* Free any memory in the current return data buffer. */ - prs_mem_free(&out_data->rdata); + prs_mem_free(&o_data->rdata); /* * Initialize the outgoing RPC data buffer. * we will use this as the raw data area for replying to rpc requests. */ - if(!prs_init(&out_data->rdata, 1024, 4, MARSHALL)) { + if(!prs_init(&o_data->rdata, MAX_PDU_FRAG_LEN, 4, MARSHALL)) { DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n")); return False; } /* Reset the offset counters. */ - out_data->data_sent_length = 0; - out_data->current_pdu_len = 0; - out_data->current_pdu_sent = 0; + o_data->data_sent_length = 0; + o_data->current_pdu_len = 0; + o_data->current_pdu_sent = 0; return True; } /**************************************************************************** - Find first available pipe slot. + HACK !!! Attempt to find a remote process to communicate RPC's with. ****************************************************************************/ -pipes_struct *open_rpc_pipe_p(char *pipe_name, - connection_struct *conn, uint16 vuid) +static void attempt_remote_rpc_connect(pipes_struct *p) { - 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; + struct msrpc_state *m; + user_struct *vuser = get_valid_user_struct(p->vuid); - ZERO_STRUCT(usr); + p->m = NULL; - 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; + if (vuser == NULL) { + DEBUG(4,("attempt_remote_rpc_connect: invalid vuid %d\n", (int)p->vuid)); + return; } + ZERO_STRUCT(usr); + /* 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); + vuser->real_name, vuser->guest); usr.ptr_uxc = 1; make_creds_unix_sec(&usr.uxs, vuser->uid, vuser->gid, - vuser->n_groups, vuser->groups); + vuser->n_groups, vuser->groups); usr.ptr_uxs = 1; usr.ptr_ssk = 1; - DEBUG(0,("user session key not available (yet).\n")); - DEBUG(0,("password-change operations may fail.\n")); + DEBUG(10,("user session key not available (yet).\n")); + DEBUG(10,("password-change operations may fail.\n")); #if USER_SESSION_KEY_DEFINED_IN_VUSER_STRUCT memcpy(usr.usr_sess_key, vuser->usr_sess_key, sizeof(usr.usr_sess_key)); @@ -153,14 +146,28 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, */ become_root(False); /* to connect to pipe */ - m = msrpc_use_add(pipe_name, getpid(), &usr, False); + p->m = msrpc_use_add(p->name, getpid(), &usr, False); unbecome_root(False); - if (m == NULL) - { - DEBUG(10,("open pipes: msrpc redirect failed - go local.\n")); - } + if (p->m == NULL) + DEBUG(10,("attempt_remote_rpc_connect: msrpc redirect failed - using local implementation.\n")); +} + +/**************************************************************************** + Find first available pipe slot. +****************************************************************************/ + +pipes_struct *open_rpc_pipe_p(char *pipe_name, + connection_struct *conn, uint16 vuid) +{ + int i; + pipes_struct *p; + static int next_pipe; + + DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n", + pipe_name, pipes_open)); + /* 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 */ @@ -180,18 +187,26 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum)); p = (pipes_struct *)malloc(sizeof(*p)); + if (!p) return NULL; ZERO_STRUCTP(p); - /* - * Initialize the RPC and PDU data buffers with no memory. - */ - prs_init(&p->out_data.rdata, 0, 4, MARSHALL); - DLIST_ADD(Pipes, p); + /* + * Initialize the incoming RPC data buffer with one PDU worth of memory. + * We cheat here and say we're marshalling, as we intend to add incoming + * data directly into the prs_struct and we want it to auto grow. We will + * change the type to UNMARSALLING before processing the stream. + */ + + if(!prs_init(&p->in_data.data, MAX_PDU_FRAG_LEN, 4, MARSHALL)) { + DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n")); + return NULL; + } + bitmap_set(bmap, i); i += pipe_handle_offset; @@ -204,8 +219,6 @@ 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; @@ -213,15 +226,40 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, p->ntlmssp_auth_validated = False; p->ntlmssp_auth_requested = False; + p->pipe_bound = False; + p->fault_state = False; + + /* + * Initialize the incoming RPC struct. + */ + + p->in_data.pdu_needed_len = 0; + p->in_data.pdu_received_len = 0; + + /* + * Initialize the outgoing RPC struct. + */ + p->out_data.current_pdu_len = 0; p->out_data.current_pdu_sent = 0; p->out_data.data_sent_length = 0; + /* + * Initialize the outgoing RPC data buffer with no memory. + */ + prs_init(&p->out_data.rdata, 0, 4, MARSHALL); + p->uid = (uid_t)-1; p->gid = (gid_t)-1; fstrcpy(p->name, pipe_name); + /* + * HACK !!! For Luke - attempt to connect to RPC redirect process. + */ + + attempt_remote_rpc_connect(p); + DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n", pipe_name, i, pipes_open)); @@ -234,27 +272,408 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, return chain_p; } +/**************************************************************************** + Sets the fault state on incoming packets. +****************************************************************************/ + +static void set_incoming_fault(pipes_struct *p) +{ + prs_mem_free(&p->in_data.data); + p->in_data.pdu_needed_len = 0; + p->in_data.pdu_received_len = 0; + p->fault_state = True; + DEBUG(10,("set_incoming_fault: Setting fault state on pipe %s : pnum = 0x%x\n", + p->name, p->pnum )); +} /**************************************************************************** - Accepts incoming data on an rpc pipe. + Ensures we have at least RPC_HEADER_LEN amount of data in the incoming buffer. +****************************************************************************/ - This code is probably incorrect at the moment. The problem is - that the rpc request shouldn't really be executed until all the - data needed for it is received. This currently assumes that each - SMBwrite or SMBwriteX contains all the data needed for an rpc - request. JRA. - ****************************************************************************/ +static ssize_t fill_rpc_header(pipes_struct *p, char *data, size_t data_to_copy) +{ + size_t len_needed_to_complete_hdr = MIN(data_to_copy, RPC_HEADER_LEN - p->in_data.pdu_received_len); + + DEBUG(10,("fill_rpc_header: data_to_copy = %u, len_needed_to_complete_hdr = %u, receive_len = %u\n", + (unsigned int)data_to_copy, (unsigned int)len_needed_to_complete_hdr, + (unsigned int)p->in_data.pdu_received_len )); + + memcpy((char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, len_needed_to_complete_hdr); + p->in_data.pdu_received_len += len_needed_to_complete_hdr; + + return (ssize_t)len_needed_to_complete_hdr; +} + +/**************************************************************************** + Unmarshalls a new PDU header. Assumes the raw header data is in current_in_pdu. +****************************************************************************/ + +static ssize_t unmarshall_rpc_header(pipes_struct *p) +{ + /* + * Unmarshall the header to determine the needed length. + */ + + prs_struct rpc_in; + + if(p->in_data.pdu_received_len != RPC_HEADER_LEN) { + DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n")); + set_incoming_fault(p); + return -1; + } + + prs_init( &rpc_in, 0, 4, UNMARSHALL); + prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0], + p->in_data.pdu_received_len, False); + + /* + * Unmarshall the header as this will tell us how much + * data we need to read to get the complete pdu. + */ + + if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { + DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n")); + set_incoming_fault(p); + return -1; + } + + /* + * Validate the RPC header. + */ + + if(p->hdr.major != 5 && p->hdr.minor != 0) { + DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n")); + set_incoming_fault(p); + return -1; + } + + /* + * If there is no data in the incoming buffer and it's a requst pdu then + * ensure that the FIRST flag is set. If not then we have + * a stream missmatch. + */ + + if((p->hdr.pkt_type == RPC_REQUEST) && (prs_offset(&p->in_data.data) == 0) && !(p->hdr.flags & RPC_FLG_FIRST)) { + DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n")); + set_incoming_fault(p); + return -1; + } + + /* + * Ensure that the pdu length is sane. + */ + + if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > MAX_PDU_FRAG_LEN)) { + DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n")); + set_incoming_fault(p); + return -1; + } + + DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type, + (unsigned int)p->hdr.flags )); + + /* + * Adjust for the header we just ate. + */ + p->in_data.pdu_received_len = 0; + p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN; + + /* + * Null the data we just ate. + */ + + memset((char *)&p->in_data.current_in_pdu[0], '\0', RPC_HEADER_LEN); + + return 0; /* No extra data processed. */ +} + +/**************************************************************************** + Processes a request pdu. This will do auth processing if needed, and + appends the data into the complete stream if the LAST flag is not set. +****************************************************************************/ + +static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) +{ + BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal_flags, NTLMSSP_NEGOTIATE_SIGN); + size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - + (auth_verify ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; + + if(!p->pipe_bound) { + DEBUG(0,("process_request_pdu: rpc request with no bind.\n")); + set_incoming_fault(p); + return False; + } + + /* + * Check if we need to do authentication processing. + * This is only done on requests, not binds. + */ + + /* + * Read the RPC request header. + */ + + if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) { + DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n")); + set_incoming_fault(p); + return False; + } + + if(p->ntlmssp_auth_validated && !api_pipe_auth_process(p, rpc_in_p)) { + DEBUG(0,("process_request_pdu: failed to do auth processing.\n")); + set_incoming_fault(p); + return False; + } + + if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) { + + /* + * Authentication _was_ requested and it already failed. + */ + + DEBUG(0,("process_request_pdu: RPC request received on pipe %s where \ +authentication failed. Denying the request.\n", p->name)); + set_incoming_fault(p); + return False; + } + + /* + * Check the data length doesn't go over the 1Mb limit. + */ + + if(prs_data_size(&p->in_data.data) + data_len > 1024*1024) { + DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n", + (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len )); + set_incoming_fault(p); + return False; + } + + /* + * Append the data portion into the buffer and return. + */ + + { + char *data_from = prs_data_p(rpc_in_p) + prs_offset(rpc_in_p); + + if(!prs_append_data(&p->in_data.data, data_from, data_len)) { + DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n", + (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) )); + set_incoming_fault(p); + return False; + } + + } + + if(p->hdr.flags & RPC_FLG_LAST) { + BOOL ret; + /* + * Ok - we finally have a complete RPC stream. + * Call the rpc command to process it. + */ + + /* + * Set the parse offset to the start of the data and set the + * prs_struct to UNMARSHALL. + */ + + prs_set_offset(&p->in_data.data, 0); + prs_switch_type(&p->in_data.data, UNMARSHALL); + + /* + * Process the complete data stream here. + */ + + ret = api_pipe_request(p); + + /* + * We have consumed the whole data stream. Set back to + * marshalling and set the offset back to the start of + * the buffer to re-use it (we could also do a prs_mem_free() + * and then re_init on the next start of PDU. Not sure which + * is best here.... JRA. + */ + + prs_switch_type(&p->in_data.data, MARSHALL); + prs_set_offset(&p->in_data.data, 0); + return ret; + } + + return True; +} + +/**************************************************************************** + Processes a finished PDU stored in current_in_pdu. The RPC_HEADER has + already been parsed and stored in p->hdr. +****************************************************************************/ + +static ssize_t process_complete_pdu(pipes_struct *p) +{ + prs_struct rpc_in; + size_t data_len = p->in_data.pdu_received_len; + char *data_p = (char *)&p->in_data.current_in_pdu[0]; + BOOL reply = False; + + if(p->fault_state) { + DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n", + p->name )); + set_incoming_fault(p); + setup_fault_pdu(p); + return (ssize_t)data_len; + } + + prs_init( &rpc_in, 0, 4, UNMARSHALL); + prs_give_memory( &rpc_in, data_p, (uint32)data_len, False); + + DEBUG(10,("process_complete_pdu: processing packet type %u\n", + (unsigned int)p->hdr.pkt_type )); + + switch (p->hdr.pkt_type) { + case RPC_BIND: + case RPC_ALTCONT: + /* + * We assume that a pipe bind is only in one pdu. + */ + reply = api_pipe_bind_req(p, &rpc_in); + break; + case RPC_BINDRESP: + /* + * We assume that a pipe bind_resp is only in one pdu. + */ + reply = api_pipe_bind_auth_resp(p, &rpc_in); + break; + case RPC_REQUEST: + reply = process_request_pdu(p, &rpc_in); + break; + default: + DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type )); + break; + } + + if (!reply) { + DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on pipe %s\n", p->pipe_srv_name)); + set_incoming_fault(p); + setup_fault_pdu(p); + } else { + /* + * Reset the lengths. We're ready for a new pdu. + */ + p->in_data.pdu_needed_len = 0; + p->in_data.pdu_received_len = 0; + } + + return (ssize_t)data_len; +} + +/**************************************************************************** + Accepts incoming data on an rpc pipe. Processes the data in pdu sized units. +****************************************************************************/ + +static ssize_t process_incoming_data(pipes_struct *p, char *data, size_t n) +{ + size_t data_to_copy = MIN(n, MAX_PDU_FRAG_LEN - p->in_data.pdu_received_len); + + DEBUG(10,("process_incoming_data: Start: pdu_received_len = %u, pdu_needed_len = %u, incoming data = %u\n", + (unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len, + (unsigned int)n )); + + if(data_to_copy == 0) { + /* + * This is an error - data is being received and there is no + * space in the PDU. Free the received data and go into the fault state. + */ + DEBUG(0,("process_incoming_data: No space in incoming pdu buffer. Current size = %u \ +incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned int)n )); + set_incoming_fault(p); + return -1; + } + + /* + * If we have no data already, wait until we get at least a RPC_HEADER_LEN + * number of bytes before we can do anything. + */ + + if((p->in_data.pdu_needed_len == 0) && (p->in_data.pdu_received_len < RPC_HEADER_LEN)) { + /* + * Always return here. If we have more data then the RPC_HEADER + * will be processed the next time around the loop. + */ + return fill_rpc_header(p, data, data_to_copy); + } + + /* + * At this point we know we have at least an RPC_HEADER_LEN amount of data + * stored in current_in_pdu. + */ + + /* + * If pdu_needed_len is zero this is a new pdu. + * Unmarshall the header so we know how much more + * data we need, then loop again. + */ + + if(p->in_data.pdu_needed_len == 0) + return unmarshall_rpc_header(p); + + /* + * Ok - at this point we have a valid RPC_HEADER in p->hdr. + * Keep reading until we have a full pdu. + */ + + data_to_copy = MIN(data_to_copy, p->in_data.pdu_needed_len); + + /* + * Copy as much of the data as we need into the current_in_pdu buffer. + */ + + memcpy( (char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, data_to_copy); + p->in_data.pdu_received_len += data_to_copy; + + /* + * Do we have a complete PDU ? + */ + + if(p->in_data.pdu_received_len == p->in_data.pdu_needed_len) + return process_complete_pdu(p); + + DEBUG(10,("process_incoming_data: not a complete PDU yet. pdu_received_len = %u, pdu_needed_len = %u\n", + (unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len )); + + return (ssize_t)data_to_copy; + +} + +/**************************************************************************** + Accepts incoming data on an rpc pipe. +****************************************************************************/ ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n) { + size_t data_left = n; + DEBUG(6,("write_to_pipe: %x", p->pnum)); - DEBUG(6,("name: %s open: %s len: %d", + DEBUG(6,(" name: %s open: %s len: %d\n", p->name, BOOLSTR(p->open), (int)n)); dump_data(50, data, n); - return rpc_command(p, data, (int)n) ? ((ssize_t)n) : -1; + while(data_left) { + ssize_t data_used; + + DEBUG(10,("write_to_pipe: data_left = %u\n", (unsigned int)data_left )); + + data_used = process_incoming_data(p, data, data_left); + + DEBUG(10,("write_to_pipe: data_used = %d\n", (int)data_used )); + + if(data_used < 0) + return -1; + + data_left -= data_used; + data += data_used; + } + + return n; } @@ -282,7 +701,7 @@ int read_from_pipe(pipes_struct *p, char *data, int n) DEBUG(6,("read_from_pipe: %x", p->pnum)); - DEBUG(6,("name: %s len: %d\n", p->name, n)); + DEBUG(6,(" name: %s len: %d\n", p->name, n)); /* * We cannot return more than one PDU length per @@ -320,8 +739,9 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len, * may of course be zero if this is the first return fragment. */ - DEBUG(10,("read_from_pipe: %s: data_sent_length = %u, prs_offset(&p->out_data.rdata) = %u.\n", - p->name, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) )); + DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length \ += %u, prs_offset(&p->out_data.rdata) = %u.\n", + p->name, (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) )); if(p->out_data.data_sent_length >= prs_offset(&p->out_data.rdata)) { /* @@ -415,22 +835,17 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn) pipes_open--; - 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 (p->m != NULL) { + DEBUG(4,("close_rpc_pipe_hnd: closing msrpc redirect: ")); if (msrpc_use_del(p->m->pipe_name, &p->m->usr, False, NULL)) - { DEBUG(4,("OK\n")); - } else - { DEBUG(4,("FAILED\n")); - } } + DEBUG(4,("closed pipe name %s pnum=%x (pipes_open=%d)\n", + p->name, p->pnum, pipes_open)); + DLIST_REMOVE(Pipes, p); ZERO_STRUCTP(p); diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 5ee70e7d94..d42c2727d4 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -3201,20 +3201,11 @@ 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, - char *redir_data, int redir_len) +static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p) { - char *rdata; + char *rdata = malloc(p->max_trans_reply); 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; @@ -3340,23 +3331,11 @@ static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf, switch (subcommand) { case 0x26: - { - 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); - } + /* dce/rpc command */ + reply = write_to_pipe(p, data, tdscnt); if (reply) - reply = api_rpc_trans_reply(outbuf, p, rdata, rlen); + reply = api_rpc_trans_reply(outbuf, p); 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 1a9ac1d7a4..65a71e1c00 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -129,16 +129,7 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) if (numtowrite == 0) nwritten = 0; else - { - if (p->m != NULL) - { - nwritten = write_pipe(p, data, numtowrite); - } - else - { - nwritten = write_to_pipe(p, data, numtowrite); - } - } + nwritten = write_to_pipe(p, data, numtowrite); if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) return (UNIXERROR(ERRDOS,ERRnoaccess)); @@ -154,17 +145,19 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) } /**************************************************************************** - reply to a write and X + Reply to a write and X. - This code is basically stolen from reply_write_and_X with some - wrinkles to handle pipes. + This code is basically stolen from reply_write_and_X with some + wrinkles to handle pipes. ****************************************************************************/ + int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) { pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2); size_t numtowrite = SVAL(inbuf,smb_vwv10); int nwritten = -1; int smb_doff = SVAL(inbuf, smb_vwv11); + BOOL pipe_start_message_raw = ((SVAL(inbuf, smb_vwv7) & (PIPE_START_MESSAGE|PIPE_RAW_MODE)) != 0); char *data; if (!p) @@ -174,14 +167,31 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) if (numtowrite == 0) nwritten = 0; - else + else { + if(pipe_start_message_raw) { + /* + * For the start of a message in named pipe byte mode, + * the first two bytes are a length-of-pdu field. Ignore + * them (we don't trust the client. JRA. + */ + if(numtowrite < 2) { + DEBUG(0,("reply_pipe_write_and_X: start of message set and not enough data sent.(%u)\n", + (unsigned int)numtowrite )); + return (UNIXERROR(ERRDOS,ERRnoaccess)); + } + + data += 2; + numtowrite -= 2; + } nwritten = write_to_pipe(p, data, numtowrite); + } if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) return (UNIXERROR(ERRDOS,ERRnoaccess)); set_message(outbuf,6,0,True); + nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten); SSVAL(outbuf,smb_vwv2,nwritten); DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", @@ -216,14 +226,7 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) set_message(outbuf,12,0,True); data = smb_buf(outbuf); - if (p->m != NULL) - { - nread = read_pipe(p, data, smb_maxcnt); - } - else - { - nread = read_from_pipe(p, data, smb_maxcnt); - } + nread = read_from_pipe(p, data, smb_maxcnt); if (nread < 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); |