From cba7662da1fd9ed8bd9f9969417adf1fe5f0d33b Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Thu, 7 Oct 1999 22:10:29 +0000 Subject: - added rudimentary CAP_UNICODE support because i thought it was part of a problem i was having. - added rudimentary CAP_STATUS32 support for same reason. - added hard-coded, copy-the-same-data-from-over-the-wire version of CAP_EXTENDED_SECURITY, which is a security-blob to encapsulate GSSAPI which encodes SPNEGO which is used to negotiate Kerberos or NTLMSSP. i have implemented NTLMSSP which negotiates NTLMv1 or NTLMv2 and 40-bit or 128-bit etc. i have implemented NTLMv1 / 40-bit. *whew*. (This used to be commit e5b80bd2f76fda70e41e4a9007eb035dab92ed8e) --- source3/include/proto.h | 13 +- source3/include/smb.h | 26 +-- source3/lib/util_str.c | 2 +- source3/lib/util_unistr.c | 5 +- source3/libsmb/clientgen.c | 466 +++++++++++++++++++++++++++++++++++------- source3/libsmb/pwd_cache.c | 21 ++ source3/rpc_client/cli_pipe.c | 45 ++-- source3/rpc_parse/parse_rpc.c | 30 ++- 8 files changed, 503 insertions(+), 105 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 5172dfb495..5984a845dd 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -604,7 +604,7 @@ char *enum_field_to_str(uint32 type, struct field_info *bs, BOOL first_default); /*The following definitions come from lib/util_unistr.c */ char *ascii_to_unibuf(char *dest, const char *src, int maxlen); -void unibuf_to_ascii(char *dest, const char *src, int maxlen); +const char *unibuf_to_ascii(char *dest, const char *src, int maxlen); void ascii_to_unistr(uint16 *dest, const char *src, int maxlen); void unistr_to_ascii(char *dest, const uint16 *src, int len); void unistr2_to_ascii(char *dest, const UNISTR2 *str, int maxlen); @@ -1779,6 +1779,17 @@ BOOL synchronise_passdb(void); /*The following definitions come from rpc_client/cli_pipe.c */ +void create_ntlmssp_resp(struct pwd_info *pwd, + char *domain, char *user_name, char *my_name, + uint32 ntlmssp_cli_flgs, + prs_struct *auth_resp); +BOOL create_rpc_bind_resp(struct pwd_info *pwd, + char *domain, char *user_name, char *my_name, + uint32 ntlmssp_cli_flgs, + uint32 rpc_call_id, + prs_struct *rhdr, + prs_struct *rhdr_autha, + prs_struct *auth_resp); BOOL rpc_api_pipe_req(struct cli_state *cli, uint16 nt_pipe_fnum, uint8 op_num, prs_struct *data, prs_struct *rdata); void cli_nt_set_ntlmssp_flgs(struct cli_state *cli, uint32 ntlmssp_flgs); diff --git a/source3/include/smb.h b/source3/include/smb.h index 88890de374..80860cf57c 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1492,6 +1492,7 @@ char *strdup(char *s); #define FLAGS2_LONG_PATH_COMPONENTS 0x0001 #define FLAGS2_EXTENDED_ATTRIBUTES 0x0002 +#define FLAGS2_EXT_SEC 0x0800 #define FLAGS2_DFS_PATHNAMES 0x1000 #define FLAGS2_READ_PERMIT_NO_EXECUTE 0x2000 #define FLAGS2_32_BIT_ERROR_CODES 0x4000 @@ -1499,18 +1500,19 @@ char *strdup(char *s); /* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */ -#define CAP_RAW_MODE 0x0001 -#define CAP_MPX_MODE 0x0002 -#define CAP_UNICODE 0x0004 -#define CAP_LARGE_FILES 0x0008 -#define CAP_NT_SMBS 0x0010 -#define CAP_RPC_REMOTE_APIS 0x0020 -#define CAP_STATUS32 0x0040 -#define CAP_LEVEL_II_OPLOCKS 0x0080 -#define CAP_LOCK_AND_READ 0x0100 -#define CAP_NT_FIND 0x0200 -#define CAP_DFS 0x1000 -#define CAP_LARGE_READX 0x4000 +#define CAP_RAW_MODE 0x00000001 +#define CAP_MPX_MODE 0x00000002 +#define CAP_UNICODE 0x00000004 +#define CAP_LARGE_FILES 0x00000008 +#define CAP_NT_SMBS 0x00000010 +#define CAP_RPC_REMOTE_APIS 0x00000020 +#define CAP_STATUS32 0x00000040 +#define CAP_LEVEL_II_OPLOCKS 0x00000080 +#define CAP_LOCK_AND_READ 0x00000100 +#define CAP_NT_FIND 0x00000200 +#define CAP_DFS 0x00001000 +#define CAP_LARGE_READX 0x00004000 +#define CAP_EXTENDED_SECURITY 0x80000000 /* protocol types. It assumes that higher protocols include lower protocols as subsets */ diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c index 4c6a993777..636be164ac 100644 --- a/source3/lib/util_str.c +++ b/source3/lib/util_str.c @@ -462,7 +462,7 @@ char *skip_string(char *buf,size_t n) { while (n--) buf += strlen(buf) + 1; - return(buf); + return buf; } /******************************************************************* diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c index 4e7872021b..e047697a0f 100644 --- a/source3/lib/util_unistr.c +++ b/source3/lib/util_unistr.c @@ -51,8 +51,7 @@ char *ascii_to_unibuf(char *dest, const char *src, int maxlen) /******************************************************************* Pull an ASCII string out of a UNICODE buffer (little endian). ********************************************************************/ - -void unibuf_to_ascii(char *dest, const char *src, int maxlen) +const char *unibuf_to_ascii(char *dest, const char *src, int maxlen) { char *destend = dest + maxlen; register char c; @@ -70,6 +69,8 @@ void unibuf_to_ascii(char *dest, const char *src, int maxlen) } *dest = 0; + + return src; } diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 6d704dc144..8db5bd6e00 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -42,6 +42,56 @@ int cli_set_port(struct cli_state *cli, int port) } +/**************************************************************************** +copy a string (unicode or otherwise) into an SMB buffer. skips a string +plus points to next +****************************************************************************/ +static char *cli_put_string(struct cli_state *cli, char *p, const char *str, + BOOL skip_end) +{ + uint16 flgs2 = SVAL(cli->outbuf, smb_flg2); + if (IS_BITS_SET_ALL(flgs2, FLAGS2_UNICODE_STRINGS)) + { + p = align2(p, cli->outbuf); + p = ascii_to_unibuf(p, str, 1024); + if (skip_end) + { + CVAL(p, 0) = 0; p++; + CVAL(p, 0) = 0; p++; + } + return p; + } + else + { + pstrcpy(p, str); + p = skip_string(p, 1); + if (skip_end) + { + CVAL(p, 0) = 0; p++; + } + return p; + } +} + +/**************************************************************************** +copy a string (unicode or otherwise) into an SMB buffer. skips a string +plus points to next +****************************************************************************/ +static const char *cli_get_string(struct cli_state *cli, const char *p, + char *str, size_t str_len) +{ + uint16 flgs2 = SVAL(cli->inbuf,smb_flg2); + if (IS_BITS_SET_ALL(flgs2, FLAGS2_UNICODE_STRINGS)) + { + return unibuf_to_ascii(str, p, str_len); + } + else + { + safe_strcpy(str, p, str_len-1); + return skip_string(p, 1); + } +} + /**************************************************************************** recv an smb ****************************************************************************/ @@ -202,14 +252,24 @@ setup basics in a outgoing packet ****************************************************************************/ static void cli_setup_packet(struct cli_state *cli) { + uint16 flgs2 = 0; + flgs2 |= FLAGS2_LONG_PATH_COMPONENTS; + flgs2 |= FLAGS2_32_BIT_ERROR_CODES; +#if 0 + flgs2 |= FLAGS2_UNICODE_STRINGS; +#endif + flgs2 |= FLAGS2_EXT_SEC; + cli->rap_error = 0; cli->nt_error = 0; SSVAL(cli->outbuf,smb_pid,cli->pid); SSVAL(cli->outbuf,smb_uid,cli->vuid); SSVAL(cli->outbuf,smb_mid,cli->mid); - if (cli->protocol > PROTOCOL_CORE) { + + if (cli->protocol > PROTOCOL_CORE) + { SCVAL(cli->outbuf,smb_flg,0x8); - SSVAL(cli->outbuf,smb_flg2,0x1); + SSVAL(cli->outbuf,smb_flg2,flgs2); } } @@ -705,7 +765,13 @@ BOOL cli_session_setup_x(struct cli_state *cli, char *ntpass, int ntpasslen, char *user_domain) { + uint8 eclass; + uint32 ecode; char *p; + BOOL esec = cli->capabilities & CAP_EXTENDED_SECURITY; + + DEBUG(100,("cli_session_setup. extended security: %s\n", + BOOLSTR(esec))); #ifdef DEBUG_PASSWORD DEBUG(100,("cli_session_setup. pass, ntpass\n")); @@ -739,7 +805,31 @@ BOOL cli_session_setup_x(struct cli_state *cli, pstrcpy(p,user); strupper(p); } - else + else if (esec) + { + set_message(cli->outbuf,12,0,True); + CVAL(cli->outbuf,smb_com) = SMBsesssetupX; + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE); + SSVAL(cli->outbuf,smb_vwv3,2); + SSVAL(cli->outbuf,smb_vwv4,cli->pid); + SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); + SSVAL(cli->outbuf,smb_vwv7,passlen); + SIVAL(cli->outbuf,smb_vwv10, CAP_EXTENDED_SECURITY|CAP_STATUS32|CAP_UNICODE); + p = smb_buf(cli->outbuf); + memcpy(p,pass,passlen); + p += passlen; + + p = cli_put_string(cli, p, "Unix", False); + p = cli_put_string(cli, p, "Samba", False); + p = cli_put_string(cli, p, "", False); + p++; + + set_message(cli->outbuf,12,PTR_DIFF(p,smb_buf(cli->outbuf)),False); + } + else { set_message(cli->outbuf,13,0,True); CVAL(cli->outbuf,smb_com) = SMBsesssetupX; @@ -758,44 +848,65 @@ BOOL cli_session_setup_x(struct cli_state *cli, p += SVAL(cli->outbuf,smb_vwv7); memcpy(p,ntpass,ntpasslen); p += SVAL(cli->outbuf,smb_vwv8); - pstrcpy(p,user); - strupper(p); - p = skip_string(p,1); - pstrcpy(p,user_domain); - strupper(p); - p = skip_string(p,1); - pstrcpy(p,"Unix");p = skip_string(p,1); - CVAL(p, 0) = 0; p++; - pstrcpy(p,"Samba");p = skip_string(p,1); + strupper(user); + p = cli_put_string(cli, p, user, False); + strupper(user_domain); + p = cli_put_string(cli, p, user_domain, False); + p = cli_put_string(cli, p, "Unix", True); + p = cli_put_string(cli, p, "Samba", False); + set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False); } - cli_send_smb(cli, True); - if (!cli_receive_smb(cli)) + cli_send_smb(cli, True); + if (!cli_receive_smb(cli)) { DEBUG(10,("cli_session_setup_x: receive smb failed\n")); return False; } - if (CVAL(cli->inbuf,smb_rcls) != 0) { - return False; - } + if (cli_error(cli, &eclass, &ecode)) + { + uint16 flgs2 = SVAL(cli->inbuf,smb_flg2); + if (IS_BITS_CLR_ALL(flgs2, FLAGS2_32_BIT_ERROR_CODES)) + { + if (ecode != ERRmoredata || !esec) + { + return False; + } + } + else if (ecode != 0xC0000016) /* STATUS_MORE_PROCESSING_REQD */ + { + return False; + } + } + + /* use the returned vuid from now on */ + cli->vuid = SVAL(cli->inbuf,smb_uid); - /* use the returned vuid from now on */ - cli->vuid = SVAL(cli->inbuf,smb_uid); - - if (cli->protocol >= PROTOCOL_NT1) { - /* - * Save off some of the connected server - * info. - */ - char *server_domain,*server_os,*server_type; - server_os = smb_buf(cli->inbuf); - server_type = skip_string(server_os,1); - server_domain = skip_string(server_type,1); - fstrcpy(cli->server_os, server_os); - fstrcpy(cli->server_type, server_type); - fstrcpy(cli->server_domain, server_domain); + if (cli->protocol >= PROTOCOL_NT1) + { + if (esec) + { + } + else + { + /* + * Save off some of the connected server + * info. + */ + char *server_domain; + char *server_os; + char *server_type; + + server_os = smb_buf(cli->inbuf); + server_type = skip_string(server_os,1); + server_domain = skip_string(server_type,1); + + fstrcpy(cli->server_os, server_os); + fstrcpy(cli->server_type, server_type); + fstrcpy(cli->server_domain, server_domain); + } } return True; @@ -1003,8 +1114,7 @@ BOOL cli_send_tconX(struct cli_state *cli, "\\\\%s\\%s", cli->desthost, share); strupper(fullshare); - set_message(cli->outbuf,4, - 2 + strlen(fullshare) + passlen + strlen(dev),True); + set_message(cli->outbuf,4, 0, True); CVAL(cli->outbuf,smb_com) = SMBtconX; cli_setup_packet(cli); @@ -1014,9 +1124,11 @@ BOOL cli_send_tconX(struct cli_state *cli, p = smb_buf(cli->outbuf); memcpy(p,pword,passlen); p += passlen; - fstrcpy(p,fullshare); - p = skip_string(p,1); - pstrcpy(p,dev); + p = cli_put_string(cli, p, fullshare, False); + fstrcpy(p, dev); + p = skip_string(p, 1); + + set_message(cli->outbuf,4,PTR_DIFF(p, smb_buf(cli->outbuf)),False); SCVAL(cli->inbuf,smb_rcls, 1); @@ -1030,8 +1142,10 @@ BOOL cli_send_tconX(struct cli_state *cli, fstrcpy(cli->dev, "A:"); - if (cli->protocol >= PROTOCOL_NT1) { - fstrcpy(cli->dev, smb_buf(cli->inbuf)); + if (cli->protocol >= PROTOCOL_NT1) + { + cli_get_string(cli, smb_buf(cli->inbuf), + cli->dev, sizeof(cli->dev)); } if (strcasecmp(share,"IPC$")==0) { @@ -1039,8 +1153,8 @@ BOOL cli_send_tconX(struct cli_state *cli, } /* only grab the device if we have a recent protocol level */ - if (cli->protocol >= PROTOCOL_NT1 && - smb_buflen(cli->inbuf) == 3) { + if (cli->protocol >= PROTOCOL_NT1 && smb_buflen(cli->inbuf) == 3) + { /* almost certainly win95 - enable bug fixes */ cli->win95 = True; } @@ -1304,8 +1418,9 @@ int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode) SSVAL(cli->outbuf,smb_vwv8,openfn); p = smb_buf(cli->outbuf); - pstrcpy(p,fname); - p = skip_string(p,1); + p = cli_put_string(cli, p, fname, False); + + set_message(cli->outbuf,15,PTR_DIFF(p, smb_buf(cli->outbuf)),False); cli_send_smb(cli, True); if (!cli_receive_smb(cli)) { @@ -2412,23 +2527,37 @@ BOOL cli_negprot(struct cli_state *cli) cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60; /* this time arrives in real GMT */ cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1); - memcpy(cli->cryptkey, buf,8); - if (bcc > 8) + + cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1); + if (IS_BITS_SET_ALL(cli->capabilities, CAP_RAW_MODE)) { - unibuf_to_ascii(cli->server_domain, buf+8, - sizeof(cli->server_domain)); + cli->readbraw_supported = True; + cli->writebraw_supported = True; } - else + + if (IS_BITS_SET_ALL(cli->capabilities, CAP_EXTENDED_SECURITY)) { + /* oops, some kerberos-related nonsense. */ + /* expect to have to use NTLMSSP-over-SMB */ + DEBUG(10,("unknown kerberos-related (?) blob\n")); + memset(cli->cryptkey, 0, 8); cli->server_domain[0] = 0; } - cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1); - if (cli->capabilities & CAP_RAW_MODE) { - cli->readbraw_supported = True; - cli->writebraw_supported = True; + else + { + memcpy(cli->cryptkey, buf,8); + if (bcc > 8) + { + unibuf_to_ascii(cli->server_domain, buf+8, + sizeof(cli->server_domain)); + } + else + { + cli->server_domain[0] = 0; + } + DEBUG(5,("server's domain: %s bcc: %d\n", + cli->server_domain, bcc)); } - DEBUG(5,("server's domain: %s bcc: %d\n", - cli->server_domain, bcc)); } else if (cli->protocol >= PROTOCOL_LANMAN1) { @@ -2659,24 +2788,26 @@ int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num) if (eclass) *eclass = 0; if (num ) *num = 0; - if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) { + if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) + { /* 32 bit error codes detected */ uint32 nt_err = IVAL(cli->inbuf,smb_rcls); if (num) *num = nt_err; DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err)); if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0; - switch (nt_err & 0xFFFFFF) { - case NT_STATUS_ACCESS_VIOLATION: return EACCES; - case NT_STATUS_NO_SUCH_FILE: return ENOENT; - case NT_STATUS_NO_SUCH_DEVICE: return ENODEV; - case NT_STATUS_INVALID_HANDLE: return EBADF; - case NT_STATUS_NO_MEMORY: return ENOMEM; - case NT_STATUS_ACCESS_DENIED: return EACCES; - case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT; - case NT_STATUS_SHARING_VIOLATION: return EBUSY; - case NT_STATUS_OBJECT_PATH_INVALID: return ENOTDIR; - case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST; + switch (nt_err & 0xFFFFFF) + { + case NT_STATUS_ACCESS_VIOLATION : return EACCES; + case NT_STATUS_NO_SUCH_FILE : return ENOENT; + case NT_STATUS_NO_SUCH_DEVICE : return ENODEV; + case NT_STATUS_INVALID_HANDLE : return EBADF; + case NT_STATUS_NO_MEMORY : return ENOMEM; + case NT_STATUS_ACCESS_DENIED : return EACCES; + case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT; + case NT_STATUS_SHARING_VIOLATION : return EBUSY; + case NT_STATUS_OBJECT_PATH_INVALID : return ENOTDIR; + case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST; } /* for all other cases - a default code */ @@ -2856,7 +2987,202 @@ BOOL cli_establish_connection(struct cli_state *cli, sizeof(cli->domain)); } - if (cli->pwd.cleartext || cli->pwd.null_pwd) + if (IS_BITS_SET_ALL(cli->capabilities, CAP_EXTENDED_SECURITY)) + { + /* common to both session setups */ + char pwd_buf[128]; + int buf_len; + char *p; + char *e = pwd_buf + sizeof(pwd_buf); + + /* 1st session setup */ + char pwd_data[34] = + { + 0x60, 0x40, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x02, 0xa0, 0x36, 0x30, 0x34, 0xa0, 0x0e, + 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, + 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x22, + 0x04, 0x20 + }; + /* 2nd session setup */ +#if 0 + char pwd_data_2[8] = + { + 0xa1, 0x51, 0x30, 0x4f, 0xa2, 0x4d, 0x04, 0x4b + }; +#endif + char pwd_data_2[8] = + { + 0xa1, 0x51, 0x30, 0x4f, 0xa2, 0x4d, 0x04, 0x4b + }; + prs_struct auth_resp; + int resp_len; + char *p_gssapi; + char *p_oem; + char *p_gssapi_end; + uint16 gssapi_len; + + memset(pwd_buf, 0, sizeof(pwd_buf)); + memcpy(pwd_buf, pwd_data, sizeof(pwd_data)); + p = pwd_buf + sizeof(pwd_data); + + safe_strcpy(p, "NTLMSSP", PTR_DIFF(e, p) - 1); + p = skip_string(p, 1); + CVAL(p, 0) = 0x1; + p += 4; + if (cli->ntlmssp_cli_flgs == 0) + { + cli->ntlmssp_cli_flgs = + NTLMSSP_NEGOTIATE_UNICODE | + NTLMSSP_NEGOTIATE_OEM | + NTLMSSP_NEGOTIATE_SIGN | + NTLMSSP_NEGOTIATE_SEAL | + NTLMSSP_NEGOTIATE_LM_KEY | + NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_NEGOTIATE_ALWAYS_SIGN | + NTLMSSP_NEGOTIATE_00001000 | + NTLMSSP_NEGOTIATE_00002000; +#if 0 + cli->ntlmssp_cli_flgs = 0x80008207; +#endif + } + SIVAL(p, 0, cli->ntlmssp_cli_flgs); + p += 4; + p += 16; /* skip some NULL space */ + CVAL(p, 0) = 0; p++; /* alignment */ + + buf_len = PTR_DIFF(p, pwd_buf); + + /* first session negotiation stage */ + if (!cli_session_setup_x(cli, cli->user_name, + pwd_buf, buf_len, + NULL, 0, + cli->domain)) + { + DEBUG(1,("failed session setup\n")); + if (do_shutdown) + { + cli_shutdown(cli); + } + return False; + } + + DEBUG(1,("1st session setup ok\n")); + + if (*cli->server_domain || *cli->server_os || *cli->server_type) + { + DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n", + cli->server_domain, + cli->server_os, + cli->server_type)); + } + + p = smb_buf(cli->inbuf) + 0x2f; + cli->ntlmssp_cli_flgs = IVAL(p, 0); /* 0x80808a05; */ + p += 4; + memcpy(cli->cryptkey, p, 8); +#ifdef DEBUG_PASSWORD + DEBUG(100,("cli_session_setup_x: ntlmssp %8x\n", + cli->ntlmssp_cli_flgs)); + + DEBUG(100,("cli_session_setup_x: crypt key\n")); + dump_data(100, cli->cryptkey, 8); +#endif + prs_init(&auth_resp, 1024, 4, SAFETY_MARGIN, False); + + pwd_make_lm_nt_owf(&cli->pwd, cli->cryptkey); + + create_ntlmssp_resp(&cli->pwd, cli->domain, + cli->user_name, cli->calling.name, + cli->ntlmssp_cli_flgs, + &auth_resp); + prs_link(NULL, &auth_resp, NULL); + + memset(pwd_buf, 0, sizeof(pwd_buf)); + p = pwd_buf; + + CVAL(p, 0) = 0xa1; p++; + CVAL(p, 0) = 0x82; p++; + p_gssapi = p; p+= 2; + CVAL(p, 0) = 0x30; p++; + CVAL(p, 0) = 0x82; p++; + p += 2; + + CVAL(p, 0) = 0xa2; p++; + CVAL(p, 0) = 0x82; p++; + p_oem = p; p+= 2; + CVAL(p, 0) = 0x04; p++; + CVAL(p, 0) = 0x82; p++; + p += 2; + + p_gssapi_end = p; + + safe_strcpy(p, "NTLMSSP", PTR_DIFF(e, p) - 1); + p = skip_string(p, 1); + CVAL(p, 0) = 0x3; + p += 4; + + resp_len = mem_buf_len(auth_resp.data); + mem_buf_copy(p, auth_resp.data, 0, resp_len); + prs_mem_free(&auth_resp); + + p += resp_len; + + buf_len = PTR_DIFF(p, pwd_buf); + gssapi_len = PTR_DIFF(p, p_gssapi_end) + 12; + + *p_gssapi++ = (gssapi_len >> 8) & 0xff; + *p_gssapi++ = gssapi_len & 0xff; + + p_gssapi += 2; + gssapi_len -= 4; + + *p_gssapi++ = (gssapi_len >> 8) & 0xff; + *p_gssapi++ = gssapi_len & 0xff; + + gssapi_len -= 4; + + *p_oem++ = (gssapi_len >> 8) & 0xff; + *p_oem++ = gssapi_len & 0xff; + + p_oem += 2; + gssapi_len -= 4; + + *p_oem++ = (gssapi_len >> 8) & 0xff; + *p_oem++ = gssapi_len & 0xff; + + /* second session negotiation stage */ + if (!cli_session_setup_x(cli, cli->user_name, + pwd_buf, buf_len, + NULL, 0, + cli->domain)) + { + DEBUG(1,("failed session setup\n")); + if (do_shutdown) + { + cli_shutdown(cli); + } + return False; + } + + DEBUG(1,("2nd session setup ok\n")); + + if (do_tcon) + { + if (!cli_send_tconX(cli, service, service_type, + NULL, 0)) + + { + DEBUG(1,("failed tcon_X\n")); + if (do_shutdown) + { + cli_shutdown(cli); + } + return False; + } + } + } + else if (cli->pwd.cleartext || cli->pwd.null_pwd) { fstring passwd, ntpasswd; int pass_len = 0, ntpass_len = 0; @@ -2925,9 +3251,9 @@ BOOL cli_establish_connection(struct cli_state *cli, /* attempt encrypted session */ if (!cli_session_setup_x(cli, cli->user_name, - (char*)lm_sess_pwd, sizeof(lm_sess_pwd), - (char*)nt_sess_pwd, nt_sess_pwd_len, - cli->domain)) + (char*)lm_sess_pwd, sizeof(lm_sess_pwd), + (char*)nt_sess_pwd, nt_sess_pwd_len, + cli->domain)) { DEBUG(1,("failed session setup\n")); diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c index 655df5be8a..c8b0e6a442 100644 --- a/source3/libsmb/pwd_cache.c +++ b/source3/libsmb/pwd_cache.c @@ -34,6 +34,7 @@ void pwd_init(struct pwd_info *pwd) bzero(pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd)); bzero(pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf)); bzero(pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf)); + pwd->nt_owf_len = 0; pwd->null_pwd = True; /* safest option... */ pwd->cleartext = False; @@ -259,6 +260,14 @@ void pwd_make_lm_nt_owf2(struct pwd_info *pwd, const uchar srv_key[8], ****************************************************************************/ void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]) { + if (pwd->null_pwd) + { +#ifdef DEBUG_PASSWORD + DEBUG(100,("pwd_make_lm_nt_owf: NULL password\n")); +#endif + pwd->nt_owf_len = 0; + return; + } pwd_deobfuscate(pwd); SMBOWFencrypt(pwd->smb_lm_pwd, cryptkey, pwd->smb_lm_owf); @@ -291,6 +300,18 @@ void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]) void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar *nt_owf, size_t *nt_owf_len) { + if (pwd->null_pwd) + { +#ifdef DEBUG_PASSWORD + DEBUG(100,("pwd_get_lm_nt_owf: NULL password\n")); +#endif + if (nt_owf_len != NULL) + { + *nt_owf_len = 0; + } + return; + } + pwd_deobfuscate(pwd); if (lm_owf != NULL) { diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index d5745adb55..0453bb3125 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -473,6 +473,34 @@ static BOOL create_rpc_bind_req(prs_struct *rhdr, return True; } +/******************************************************************* + creates a DCE/RPC bind authentication response + + - initialises the parse structure. + - dynamically allocates the header data structure + - caller is expected to free the header data structure once used. + + ********************************************************************/ +void create_ntlmssp_resp(struct pwd_info *pwd, + char *domain, char *user_name, char *my_name, + uint32 ntlmssp_cli_flgs, + prs_struct *auth_resp) +{ + RPC_AUTH_NTLMSSP_RESP ntlmssp_resp; + unsigned char lm_owf[24]; + unsigned char nt_owf[128]; + size_t nt_owf_len; + + pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf, &nt_owf_len); + + make_rpc_auth_ntlmssp_resp(&ntlmssp_resp, + lm_owf, nt_owf, nt_owf_len, + domain, user_name, my_name, + ntlmssp_cli_flgs); + + smb_io_rpc_auth_ntlmssp_resp("ntlmssp_resp", &ntlmssp_resp, auth_resp, 0); + mem_realloc_data(auth_resp->data, auth_resp->offset); +} /******************************************************************* creates a DCE/RPC bind authentication response @@ -482,7 +510,7 @@ static BOOL create_rpc_bind_req(prs_struct *rhdr, - caller is expected to free the header data structure once used. ********************************************************************/ -static BOOL create_rpc_bind_resp(struct pwd_info *pwd, +BOOL create_rpc_bind_resp(struct pwd_info *pwd, char *domain, char *user_name, char *my_name, uint32 ntlmssp_cli_flgs, uint32 rpc_call_id, @@ -490,13 +518,9 @@ static BOOL create_rpc_bind_resp(struct pwd_info *pwd, prs_struct *rhdr_autha, prs_struct *auth_resp) { - unsigned char lm_owf[24]; - unsigned char nt_owf[128]; - size_t nt_owf_len; RPC_HDR hdr; RPC_HDR_AUTHA hdr_autha; RPC_AUTH_NTLMSSP_VERIFIER auth_verifier; - RPC_AUTH_NTLMSSP_RESP ntlmssp_resp; make_rpc_hdr_autha(&hdr_autha, 0x1630, 0x1630, 0x0a, 0x06, 0x00); smb_io_rpc_hdr_autha("hdr_autha", &hdr_autha, rhdr_autha, 0); @@ -508,15 +532,8 @@ static BOOL create_rpc_bind_resp(struct pwd_info *pwd, smb_io_rpc_auth_ntlmssp_verifier("auth_verifier", &auth_verifier, auth_resp, 0); mem_realloc_data(auth_resp->data, auth_resp->offset); - pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf, &nt_owf_len); - - make_rpc_auth_ntlmssp_resp(&ntlmssp_resp, - lm_owf, nt_owf, nt_owf_len, - domain, user_name, my_name, - ntlmssp_cli_flgs); - - smb_io_rpc_auth_ntlmssp_resp("ntlmssp_resp", &ntlmssp_resp, auth_resp, 0); - mem_realloc_data(auth_resp->data, auth_resp->offset); + create_ntlmssp_resp(pwd, domain, user_name, my_name, ntlmssp_cli_flgs, + auth_resp); /* create the request RPC_HDR */ make_rpc_hdr(&hdr, RPC_BINDRESP, 0x0, rpc_call_id, diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c index 138dbd90b1..19cb4dfa4b 100644 --- a/source3/rpc_parse/parse_rpc.c +++ b/source3/rpc_parse/parse_rpc.c @@ -702,7 +702,7 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, int dom_len = strlen(domain); int wks_len = strlen(wks ); int usr_len = strlen(user ); - int lm_len = lm_resp != NULL ? 24 : 0; + int lm_len = nt_len != 0 ? (lm_resp != NULL ? 24 : 0) : 1; DEBUG(5,("make_rpc_auth_ntlmssp_resp\n")); @@ -710,9 +710,15 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, #ifdef DEBUG_PASSWORD DEBUG(100,("lm_resp\n")); - dump_data(100, lm_resp, lm_len); + if (lm_resp != NULL) + { + dump_data(100, lm_resp, lm_len); + } DEBUG(100,("nt_resp\n")); - dump_data(100, nt_resp, nt_len); + if (nt_resp != NULL) + { + dump_data(100, nt_resp, nt_len); + } #endif DEBUG(6,("dom: %s user: %s wks: %s neg_flgs: 0x%x\n", @@ -746,8 +752,22 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, rsp->neg_flags = neg_flags; - memcpy(rsp->lm_resp, lm_resp, lm_len); - memcpy(rsp->nt_resp, nt_resp, nt_len); + if (lm_resp != NULL && lm_len != 1) + { + memcpy(rsp->lm_resp, lm_resp, lm_len); + } + else + { + rsp->lm_resp[0] = 0; + } + if (nt_resp != NULL) + { + memcpy(rsp->nt_resp, nt_resp, nt_len); + } + else + { + rsp->nt_resp[0] = 0; + } if (IS_BITS_SET_ALL(neg_flags, NTLMSSP_NEGOTIATE_UNICODE)) { -- cgit