X-Git-Url: http://git.samba.org/samba.git/?p=kai%2Fsamba.git;a=blobdiff_plain;f=source3%2Frpc_server%2Fsrv_samr_nt.c;h=dc2377b90259d2f3fd80807032e5e9d8c9a5350c;hp=62632d08c5c74f886cc4d126bc027e8b575399d5;hb=931f16f6229f16eac866934f65f567c200d4b111;hpb=edcbb657deea1fd177bd66bd1bc653e15b1b99d9 diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index 62632d08c5c..dc2377b9025 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -5,7 +5,7 @@ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, * Copyright (C) Paul Ashton 1997, * Copyright (C) Marc Jacobsen 1999, - * Copyright (C) Jeremy Allison 2001-2005, + * Copyright (C) Jeremy Allison 2001-2008, * Copyright (C) Jean François Micouleau 1998-2001, * Copyright (C) Jim McDonough 2002, * Copyright (C) Gerald (Jerry) Carter 2003-2004, @@ -38,13 +38,16 @@ #define SAMR_USR_RIGHTS_WRITE_PW \ ( READ_CONTROL_ACCESS | \ - SA_RIGHT_USER_CHANGE_PASSWORD | \ - SA_RIGHT_USER_SET_LOC_COM ) + SAMR_USER_ACCESS_CHANGE_PASSWORD | \ + SAMR_USER_ACCESS_SET_LOC_COM) #define SAMR_USR_RIGHTS_CANT_WRITE_PW \ - ( READ_CONTROL_ACCESS | SA_RIGHT_USER_SET_LOC_COM ) + ( READ_CONTROL_ACCESS | SAMR_USER_ACCESS_SET_LOC_COM ) #define DISP_INFO_CACHE_TIMEOUT 10 +#define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */ +#define MAX_SAM_ENTRIES_W95 50 + typedef struct disp_info { DOM_SID sid; /* identify which domain this is. */ bool builtin_domain; /* Quick flag to check if this is the builtin domain. */ @@ -91,7 +94,7 @@ static const struct generic_mapping usr_generic_mapping = { static const struct generic_mapping usr_nopwchange_generic_mapping = { GENERIC_RIGHTS_USER_READ, GENERIC_RIGHTS_USER_WRITE, - GENERIC_RIGHTS_USER_EXECUTE & ~SA_RIGHT_USER_CHANGE_PASSWORD, + GENERIC_RIGHTS_USER_EXECUTE & ~SAMR_USER_ACCESS_CHANGE_PASSWORD, GENERIC_RIGHTS_USER_ALL_ACCESS}; static const struct generic_mapping grp_generic_mapping = { GENERIC_RIGHTS_GROUP_READ, @@ -113,36 +116,35 @@ static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd { DOM_SID domadmin_sid; SEC_ACE ace[5]; /* at most 5 entries */ - SEC_ACCESS mask; size_t i = 0; SEC_ACL *psa = NULL; /* basic access for Everyone */ - init_sec_access(&mask, map->generic_execute | map->generic_read ); - init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, + map->generic_execute | map->generic_read, 0); /* add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ - init_sec_access(&mask, map->generic_all); - - init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); - init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); + init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); /* Add Full Access for Domain Admins if we are a DC */ if ( IS_DC ) { sid_copy( &domadmin_sid, get_global_sam_sid() ); sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS ); - init_sec_ace(&ace[i++], &domadmin_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &domadmin_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); } /* if we have a sid, give it some special access */ if ( sid ) { - init_sec_access( &mask, sid_access ); - init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, sid_access, 0); } /* create the security descriptor */ @@ -187,8 +189,10 @@ static NTSTATUS access_check_samr_object( SEC_DESC *psd, NT_USER_TOKEN *token, /* check the security descriptor first */ - if ( se_access_check(psd, token, des_access, acc_granted, &status) ) + status = se_access_check(psd, token, des_access, acc_granted); + if (NT_STATUS_IS_OK(status)) { goto done; + } /* give root a free pass */ @@ -248,6 +252,48 @@ static NTSTATUS access_check_samr_function(uint32 acc_granted, uint32 acc_requir return NT_STATUS_ACCESS_DENIED; } +/******************************************************************* + Map any MAXIMUM_ALLOWED_ACCESS request to a valid access set. +********************************************************************/ + +static void map_max_allowed_access(const NT_USER_TOKEN *token, + uint32_t *pacc_requested) +{ + if (!((*pacc_requested) & MAXIMUM_ALLOWED_ACCESS)) { + return; + } + *pacc_requested &= ~MAXIMUM_ALLOWED_ACCESS; + + /* At least try for generic read. */ + *pacc_requested = GENERIC_READ_ACCESS; + + /* root gets anything. */ + if (geteuid() == sec_initial_uid()) { + *pacc_requested |= GENERIC_ALL_ACCESS; + return; + } + + /* Full Access for 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ + + if (is_sid_in_token(token, &global_sid_Builtin_Administrators) || + is_sid_in_token(token, &global_sid_Builtin_Account_Operators)) { + *pacc_requested |= GENERIC_ALL_ACCESS; + return; + } + + /* Full access for DOMAIN\Domain Admins. */ + if ( IS_DC ) { + DOM_SID domadmin_sid; + sid_copy( &domadmin_sid, get_global_sam_sid() ); + sid_append_rid( &domadmin_sid, DOMAIN_GROUP_RID_ADMINS ); + if (is_sid_in_token(token, &domadmin_sid)) { + *pacc_requested |= GENERIC_ALL_ACCESS; + return; + } + } + /* TODO ! Check privileges. */ +} + /******************************************************************* Fetch or create a dispinfo struct. ********************************************************************/ @@ -579,13 +625,14 @@ NTSTATUS _samr_OpenDomain(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(info->acc_granted, - SA_RIGHT_SAM_OPEN_DOMAIN, + SAMR_ACCESS_OPEN_DOMAIN, "_samr_OpenDomain" ); if ( !NT_STATUS_IS_OK(status) ) return status; /*check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->ptok, &des_access); make_samr_object_sd( p->mem_ctx, &psd, &sd_size, &dom_generic_mapping, NULL, 0 ); se_map_generic( &des_access, &dom_generic_mapping ); @@ -593,7 +640,7 @@ NTSTATUS _samr_OpenDomain(pipes_struct *p, se_priv_copy( &se_rights, &se_machine_account ); se_priv_add( &se_rights, &se_add_users ); - status = access_check_samr_object( psd, p->pipe_user.nt_user_token, + status = access_check_samr_object( psd, p->server_info->ptok, &se_rights, GENERIC_RIGHTS_DOMAIN_WRITE, des_access, &acc_granted, "_samr_OpenDomain" ); @@ -627,22 +674,59 @@ NTSTATUS _samr_GetUserPwInfo(pipes_struct *p, struct samr_GetUserPwInfo *r) { struct samr_info *info = NULL; + enum lsa_SidType sid_type; + uint32_t min_password_length = 0; + uint32_t password_properties = 0; + bool ret = false; + NTSTATUS status; + + DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); /* find the policy handle. open a policy on it. */ - if (!find_policy_by_hnd(p, r->in.user_handle, (void **)(void *)&info)) + if (!find_policy_by_hnd(p, r->in.user_handle, (void **)(void *)&info)) { return NT_STATUS_INVALID_HANDLE; + } - if (!sid_check_is_in_our_domain(&info->sid)) + status = access_check_samr_function(info->acc_granted, + SAMR_USER_ACCESS_GET_ATTRIBUTES, + "_samr_GetUserPwInfo" ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_check_is_in_our_domain(&info->sid)) { return NT_STATUS_OBJECT_TYPE_MISMATCH; + } - ZERO_STRUCTP(r->out.info); + become_root(); + ret = lookup_sid(p->mem_ctx, &info->sid, NULL, NULL, &sid_type); + unbecome_root(); + if (ret == false) { + return NT_STATUS_NO_SUCH_USER; + } - DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); + switch (sid_type) { + case SID_NAME_USER: + become_root(); + pdb_get_account_policy(AP_MIN_PASSWORD_LEN, + &min_password_length); + pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, + &password_properties); + unbecome_root(); - /* - * NT sometimes return NT_STATUS_ACCESS_DENIED - * I don't know yet why. - */ + if (lp_check_password_script() && *lp_check_password_script()) { + password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + + break; + default: + break; + } + + r->out.info->min_password_length = min_password_length; + r->out.info->password_properties = password_properties; + + DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); return NT_STATUS_OK; } @@ -710,7 +794,7 @@ NTSTATUS _samr_SetSecurity(pipes_struct *p, if (sid_equal(&pol_sid, &dacl->aces[i].trustee)) { ret = pdb_set_pass_can_change(sampass, (dacl->aces[i].access_mask & - SA_RIGHT_USER_CHANGE_PASSWORD) ? + SAMR_USER_ACCESS_CHANGE_PASSWORD) ? True: False); break; } @@ -722,7 +806,7 @@ NTSTATUS _samr_SetSecurity(pipes_struct *p, } status = access_check_samr_function(acc_granted, - SA_RIGHT_USER_SET_ATTRIBUTES, + SAMR_USER_ACCESS_SET_ATTRIBUTES, "_samr_SetSecurity"); if (NT_STATUS_IS_OK(status)) { become_root(); @@ -789,6 +873,13 @@ NTSTATUS _samr_QuerySecurity(pipes_struct *p, DEBUG(10,("_samr_QuerySecurity: querying security on SID: %s\n", sid_string_dbg(&pol_sid))); + status = access_check_samr_function(acc_granted, + STD_RIGHT_READ_CONTROL_ACCESS, + "_samr_QuerySecurity"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* Check what typ of SID is beeing queried (e.g Domain SID, User SID, Group SID) */ /* To query the security of the SAM it self an invalid SID with S-0-0 is passed to this function */ @@ -902,7 +993,7 @@ NTSTATUS _samr_EnumDomainUsers(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(info->acc_granted, - SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, "_samr_EnumDomainUsers"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -921,6 +1012,7 @@ NTSTATUS _samr_EnumDomainUsers(pipes_struct *p, if (!samr_array) { return NT_STATUS_NO_MEMORY; } + *r->out.sam = samr_array; become_root(); @@ -980,7 +1072,6 @@ NTSTATUS _samr_EnumDomainUsers(pipes_struct *p, samr_array->entries = samr_entries; *r->out.resume_handle = *r->in.resume_handle + num_account; - *r->out.sam = samr_array; *r->out.num_entries = num_account; DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__)); @@ -1041,7 +1132,7 @@ NTSTATUS _samr_EnumDomainGroups(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(info->acc_granted, - SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, "_samr_EnumDomainGroups"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -1117,16 +1208,16 @@ NTSTATUS _samr_EnumDomainAliases(pipes_struct *p, if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info)) return NT_STATUS_INVALID_HANDLE; + DEBUG(5,("_samr_EnumDomainAliases: sid %s\n", + sid_string_dbg(&info->sid))); + status = access_check_samr_function(info->acc_granted, - SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, "_samr_EnumDomainAliases"); if (!NT_STATUS_IS_OK(status)) { return status; } - DEBUG(5,("_samr_EnumDomainAliases: sid %s\n", - sid_string_dbg(&info->sid))); - samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); if (!samr_array) { return NT_STATUS_NO_MEMORY; @@ -1393,6 +1484,18 @@ NTSTATUS _samr_QueryDisplayInfo(pipes_struct *p, if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info)) return NT_STATUS_INVALID_HANDLE; + if (info->builtin_domain) { + DEBUG(5,("_samr_QueryDisplayInfo: Nothing in BUILTIN\n")); + return NT_STATUS_OK; + } + + status = access_check_samr_function(info->acc_granted, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, + "_samr_QueryDisplayInfo"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* * calculate how many entries we will return. * based on @@ -1554,7 +1657,7 @@ NTSTATUS _samr_QueryDisplayInfo(pipes_struct *p, /* calculate the total size */ total_data_size=num_account*struct_size; - if (num_account) { + if (max_entries <= num_account) { status = STATUS_MORE_ENTRIES; } else { status = NT_STATUS_OK; @@ -1642,7 +1745,7 @@ NTSTATUS _samr_QueryAliasInfo(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_ALIAS_LOOKUP_INFO, + SAMR_ALIAS_ACCESS_LOOKUP_INFO, "_samr_QueryAliasInfo"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -1681,66 +1784,6 @@ NTSTATUS _samr_QueryAliasInfo(pipes_struct *p, return NT_STATUS_OK; } -#if 0 -/******************************************************************* - samr_reply_lookup_ids - ********************************************************************/ - - uint32 _samr_lookup_ids(pipes_struct *p, SAMR_Q_LOOKUP_IDS *q_u, SAMR_R_LOOKUP_IDS *r_u) -{ - uint32 rid[MAX_SAM_ENTRIES]; - int num_rids = q_u->num_sids1; - - r_u->status = NT_STATUS_OK; - - DEBUG(5,("_samr_lookup_ids: %d\n", __LINE__)); - - if (num_rids > MAX_SAM_ENTRIES) { - num_rids = MAX_SAM_ENTRIES; - DEBUG(5,("_samr_lookup_ids: truncating entries to %d\n", num_rids)); - } - -#if 0 - int i; - SMB_ASSERT_ARRAY(q_u->uni_user_name, num_rids); - - for (i = 0; i < num_rids && status == 0; i++) - { - struct sam_passwd *sam_pass; - fstring user_name; - - - fstrcpy(user_name, unistrn2(q_u->uni_user_name[i].buffer, - q_u->uni_user_name[i].uni_str_len)); - - /* find the user account */ - become_root(); - sam_pass = get_smb21pwd_entry(user_name, 0); - unbecome_root(); - - if (sam_pass == NULL) - { - status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; - rid[i] = 0; - } - else - { - rid[i] = sam_pass->user_rid; - } - } -#endif - - num_rids = 1; - rid[0] = BUILTIN_ALIAS_RID_USERS; - - init_samr_r_lookup_ids(&r_u, num_rids, rid, NT_STATUS_OK); - - DEBUG(5,("_samr_lookup_ids: %d\n", __LINE__)); - - return r_u->status; -} -#endif - /******************************************************************* _samr_LookupNames ********************************************************************/ @@ -1749,19 +1792,17 @@ NTSTATUS _samr_LookupNames(pipes_struct *p, struct samr_LookupNames *r) { NTSTATUS status; - uint32 rid[MAX_SAM_ENTRIES]; - enum lsa_SidType type[MAX_SAM_ENTRIES]; + uint32 *rid; + enum lsa_SidType *type; int i; int num_rids = r->in.num_names; DOM_SID pol_sid; uint32 acc_granted; struct samr_Ids rids, types; + uint32_t num_mapped = 0; DEBUG(5,("_samr_LookupNames: %d\n", __LINE__)); - ZERO_ARRAY(rid); - ZERO_ARRAY(type); - if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &pol_sid, &acc_granted, NULL)) { return NT_STATUS_OBJECT_TYPE_MISMATCH; } @@ -1778,6 +1819,12 @@ NTSTATUS _samr_LookupNames(pipes_struct *p, DEBUG(5,("_samr_LookupNames: truncating entries to %d\n", num_rids)); } + rid = talloc_array(p->mem_ctx, uint32, num_rids); + NT_STATUS_HAVE_NO_MEMORY(rid); + + type = talloc_array(p->mem_ctx, enum lsa_SidType, num_rids); + NT_STATUS_HAVE_NO_MEMORY(type); + DEBUG(5,("_samr_LookupNames: looking name on SID %s\n", sid_string_dbg(&pol_sid))); @@ -1800,10 +1847,18 @@ NTSTATUS _samr_LookupNames(pipes_struct *p, } if (type[i] != SID_NAME_UNKNOWN) { - status = NT_STATUS_OK; + num_mapped++; } } + if (num_mapped == num_rids) { + status = NT_STATUS_OK; + } else if (num_mapped == 0) { + status = NT_STATUS_NONE_MAPPED; + } else { + status = STATUS_SOME_UNMAPPED; + } + rids.count = num_rids; rids.ids = rid; @@ -2023,6 +2078,13 @@ NTSTATUS _samr_LookupRids(pipes_struct *p, if (!get_lsa_policy_samr_sid(p, r->in.domain_handle, &pol_sid, &acc_granted, NULL)) return NT_STATUS_INVALID_HANDLE; + status = access_check_samr_function(acc_granted, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, + "_samr_LookupRids"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (num_rids > 1000) { DEBUG(0, ("Got asked for %d rids (more than 1000) -- according " "to samba4 idl this is not possible\n", num_rids)); @@ -2101,7 +2163,7 @@ NTSTATUS _samr_OpenUser(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; nt_status = access_check_samr_function(acc_granted, - SA_RIGHT_DOMAIN_OPEN_ACCOUNT, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, "_samr_OpenUser" ); if ( !NT_STATUS_IS_OK(nt_status) ) @@ -2118,13 +2180,15 @@ NTSTATUS _samr_OpenUser(pipes_struct *p, /* check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->ptok, &des_access); + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW); se_map_generic(&des_access, &usr_generic_mapping); se_priv_copy( &se_rights, &se_machine_account ); se_priv_add( &se_rights, &se_add_users ); - nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, + nt_status = access_check_samr_object(psd, p->server_info->ptok, &se_rights, GENERIC_RIGHTS_USER_WRITE, des_access, &acc_granted, "_samr_OpenUser"); @@ -2189,6 +2253,108 @@ static NTSTATUS init_samr_parameters_string(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } +static NTSTATUS get_user_info_5(TALLOC_CTX *mem_ctx, + struct samr_UserInfo5 *r, + DOM_SID *user_sid, + DOM_SID *domain_sid) +{ + struct samu *pw = NULL; + bool ret; + const DOM_SID *sid_user, *sid_group; + uint32_t rid, primary_gid; + NTTIME last_logon, last_logoff, last_password_change, + acct_expiry; + const char *account_name, *full_name, *home_directory, *home_drive, + *logon_script, *profile_path, *description, + *workstations, *comment; + struct samr_LogonHours logon_hours; + + ZERO_STRUCTP(r); + + if (!(pw = samu_new(mem_ctx))) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + ret = pdb_getsampwsid(pw, user_sid); + unbecome_root(); + + if (ret == False) { + DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid))); + TALLOC_FREE(pw); + return NT_STATUS_NO_SUCH_USER; + } + + samr_clear_sam_passwd(pw); + + DEBUG(3,("User:[%s]\n", pdb_get_username(pw))); + + sid_user = pdb_get_user_sid(pw); + + if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { + DEBUG(0, ("get_user_info_5: User %s has SID %s, \nwhich conflicts with " + "the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_user), + sid_string_dbg(domain_sid))); + TALLOC_FREE(pw); + return NT_STATUS_UNSUCCESSFUL; + } + + become_root(); + sid_group = pdb_get_group_sid(pw); + unbecome_root(); + + if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { + DEBUG(0, ("get_user_info_5: User %s has Primary Group SID %s, \n" + "which conflicts with the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_group), + sid_string_dbg(domain_sid))); + TALLOC_FREE(pw); + return NT_STATUS_UNSUCCESSFUL; + } + + unix_to_nt_time(&last_logon, pdb_get_logon_time(pw)); + unix_to_nt_time(&last_logoff, pdb_get_logoff_time(pw)); + unix_to_nt_time(&acct_expiry, pdb_get_kickoff_time(pw)); + unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(pw)); + + account_name = talloc_strdup(mem_ctx, pdb_get_username(pw)); + full_name = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + home_directory = talloc_strdup(mem_ctx, pdb_get_homedir(pw)); + home_drive = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); + logon_script = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); + profile_path = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); + description = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); + workstations = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); + comment = talloc_strdup(mem_ctx, pdb_get_comment(pw)); + + logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); + + init_samr_user_info5(r, + account_name, + full_name, + rid, + primary_gid, + home_directory, + home_drive, + logon_script, + profile_path, + description, + workstations, + last_logon, + last_logoff, + logon_hours, + pdb_get_bad_password_count(pw), + pdb_get_logon_count(pw), + last_password_change, + acct_expiry, + pdb_get_acct_ctrl(pw)); + + TALLOC_FREE(pw); + + return NT_STATUS_OK; +} + /************************************************************************* get_user_info_7. Safe. Only gives out account_name. *************************************************************************/ @@ -2398,7 +2564,7 @@ static NTSTATUS get_user_info_20(TALLOC_CTX *mem_ctx, if (munged_dial) { blob = base64_decode_data_blob(munged_dial); } else { - blob = data_blob_string_const(""); + blob = data_blob_string_const_null(""); } status = init_samr_parameters_string(mem_ctx, &blob, ¶meters); @@ -2507,7 +2673,7 @@ static NTSTATUS get_user_info_21(TALLOC_CTX *mem_ctx, if (munged_dial) { blob = base64_decode_data_blob(munged_dial); } else { - blob = data_blob_string_const(""); + blob = data_blob_string_const_null(""); } status = init_samr_parameters_string(mem_ctx, &blob, ¶meters); @@ -2593,6 +2759,13 @@ NTSTATUS _samr_QueryUserInfo(pipes_struct *p, if (!find_policy_by_hnd(p, r->in.user_handle, (void **)(void *)&info)) return NT_STATUS_INVALID_HANDLE; + status = access_check_samr_function(info->acc_granted, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, + "_samr_QueryUserInfo"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + domain_sid = info->sid; sid_split_rid(&domain_sid, &rid); @@ -2611,6 +2784,12 @@ NTSTATUS _samr_QueryUserInfo(pipes_struct *p, DEBUG(5,("_samr_QueryUserInfo: user info level: %d\n", r->in.level)); switch (r->in.level) { + case 5: + status = get_user_info_5(p->mem_ctx, &user_info->info5, &info->sid, &domain_sid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; case 7: status = get_user_info_7(p->mem_ctx, &user_info->info7, &info->sid); if (!NT_STATUS_IS_OK(status)) { @@ -2663,6 +2842,21 @@ NTSTATUS _samr_QueryUserInfo(pipes_struct *p, return status; } +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_QueryUserInfo2(pipes_struct *p, + struct samr_QueryUserInfo2 *r) +{ + struct samr_QueryUserInfo u; + + u.in.user_handle = r->in.user_handle; + u.in.level = r->in.level; + u.out.info = r->out.info; + + return _samr_QueryUserInfo(p, &u); +} + /******************************************************************* _samr_GetGroupsForUser ********************************************************************/ @@ -2710,7 +2904,7 @@ NTSTATUS _samr_GetGroupsForUser(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; result = access_check_samr_function(acc_granted, - SA_RIGHT_USER_GET_GROUPS, + SAMR_USER_ACCESS_GET_GROUPS, "_samr_GetGroupsForUser"); if (!NT_STATUS_IS_OK(result)) { return result; @@ -2798,14 +2992,11 @@ NTSTATUS _samr_GetGroupsForUser(pipes_struct *p, } /******************************************************************* - samr_QueryDomainInfo_internal + _samr_QueryDomainInfo ********************************************************************/ -static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name, - pipes_struct *p, - struct policy_handle *handle, - uint32_t level, - union samr_DomainInfo **dom_info_ptr) +NTSTATUS _samr_QueryDomainInfo(pipes_struct *p, + struct samr_QueryDomainInfo *r) { NTSTATUS status = NT_STATUS_OK; struct samr_info *info = NULL; @@ -2827,21 +3018,26 @@ static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name, uint32 num_users=0, num_groups=0, num_aliases=0; - DEBUG(5,("%s: %d\n", fn_name, __LINE__)); + DEBUG(5,("_samr_QueryDomainInfo: %d\n", __LINE__)); dom_info = TALLOC_ZERO_P(p->mem_ctx, union samr_DomainInfo); if (!dom_info) { return NT_STATUS_NO_MEMORY; } - *dom_info_ptr = dom_info; - /* find the policy handle. open a policy on it. */ - if (!find_policy_by_hnd(p, handle, (void **)(void *)&info)) { + if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info)) { return NT_STATUS_INVALID_HANDLE; } - switch (level) { + status = access_check_samr_function(info->acc_granted, + SAMR_ACCESS_OPEN_DOMAIN, + "_samr_QueryDomainInfo" ); + + if ( !NT_STATUS_IS_OK(status) ) + return status; + + switch (r->in.level) { case 0x01: become_root(); @@ -2870,6 +3066,10 @@ static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name, unix_to_nt_time_abs(&nt_expire, u_expire); unix_to_nt_time_abs(&nt_min_age, u_min_age); + if (lp_check_password_script() && *lp_check_password_script()) { + password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + init_samr_DomInfo1(&dom_info->info1, (uint16)min_pass_len, (uint16)pass_hist, @@ -2903,18 +3103,18 @@ static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name, if (lp_server_role() == ROLE_DOMAIN_BDC) server_role = ROLE_DOMAIN_BDC; - init_samr_DomInfo2(&dom_info->info2, - nt_logout, - lp_serverstring(), - lp_workgroup(), - global_myname(), - seq_num, - 1, - server_role, - 1, - num_users, - num_groups, - num_aliases); + init_samr_DomGeneralInformation(&dom_info->general, + nt_logout, + lp_serverstring(), + lp_workgroup(), + global_myname(), + seq_num, + DOMAIN_SERVER_ENABLED, + server_role, + 1, + num_users, + num_groups, + num_aliases); break; case 0x03: @@ -2939,8 +3139,8 @@ static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name, break; case 0x04: - init_samr_DomInfo4(&dom_info->info4, - lp_serverstring()); + init_samr_DomOEMInformation(&dom_info->oem, + lp_serverstring()); break; case 0x05: init_samr_DomInfo5(&dom_info->info5, @@ -3013,23 +3213,11 @@ static NTSTATUS samr_QueryDomainInfo_internal(const char *fn_name, return NT_STATUS_INVALID_INFO_CLASS; } - DEBUG(5,("%s: %d\n", fn_name, __LINE__)); - - return status; -} + *r->out.info = dom_info; -/******************************************************************* - _samr_QueryDomainInfo - ********************************************************************/ + DEBUG(5,("_samr_QueryDomainInfo: %d\n", __LINE__)); -NTSTATUS _samr_QueryDomainInfo(pipes_struct *p, - struct samr_QueryDomainInfo *r) -{ - return samr_QueryDomainInfo_internal("_samr_QueryDomainInfo", - p, - r->in.domain_handle, - r->in.level, - r->out.info); + return status; } /* W2k3 seems to use the same check for all 3 objects that can be created via @@ -3098,8 +3286,13 @@ NTSTATUS _samr_CreateUser2(pipes_struct *p, &disp_info)) return NT_STATUS_INVALID_HANDLE; + if (disp_info->builtin_domain) { + DEBUG(5,("_samr_CreateUser2: Refusing user create in BUILTIN\n")); + return NT_STATUS_ACCESS_DENIED; + } + nt_status = access_check_samr_function(acc_granted, - SA_RIGHT_DOMAIN_CREATE_USER, + SAMR_DOMAIN_ACCESS_CREATE_USER, "_samr_CreateUser2"); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; @@ -3128,7 +3321,7 @@ NTSTATUS _samr_CreateUser2(pipes_struct *p, { se_priv_copy( &se_rights, &se_machine_account ); can_add_account = user_has_privileges( - p->pipe_user.nt_user_token, &se_rights ); + p->server_info->ptok, &se_rights ); } /* usrmgr.exe (and net rpc trustdom grant) creates a normal user account for domain trusts and changes the ACB flags later */ @@ -3137,7 +3330,7 @@ NTSTATUS _samr_CreateUser2(pipes_struct *p, { se_priv_copy( &se_rights, &se_add_users ); can_add_account = user_has_privileges( - p->pipe_user.nt_user_token, &se_rights ); + p->server_info->ptok, &se_rights ); } else /* implicit assumption of a BDC or domain trust account here * (we already check the flags earlier) */ @@ -3146,13 +3339,13 @@ NTSTATUS _samr_CreateUser2(pipes_struct *p, /* only Domain Admins can add a BDC or domain trust */ se_priv_copy( &se_rights, &se_priv_none ); can_add_account = nt_token_check_domain_rid( - p->pipe_user.nt_user_token, + p->server_info->ptok, DOMAIN_GROUP_RID_ADMINS ); } } DEBUG(5, ("_samr_CreateUser2: %s can add this account : %s\n", - uidtoname(p->pipe_user.ut.uid), + uidtoname(p->server_info->utok.uid), can_add_account ? "True":"False" )); /********** BEGIN Admin BLOCK **********/ @@ -3177,11 +3370,13 @@ NTSTATUS _samr_CreateUser2(pipes_struct *p, sid_compose(&sid, get_global_sam_sid(), *r->out.rid); + map_max_allowed_access(p->server_info->ptok, &des_access); + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW); se_map_generic(&des_access, &usr_generic_mapping); - nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, + nt_status = access_check_samr_object(psd, p->server_info->ptok, &se_rights, GENERIC_RIGHTS_USER_WRITE, des_access, &acc_granted, "_samr_CreateUser2"); @@ -3211,6 +3406,26 @@ NTSTATUS _samr_CreateUser2(pipes_struct *p, return NT_STATUS_OK; } +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_CreateUser(pipes_struct *p, + struct samr_CreateUser *r) +{ + struct samr_CreateUser2 c; + uint32_t access_granted; + + c.in.domain_handle = r->in.domain_handle; + c.in.account_name = r->in.account_name; + c.in.acct_flags = ACB_NORMAL; + c.in.access_mask = r->in.access_mask; + c.out.user_handle = r->out.user_handle; + c.out.access_granted = &access_granted; + c.out.rid = r->out.rid; + + return _samr_CreateUser2(p, &c); +} + /******************************************************************* _samr_Connect ********************************************************************/ @@ -3234,17 +3449,14 @@ NTSTATUS _samr_Connect(pipes_struct *p, if ((info = get_samr_info_by_sid(NULL)) == NULL) return NT_STATUS_NO_MEMORY; - /* don't give away the farm but this is probably ok. The SA_RIGHT_SAM_ENUM_DOMAINS + /* don't give away the farm but this is probably ok. The SAMR_ACCESS_ENUM_DOMAINS was observed from a win98 client trying to enumerate users (when configured user level access control on shares) --jerry */ - if (des_access == MAXIMUM_ALLOWED_ACCESS) { - /* Map to max possible knowing we're filtered below. */ - des_access = GENERIC_ALL_ACCESS; - } + map_max_allowed_access(p->server_info->ptok, &des_access); se_map_generic( &des_access, &sam_generic_mapping ); - info->acc_granted = des_access & (SA_RIGHT_SAM_ENUM_DOMAINS|SA_RIGHT_SAM_OPEN_DOMAIN); + info->acc_granted = des_access & (SAMR_ACCESS_ENUM_DOMAINS|SAMR_ACCESS_OPEN_DOMAIN); /* get a (unique) handle. open a policy on it. */ if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info)) @@ -3266,22 +3478,36 @@ NTSTATUS _samr_Connect2(pipes_struct *p, uint32 des_access = r->in.access_mask; NTSTATUS nt_status; size_t sd_size; + const char *fn = "_samr_Connect2"; + switch (p->hdr_req.opnum) { + case NDR_SAMR_CONNECT2: + fn = "_samr_Connect2"; + break; + case NDR_SAMR_CONNECT4: + fn = "_samr_Connect4"; + break; + case NDR_SAMR_CONNECT5: + fn = "_samr_Connect5"; + break; + } - DEBUG(5,("_samr_Connect2: %d\n", __LINE__)); + DEBUG(5,("%s: %d\n", fn, __LINE__)); /* Access check */ if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to _samr_Connect2\n")); + DEBUG(3, ("access denied to %s\n", fn)); return NT_STATUS_ACCESS_DENIED; } + map_max_allowed_access(p->server_info->ptok, &des_access); + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0); se_map_generic(&des_access, &sam_generic_mapping); - nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, - NULL, 0, des_access, &acc_granted, "_samr_Connect2"); + nt_status = access_check_samr_object(psd, p->server_info->ptok, + NULL, 0, des_access, &acc_granted, fn); if ( !NT_STATUS_IS_OK(nt_status) ) return nt_status; @@ -3297,7 +3523,7 @@ NTSTATUS _samr_Connect2(pipes_struct *p, if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info)) return NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(5,("_samr_Connect2: %d\n", __LINE__)); + DEBUG(5,("%s: %d\n", fn, __LINE__)); return nt_status; } @@ -3309,46 +3535,13 @@ NTSTATUS _samr_Connect2(pipes_struct *p, NTSTATUS _samr_Connect4(pipes_struct *p, struct samr_Connect4 *r) { - struct samr_info *info = NULL; - SEC_DESC *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - NTSTATUS nt_status; - size_t sd_size; - - - DEBUG(5,("_samr_Connect4: %d\n", __LINE__)); - - /* Access check */ - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to samr_Connect4\n")); - return NT_STATUS_ACCESS_DENIED; - } - - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0); - se_map_generic(&des_access, &sam_generic_mapping); - - nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, - NULL, 0, des_access, &acc_granted, "_samr_Connect4"); - - if ( !NT_STATUS_IS_OK(nt_status) ) - return nt_status; - - /* associate the user's SID and access granted with the new handle. */ - if ((info = get_samr_info_by_sid(NULL)) == NULL) - return NT_STATUS_NO_MEMORY; - - info->acc_granted = acc_granted; - info->status = r->in.access_mask; /* ??? */ - - /* get a (unique) handle. open a policy on it. */ - if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + struct samr_Connect2 c; - DEBUG(5,("_samr_Connect4: %d\n", __LINE__)); + c.in.system_name = r->in.system_name; + c.in.access_mask = r->in.access_mask; + c.out.connect_handle = r->out.connect_handle; - return NT_STATUS_OK; + return _samr_Connect2(p, &c); } /******************************************************************* @@ -3358,48 +3551,22 @@ NTSTATUS _samr_Connect4(pipes_struct *p, NTSTATUS _samr_Connect5(pipes_struct *p, struct samr_Connect5 *r) { - struct samr_info *info = NULL; - SEC_DESC *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - NTSTATUS nt_status; - size_t sd_size; + NTSTATUS status; + struct samr_Connect2 c; struct samr_ConnectInfo1 info1; - DEBUG(5,("_samr_Connect5: %d\n", __LINE__)); + info1.client_version = SAMR_CONNECT_AFTER_W2K; + info1.unknown2 = 0; - /* Access check */ + c.in.system_name = r->in.system_name; + c.in.access_mask = r->in.access_mask; + c.out.connect_handle = r->out.connect_handle; - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to samr_Connect5\n")); - return NT_STATUS_ACCESS_DENIED; + status = _samr_Connect2(p, &c); + if (!NT_STATUS_IS_OK(status)) { + return status; } - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0); - se_map_generic(&des_access, &sam_generic_mapping); - - nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, - NULL, 0, des_access, &acc_granted, "_samr_Connect5"); - - if ( !NT_STATUS_IS_OK(nt_status) ) - return nt_status; - - /* associate the user's SID and access granted with the new handle. */ - if ((info = get_samr_info_by_sid(NULL)) == NULL) - return NT_STATUS_NO_MEMORY; - - info->acc_granted = acc_granted; - info->status = r->in.access_mask; /* ??? */ - - /* get a (unique) handle. open a policy on it. */ - if (!create_policy_hnd(p, r->out.connect_handle, free_samr_info, (void *)info)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - - DEBUG(5,("_samr_Connect5: %d\n", __LINE__)); - - info1.client_version = SAMR_CONNECT_AFTER_W2K; - info1.unknown2 = 0; - *r->out.level_out = 1; r->out.info_out->info1 = info1; @@ -3421,17 +3588,20 @@ NTSTATUS _samr_LookupDomain(pipes_struct *p, if (!find_policy_by_hnd(p, r->in.connect_handle, (void**)(void *)&info)) return NT_STATUS_INVALID_HANDLE; - /* win9x user manager likes to use SA_RIGHT_SAM_ENUM_DOMAINS here. + /* win9x user manager likes to use SAMR_ACCESS_ENUM_DOMAINS here. Reverted that change so we will work with RAS servers again */ status = access_check_samr_function(info->acc_granted, - SA_RIGHT_SAM_OPEN_DOMAIN, + SAMR_ACCESS_OPEN_DOMAIN, "_samr_LookupDomain"); if (!NT_STATUS_IS_OK(status)) { return status; } domain_name = r->in.domain_name->string; + if (!domain_name) { + return NT_STATUS_INVALID_PARAMETER; + } sid = TALLOC_ZERO_P(p->mem_ctx, struct dom_sid2); if (!sid) { @@ -3471,7 +3641,7 @@ NTSTATUS _samr_EnumDomains(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(info->acc_granted, - SA_RIGHT_SAM_ENUM_DOMAINS, + SAMR_ACCESS_ENUM_DOMAINS, "_samr_EnumDomains"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -3529,7 +3699,7 @@ NTSTATUS _samr_OpenAlias(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_DOMAIN_OPEN_ACCOUNT, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, "_samr_OpenAlias"); if ( !NT_STATUS_IS_OK(status) ) @@ -3542,13 +3712,15 @@ NTSTATUS _samr_OpenAlias(pipes_struct *p, /*check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->ptok, &des_access); + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &ali_generic_mapping, NULL, 0); se_map_generic(&des_access,&ali_generic_mapping); se_priv_copy( &se_rights, &se_add_users ); - status = access_check_samr_object(psd, p->pipe_user.nt_user_token, + status = access_check_samr_object(psd, p->server_info->ptok, &se_rights, GENERIC_RIGHTS_ALIAS_WRITE, des_access, &acc_granted, "_samr_OpenAlias"); @@ -3602,13 +3774,11 @@ static NTSTATUS set_user_info_7(TALLOC_CTX *mem_ctx, if (id7 == NULL) { DEBUG(5, ("set_user_info_7: NULL id7\n")); - TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } if (!id7->account_name.string) { DEBUG(5, ("set_user_info_7: failed to get new username\n")); - TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } @@ -3628,7 +3798,6 @@ static NTSTATUS set_user_info_7(TALLOC_CTX *mem_ctx, rc = pdb_rename_sam_account(pwd, id7->account_name.string); - TALLOC_FREE(pwd); return rc; } @@ -3641,23 +3810,18 @@ static bool set_user_info_16(struct samr_UserInfo16 *id16, { if (id16 == NULL) { DEBUG(5, ("set_user_info_16: NULL id16\n")); - TALLOC_FREE(pwd); return False; } /* FIX ME: check if the value is really changed --metze */ if (!pdb_set_acct_ctrl(pwd, id16->acct_flags, PDB_CHANGED)) { - TALLOC_FREE(pwd); return False; } if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return False; } - TALLOC_FREE(pwd); - return True; } @@ -3670,29 +3834,23 @@ static bool set_user_info_18(struct samr_UserInfo18 *id18, { if (id18 == NULL) { DEBUG(2, ("set_user_info_18: id18 is NULL\n")); - TALLOC_FREE(pwd); return False; } if (!pdb_set_lanman_passwd (pwd, id18->lm_pwd.hash, PDB_CHANGED)) { - TALLOC_FREE(pwd); return False; } if (!pdb_set_nt_passwd (pwd, id18->nt_pwd.hash, PDB_CHANGED)) { - TALLOC_FREE(pwd); return False; } if (!pdb_set_pass_last_set_time (pwd, time(NULL), PDB_CHANGED)) { - TALLOC_FREE(pwd); return False; } if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return False; } - TALLOC_FREE(pwd); return True; } @@ -3712,12 +3870,9 @@ static bool set_user_info_20(struct samr_UserInfo20 *id20, /* write the change out */ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return False; } - TALLOC_FREE(pwd); - return True; } @@ -3736,6 +3891,14 @@ static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, return NT_STATUS_INVALID_PARAMETER; } + if (id21->fields_present == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (id21->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + return NT_STATUS_ACCESS_DENIED; + } + /* we need to separately check for an account rename first */ if (id21->account_name.string && @@ -3761,7 +3924,6 @@ static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("set_user_info_21: failed to rename account: %s\n", nt_errstr(status))); - TALLOC_FREE(pwd); return status; } @@ -3792,12 +3954,9 @@ static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, /* write the change out */ if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return status; } - TALLOC_FREE(pwd); - return NT_STATUS_OK; } @@ -3819,6 +3978,15 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, return NT_STATUS_INVALID_PARAMETER; } + if (id23->info.fields_present == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (id23->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + return NT_STATUS_ACCESS_DENIED; + } + + DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n", pdb_get_username(pwd))); @@ -3829,12 +3997,10 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, &plaintext_buf, &len, STR_UNICODE)) { - TALLOC_FREE(pwd); - return NT_STATUS_INVALID_PARAMETER; + return NT_STATUS_WRONG_PASSWORD; } if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { - TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } @@ -3851,7 +4017,6 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, struct passwd *passwd; if (pdb_get_username(pwd) == NULL) { DEBUG(1, ("chgpasswd: User without name???\n")); - TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } @@ -3861,7 +4026,6 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, } if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { - TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } TALLOC_FREE(passwd); @@ -3873,17 +4037,13 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) && (!NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx, pwd)))) { - TALLOC_FREE(pwd); return status; } if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return status; } - TALLOC_FREE(pwd); - return NT_STATUS_OK; } @@ -3914,12 +4074,10 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd, &plaintext_buf, &len, STR_UNICODE)) { - TALLOC_FREE(pwd); return False; } if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { - TALLOC_FREE(pwd); return False; } @@ -3935,7 +4093,6 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd, if (pdb_get_username(pwd) == NULL) { DEBUG(1, ("chgpasswd: User without name???\n")); - TALLOC_FREE(pwd); return False; } @@ -3945,7 +4102,6 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd, } if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { - TALLOC_FREE(pwd); return False; } TALLOC_FREE(passwd); @@ -3973,12 +4129,9 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd, /* update the SAMBA password */ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return False; } - TALLOC_FREE(pwd); - return True; } @@ -3997,11 +4150,18 @@ static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx, return NT_STATUS_INVALID_PARAMETER; } + if (id25->info.fields_present == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (id25->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + return NT_STATUS_ACCESS_DENIED; + } + copy_id25_to_sam_passwd(pwd, id25); /* write the change out */ if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { - TALLOC_FREE(pwd); return status; } @@ -4020,27 +4180,22 @@ static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx, } } - /* WARNING: No TALLOC_FREE(pwd), we are about to set the password - * hereafter! */ - return NT_STATUS_OK; } /******************************************************************* - samr_SetUserInfo_internal + samr_SetUserInfo ********************************************************************/ -static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, - pipes_struct *p, - struct policy_handle *user_handle, - uint16_t level, - union samr_UserInfo *info) +NTSTATUS _samr_SetUserInfo(pipes_struct *p, + struct samr_SetUserInfo *r) { NTSTATUS status; struct samu *pwd = NULL; DOM_SID sid; - POLICY_HND *pol = user_handle; - uint16_t switch_value = level; + POLICY_HND *pol = r->in.user_handle; + union samr_UserInfo *info = r->in.info; + uint16_t switch_value = r->in.level; uint32_t acc_granted; uint32_t acc_required; bool ret; @@ -4048,7 +4203,7 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, uint32_t acb_info; DISP_INFO *disp_info = NULL; - DEBUG(5,("%s: %d\n", fn_name, __LINE__)); + DEBUG(5,("_samr_SetUserInfo: %d\n", __LINE__)); /* find the policy handle. open a policy on it. */ if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted, &disp_info)) { @@ -4056,9 +4211,9 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, } /* This is tricky. A WinXP domain join sets - (SA_RIGHT_USER_SET_PASSWORD|SA_RIGHT_USER_SET_ATTRIBUTES|SA_RIGHT_USER_ACCT_FLAGS_EXPIRY) + (SAMR_USER_ACCESS_SET_PASSWORD|SAMR_USER_ACCESS_SET_ATTRIBUTES|SAMR_USER_ACCESS_GET_ATTRIBUTES) The MMC lusrmgr plugin includes these perms and more in the SamrOpenUser(). But the - standard Win32 API calls just ask for SA_RIGHT_USER_SET_PASSWORD in the SamrOpenUser(). + standard Win32 API calls just ask for SAMR_USER_ACCESS_SET_PASSWORD in the SamrOpenUser(). This should be enough for levels 18, 24, 25,& 26. Info level 23 can set more so we'll use the set from the WinXP join as the basis. */ @@ -4067,27 +4222,27 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, case 24: case 25: case 26: - acc_required = SA_RIGHT_USER_SET_PASSWORD; + acc_required = SAMR_USER_ACCESS_SET_PASSWORD; break; default: - acc_required = SA_RIGHT_USER_SET_PASSWORD | - SA_RIGHT_USER_SET_ATTRIBUTES | - SA_RIGHT_USER_ACCT_FLAGS_EXPIRY; + acc_required = SAMR_USER_ACCESS_SET_PASSWORD | + SAMR_USER_ACCESS_SET_ATTRIBUTES | + SAMR_USER_ACCESS_GET_ATTRIBUTES; break; } status = access_check_samr_function(acc_granted, acc_required, - fn_name); + "_samr_SetUserInfo"); if (!NT_STATUS_IS_OK(status)) { return status; } - DEBUG(5, ("%s: sid:%s, level:%d\n", - fn_name, sid_string_dbg(&sid), switch_value)); + DEBUG(5, ("_samr_SetUserInfo: sid:%s, level:%d\n", + sid_string_dbg(&sid), switch_value)); if (info == NULL) { - DEBUG(5, ("%s: NULL info level\n", fn_name)); + DEBUG(5, ("_samr_SetUserInfo: NULL info level\n")); return NT_STATUS_INVALID_INFO_CLASS; } @@ -4109,21 +4264,20 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, acb_info = pdb_get_acct_ctrl(pwd); if (acb_info & ACB_WSTRUST) - has_enough_rights = user_has_privileges(p->pipe_user.nt_user_token, + has_enough_rights = user_has_privileges(p->server_info->ptok, &se_machine_account); else if (acb_info & ACB_NORMAL) - has_enough_rights = user_has_privileges(p->pipe_user.nt_user_token, + has_enough_rights = user_has_privileges(p->server_info->ptok, &se_add_users); else if (acb_info & (ACB_SVRTRUST|ACB_DOMTRUST)) { if (lp_enable_privileges()) { - has_enough_rights = nt_token_check_domain_rid(p->pipe_user.nt_user_token, + has_enough_rights = nt_token_check_domain_rid(p->server_info->ptok, DOMAIN_GROUP_RID_ADMINS); } } - DEBUG(5, ("%s: %s does%s possess sufficient rights\n", - fn_name, - uidtoname(p->pipe_user.ut.uid), + DEBUG(5, ("_samr_SetUserInfo: %s does%s possess sufficient rights\n", + uidtoname(p->server_info->utok.uid), has_enough_rights ? "" : " not")); /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ @@ -4166,11 +4320,11 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, break; case 23: - if (!p->session_key.length) { + if (!p->server_info->user_session_key.length) { status = NT_STATUS_NO_USER_SESSION_KEY; } SamOEMhashBlob(info->info23.password.data, 516, - &p->session_key); + &p->server_info->user_session_key); dump_data(100, info->info23.password.data, 516); @@ -4179,27 +4333,28 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, break; case 24: - if (!p->session_key.length) { + if (!p->server_info->user_session_key.length) { status = NT_STATUS_NO_USER_SESSION_KEY; } SamOEMhashBlob(info->info24.password.data, 516, - &p->session_key); + &p->server_info->user_session_key); dump_data(100, info->info24.password.data, 516); if (!set_user_info_pw(info->info24.password.data, pwd, switch_value)) { - status = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_WRONG_PASSWORD; } break; case 25: - if (!p->session_key.length) { + if (!p->server_info->user_session_key.length) { status = NT_STATUS_NO_USER_SESSION_KEY; } - encode_or_decode_arc4_passwd_buffer(info->info25.password.data, - &p->session_key); + encode_or_decode_arc4_passwd_buffer( + info->info25.password.data, + &p->server_info->user_session_key); dump_data(100, info->info25.password.data, 532); @@ -4210,22 +4365,23 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, } if (!set_user_info_pw(info->info25.password.data, pwd, switch_value)) { - status = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_WRONG_PASSWORD; } break; case 26: - if (!p->session_key.length) { + if (!p->server_info->user_session_key.length) { status = NT_STATUS_NO_USER_SESSION_KEY; } - encode_or_decode_arc4_passwd_buffer(info->info26.password.data, - &p->session_key); + encode_or_decode_arc4_passwd_buffer( + info->info26.password.data, + &p->server_info->user_session_key); dump_data(100, info->info26.password.data, 516); if (!set_user_info_pw(info->info26.password.data, pwd, switch_value)) { - status = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_WRONG_PASSWORD; } break; @@ -4235,6 +4391,8 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, done: + TALLOC_FREE(pwd); + if (has_enough_rights) { unbecome_root(); } @@ -4248,20 +4406,6 @@ static NTSTATUS samr_SetUserInfo_internal(const char *fn_name, return status; } -/******************************************************************* - _samr_SetUserInfo - ********************************************************************/ - -NTSTATUS _samr_SetUserInfo(pipes_struct *p, - struct samr_SetUserInfo *r) -{ - return samr_SetUserInfo_internal("_samr_SetUserInfo", - p, - r->in.user_handle, - r->in.level, - r->in.info); -} - /******************************************************************* _samr_SetUserInfo2 ********************************************************************/ @@ -4269,11 +4413,13 @@ NTSTATUS _samr_SetUserInfo(pipes_struct *p, NTSTATUS _samr_SetUserInfo2(pipes_struct *p, struct samr_SetUserInfo2 *r) { - return samr_SetUserInfo_internal("_samr_SetUserInfo2", - p, - r->in.user_handle, - r->in.level, - r->in.info); + struct samr_SetUserInfo q; + + q.in.user_handle = r->in.user_handle; + q.in.level = r->in.level; + q.in.info = r->in.info; + + return _samr_SetUserInfo(p, &q); } /********************************************************************* @@ -4300,10 +4446,10 @@ NTSTATUS _samr_GetAliasMembership(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; ntstatus1 = access_check_samr_function(info->acc_granted, - SA_RIGHT_DOMAIN_LOOKUP_ALIAS_BY_MEM, + SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS, "_samr_GetAliasMembership"); ntstatus2 = access_check_samr_function(info->acc_granted, - SA_RIGHT_DOMAIN_OPEN_ACCOUNT, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, "_samr_GetAliasMembership"); if (!NT_STATUS_IS_OK(ntstatus1) || !NT_STATUS_IS_OK(ntstatus2)) { @@ -4370,7 +4516,7 @@ NTSTATUS _samr_GetMembersInAlias(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_ALIAS_GET_MEMBERS, + SAMR_ALIAS_ACCESS_GET_MEMBERS, "_samr_GetMembersInAlias"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4438,7 +4584,7 @@ NTSTATUS _samr_QueryGroupMember(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_GROUP_GET_MEMBERS, + SAMR_GROUP_ACCESS_GET_MEMBERS, "_samr_QueryGroupMember"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4502,7 +4648,7 @@ NTSTATUS _samr_AddAliasMember(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_ALIAS_ADD_MEMBER, + SAMR_ALIAS_ACCESS_ADD_MEMBER, "_samr_AddAliasMember"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4511,7 +4657,7 @@ NTSTATUS _samr_AddAliasMember(pipes_struct *p, DEBUG(10, ("sid is %s\n", sid_string_dbg(&alias_sid))); se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -4551,7 +4697,7 @@ NTSTATUS _samr_DeleteAliasMember(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_ALIAS_REMOVE_MEMBER, + SAMR_ALIAS_ACCESS_REMOVE_MEMBER, "_samr_DeleteAliasMember"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4561,7 +4707,7 @@ NTSTATUS _samr_DeleteAliasMember(pipes_struct *p, sid_string_dbg(&alias_sid))); se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -4602,7 +4748,7 @@ NTSTATUS _samr_AddGroupMember(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_GROUP_ADD_MEMBER, + SAMR_GROUP_ACCESS_ADD_MEMBER, "_samr_AddGroupMember"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4616,7 +4762,7 @@ NTSTATUS _samr_AddGroupMember(pipes_struct *p, } se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -4662,7 +4808,7 @@ NTSTATUS _samr_DeleteGroupMember(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_GROUP_REMOVE_MEMBER, + SAMR_GROUP_ACCESS_REMOVE_MEMBER, "_samr_DeleteGroupMember"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4674,7 +4820,7 @@ NTSTATUS _samr_DeleteGroupMember(pipes_struct *p, } se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -4745,9 +4891,9 @@ NTSTATUS _samr_DeleteUser(pipes_struct *p, /* For machine accounts it's the SeMachineAccountPrivilege that counts. */ if ( acb_info & ACB_WSTRUST ) { - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_machine_account ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_machine_account ); } else { - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_add_users ); } /******** BEGIN SeAddUsers BLOCK *********/ @@ -4776,6 +4922,8 @@ NTSTATUS _samr_DeleteUser(pipes_struct *p, if (!close_policy_hnd(p, r->in.user_handle)) return NT_STATUS_OBJECT_NAME_INVALID; + ZERO_STRUCTP(r->out.user_handle); + force_flush_samr_cache(disp_info); return NT_STATUS_OK; @@ -4817,7 +4965,7 @@ NTSTATUS _samr_DeleteDomainGroup(pipes_struct *p, } se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -4892,7 +5040,7 @@ NTSTATUS _samr_DeleteDomAlias(pipes_struct *p, DEBUG(10, ("lookup on Local SID\n")); se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -4941,7 +5089,7 @@ NTSTATUS _samr_CreateDomainGroup(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_DOMAIN_CREATE_GROUP, + SAMR_DOMAIN_ACCESS_CREATE_GROUP, "_samr_CreateDomainGroup"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4961,7 +5109,7 @@ NTSTATUS _samr_CreateDomainGroup(pipes_struct *p, } se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -5023,7 +5171,7 @@ NTSTATUS _samr_CreateDomAlias(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; result = access_check_samr_function(acc_granted, - SA_RIGHT_DOMAIN_CREATE_ALIAS, + SAMR_DOMAIN_ACCESS_CREATE_ALIAS, "_samr_CreateDomAlias"); if (!NT_STATUS_IS_OK(result)) { return result; @@ -5035,7 +5183,7 @@ NTSTATUS _samr_CreateDomAlias(pipes_struct *p, name = r->in.alias_name->string; se_priv_copy( &se_rights, &se_add_users ); - can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); + can_add_accounts = user_has_privileges( p->server_info->ptok, &se_rights ); result = can_create(p->mem_ctx, name); if (!NT_STATUS_IS_OK(result)) { @@ -5115,7 +5263,7 @@ NTSTATUS _samr_QueryGroupInfo(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_GROUP_LOOKUP_INFO, + SAMR_GROUP_ACCESS_LOOKUP_INFO, "_samr_QueryGroupInfo"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -5221,7 +5369,7 @@ NTSTATUS _samr_SetGroupInfo(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_GROUP_SET_INFO, + SAMR_GROUP_ACCESS_SET_INFO, "_samr_SetGroupInfo"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -5237,6 +5385,9 @@ NTSTATUS _samr_SetGroupInfo(pipes_struct *p, case 1: fstrcpy(map.comment, r->in.info->all.description.string); break; + case 2: + /* group rename is not supported yet */ + return NT_STATUS_NOT_SUPPORTED; case 4: fstrcpy(map.comment, r->in.info->description.string); break; @@ -5244,7 +5395,7 @@ NTSTATUS _samr_SetGroupInfo(pipes_struct *p, return NT_STATUS_INVALID_INFO_CLASS; } - can_mod_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users ); + can_mod_accounts = user_has_privileges( p->server_info->ptok, &se_add_users ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -5283,7 +5434,7 @@ NTSTATUS _samr_SetAliasInfo(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_ALIAS_SET_INFO, + SAMR_ALIAS_ACCESS_SET_INFO, "_samr_SetAliasInfo"); if (!NT_STATUS_IS_OK(status)) { return status; @@ -5346,7 +5497,7 @@ NTSTATUS _samr_SetAliasInfo(pipes_struct *p, return NT_STATUS_INVALID_INFO_CLASS; } - can_mod_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users ); + can_mod_accounts = user_has_privileges( p->server_info->ptok, &se_add_users ); /******** BEGIN SeAddUsers BLOCK *********/ @@ -5373,6 +5524,9 @@ NTSTATUS _samr_SetAliasInfo(pipes_struct *p, NTSTATUS _samr_GetDomPwInfo(pipes_struct *p, struct samr_GetDomPwInfo *r) { + uint32_t min_password_length = 0; + uint32_t password_properties = 0; + /* Perform access check. Since this rpc does not require a policy handle it will not be caught by the access checks on SAMR_CONNECT or SAMR_CONNECT_ANON. */ @@ -5382,8 +5536,19 @@ NTSTATUS _samr_GetDomPwInfo(pipes_struct *p, return NT_STATUS_ACCESS_DENIED; } - /* Actually, returning zeros here works quite well :-). */ - ZERO_STRUCTP(r->out.info); + become_root(); + pdb_get_account_policy(AP_MIN_PASSWORD_LEN, + &min_password_length); + pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, + &password_properties); + unbecome_root(); + + if (lp_check_password_script() && *lp_check_password_script()) { + password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + + r->out.info->min_password_length = min_password_length; + r->out.info->password_properties = password_properties; return NT_STATUS_OK; } @@ -5413,19 +5578,21 @@ NTSTATUS _samr_OpenGroup(pipes_struct *p, return NT_STATUS_INVALID_HANDLE; status = access_check_samr_function(acc_granted, - SA_RIGHT_DOMAIN_OPEN_ACCOUNT, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, "_samr_OpenGroup"); if ( !NT_STATUS_IS_OK(status) ) return status; /*check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->ptok, &des_access); + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &grp_generic_mapping, NULL, 0); se_map_generic(&des_access,&grp_generic_mapping); se_priv_copy( &se_rights, &se_add_users ); - status = access_check_samr_object(psd, p->pipe_user.nt_user_token, + status = access_check_samr_object(psd, p->server_info->ptok, &se_rights, GENERIC_RIGHTS_GROUP_WRITE, des_access, &acc_granted, "_samr_OpenGroup"); @@ -5532,11 +5699,14 @@ NTSTATUS _samr_RemoveMemberFromForeignDomain(pipes_struct *p, NTSTATUS _samr_QueryDomainInfo2(pipes_struct *p, struct samr_QueryDomainInfo2 *r) { - return samr_QueryDomainInfo_internal("_samr_QueryDomainInfo2", - p, - r->in.domain_handle, - r->in.level, - r->out.info); + struct samr_QueryDomainInfo q; + + q.in.domain_handle = r->in.domain_handle; + q.in.level = r->in.level; + + q.out.info = r->out.info; + + return _samr_QueryDomainInfo(p, &q); } /******************************************************************* @@ -5546,16 +5716,32 @@ NTSTATUS _samr_QueryDomainInfo2(pipes_struct *p, NTSTATUS _samr_SetDomainInfo(pipes_struct *p, struct samr_SetDomainInfo *r) { + struct samr_info *info = NULL; time_t u_expire, u_min_age; time_t u_logout; time_t u_lock_duration, u_reset_time; + NTSTATUS result; DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__)); /* find the policy handle. open a policy on it. */ - if (!find_policy_by_hnd(p, r->in.domain_handle, NULL)) + if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info)) return NT_STATUS_INVALID_HANDLE; + /* We do have different access bits for info + * levels here, but we're really just looking for + * GENERIC_RIGHTS_DOMAIN_WRITE access. Unfortunately + * this maps to different specific bits. So + * assume if we have SAMR_DOMAIN_ACCESS_SET_INFO_1 + * set we are ok. */ + + result = access_check_samr_function(info->acc_granted, + SAMR_DOMAIN_ACCESS_SET_INFO_1, + "_samr_SetDomainInfo"); + + if (!NT_STATUS_IS_OK(result)) + return result; + DEBUG(5,("_samr_SetDomainInfo: level: %d\n", r->in.level)); switch (r->in.level) { @@ -5601,50 +5787,157 @@ NTSTATUS _samr_SetDomainInfo(pipes_struct *p, } /**************************************************************** + _samr_GetDisplayEnumerationIndex ****************************************************************/ -NTSTATUS _samr_Shutdown(pipes_struct *p, - struct samr_Shutdown *r) +NTSTATUS _samr_GetDisplayEnumerationIndex(pipes_struct *p, + struct samr_GetDisplayEnumerationIndex *r) { - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} + struct samr_info *info = NULL; + uint32_t max_entries = (uint32_t) -1; + uint32_t enum_context = 0; + int i; + uint32_t num_account = 0; + struct samr_displayentry *entries = NULL; + NTSTATUS status; -/**************************************************************** -****************************************************************/ + DEBUG(5,("_samr_GetDisplayEnumerationIndex: %d\n", __LINE__)); -NTSTATUS _samr_CreateUser(pipes_struct *p, - struct samr_CreateUser *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} + /* find the policy handle. open a policy on it. */ + if (!find_policy_by_hnd(p, r->in.domain_handle, (void **)(void *)&info)) { + return NT_STATUS_INVALID_HANDLE; + } -/**************************************************************** -****************************************************************/ + status = access_check_samr_function(info->acc_granted, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, + "_samr_GetDisplayEnumerationIndex"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } -NTSTATUS _samr_SetMemberAttributesOfGroup(pipes_struct *p, - struct samr_SetMemberAttributesOfGroup *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; + if ((r->in.level < 1) || (r->in.level > 3)) { + DEBUG(0,("_samr_GetDisplayEnumerationIndex: " + "Unknown info level (%u)\n", + r->in.level)); + return NT_STATUS_INVALID_INFO_CLASS; + } + + become_root(); + + /* The following done as ROOT. Don't return without unbecome_root(). */ + + switch (r->in.level) { + case 1: + if (info->disp_info->users == NULL) { + info->disp_info->users = pdb_search_users(ACB_NORMAL); + if (info->disp_info->users == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "starting user enumeration at index %u\n", + (unsigned int)enum_context)); + } else { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "using cached user enumeration at index %u\n", + (unsigned int)enum_context)); + } + num_account = pdb_search_entries(info->disp_info->users, + enum_context, max_entries, + &entries); + break; + case 2: + if (info->disp_info->machines == NULL) { + info->disp_info->machines = + pdb_search_users(ACB_WSTRUST|ACB_SVRTRUST); + if (info->disp_info->machines == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "starting machine enumeration at index %u\n", + (unsigned int)enum_context)); + } else { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "using cached machine enumeration at index %u\n", + (unsigned int)enum_context)); + } + num_account = pdb_search_entries(info->disp_info->machines, + enum_context, max_entries, + &entries); + break; + case 3: + if (info->disp_info->groups == NULL) { + info->disp_info->groups = pdb_search_groups(); + if (info->disp_info->groups == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "starting group enumeration at index %u\n", + (unsigned int)enum_context)); + } else { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "using cached group enumeration at index %u\n", + (unsigned int)enum_context)); + } + num_account = pdb_search_entries(info->disp_info->groups, + enum_context, max_entries, + &entries); + break; + default: + unbecome_root(); + smb_panic("info class changed"); + break; + } + + unbecome_root(); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT); + + DEBUG(10,("_samr_GetDisplayEnumerationIndex: looking for :%s\n", + r->in.name->string)); + + for (i=0; iin.name->string)) { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "found %s at idx %d\n", + r->in.name->string, i)); + *r->out.idx = i; + return NT_STATUS_OK; + } + } + + /* assuming account_name lives at the very end */ + *r->out.idx = num_account; + + return NT_STATUS_NO_MORE_ENTRIES; } /**************************************************************** + _samr_GetDisplayEnumerationIndex2 ****************************************************************/ -NTSTATUS _samr_ChangePasswordUser(pipes_struct *p, - struct samr_ChangePasswordUser *r) +NTSTATUS _samr_GetDisplayEnumerationIndex2(pipes_struct *p, + struct samr_GetDisplayEnumerationIndex2 *r) { - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; + struct samr_GetDisplayEnumerationIndex q; + + q.in.domain_handle = r->in.domain_handle; + q.in.level = r->in.level; + q.in.name = r->in.name; + + q.out.idx = r->out.idx; + + return _samr_GetDisplayEnumerationIndex(p, &q); } /**************************************************************** ****************************************************************/ -NTSTATUS _samr_GetDisplayEnumerationIndex(pipes_struct *p, - struct samr_GetDisplayEnumerationIndex *r) +NTSTATUS _samr_Shutdown(pipes_struct *p, + struct samr_Shutdown *r) { p->rng_fault_state = true; return NT_STATUS_NOT_IMPLEMENTED; @@ -5653,8 +5946,8 @@ NTSTATUS _samr_GetDisplayEnumerationIndex(pipes_struct *p, /**************************************************************** ****************************************************************/ -NTSTATUS _samr_TestPrivateFunctionsDomain(pipes_struct *p, - struct samr_TestPrivateFunctionsDomain *r) +NTSTATUS _samr_SetMemberAttributesOfGroup(pipes_struct *p, + struct samr_SetMemberAttributesOfGroup *r) { p->rng_fault_state = true; return NT_STATUS_NOT_IMPLEMENTED; @@ -5663,8 +5956,8 @@ NTSTATUS _samr_TestPrivateFunctionsDomain(pipes_struct *p, /**************************************************************** ****************************************************************/ -NTSTATUS _samr_TestPrivateFunctionsUser(pipes_struct *p, - struct samr_TestPrivateFunctionsUser *r) +NTSTATUS _samr_ChangePasswordUser(pipes_struct *p, + struct samr_ChangePasswordUser *r) { p->rng_fault_state = true; return NT_STATUS_NOT_IMPLEMENTED; @@ -5673,8 +5966,8 @@ NTSTATUS _samr_TestPrivateFunctionsUser(pipes_struct *p, /**************************************************************** ****************************************************************/ -NTSTATUS _samr_QueryUserInfo2(pipes_struct *p, - struct samr_QueryUserInfo2 *r) +NTSTATUS _samr_TestPrivateFunctionsDomain(pipes_struct *p, + struct samr_TestPrivateFunctionsDomain *r) { p->rng_fault_state = true; return NT_STATUS_NOT_IMPLEMENTED; @@ -5683,8 +5976,8 @@ NTSTATUS _samr_QueryUserInfo2(pipes_struct *p, /**************************************************************** ****************************************************************/ -NTSTATUS _samr_GetDisplayEnumerationIndex2(pipes_struct *p, - struct samr_GetDisplayEnumerationIndex2 *r) +NTSTATUS _samr_TestPrivateFunctionsUser(pipes_struct *p, + struct samr_TestPrivateFunctionsUser *r) { p->rng_fault_state = true; return NT_STATUS_NOT_IMPLEMENTED;