From 01de6030843f5f402dee8bf72f564a91ae8437ca Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Mon, 19 Oct 1998 17:32:10 +0000 Subject: - dce/rpc code - removed debug info in struni2 and unistr2 (security risk) - rpc_pipe function was getting pointer to data then calling realloc *dur* - password check function, the start of "credential checking", user, wks, domain, pass as the credentials (not just user,pass which is incorrect in a domain context) - cli_write needs to return ssize_t not size_t, because total can be -1 if the write fails. - fixed signed / unsigned warnings (how come i don't get those any more when i compile with gcc???) - nt password change added in smbd. yes, jeremy, i verified that the SMBtrans2 version still works. (This used to be commit fcfb40d2b0fc565ee4f66b3a3761c246366a2ef3) --- source3/include/ntdomain.h | 2 + source3/include/proto.h | 26 ++- source3/lib/util.c | 20 +-- source3/libsmb/clientgen.c | 3 +- source3/libsmb/smbencrypt.c | 2 +- source3/rpc_client/cli_pipe.c | 43 +++-- source3/rpc_parse/parse_rpc.c | 41 +++++ source3/rpc_server/srv_ldap_helpers.c | 4 +- source3/rpc_server/srv_samr.c | 8 +- source3/rpc_server/srv_util.c | 124 ++++++++++--- source3/smbd/chgpasswd.c | 323 ++++++++++++++++++++++------------ source3/smbd/ipc.c | 24 +-- source3/smbd/password.c | 23 ++- source3/smbd/reply.c | 2 +- 14 files changed, 431 insertions(+), 214 deletions(-) diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index 07d32519bf..b7c3b5b577 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -83,10 +83,12 @@ typedef struct pipes_struct RPC_AUTH_NTLMSSP_NEG ntlmssp_neg; RPC_AUTH_NTLMSSP_CHAL ntlmssp_chal; RPC_AUTH_NTLMSSP_RESP ntlmssp_resp; + RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; BOOL ntlmssp_auth; BOOL ntlmssp_validated; unsigned char ntlmssp_hash[258]; + uint32 ntlmssp_seq_num; fstring user_name; fstring domain; fstring wks; diff --git a/source3/include/proto.h b/source3/include/proto.h index 300eddae40..6067430740 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -390,7 +390,7 @@ BOOL cli_close(struct cli_state *cli, int fnum); BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout); BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout); size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size); -size_t cli_write(struct cli_state *cli, +ssize_t cli_write(struct cli_state *cli, int fnum, uint16 write_mode, char *buf, off_t offset, size_t size); BOOL cli_getattrE(struct cli_state *cli, int fd, @@ -510,7 +510,7 @@ void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16]); void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]); 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], char *passwd, char old_pw_hash[16], BOOL unicode); +BOOL make_oem_passwd_hash(char data[516], char *passwd, uchar old_pw_hash[16], BOOL unicode); /*The following definitions come from libsmb/smberr.c */ @@ -1569,11 +1569,14 @@ void make_rpc_hdr_autha(RPC_HDR_AUTHA *rai, uint8 auth_type, uint8 auth_level, uint8 stub_type_len); void smb_io_rpc_hdr_autha(char *desc, RPC_HDR_AUTHA *rai, prs_struct *ps, int depth); +BOOL rpc_hdr_auth_chk(RPC_HDR_AUTH *rai); void make_rpc_hdr_auth(RPC_HDR_AUTH *rai, uint8 auth_type, uint8 auth_level, uint8 stub_type_len, uint32 ptr); void smb_io_rpc_hdr_auth(char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth); +BOOL rpc_auth_verifier_chk(RPC_AUTH_VERIFIER *rav, + char *signature, uint32 msg_type); void make_rpc_auth_verifier(RPC_AUTH_VERIFIER *rav, char *signature, uint32 msg_type); void smb_io_rpc_auth_verifier(char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth); @@ -1590,6 +1593,7 @@ void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp, 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); +BOOL rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk, uint32 crc32, uint32 *seq_num); void make_rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk, uint32 ver, uint32 crc32, uint32 seq_num); void smb_io_rpc_auth_ntlmssp_chk(char *desc, RPC_AUTH_NTLMSSP_CHK *chk, prs_struct *ps, int depth); @@ -1846,6 +1850,7 @@ void wks_io_r_query_info(char *desc, WKS_R_QUERY_INFO *r_u, prs_struct *ps, int /*The following definitions come from rpc_server/srv_ldap_helpers.c */ +void ldap_helper_dummy(void); /*The following definitions come from rpc_server/srv_lsa.c */ @@ -2011,10 +2016,15 @@ void process_blocking_lock_queue(time_t t); BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root); BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root); -BOOL check_lanman_password(char *user, unsigned char *pass1, - unsigned char *pass2, struct smb_passwd **psmbpw); -BOOL change_lanman_password(struct smb_passwd *smbpw, unsigned char *pass1, unsigned char *pass2); -BOOL check_oem_password(char *user, unsigned char *data, +BOOL check_lanman_password(char *user, uchar *pass1, + uchar *pass2, struct smb_passwd **psmbpw); +BOOL change_lanman_password(struct smb_passwd *smbpw, uchar *pass1, uchar *pass2); +BOOL pass_oem_change(char *user, + uchar *lmdata, uchar *lmhash, + uchar *ntdata, uchar *nthash); +BOOL check_oem_password(char *user, + uchar *lmdata, uchar *lmhash, + uchar *ntdata, uchar *nthash, struct smb_passwd **psmbpw, char *new_passwd, int new_passwd_size); BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override); @@ -2195,10 +2205,10 @@ int setup_groups(char *user, uid_t uid, gid_t gid, int *p_ngroups, gid_t **p_gro uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest); 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, +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, - char *challenge, char *lm_pwd, char *nt_pwd, + uchar *chal, char *lm_pwd, char *nt_pwd, struct passwd *pwd); BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd); BOOL user_ok(char *user,int snum); diff --git a/source3/lib/util.c b/source3/lib/util.c index b49369a582..f2cd2a99d1 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -4490,16 +4490,11 @@ char *unistrn2(uint16 *buf, int len) nexti = (nexti+1)%8; - DEBUG(10, ("unistrn2: ")); - for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++) { - DEBUG(10, ("%4x ", *buf)); *p = *buf; } - DEBUG(10,("\n")); - *p = 0; return lbuf; } @@ -4518,16 +4513,11 @@ char *unistr2(uint16 *buf) nexti = (nexti+1)%8; - DEBUG(10, ("unistr2: ")); - for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++) { - DEBUG(10, ("%4x ", *buf)); *p = *buf; } - DEBUG(10,("\n")); - *p = 0; return lbuf; } @@ -4545,17 +4535,12 @@ int struni2(uint16 *p, char *buf) if (p == NULL) return 0; - DEBUG(10, ("struni2: ")); - if (buf != NULL) { for (; *buf && len < MAXUNI-2; len++, p++, buf++) { - DEBUG(10, ("%2x ", *buf)); *p = *buf; } - - DEBUG(10,("\n")); } *p = 0; @@ -4857,6 +4842,10 @@ int set_maxfiles(int requested_max) #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)) struct rlimit rlp; getrlimit(RLIMIT_NOFILE, &rlp); + /* Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to + * account for the extra fd we need + * as well as the log files and standard + * handles etc. */ rlp.rlim_cur = MIN(requested_max,rlp.rlim_max); setrlimit(RLIMIT_NOFILE, &rlp); getrlimit(RLIMIT_NOFILE, &rlp); @@ -4868,4 +4857,3 @@ int set_maxfiles(int requested_max) return requested_max; #endif } - diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 7c58a969e7..d3233f59fd 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -1195,7 +1195,6 @@ BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int ti SSVAL(p, 0, cli->pid); SIVAL(p, 2, offset); SIVAL(p, 6, len); - cli_send_smb(cli); cli->timeout = (timeout == -1) ? 0x7FFFFFFF : timeout; @@ -1395,7 +1394,7 @@ static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint1 0x0004 use raw named pipe protocol 0x0008 start of message mode named pipe protocol ****************************************************************************/ -size_t cli_write(struct cli_state *cli, +ssize_t cli_write(struct cli_state *cli, int fnum, uint16 write_mode, char *buf, off_t offset, size_t size) { diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index 66eba88f49..5017b33c07 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -190,7 +190,7 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) #endif } -BOOL make_oem_passwd_hash(char data[516], char *passwd, char old_pw_hash[16], BOOL unicode) +BOOL make_oem_passwd_hash(char data[516], char *passwd, uchar old_pw_hash[16], BOOL unicode) { int new_pw_len = strlen(passwd) * (unicode ? 2 : 1); diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index f252c99d97..08b3575733 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -142,7 +142,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, RPC_AUTH_NTLMSSP_CHK chk; uint32 crc32; int data_len = len - 0x18 - auth_len - 8; - char *reply_data = (uchar*)mem_data(&rdata->data, 0x18); + char *reply_data = mem_data(&rdata->data, 0x18); BOOL auth_verify = IS_BITS_SET_ALL(cli->ntlmssp_srv_flgs, NTLMSSP_NEGOTIATE_SIGN); BOOL auth_seal = IS_BITS_SET_ALL(cli->ntlmssp_srv_flgs, NTLMSSP_NEGOTIATE_SEAL); @@ -150,13 +150,8 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s\n", len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal))); -/* RPC_HDR_AUTH rhdr_auth; - prs_struct auth_req; - prs_init(&auth_req , 0x10, 4, 0, True); - smb_io_rpc_hdr_auth("hdr_auth", &rhdr_auth, &hdr_auth, 0); - prs_mem_free(&auth_req); + if (reply_data == NULL) return False; -*/ if (auth_seal) { DEBUG(10,("rpc_auth_pipe: seal\n")); @@ -165,14 +160,32 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, dump_data(100, reply_data, data_len); } + if (auth_verify || auth_seal) + { + RPC_HDR_AUTH rhdr_auth; + prs_struct auth_req; + char *data = mem_data(&rdata->data, len - auth_len - 8); + prs_init(&auth_req , 0x08, 4, 0, True); + memcpy(auth_req.data->data, data, 8); + smb_io_rpc_hdr_auth("hdr_auth", &rhdr_auth, &auth_req, 0); + prs_mem_free(&auth_req); + + if (!rpc_hdr_auth_chk(&rhdr_auth)) + { + return False; + } + } + if (auth_verify) { prs_struct auth_verf; char *data = (uchar*)mem_data(&rdata->data, len - auth_len); - prs_init(&auth_verf, 0x08, 4, 0, True); + if (data == NULL) return False; + DEBUG(10,("rpc_auth_pipe: verify\n")); dump_data(100, data, auth_len); - NTLMSSPcalc(cli->ntlmssp_hash, data + 4, auth_len - 4); + NTLMSSPcalc(cli->ntlmssp_hash, (uchar*)(data+4), auth_len - 4); + prs_init(&auth_verf, 0x08, 4, 0, True); memcpy(auth_verf.data->data, data, 16); smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &auth_verf, 0); dump_data(100, data, auth_len); @@ -182,14 +195,8 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, if (auth_verify) { crc32 = crc32_calc_buffer(data_len, reply_data); - if (chk.crc32 != crc32 || - chk.ver != NTLMSSP_SIGN_VERSION || - chk.seq_num != cli->ntlmssp_seq_num++) + if (!rpc_auth_ntlmssp_chk(&chk, crc32 , &cli->ntlmssp_seq_num)) { - DEBUG(5,("rpc_auth_pipe: verify failed - crc %x ver %x seq %d\n", - crc32, NTLMSSP_SIGN_VERSION, cli->ntlmssp_seq_num)); - DEBUG(5,("rpc_auth_pipe: verify expect - crc %x ver %x seq %d\n", - chk.crc32, chk.ver, chk.seq_num)); return False; } } @@ -585,7 +592,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num, BOOL ret; BOOL auth_verify; BOOL auth_seal; - uint32 crc32 = 0; + uint32 crc32; auth_verify = IS_BITS_SET_ALL(cli->ntlmssp_srv_flgs, NTLMSSP_NEGOTIATE_SIGN); auth_seal = IS_BITS_SET_ALL(cli->ntlmssp_srv_flgs, NTLMSSP_NEGOTIATE_SEAL); @@ -915,8 +922,8 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, char *pipe_name, pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL); pwd_get_lm_nt_16(&cli->pwd, lm_hash, NULL); NTLMSSPOWFencrypt(lm_hash, lm_owf, p24); - bzero(lm_hash, sizeof(lm_hash)); NTLMSSPhash(cli->ntlmssp_hash, p24); + bzero(lm_hash, sizeof(lm_hash)); /* this is a hack due to limitations in rpc_api_pipe */ prs_init(&dataa, mem_buf_len(hdra.data), 4, 0x0, False); diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c index f9745da4b4..44f95c7e0c 100644 --- a/source3/rpc_parse/parse_rpc.c +++ b/source3/rpc_parse/parse_rpc.c @@ -457,6 +457,14 @@ void smb_io_rpc_hdr_autha(char *desc, RPC_HDR_AUTHA *rai, prs_struct *ps, int de prs_uint32("unknown ", ps, depth, &(rai->unknown )); /* 0x0014a0c0 */ } +/******************************************************************* +checks an RPC_HDR_AUTH structure. +********************************************************************/ +BOOL rpc_hdr_auth_chk(RPC_HDR_AUTH *rai) +{ + return (rai->auth_type == 0x0a && rai->auth_level == 0x06); +} + /******************************************************************* creates an RPC_HDR_AUTH structure. ********************************************************************/ @@ -493,6 +501,15 @@ void smb_io_rpc_hdr_auth(char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int dept prs_uint32("unknown ", ps, depth, &(rai->unknown )); /* 0x0014a0c0 */ } +/******************************************************************* +checks an RPC_AUTH_VERIFIER structure. +********************************************************************/ +BOOL rpc_auth_verifier_chk(RPC_AUTH_VERIFIER *rav, + char *signature, uint32 msg_type) +{ + return (strequal(rav->signature, signature) && rav->msg_type == msg_type); +} + /******************************************************************* creates an RPC_AUTH_VERIFIER structure. ********************************************************************/ @@ -783,6 +800,30 @@ void smb_io_rpc_auth_ntlmssp_resp(char *desc, RPC_AUTH_NTLMSSP_RESP *rsp, prs_st } } +/******************************************************************* +checks an RPC_AUTH_NTLMSSP_CHK structure. +********************************************************************/ +BOOL rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk, uint32 crc32, uint32 *seq_num) +{ + if (chk == NULL || seq_num == NULL) + { + return False; + } + + if (chk->crc32 != crc32 || + chk->ver != NTLMSSP_SIGN_VERSION || + chk->seq_num != (*seq_num)) + { + DEBUG(5,("verify failed - crc %x ver %x seq %d\n", + crc32, NTLMSSP_SIGN_VERSION, (*seq_num)-1)); + DEBUG(5,("verify expect - crc %x ver %x seq %d\n", + chk->crc32, chk->ver, chk->seq_num)); + return False; + } + (*seq_num)++; + return True; +} + /******************************************************************* creates an RPC_AUTH_NTLMSSP_CHK structure. ********************************************************************/ diff --git a/source3/rpc_server/srv_ldap_helpers.c b/source3/rpc_server/srv_ldap_helpers.c index 4db841990e..fb2442789c 100644 --- a/source3/rpc_server/srv_ldap_helpers.c +++ b/source3/rpc_server/srv_ldap_helpers.c @@ -9,6 +9,6 @@ extern int DEBUGLEVEL; #else /* USE_LDAP */ /* this keeps fussy compilers happy */ - void ldap_helper_dummy(void); - void ldap_helper_dummy(void) {} +void ldap_helper_dummy(void) +{} #endif /* USE_LDAP */ diff --git a/source3/rpc_server/srv_samr.c b/source3/rpc_server/srv_samr.c index a3d758489c..1b159cd65d 100644 --- a/source3/rpc_server/srv_samr.c +++ b/source3/rpc_server/srv_samr.c @@ -735,8 +735,12 @@ static void samr_reply_chgpasswd_user(SAMR_Q_CHGPASSWD_USER *q_u, DEBUG(5,("samr_chgpasswd_user: user: %s wks: %s\n", user_name, wks)); - /* oops! */ - status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + if (!pass_oem_change(user_name, + q_u->lm_newpass.pass, q_u->lm_oldhash.hash, + q_u->nt_newpass.pass, q_u->nt_oldhash.hash)) + { + status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD; + } make_samr_r_chgpasswd_user(&r_u, status); diff --git a/source3/rpc_server/srv_util.c b/source3/rpc_server/srv_util.c index 850282b6b5..7ddc2da5d1 100644 --- a/source3/rpc_server/srv_util.c +++ b/source3/rpc_server/srv_util.c @@ -212,6 +212,7 @@ static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) { uchar lm_owf[24]; uchar nt_owf[24]; + struct smb_passwd *smb_pass = NULL; DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n")); @@ -244,15 +245,29 @@ static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) memcpy(nt_owf, p->ntlmssp_resp.nt_resp, sizeof(nt_owf)); #ifdef DEBUG_PASSWORD - DEBUG(100,("lm, nt owfs:\n")); + 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, - p->ntlmssp_chal.challenge, lm_owf, nt_owf, NULL); + p->ntlmssp_chal.challenge, (uchar*)lm_owf, (uchar*)nt_owf, NULL); + smb_pass = getsmbpwnam(p->user_name); unbecome_root(True); + if (p->ntlmssp_validated && smb_pass != NULL && smb_pass->smb_passwd) + { + uchar p24[24]; + NTLMSSPOWFencrypt(smb_pass->smb_passwd, lm_owf, p24); + NTLMSSPhash(p->ntlmssp_hash, p24); + p->ntlmssp_seq_num = 0; + } + else + { + p->ntlmssp_validated = False; + } + return p->ntlmssp_validated; } @@ -307,33 +322,22 @@ static struct api_cmd api_fd_commands[] = static BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *pd) { - p->ntlmssp_auth = False; - DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__)); - if (p->hdr.auth_len != 0) - { - /* decode the authentication verifier response */ - smb_io_rpc_hdr_autha("", &p->autha_info, pd, 0); - if (pd->offset == 0) return False; + if (p->hdr.auth_len == 0) return False; - p->ntlmssp_auth = p->auth_info.auth_type = 0x0a; - - if (p->ntlmssp_auth) - { - smb_io_rpc_auth_verifier("", &p->auth_verifier, pd, 0); - if (pd->offset == 0) return False; + /* decode the authentication verifier response */ + smb_io_rpc_hdr_autha("", &p->autha_info, pd, 0); + if (pd->offset == 0) return False; - p->ntlmssp_auth = strequal(p->auth_verifier.signature, "NTLMSSP"); - } + if (!rpc_hdr_auth_chk(&(p->auth_info))) return False; - if (p->ntlmssp_auth) - { - if (!api_pipe_ntlmssp(p, pd)) return False; - } - } + smb_io_rpc_auth_verifier("", &p->auth_verifier, pd, 0); + if (pd->offset == 0) return False; - return p->ntlmssp_auth; + if (!rpc_auth_verifier_chk(&(p->auth_verifier), "NTLMSSP", NTLMSSP_AUTH)) return False; + + return api_pipe_ntlmssp(p, pd); } static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd) @@ -490,6 +494,58 @@ static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd) static BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *pd) { + BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SIGN); + BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SEAL); + int data_len; + int auth_len; + uint32 old_offset; + uint32 crc32; + + auth_len = p->hdr.auth_len; + + if (auth_len != 16 && auth_verify) + { + return False; + } + + data_len = p->hdr.frag_len - auth_len - (auth_verify ? 8 : 0) - 0x18; + + 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 = (uchar*)mem_data(&pd->data, pd->offset); + DEBUG(5,("api_pipe_auth_process: data %d\n", pd->offset)); + NTLMSSPcalc(p->ntlmssp_hash, data, data_len); + crc32 = crc32_calc_buffer(data_len, data); + } + + /*** skip the data, record the offset so we can restore it again */ + old_offset = pd->offset; + + if (auth_seal || auth_verify) + { + pd->offset += data_len; + smb_io_rpc_hdr_auth("hdr_auth", &p->auth_info, pd, 0); + } + + if (auth_verify) + { + char *req_data = (uchar*)mem_data(&pd->data, pd->offset + 4); + DEBUG(5,("api_pipe_auth_process: auth %d\n", pd->offset + 4)); + NTLMSSPcalc(p->ntlmssp_hash, req_data, 12); + smb_io_rpc_auth_ntlmssp_chk("auth_sign", &(p->ntlmssp_chk), pd, 0); + + if (!rpc_auth_ntlmssp_chk(&(p->ntlmssp_chk), crc32, + &(p->ntlmssp_seq_num))) + { + return False; + } + } + + pd->offset = old_offset; + return True; } @@ -538,16 +594,33 @@ BOOL rpc_command(pipes_struct *p, prs_struct *pd) } case RPC_REQUEST: { - reply = api_pipe_request (p, pd); + if (p->ntlmssp_auth && !p->ntlmssp_validated) + { + /* authentication _was_ requested + and it failed. sorry, no deal! + */ + reply = False; + } + else + { + /* read the rpc header */ + smb_io_rpc_hdr_req("req", &(p->hdr_req), pd, 0); + reply = api_pipe_request(p, pd); + } break; } case RPC_BINDRESP: /* not the real name! */ { reply = api_pipe_bind_auth_resp(p, pd); + p->ntlmssp_auth = reply; break; } } + if (!reply) + { + DEBUG(3,("rpc_command: DCE/RPC fault should be sent here\n")); + } return reply; } @@ -618,9 +691,6 @@ BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds return False; } - /* read the rpc header */ - smb_io_rpc_hdr_req("req", &(p->hdr_req), data, 0); - /* interpret the command */ if (!api_rpc_command(p, rpc_name, api_rpc_cmds, data)) { diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 4131bc9297..45497e4cf8 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -69,7 +69,7 @@ static int findpty(char **slave) grantpt(master); unlockpt(master); *slave = ptsname(master); - if(*slave == NULL) { + if (*slave == NULL) { DEBUG(0,("findpty: Unable to create master/slave pty pair.\n")); return -1; } else { @@ -109,7 +109,7 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram, int gid; int uid; - if(pass == NULL) { + if (pass == NULL) { DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n", name)); return False; @@ -180,7 +180,7 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram, } /* make us completely into the right uid */ - if(!as_root) { + if (!as_root) { #ifdef HAVE_SETRESUID setresgid(0,0,0); setresuid(0,0,0); @@ -269,7 +269,7 @@ static int talktochild(int master, char *chatsequence) if (!strequal(chatbuf,".")) ok = expect(master,chatbuf,buf); - if(lp_passwd_chat_debug()) + if (lp_passwd_chat_debug()) DEBUG(100,("talktochild: chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf)); if (!ok) { @@ -282,7 +282,7 @@ static int talktochild(int master, char *chatsequence) if (!strequal(chatbuf,".")) writestring(master,chatbuf); - if(lp_passwd_chat_debug()) + if (lp_passwd_chat_debug()) DEBUG(100,("talktochild: sendbuf=[%s]\n",chatbuf)); } @@ -352,16 +352,16 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc /* make sure it doesn't freeze */ alarm(20); - if(as_root) + if (as_root) become_root(False); DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid())); chstat = dochild(master, slavedev, name, passwordprogram, as_root); - if(as_root) + if (as_root) unbecome_root(False); } - if(chstat) + if (chstat) DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name)); return (chstat); } @@ -416,7 +416,7 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root) len = strlen(oldpass); for(i = 0; i < len; i++) { - if(iscntrl((int)oldpass[i])) { + if (iscntrl((int)oldpass[i])) { DEBUG(0,("chat_with_program: oldpass contains control characters (disallowed).\n")); return False; } @@ -424,7 +424,7 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root) len = strlen(newpass); for(i = 0; i < len; i++) { - if(iscntrl((int)newpass[i])) { + if (iscntrl((int)newpass[i])) { DEBUG(0,("chat_with_program: newpass contains control characters (disallowed).\n")); return False; } @@ -452,12 +452,12 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root) Code to check the lanman hashed password. ************************************************************/ -BOOL check_lanman_password(char *user, unsigned char *pass1, - unsigned char *pass2, struct smb_passwd **psmbpw) +BOOL check_lanman_password(char *user, uchar *pass1, + uchar *pass2, struct smb_passwd **psmbpw) { - unsigned char unenc_new_pw[16]; - unsigned char unenc_old_pw[16]; - unsigned char null_pw[16]; + uchar unenc_new_pw[16]; + uchar unenc_old_pw[16]; + uchar null_pw[16]; struct smb_passwd *smbpw; *psmbpw = NULL; @@ -466,21 +466,21 @@ BOOL check_lanman_password(char *user, unsigned char *pass1, smbpw = getsmbpwnam(user); unbecome_root(0); - if(smbpw == NULL) + if (smbpw == NULL) { DEBUG(0,("check_lanman_password: getsmbpwnam returned NULL\n")); return False; } - if(smbpw->acct_ctrl & ACB_DISABLED) + if (smbpw->acct_ctrl & ACB_DISABLED) { DEBUG(0,("check_lanman_password: account %s disabled.\n", user)); return False; } - if((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ)) + if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ)) { - unsigned char no_pw[14]; + uchar no_pw[14]; memset(no_pw, '\0', 14); E_P16((uchar *)no_pw, (uchar *)null_pw); smbpw->smb_passwd = null_pw; @@ -496,7 +496,7 @@ BOOL check_lanman_password(char *user, unsigned char *pass1, D_P16(unenc_new_pw, pass1, unenc_old_pw); /* Check that the two old passwords match. */ - if(memcmp(smbpw->smb_passwd, unenc_old_pw, 16)) + if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16)) { DEBUG(0,("check_lanman_password: old password doesn't match.\n")); return False; @@ -512,27 +512,27 @@ BOOL check_lanman_password(char *user, unsigned char *pass1, no longer be valid. ************************************************************/ -BOOL change_lanman_password(struct smb_passwd *smbpw, unsigned char *pass1, unsigned char *pass2) +BOOL change_lanman_password(struct smb_passwd *smbpw, uchar *pass1, uchar *pass2) { - unsigned char unenc_new_pw[16]; - unsigned char null_pw[16]; + uchar unenc_new_pw[16]; + uchar null_pw[16]; BOOL ret; - if(smbpw == NULL) + if (smbpw == NULL) { DEBUG(0,("change_lanman_password: no smb password entry.\n")); return False; } - if(smbpw->acct_ctrl & ACB_DISABLED) + if (smbpw->acct_ctrl & ACB_DISABLED) { DEBUG(0,("change_lanman_password: account %s disabled.\n", smbpw->smb_name)); return False; } - if((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ)) + if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ)) { - unsigned char no_pw[14]; + uchar no_pw[14]; memset(no_pw, '\0', 14); E_P16((uchar *)no_pw, (uchar *)null_pw); smbpw->smb_passwd = null_pw; @@ -556,90 +556,197 @@ BOOL change_lanman_password(struct smb_passwd *smbpw, unsigned char *pass1, unsi } /*********************************************************** - Code to check the OEM hashed password. + Code to check and change the OEM hashed password. ************************************************************/ - -BOOL check_oem_password(char *user, unsigned char *data, - struct smb_passwd **psmbpw, char *new_passwd, - int new_passwd_size) +BOOL pass_oem_change(char *user, + uchar *lmdata, uchar *lmhash, + uchar *ntdata, uchar *nthash) { - struct smb_passwd *smbpw = NULL; - int new_pw_len; - fstring upper_case_new_passwd; - unsigned char new_p16[16]; - unsigned char unenc_old_pw[16]; - unsigned char null_pw[16]; - - become_root(0); - *psmbpw = smbpw = getsmbpwnam(user); - unbecome_root(0); - - if(smbpw == NULL) - { - DEBUG(0,("check_oem_password: getsmbpwnam returned NULL\n")); - return False; - } - - if(smbpw->acct_ctrl & ACB_DISABLED) - { - DEBUG(0,("check_lanman_password: account %s disabled.\n", user)); - return False; - } - - if((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ)) - { - unsigned char no_pw[14]; - memset(no_pw, '\0', 14); - E_P16((uchar *)no_pw, (uchar *)null_pw); - smbpw->smb_passwd = null_pw; - } else if (smbpw->smb_passwd == NULL) { - DEBUG(0,("check_oem_password: no lanman password !\n")); - return False; - } - - /* - * Call the hash function to get the new password. - */ - SamOEMhash( (unsigned char *)data, (unsigned char *)smbpw->smb_passwd, True); - - /* - * The length of the new password is in the last 4 bytes of - * the data buffer. - */ - new_pw_len = IVAL(data,512); - if(new_pw_len < 0 || new_pw_len > new_passwd_size - 1) { - DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len)); - return False; - } - - memcpy(new_passwd, &data[512-new_pw_len], new_pw_len); - new_passwd[new_pw_len] = '\0'; - - /* - * To ensure we got the correct new password, hash it and - * use it as a key to test the passed old password. - */ - - memset(upper_case_new_passwd, '\0', sizeof(upper_case_new_passwd)); - fstrcpy(upper_case_new_passwd, new_passwd); - strupper(upper_case_new_passwd); - - E_P16((uchar *)upper_case_new_passwd, new_p16); - - /* - * Now use new_p16 as the key to see if the old - * password matches. - */ - D_P16(new_p16, &data[516], unenc_old_pw); + fstring new_passwd; + struct smb_passwd *sampw; + BOOL ret = check_oem_password( user, lmdata, lmhash, ntdata, nthash, + &sampw, + new_passwd, sizeof(new_passwd)); + + /* + * At this point we have the new case-sensitive plaintext + * password in the fstring new_passwd. If we wanted to synchronise + * with UNIX passwords we would call a UNIX password changing + * function here. However it would have to be done as root + * as the plaintext of the old users password is not + * available. JRA. + */ + + if ( ret && lp_unix_password_sync()) + { + ret = chgpasswd(user,"", new_passwd, True); + } + + if (ret) + { + ret = change_oem_password( sampw, new_passwd, False ); + } + + memset(new_passwd, 0, sizeof(new_passwd)); + + return ret; +} - if(memcmp(smbpw->smb_passwd, unenc_old_pw, 16)) { - DEBUG(0,("check_oem_password: old password doesn't match.\n")); - return False; - } +/*********************************************************** + Code to check the OEM hashed password. - memset(upper_case_new_passwd, '\0', strlen(upper_case_new_passwd)); + this function ignores the 516 byte nt OEM hashed password + but does use the lm OEM password to check the nt hashed-hash. - return True; +************************************************************/ +BOOL check_oem_password(char *user, + uchar *lmdata, uchar *lmhash, + uchar *ntdata, uchar *nthash, + struct smb_passwd **psmbpw, char *new_passwd, + int new_passwd_size) +{ + struct smb_passwd *smbpw = NULL; + int new_pw_len; + uchar new_ntp16[16]; + uchar unenc_old_ntpw[16]; + uchar new_p16[16]; + uchar unenc_old_pw[16]; + uchar null_pw[16]; + uchar null_ntpw[16]; + uchar no_pw[2]; + BOOL nt_pass_set = (ntdata != NULL && nthash != NULL); + + become_root(False); + *psmbpw = smbpw = getsmbpwnam(user); + unbecome_root(False); + + if (smbpw == NULL) + { + DEBUG(0,("check_oem_password: getsmbpwnam returned NULL\n")); + return False; + } + + if (smbpw->acct_ctrl & ACB_DISABLED) + { + DEBUG(0,("check_lanman_password: account %s disabled.\n", user)); + return False; + } + + /* construct a null password (in case one is needed */ + no_pw[0] = 0; + no_pw[1] = 0; + nt_lm_owf_gen(no_pw, null_ntpw, null_pw); + + /* check for null passwords */ + if (smbpw->smb_passwd == NULL) + { + if (smbpw->acct_ctrl & ACB_PWNOTREQ) + { + smbpw->smb_passwd = null_pw; + } + else + { + DEBUG(0,("check_oem_password: no lanman password !\n")); + return False; + } + } + + if (smbpw->smb_nt_passwd == NULL && nt_pass_set) + { + if (smbpw->acct_ctrl & ACB_PWNOTREQ) + { + smbpw->smb_nt_passwd = null_pw; + } + else + { + DEBUG(0,("check_oem_password: no ntlm password !\n")); + return False; + } + } + + /* + * Call the hash function to get the new password. + */ + SamOEMhash( (uchar *)lmdata, (uchar *)smbpw->smb_passwd, True); + + /* + * The length of the new password is in the last 4 bytes of + * the data buffer. + */ + + new_pw_len = IVAL(lmdata, 512); + if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) + { + DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len)); + return False; + } + + if (nt_pass_set) + { + /* + * nt passwords are in unicode + */ + int uni_pw_len = new_pw_len; + char *pw; + new_pw_len /= 2; + pw = unistrn2((uint16*)(&lmdata[512-uni_pw_len]), new_pw_len); + memcpy(new_passwd, pw, new_pw_len+1); + } + else + { + memcpy(new_passwd, &lmdata[512-new_pw_len], new_pw_len); + new_passwd[new_pw_len] = '\0'; + } + + /* + * To ensure we got the correct new password, hash it and + * use it as a key to test the passed old password. + */ + + nt_lm_owf_gen(new_passwd, new_ntp16, new_p16); + + if (!nt_pass_set) + { + /* + * Now use new_p16 as the key to see if the old + * password matches. + */ + D_P16(new_p16 , lmhash, unenc_old_pw); + + if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16)) + { + DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); + return False; + } + +#ifdef DEBUG_PASSWORD + DEBUG(100,("check_oem_password: password %s ok\n", new_passwd)); +#endif + return True; + } + + /* + * Now use new_p16 as the key to see if the old + * password matches. + */ + D_P16(new_ntp16, lmhash, unenc_old_pw); + D_P16(new_ntp16, nthash, unenc_old_ntpw); + + if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16)) + { + DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); + return False; + } + + if (memcmp(smbpw->smb_nt_passwd, unenc_old_ntpw, 16)) + { + DEBUG(0,("check_oem_password: old nt password doesn't match.\n")); + return False; + } +#ifdef DEBUG_PASSWORD + DEBUG(100,("check_oem_password: password %s ok\n", new_passwd)); +#endif + return True; } /*********************************************************** @@ -653,8 +760,8 @@ BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL overri { int ret; fstring upper_case_new_passwd; - unsigned char new_nt_p16[16]; - unsigned char new_p16[16]; + uchar new_nt_p16[16]; + uchar new_p16[16]; memset(upper_case_new_passwd, '\0', sizeof(upper_case_new_passwd)); fstrcpy(upper_case_new_passwd, new_passwd); diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index df04cd82a0..2b8b8698db 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -1692,11 +1692,7 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char * int *rdata_len,int *rparam_len) { fstring user; - fstring new_passwd; - struct smb_passwd *sampw = NULL; char *p = param + 2; - int ret = True; - *rparam_len = 2; *rparam = REALLOC(*rparam,*rparam_len); @@ -1736,24 +1732,8 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char * */ (void)Get_Pwnam( user, True); - if(check_oem_password( user, (unsigned char *)data, &sampw, - new_passwd, (int)sizeof(new_passwd)) == False) { - return True; - } - - /* - * At this point we have the new case-sensitive plaintext - * password in the fstring new_passwd. If we wanted to synchronise - * with UNIX passwords we would call a UNIX password changing - * function here. However it would have to be done as root - * as the plaintext of the old users password is not - * available. JRA. - */ - - if(lp_unix_password_sync()) - ret = chgpasswd(user,"", new_passwd, True); - - if(ret && change_oem_password( sampw, new_passwd, False)) { + if (pass_oem_change(user, (uchar*) data, &data[516], NULL, NULL)) + { SSVAL(*rparam,0,NERR_Success); } diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 1c9eb19759..eac8c9cd65 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -383,8 +383,7 @@ BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned cha 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, +BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], uchar lm_pass[24], uchar nt_pass[24]) { uchar challenge[8]; @@ -400,9 +399,19 @@ BOOL smb_password_ok(struct smb_passwd *smb_pass, return(False); } - if (!last_challenge(challenge)) { - DEBUG(1,("no challenge done - password failed\n")); - return False; + if (chal == NULL) + { + DEBUG(5,("use last SMBnegprot challenge\n")); + if (!last_challenge(challenge)) + { + DEBUG(1,("no challenge done - password failed\n")); + return False; + } + } + else + { + DEBUG(5,("challenge received\n")); + memcpy(challenge, chal, 8); } if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) { @@ -450,7 +459,7 @@ SMB hash return True if the password is correct, False otherwise ****************************************************************************/ BOOL pass_check_smb(char *user, char *domain, - char *challenge, char *lm_pwd, char *nt_pwd, + uchar *chal, char *lm_pwd, char *nt_pwd, struct passwd *pwd) { struct passwd *pass; @@ -504,7 +513,7 @@ BOOL pass_check_smb(char *user, char *domain, return(True); } - if (smb_password_ok(smb_pass, (uchar *)lm_pwd, (uchar *)nt_pwd)) + if (smb_password_ok(smb_pass, chal, (uchar *)lm_pwd, (uchar *)nt_pwd)) { return(True); } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index bcb408c2a6..8b96ff17fd 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -413,7 +413,7 @@ 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, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) + if (!smb_password_ok(smb_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) { DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user)); SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES); -- cgit