* 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 <jmcd@us.ibm.com> 2002,
* Copyright (C) Gerald (Jerry) Carter 2003-2004,
* Copyright (C) Simo Sorce 2003.
* Copyright (C) Volker Lendecke 2005.
+ * Copyright (C) Guenther Deschner 2008.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#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. */
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,
{
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 */
/* 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 */
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.
********************************************************************/
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 );
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" );
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;
}
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;
}
}
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();
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 */
return NT_STATUS_OK;
}
+#define MAX_SAM_ENTRIES MAX_SAM_ENTRIES_W2K
+
/*******************************************************************
_samr_EnumDomainUsers
********************************************************************/
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;
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;
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;
for (i = 0; i < num_entries ; i++) {
- init_lsa_AsciiString(&r->entries[i].account_name,
- entries[i].account_name);
+ init_lsa_AsciiStringLarge(&r->entries[i].account_name,
+ entries[i].account_name);
r->entries[i].idx = start_idx+i+1;
}
for (i = 0; i < num_entries ; i++) {
- init_lsa_AsciiString(&r->entries[i].account_name,
- entries[i].account_name);
+ init_lsa_AsciiStringLarge(&r->entries[i].account_name,
+ entries[i].account_name);
r->entries[i].idx = start_idx+i+1;
}
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
/* 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;
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;
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
********************************************************************/
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;
}
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)));
}
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;
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));
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) )
/* 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");
return NT_STATUS_OK;
}
+/*************************************************************************
+ *************************************************************************/
+
+static NTSTATUS init_samr_parameters_string(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct lsa_BinaryString **_r)
+{
+ struct lsa_BinaryString *r;
+
+ if (!blob || !_r) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ r = TALLOC_ZERO_P(mem_ctx, struct lsa_BinaryString);
+ if (!r) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->array = TALLOC_ZERO_ARRAY(mem_ctx, uint16_t, blob->length/2);
+ if (!r->array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcpy(r->array, blob->data, blob->length);
+ r->size = blob->length;
+ r->length = blob->length;
+
+ if (!r->array) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *_r = r;
+
+ 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.
*************************************************************************/
struct samu *sampass=NULL;
bool ret;
const char *munged_dial = NULL;
- const char *munged_dial_decoded = NULL;
DATA_BLOB blob;
+ NTSTATUS status;
+ struct lsa_BinaryString *parameters = NULL;
ZERO_STRUCTP(r);
samr_clear_sam_passwd(sampass);
- DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+ DEBUG(3,("User:[%s] has [%s] (length: %d)\n", pdb_get_username(sampass),
+ munged_dial, (int)strlen(munged_dial)));
if (munged_dial) {
blob = base64_decode_data_blob(munged_dial);
- munged_dial_decoded = talloc_strndup(mem_ctx,
- (const char *)blob.data,
- blob.length);
- data_blob_free(&blob);
- if (!munged_dial_decoded) {
- TALLOC_FREE(sampass);
- return NT_STATUS_NO_MEMORY;
- }
+ } else {
+ blob = data_blob_string_const_null("");
}
-#if 0
- init_unistr2_from_datablob(&usr->uni_munged_dial, &blob);
- init_uni_hdr(&usr->hdr_munged_dial, &usr->uni_munged_dial);
+ status = init_samr_parameters_string(mem_ctx, &blob, ¶meters);
data_blob_free(&blob);
-#endif
- init_samr_user_info20(r, munged_dial_decoded);
-
TALLOC_FREE(sampass);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ init_samr_user_info20(r, parameters);
return NT_STATUS_OK;
}
DOM_SID *user_sid,
DOM_SID *domain_sid)
{
+ NTSTATUS status;
struct samu *pw = NULL;
bool ret;
const DOM_SID *sid_user, *sid_group;
uint8_t password_expired;
const char *account_name, *full_name, *home_directory, *home_drive,
*logon_script, *profile_path, *description,
- *workstations, *comment, *parameters;
+ *workstations, *comment;
struct samr_LogonHours logon_hours;
+ struct lsa_BinaryString *parameters = NULL;
const char *munged_dial = NULL;
DATA_BLOB blob;
munged_dial = pdb_get_munged_dial(pw);
if (munged_dial) {
blob = base64_decode_data_blob(munged_dial);
- parameters = talloc_strndup(mem_ctx, (const char *)blob.data, blob.length);
- data_blob_free(&blob);
- if (!parameters) {
- TALLOC_FREE(pw);
- return NT_STATUS_NO_MEMORY;
- }
+ } else {
+ blob = data_blob_string_const_null("");
}
+ status = init_samr_parameters_string(mem_ctx, &blob, ¶meters);
+ data_blob_free(&blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(pw);
+ return status;
+ }
account_name = talloc_strdup(mem_ctx, pdb_get_username(pw));
full_name = talloc_strdup(mem_ctx, pdb_get_fullname(pw));
-- Volker
*/
-#if 0
- init_unistr2_from_datablob(&usr->uni_munged_dial, &munged_dial_blob);
- init_uni_hdr(&usr->hdr_munged_dial, &usr->uni_munged_dial);
- data_blob_free(&munged_dial_blob);
-#endif
#endif
init_samr_user_info21(r,
logon_hours,
pdb_get_bad_password_count(pw),
pdb_get_logon_count(pw),
- 0, //country_code,
- 0, //code_page,
- 0, //nt_password_set,
- 0, //lm_password_set,
+ 0, /* country_code */
+ 0, /* code_page */
+ 0, /* nt_password_set */
+ 0, /* lm_password_set */
password_expired);
TALLOC_FREE(pw);
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);
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)) {
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
********************************************************************/
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;
}
/*******************************************************************
- 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;
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();
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,
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,
+ 1,
+ server_role,
+ 1,
+ num_users,
+ num_groups,
+ num_aliases);
break;
case 0x03:
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,
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
&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;
{
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 */
{
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) */
/* 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 **********/
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");
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
********************************************************************/
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))
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,
+ nt_status = access_check_samr_object(psd, p->server_info->ptok,
NULL, 0, des_access, &acc_granted, "_samr_Connect2");
if ( !NT_STATUS_IS_OK(nt_status) )
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,
+ nt_status = access_check_samr_object(psd, p->server_info->ptok,
NULL, 0, des_access, &acc_granted, "_samr_Connect4");
if ( !NT_STATUS_IS_OK(nt_status) )
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,
+ nt_status = access_check_samr_object(psd, p->server_info->ptok,
NULL, 0, des_access, &acc_granted, "_samr_Connect5");
if ( !NT_STATUS_IS_OK(nt_status) )
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) {
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;
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) )
/*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");
return NT_STATUS_INVALID_PARAMETER;
}
+ if (id21->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
/* we need to separately check for an account rename first */
if (id21->account_name.string &&
return NT_STATUS_INVALID_PARAMETER;
}
+ if (id23->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+
DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n",
pdb_get_username(pwd)));
&len,
STR_UNICODE)) {
TALLOC_FREE(pwd);
- return NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_WRONG_PASSWORD;
}
if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) {
set_user_info_pw
********************************************************************/
-static bool set_user_info_pw(uint8 *pass, struct samu *pwd)
+static bool set_user_info_pw(uint8 *pass, struct samu *pwd,
+ int level)
{
uint32 len = 0;
char *plaintext_buf = NULL;
memset(plaintext_buf, '\0', strlen(plaintext_buf));
- /* restore last set time as this is an admin change, not a user pw change */
- pdb_set_pass_last_set_time (pwd, last_set_time, last_set_state);
+ /*
+ * A level 25 change does reset the pwdlastset field, a level 24
+ * change does not. I know this is probably not the full story, but
+ * it is needed to make XP join LDAP correctly, without it the later
+ * auth2 check can fail with PWD_MUST_CHANGE.
+ */
+ if (level != 25) {
+ /*
+ * restore last set time as this is an admin change, not a
+ * user pw change
+ */
+ pdb_set_pass_last_set_time (pwd, last_set_time,
+ last_set_state);
+ }
DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n"));
return NT_STATUS_INVALID_PARAMETER;
}
+ if (id25->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
copy_id25_to_sam_passwd(pwd, id25);
/* write the change out */
}
/*******************************************************************
- 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;
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)) {
}
/* 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. */
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;
}
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 ================ */
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);
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)) {
- status = NT_STATUS_ACCESS_DENIED;
+ if (!set_user_info_pw(info->info24.password.data, pwd,
+ switch_value)) {
+ 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);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
- if (!set_user_info_pw(info->info25.password.data, pwd)) {
- status = NT_STATUS_ACCESS_DENIED;
+ if (!set_user_info_pw(info->info25.password.data, pwd,
+ switch_value)) {
+ 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)) {
- status = NT_STATUS_ACCESS_DENIED;
+ if (!set_user_info_pw(info->info26.password.data, pwd,
+ switch_value)) {
+ status = NT_STATUS_WRONG_PASSWORD;
}
break;
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
********************************************************************/
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);
}
/*********************************************************************
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)) {
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;
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;
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;
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 *********/
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;
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 *********/
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;
}
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 *********/
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;
}
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 *********/
/* 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 *********/
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;
}
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 *********/
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 *********/
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;
}
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 *********/
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;
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)) {
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;
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;
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;
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 *********/
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;
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 *********/
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. */
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;
}
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");
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);
}
/*******************************************************************
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) {
}
/****************************************************************
+ _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; i<num_account; i++) {
+ if (strequal(entries[i].account_name, r->in.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;
/****************************************************************
****************************************************************/
-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;
/****************************************************************
****************************************************************/
-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;
/****************************************************************
****************************************************************/
-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;
/****************************************************************
****************************************************************/
-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;