From 3f1254bee1b3cc8cce1e17be6f0250090f579417 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 20 Jun 2001 19:55:59 +0000 Subject: Fixed W2K SP2 joining a Samba PDC hosted domain. Jermey. (This used to be commit 05a2911403a0710d994a618e72743205a3b0b87a) --- source3/include/rpc_samr.h | 53 ++++++++++++++ source3/libsmb/smbdes.c | 2 +- source3/libsmb/smbencrypt.c | 2 +- source3/rpc_parse/parse_net.c | 4 +- source3/rpc_parse/parse_samr.c | 138 +++++++++++++++++++++++++++++++++++-- source3/rpc_server/srv_netlog_nt.c | 4 +- source3/rpc_server/srv_samr_nt.c | 40 +++++++++-- source3/smbd/chgpasswd.c | 2 +- 8 files changed, 227 insertions(+), 18 deletions(-) diff --git a/source3/include/rpc_samr.h b/source3/include/rpc_samr.h index d996170200..cfe856b07f 100644 --- a/source3/include/rpc_samr.h +++ b/source3/include/rpc_samr.h @@ -219,6 +219,58 @@ typedef struct sam_user_info_24 uint8 pass[516]; } SAM_USER_INFO_24; +/* + * NB. This structure is *definately* incorrect. It's my best guess + * currently for W2K SP2. The password field is encrypted in a different + * way than normal... And there are definately other problems. JRA. + */ + +/* SAM_USER_INFO_25 */ +typedef struct sam_user_info_25 +{ + /* TIMES MAY NOT IN RIGHT ORDER!!!! */ + NTTIME logon_time; /* logon time */ + NTTIME logoff_time; /* logoff time */ + NTTIME kickoff_time; /* kickoff time */ + NTTIME pass_last_set_time; /* password last set time */ + NTTIME pass_can_change_time; /* password can change time */ + NTTIME pass_must_change_time; /* password must change time */ + + UNIHDR hdr_user_name; /* NULL - user name unicode string header */ + UNIHDR hdr_full_name; /* user's full name unicode string header */ + UNIHDR hdr_home_dir; /* home directory unicode string header */ + UNIHDR hdr_dir_drive; /* home drive unicode string header */ + UNIHDR hdr_logon_script; /* logon script unicode string header */ + UNIHDR hdr_profile_path; /* profile path unicode string header */ + UNIHDR hdr_acct_desc ; /* user description */ + UNIHDR hdr_workstations; /* comma-separated workstations user can log in from */ + UNIHDR hdr_unknown_str ; /* don't know what this is, yet. */ + UNIHDR hdr_munged_dial ; /* munged path name and dial-back tel number */ + + uint8 lm_pwd[16]; /* lm user passwords */ + uint8 nt_pwd[16]; /* nt user passwords */ + + uint32 user_rid; /* Primary User ID */ + uint32 group_rid; /* Primary Group ID */ + + uint32 acb_info; /* account info (ACB_xxxx bit-mask) */ + + uint32 unknown_6[6]; + + uint8 pass[532]; + + UNISTR2 uni_user_name; /* NULL - username unicode string */ + UNISTR2 uni_full_name; /* user's full name unicode string */ + UNISTR2 uni_home_dir; /* home directory unicode string */ + UNISTR2 uni_dir_drive; /* home directory drive unicode string */ + UNISTR2 uni_logon_script; /* logon script unicode string */ + UNISTR2 uni_profile_path; /* profile path unicode string */ + UNISTR2 uni_acct_desc ; /* user description unicode string */ + UNISTR2 uni_workstations; /* login from workstations unicode string */ + UNISTR2 uni_unknown_str ; /* don't know what this is, yet. */ + UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel no */ +} SAM_USER_INFO_25; + /* SAM_USER_INFO_21 */ typedef struct sam_user_info_21 @@ -1140,6 +1192,7 @@ typedef struct sam_userinfo_ctr_info SAM_USER_INFO_21 *id21; /* auth-level 21 */ SAM_USER_INFO_23 *id23; /* auth-level 0x17 */ SAM_USER_INFO_24 *id24; /* auth-level 0x18 */ + SAM_USER_INFO_25 *id25; /* auth-level 0x19 */ void* id; /* to make typecasting easy */ } info; diff --git a/source3/libsmb/smbdes.c b/source3/libsmb/smbdes.c index d0e1c6e85f..7e8a9a5b89 100644 --- a/source3/libsmb/smbdes.c +++ b/source3/libsmb/smbdes.c @@ -381,7 +381,7 @@ void SamOEMhash( unsigned char *data, unsigned char *key, int val) s_box[ind] = s_box[j]; s_box[j] = tc; } - for( ind = 0; ind < (val ? 516 : 16); ind++) + for( ind = 0; ind < val; ind++) { unsigned char tc; unsigned char t; diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index 68af1b4941..b9827333d8 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -223,7 +223,7 @@ BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[ DEBUG(100,("make_oem_passwd_hash\n")); dump_data(100, data, 516); #endif - SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True); + SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); return True; } diff --git a/source3/rpc_parse/parse_net.c b/source3/rpc_parse/parse_net.c index 85de667b00..c0d9544ba8 100644 --- a/source3/rpc_parse/parse_net.c +++ b/source3/rpc_parse/parse_net.c @@ -883,9 +883,9 @@ void init_id_info1(NET_ID_INFO_1 *id, char *domain_name, memcpy(key, sess_key, 8); memcpy(lm_owf, lm_cypher, 16); - SamOEMhash(lm_owf, key, False); + SamOEMhash(lm_owf, key, 16); memcpy(nt_owf, nt_cypher, 16); - SamOEMhash(nt_owf, key, False); + SamOEMhash(nt_owf, key, 16); #ifdef DEBUG_PASSWORD DEBUG(100,("encrypt of lm owf password:")); diff --git a/source3/rpc_parse/parse_samr.c b/source3/rpc_parse/parse_samr.c index 6e94b62d40..395931edd9 100644 --- a/source3/rpc_parse/parse_samr.c +++ b/source3/rpc_parse/parse_samr.c @@ -5340,6 +5340,126 @@ static BOOL sam_io_user_info23(char *desc, SAM_USER_INFO_23 * usr, return True; } +/******************************************************************* + reads or writes a structure. + NB. This structure is *definately* incorrect. It's my best guess + currently for W2K SP2. The password field is encrypted in a different + way than normal... And there are definately other problems. JRA. +********************************************************************/ + +static BOOL sam_io_user_info25(char *desc, SAM_USER_INFO_25 * usr, prs_struct *ps, int depth) +{ + if (usr == NULL) + return False; + + prs_debug(ps, depth, desc, "sam_io_user_info23"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!smb_io_time("logon_time ", &usr->logon_time, ps, depth)) + return False; + if(!smb_io_time("logoff_time ", &usr->logoff_time, ps, depth)) + return False; + if(!smb_io_time("kickoff_time ", &usr->kickoff_time, ps, depth)) + return False; + if(!smb_io_time("pass_last_set_time ", &usr->pass_last_set_time, ps, depth)) + return False; + if(!smb_io_time("pass_can_change_time ", &usr->pass_can_change_time, ps, depth)) + return False; + if(!smb_io_time("pass_must_change_time", &usr->pass_must_change_time, ps, depth)) + return False; + + if(!smb_io_unihdr("hdr_user_name ", &usr->hdr_user_name, ps, depth)) /* username unicode string header */ + return False; + if(!smb_io_unihdr("hdr_full_name ", &usr->hdr_full_name, ps, depth)) /* user's full name unicode string header */ + return False; + if(!smb_io_unihdr("hdr_home_dir ", &usr->hdr_home_dir, ps, depth)) /* home directory unicode string header */ + return False; + if(!smb_io_unihdr("hdr_dir_drive ", &usr->hdr_dir_drive, ps, depth)) /* home directory drive */ + return False; + if(!smb_io_unihdr("hdr_logon_script", &usr->hdr_logon_script, ps, depth)) /* logon script unicode string header */ + return False; + if(!smb_io_unihdr("hdr_profile_path", &usr->hdr_profile_path, ps, depth)) /* profile path unicode string header */ + return False; + if(!smb_io_unihdr("hdr_acct_desc ", &usr->hdr_acct_desc, ps, depth)) /* account desc */ + return False; + if(!smb_io_unihdr("hdr_workstations", &usr->hdr_workstations, ps, depth)) /* wkstas user can log on from */ + return False; + if(!smb_io_unihdr("hdr_unknown_str ", &usr->hdr_unknown_str, ps, depth)) /* unknown string */ + return False; + if(!smb_io_unihdr("hdr_munged_dial ", &usr->hdr_munged_dial, ps, depth)) /* wkstas user can log on from */ + return False; + + if(!prs_uint8s(False, "lm_pwd ", ps, depth, usr->lm_pwd, sizeof(usr->lm_pwd))) + return False; + if(!prs_uint8s(False, "nt_pwd ", ps, depth, usr->nt_pwd, sizeof(usr->nt_pwd))) + return False; + + if(!prs_uint32("user_rid ", ps, depth, &usr->user_rid)) /* User ID */ + return False; + if(!prs_uint32("group_rid ", ps, depth, &usr->group_rid)) /* Group ID */ + return False; + if(!prs_uint32("acb_info ", ps, depth, &usr->acb_info)) + return False; + + if(!prs_uint32s(False, "unknown_6 ", ps, depth, usr->unknown_6, 6)) + return False; + + if(!prs_uint8s(False, "password ", ps, depth, usr->pass, sizeof(usr->pass))) + return False; + + /* here begins pointed-to data */ + + if(!smb_io_unistr2("uni_user_name ", &usr->uni_user_name, usr->hdr_user_name.buffer, ps, depth)) /* username unicode string */ + return False; + + if(!smb_io_unistr2("uni_full_name ", &usr->uni_full_name, usr->hdr_full_name.buffer, ps, depth)) /* user's full name unicode string */ + return False; + + if(!smb_io_unistr2("uni_home_dir ", &usr->uni_home_dir, usr->hdr_home_dir.buffer, ps, depth)) /* home directory unicode string */ + return False; + + if(!smb_io_unistr2("uni_dir_drive ", &usr->uni_dir_drive, usr->hdr_dir_drive.buffer, ps, depth)) /* home directory drive unicode string */ + return False; + + if(!smb_io_unistr2("uni_logon_script", &usr->uni_logon_script, usr->hdr_logon_script.buffer, ps, depth)) /* logon script unicode string */ + return False; + + if(!smb_io_unistr2("uni_profile_path", &usr->uni_profile_path, usr->hdr_profile_path.buffer, ps, depth)) /* profile path unicode string */ + return False; + + if(!smb_io_unistr2("uni_acct_desc ", &usr->uni_acct_desc, usr->hdr_acct_desc.buffer, ps, depth)) /* user desc unicode string */ + return False; + + if(!smb_io_unistr2("uni_workstations", &usr->uni_workstations, usr->hdr_workstations.buffer, ps, depth)) /* worksations user can log on from */ + return False; + + if(!smb_io_unistr2("uni_unknown_str ", &usr->uni_unknown_str, usr->hdr_unknown_str.buffer, ps, depth)) /* unknown string */ + return False; + + if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial, usr->hdr_munged_dial.buffer, ps, depth)) + return False; + +#if 0 /* JRA - unknown... */ + /* ok, this is only guess-work (as usual) */ + if (usr->ptr_logon_hrs) { + if(!prs_uint32("unknown_6 ", ps, depth, &usr->unknown_6)) + return False; + if(!prs_uint32("padding4 ", ps, depth, &usr->padding4)) + return False; + if(!sam_io_logon_hrs("logon_hrs", &usr->logon_hrs, ps, depth)) + return False; + } else if (UNMARSHALLING(ps)) { + usr->unknown_6 = 0; + usr->padding4 = 0; + } +#endif + + return True; +} + /************************************************************************* init_sam_user_info21W @@ -5740,12 +5860,12 @@ void init_samr_userinfo_ctr(SAM_USERINFO_CTR * ctr, uchar * sess_key, switch (switch_value) { case 0x18: - SamOEMhash(ctr->info.id24->pass, sess_key, 1); + SamOEMhash(ctr->info.id24->pass, sess_key, 516); dump_data(100, (char *)sess_key, 16); dump_data(100, (char *)ctr->info.id24->pass, 516); break; case 0x17: - SamOEMhash(ctr->info.id23->pass, sess_key, 1); + SamOEMhash(ctr->info.id23->pass, sess_key, 516); dump_data(100, (char *)sess_key, 16); dump_data(100, (char *)ctr->info.id23->pass, 516); break; @@ -5845,6 +5965,16 @@ static BOOL samr_io_userinfo_ctr(char *desc, SAM_USERINFO_CTR **ppctr, } ret = sam_io_user_info24("", ctr->info.id24, ps, depth); break; + case 25: + if (UNMARSHALLING(ps)) + ctr->info.id25 = (SAM_USER_INFO_25 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_25)); + + if (ctr->info.id25 == NULL) { + DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n")); + return False; + } + ret = sam_io_user_info25("", ctr->info.id25, ps, depth); + break; default: DEBUG(2, ("samr_io_userinfo_ctr: unknown switch level 0x%x\n", ctr->switch_value)); ret = False; @@ -5999,8 +6129,8 @@ void init_samr_q_set_userinfo2(SAMR_Q_SET_USERINFO2 * q_u, switch (switch_value) { case 0x12: - SamOEMhash(ctr->info.id12->lm_pwd, sess_key, 0); - SamOEMhash(ctr->info.id12->nt_pwd, sess_key, 0); + SamOEMhash(ctr->info.id12->lm_pwd, sess_key, 16); + SamOEMhash(ctr->info.id12->nt_pwd, sess_key, 16); dump_data(100, (char *)sess_key, 16); dump_data(100, (char *)ctr->info.id12->lm_pwd, 16); dump_data(100, (char *)ctr->info.id12->nt_pwd, 16); diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c index eb026a1f98..bbda4060f2 100644 --- a/source3/rpc_server/srv_netlog_nt.c +++ b/source3/rpc_server/srv_netlog_nt.c @@ -470,8 +470,8 @@ static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, pi dump_data(100, nt_pwd, 16); #endif - SamOEMhash((uchar *)lm_pwd, key, False); - SamOEMhash((uchar *)nt_pwd, key, False); + SamOEMhash((uchar *)lm_pwd, key, 16); + SamOEMhash((uchar *)nt_pwd, key, 16); #ifdef DEBUG_PASSWORD DEBUG(100,("decrypt of lm owf password:")); diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index 0a82c90a1d..502774e986 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -2259,10 +2259,10 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, uint32 rid) } /******************************************************************* - set_user_info_24 + set_user_info_pw ********************************************************************/ -static BOOL set_user_info_24(SAM_USER_INFO_24 *id24, uint32 rid) +static BOOL set_user_info_pw(char *pass, uint32 rid) { SAM_ACCOUNT *pwd = NULL; uchar nt_hash[16]; @@ -2282,7 +2282,7 @@ static BOOL set_user_info_24(SAM_USER_INFO_24 *id24, uint32 rid) memset(buf, 0, sizeof(buf)); - if (!decode_pw_buffer((char*)id24->pass, buf, 256, &len, nt_hash, lm_hash)) { + if (!decode_pw_buffer(pass, buf, 256, &len, nt_hash, lm_hash)) { pdb_free_sam(pwd); return False; } @@ -2306,7 +2306,7 @@ static BOOL set_user_info_24(SAM_USER_INFO_24 *id24, uint32 rid) memset(buf, 0, sizeof(buf)); - DEBUG(0,("set_user_info_24: pdb_update_sam_account()\n")); + DEBUG(5,("set_user_info_pw: pdb_update_sam_account()\n")); /* update the SAMBA password */ if(!pdb_update_sam_account(pwd, True)) { @@ -2390,13 +2390,39 @@ uint32 _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SET_ break; case 24: - SamOEMhash(ctr->info.id24->pass, sess_key, 1); - if (!set_user_info_24(ctr->info.id24, rid)) + SamOEMhash(ctr->info.id24->pass, sess_key, 516); + + dump_data(100, (char *)ctr->info.id24->pass, 516); + + if (!set_user_info_pw(ctr->info.id24->pass, rid)) return NT_STATUS_ACCESS_DENIED; break; + case 25: +#if 0 + /* + * Currently we don't really know how to unmarshall + * the level 25 struct, and the password encryption + * is different. This is a placeholder for when we + * do understand it. In the meantime just return INVALID + * info level and W2K SP2 drops down to level 23... JRA. + */ + + SamOEMhash(ctr->info.id25->pass, sess_key, 532); + + dump_data(100, (char *)ctr->info.id25->pass, 532); + + if (!set_user_info_pw(ctr->info.id25->pass, rid)) + return NT_STATUS_ACCESS_DENIED; + break; +#endif + return NT_STATUS_INVALID_INFO_CLASS; + case 23: - SamOEMhash(ctr->info.id23->pass, sess_key, 1); + SamOEMhash(ctr->info.id23->pass, sess_key, 516); + + dump_data(100, (char *)ctr->info.id23->pass, 516); + if (!set_user_info_23(ctr->info.id23, rid)) return NT_STATUS_ACCESS_DENIED; break; diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index cf1fca405a..c6f6eca0ba 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -776,7 +776,7 @@ BOOL check_oem_password(char *user, /* * Call the hash function to get the new password. */ - SamOEMhash((uchar *) lmdata, (uchar *)lanman_pw, True); + SamOEMhash((uchar *) lmdata, (uchar *)lanman_pw, 516); /* * The length of the new password is in the last 4 bytes of -- cgit