From 73891ca8e4f6cca6aa8bb0ae043f660a64baa056 Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Tue, 29 Jun 1999 18:47:06 +0000 Subject: improving authentication code (tidyup). (This used to be commit ab1a6aa42db5217f025941fb5107436556bc23b7) --- source3/include/client.h | 27 ++-- source3/include/proto.h | 58 ++++++--- source3/include/rpc_dce.h | 4 +- source3/lib/hmacmd5.c | 5 +- source3/lib/util.c | 6 +- source3/libsmb/clientgen.c | 259 ++++++++++++++++++++++++++------------ source3/libsmb/pwd_cache.c | 82 ++++++++++-- source3/libsmb/smbencrypt.c | 271 +++++++++++++++++++++++++++++++++------- source3/param/loadparm.c | 8 +- source3/passdb/sampassdb.c | 1 - source3/rpc_client/cli_pipe.c | 9 +- source3/rpc_parse/parse_rpc.c | 12 +- source3/rpc_server/srv_netlog.c | 45 +++---- source3/rpc_server/srv_pipe.c | 38 ++++-- source3/rpcclient/rpcclient.c | 2 + source3/smbd/password.c | 147 +++++++++++++++------- source3/smbd/reply.c | 8 +- source3/smbd/service.c | 4 +- source3/utils/rpctorture.c | 2 + 19 files changed, 721 insertions(+), 267 deletions(-) (limited to 'source3') diff --git a/source3/include/client.h b/source3/include/client.h index 89bcf49248..b06d877181 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -58,17 +58,22 @@ struct print_job_info struct pwd_info { - BOOL null_pwd; - BOOL cleartext; - BOOL crypted; + BOOL null_pwd; + BOOL cleartext; + BOOL crypted; - fstring password; + fstring password; - uchar smb_lm_pwd[16]; - uchar smb_nt_pwd[16]; + uchar smb_lm_pwd[16]; + uchar smb_nt_pwd[16]; - uchar smb_lm_owf[24]; - uchar smb_nt_owf[24]; + uchar smb_lm_owf[24]; + uchar smb_nt_owf[128]; + size_t nt_owf_len; + + uchar lm_cli_chal[8]; + uchar nt_cli_chal[128]; + size_t nt_cli_chal_len; }; struct cli_state { @@ -106,6 +111,12 @@ struct cli_state { struct pwd_info pwd; unsigned char cryptkey[8]; + unsigned char lm_cli_chal[8]; + unsigned char nt_cli_chal[128]; + size_t nt_cli_chal_len; + + BOOL use_ntlmv2; + uint32 sesskey; int serverzone; uint32 servertime; diff --git a/source3/include/proto.h b/source3/include/proto.h index 361eda72b5..7673fc2ed5 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -229,8 +229,9 @@ char *getsmbpass(char *prompt) ; /*The following definitions come from lib/hmacmd5.c */ void hmac_md5_init_rfc2104(uchar* key, int key_len, HMACMD5Context *ctx); -void hmac_md5_init_limK_to_64(uchar* key, int key_len, HMACMD5Context *ctx); -void hmac_md5_update(uchar* text, int text_len, HMACMD5Context *ctx); +void hmac_md5_init_limK_to_64(const uchar* key, int key_len, + HMACMD5Context *ctx); +void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx); void hmac_md5_final(caddr_t digest, HMACMD5Context *ctx); /*The following definitions come from lib/interface.c */ @@ -466,8 +467,8 @@ char *align4(char *q, char *base); char *align2(char *q, char *base); void out_ascii(FILE *f, unsigned char *buf,int len); void out_data(FILE *f,char *buf1,int len, int per_line); -void print_asc(int level, unsigned char *buf,int len); -void dump_data(int level,char *buf1, int len); +void print_asc(int level, unsigned char const *buf,int len); +void dump_data(int level, const char *buf1, int len); char *tab_depth(int depth); int str_checksum(const char *s); void zero_free(void *p, size_t size); @@ -621,11 +622,16 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation); BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *)); BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, void (*fn)(const char *, uint32, const char *)); +BOOL cli_session_setup_x(struct cli_state *cli, + char *user, + char *pass, int passlen, + char *ntpass, int ntpasslen, + char *user_domain); BOOL cli_session_setup(struct cli_state *cli, - char *user, - char *pass, int passlen, - char *ntpass, int ntpasslen, - char *workgroup); + char *user, + char *pass, int passlen, + char *ntpass, int ntpasslen, + char *user_domain); BOOL cli_ulogoff(struct cli_state *cli); BOOL cli_send_tconX(struct cli_state *cli, char *share, char *dev, char *pass, int passlen); @@ -754,8 +760,11 @@ void pwd_get_cleartext(struct pwd_info *pwd, char *clr); void pwd_set_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16]); void pwd_get_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16]); void pwd_make_lm_nt_16(struct pwd_info *pwd, char *clr); +void pwd_make_lm_nt_owf2(struct pwd_info *pwd, const uchar srv_key[8], + const char *user, const char *server, const char *domain); 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[24]); +void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], + uchar *nt_owf, size_t *nt_owf_len); /*The following definitions come from libsmb/smbdes.c */ @@ -772,11 +781,24 @@ void SamOEMhash( unsigned char *data, unsigned char *key, int val); /*The following definitions come from libsmb/smbencrypt.c */ void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24); +void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24); void E_md4hash(uchar *passwd, uchar *p16); -void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16]); +void lm_owf_gen(const char *pwd, uchar p16[16]); +void nt_owf_gen(const char *pwd, uchar nt_p16[16]); +void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar lm_p16[16]); void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]); +void SMBOWFencrypt_ntv2(const uchar kr[16], + const uchar *srv_chal, int srv_chal_len, + const uchar *cli_chal, int cli_chal_len, + char resp_buf[16]); +void SMBgenclientchals(char *lm_cli_chal, + char *nt_cli_chal, int *nt_cli_chal_len, + const char *srv, const char *domain); +void ntv2_owf_gen(const uchar owf[16], + const char *user_n, + const char *domain_n, + uchar kr_buf[16]); void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24]); -void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24); BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode); BOOL nt_decrypt_string2(STRING2 *out, const STRING2 *in, char nt_hash[16]); @@ -1259,6 +1281,7 @@ BOOL lp_null_passwords(void); BOOL lp_strip_dot(void); BOOL lp_encrypted_passwords(void); BOOL lp_update_encrypted(void); +BOOL lp_client_ntlmv2(void); BOOL lp_server_ntlmv2(void); BOOL lp_syslog_only(void); BOOL lp_timestamp_logs(void); @@ -2360,7 +2383,8 @@ void make_rpc_auth_ntlmssp_chal(RPC_AUTH_NTLMSSP_CHAL *chl, uint8 challenge[8]); void smb_io_rpc_auth_ntlmssp_chal(char *desc, RPC_AUTH_NTLMSSP_CHAL *chl, prs_struct *ps, int depth); void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, - uchar lm_resp[24], uchar nt_resp[24], + uchar lm_resp[24], + uchar *nt_resp, size_t nt_len, char *domain, char *user, char *wks, uint32 neg_flags); void smb_io_rpc_auth_ntlmssp_resp(char *desc, RPC_AUTH_NTLMSSP_RESP *rsp, prs_struct *ps, int depth); @@ -3429,11 +3453,13 @@ void invalidate_vuid(uint16 vuid); char *validated_username(uint16 vuid); uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest, uchar user_sess_key[16]); void add_session_user(char *user); -BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8); BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], - uchar lm_pass[24], uchar nt_pass[24]); -BOOL pass_check_smb(char *user, char *domain, - uchar *chal, uchar *lm_pwd, uchar *nt_pwd, + const char *user, const char *domain, + uchar *lm_pass, size_t lm_pwd_len, + uchar *nt_pass, size_t nt_pwd_len); +BOOL pass_check_smb(char *user, char *domain, uchar *chal, + uchar *lm_pwd, size_t lm_pwd_len, + uchar *nt_pwd, size_t nt_pwd_len, struct passwd *pwd, uchar user_sess_key[16]); BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd, uchar user_sess_key[16]); diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h index b8647fda0f..3a2956cb6d 100644 --- a/source3/include/rpc_dce.h +++ b/source3/include/rpc_dce.h @@ -259,8 +259,8 @@ typedef struct rpc_auth_ntlmssp_chal_info /* RPC_AUTH_NTLMSSP_RESP */ typedef struct rpc_auth_ntlmssp_resp_info { - STRHDR hdr_lm_resp; /* 24 byte response */ - STRHDR hdr_nt_resp; /* 24 byte response */ + STRHDR hdr_lm_resp; /* LM response (NULL or 24 bytes) */ + STRHDR hdr_nt_resp; /* NT response (NULL, 24 or variable-length) */ STRHDR hdr_domain; STRHDR hdr_usr; STRHDR hdr_wks; diff --git a/source3/lib/hmacmd5.c b/source3/lib/hmacmd5.c index 9821afdc1d..d3c0d42d97 100644 --- a/source3/lib/hmacmd5.c +++ b/source3/lib/hmacmd5.c @@ -67,7 +67,8 @@ void hmac_md5_init_rfc2104(uchar* key, int key_len, HMACMD5Context *ctx) /*********************************************************************** the microsoft version of hmac_md5 initialisation. ***********************************************************************/ -void hmac_md5_init_limK_to_64(uchar* key, int key_len, HMACMD5Context *ctx) +void hmac_md5_init_limK_to_64(const uchar* key, int key_len, + HMACMD5Context *ctx) { int i; @@ -97,7 +98,7 @@ void hmac_md5_init_limK_to_64(uchar* key, int key_len, HMACMD5Context *ctx) /*********************************************************************** update hmac_md5 "inner" buffer ***********************************************************************/ -void hmac_md5_update(uchar* text, int text_len, HMACMD5Context *ctx) +void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx) { MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */ } diff --git a/source3/lib/util.c b/source3/lib/util.c index 3211c6687a..9266e988d8 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -2972,7 +2972,7 @@ void out_data(FILE *f,char *buf1,int len, int per_line) } } -void print_asc(int level, unsigned char *buf,int len) +void print_asc(int level, unsigned char const *buf,int len) { int i; for (i=0;iprotocol < PROTOCOL_LANMAN1) { return True; } - if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) - { - return False; - } - - if (!IS_BITS_SET_ALL(cli->sec_mode, 1)) - { - /* if in share level security then don't send a password now */ - fstrcpy(pword, ""); - passlen=1; - fstrcpy(ntpword, ""); - ntpasslen=1; - } - else if ((passlen == 0 || passlen == 1) && (pass[0] == '\0')) - { - /* Null session connect. */ - pword [0] = '\0'; - ntpword[0] = '\0'; - } - else if (passlen == 24 && ntpasslen == 24) - { - if (IS_BITS_SET_ALL(cli->sec_mode, 2)) - { - /* encrypted password, implicit from 24-byte lengths */ - memcpy(pword , pass , 24); - memcpy(ntpword, ntpass, 24); - } - else - { - DEBUG(0,("cli_session_setup: encrypted passwords not supported by server\n")); - return False; - } - } - else if (ntpasslen == 0 || !IS_BITS_SET_ALL(cli->sec_mode, 2)) - { - /* plain-text password: server doesn't support encrypted. */ - fstrcpy(pword, pass); - fstrcpy(ntpword, ""); - ntpasslen = 0; - } - else /* passlen != 0 && ntpasslen != 0 && server supports encryption */ - { - /* plain-text password requesting to be encrypted */ - uchar *key = (uchar *)cli->cryptkey; - SMBencrypt ((uchar *)pass , key,(uchar *)pword ); - SMBNTencrypt((uchar *)ntpass, key,(uchar *)ntpword); - passlen = 24; - ntpasslen = 24; - } - /* send a session setup command */ bzero(cli->outbuf,smb_size); @@ -770,7 +726,7 @@ BOOL cli_session_setup(struct cli_state *cli, SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); SSVAL(cli->outbuf,smb_vwv7,passlen); p = smb_buf(cli->outbuf); - memcpy(p,pword,passlen); + memcpy(p,pass,passlen); p += passlen; pstrcpy(p,user); strupper(p); @@ -790,17 +746,17 @@ BOOL cli_session_setup(struct cli_state *cli, SSVAL(cli->outbuf,smb_vwv8,ntpasslen); SSVAL(cli->outbuf,smb_vwv11,0); p = smb_buf(cli->outbuf); - memcpy(p,pword,passlen); + memcpy(p,pass,passlen); p += SVAL(cli->outbuf,smb_vwv7); - memcpy(p,ntpword,ntpasslen); + memcpy(p,ntpass,ntpasslen); p += SVAL(cli->outbuf,smb_vwv8); pstrcpy(p,user); strupper(p); p = skip_string(p,1); - pstrcpy(p,workgroup); - strupper(p); + pstrcpy(p,user_domain); 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); set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False); } @@ -833,11 +789,127 @@ BOOL cli_session_setup(struct cli_state *cli, fstrcpy(cli->server_domain, server_domain); } - fstrcpy(cli->user_name, user); - return True; } +static BOOL cli_calc_session_pwds(struct cli_state *cli, + char *pword, char *ntpword, + char *pass, int *passlen, + char *ntpass, int *ntpasslen, + BOOL ntlmv2) +{ +#ifdef DEBUG_PASSWORD + DEBUG(100,("cli_calc_session_pwds. pass, ntpass\n")); + dump_data(100, pass, *passlen); + dump_data(100, ntpass, *ntpasslen); +#endif + if (!IS_BITS_SET_ALL(cli->sec_mode, 1)) + { + /* if in share level security then don't send a password now */ + fstrcpy(pword, ""); + *passlen=1; + fstrcpy(ntpword, ""); + *ntpasslen=1; + } + else if ((*passlen == 0 || *passlen == 1) && (pass[0] == '\0')) + { + /* Null session connect. */ + pword [0] = '\0'; + ntpword[0] = '\0'; + } + else if (*passlen == 24 && *ntpasslen >= 24) + { + if (IS_BITS_SET_ALL(cli->sec_mode, 2)) + { + /* encrypted password, implicit from 24-byte lengths */ + memcpy(pword , pass , *passlen); + memcpy(ntpword, ntpass, *ntpasslen); + } + else + { + DEBUG(0,("cli_session_setup: encrypted passwords not supported by server\n")); + return False; + } + } + else if (*ntpasslen == 0 || !IS_BITS_SET_ALL(cli->sec_mode, 2)) + { + /* plain-text password: server doesn't support encrypted. */ + fstrcpy(pword, pass); + fstrcpy(ntpword, ""); + *ntpasslen = 0; + } + else /* passlen != 0 && ntpasslen != 0 && server supports encryption */ + { + if (ntlmv2) + { + /* plain-text password requesting to be encrypted */ + uchar *srv_key = (uchar *)cli->cryptkey; + uchar nt_owf[16]; + uchar kr[16]; + + SMBgenclientchals(cli->lm_cli_chal, + cli->nt_cli_chal, + &cli->nt_cli_chal_len, + cli->calling.name, + cli->domain); + + nt_owf_gen(pword, nt_owf); + ntv2_owf_gen(nt_owf, cli->user_name, cli->domain, kr); + + /* lm # */ + memcpy(pword, cli->lm_cli_chal, 8); + SMBOWFencrypt_ntv2(kr, + srv_key, 8, + cli->lm_cli_chal, 8, + &pword[8]); + *passlen = 24; + + /* nt # */ + memcpy(ntpword, cli->lm_cli_chal, cli->nt_cli_chal_len); + SMBOWFencrypt_ntv2(kr, + srv_key, 8, + cli->nt_cli_chal, cli->nt_cli_chal_len, + &ntpword[cli->nt_cli_chal_len]); + *ntpasslen = cli->nt_cli_chal_len + 16; + } + else + { + /* plain-text password requesting to be encrypted */ + uchar *key = (uchar *)cli->cryptkey; + SMBencrypt ((uchar *)pass , key,(uchar *)pword ); + SMBNTencrypt((uchar *)ntpass, key,(uchar *)ntpword); + *passlen = 24; + *ntpasslen = 24; + } + } + return True; +} + +/**************************************************************************** +send a session setup +****************************************************************************/ +BOOL cli_session_setup(struct cli_state *cli, + char *user, + char *pass, int passlen, + char *ntpass, int ntpasslen, + char *user_domain) +{ + fstring pword, ntpword; + + if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) + { + return False; + } + + fstrcpy(cli->user_name, user); + + return cli_calc_session_pwds(cli, pword, ntpword, + pass, &passlen, + ntpass, &ntpasslen, cli->use_ntlmv2) && + cli_session_setup_x(cli, user, pass, passlen, ntpass, ntpasslen, + user_domain); +} + /**************************************************************************** Send a uloggoff. *****************************************************************************/ @@ -2614,9 +2686,12 @@ BOOL cli_reestablish_connection(struct cli_state *cli) if (cli_establish_connection(cli, dest_host, &cli->dest_ip, &calling, &called, - share, dev, False, do_tcon)) { - if (cli->fd != oldfd) { - if (dup2(cli->fd, oldfd) == oldfd) { + share, dev, False, do_tcon)) + { + if (cli->fd != oldfd) + { + if (dup2(cli->fd, oldfd) == oldfd) + { close(cli->fd); } } @@ -2640,9 +2715,10 @@ BOOL cli_establish_connection(struct cli_state *cli, nmb_safe_namestr(calling, callingstr, sizeof(callingstr)); nmb_safe_namestr(called , calledstr , sizeof(calledstr )); - DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n", + DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s] with NTLM%s\n", callingstr, calledstr, inet_ntoa(*dest_ip), - cli->user_name, cli->domain)); + cli->user_name, cli->domain, + cli->use_ntlmv2 ? "v2" : "v1")); /* establish connection */ @@ -2665,7 +2741,9 @@ BOOL cli_establish_connection(struct cli_state *cli, { DEBUG(1,("failed session request\n")); if (do_shutdown) - cli_shutdown(cli); + { + cli_shutdown(cli); + } return False; } @@ -2673,7 +2751,9 @@ BOOL cli_establish_connection(struct cli_state *cli, { DEBUG(1,("failed negprot\n")); if (do_shutdown) - cli_shutdown(cli); + { + cli_shutdown(cli); + } return False; } @@ -2725,20 +2805,45 @@ BOOL cli_establish_connection(struct cli_state *cli, else { /* attempt encrypted session */ - unsigned char nt_sess_pwd[24]; unsigned char lm_sess_pwd[24]; + unsigned char nt_sess_pwd[128]; + size_t nt_sess_pwd_len; + extern pstring global_myname; + + if (cli->use_ntlmv2 != False) + { + DEBUG(10,("cli_establish_connection: NTLMv2\n")); + pwd_make_lm_nt_owf2(&(cli->pwd), cli->cryptkey, + cli->user_name, global_myname, cli->domain); + } + else + { + DEBUG(10,("cli_establish_connection: NTLMv1\n")); + pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey); + } - /* creates (storing a copy of) and then obtains a 24 byte password OWF */ - pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey); - pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd); + pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd, + &nt_sess_pwd_len); /* attempt encrypted session */ - if (!cli_session_setup(cli, cli->user_name, + if (!cli_session_setup_x(cli, cli->user_name, (char*)lm_sess_pwd, sizeof(lm_sess_pwd), - (char*)nt_sess_pwd, sizeof(nt_sess_pwd), + (char*)nt_sess_pwd, nt_sess_pwd_len, cli->domain)) { DEBUG(1,("failed session setup\n")); + + if (cli->use_ntlmv2 == Auto) + { + DEBUG(10,("NTLMv2 failed. Using NTLMv1\n")); + cli->use_ntlmv2 = False; + return cli_establish_connection(cli, + dest_host, dest_ip, + calling, called, + service, service_type, + do_shutdown, do_tcon); + } + if (do_shutdown) { cli_shutdown(cli); diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c index bbd5f63d4b..655df5be8a 100644 --- a/source3/libsmb/pwd_cache.c +++ b/source3/libsmb/pwd_cache.c @@ -197,27 +197,83 @@ void pwd_make_lm_nt_16(struct pwd_info *pwd, char *clr) /**************************************************************************** makes lm and nt OWF crypts ****************************************************************************/ -void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]) +void pwd_make_lm_nt_owf2(struct pwd_info *pwd, const uchar srv_key[8], + const char *user, const char *server, const char *domain) { + uchar kr[16]; + + DEBUG(10,("pwd_make_lm_nt_owf2: user %s, srv %s, dom %s\n", + user, server, domain)); + pwd_deobfuscate(pwd); + SMBgenclientchals(pwd->lm_cli_chal, + pwd->nt_cli_chal, + &pwd->nt_cli_chal_len, + server, domain); + + ntv2_owf_gen(pwd->smb_nt_pwd, user, domain, kr); + + /* lm # */ + SMBOWFencrypt_ntv2(kr, + srv_key, 8, + pwd->lm_cli_chal, 8, + pwd->smb_lm_owf); + memcpy(&pwd->smb_lm_owf[16], pwd->lm_cli_chal, 8); + + /* nt # */ + SMBOWFencrypt_ntv2(kr, + srv_key, 8, + pwd->nt_cli_chal, pwd->nt_cli_chal_len, + pwd->smb_nt_owf); + memcpy(&pwd->smb_nt_owf[16], pwd->nt_cli_chal, pwd->nt_cli_chal_len); + pwd->nt_owf_len = pwd->nt_cli_chal_len + 16; + #ifdef DEBUG_PASSWORD - DEBUG(100,("client cryptkey: ")); - dump_data(100, cryptkey, 8); -#endif + DEBUG(100,("server cryptkey: ")); + dump_data(100, srv_key, 8); - SMBOWFencrypt(pwd->smb_nt_pwd, cryptkey, pwd->smb_nt_owf); + DEBUG(100,("client lmv2 cryptkey: ")); + dump_data(100, pwd->lm_cli_chal, 8); -#ifdef DEBUG_PASSWORD - DEBUG(100,("nt_owf_passwd: ")); - dump_data(100, pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf)); + DEBUG(100,("client ntv2 cryptkey: ")); + dump_data(100, pwd->nt_cli_chal, pwd->nt_cli_chal_len); + + DEBUG(100,("ntv2_owf_passwd: ")); + dump_data(100, pwd->smb_nt_owf, pwd->nt_owf_len); DEBUG(100,("nt_sess_pwd: ")); dump_data(100, pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd)); + + DEBUG(100,("lmv2_owf_passwd: ")); + dump_data(100, pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf)); + DEBUG(100,("lm_sess_pwd: ")); + dump_data(100, pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd)); #endif + pwd->crypted = True; + + pwd_obfuscate(pwd); +} + +/**************************************************************************** + makes lm and nt OWF crypts + ****************************************************************************/ +void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]) +{ + pwd_deobfuscate(pwd); SMBOWFencrypt(pwd->smb_lm_pwd, cryptkey, pwd->smb_lm_owf); + SMBOWFencrypt(pwd->smb_nt_pwd, cryptkey, pwd->smb_nt_owf); + pwd->nt_owf_len = 24; #ifdef DEBUG_PASSWORD + DEBUG(100,("client cryptkey: ")); + dump_data(100, cryptkey, 8); + + DEBUG(100,("nt_owf_passwd: ")); + dump_data(100, pwd->smb_nt_owf, pwd->nt_owf_len); + DEBUG(100,("nt_sess_pwd: ")); + dump_data(100, pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd)); + DEBUG(100,("lm_owf_passwd: ")); dump_data(100, pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf)); DEBUG(100,("lm_sess_pwd: ")); @@ -232,7 +288,8 @@ void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]) /**************************************************************************** gets lm and nt crypts ****************************************************************************/ -void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24]) +void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], + uchar *nt_owf, size_t *nt_owf_len) { pwd_deobfuscate(pwd); if (lm_owf != NULL) @@ -241,7 +298,12 @@ void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24]) } if (nt_owf != NULL) { - memcpy(nt_owf, pwd->smb_nt_owf, 24); + memcpy(nt_owf, pwd->smb_nt_owf, pwd->nt_owf_len); + } + if (nt_owf_len != NULL) + { + *nt_owf_len = pwd->nt_owf_len; } pwd_obfuscate(pwd); } + diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index f0bfbd9b84..852e5327cf 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -32,19 +32,30 @@ extern int DEBUGLEVEL; encrypted password into p24 */ void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24) { - uchar p14[15], p21[21]; + uchar p21[21]; - memset(p21,'\0',21); - memset(p14,'\0',14); - StrnCpy((char *)p14,(char *)passwd,14); + lm_owf_gen(passwd, p21); + SMBOWFencrypt(p21, c8, p24); - strupper((char *)p14); - E_P16(p14, p21); +#ifdef DEBUG_PASSWORD + DEBUG(100,("SMBencrypt: lm#, challenge, response\n")); + dump_data(100, p21, 16); + dump_data(100, c8, 8); + dump_data(100, p24, 24); +#endif +} +void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) +{ + uchar p21[21]; + + memset(p21,'\0',21); + + nt_owf_gen(passwd, p21); SMBOWFencrypt(p21, c8, p24); #ifdef DEBUG_PASSWORD - DEBUG(100,("SMBencrypt: lm#, challenge, response\n")); + DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n")); dump_data(100, p21, 16); dump_data(100, c8, 8); dump_data(100, p24, 24); @@ -67,7 +78,23 @@ static int _my_wcslen(int16 *str) * format. */ -static int _my_mbstowcs(int16 *dst, uchar *src, int len) +static int _my_mbstowcsupper(int16 *dst, const uchar *src, int len) +{ + int i; + int16 val; + + for(i = 0; i < len; i++) { + val = toupper(*src); + SSVAL(dst,0,val); + dst++; + src++; + if(val == 0) + break; + } + return i; +} + +static int _my_mbstowcs(int16 *dst, const uchar *src, int len) { int i; int16 val; @@ -105,27 +132,17 @@ void E_md4hash(uchar *passwd, uchar *p16) mdfour(p16, (unsigned char *)wpwd, len); } -/* Does both the NT and LM owfs of a user's password */ -void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16]) +/* Does the LM owf of a user's password */ +void lm_owf_gen(const char *pwd, uchar p16[16]) { - char passwd[130]; + char passwd[15]; - memset(passwd,'\0',130); + memset(passwd,'\0',15); if (pwd != NULL) { safe_strcpy( passwd, pwd, sizeof(passwd)-1); } - /* Calculate the MD4 hash (NT compatible) of the password */ - memset(nt_p16, '\0', 16); - E_md4hash((uchar *)passwd, nt_p16); - -#ifdef DEBUG_PASSWORD - DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n")); - dump_data(120, passwd, strlen(passwd)); - dump_data(100, nt_p16, 16); -#endif - /* Mangle the passwords into Lanman format */ passwd[14] = '\0'; strupper(passwd); @@ -144,6 +161,37 @@ void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16]) bzero(passwd, sizeof(passwd)); } +/* Does both the NT and LM owfs of a user's password */ +void nt_owf_gen(const char *pwd, uchar nt_p16[16]) +{ + char passwd[130]; + + memset(passwd,'\0',130); + if (pwd != NULL) + { + safe_strcpy( passwd, pwd, sizeof(passwd)-1); + } + + /* Calculate the MD4 hash (NT compatible) of the password */ + memset(nt_p16, '\0', 16); + E_md4hash((uchar *)passwd, nt_p16); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n")); + dump_data(120, passwd, strlen(passwd)); + dump_data(100, nt_p16, 16); +#endif + /* clear out local copy of user's password (just being paranoid). */ + bzero(passwd, sizeof(passwd)); +} + +/* Does both the NT and LM owfs of a user's password */ +void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar lm_p16[16]) +{ + nt_owf_gen(pwd, nt_p16); + lm_owf_gen(pwd, lm_p16); +} + /* Does the des encryption from the NT or LM MD4 hash. */ void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]) { @@ -155,6 +203,165 @@ void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]) E_P24(p21, c8, p24); } +void SMBOWFencrypt_ntv2(const uchar kr[16], + const uchar *srv_chal, int srv_chal_len, + const uchar *cli_chal, int cli_chal_len, + char resp_buf[16]) +{ + HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(srv_chal, srv_chal_len, &ctx); + hmac_md5_update(cli_chal, cli_chal_len, &ctx); + hmac_md5_final(resp_buf, &ctx); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); + dump_data(100, srv_chal, srv_chal_len); + dump_data(100, cli_chal, cli_chal_len); + dump_data(100, resp_buf, 16); +#endif +} + +#if 0 +static char np_cli_chal[58] = +{ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x20, 0xd0, 0xb6, 0xc2, 0x92, 0xBE, 0x01, + 0x05, 0x83, 0x32, 0xec, 0xfa, 0xe4, 0xf3, 0x6d, + 0x6f, 0x00, 0x6e, 0x00, 0x02, 0x00, 0x12, 0x00, + 0x52, 0x00, 0x4f, 0x00, 0x43, 0x00, 0x4b, 0x00, + 0x4e, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x4c, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, + 0x00, 0x00 +}; +#endif + +void SMBgenclientchals(char *lm_cli_chal, + char *nt_cli_chal, int *nt_cli_chal_len, + const char *srv, const char *domain) +{ + NTTIME nt_time; + int srv_len = strlen(srv); + int dom_len = strlen(domain); + + generate_random_buffer(lm_cli_chal, 8, False); + unix_to_nt_time(&nt_time, time(NULL)); + + CVAL(nt_cli_chal,0) = 0x1; + CVAL(nt_cli_chal,1) = 0x1; + SSVAL(nt_cli_chal, 2, 0x0); + SIVAL(nt_cli_chal, 4, 0x0); + SIVAL(nt_cli_chal, 8, nt_time.low); + SIVAL(nt_cli_chal, 12, nt_time.high); + memcpy(nt_cli_chal+16, lm_cli_chal, 8); + /* fill in offset 24, size of structure, later */ + + *nt_cli_chal_len = 28; + + SSVAL(nt_cli_chal, *nt_cli_chal_len, 2); + *nt_cli_chal_len += 2; + SSVAL(nt_cli_chal, *nt_cli_chal_len, dom_len*2); + *nt_cli_chal_len += 2; + ascii_to_unibuf(nt_cli_chal+(*nt_cli_chal_len), domain, dom_len*2); + *nt_cli_chal_len += dom_len*2; + *nt_cli_chal_len += 4 - ((*nt_cli_chal_len) % 4); + + SSVAL(nt_cli_chal, *nt_cli_chal_len, 2); + *nt_cli_chal_len += 2; + SSVAL(nt_cli_chal, 30, srv_len*2); + *nt_cli_chal_len += 2; + ascii_to_unibuf(nt_cli_chal+(*nt_cli_chal_len), srv, srv_len*2); + *nt_cli_chal_len += srv_len*2; + + SSVAL(nt_cli_chal, 24, (*nt_cli_chal_len)+16); + SSVAL(nt_cli_chal, 26, (*nt_cli_chal_len)+15); + + DEBUG(100,("SMBgenclientchals: srv %s, dom %s\n", srv, domain)); + dump_data(100, nt_cli_chal, *nt_cli_chal_len); +} + +void ntv2_owf_gen(const uchar owf[16], + const char *user_n, + const char *domain_n, + uchar kr_buf[16]) +{ + pstring user_u; + pstring dom_u; + HMACMD5Context ctx; + + int user_l = strlen(user_n ); + int domain_l = strlen(domain_n); + + _my_mbstowcsupper((int16*)user_u, user_n , user_l*2 ); + _my_mbstowcs((int16*)dom_u , domain_n, domain_l*2); + + hmac_md5_init_limK_to_64(owf, 16, &ctx); + hmac_md5_update(user_u, user_l*2, &ctx); + hmac_md5_update(dom_u, domain_l*2, &ctx); + hmac_md5_final(kr_buf, &ctx); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("ntv2_owf_gen: user, domain, owfkey, kr\n")); + dump_data(100, user_u, user_l*2); + dump_data(100, dom_u, domain_l*2); + dump_data(100, owf, 16); + dump_data(100, kr_buf, 16); +#endif +} + +#if 0 +static void main() +{ + char *kr; + int kr_len; + char *cli_chal; + int cli_chal_len; + char *resp; + int resp_len; + char *k_x; + int k_x_len; + + char k_u[16]; + int k_u_len = sizeof(k_u); + + char sesk[16]; + int sesk_len; + + char buf[1024]; + + int flgs = NTLMSSP_NP | NTLMSSP_N2; + + gen_client_chal(flgs, "BROOKFIELDS1", "TEST1", &cli_chal, &cli_chal_len); + gen_owf(flgs, "test", "ADMINISTRATOR", "BROOKFIELDS1", &kr, &kr_len); + gen_resp(flgs, kr, kr_len, srv_chal, 8, cli_chal, cli_chal_len, + &resp, &resp_len); + + gen_sesskey(flgs, kr, kr_len, resp, resp_len, &k_x, &k_x_len); + + printf("lm_resp:\n"); dump_data(lm_resp, 16); printf("\n"); + printf("np_resp:\n"); dump_data(np_resp, 16); printf("\n"); + printf("resp:\n"); dump_data(resp, 16); printf("\n"); + +#if 0 + printf("np_sesk:\n"); dump_data(np_sess_key, 16); printf("\n"); + if (flgs & NTLMSSP_NP) + { + oem_hash(k_x, k_x_len, k_u, np_sess_key, k_u_len); + sesk_len = k_u_len; + } + else + { + memcpy(sesk, k_x, k_x_len); + sesk_len = k_x_len; + } + + oem_hash(sesk, sesk_len, buf, cli_req, sizeof(cli_req)); + printf("cli_req:\n"); dump_data(buf, sizeof(cli_req)); printf("\n"); +#endif +} +#endif + /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24]) { @@ -173,26 +380,6 @@ void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24]) #endif } - -/* Does the NT MD4 hash then des encryption. */ - -void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) -{ - uchar p21[21]; - - memset(p21,'\0',21); - - E_md4hash(passwd, p21); - SMBOWFencrypt(p21, c8, p24); - -#ifdef DEBUG_PASSWORD - DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n")); - dump_data(100, p21, 16); - dump_data(100, c8, 8); - dump_data(100, p24, 24); -#endif -} - BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode) { int new_pw_len = strlen(passwd) * (unicode ? 2 : 1); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 34c405dd50..7811d58afb 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -212,6 +212,7 @@ typedef struct BOOL bEncryptPasswords; BOOL bUpdateEncrypt; BOOL bServerNTLMv2; + BOOL bClientNTLMv2; BOOL bStripDot; BOOL bNullPasswords; BOOL bLoadPrinters; @@ -530,7 +531,8 @@ static struct parm_struct parm_table[] = {"security", P_ENUM, P_GLOBAL, &Globals.security, NULL, enum_security, FLAG_BASIC}, {"encrypt passwords",P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC}, {"update encrypted", P_BOOL, P_GLOBAL, &Globals.bUpdateEncrypt, NULL, NULL, FLAG_BASIC}, - {"server ntlmv2", P_BOOL, P_GLOBAL, &Globals.bServerNTLMv2, NULL, enum_bool_auto, FLAG_BASIC}, + {"server ntlmv2", P_ENUM, P_GLOBAL, &Globals.bServerNTLMv2, NULL, enum_bool_auto, FLAG_BASIC}, + {"client ntlmv2", P_ENUM, P_GLOBAL, &Globals.bClientNTLMv2, NULL, enum_bool_auto, FLAG_BASIC}, {"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL, NULL, 0}, {"map to guest", P_ENUM, P_GLOBAL, &Globals.map_to_guest, NULL, enum_map_to_guest, 0}, {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL, 0}, @@ -974,6 +976,7 @@ static void init_globals(void) /* NTLMv2 */ + Globals.bClientNTLMv2 = False; Globals.bServerNTLMv2 = False; /* these parameters are set to defaults that are more appropriate @@ -1250,7 +1253,8 @@ FN_GLOBAL_BOOL(lp_null_passwords,&Globals.bNullPasswords) FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot) FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords) FN_GLOBAL_BOOL(lp_update_encrypted,&Globals.bUpdateEncrypt) -FN_GLOBAL_BOOL(lp_server_ntlmv2,&Globals.bUpdateEncrypt) +FN_GLOBAL_BOOL(lp_client_ntlmv2,&Globals.bClientNTLMv2) +FN_GLOBAL_BOOL(lp_server_ntlmv2,&Globals.bServerNTLMv2) FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly) FN_GLOBAL_BOOL(lp_timestamp_logs,&Globals.bTimestampLogs) FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList) diff --git a/source3/passdb/sampassdb.c b/source3/passdb/sampassdb.c index d5b395a0a1..497ea344d1 100644 --- a/source3/passdb/sampassdb.c +++ b/source3/passdb/sampassdb.c @@ -531,7 +531,6 @@ void copy_sam_passwd(struct sam_passwd *to, const struct sam_passwd *from) /************************************************************* converts a sam_passwd structure to a smb_passwd structure. **************************************************************/ - struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user) { static struct smb_passwd pw_buf; diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 482dbe71ce..3ced236281 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -502,7 +502,8 @@ static BOOL create_rpc_bind_resp(struct pwd_info *pwd, prs_struct *auth_resp) { unsigned char lm_owf[24]; - unsigned char nt_owf[24]; + unsigned char nt_owf[128]; + size_t nt_owf_len; RPC_HDR hdr; RPC_HDR_AUTHA hdr_autha; RPC_AUTH_VERIFIER auth_verifier; @@ -518,10 +519,10 @@ static BOOL create_rpc_bind_resp(struct pwd_info *pwd, smb_io_rpc_auth_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); + pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf, &nt_owf_len); make_rpc_auth_ntlmssp_resp(&ntlmssp_resp, - lm_owf, nt_owf, + lm_owf, nt_owf, nt_owf_len, domain, user_name, my_name, ntlmssp_cli_flgs); @@ -947,7 +948,7 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, uint16 nt_pipe_fnum, rpc_call_id, &hdra, &hdr_autha, &auth_resp); - pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL); + pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL, NULL); pwd_get_lm_nt_16(&cli->pwd, lm_hash, NULL); NTLMSSPOWFencrypt(lm_hash, lm_owf, p24); { diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c index 524c4201ad..3066d94dec 100644 --- a/source3/rpc_parse/parse_rpc.c +++ b/source3/rpc_parse/parse_rpc.c @@ -692,7 +692,8 @@ creates an RPC_AUTH_NTLMSSP_RESP structure. ********************************************************************/ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, - uchar lm_resp[24], uchar nt_resp[24], + uchar lm_resp[24], + uchar *nt_resp, size_t nt_len, char *domain, char *user, char *wks, uint32 neg_flags) { @@ -701,7 +702,6 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, int wks_len = strlen(wks ); int usr_len = strlen(user ); int lm_len = lm_resp != NULL ? 24 : 0; - int nt_len = nt_resp != NULL ? 24 : 0; DEBUG(5,("make_rpc_auth_ntlmssp_resp\n")); @@ -709,9 +709,9 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, #ifdef DEBUG_PASSWORD DEBUG(100,("lm_resp\n")); - dump_data(100, lm_resp, 24); + dump_data(100, lm_resp, lm_len); DEBUG(100,("nt_resp\n")); - dump_data(100, nt_resp, 24); + dump_data(100, nt_resp, nt_len); #endif DEBUG(6,("dom: %s user: %s wks: %s neg_flgs: 0x%x\n", @@ -745,8 +745,8 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, rsp->neg_flags = neg_flags; - memcpy(rsp->lm_resp, lm_resp, 24); - memcpy(rsp->nt_resp, nt_resp, 24); + memcpy(rsp->lm_resp, lm_resp, lm_len); + memcpy(rsp->nt_resp, nt_resp, nt_len); if (IS_BITS_SET_ALL(neg_flags, NTLMSSP_NEGOTIATE_UNICODE)) { diff --git a/source3/rpc_server/srv_netlog.c b/source3/rpc_server/srv_netlog.c index 7ee45ada16..9c260d5759 100644 --- a/source3/rpc_server/srv_netlog.c +++ b/source3/rpc_server/srv_netlog.c @@ -630,43 +630,26 @@ static uint32 net_login_network(NET_ID_INFO_2 *id2, struct sam_passwd *smb_pass, user_struct *vuser) { - DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n", - id2->hdr_lm_chal_resp.str_str_len, - id2->hdr_nt_chal_resp.str_str_len)); + fstring user; + fstring domain; - /* JRA. Check the NT password first if it exists - this is a higher quality - password, if it exists and it doesn't match - fail. */ + int nt_pw_len = id2->hdr_nt_chal_resp.str_str_len >= 24; + int lm_pw_len = id2->hdr_lm_chal_resp.str_str_len >= 24; - if (id2->hdr_nt_chal_resp.str_str_len == 24 && - smb_pass->smb_nt_passwd != NULL) - { - if(smb_password_check((char *)id2->nt_chal_resp.buffer, - smb_pass->smb_nt_passwd, - id2->lm_chal)) - return 0x0; - else - return 0xC0000000 | NT_STATUS_WRONG_PASSWORD; - } + unistr2_to_ascii(user , &id2->uni_user_name, sizeof(user)-1); + unistr2_to_ascii(domain, &id2->uni_domain_name, sizeof(domain)-1); + + DEBUG(5,("net_login_network: lm_len:%d nt_len:%d user:%s domain:%s\n", + lm_pw_len, nt_pw_len, user, domain)); - /* lkclXXXX this is not a good place to put disabling of LM hashes in. - if that is to be done, first move this entire function into a - library routine that calls the two smb_password_check() functions. - if disabling LM hashes (which nt can do for security reasons) then - an attempt should be made to disable them everywhere (which nt does - not do, for various security-hole reasons). - */ - - if (id2->hdr_lm_chal_resp.str_str_len == 24 && - smb_password_check((char *)id2->lm_chal_resp.buffer, - smb_pass->smb_passwd, - id2->lm_chal)) + if (smb_password_ok(pwdb_sam_to_smb(smb_pass), id2->lm_chal, + user, domain, + (uchar *)id2->lm_chal_resp.buffer, lm_pw_len, + (uchar *)id2->nt_chal_resp.buffer, nt_pw_len)) { - return 0x0; + return 0x0; } - - /* oops! neither password check succeeded */ - return 0xC0000000 | NT_STATUS_WRONG_PASSWORD; } diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index d98fecbc1f..3e5d986935 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -208,7 +208,9 @@ BOOL create_rpc_reply(pipes_struct *p, static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) { uchar lm_owf[24]; - uchar nt_owf[24]; + uchar nt_owf[128]; + size_t lm_owf_len; + size_t nt_owf_len; struct smb_passwd *smb_pass = NULL; user_struct *vuser = get_valid_user_struct(p->vuid); @@ -221,12 +223,29 @@ static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) return False; } - if (p->ntlmssp_resp.hdr_lm_resp.str_str_len == 0) return False; - if (p->ntlmssp_resp.hdr_nt_resp.str_str_len == 0) return False; + lm_owf_len = p->ntlmssp_resp.hdr_lm_resp.str_str_len; + nt_owf_len = p->ntlmssp_resp.hdr_nt_resp.str_str_len; + + + if (lm_owf_len == 0) return False; + if (nt_owf_len == 0) return False; if (p->ntlmssp_resp.hdr_usr .str_str_len == 0) return False; if (p->ntlmssp_resp.hdr_domain .str_str_len == 0) return False; if (p->ntlmssp_resp.hdr_wks .str_str_len == 0) return False; + if (lm_owf_len > sizeof(lm_owf)) return False; + if (nt_owf_len > sizeof(nt_owf)) return False; + + memcpy(lm_owf, p->ntlmssp_resp.lm_resp, sizeof(lm_owf)); + memcpy(nt_owf, p->ntlmssp_resp.nt_resp, sizeof(nt_owf)); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("lm, nt owfs, chal\n")); + dump_data(100, lm_owf, sizeof(lm_owf)); + dump_data(100, nt_owf, sizeof(nt_owf)); + dump_data(100, p->ntlmssp_chal.challenge, 8); +#endif + memset(p->user_name, 0, sizeof(p->user_name)); memset(p->domain , 0, sizeof(p->domain )); memset(p->wks , 0, sizeof(p->wks )); @@ -252,19 +271,12 @@ static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) DEBUG(5,("user: %s domain: %s wks: %s\n", p->user_name, p->domain, p->wks)); - memcpy(lm_owf, p->ntlmssp_resp.lm_resp, sizeof(lm_owf)); - memcpy(nt_owf, p->ntlmssp_resp.nt_resp, sizeof(nt_owf)); - -#ifdef DEBUG_PASSWORD - DEBUG(100,("lm, nt owfs, chal\n")); - dump_data(100, lm_owf, sizeof(lm_owf)); - dump_data(100, nt_owf, sizeof(nt_owf)); - dump_data(100, p->ntlmssp_chal.challenge, 8); -#endif become_root(True); p->ntlmssp_validated = pass_check_smb(p->user_name, p->domain, (uchar*)p->ntlmssp_chal.challenge, - lm_owf, nt_owf, NULL, vuser->dc.user_sess_key); + lm_owf, lm_owf_len, + nt_owf, nt_owf_len, + NULL, vuser->dc.user_sess_key); smb_pass = getsmbpwnam(p->user_name); unbecome_root(True); diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c index 259c10d11f..25308697a6 100644 --- a/source3/rpcclient/rpcclient.c +++ b/source3/rpcclient/rpcclient.c @@ -72,6 +72,8 @@ static BOOL rpcclient_connect(struct client_info *info) make_nmb_name(&called , dns_to_netbios_name(info->dest_host ), info->name_type, scope); make_nmb_name(&calling, dns_to_netbios_name(info->myhostname), 0x0 , scope); + smb_cli->use_ntlmv2 = lp_client_ntlmv2(); + if (!cli_establish_connection(smb_cli, info->dest_host, &info->dest_ip, &calling, &called, diff --git a/source3/smbd/password.c b/source3/smbd/password.c index c05b82ef15..14a63c6ef4 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -292,51 +292,78 @@ static BOOL update_smbpassword_file(char *user, char *password) /**************************************************************************** core of smb password checking routine. ****************************************************************************/ -BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8) +static BOOL smb_pwd_check_ntlmv1(char *password, unsigned char *part_passwd, + unsigned char *c8) { /* Finish the encryption of part_passwd. */ - unsigned char p21[21]; unsigned char p24[24]; if (part_passwd == NULL) DEBUG(10,("No password set - allowing access\n")); /* No password set - always true ! */ if (part_passwd == NULL) - return 1; + return True; - memset(p21,'\0',21); - memcpy(p21,part_passwd,16); - E_P24(p21, c8, p24); + SMBOWFencrypt(part_passwd, c8, p24); #if DEBUG_PASSWORD - { - int i; - DEBUG(100,("Part password (P16) was |")); - for(i = 0; i < 16; i++) - DEBUG(100,("%X ", (unsigned char)part_passwd[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Password from client was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)password[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Given challenge was |")); - for(i = 0; i < 8; i++) - DEBUG(100,("%X ", (unsigned char)c8[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Value from encryption was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)p24[i])); - DEBUG(100,("|\n")); - } + DEBUG(100,("Part password (P16) was |")); + dump_data(100, part_passwd, 16); + DEBUG(100,("Password from client was |")); + dump_data(100, password, 24); + DEBUG(100,("Given challenge was |")); + dump_data(100, c8, 8); + DEBUG(100,("Value from encryption was |")); + dump_data(100, p24, 24); #endif return (memcmp(p24, password, 24) == 0); } +/**************************************************************************** +core of smb password checking routine. +****************************************************************************/ +static BOOL smb_pwd_check_ntlmv2(char *password, size_t pwd_len, + unsigned char *part_passwd, + unsigned char const *c8, + const char *user, const char *domain) +{ + /* Finish the encryption of part_passwd. */ + unsigned char kr[16]; + + if (part_passwd == NULL) + { + DEBUG(10,("No password set - allowing access\n")); + } + /* No password set - always true ! */ + if (part_passwd == NULL) + { + return True; + } + + ntv2_owf_gen(part_passwd, user, domain, kr); + SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, kr); + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |")); + dump_data(100, part_passwd, 16); + DEBUG(100,("Password from client was |")); + dump_data(100, password, pwd_len); + DEBUG(100,("Given challenge was |")); + dump_data(100, c8, 8); + DEBUG(100,("Value from encryption was |")); + dump_data(100, kr, 16); +#endif + + return (memcmp(kr, password, 16) == 0); +} + /**************************************************************************** Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], - uchar lm_pass[24], uchar nt_pass[24]) + const char *user, const char *domain, + uchar *lm_pass, size_t lm_pwd_len, + uchar *nt_pass, size_t nt_pwd_len) { uchar challenge[8]; @@ -345,7 +372,8 @@ BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], DEBUG(4,("Checking SMB password for user %s\n", smb_pass->unix_name)); - if(smb_pass->acct_ctrl & ACB_DISABLED) { + if (smb_pass->acct_ctrl & ACB_DISABLED) + { DEBUG(3,("account for user %s was disabled.\n", smb_pass->unix_name)); return(False); @@ -366,35 +394,59 @@ BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], memcpy(challenge, chal, 8); } - if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) { + if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) + { /* We have the NT MD4 hash challenge available - see if we can use it (ie. does it exist in the smbpasswd file). */ - DEBUG(4,("smb_password_ok: Checking NT MD4 password\n")); - if (smb_password_check((char *)nt_pass, + if (lp_server_ntlmv2()) + { + DEBUG(4,("smb_password_ok: Check NTLMv2 password\n")); + if (smb_pwd_check_ntlmv2(nt_pass, nt_pwd_len, + (uchar *)smb_pass->smb_nt_passwd, + challenge, user, domain)) + { + return True; + } + } + if (lp_server_ntlmv2() != True && nt_pwd_len == 24) + { + DEBUG(4,("smb_password_ok: Check NT MD4 password\n")); + if (smb_pwd_check_ntlmv1((char *)nt_pass, (uchar *)smb_pass->smb_nt_passwd, - challenge)) { - DEBUG(4,("NT MD4 password check succeeded\n")); - return(True); + challenge)) + { + DEBUG(4,("NT MD4 password check succeeded\n")); + return True; + } } DEBUG(4,("NT MD4 password check failed\n")); } + if (lp_server_ntlmv2() == False) + { + DEBUG(4,("Not checking LM MD4 password\n")); + return False; + } + /* Try against the lanman password. smb_pass->smb_passwd == NULL means no password, allow access. */ DEBUG(4,("Checking LM MD4 password\n")); - if((smb_pass->smb_passwd == NULL) && - (smb_pass->acct_ctrl & ACB_PWNOTREQ)) { + if ((smb_pass->smb_passwd == NULL) && + (smb_pass->acct_ctrl & ACB_PWNOTREQ)) + { DEBUG(4,("no password required for user %s\n", smb_pass->unix_name)); return True; } - if((smb_pass->smb_passwd != NULL) && - smb_password_check((char *)lm_pass, - (uchar *)smb_pass->smb_passwd, challenge)) { + if ((smb_pass->smb_passwd != NULL) && + smb_pwd_check_ntlmv1((char *)lm_pass, + (uchar *)smb_pass->smb_passwd, + challenge)) + { DEBUG(4,("LM MD4 password check succeeded\n")); return(True); } @@ -411,8 +463,9 @@ SMB hash return True if the password is correct, False otherwise ****************************************************************************/ -BOOL pass_check_smb(char *user, char *domain, - uchar *chal, uchar *lm_pwd, uchar *nt_pwd, +BOOL pass_check_smb(char *user, char *domain, uchar *chal, + uchar *lm_pwd, size_t lm_pwd_len, + uchar *nt_pwd, size_t nt_pwd_len, struct passwd *pwd, uchar user_sess_key[16]) { const struct passwd *pass; @@ -466,7 +519,9 @@ BOOL pass_check_smb(char *user, char *domain, return(True); } - if (smb_password_ok(smb_pass, chal, lm_pwd, nt_pwd)) + if (smb_password_ok(smb_pass, chal, user, domain, + lm_pwd, lm_pwd_len, + nt_pwd, nt_pwd_len)) { if (user_sess_key != NULL) { @@ -479,7 +534,7 @@ BOOL pass_check_smb(char *user, char *domain, return(True); } - DEBUG(3,("Error smb_password_check failed\n")); + DEBUG(3,("Error pass_check_smb failed\n")); return False; } @@ -491,9 +546,9 @@ return True if the password is correct, False otherwise BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd, uchar user_sess_key[16]) { - if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords())) + if (pwlen >= 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords())) { - /* if 24 bytes long assume it is an encrypted password */ + /* if 24 bytes or longer assume it is an encrypted password */ uchar challenge[8]; if (!last_challenge(challenge)) @@ -503,7 +558,9 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd, } return pass_check_smb(user, global_myworkgroup, - challenge, (uchar *)password, (uchar *)password, pwd, user_sess_key); + challenge, (uchar *)password, + pwlen, (uchar *)password, pwlen, + pwd, user_sess_key); } return pass_check(user, password, pwlen, pwd, diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 58f327771d..c44cf069a9 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -441,7 +441,9 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE)); } - if (!smb_password_ok(smb_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) + if (!smb_password_ok(smb_trust_acct, NULL, NULL, NULL, + (unsigned char *)smb_passwd, smb_passlen, + (unsigned char *)smb_nt_passwd, smb_nt_passlen)) { DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user)); SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES); @@ -570,7 +572,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int set_remote_arch( RA_WIN95); } - if (passlen1 != 24 && passlen2 != 24) + if (passlen1 != 24 && passlen2 <= 24) doencrypt = False; if (passlen1 > MAX_PASS_LEN) { @@ -593,7 +595,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int setting passlen2 to some random value which really stuffs things up. we need to fix that one. */ - if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) + if (passlen1 > 0 && passlen2 > 0 && passlen2 <= 24 && passlen2 != 1) passlen2 = 0; } diff --git a/source3/smbd/service.c b/source3/smbd/service.c index becfd01504..232579a0f1 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -390,10 +390,10 @@ connection_struct *make_connection(char *service,char *user,char *password, int #endif if (*lp_force_user(snum)) { - struct passwd *pass2; + const struct passwd *pass2; fstring fuser; fstrcpy(fuser,lp_force_user(snum)); - pass2 = (struct passwd *)Get_Pwnam(fuser,True); + pass2 = (const struct passwd *)Get_Pwnam(fuser,True); if (pass2) { conn->uid = pass2->pw_uid; string_set(&conn->user,fuser); diff --git a/source3/utils/rpctorture.c b/source3/utils/rpctorture.c index 86729c3d10..ff98c0a837 100644 --- a/source3/utils/rpctorture.c +++ b/source3/utils/rpctorture.c @@ -113,6 +113,8 @@ static BOOL rpcclient_connect(struct client_info *info) { rpcclient_init(); + smb_cli->use_ntlmv2 = lp_client_ntlmv2(); + if (!cli_establish_connection(smb_cli, info->dest_host, &info->dest_ip, &calling, &called, -- cgit