( READ_CONTROL_ACCESS | \
SA_RIGHT_USER_CHANGE_PASSWORD | \
SA_RIGHT_USER_SET_LOC_COM )
+#define SAMR_USR_RIGHTS_CANT_WRITE_PW \
+ ( READ_CONTROL_ACCESS | SA_RIGHT_USER_SET_LOC_COM )
#define DISP_INFO_CACHE_TIMEOUT 10
typedef struct disp_info {
- struct disp_info *next, *prev;
- TALLOC_CTX *mem_ctx;
DOM_SID sid; /* identify which domain this is. */
BOOL builtin_domain; /* Quick flag to check if this is the builtin domain. */
struct pdb_search *users; /* querydispinfo 1 and 4 */
/* We keep a static list of these by SID as modern clients close down
all resources between each request in a complete enumeration. */
-static DISP_INFO *disp_info_list;
-
struct samr_info {
/* for use by the \PIPE\samr policy */
DOM_SID sid;
GENERIC_RIGHTS_USER_WRITE,
GENERIC_RIGHTS_USER_EXECUTE,
GENERIC_RIGHTS_USER_ALL_ACCESS};
+static 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_ALL_ACCESS};
static struct generic_mapping grp_generic_mapping = {
GENERIC_RIGHTS_GROUP_READ,
GENERIC_RIGHTS_GROUP_WRITE,
Fetch or create a dispinfo struct.
********************************************************************/
-static DISP_INFO *get_samr_dispinfo_by_sid(DOM_SID *psid, const char *sid_str)
+static DISP_INFO *get_samr_dispinfo_by_sid(DOM_SID *psid)
{
- TALLOC_CTX *mem_ctx;
- DISP_INFO *dpi;
+ /*
+ * We do a static cache for DISP_INFO's here. Explanation can be found
+ * in Jeremy's checkin message to r11793:
+ *
+ * Fix the SAMR cache so it works across completely insane
+ * client behaviour (ie.:
+ * open pipe/open SAMR handle/enumerate 0 - 1024
+ * close SAMR handle, close pipe.
+ * open pipe/open SAMR handle/enumerate 1024 - 2048...
+ * close SAMR handle, close pipe.
+ * And on ad-nausium. Amazing.... probably object-oriented
+ * client side programming in action yet again.
+ * This change should *massively* improve performance when
+ * enumerating users from an LDAP database.
+ * Jeremy.
+ *
+ * "Our" and the builtin domain are the only ones where we ever
+ * enumerate stuff, so just cache 2 entries.
+ */
+
+ static struct disp_info builtin_dispinfo;
+ static struct disp_info domain_dispinfo;
/* There are two cases to consider here:
1) The SID is a domain SID and we look for an equality match, or
2) This is an account SID and so we return the DISP_INFO* for our
domain */
- if ( psid && sid_check_is_in_our_domain( psid ) ) {
- DEBUG(10,("get_samr_dispinfo_by_sid: Replacing %s with our domain SID\n",
- sid_str));
- psid = get_global_sam_sid();
- }
-
- for (dpi = disp_info_list; dpi; dpi = dpi->next) {
- if (sid_equal(psid, &dpi->sid)) {
- return dpi;
- }
- }
-
- /* This struct is never free'd - I'm using talloc so we
- can get a list out of smbd using smbcontrol. There will
- be one of these per SID we're authorative for. JRA. */
-
- mem_ctx = talloc_init("DISP_INFO for domain sid %s", sid_str);
-
- if ((dpi = TALLOC_ZERO_P(mem_ctx, DISP_INFO)) == NULL)
+ if (psid == NULL) {
return NULL;
+ }
- dpi->mem_ctx = mem_ctx;
+ if (sid_check_is_builtin(psid) || sid_check_is_in_builtin(psid)) {
+ /*
+ * Necessary only once, but it does not really hurt.
+ */
+ sid_copy(&builtin_dispinfo.sid, &global_sid_Builtin);
- if (psid) {
- sid_copy( &dpi->sid, psid);
- dpi->builtin_domain = sid_check_is_builtin(psid);
- } else {
- dpi->builtin_domain = False;
+ return &builtin_dispinfo;
}
+
+ if (sid_check_is_domain(psid) || sid_check_is_in_our_domain(psid)) {
+ /*
+ * Necessary only once, but it does not really hurt.
+ */
+ sid_copy(&domain_dispinfo.sid, get_global_sam_sid());
- DLIST_ADD(disp_info_list, dpi);
+ return &domain_dispinfo;
+ }
- return dpi;
+ return NULL;
}
/*******************************************************************
}
info->mem_ctx = mem_ctx;
- info->disp_info = get_samr_dispinfo_by_sid(psid, sid_str);
-
- if (!info->disp_info) {
- talloc_destroy(mem_ctx);
- return NULL;
- }
+ info->disp_info = get_samr_dispinfo_by_sid(psid);
return info;
}
pdb_set_nt_passwd(sam_pass, NULL, PDB_DEFAULT);
}
-static uint32 count_sam_users(struct disp_info *info, uint16 acct_flags)
+static uint32 count_sam_users(struct disp_info *info, uint32 acct_flags)
{
struct samr_displayentry *entry;
return r_u->status;
}
-/*******************************************************************
- _samr_set_sec_obj
- ********************************************************************/
-
-NTSTATUS _samr_set_sec_obj(pipes_struct *p, SAMR_Q_SET_SEC_OBJ *q_u, SAMR_R_SET_SEC_OBJ *r_u)
-{
- DEBUG(0,("_samr_set_sec_obj: Not yet implemented!\n"));
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
/*******************************************************************
********************************************************************/
return True;
}
+/*******************************************************************
+ _samr_set_sec_obj
+ ********************************************************************/
+
+NTSTATUS _samr_set_sec_obj(pipes_struct *p, SAMR_Q_SET_SEC_OBJ *q_u, SAMR_R_SET_SEC_OBJ *r_u)
+{
+ DOM_SID pol_sid;
+ uint32 acc_granted, i;
+ SEC_ACL *dacl;
+ BOOL ret;
+ struct samu *sampass=NULL;
+ NTSTATUS status;
+
+ r_u->status = NT_STATUS_OK;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &pol_sid, &acc_granted, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!(sampass = samu_new( p->mem_ctx))) {
+ DEBUG(0,("No memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get the user record */
+ become_root();
+ ret = pdb_getsampwsid(sampass, &pol_sid);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(4, ("User %s not found\n", sid_string_static(&pol_sid)));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ dacl = q_u->buf->sd->dacl;
+ for (i=0; i < dacl->num_aces; i++) {
+ 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) ?
+ True: False);
+ break;
+ }
+ }
+
+ if (!ret) {
+ TALLOC_FREE(sampass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = pdb_update_sam_account(sampass);
+
+ TALLOC_FREE(sampass);
+
+ return status;
+}
+
+/*******************************************************************
+ build correct perms based on policies and password times for _samr_query_sec_obj
+*******************************************************************/
+static BOOL check_change_pw_access(TALLOC_CTX *mem_ctx, DOM_SID *user_sid)
+{
+ struct samu *sampass=NULL;
+ BOOL ret;
+
+ if ( !(sampass = samu_new( mem_ctx )) ) {
+ DEBUG(0,("No memory!\n"));
+ return False;
+ }
+
+ become_root();
+ ret = pdb_getsampwsid(sampass, user_sid);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(4,("User %s not found\n", sid_string_static(user_sid)));
+ TALLOC_FREE(sampass);
+ return False;
+ }
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+
+ if (pdb_get_pass_can_change(sampass)) {
+ TALLOC_FREE(sampass);
+ return True;
+ }
+ TALLOC_FREE(sampass);
+ return False;
+}
+
+
/*******************************************************************
_samr_query_sec_obj
********************************************************************/
/* TODO: different SDs have to be generated for aliases groups and users.
Currently all three get a default user SD */
DEBUG(10,("_samr_query_sec_obj: querying security on Object with SID: %s\n", sid_to_string(str_sid, &pol_sid)));
- r_u->status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &pol_sid, SAMR_USR_RIGHTS_WRITE_PW);
+ if (check_change_pw_access(p->mem_ctx, &pol_sid)) {
+ r_u->status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping,
+ &pol_sid, SAMR_USR_RIGHTS_WRITE_PW);
+ } else {
+ r_u->status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_nopwchange_generic_mapping,
+ &pol_sid, SAMR_USR_RIGHTS_CANT_WRITE_PW);
+ }
} else {
return NT_STATUS_OBJECT_TYPE_MISMATCH;
}
NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LOOKUP_NAMES *r_u)
{
uint32 rid[MAX_SAM_ENTRIES];
- enum SID_NAME_USE type[MAX_SAM_ENTRIES];
+ enum lsa_SidType type[MAX_SAM_ENTRIES];
int i;
int num_rids = q_u->num_names2;
DOM_SID pol_sid;
}
}
- init_samr_r_lookup_names(p->mem_ctx, r_u, num_rids, rid, (uint32 *)type, r_u->status);
+ init_samr_r_lookup_names(p->mem_ctx, r_u, num_rids, rid, type, r_u->status);
DEBUG(5,("_samr_lookup_names: %d\n", __LINE__));
NTSTATUS _samr_lookup_rids(pipes_struct *p, SAMR_Q_LOOKUP_RIDS *q_u, SAMR_R_LOOKUP_RIDS *r_u)
{
const char **names;
- uint32 *attrs = NULL;
+ enum lsa_SidType *attrs = NULL;
+ uint32 *wire_attrs = NULL;
UNIHDR *hdr_name = NULL;
UNISTR2 *uni_name = NULL;
DOM_SID pol_sid;
int num_rids = q_u->num_rids1;
uint32 acc_granted;
-
+ int i;
+
r_u->status = NT_STATUS_OK;
DEBUG(5,("_samr_lookup_rids: %d\n", __LINE__));
}
names = TALLOC_ZERO_ARRAY(p->mem_ctx, const char *, num_rids);
- attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_rids);
+ attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, enum lsa_SidType, num_rids);
+ wire_attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_rids);
- if ((num_rids != 0) && ((names == NULL) || (attrs == NULL)))
+ if ((num_rids != 0) && ((names == NULL) || (attrs == NULL) || (wire_attrs==NULL)))
return NT_STATUS_NO_MEMORY;
become_root(); /* lookup_sid can require root privs */
names, attrs);
unbecome_root();
+ if ( NT_STATUS_EQUAL(r_u->status, NT_STATUS_NONE_MAPPED) && (num_rids == 0) ) {
+ r_u->status = NT_STATUS_OK;
+ }
+
if(!make_samr_lookup_rids(p->mem_ctx, num_rids, names,
&hdr_name, &uni_name))
return NT_STATUS_NO_MEMORY;
- init_samr_r_lookup_rids(r_u, num_rids, hdr_name, uni_name, attrs);
+ /* Convert from enum lsa_SidType to uint32 for wire format. */
+ for (i = 0; i < num_rids; i++) {
+ wire_attrs[i] = (uint32)attrs[i];
+ }
+
+ init_samr_r_lookup_rids(r_u, num_rids, hdr_name, uni_name, wire_attrs);
DEBUG(5,("_samr_lookup_rids: %d\n", __LINE__));
TALLOC_FREE(sampass);
- return NT_STATUS_OK;
+ return nt_status;
}
/*******************************************************************
uint32 acc_granted;
BOOL ret;
NTSTATUS result;
+ BOOL success = False;
/*
* from the SID in the request:
sids = NULL;
+ /* make both calls inside the root block */
become_root();
result = pdb_enum_group_memberships(p->mem_ctx, sam_pass,
&sids, &unix_gids, &num_groups);
+ if ( NT_STATUS_IS_OK(result) ) {
+ success = sid_peek_check_rid(get_global_sam_sid(),
+ pdb_get_group_sid(sam_pass),
+ &primary_group_rid);
+ }
unbecome_root();
if (!NT_STATUS_IS_OK(result)) {
return result;
}
- gids = NULL;
- num_gids = 0;
-
- dom_gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|
- SE_GROUP_ENABLED);
-
- if (!sid_peek_check_rid(get_global_sam_sid(),
- pdb_get_group_sid(sam_pass),
- &primary_group_rid)) {
+ if ( !success ) {
DEBUG(5, ("Group sid %s for user %s not in our domain\n",
sid_string_static(pdb_get_group_sid(sam_pass)),
pdb_get_username(sam_pass)));
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- dom_gid.g_rid = primary_group_rid;
+ gids = NULL;
+ num_gids = 0;
+ dom_gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|
+ SE_GROUP_ENABLED);
+ dom_gid.g_rid = primary_group_rid;
ADD_TO_ARRAY(p->mem_ctx, DOM_GID, dom_gid, &gids, &num_gids);
for (i=0; i<num_groups; i++) {
}
/*******************************************************************
- _samr_query_dom_info
+ _samr_query_domain_info
********************************************************************/
-NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SAMR_R_QUERY_DOMAIN_INFO *r_u)
+NTSTATUS _samr_query_domain_info(pipes_struct *p,
+ SAMR_Q_QUERY_DOMAIN_INFO *q_u,
+ SAMR_R_QUERY_DOMAIN_INFO *r_u)
{
struct samr_info *info = NULL;
SAM_UNK_CTR *ctr;
r_u->status = NT_STATUS_OK;
- DEBUG(5,("_samr_query_dom_info: %d\n", __LINE__));
+ DEBUG(5,("_samr_query_domain_info: %d\n", __LINE__));
/* find the policy handle. open a policy on it. */
if (!find_policy_by_hnd(p, &q_u->domain_pol, (void **)(void *)&info)) {
init_unk_info3(&ctr->info.inf3, nt_logout);
break;
+ case 0x04:
+ init_unk_info4(&ctr->info.inf4, lp_serverstring());
+ break;
case 0x05:
- init_unk_info5(&ctr->info.inf5, global_myname());
+ init_unk_info5(&ctr->info.inf5, get_global_sam_name());
break;
case 0x06:
- init_unk_info6(&ctr->info.inf6);
+ /* NT returns its own name when a PDC. win2k and later
+ * only the name of the PDC if itself is a BDC (samba4
+ * idl) */
+ init_unk_info6(&ctr->info.inf6, global_myname());
break;
case 0x07:
server_role = ROLE_DOMAIN_PDC;
}
- init_samr_r_query_dom_info(r_u, q_u->switch_value, ctr, NT_STATUS_OK);
+ init_samr_r_query_domain_info(r_u, q_u->switch_value, ctr, NT_STATUS_OK);
- DEBUG(5,("_samr_query_dom_info: %d\n", __LINE__));
+ DEBUG(5,("_samr_query_domain_info: %d\n", __LINE__));
return r_u->status;
}
static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name)
{
- enum SID_NAME_USE type;
+ enum lsa_SidType type;
BOOL result;
DEBUG(10, ("Checking whether [%s] can be created\n", new_name));
}
DEBUG(5, ("_samr_create_user: %s can add this account : %s\n",
- p->pipe_user_name, can_add_account ? "True":"False" ));
+ uidtoname(p->pipe_user.ut.uid),
+ can_add_account ? "True":"False" ));
/********** BEGIN Admin BLOCK **********/
{
/* Check we actually have the requested alias */
- enum SID_NAME_USE type;
+ enum lsa_SidType type;
BOOL result;
+ gid_t gid;
become_root();
result = lookup_sid(NULL, &sid, NULL, NULL, &type);
if (!result || (type != SID_NAME_ALIAS)) {
return NT_STATUS_NO_SUCH_ALIAS;
}
+
+ /* make sure there is a mapping */
+
+ if ( !sid_to_gid( &sid, &gid ) ) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
}
/* associate the alias SID with the new handle. */
TALLOC_FREE(pwd);
return False;
}
- if (!pdb_set_pass_changed_now (pwd)) {
+ if (!pdb_set_pass_last_set_time (pwd, time(NULL), PDB_CHANGED)) {
TALLOC_FREE(pwd);
return False;
}
}
/* we need to separately check for an account rename first */
+
if (rpcstr_pull(new_name, id21->uni_user_name.buffer,
- sizeof(new_name), id21->uni_user_name.uni_str_len*2, 0) &&
- (!strequal(new_name, pdb_get_username(pwd)))) {
+ sizeof(new_name), id21->uni_user_name.uni_str_len*2, 0)
+ && (!strequal(new_name, pdb_get_username(pwd))))
+ {
/* check to see if the new username already exists. Note: we can't
reliably lock all backends, so there is potentially the
* id21. I don't know if they need to be set. --jerry
*/
- if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) &&
- !NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx,
- pwd))) {
- return status;
+ if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) {
+ status = pdb_set_unix_primary_group(mem_ctx, pwd);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ return status;
+ }
}
+
+ /* Don't worry about writing out the user account since the
+ primary group SID is generated solely from the user's Unix
+ primary group. */
/* write the change out */
if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) {
if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) ||
( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) ||
( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) {
- DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n"));
+ DEBUG(5, ("Changing trust account. Not updating /etc/passwd\n"));
} else {
/* update the UNIX password */
if (lp_unix_password_sync() ) {
- struct passwd *passwd = Get_Pwnam(pdb_get_username(pwd));
- if (!passwd) {
+ struct passwd *passwd;
+ if (pdb_get_username(pwd) == NULL) {
+ DEBUG(1, ("chgpasswd: User without name???\n"));
+ TALLOC_FREE(pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ((passwd = Get_Pwnam(pdb_get_username(pwd))) == NULL) {
DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n"));
}
{
uint32 len;
pstring plaintext_buf;
- uint16 acct_ctrl;
+ uint32 acct_ctrl;
DEBUG(5, ("Attempting administrator password change for user %s\n",
pdb_get_username(pwd)));
} else {
/* update the UNIX password */
if (lp_unix_password_sync()) {
- struct passwd *passwd = Get_Pwnam(pdb_get_username(pwd));
- if (!passwd) {
+ struct passwd *passwd;
+
+ if (pdb_get_username(pwd) == NULL) {
+ DEBUG(1, ("chgpasswd: User without name???\n"));
+ TALLOC_FREE(pwd);
+ return False;
+ }
+
+ if ((passwd = Get_Pwnam(pdb_get_username(pwd))) == NULL) {
DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n"));
}
return True;
}
+/*******************************************************************
+ set_user_info_25
+ ********************************************************************/
+
+static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx, SAM_USER_INFO_25 *id25,
+ struct samu *pwd)
+{
+ NTSTATUS status;
+
+ if (id25 == NULL) {
+ DEBUG(5, ("set_user_info_25: NULL id25\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ copy_id25_to_sam_passwd(pwd, id25);
+
+ /* write the change out */
+ if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) {
+ TALLOC_FREE(pwd);
+ return status;
+ }
+
+ /*
+ * We need to "pdb_update_sam_account" before the unix primary group
+ * is set, because the idealx scripts would also change the
+ * sambaPrimaryGroupSid using the ldap replace method. pdb_ldap uses
+ * the delete explicit / add explicit, which would then fail to find
+ * the previous primaryGroupSid value.
+ */
+
+ if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) {
+ status = pdb_set_unix_primary_group(mem_ctx, pwd);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ return status;
+ }
+ }
+
+ /* WARNING: No TALLOC_FREE(pwd), we are about to set the password
+ * hereafter! */
+
+ return NT_STATUS_OK;
+}
+
/*******************************************************************
samr_reply_set_userinfo
********************************************************************/
if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted, &disp_info))
return NT_STATUS_INVALID_HANDLE;
- /* observed when joining an XP client to a Samba domain */
+ /* This is tricky. A WinXP domain join sets
+ (SA_RIGHT_USER_SET_PASSWORD|SA_RIGHT_USER_SET_ATTRIBUTES|SA_RIGHT_USER_ACCT_FLAGS_EXPIRY)
+ 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().
+ 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. */
+
+ switch (switch_value) {
+ case 18:
+ case 24:
+ case 25:
+ case 26:
+ acc_required = SA_RIGHT_USER_SET_PASSWORD;
+ break;
+ default:
+ acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY;
+ break;
+ }
- acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY;
-
if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, acc_required, "_samr_set_userinfo"))) {
return r_u->status;
}
}
DEBUG(5, ("_samr_set_userinfo: %s does%s possess sufficient rights\n",
- p->pipe_user_name, has_enough_rights ? "" : " not"));
+ uidtoname(p->pipe_user.ut.uid),
+ has_enough_rights ? "" : " not"));
/* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */
dump_data(100, (char *)ctr->info.id25->pass, 532);
+ r_u->status = set_user_info_25(p->mem_ctx,
+ ctr->info.id25, pwd);
+ if (!NT_STATUS_IS_OK(r_u->status)) {
+ goto done;
+ }
if (!set_user_info_pw(ctr->info.id25->pass, pwd))
r_u->status = NT_STATUS_ACCESS_DENIED;
break;
r_u->status = NT_STATUS_INVALID_INFO_CLASS;
}
+ done:
if ( has_enough_rights )
unbecome_root();
if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted, &disp_info))
return NT_STATUS_INVALID_HANDLE;
- /* observed when joining XP client to Samba domain */
+#if 0 /* this really should be applied on a per info level basis --jerry */
+
+ /* observed when joining XP client to Samba domain */
acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY;
+#else
+ acc_required = SA_RIGHT_USER_SET_ATTRIBUTES;
+#endif
if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, acc_required, "_samr_set_userinfo2"))) {
return r_u->status;
}
DEBUG(5, ("_samr_set_userinfo2: %s does%s possess sufficient rights\n",
- p->pipe_user_name, has_enough_rights ? "" : " not"));
+ uidtoname(p->pipe_user.ut.uid),
+ has_enough_rights ? "" : " not"));
/* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */
DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid)));
+ become_root();
status = pdb_enum_aliasmem(&alias_sid, &sids, &num_sids);
+ unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
return status;
attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_members);
- if ((num_members!=0) && (rid==NULL))
+ if ((num_members!=0) && (attr==NULL))
return NT_STATUS_NO_MEMORY;
for (i=0; i<num_members; i++)
struct samu *sam_pass=NULL;
uint32 acc_granted;
BOOL can_add_accounts;
+ uint32 acb_info;
DISP_INFO *disp_info = NULL;
+ BOOL ret;
DEBUG(5, ("_samr_delete_dom_user: %d\n", __LINE__));
return NT_STATUS_NO_MEMORY;
}
- if(!pdb_getsampwsid(sam_pass, &user_sid)) {
+ become_root();
+ ret = pdb_getsampwsid(sam_pass, &user_sid);
+ unbecome_root();
+
+ if( !ret ) {
DEBUG(5,("_samr_delete_dom_user:User %s doesn't exist.\n",
sid_string_static(&user_sid)));
TALLOC_FREE(sam_pass);
return NT_STATUS_NO_SUCH_USER;
}
- can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users );
+ acb_info = pdb_get_acct_ctrl(sam_pass);
+
+ /* 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 );
+ } else {
+ can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_add_users );
+ }
/******** BEGIN SeAddUsers BLOCK *********/
if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &alias_sid, &acc_granted, &disp_info))
return NT_STATUS_INVALID_HANDLE;
+ /* copy the handle to the outgoing reply */
+
+ memcpy( &r_u->pol, &q_u->alias_pol, sizeof(r_u->pol) );
+
if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS, "_samr_delete_dom_alias"))) {
return r_u->status;
}
DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid)));
+ /* Don't let Windows delete builtin groups */
+
+ if ( sid_check_is_in_builtin( &alias_sid ) ) {
+ return NT_STATUS_SPECIAL_ACCOUNT;
+ }
+
if (!sid_check_is_in_our_domain(&alias_sid))
return NT_STATUS_NO_SUCH_ALIAS;
map.comment, num_members);
break;
}
+ case 2:
+ ctr->switch_value1 = 2;
+ init_samr_group_info2(&ctr->group.info2, map.nt_name);
+ break;
case 3:
ctr->switch_value1 = 3;
init_samr_group_info3(&ctr->group.info3);
ctr->switch_value1 = 4;
init_samr_group_info4(&ctr->group.info4, map.comment);
break;
+ case 5: {
+ /*
+ uint32 *members;
+ size_t num_members;
+ */
+
+ ctr->switch_value1 = 5;
+
+ /*
+ become_root();
+ r_u->status = pdb_enum_group_members(
+ p->mem_ctx, &group_sid, &members, &num_members);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(r_u->status)) {
+ return r_u->status;
+ }
+ */
+ init_samr_group_info5(&ctr->group.info5, map.nt_name,
+ map.comment, 0 /* num_members */); /* in w2k3 this is always 0 */
+ break;
+ }
default:
return NT_STATUS_INVALID_INFO_CLASS;
}
ctr=&q_u->ctr;
+ /* get the current group information */
+
+ become_root();
+ ret = pdb_get_aliasinfo( &group_sid, &info );
+ unbecome_root();
+
+ if ( !ret ) {
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
switch (ctr->level) {
+ case 2:
+ {
+ fstring group_name, acct_name;
+ NTSTATUS status;
+
+ /* We currently do not support renaming groups in the
+ the BUILTIN domain. Refer to util_builtin.c to understand
+ why. The eventually needs to be fixed to be like Windows
+ where you can rename builtin groups, just not delete them */
+
+ if ( sid_check_is_in_builtin( &group_sid ) ) {
+ return NT_STATUS_SPECIAL_ACCOUNT;
+ }
+
+ /* There has to be a valid name (and it has to be different) */
+
+ if ( !ctr->alias.info2.name.string )
+ return NT_STATUS_INVALID_PARAMETER;
+
+ unistr2_to_ascii( acct_name, ctr->alias.info2.name.string,
+ sizeof(acct_name)-1 );
+
+ /* If the name is the same just reply "ok". Yes this
+ doesn't allow you to change the case of a group name. */
+
+ if ( strequal( acct_name, info.acct_name ) )
+ return NT_STATUS_OK;
+
+ fstrcpy( info.acct_name, acct_name );
+
+ /* make sure the name doesn't already exist as a user
+ or local group */
+
+ fstr_sprintf( group_name, "%s\\%s", global_myname(), info.acct_name );
+ status = can_create( p->mem_ctx, group_name );
+ if ( !NT_STATUS_IS_OK( status ) )
+ return status;
+ break;
+ }
case 3:
if ( ctr->alias.info3.description.string ) {
unistr2_to_ascii( info.acct_desc,
********************************************************************/
NTSTATUS _samr_query_domain_info2(pipes_struct *p,
- SAMR_Q_QUERY_DOMAIN_INFO2 *q_u,
- SAMR_R_QUERY_DOMAIN_INFO2 *r_u)
+ SAMR_Q_QUERY_DOMAIN_INFO2 *q_u,
+ SAMR_R_QUERY_DOMAIN_INFO2 *r_u)
{
- struct samr_info *info = NULL;
- SAM_UNK_CTR *ctr;
- uint32 min_pass_len,pass_hist,password_properties;
- time_t u_expire, u_min_age;
- NTTIME nt_expire, nt_min_age;
+ SAMR_Q_QUERY_DOMAIN_INFO q;
+ SAMR_R_QUERY_DOMAIN_INFO r;
- time_t u_lock_duration, u_reset_time;
- NTTIME nt_lock_duration, nt_reset_time;
- uint32 lockout;
-
- time_t u_logout;
- NTTIME nt_logout;
-
- uint32 num_users=0, num_groups=0, num_aliases=0;
-
- uint32 account_policy_temp;
-
- time_t seq_num;
- uint32 server_role;
-
- if ((ctr = TALLOC_ZERO_P(p->mem_ctx, SAM_UNK_CTR)) == NULL)
- return NT_STATUS_NO_MEMORY;
-
- ZERO_STRUCTP(ctr);
-
- r_u->status = NT_STATUS_OK;
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
DEBUG(5,("_samr_query_domain_info2: %d\n", __LINE__));
- /* find the policy handle. open a policy on it. */
- if (!find_policy_by_hnd(p, &q_u->domain_pol, (void **)(void *)&info))
- return NT_STATUS_INVALID_HANDLE;
+ q.domain_pol = q_u->domain_pol;
+ q.switch_value = q_u->switch_value;
- switch (q_u->switch_value) {
- case 0x01:
- pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp);
- min_pass_len = account_policy_temp;
-
- pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp);
- pass_hist = account_policy_temp;
-
- pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
- password_properties = account_policy_temp;
-
- pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
- u_expire = account_policy_temp;
-
- pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp);
- u_min_age = account_policy_temp;
-
- unix_to_nt_time_abs(&nt_expire, u_expire);
- unix_to_nt_time_abs(&nt_min_age, u_min_age);
-
- init_unk_info1(&ctr->info.inf1, (uint16)min_pass_len, (uint16)pass_hist,
- password_properties, nt_expire, nt_min_age);
- break;
- case 0x02:
- become_root();
- num_users = count_sam_users(info->disp_info, ACB_NORMAL);
- num_groups = count_sam_groups(info->disp_info);
- num_aliases = count_sam_aliases(info->disp_info);
- unbecome_root();
-
- pdb_get_account_policy(AP_TIME_TO_LOGOUT, &account_policy_temp);
- u_logout = account_policy_temp;
-
- unix_to_nt_time_abs(&nt_logout, u_logout);
-
- if (!pdb_get_seq_num(&seq_num))
- seq_num = time(NULL);
-
- server_role = ROLE_DOMAIN_PDC;
- if (lp_server_role() == ROLE_DOMAIN_BDC)
- server_role = ROLE_DOMAIN_BDC;
-
- init_unk_info2(&ctr->info.inf2, lp_serverstring(), lp_workgroup(), global_myname(), seq_num,
- num_users, num_groups, num_aliases, nt_logout, server_role);
- break;
- case 0x03:
- pdb_get_account_policy(AP_TIME_TO_LOGOUT, &account_policy_temp);
- u_logout = account_policy_temp;
+ r_u->status = _samr_query_domain_info(p, &q, &r);
- unix_to_nt_time_abs(&nt_logout, u_logout);
-
- init_unk_info3(&ctr->info.inf3, nt_logout);
- break;
- case 0x05:
- init_unk_info5(&ctr->info.inf5, global_myname());
- break;
- case 0x06:
- init_unk_info6(&ctr->info.inf6);
- break;
- case 0x07:
- server_role = ROLE_DOMAIN_PDC;
- if (lp_server_role() == ROLE_DOMAIN_BDC)
- server_role = ROLE_DOMAIN_BDC;
-
- init_unk_info7(&ctr->info.inf7, server_role);
- break;
- case 0x08:
- if (!pdb_get_seq_num(&seq_num))
- seq_num = time(NULL);
-
- init_unk_info8(&ctr->info.inf8, (uint32) seq_num);
- break;
- case 0x0c:
- pdb_get_account_policy(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp);
- u_lock_duration = account_policy_temp;
- if (u_lock_duration != -1)
- u_lock_duration *= 60;
-
- pdb_get_account_policy(AP_RESET_COUNT_TIME, &account_policy_temp);
- u_reset_time = account_policy_temp * 60;
-
- pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp);
- lockout = account_policy_temp;
-
- unix_to_nt_time_abs(&nt_lock_duration, u_lock_duration);
- unix_to_nt_time_abs(&nt_reset_time, u_reset_time);
-
- init_unk_info12(&ctr->info.inf12, nt_lock_duration, nt_reset_time, (uint16)lockout);
- break;
- default:
- return NT_STATUS_INVALID_INFO_CLASS;
- }
-
- init_samr_r_samr_query_domain_info2(r_u, q_u->switch_value, ctr, NT_STATUS_OK);
-
- DEBUG(5,("_samr_query_domain_info2: %d\n", __LINE__));
+ r_u->ptr_0 = r.ptr_0;
+ r_u->switch_value = r.switch_value;
+ r_u->ctr = r.ctr;
return r_u->status;
}
/*******************************************************************
- _samr_
+ _samr_set_dom_info
********************************************************************/
NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R_SET_DOMAIN_INFO *r_u)