diff options
Diffstat (limited to 'source3/rpc_server')
-rw-r--r-- | source3/rpc_server/srv_lsa_nt.c | 123 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 144 |
2 files changed, 153 insertions, 114 deletions
diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index b56ae10914..78e9cd6211 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -135,67 +135,75 @@ static int init_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid) init_lsa_rid2s ***************************************************************************/ -static void init_lsa_rid2s(DOM_R_REF *ref, DOM_RID2 *rid2, - int num_entries, UNISTR2 *name, - uint32 *mapped_count, BOOL endian) +static int init_lsa_rid2s(TALLOC_CTX *mem_ctx, + DOM_R_REF *ref, DOM_RID2 *rid2, + int num_entries, UNISTR2 *name, + int flags) { - int i; - int total = 0; - *mapped_count = 0; + int mapped_count, i; SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS); + mapped_count = 0; + become_root(); /* lookup_name can require root privs */ for (i = 0; i < num_entries; i++) { BOOL status = False; DOM_SID sid; - uint32 rid = 0xffffffff; - int dom_idx = -1; - pstring full_name; - fstring dom_name, user; - enum SID_NAME_USE name_type = SID_NAME_UNKNOWN; + uint32 rid; + int dom_idx; + char *full_name, *domain; + enum SID_NAME_USE type = SID_NAME_UNKNOWN; /* Split name into domain and user component */ - unistr2_to_ascii(full_name, &name[i], sizeof(full_name)); - split_domain_name(full_name, dom_name, user); - - /* Lookup name */ + if (rpcstr_pull_unistr2_talloc(mem_ctx, &full_name, + &name[i]) < 0) { + DEBUG(0, ("pull_ucs2_talloc failed\n")); + return 0; + } DEBUG(5, ("init_lsa_rid2s: looking up name %s\n", full_name)); - status = lookup_name(dom_name, user, &sid, &name_type); - - if((name_type == SID_NAME_UNKNOWN) && (lp_server_role() == ROLE_DOMAIN_MEMBER) && (strncmp(dom_name, full_name, strlen(dom_name)) != 0)) { - DEBUG(5, ("init_lsa_rid2s: domain name not provided and local account not found, using member domain\n")); - fstrcpy(dom_name, lp_workgroup()); - status = lookup_name(dom_name, user, &sid, &name_type); - } + /* We can ignore the result of lookup_name, it will not touch + "type" if it's not successful */ - if (name_type == SID_NAME_WKN_GRP) { - /* BUILTIN aliases are still aliases :-) */ - name_type = SID_NAME_ALIAS; - } + lookup_name(mem_ctx, full_name, flags, &domain, NULL, + &sid, &type); DEBUG(5, ("init_lsa_rid2s: %s\n", status ? "found" : "not found")); - if (status && name_type != SID_NAME_UNKNOWN) { + switch (type) { + case SID_NAME_USER: + case SID_NAME_DOM_GRP: + case SID_NAME_DOMAIN: + case SID_NAME_ALIAS: + case SID_NAME_WKN_GRP: + /* Leave these unchanged */ + break; + default: + /* Don't hand out anything but the list above */ + type = SID_NAME_UNKNOWN; + break; + } + + rid = 0; + dom_idx = -1; + + if (type != SID_NAME_UNKNOWN) { sid_split_rid(&sid, &rid); - dom_idx = init_dom_ref(ref, dom_name, &sid); - (*mapped_count)++; - } else { - dom_idx = -1; - rid = 0; - name_type = SID_NAME_UNKNOWN; + dom_idx = init_dom_ref(ref, domain, &sid); + mapped_count++; } - init_dom_rid2(&rid2[total], rid, name_type, dom_idx); - total++; + init_dom_rid2(&rid2[i], rid, type, dom_idx); } unbecome_root(); + + return mapped_count; } /*************************************************************************** @@ -250,42 +258,44 @@ static void init_lsa_trans_names(TALLOC_CTX *ctx, DOM_R_REF *ref, LSA_TRANS_NAME DOM_SID find_sid = sid[i].sid; uint32 rid = 0xffffffff; int dom_idx = -1; - fstring name, dom_name; - enum SID_NAME_USE sid_name_use = (enum SID_NAME_USE)0; + char *name, *domain; + enum SID_NAME_USE type = SID_NAME_UNKNOWN; - sid_to_string(name, &find_sid); - DEBUG(5, ("init_lsa_trans_names: looking up sid %s\n", name)); + DEBUG(5, ("init_lsa_trans_names: looking up sid %s\n", + sid_string_static(&find_sid))); /* Lookup sid from winbindd */ - status = lookup_sid(&find_sid, dom_name, name, &sid_name_use); + status = lookup_sid(ctx, &find_sid, &domain, &name, &type); DEBUG(5, ("init_lsa_trans_names: %s\n", status ? "found" : "not found")); if (!status) { - sid_name_use = SID_NAME_UNKNOWN; - memset(dom_name, '\0', sizeof(dom_name)); - sid_to_string(name, &find_sid); + type = SID_NAME_UNKNOWN; + domain = talloc_strdup(ctx, ""); + name = talloc_strdup(ctx, + sid_string_static(&find_sid)); dom_idx = -1; - DEBUG(10,("init_lsa_trans_names: added unknown user '%s' to " - "referenced list.\n", name )); + DEBUG(10,("init_lsa_trans_names: added unknown user " + "'%s' to referenced list.\n", name )); } else { (*mapped_count)++; /* Store domain sid in ref array */ if (find_sid.num_auths == 5) { sid_split_rid(&find_sid, &rid); } - dom_idx = init_dom_ref(ref, dom_name, &find_sid); + dom_idx = init_dom_ref(ref, domain, &find_sid); - DEBUG(10,("init_lsa_trans_names: added %s '%s\\%s' (%d) to referenced list.\n", - sid_type_lookup(sid_name_use), dom_name, name, sid_name_use )); + DEBUG(10,("init_lsa_trans_names: added %s '%s\\%s' " + "(%d) to referenced list.\n", + sid_type_lookup(type), domain, name, type)); } init_lsa_trans_name(&trn->name[total], &trn->uni_name[total], - sid_name_use, name, dom_idx); + type, name, dom_idx); total++; } @@ -697,12 +707,18 @@ NTSTATUS _lsa_lookup_names(pipes_struct *p,LSA_Q_LOOKUP_NAMES *q_u, LSA_R_LOOKUP DOM_R_REF *ref; DOM_RID2 *rids; uint32 mapped_count = 0; + int flags = 0; if (num_entries > MAX_LOOKUP_SIDS) { num_entries = MAX_LOOKUP_SIDS; DEBUG(5,("_lsa_lookup_names: truncating name lookup list to %d\n", num_entries)); } + /* Probably the lookup_level is some sort of bitmask. */ + if (q_u->lookup_level == 1) { + flags = LOOKUP_NAME_ALL; + } + ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); rids = TALLOC_ZERO_ARRAY(p->mem_ctx, DOM_RID2, num_entries); @@ -720,10 +736,11 @@ NTSTATUS _lsa_lookup_names(pipes_struct *p,LSA_Q_LOOKUP_NAMES *q_u, LSA_R_LOOKUP if (!ref || !rids) return NT_STATUS_NO_MEMORY; + /* set up the LSA Lookup RIDs response */ + mapped_count = init_lsa_rid2s(p->mem_ctx, ref, rids, num_entries, + names, flags); done: - /* set up the LSA Lookup RIDs response */ - init_lsa_rid2s(ref, rids, num_entries, names, &mapped_count, p->endian); if (NT_STATUS_IS_OK(r_u->status)) { if (mapped_count == 0) r_u->status = NT_STATUS_NONE_MAPPED; @@ -1109,15 +1126,13 @@ NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, prs_struct *ps, LSA_Q_ENUMPRIVS NTSTATUS _lsa_getsystemaccount(pipes_struct *p, LSA_Q_GETSYSTEMACCOUNT *q_u, LSA_R_GETSYSTEMACCOUNT *r_u) { struct lsa_info *info=NULL; - fstring name, dom_name; - enum SID_NAME_USE type; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)(void *)&info)) return NT_STATUS_INVALID_HANDLE; - if (!lookup_sid(&info->sid, dom_name, name, &type)) + if (!lookup_sid(p->mem_ctx, &info->sid, NULL, NULL, NULL)) return NT_STATUS_ACCESS_DENIED; /* diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index 635d870762..13f3a3284b 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -1366,9 +1366,7 @@ NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAM NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LOOKUP_NAMES *r_u) { uint32 rid[MAX_SAM_ENTRIES]; - uint32 local_rid; enum SID_NAME_USE type[MAX_SAM_ENTRIES]; - enum SID_NAME_USE local_type; int i; int num_rids = q_u->num_names2; DOM_SID pol_sid; @@ -1400,42 +1398,30 @@ NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LO for (i = 0; i < num_rids; i++) { fstring name; - DOM_SID sid; int ret; r_u->status = NT_STATUS_NONE_MAPPED; + type[i] = SID_NAME_UNKNOWN; rid [i] = 0xffffffff; - type[i] = SID_NAME_UNKNOWN; ret = rpcstr_pull(name, q_u->uni_name[i].buffer, sizeof(name), q_u->uni_name[i].uni_str_len*2, 0); - /* - * we are only looking for a name - * the SID we get back can be outside - * the scope of the pol_sid - * - * in clear: it prevents to reply to domain\group: yes - * when only builtin\group exists. - * - * a cleaner code is to add the sid of the domain we're looking in - * to the local_lookup_name function. - */ - - if ((ret > 0) && local_lookup_name(name, &sid, &local_type)) { - sid_split_rid(&sid, &local_rid); - - if (sid_equal(&sid, &pol_sid)) { - rid[i]=local_rid; - - /* Windows does not return WKN_GRP here, even - * on lookups in builtin */ - type[i] = (local_type == SID_NAME_WKN_GRP) ? - SID_NAME_ALIAS : local_type; - - r_u->status = NT_STATUS_OK; + if (ret <= 0) { + continue; + } + + if (sid_check_is_builtin(&pol_sid)) { + if (lookup_builtin_name(name, &rid[i])) { + type[i] = SID_NAME_ALIAS; } - } + } else { + lookup_global_sam_name(name, &rid[i], &type[i]); + } + + if (type[i] != SID_NAME_UNKNOWN) { + r_u->status = NT_STATUS_OK; + } } init_samr_r_lookup_names(p->mem_ctx, r_u, num_rids, rid, (uint32 *)type, r_u->status); @@ -2247,6 +2233,41 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA return r_u->status; } +/* W2k3 seems to use the same check for all 3 objects that can be created via + * SAMR, if you try to create for example "Dialup" as an alias it says + * "NT_STATUS_USER_EXISTS". This is racy, but we can't really lock the user + * database. */ + +static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name) +{ + enum SID_NAME_USE type; + BOOL result; + + become_root(); + /* Lookup in our local databases (only LOOKUP_NAME_ISOLATED set) + * whether the name already exists */ + result = lookup_name(mem_ctx, new_name, LOOKUP_NAME_ISOLATED, + NULL, NULL, NULL, &type); + unbecome_root(); + + if (!result) { + return NT_STATUS_OK; + } + + DEBUG(5, ("trying to create %s, exists as %s\n", + new_name, sid_type_lookup(type))); + + if (type == SID_NAME_DOM_GRP) { + return NT_STATUS_GROUP_EXISTS; + } + if (type == SID_NAME_ALIAS) { + return NT_STATUS_ALIAS_EXISTS; + } + + /* Yes, the default is NT_STATUS_USER_EXISTS */ + return NT_STATUS_USER_EXISTS; +} + /******************************************************************* _samr_create_user Create an account, can be either a normal user or a machine. @@ -2294,19 +2315,11 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA rpcstr_pull(account, user_account.buffer, sizeof(account), user_account.uni_str_len*2, 0); strlower_m(account); - pdb_init_sam(&sam_pass); - - become_root(); - ret = pdb_getsampwnam(sam_pass, account); - unbecome_root(); - if (ret == True) { - /* this account exists: say so */ - pdb_free_sam(&sam_pass); - return NT_STATUS_USER_EXISTS; + nt_status = can_create(p->mem_ctx, account); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; } - pdb_free_sam(&sam_pass); - /********************************************************************* * HEADS UP! If we have to create a new user account, we have to get * a new RID from somewhere. This used to be done by the passdb @@ -2776,7 +2789,7 @@ NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_A /* append the alias' RID to it */ if (!sid_append_rid(&sid, alias_rid)) - return NT_STATUS_NO_SUCH_USER; + return NT_STATUS_NO_SUCH_ALIAS; /*check if access can be granted as requested by client. */ @@ -2793,12 +2806,21 @@ NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_A if ( !NT_STATUS_IS_OK(status) ) return status; - /* - * we should check if the rid really exist !!! - * JFM. - */ + { + /* Check we actually have the requested alias */ + enum SID_NAME_USE type; + BOOL result; - /* associate the user's SID with the new handle. */ + become_root(); + result = lookup_sid(NULL, &sid, NULL, NULL, &type); + unbecome_root(); + + if (!result || (type != SID_NAME_ALIAS)) { + return NT_STATUS_NO_SUCH_ALIAS; + } + } + + /* associate the alias SID with the new handle. */ if ((info = get_samr_info_by_sid(&sid)) == NULL) return NT_STATUS_NO_MEMORY; @@ -2814,12 +2836,11 @@ NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_A /******************************************************************* set_user_info_7 ********************************************************************/ -static NTSTATUS set_user_info_7(const SAM_USER_INFO_7 *id7, SAM_ACCOUNT *pwd) +static NTSTATUS set_user_info_7(TALLOC_CTX *mem_ctx, + const SAM_USER_INFO_7 *id7, SAM_ACCOUNT *pwd) { fstring new_name; - SAM_ACCOUNT *check_acct = NULL; NTSTATUS rc; - BOOL check_rc; if (id7 == NULL) { DEBUG(5, ("set_user_info_7: NULL id7\n")); @@ -2842,13 +2863,9 @@ static NTSTATUS set_user_info_7(const SAM_USER_INFO_7 *id7, SAM_ACCOUNT *pwd) simply that the rename fails with a slightly different status code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */ - pdb_init_sam(&check_acct); - check_rc = pdb_getsampwnam(check_acct, new_name); - pdb_free_sam(&check_acct); - - if (check_rc == True) { - /* this account exists: say so */ - return NT_STATUS_USER_EXISTS; + rc = can_create(mem_ctx, new_name); + if (!NT_STATUS_IS_OK(rc)) { + return rc; } rc = pdb_rename_sam_account(pwd, new_name); @@ -3365,7 +3382,8 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ switch (switch_value) { case 7: - r_u->status = set_user_info_7(ctr->info.id7, pwd); + r_u->status = set_user_info_7(p->mem_ctx, + ctr->info.id7, pwd); break; case 16: if (!set_user_info_16(ctr->info.id16, pwd)) @@ -4199,9 +4217,10 @@ NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, S unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1); - /* check if group already exist */ - if ((grp=getgrnam(name)) != NULL) - return NT_STATUS_GROUP_EXISTS; + r_u->status = can_create(p->mem_ctx, name); + if (!NT_STATUS_IS_OK(r_u->status)) { + return r_u->status; + } se_priv_copy( &se_rights, &se_add_users ); can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); @@ -4289,6 +4308,11 @@ NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, S if (!sid_equal(&dom_sid, get_global_sam_sid())) return NT_STATUS_ACCESS_DENIED; + r_u->status = can_create(p->mem_ctx, name); + if (!NT_STATUS_IS_OK(r_u->status)) { + return r_u->status; + } + unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1); se_priv_copy( &se_rights, &se_add_users ); |