mirror of
https://github.com/samba-team/samba.git
synced 2025-11-23 20:23:50 +03:00
r16060: This is one of the more dirty patches I've put in lately. Parse enough of
SetUserInfo level 25 to survive the join method XP uses if the user did not exist before. For good taste this contains way too much cut&paste, but for a real fix there is just not enough time. Up to 3.0.22 we completely ignored that a full level 21 is being sent together with level 25, but we got away with that because on creation we did not set the "disabled" flag on the workstation account. Now we correctly follow W2k3 in this regard, and we end up with a disabled workstation after join. Man, I hate rpc_parse/. The correct fix would be to import PIDL generated samr parsing, but this is would probably be a bit too much for .23... Thanks to Tom Bork for finding this one. Volker
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
aafd4db457
commit
5a37aba105
@@ -260,8 +260,9 @@ typedef struct sam_user_info_25
|
||||
uint32 group_rid; /* Primary Group ID */
|
||||
|
||||
uint32 acb_info; /* account info (ACB_xxxx bit-mask) */
|
||||
uint32 fields_present;
|
||||
|
||||
uint32 unknown_6[6];
|
||||
uint32 unknown_5[5];
|
||||
|
||||
uint8 pass[532];
|
||||
|
||||
|
||||
@@ -6041,8 +6041,10 @@ static BOOL sam_io_user_info25(const char *desc, SAM_USER_INFO_25 * usr, prs_str
|
||||
return False;
|
||||
if(!prs_uint32("acb_info ", ps, depth, &usr->acb_info))
|
||||
return False;
|
||||
if(!prs_uint32("fields_present ", ps, depth, &usr->fields_present))
|
||||
return False;
|
||||
|
||||
if(!prs_uint32s(False, "unknown_6 ", ps, depth, usr->unknown_6, 6))
|
||||
if(!prs_uint32s(False, "unknown_5 ", ps, depth, usr->unknown_5, 5))
|
||||
return False;
|
||||
|
||||
if(!prs_uint8s(False, "password ", ps, depth, usr->pass, sizeof(usr->pass)))
|
||||
|
||||
@@ -3298,6 +3298,52 @@ static BOOL set_user_info_pw(uint8 *pass, struct samu *pwd)
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
set_user_info_25
|
||||
********************************************************************/
|
||||
|
||||
static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx, SAM_USER_INFO_25 *id25,
|
||||
struct samu *pwd)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
if (id25 == NULL) {
|
||||
DEBUG(5, ("set_user_info_25: NULL id25\n"));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
copy_id25_to_sam_passwd(pwd, id25);
|
||||
|
||||
/*
|
||||
* The funny part about the previous two calls is
|
||||
* that pwd still has the password hashes from the
|
||||
* passdb entry. These have not been updated from
|
||||
* id21. I don't know if they need to be set. --jerry
|
||||
*/
|
||||
|
||||
if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) {
|
||||
status = pdb_set_unix_primary_group(mem_ctx, pwd);
|
||||
if ( !NT_STATUS_IS_OK(status) ) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't worry about writing out the user account since the
|
||||
primary group SID is generated solely from the user's Unix
|
||||
primary group. */
|
||||
|
||||
/* write the change out */
|
||||
if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) {
|
||||
TALLOC_FREE(pwd);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* WARNING: No TALLOC_FREE(pwd), we are about to set the password
|
||||
* hereafter! */
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
samr_reply_set_userinfo
|
||||
********************************************************************/
|
||||
@@ -3401,6 +3447,11 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
|
||||
|
||||
dump_data(100, (char *)ctr->info.id25->pass, 532);
|
||||
|
||||
r_u->status = set_user_info_25(p->mem_ctx,
|
||||
ctr->info.id25, pwd);
|
||||
if (!NT_STATUS_IS_OK(r_u->status)) {
|
||||
goto done;
|
||||
}
|
||||
if (!set_user_info_pw(ctr->info.id25->pass, pwd))
|
||||
r_u->status = NT_STATUS_ACCESS_DENIED;
|
||||
break;
|
||||
@@ -3433,6 +3484,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
|
||||
r_u->status = NT_STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if ( has_enough_rights )
|
||||
unbecome_root();
|
||||
|
||||
@@ -549,3 +549,192 @@ void copy_id23_to_sam_passwd(struct samu *to, SAM_USER_INFO_23 *from)
|
||||
|
||||
DEBUG(10,("INFO_23 PADDING_2: %02X\n",from->padding2));
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Copies a SAM_USER_INFO_25 to a struct samu
|
||||
**************************************************************/
|
||||
|
||||
void copy_id25_to_sam_passwd(struct samu *to, SAM_USER_INFO_25 *from)
|
||||
{
|
||||
time_t unix_time, stored_time;
|
||||
const char *old_string, *new_string;
|
||||
DATA_BLOB mung;
|
||||
|
||||
if (from == NULL || to == NULL)
|
||||
return;
|
||||
|
||||
if (from->fields_present & ACCT_LAST_LOGON) {
|
||||
unix_time=nt_time_to_unix(&from->logon_time);
|
||||
stored_time = pdb_get_logon_time(to);
|
||||
DEBUG(10,("INFO_25 LOGON_TIME: %lu -> %lu\n",(long unsigned int)stored_time, (long unsigned int)unix_time));
|
||||
if (stored_time != unix_time)
|
||||
pdb_set_logon_time(to, unix_time, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_LAST_LOGOFF) {
|
||||
unix_time=nt_time_to_unix(&from->logoff_time);
|
||||
stored_time = pdb_get_logoff_time(to);
|
||||
DEBUG(10,("INFO_25 LOGOFF_TIME: %lu -> %lu\n",(long unsigned int)stored_time, (long unsigned int)unix_time));
|
||||
if (stored_time != unix_time)
|
||||
pdb_set_logoff_time(to, unix_time, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_EXPIRY) {
|
||||
unix_time=nt_time_to_unix(&from->kickoff_time);
|
||||
stored_time = pdb_get_kickoff_time(to);
|
||||
DEBUG(10,("INFO_25 KICKOFF_TIME: %lu -> %lu\n",(long unsigned int)stored_time, (long unsigned int)unix_time));
|
||||
if (stored_time != unix_time)
|
||||
pdb_set_kickoff_time(to, unix_time , PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_ALLOW_PWD_CHANGE) {
|
||||
unix_time=nt_time_to_unix(&from->pass_can_change_time);
|
||||
stored_time = pdb_get_pass_can_change_time(to);
|
||||
DEBUG(10,("INFO_25 PASS_CAN_CH: %lu -> %lu\n",(long unsigned int)stored_time, (long unsigned int)unix_time));
|
||||
if (stored_time != unix_time)
|
||||
pdb_set_pass_can_change_time(to, unix_time, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_LAST_PWD_CHANGE) {
|
||||
unix_time=nt_time_to_unix(&from->pass_last_set_time);
|
||||
stored_time = pdb_get_pass_last_set_time(to);
|
||||
DEBUG(10,("INFO_25 PASS_LAST_SET: %lu -> %lu\n",(long unsigned int)stored_time, (long unsigned int)unix_time));
|
||||
if (stored_time != unix_time)
|
||||
pdb_set_pass_last_set_time(to, unix_time, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_FORCE_PWD_CHANGE) {
|
||||
unix_time=nt_time_to_unix(&from->pass_must_change_time);
|
||||
stored_time=pdb_get_pass_must_change_time(to);
|
||||
DEBUG(10,("INFO_25 PASS_MUST_CH: %lu -> %lu\n",(long unsigned int)stored_time, (long unsigned int)unix_time));
|
||||
if (stored_time != unix_time)
|
||||
pdb_set_pass_must_change_time(to, unix_time, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_USERNAME) &&
|
||||
(from->hdr_user_name.buffer)) {
|
||||
old_string = pdb_get_username(to);
|
||||
new_string = unistr2_static(&from->uni_user_name);
|
||||
DEBUG(10,("INFO_25 UNI_USER_NAME: %s -> %s\n", old_string, new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_username(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_FULL_NAME) &&
|
||||
(from->hdr_full_name.buffer)) {
|
||||
old_string = pdb_get_fullname(to);
|
||||
new_string = unistr2_static(&from->uni_full_name);
|
||||
DEBUG(10,("INFO_25 UNI_FULL_NAME: %s -> %s\n",old_string, new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_fullname(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_HOME_DIR) &&
|
||||
(from->hdr_home_dir.buffer)) {
|
||||
old_string = pdb_get_homedir(to);
|
||||
new_string = unistr2_static(&from->uni_home_dir);
|
||||
DEBUG(10,("INFO_25 UNI_HOME_DIR: %s -> %s\n",old_string,new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_homedir(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_HOME_DRIVE) &&
|
||||
(from->hdr_dir_drive.buffer)) {
|
||||
old_string = pdb_get_dir_drive(to);
|
||||
new_string = unistr2_static(&from->uni_dir_drive);
|
||||
DEBUG(10,("INFO_25 UNI_DIR_DRIVE: %s -> %s\n",old_string,new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_dir_drive(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_LOGON_SCRIPT) &&
|
||||
(from->hdr_logon_script.buffer)) {
|
||||
old_string = pdb_get_logon_script(to);
|
||||
new_string = unistr2_static(&from->uni_logon_script);
|
||||
DEBUG(10,("INFO_25 UNI_LOGON_SCRIPT: %s -> %s\n",old_string,new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_logon_script(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_PROFILE) &&
|
||||
(from->hdr_profile_path.buffer)) {
|
||||
old_string = pdb_get_profile_path(to);
|
||||
new_string = unistr2_static(&from->uni_profile_path);
|
||||
DEBUG(10,("INFO_25 UNI_PROFILE_PATH: %s -> %s\n",old_string, new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_profile_path(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_DESCRIPTION) &&
|
||||
(from->hdr_acct_desc.buffer)) {
|
||||
old_string = pdb_get_acct_desc(to);
|
||||
new_string = unistr2_static(&from->uni_acct_desc);
|
||||
DEBUG(10,("INFO_25 UNI_ACCT_DESC: %s -> %s\n",old_string,new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_acct_desc(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_WORKSTATIONS) &&
|
||||
(from->hdr_workstations.buffer)) {
|
||||
old_string = pdb_get_workstations(to);
|
||||
new_string = unistr2_static(&from->uni_workstations);
|
||||
DEBUG(10,("INFO_25 UNI_WORKSTATIONS: %s -> %s\n",old_string, new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_workstations(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
/* is this right? */
|
||||
if ((from->fields_present & ACCT_ADMIN_DESC) &&
|
||||
(from->hdr_unknown_str.buffer)) {
|
||||
old_string = pdb_get_unknown_str(to);
|
||||
new_string = unistr2_static(&from->uni_unknown_str);
|
||||
DEBUG(10,("INFO_25 UNI_UNKNOWN_STR: %s -> %s\n",old_string, new_string));
|
||||
if (STRING_CHANGED)
|
||||
pdb_set_unknown_str(to , new_string, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if ((from->fields_present & ACCT_CALLBACK) &&
|
||||
(from->hdr_munged_dial.buffer)) {
|
||||
char *newstr;
|
||||
old_string = pdb_get_munged_dial(to);
|
||||
mung.length = from->hdr_munged_dial.uni_str_len;
|
||||
mung.data = (uint8 *) from->uni_munged_dial.buffer;
|
||||
newstr = (mung.length == 0) ?
|
||||
NULL : base64_encode_data_blob(mung);
|
||||
DEBUG(10,("INFO_25 UNI_MUNGED_DIAL: %s -> %s\n",old_string, newstr));
|
||||
if (STRING_CHANGED_NC(old_string,newstr))
|
||||
pdb_set_munged_dial(to , newstr, PDB_CHANGED);
|
||||
|
||||
SAFE_FREE(newstr);
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_RID) {
|
||||
if (from->user_rid == 0) {
|
||||
DEBUG(10, ("INFO_25: Asked to set User RID to 0 !? Skipping change!\n"));
|
||||
} else if (from->user_rid != pdb_get_user_rid(to)) {
|
||||
DEBUG(10,("INFO_25 USER_RID: %u -> %u NOT UPDATED!\n",pdb_get_user_rid(to),from->user_rid));
|
||||
}
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_PRIMARY_GID) {
|
||||
if (from->group_rid == 0) {
|
||||
DEBUG(10, ("INFO_25: Asked to set Group RID to 0 !? Skipping change!\n"));
|
||||
} else if (from->group_rid != pdb_get_group_rid(to)) {
|
||||
DEBUG(10,("INFO_25 GROUP_RID: %u -> %u\n",pdb_get_group_rid(to),from->group_rid));
|
||||
pdb_set_group_sid_from_rid(to, from->group_rid, PDB_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
if (from->fields_present & ACCT_FLAGS) {
|
||||
DEBUG(10,("INFO_25 ACCT_CTRL: %08X -> %08X\n",pdb_get_acct_ctrl(to),from->acb_info));
|
||||
if (from->acb_info != pdb_get_acct_ctrl(to)) {
|
||||
if (!(from->acb_info & ACB_AUTOLOCK) && (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) {
|
||||
/* We're unlocking a previously locked user. Reset bad password counts.
|
||||
Patch from Jianliang Lu. <Jianliang.Lu@getronics.com> */
|
||||
pdb_set_bad_password_count(to, 0, PDB_CHANGED);
|
||||
pdb_set_bad_password_time(to, 0, PDB_CHANGED);
|
||||
}
|
||||
pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user