X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Frpc_server%2Fsrv_samr_nt.c;h=515eefb1fa6945ce6794ab0d55534b1f14325189;hb=46e5effea948931509283cb84b27007d34b521c8;hp=a14c6cd7e83c4c88f3feaab9db348f2479a364f0;hpb=65409a49feb83c48043b980c7cda79149e2d837b;p=samba.git diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index a14c6cd7e83..515eefb1fa6 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -7,8 +7,8 @@ * Copyright (C) Marc Jacobsen 1999, * Copyright (C) Jeremy Allison 2001-2002, * Copyright (C) Jean François Micouleau 1998-2001, - * Copyright (C) Jim McDonough 2002. - * Copyright (C) Gerald (Jerry) Carter 2003. + * Copyright (C) Jim McDonough 2002, + * Copyright (C) Gerald (Jerry) Carter 2003 - 2004, * * 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 @@ -75,7 +75,7 @@ static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd level of access for further checks. ********************************************************************/ -NTSTATUS access_check_samr_object(SEC_DESC *psd, NT_USER_TOKEN *nt_user_token, uint32 des_access, +static NTSTATUS access_check_samr_object(SEC_DESC *psd, NT_USER_TOKEN *nt_user_token, uint32 des_access, uint32 *acc_granted, const char *debug) { NTSTATUS status = NT_STATUS_ACCESS_DENIED; @@ -100,7 +100,7 @@ NTSTATUS access_check_samr_object(SEC_DESC *psd, NT_USER_TOKEN *nt_user_token, u Checks if access to a function can be granted ********************************************************************/ -NTSTATUS access_check_samr_function(uint32 acc_granted, uint32 acc_required, const char *debug) +static NTSTATUS access_check_samr_function(uint32 acc_granted, uint32 acc_required, const char *debug) { DEBUG(5,("%s: access check ((granted: %#010x; required: %#010x)\n", debug, acc_granted, acc_required)); @@ -137,7 +137,7 @@ static struct samr_info *get_samr_info_by_sid(DOM_SID *psid) mem_ctx = talloc_init("samr_info for domain sid %s", sid_str); - if ((info = (struct samr_info *)talloc(mem_ctx, sizeof(struct samr_info))) == NULL) + if ((info = TALLOC_P(mem_ctx, struct samr_info)) == NULL) return NULL; ZERO_STRUCTP(info); @@ -255,8 +255,8 @@ static NTSTATUS load_sampwd_entries(struct samr_info *info, uint16 acb_mask, BOO if (info->disp_info.num_user_account % MAX_SAM_ENTRIES == 0) { DEBUG(10,("load_sampwd_entries: allocating more memory\n")); - pwd_array=(SAM_ACCOUNT *)talloc_realloc(mem_ctx, info->disp_info.disp_user_info, - (info->disp_info.num_user_account+MAX_SAM_ENTRIES)*sizeof(SAM_ACCOUNT)); + pwd_array=TALLOC_REALLOC_ARRAY(mem_ctx, info->disp_info.disp_user_info, SAM_ACCOUNT, + info->disp_info.num_user_account+MAX_SAM_ENTRIES); if (pwd_array==NULL) return NT_STATUS_NO_MEMORY; @@ -292,6 +292,7 @@ static NTSTATUS load_group_domain_entries(struct samr_info *info, DOM_SID *sid) uint32 group_entries = 0; uint32 i; TALLOC_CTX *mem_ctx = info->mem_ctx; + BOOL ret; DEBUG(10,("load_group_domain_entries\n")); @@ -301,19 +302,27 @@ static NTSTATUS load_group_domain_entries(struct samr_info *info, DOM_SID *sid) return NT_STATUS_OK; } + if (sid_equal(sid, &global_sid_Builtin)) { + /* No domain groups for now in the BUILTIN domain */ + info->disp_info.num_group_account=0; + info->disp_info.disp_group_info=NULL; + info->disp_info.group_dbloaded=True; + return NT_STATUS_OK; + } become_root(); - - if (!pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED)) { + ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED); + unbecome_root(); + + if ( !ret ) { DEBUG(1, ("load_group_domain_entries: pdb_enum_group_mapping() failed!\n")); return NT_STATUS_NO_MEMORY; } - unbecome_root(); info->disp_info.num_group_account=group_entries; - grp_array=(DOMAIN_GRP *)talloc(mem_ctx, info->disp_info.num_group_account*sizeof(DOMAIN_GRP)); + grp_array=TALLOC_ARRAY(mem_ctx, DOMAIN_GRP, info->disp_info.num_group_account); if (group_entries!=0 && grp_array==NULL) { DEBUG(1, ("load_group_domain_entries: talloc() failed for grp_array!\n")); SAFE_FREE(map); @@ -441,11 +450,10 @@ NTSTATUS _samr_get_usrdom_pwinfo(pipes_struct *p, SAMR_Q_GET_USRDOM_PWINFO *q_u, static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size) { extern DOM_SID global_sid_World; - DOM_SID adm_sid; - DOM_SID act_sid; - - SEC_ACE ace[3]; + DOM_SID adm_sid, act_sid, domadmin_sid; + SEC_ACE ace[4]; SEC_ACCESS mask; + size_t i = 0; SEC_ACL *psa = NULL; @@ -457,17 +465,27 @@ static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd /*basic access for every one*/ init_sec_access(&mask, GENERIC_RIGHTS_DOMAIN_EXECUTE | GENERIC_RIGHTS_DOMAIN_READ); - init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); /*full access for builtin aliases Administrators and Account Operators*/ + init_sec_access(&mask, GENERIC_RIGHTS_DOMAIN_ALL_ACCESS); - init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); - init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + + init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + + /* add 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); + } - if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL) + if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL) return NT_STATUS_NO_MEMORY; - if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, sd_size)) == NULL) + if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL) return NT_STATUS_NO_MEMORY; return NT_STATUS_OK; @@ -480,10 +498,10 @@ static NTSTATUS samr_make_dom_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd static NTSTATUS samr_make_usr_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size, DOM_SID *usr_sid) { extern DOM_SID global_sid_World; - DOM_SID adm_sid; - DOM_SID act_sid; + DOM_SID adm_sid, act_sid, domadmin_sid; + size_t i = 0; - SEC_ACE ace[4]; + SEC_ACE ace[5]; SEC_ACCESS mask; SEC_ACL *psa = NULL; @@ -495,22 +513,33 @@ static NTSTATUS samr_make_usr_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS); /*basic access for every one*/ + init_sec_access(&mask, GENERIC_RIGHTS_USER_EXECUTE | GENERIC_RIGHTS_USER_READ); - init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); /*full access for builtin aliases Administrators and Account Operators*/ + init_sec_access(&mask, GENERIC_RIGHTS_USER_ALL_ACCESS); - init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); - init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + + /* add 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); + } /*extended access for the user*/ + init_sec_access(&mask,READ_CONTROL_ACCESS | SA_RIGHT_USER_CHANGE_PASSWORD | SA_RIGHT_USER_SET_LOC_COM); - init_sec_ace(&ace[3], usr_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); + init_sec_ace(&ace[i++], usr_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 4, ace)) == NULL) return NT_STATUS_NO_MEMORY; - if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, sd_size)) == NULL) + if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL) return NT_STATUS_NO_MEMORY; return NT_STATUS_OK; @@ -549,7 +578,7 @@ static NTSTATUS samr_make_grp_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL) return NT_STATUS_NO_MEMORY; - if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, sd_size)) == NULL) + if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL) return NT_STATUS_NO_MEMORY; return NT_STATUS_OK; @@ -588,7 +617,7 @@ static NTSTATUS samr_make_ali_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL) return NT_STATUS_NO_MEMORY; - if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, sd_size)) == NULL) + if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL) return NT_STATUS_NO_MEMORY; return NT_STATUS_OK; @@ -707,9 +736,9 @@ static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UN if (num_entries == 0) return NT_STATUS_OK; - sam = (SAM_ENTRY *)talloc_zero(ctx, sizeof(SAM_ENTRY)*num_entries); + sam = TALLOC_ZERO_ARRAY(ctx, SAM_ENTRY, num_entries); - uni_name = (UNISTR2 *)talloc_zero(ctx, sizeof(UNISTR2)*num_entries); + uni_name = TALLOC_ZERO_ARRAY(ctx, UNISTR2, num_entries); if (sam == NULL || uni_name == NULL) { DEBUG(0, ("make_user_sam_entry_list: talloc_zero failed!\n")); @@ -719,7 +748,17 @@ static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UN for (i = 0; i < num_entries; i++) { pwd = &disp_user_info[i+start_idx]; temp_name = pdb_get_username(pwd); - init_unistr2(&uni_temp_name, temp_name, strlen(temp_name)+1); + + /* + * usrmgr expects a non-NULL terminated string with + * trust relationships + */ + if (pdb_get_acct_ctrl(pwd) & ACB_DOMTRUST) { + init_unistr2(&uni_temp_name, temp_name, UNI_FLAGS_NONE); + } else { + init_unistr2(&uni_temp_name, temp_name, UNI_STR_TERMINATE); + } + user_sid = pdb_get_user_sid(pwd); if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) { @@ -731,7 +770,7 @@ static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UN return NT_STATUS_UNSUCCESSFUL; } - init_sam_entry(&sam[i], uni_temp_name.uni_str_len, user_rid); + init_sam_entry(&sam[i], &uni_temp_name, user_rid); copy_unistr2(&uni_name[i], &uni_temp_name); } @@ -852,9 +891,8 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST if (num_sam_entries == 0) return; - sam = (SAM_ENTRY *)talloc_zero(ctx, sizeof(SAM_ENTRY)*num_sam_entries); - - uni_name = (UNISTR2 *)talloc_zero(ctx, sizeof(UNISTR2)*num_sam_entries); + sam = TALLOC_ZERO_ARRAY(ctx, SAM_ENTRY, num_sam_entries); + uni_name = TALLOC_ZERO_ARRAY(ctx, UNISTR2, num_sam_entries); if (sam == NULL || uni_name == NULL) { DEBUG(0, ("NULL pointers in SAMR_R_QUERY_DISPINFO\n")); @@ -865,10 +903,8 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST /* * JRA. I think this should include the null. TNG does not. */ - int len = strlen(grp[i].name)+1; - - init_sam_entry(&sam[i], len, grp[i].rid); - init_unistr2(&uni_name[i], grp[i].name, len); + init_unistr2(&uni_name[i], grp[i].name, UNI_STR_TERMINATE); + init_sam_entry(&sam[i], &uni_name[i], grp[i].rid); } *sam_pp = sam; @@ -877,134 +913,11 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST /******************************************************************* Get the group entries - similar to get_sampwd_entries(). - ********************************************************************/ - -static NTSTATUS get_group_alias_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx, - uint32 *p_num_entries, uint32 max_entries) -{ - fstring sid_str; - uint32 num_entries = 0; - int i; - GROUP_MAP smap; - GROUP_MAP *map = NULL; - - sid_to_string(sid_str, sid); - DEBUG(5, ("get_group_alias_entries: enumerating aliases on SID: %s\n", sid_str)); - - *p_num_entries = 0; - - /* well-known aliases */ - if (sid_equal(sid, &global_sid_Builtin) && !lp_hide_local_users()) { - - pdb_enum_group_mapping(SID_NAME_WKN_GRP, &map, (int *)&num_entries, ENUM_ONLY_MAPPED); - - if (num_entries != 0) { - *d_grp=(DOMAIN_GRP *)talloc_zero(ctx, num_entries*sizeof(DOMAIN_GRP)); - if (*d_grp==NULL) - return NT_STATUS_NO_MEMORY; - - for(i=0; inext) { - uint32 trid; - - if(!pdb_getgrgid(&smap, grp->gr_gid)) - continue; - - if (smap.sid_name_use!=SID_NAME_ALIAS) { - continue; - } - - sid_split_rid(&smap.sid, &trid); - - if (!sid_equal(sid, &smap.sid)) - continue; - - /* Don't return winbind groups as they are not local! */ - if (winbind_groups_exist && (grp->gr_gid >= winbind_gid_low)&&(grp->gr_gid <= winbind_gid_high)) { - DEBUG(10,("get_group_alias_entries: not returing %s, not local.\n", smap.nt_name )); - continue; - } - - /* Don't return user private groups... */ - - if (Get_Pwnam(smap.nt_name) != 0) { - DEBUG(10,("get_group_alias_entries: not returing %s, clashes with user.\n", smap.nt_name )); - continue; - } - - for( i = 0; i < num_entries; i++) - if ( (*d_grp)[i].rid == trid ) - break; - - if ( i < num_entries ) { - continue; /* rid was there, dup! */ - } - - /* JRA - added this for large group db enumeration... */ - - if (start_idx > 0) { - /* skip the requested number of entries. - not very efficient, but hey... - */ - start_idx--; - continue; - } - - *d_grp=talloc_realloc(ctx,*d_grp, (num_entries+1)*sizeof(DOMAIN_GRP)); - if (*d_grp==NULL) { - grent_free(glist); - return NT_STATUS_NO_MEMORY; - } - - fstrcpy((*d_grp)[num_entries].name, smap.nt_name); - (*d_grp)[num_entries].rid = trid; - num_entries++; - DEBUG(10,("get_group_alias_entries: added entry %d, rid:%d\n", num_entries, trid)); - } - - grent_free(glist); - } - - *p_num_entries = num_entries; - - DEBUG(10,("get_group_alias_entries: returning %d entries\n", *p_num_entries)); - - if (num_entries >= max_entries) - return STATUS_MORE_ENTRIES; - return NT_STATUS_OK; -} - -/******************************************************************* - Get the group entries - similar to get_sampwd_entries(). - ********************************************************************/ + ******************************************************************/ -static NTSTATUS get_group_domain_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx, - uint32 *p_num_entries, uint32 max_entries) +static NTSTATUS get_group_domain_entries( TALLOC_CTX *ctx, + DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx, + uint32 *p_num_entries, uint32 max_entries ) { GROUP_MAP *map=NULL; int i; @@ -1017,7 +930,8 @@ static NTSTATUS get_group_domain_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DO needed for some passdb backends to enumerate groups */ become_root(); - pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED); + pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, + ENUM_ONLY_MAPPED); unbecome_root(); num_entries=group_entries-start_idx; @@ -1028,7 +942,7 @@ static NTSTATUS get_group_domain_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DO num_entries=max_entries; } - *d_grp=(DOMAIN_GRP *)talloc_zero(ctx, num_entries*sizeof(DOMAIN_GRP)); + *d_grp=TALLOC_ZERO_ARRAY(ctx, DOMAIN_GRP, num_entries); if (num_entries!=0 && *d_grp==NULL){ SAFE_FREE(map); return NT_STATUS_NO_MEMORY; @@ -1045,6 +959,50 @@ static NTSTATUS get_group_domain_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DO *p_num_entries = num_entries; + DEBUG(10,("get_group_domain_entries: returning %d entries\n", + *p_num_entries)); + + return NT_STATUS_OK; +} + +/******************************************************************* + Wrapper for enumerating local groups + ******************************************************************/ + +static NTSTATUS get_alias_entries( TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, + const DOM_SID *sid, uint32 start_idx, + uint32 *p_num_entries, uint32 max_entries ) +{ + struct acct_info *info; + int i; + BOOL res; + + become_root(); + res = pdb_enum_aliases(sid, start_idx, max_entries, + p_num_entries, &info); + unbecome_root(); + + if (!res) + return NT_STATUS_ACCESS_DENIED; + + if (*p_num_entries == 0) + return NT_STATUS_OK; + + *d_grp = TALLOC_ARRAY(ctx, DOMAIN_GRP, *p_num_entries); + + if (*d_grp == NULL) { + SAFE_FREE(info); + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i<*p_num_entries; i++) { + fstrcpy((*d_grp)[i].name, info[i].acct_name); + fstrcpy((*d_grp)[i].comment, info[i].acct_desc); + (*d_grp)[i].rid = info[i].rid; + (*d_grp)[i].attr = SID_NAME_ALIAS; + } + + SAFE_FREE(info); return NT_STATUS_OK; } @@ -1110,9 +1068,9 @@ NTSTATUS _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, S sid_to_string(sid_str, &sid); DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", sid_str)); - status = get_group_alias_entries(p->mem_ctx, &grp, &sid, q_u->start_idx, - &num_entries, MAX_SAM_ENTRIES); - if (NT_STATUS_IS_ERR(status)) return status; + status = get_alias_entries(p->mem_ctx, &grp, &sid, q_u->start_idx, + &num_entries, MAX_SAM_ENTRIES); + if (!NT_STATUS_IS_OK(status)) return status; make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, num_entries, grp); @@ -1248,7 +1206,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, DEBUG(5, ("samr_reply_query_dispinfo: buffer size limits to only %d entries\n", max_entries)); } - if (!(ctr = (SAM_DISPINFO_CTR *)talloc_zero(p->mem_ctx,sizeof(SAM_DISPINFO_CTR)))) + if (!(ctr = TALLOC_ZERO_P(p->mem_ctx,SAM_DISPINFO_CTR))) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(ctr); @@ -1257,7 +1215,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, switch (q_u->switch_level) { case 0x1: if (max_entries) { - if (!(ctr->sam.info1 = (SAM_DISPINFO_1 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_1)))) + if (!(ctr->sam.info1 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_1,max_entries))) return NT_STATUS_NO_MEMORY; } disp_ret = init_sam_dispinfo_1(p->mem_ctx, ctr->sam.info1, max_entries, enum_context, @@ -1267,7 +1225,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, break; case 0x2: if (max_entries) { - if (!(ctr->sam.info2 = (SAM_DISPINFO_2 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_2)))) + if (!(ctr->sam.info2 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_2,max_entries))) return NT_STATUS_NO_MEMORY; } disp_ret = init_sam_dispinfo_2(p->mem_ctx, ctr->sam.info2, max_entries, enum_context, @@ -1277,7 +1235,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, break; case 0x3: if (max_entries) { - if (!(ctr->sam.info3 = (SAM_DISPINFO_3 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_3)))) + if (!(ctr->sam.info3 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_3,max_entries))) return NT_STATUS_NO_MEMORY; } disp_ret = init_sam_dispinfo_3(p->mem_ctx, ctr->sam.info3, max_entries, enum_context, info->disp_info.disp_group_info); @@ -1286,7 +1244,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, break; case 0x4: if (max_entries) { - if (!(ctr->sam.info4 = (SAM_DISPINFO_4 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_4)))) + if (!(ctr->sam.info4 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_4,max_entries))) return NT_STATUS_NO_MEMORY; } disp_ret = init_sam_dispinfo_4(p->mem_ctx, ctr->sam.info4, max_entries, enum_context, info->disp_info.disp_user_info); @@ -1295,7 +1253,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, break; case 0x5: if (max_entries) { - if (!(ctr->sam.info5 = (SAM_DISPINFO_5 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_5)))) + if (!(ctr->sam.info5 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_5,max_entries))) return NT_STATUS_NO_MEMORY; } disp_ret = init_sam_dispinfo_5(p->mem_ctx, ctr->sam.info5, max_entries, enum_context, info->disp_info.disp_group_info); @@ -1329,8 +1287,9 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAMR_R_QUERY_ALIASINFO *r_u) { DOM_SID sid; - GROUP_MAP map; + struct acct_info info; uint32 acc_granted; + BOOL ret; r_u->status = NT_STATUS_OK; @@ -1343,23 +1302,24 @@ NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAM return r_u->status; } - if (!sid_check_is_in_our_domain(&sid) && - !sid_check_is_in_builtin(&sid)) - return NT_STATUS_OBJECT_TYPE_MISMATCH; - - if (!pdb_getgrsid(&map, sid)) + become_root(); + ret = pdb_get_aliasinfo(&sid, &info); + unbecome_root(); + + if ( !ret ) return NT_STATUS_NO_SUCH_ALIAS; switch (q_u->switch_level) { case 1: r_u->ptr = 1; r_u->ctr.switch_value1 = 1; - init_samr_alias_info1(&r_u->ctr.alias.info1, map.nt_name, 1, map.comment); + init_samr_alias_info1(&r_u->ctr.alias.info1, + info.acct_name, 1, info.acct_desc); break; case 3: r_u->ptr = 1; r_u->ctr.switch_value1 = 3; - init_samr_alias_info3(&r_u->ctr.alias.info3, map.comment); + init_samr_alias_info3(&r_u->ctr.alias.info3, info.acct_desc); break; default: return NT_STATUS_INVALID_INFO_CLASS; @@ -1469,8 +1429,6 @@ NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LO DEBUG(5,("_samr_lookup_names: looking name on SID %s\n", sid_to_string(sid_str, &pol_sid))); - become_root(); /* local_lookup_name can require root privs */ - for (i = 0; i < num_rids; i++) { fstring name; DOM_SID sid; @@ -1500,14 +1458,17 @@ NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LO if (sid_equal(&sid, &pol_sid)) { rid[i]=local_rid; - type[i]=local_type; + + /* 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; } } } - unbecome_root(); - init_samr_r_lookup_names(p->mem_ctx, r_u, num_rids, rid, (uint32 *)type, r_u->status); DEBUG(5,("_samr_lookup_names: %d\n", __LINE__)); @@ -1570,20 +1531,19 @@ static BOOL make_samr_lookup_rids(TALLOC_CTX *ctx, uint32 num_names, fstring nam *pp_hdr_name = NULL; if (num_names != 0) { - hdr_name = (UNIHDR *)talloc_zero(ctx, sizeof(UNIHDR)*num_names); + hdr_name = TALLOC_ZERO_ARRAY(ctx, UNIHDR, num_names); if (hdr_name == NULL) return False; - uni_name = (UNISTR2 *)talloc_zero(ctx,sizeof(UNISTR2)*num_names); + uni_name = TALLOC_ZERO_ARRAY(ctx,UNISTR2, num_names); if (uni_name == NULL) return False; } for (i = 0; i < num_names; i++) { - int len = names[i] != NULL ? strlen(names[i]) : 0; - DEBUG(10, ("names[%d]:%s\n", i, names[i])); - init_uni_hdr(&hdr_name[i], len); - init_unistr2(&uni_name[i], names[i], len); + DEBUG(10, ("names[%d]:%s\n", i, names[i] ? names[i] : "")); + init_unistr2(&uni_name[i], names[i], UNI_FLAGS_NONE); + init_uni_hdr(&hdr_name[i], &uni_name[i]); } *pp_uni_name = uni_name; @@ -1621,7 +1581,7 @@ NTSTATUS _samr_lookup_rids(pipes_struct *p, SAMR_Q_LOOKUP_RIDS *q_u, SAMR_R_LOOK } if (num_rids) { - if ((group_attrs = (uint32 *)talloc_zero(p->mem_ctx, num_rids * sizeof(uint32))) == NULL) + if ((group_attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_rids )) == NULL) return NT_STATUS_NO_MEMORY; } @@ -1664,10 +1624,10 @@ NTSTATUS _samr_lookup_rids(pipes_struct *p, SAMR_Q_LOOKUP_RIDS *q_u, SAMR_R_LOOK } /******************************************************************* - _api_samr_open_user. Safe - gives out no passwd info. + _samr_open_user. Safe - gives out no passwd info. ********************************************************************/ -NTSTATUS _api_samr_open_user(pipes_struct *p, SAMR_Q_OPEN_USER *q_u, SAMR_R_OPEN_USER *r_u) +NTSTATUS _samr_open_user(pipes_struct *p, SAMR_Q_OPEN_USER *q_u, SAMR_R_OPEN_USER *r_u) { SAM_ACCOUNT *sampass=NULL; DOM_SID sid; @@ -1913,7 +1873,7 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ DEBUG(5,("_samr_query_userinfo: sid:%s\n", sid_string_static(&info->sid))); - ctr = (SAM_USERINFO_CTR *)talloc_zero(p->mem_ctx, sizeof(SAM_USERINFO_CTR)); + ctr = TALLOC_ZERO_P(p->mem_ctx, SAM_USERINFO_CTR); if (!ctr) return NT_STATUS_NO_MEMORY; @@ -1924,7 +1884,7 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ switch (q_u->switch_value) { case 0x10: - ctr->info.id10 = (SAM_USER_INFO_10 *)talloc_zero(p->mem_ctx, sizeof(SAM_USER_INFO_10)); + ctr->info.id10 = TALLOC_ZERO_P(p->mem_ctx, SAM_USER_INFO_10); if (ctr->info.id10 == NULL) return NT_STATUS_NO_MEMORY; @@ -1942,11 +1902,7 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ expire.low = 0xffffffff; expire.high = 0x7fffffff; - ctr->info.id = (SAM_USER_INFO_11 *)talloc_zero(p->mem_ctx, - sizeof - (*ctr-> - info. - id11)); + ctr->info.id = TALLOC_ZERO_P(p->mem_ctx, SAM_USER_INFO_11)); ZERO_STRUCTP(ctr->info.id11); init_sam_user_info11(ctr->info.id11, &expire, "BROOKFIELDS$", /* name */ @@ -1959,7 +1915,7 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ #endif case 0x12: - ctr->info.id12 = (SAM_USER_INFO_12 *)talloc_zero(p->mem_ctx, sizeof(SAM_USER_INFO_12)); + ctr->info.id12 = TALLOC_ZERO_P(p->mem_ctx, SAM_USER_INFO_12); if (ctr->info.id12 == NULL) return NT_STATUS_NO_MEMORY; @@ -1968,7 +1924,7 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ break; case 20: - ctr->info.id20 = (SAM_USER_INFO_20 *)talloc_zero(p->mem_ctx,sizeof(SAM_USER_INFO_20)); + ctr->info.id20 = TALLOC_ZERO_P(p->mem_ctx,SAM_USER_INFO_20); if (ctr->info.id20 == NULL) return NT_STATUS_NO_MEMORY; if (!NT_STATUS_IS_OK(r_u->status = get_user_info_20(p->mem_ctx, ctr->info.id20, &info->sid))) @@ -1976,7 +1932,7 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ break; case 21: - ctr->info.id21 = (SAM_USER_INFO_21 *)talloc_zero(p->mem_ctx,sizeof(SAM_USER_INFO_21)); + ctr->info.id21 = TALLOC_ZERO_P(p->mem_ctx,SAM_USER_INFO_21); if (ctr->info.id21 == NULL) return NT_STATUS_NO_MEMORY; if (!NT_STATUS_IS_OK(r_u->status = get_user_info_21(p->mem_ctx, ctr->info.id21, @@ -2002,11 +1958,16 @@ NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_ NTSTATUS _samr_query_usergroups(pipes_struct *p, SAMR_Q_QUERY_USERGROUPS *q_u, SAMR_R_QUERY_USERGROUPS *r_u) { SAM_ACCOUNT *sam_pass=NULL; + struct passwd *passwd; DOM_SID sid; + DOM_SID *sids; DOM_GID *gids = NULL; int num_groups = 0; + gid_t *unix_gids; + int i, num_gids, num_sids; uint32 acc_granted; BOOL ret; + NTSTATUS result; /* * from the SID in the request: @@ -2045,19 +2006,52 @@ NTSTATUS _samr_query_usergroups(pipes_struct *p, SAMR_Q_QUERY_USERGROUPS *q_u, S pdb_free_sam(&sam_pass); return NT_STATUS_NO_SUCH_USER; } - - if(!get_domain_user_groups(p->mem_ctx, &num_groups, &gids, sam_pass)) { + + passwd = getpwnam_alloc(pdb_get_username(sam_pass)); + if (passwd == NULL) { pdb_free_sam(&sam_pass); - return NT_STATUS_NO_SUCH_GROUP; + return NT_STATUS_NO_SUCH_USER; + } + + sids = NULL; + num_sids = 0; + + become_root(); + result = pdb_enum_group_memberships(pdb_get_username(sam_pass), + passwd->pw_gid, + &sids, &unix_gids, &num_groups); + unbecome_root(); + + pdb_free_sam(&sam_pass); + passwd_free(&passwd); + + if (!NT_STATUS_IS_OK(result)) + return result; + + SAFE_FREE(unix_gids); + + gids = NULL; + num_gids = 0; + + for (i=0; imem_ctx, gids, DOM_GID, num_gids+1); + gids[num_gids].attr=7; + gids[num_gids].g_rid = rid; + num_gids += 1; } + SAFE_FREE(sids); /* construct the response. lkclXXXX: gids are not copied! */ init_samr_r_query_usergroups(r_u, num_groups, gids, r_u->status); DEBUG(5,("_samr_query_usergroups: %d\n", __LINE__)); - pdb_free_sam(&sam_pass); - return r_u->status; } @@ -2084,7 +2078,7 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA uint32 num_users=0, num_groups=0, num_aliases=0; - if ((ctr = (SAM_UNK_CTR *)talloc_zero(p->mem_ctx, sizeof(SAM_UNK_CTR))) == NULL) + if ((ctr = TALLOC_ZERO_P(p->mem_ctx, SAM_UNK_CTR)) == NULL) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(ctr); @@ -2139,10 +2133,15 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA } num_groups=info->disp_info.num_group_account; free_samr_db(info); - + + account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp); + u_logout = account_policy_temp; + + unix_to_nt_time_abs(&nt_logout, u_logout); + /* The time call below is to get a sequence number for the sam. FIXME !!! JRA. */ - init_unk_info2(&ctr->info.inf2, lp_workgroup(), global_myname(), (uint32) time(NULL), - num_users, num_groups, num_aliases); + init_unk_info2(&ctr->info.inf2, "", lp_workgroup(), global_myname(), (uint32) time(NULL), + num_users, num_groups, num_aliases, nt_logout); break; case 0x03: account_policy_get(AP_TIME_TO_LOGOUT, (unsigned int *)&u_logout); @@ -2159,12 +2158,17 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA case 0x07: init_unk_info7(&ctr->info.inf7); break; + case 0x08: + init_unk_info8(&ctr->info.inf8, (uint32) time(NULL)); + break; case 0x0c: account_policy_get(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp); u_lock_duration = account_policy_temp; + if (u_lock_duration != -1) + u_lock_duration *= 60; account_policy_get(AP_RESET_COUNT_TIME, &account_policy_temp); - u_reset_time = account_policy_temp; + u_reset_time = account_policy_temp * 60; account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp); lockout = account_policy_temp; @@ -2186,12 +2190,12 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA } /******************************************************************* - _api_samr_create_user + _samr_create_user Create an account, can be either a normal user or a machine. This funcion will need to be updated for bdc/domain trusts. ********************************************************************/ -NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREATE_USER *r_u) +NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREATE_USER *r_u) { SAM_ACCOUNT *sam_pass=NULL; fstring account; @@ -2211,6 +2215,8 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ uint32 new_rid = 0; /* check this, when giving away 'add computer to domain' privs */ uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS; + BOOL can_add_machines = False; + SE_PRIV se_machineop = SE_MACHINE_ACCOUNT; /* Get the domain SID stored in the domain policy */ if (!get_lsa_policy_samr_sid(p, &dom_pol, &sid, &acc_granted)) @@ -2220,6 +2226,12 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ return nt_status; } + if (!(acb_info == ACB_NORMAL || acb_info == ACB_DOMTRUST || acb_info == ACB_WSTRUST || acb_info == ACB_SVRTRUST)) { + /* Match Win2k, and return NT_STATUS_INVALID_PARAMETER if + this parameter is not an account type */ + return NT_STATUS_INVALID_PARAMETER; + } + /* find the account: tell the caller if it exists. lkclXXXX i have *no* idea if this is a problem or not or even if you are supposed to construct a different @@ -2228,6 +2240,13 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ rpcstr_pull(account, user_account.buffer, sizeof(account), user_account.uni_str_len*2, 0); strlower_m(account); + + /* check to see if we are a domain admin */ + + can_add_machines = user_has_privileges( p->pipe_user.nt_user_token, &se_machineop ); + + DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n", + p->pipe_user_name, can_add_machines ? "" : " not")); pdb_init_sam(&sam_pass); @@ -2247,35 +2266,7 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ * *NOT* surrounded by a become_root()/unbecome_root() call. This ensures * that only people with write access to the smbpasswd file will be able * to create a user. JRA. - */ - - /* - * add the user in the /etc/passwd file or the unix authority system. - * We don't check if the smb_create_user() function succed or not for 2 reasons: - * a) local_password_change() checks for us if the /etc/passwd account really exists - * b) smb_create_user() would return an error if the account already exists - * and as it could return an error also if it can't create the account, it would be tricky. - * - * So we go the easy way, only check after if the account exists. - * JFM (2/3/2001), to clear any possible bad understanding (-: - * - * We now have seperate script paramaters for adding users/machines so we - * now have some sainity-checking to match. - */ - - DEBUG(10,("checking account %s at pos %lu for $ termination\n",account, (unsigned long)strlen(account)-1)); - - /* - * we used to have code here that made sure the acb_info flags - * matched with the users named (e.g. an account flags as a machine - * trust account ended in '$'). It has been ifdef'd out for a long - * time, so I replaced it with this comment. --jerry - */ - - /* the passdb lookup has failed; check to see if we need to run the - add user/machine script */ - - pw = Get_Pwnam(account); + */ /********************************************************************* * HEADS UP! If we have to create a new user account, we have to get @@ -2288,6 +2279,13 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ * --jerry (2003-07-10) *********************************************************************/ + pw = Get_Pwnam(account); + + /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ + + if ( can_add_machines ) + become_root(); + if ( !pw ) { /* * we can't check both the ending $ and the acb_info. @@ -2303,14 +2301,14 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ if (*add_script) { int add_ret; - all_string_sub(add_script, "%u", account, sizeof(account)); + all_string_sub(add_script, "%u", account, sizeof(add_script)); add_ret = smbrun(add_script,NULL); - DEBUG(3,("_api_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret)); + DEBUG(3,("_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret)); } else /* no add user script -- ask winbindd to do it */ { if ( !winbind_create_user( account, &new_rid ) ) { - DEBUG(3,("_api_samr_create_user: winbind_create_user(%s) failed\n", + DEBUG(3,("_samr_create_user: winbind_create_user(%s) failed\n", account)); } } @@ -2319,12 +2317,22 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ /* implicit call to getpwnam() next. we have a valid SID coming out of this call */ - if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account, new_rid)) ) + if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account, new_rid)) ) { + if ( can_add_machines ) + unbecome_root(); return nt_status; + } pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED); - if (!pdb_add_sam_account(sam_pass)) { + ret = pdb_add_sam_account(sam_pass); + + if ( can_add_machines ) + unbecome_root(); + + /* ================ END SeMachineAccountPrivilege BLOCK ================ */ + + if ( !ret ) { pdb_free_sam(&sam_pass); DEBUG(0, ("could not add user/computer %s to passdb. Check permissions?\n", account)); @@ -2332,13 +2340,16 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ } /* Get the user's SID */ + sid_copy(&sid, pdb_get_user_sid(sam_pass)); samr_make_usr_obj_sd(p->mem_ctx, &psd, &sd_size, &sid); se_map_generic(&des_access, &usr_generic_mapping); - if (!NT_STATUS_IS_OK(nt_status = - access_check_samr_object(psd, p->pipe_user.nt_user_token, - des_access, &acc_granted, "_samr_create_user"))) { + + nt_status = access_check_samr_object(psd, p->pipe_user.nt_user_token, + des_access, &acc_granted, "_samr_create_user"); + + if ( !NT_STATUS_IS_OK(nt_status) ) { return nt_status; } @@ -2563,17 +2574,15 @@ static BOOL make_enum_domains(TALLOC_CTX *ctx, SAM_ENTRY **pp_sam, if (num_sam_entries == 0) return True; - sam = (SAM_ENTRY *)talloc_zero(ctx, sizeof(SAM_ENTRY)*num_sam_entries); - uni_name = (UNISTR2 *)talloc_zero(ctx, sizeof(UNISTR2)*num_sam_entries); + sam = TALLOC_ZERO_ARRAY(ctx, SAM_ENTRY, num_sam_entries); + uni_name = TALLOC_ZERO_ARRAY(ctx, UNISTR2, num_sam_entries); if (sam == NULL || uni_name == NULL) return False; for (i = 0; i < num_sam_entries; i++) { - int len = doms[i] != NULL ? strlen(doms[i]) : 0; - - init_sam_entry(&sam[i], len, 0); - init_unistr2(&uni_name[i], doms[i], len); + init_unistr2(&uni_name[i], doms[i], UNI_FLAGS_NONE); + init_sam_entry(&sam[i], &uni_name[i], 0); } *pp_sam = sam; @@ -2620,7 +2629,7 @@ NTSTATUS _samr_enum_domains(pipes_struct *p, SAMR_Q_ENUM_DOMAINS *q_u, SAMR_R_EN api_samr_open_alias ********************************************************************/ -NTSTATUS _api_samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_ALIAS *r_u) +NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_ALIAS *r_u) { DOM_SID sid; POLICY_HND domain_pol = q_u->dom_pol; @@ -2793,6 +2802,38 @@ static BOOL set_unix_primary_group(SAM_ACCOUNT *sampass) } +/******************************************************************* + set_user_info_20 + ********************************************************************/ + +static BOOL set_user_info_20(SAM_USER_INFO_20 *id20, DOM_SID *sid) +{ + SAM_ACCOUNT *pwd = NULL; + + if (id20 == NULL) { + DEBUG(5, ("set_user_info_20: NULL id20\n")); + return False; + } + + pdb_init_sam(&pwd); + + if (!pdb_getsampwsid(pwd, sid)) { + pdb_free_sam(&pwd); + return False; + } + + copy_id20_to_sam_passwd(pwd, id20); + + /* write the change out */ + if(!pdb_update_sam_account(pwd)) { + pdb_free_sam(&pwd); + return False; + } + + pdb_free_sam(&pwd); + + return True; +} /******************************************************************* set_user_info_21 ********************************************************************/ @@ -2864,7 +2905,7 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, DOM_SID *sid) acct_ctrl = pdb_get_acct_ctrl(pwd); - if (!decode_pw_buffer((char*)id23->pass, plaintext_buf, 256, &len)) { + if (!decode_pw_buffer((char*)id23->pass, plaintext_buf, 256, &len, STR_UNICODE)) { pdb_free_sam(&pwd); return False; } @@ -2883,11 +2924,17 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, DOM_SID *sid) DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n")); } else { /* update the UNIX password */ - if (lp_unix_password_sync() ) - if(!chgpasswd(pdb_get_username(pwd), "", plaintext_buf, True)) { + if (lp_unix_password_sync() ) { + struct passwd *passwd = Get_Pwnam(pdb_get_username(pwd)); + if (!passwd) { + DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); + } + + if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { pdb_free_sam(&pwd); return False; } + } } ZERO_STRUCT(plaintext_buf); @@ -2930,7 +2977,7 @@ static BOOL set_user_info_pw(char *pass, DOM_SID *sid) ZERO_STRUCT(plaintext_buf); - if (!decode_pw_buffer(pass, plaintext_buf, 256, &len)) { + if (!decode_pw_buffer(pass, plaintext_buf, 256, &len, STR_UNICODE)) { pdb_free_sam(&pwd); return False; } @@ -2948,7 +2995,12 @@ static BOOL set_user_info_pw(char *pass, DOM_SID *sid) } else { /* update the UNIX password */ if (lp_unix_password_sync()) { - if(!chgpasswd(pdb_get_username(pwd), "", plaintext_buf, True)) { + struct passwd *passwd = Get_Pwnam(pdb_get_username(pwd)); + if (!passwd) { + DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); + } + + if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { pdb_free_sam(&pwd); return False; } @@ -2982,6 +3034,8 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE SAM_USERINFO_CTR *ctr = q_u->ctr; uint32 acc_granted; uint32 acc_required; + BOOL can_add_machines; + SE_PRIV se_machineop = SE_MACHINE_ACCOUNT; DEBUG(5, ("_samr_set_userinfo: %d\n", __LINE__)); @@ -2991,7 +3045,17 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted)) return NT_STATUS_INVALID_HANDLE; - acc_required = SA_RIGHT_USER_SET_LOC_COM | SA_RIGHT_USER_SET_ATTRIBUTES; /* This is probably wrong */ + /* the access mask depends on what the caller wants to do */ + + switch (switch_value) { + case 24: + acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY; + break; + default: + acc_required = SA_RIGHT_USER_SET_LOC_COM | SA_RIGHT_USER_SET_ATTRIBUTES; /* This is probably wrong */ + break; + } + if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, acc_required, "_samr_set_userinfo"))) { return r_u->status; } @@ -3003,20 +3067,36 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE return NT_STATUS_INVALID_INFO_CLASS; } + /* check to see if we are a domain admin */ + + can_add_machines = user_has_privileges( p->pipe_user.nt_user_token, &se_machineop ); + + DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n", + p->pipe_user_name, can_add_machines ? "" : " not")); + + /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ + + if ( can_add_machines ) + become_root(); + /* ok! user info levels (lots: see MSDEV help), off we go... */ + switch (switch_value) { case 0x12: if (!set_user_info_12(ctr->info.id12, &sid)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = NT_STATUS_ACCESS_DENIED; break; case 24: - SamOEMhash(ctr->info.id24->pass, p->session_key, 516); + if (!p->session_key.length) { + r_u->status = NT_STATUS_NO_USER_SESSION_KEY; + } + SamOEMhashBlob(ctr->info.id24->pass, 516, &p->session_key); dump_data(100, (char *)ctr->info.id24->pass, 516); if (!set_user_info_pw((char *)ctr->info.id24->pass, &sid)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = NT_STATUS_ACCESS_DENIED; break; case 25: @@ -3029,29 +3109,42 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE * info level and W2K SP2 drops down to level 23... JRA. */ - SamOEMhash(ctr->info.id25->pass, p->session_key, 532); + if (!p->session_key.length) { + r_u->status = NT_STATUS_NO_USER_SESSION_KEY; + } + SamOEMhashBlob(ctr->info.id25->pass, 532, &p->session_key); dump_data(100, (char *)ctr->info.id25->pass, 532); if (!set_user_info_pw(ctr->info.id25->pass, &sid)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = NT_STATUS_ACCESS_DENIED; break; #endif - return NT_STATUS_INVALID_INFO_CLASS; + r_u->status = NT_STATUS_INVALID_INFO_CLASS; + break; case 23: - SamOEMhash(ctr->info.id23->pass, p->session_key, 516); + if (!p->session_key.length) { + r_u->status = NT_STATUS_NO_USER_SESSION_KEY; + } + SamOEMhashBlob(ctr->info.id23->pass, 516, &p->session_key); dump_data(100, (char *)ctr->info.id23->pass, 516); if (!set_user_info_23(ctr->info.id23, &sid)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = NT_STATUS_ACCESS_DENIED; break; default: - return NT_STATUS_INVALID_INFO_CLASS; + r_u->status = NT_STATUS_INVALID_INFO_CLASS; } + + if ( can_add_machines ) + unbecome_root(); + + /* ================ END SeMachineAccountPrivilege BLOCK ================ */ + return r_u->status; } @@ -3067,6 +3160,8 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ uint16 switch_value = q_u->switch_value; uint32 acc_granted; uint32 acc_required; + BOOL can_add_machines; + SE_PRIV se_machineop = SE_MACHINE_ACCOUNT; DEBUG(5, ("samr_reply_set_userinfo2: %d\n", __LINE__)); @@ -3090,25 +3185,47 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ switch_value=ctr->switch_value; + /* check to see if we are a domain admin */ + + can_add_machines = user_has_privileges( p->pipe_user.nt_user_token, &se_machineop ); + + DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n", + p->pipe_user_name, can_add_machines ? "" : " not")); + + /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ + + if ( can_add_machines ) + become_root(); + /* ok! user info levels (lots: see MSDEV help), off we go... */ + switch (switch_value) { case 21: if (!set_user_info_21(ctr->info.id21, &sid)) return NT_STATUS_ACCESS_DENIED; break; + case 20: + if (!set_user_info_20(ctr->info.id20, &sid)) + r_u->status = NT_STATUS_ACCESS_DENIED; + break; case 16: if (!set_user_info_10(ctr->info.id10, &sid)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = NT_STATUS_ACCESS_DENIED; break; case 18: /* Used by AS/U JRA. */ if (!set_user_info_12(ctr->info.id12, &sid)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = NT_STATUS_ACCESS_DENIED; break; default: - return NT_STATUS_INVALID_INFO_CLASS; + r_u->status = NT_STATUS_INVALID_INFO_CLASS; } + if ( can_add_machines ) + unbecome_root(); + + /* ================ END SeMachineAccountPrivilege BLOCK ================ */ + return r_u->status; } @@ -3118,31 +3235,19 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ NTSTATUS _samr_query_useraliases(pipes_struct *p, SAMR_Q_QUERY_USERALIASES *q_u, SAMR_R_QUERY_USERALIASES *r_u) { - int num_groups = 0, tmp_num_groups=0; - uint32 *rids=NULL, *new_rids=NULL, *tmp_rids=NULL; + int num_groups = 0; + uint32 *rids=NULL; struct samr_info *info = NULL; - int i,j; + int i; NTSTATUS ntstatus1; NTSTATUS ntstatus2; - /* until i see a real useraliases query, we fack one up */ + DOM_SID *members; + DOM_SID *aliases; + int num_aliases; + BOOL res; - /* I have seen one, JFM 2/12/2001 */ - /* - * Explanation of what this call does: - * for all the SID given in the request: - * return a list of alias (local groups) - * that have those SID as members. - * - * and that's the alias in the domain specified - * in the policy_handle - * - * if the policy handle is on an incorrect sid - * for example a user's sid - * we should reply NT_STATUS_OBJECT_TYPE_MISMATCH - */ - r_u->status = NT_STATUS_OK; DEBUG(5,("_samr_query_useraliases: %d\n", __LINE__)); @@ -3165,40 +3270,42 @@ NTSTATUS _samr_query_useraliases(pipes_struct *p, SAMR_Q_QUERY_USERALIASES *q_u, !sid_check_is_builtin(&info->sid)) return NT_STATUS_OBJECT_TYPE_MISMATCH; + members = TALLOC_ARRAY(p->mem_ctx, DOM_SID, q_u->num_sids1); - for (i=0; inum_sids1; i++) { + if (members == NULL) + return NT_STATUS_NO_MEMORY; - r_u->status=get_alias_user_groups(p->mem_ctx, &info->sid, &tmp_num_groups, &tmp_rids, &(q_u->sid[i].sid)); + for (i=0; inum_sids1; i++) + sid_copy(&members[i], &q_u->sid[i].sid); - /* - * if there is an error, we just continue as - * it can be an unfound user or group - */ - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(10,("_samr_query_useraliases: an error occured while getting groups\n")); - continue; - } + become_root(); + res = pdb_enum_alias_memberships(members, + q_u->num_sids1, &aliases, + &num_aliases); + unbecome_root(); + + if (!res) + return NT_STATUS_UNSUCCESSFUL; + + rids = NULL; + num_groups = 0; + + for (i=0; isid, &aliases[i], &rid)) continue; - } - new_rids=(uint32 *)talloc_realloc(p->mem_ctx, rids, (num_groups+tmp_num_groups)*sizeof(uint32)); - if (new_rids==NULL) { - DEBUG(0,("_samr_query_useraliases: could not realloc memory\n")); + rids = TALLOC_REALLOC_ARRAY(p->mem_ctx, rids, uint32, num_groups+1); + + if (rids == NULL) return NT_STATUS_NO_MEMORY; - } - rids=new_rids; - for (j=0; jstatus; } - - sid_copy(&als_sid, &alias_sid); - sid_to_string(alias_sid_str, &alias_sid); - sid_split_rid(&alias_sid, &alias_rid); - DEBUG(10, ("sid is %s\n", alias_sid_str)); + DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid))); - if (sid_equal(&alias_sid, &global_sid_Builtin)) { - DEBUG(10, ("lookup on Builtin SID (S-1-5-32)\n")); - if(!get_builtin_group_from_sid(als_sid, &map)) - return NT_STATUS_NO_SUCH_ALIAS; - } else { - if (sid_equal(&alias_sid, get_global_sam_sid())) { - DEBUG(10, ("lookup on Server SID\n")); - if(!get_local_group_from_sid(als_sid, &map)) - return NT_STATUS_NO_SUCH_ALIAS; - } - } - - if(!get_uid_list_of_group(map.gid, &uid, &num_uids)) + if (!pdb_enum_aliasmem(&alias_sid, &sids, &num_sids)) return NT_STATUS_NO_SUCH_ALIAS; - DEBUG(10, ("sid is %s\n", alias_sid_str)); - sid = (DOM_SID2 *)talloc_zero(p->mem_ctx, sizeof(DOM_SID2) * num_uids); - if (num_uids!=0 && sid == NULL) + sid = TALLOC_ZERO_ARRAY(p->mem_ctx, DOM_SID2, num_sids); + if (num_sids!=0 && sid == NULL) { + SAFE_FREE(sids); return NT_STATUS_NO_MEMORY; + } - for (i = 0; i < num_uids; i++) { - struct passwd *pass; - uint32 rid; + for (i = 0; i < num_sids; i++) { + init_dom_sid2(&sid[i], &sids[i]); + } - sid_copy(&temp_sid, get_global_sam_sid()); + init_samr_r_query_aliasmem(r_u, num_sids, sid, NT_STATUS_OK); - pass = getpwuid_alloc(uid[i]); - if (!pass) continue; + SAFE_FREE(sids); - if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_user))) { - passwd_free(&pass); - continue; - } + return NT_STATUS_OK; +} - become_root(); - check = pdb_getsampwnam(sam_user, pass->pw_name); - unbecome_root(); - - if (check != True) { - pdb_free_sam(&sam_user); - passwd_free(&pass); - continue; - } +static void add_uid_to_array_unique(uid_t uid, uid_t **uids, int *num) +{ + int i; + + for (i=0; i<*num; i++) { + if ((*uids)[i] == uid) + return; + } - rid = pdb_get_user_rid(sam_user); - if (rid == 0) { - pdb_free_sam(&sam_user); - passwd_free(&pass); + *uids = SMB_REALLOC_ARRAY(*uids, uid_t, *num+1); + + if (*uids == NULL) + return; + + (*uids)[*num] = uid; + *num += 1; +} + + +static BOOL get_memberuids(gid_t gid, uid_t **uids, int *num) +{ + struct group *grp; + char **gr; + struct sys_pwent *userlist, *user; + + *uids = NULL; + *num = 0; + + /* We only look at our own sam, so don't care about imported stuff */ + + winbind_off(); + + if ((grp = getgrgid(gid)) == NULL) { + winbind_on(); + return False; + } + + /* Primary group members */ + + userlist = getpwent_list(); + + for (user = userlist; user != NULL; user = user->next) { + if (user->pw_gid != gid) continue; - } + add_uid_to_array_unique(user->pw_uid, uids, num); + } - pdb_free_sam(&sam_user); - passwd_free(&pass); + pwent_free(userlist); - sid_append_rid(&temp_sid, rid); - - init_dom_sid2(&sid[i], &temp_sid); + /* Secondary group members */ + + for (gr = grp->gr_mem; (*gr != NULL) && ((*gr)[0] != '\0'); gr += 1) { + struct passwd *pw = getpwnam(*gr); + + if (pw == NULL) + continue; + add_uid_to_array_unique(pw->pw_uid, uids, num); } - DEBUG(10, ("sid is %s\n", alias_sid_str)); - init_samr_r_query_aliasmem(r_u, num_uids, sid, NT_STATUS_OK); + winbind_on(); - return NT_STATUS_OK; -} + return True; +} /********************************************************************* _samr_query_groupmem @@ -3312,20 +3427,16 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_ NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_R_QUERY_GROUPMEM *r_u) { - int num_uids = 0; - int i; + int final_num_rids, i; DOM_SID group_sid; - uint32 group_rid; fstring group_sid_str; - uid_t *uid=NULL; - - GROUP_MAP map; + uid_t *uids; + int num; + gid_t gid; uint32 *rid=NULL; uint32 *attr=NULL; - SAM_ACCOUNT *sam_user = NULL; - BOOL check; uint32 acc_granted; /* find the policy handle. open a policy on it. */ @@ -3336,68 +3447,56 @@ NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_ return r_u->status; } - /* todo: change to use sid_compare_front */ - - sid_split_rid(&group_sid, &group_rid); sid_to_string(group_sid_str, &group_sid); DEBUG(10, ("sid is %s\n", group_sid_str)); - /* can we get a query for an SID outside our domain ? */ - if (!sid_equal(&group_sid, get_global_sam_sid())) + if (!sid_check_is_in_our_domain(&group_sid)) { + DEBUG(3, ("sid %s is not in our domain\n", group_sid_str)); return NT_STATUS_NO_SUCH_GROUP; + } - sid_append_rid(&group_sid, group_rid); DEBUG(10, ("lookup on Domain SID\n")); - if(!get_domain_group_from_sid(group_sid, &map)) + if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid))) return NT_STATUS_NO_SUCH_GROUP; - if(!get_uid_list_of_group(map.gid, &uid, &num_uids)) + if(!get_memberuids(gid, &uids, &num)) return NT_STATUS_NO_SUCH_GROUP; - rid=talloc_zero(p->mem_ctx, sizeof(uint32)*num_uids); - attr=talloc_zero(p->mem_ctx, sizeof(uint32)*num_uids); + rid=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num); + attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num); - if (num_uids!=0 && (rid==NULL || attr==NULL)) + if (num!=0 && (rid==NULL || attr==NULL)) return NT_STATUS_NO_MEMORY; - for (i=0; ipw_name); - unbecome_root(); - - if (check != True) { - pdb_free_sam(&sam_user); - passwd_free(&pass); - continue; - } - - urid = pdb_get_user_rid(sam_user); - if (urid == 0) { - pdb_free_sam(&sam_user); - passwd_free(&pass); + if (!sid_check_is_in_our_domain(&sid)) { + DEBUG(1, ("Inconsistent SAM -- group member uid not " + "in our domain\n")); continue; } - pdb_free_sam(&sam_user); - passwd_free(&pass); + sid_peek_rid(&sid, &rid[final_num_rids]); + + /* Hmm. In a trace I got the constant 7 here from NT. */ + attr[final_num_rids] = SID_NAME_USER; - rid[i] = urid; - attr[i] = SID_NAME_USER; + final_num_rids += 1; } - init_samr_r_query_groupmem(r_u, num_uids, rid, attr, NT_STATUS_OK); + SAFE_FREE(uids); + + init_samr_r_query_groupmem(r_u, final_num_rids, rid, attr, + NT_STATUS_OK); return NT_STATUS_OK; } @@ -3409,15 +3508,6 @@ NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_ADD_ALIASMEM *r_u) { DOM_SID alias_sid; - fstring alias_sid_str; - uid_t uid; - struct passwd *pwd; - struct group *grp; - fstring grp_name; - GROUP_MAP map; - NTSTATUS ret; - SAM_ACCOUNT *sam_user = NULL; - BOOL check; uint32 acc_granted; /* Find the policy handle. Open a policy on it. */ @@ -3428,74 +3518,11 @@ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_AD return r_u->status; } - sid_to_string(alias_sid_str, &alias_sid); - DEBUG(10, ("sid is %s\n", alias_sid_str)); - - if (sid_compare(&alias_sid, get_global_sam_sid())>0) { - DEBUG(10, ("adding member on Server SID\n")); - if(!get_local_group_from_sid(alias_sid, &map)) - return NT_STATUS_NO_SUCH_ALIAS; - - } else { - if (sid_compare(&alias_sid, &global_sid_Builtin)>0) { - DEBUG(10, ("adding member on BUILTIN SID\n")); - if( !get_local_group_from_sid(alias_sid, &map)) - return NT_STATUS_NO_SUCH_ALIAS; - - } else - return NT_STATUS_NO_SUCH_ALIAS; - } - - ret = pdb_init_sam(&sam_user); - if (!NT_STATUS_IS_OK(ret)) - return ret; - - check = pdb_getsampwsid(sam_user, &q_u->sid.sid); - - if (check != True) { - pdb_free_sam(&sam_user); - return NT_STATUS_NO_SUCH_USER; - } - - /* check a real user exist before we run the script to add a user to a group */ - if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sam_user), &uid))) { - pdb_free_sam(&sam_user); - return NT_STATUS_NO_SUCH_USER; - } - - pdb_free_sam(&sam_user); - - if ((pwd=getpwuid_alloc(uid)) == NULL) { - return NT_STATUS_NO_SUCH_USER; - } - - if ((grp=getgrgid(map.gid)) == NULL) { - passwd_free(&pwd); - return NT_STATUS_NO_SUCH_ALIAS; - } - - /* we need to copy the name otherwise it's overloaded in user_in_group_list */ - fstrcpy(grp_name, grp->gr_name); - - /* if the user is already in the group */ - if(user_in_unix_group_list(pwd->pw_name, grp_name)) { - passwd_free(&pwd); - return NT_STATUS_MEMBER_IN_ALIAS; - } - - /* - * ok, the group exist, the user exist, the user is not in the group, - * we can (finally) add it to the group ! - */ - smb_add_user_group(grp_name, pwd->pw_name); + DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid))); - /* check if the user has been added then ... */ - if(!user_in_unix_group_list(pwd->pw_name, grp_name)) { - passwd_free(&pwd); - return NT_STATUS_MEMBER_NOT_IN_ALIAS; /* don't know what to reply else */ - } + if (!pdb_add_aliasmem(&alias_sid, &q_u->sid.sid)) + return NT_STATUS_ACCESS_DENIED; - passwd_free(&pwd); return NT_STATUS_OK; } @@ -3506,11 +3533,6 @@ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_AD NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DEL_ALIASMEM *r_u) { DOM_SID alias_sid; - fstring alias_sid_str; - struct group *grp; - fstring grp_name; - GROUP_MAP map; - SAM_ACCOUNT *sam_pass=NULL; uint32 acc_granted; /* Find the policy handle. Open a policy on it. */ @@ -3521,47 +3543,12 @@ NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DE return r_u->status; } - sid_to_string(alias_sid_str, &alias_sid); - DEBUG(10, ("_samr_del_aliasmem:sid is %s\n", alias_sid_str)); - - if (!sid_check_is_in_our_domain(&alias_sid) && - !sid_check_is_in_builtin(&alias_sid)) { - DEBUG(10, ("_samr_del_aliasmem:invalid alias group\n")); - return NT_STATUS_NO_SUCH_ALIAS; - } - - if( !get_local_group_from_sid(alias_sid, &map)) - return NT_STATUS_NO_SUCH_ALIAS; - - if ((grp=getgrgid(map.gid)) == NULL) - return NT_STATUS_NO_SUCH_ALIAS; - - /* we need to copy the name otherwise it's overloaded in user_in_unix_group_list */ - fstrcpy(grp_name, grp->gr_name); - - /* check if the user exists before trying to remove it from the group */ - pdb_init_sam(&sam_pass); - if(!pdb_getsampwsid(sam_pass, &q_u->sid.sid)) { - DEBUG(5,("_samr_del_aliasmem:User %s doesn't exist.\n", pdb_get_username(sam_pass))); - pdb_free_sam(&sam_pass); - return NT_STATUS_NO_SUCH_USER; - } - - /* if the user is not in the group */ - if(!user_in_unix_group_list(pdb_get_username(sam_pass), grp_name)) { - pdb_free_sam(&sam_pass); - return NT_STATUS_MEMBER_IN_ALIAS; - } - - smb_delete_user_group(grp_name, pdb_get_username(sam_pass)); - - /* check if the user has been removed then ... */ - if(user_in_unix_group_list(pdb_get_username(sam_pass), grp_name)) { - pdb_free_sam(&sam_pass); - return NT_STATUS_MEMBER_NOT_IN_ALIAS; /* don't know what to reply else */ - } + DEBUG(10, ("_samr_del_aliasmem:sid is %s\n", + sid_string_static(&alias_sid))); - pdb_free_sam(&sam_pass); + if (!pdb_del_aliasmem(&alias_sid, &q_u->sid.sid)) + return NT_STATUS_ACCESS_DENIED; + return NT_STATUS_OK; } @@ -3755,7 +3742,7 @@ static int smb_delete_user(const char *unix_user) pstrcpy(del_script, lp_deluser_script()); if (! *del_script) return -1; - all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); + all_string_sub(del_script, "%u", unix_user, sizeof(del_script)); ret = smbrun(del_script,NULL); DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); @@ -3794,7 +3781,14 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM return NT_STATUS_NO_SUCH_USER; } - /* delete the unix side */ + /* First delete the samba side */ + if (!pdb_delete_sam_account(sam_pass)) { + DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); + pdb_free_sam(&sam_pass); + return NT_STATUS_CANNOT_DELETE; + } + + /* Now delete the unix side */ /* * note: we don't check if the delete really happened * as the script is not necessary present @@ -3802,13 +3796,7 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM */ smb_delete_user(pdb_get_username(sam_pass)); - /* and delete the samba side */ - if (!pdb_delete_sam_account(sam_pass)) { - DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); - pdb_free_sam(&sam_pass); - return NT_STATUS_CANNOT_DELETE; - } - + pdb_free_sam(&sam_pass); if (!close_policy_hnd(p, &q_u->user_pol)) @@ -3863,6 +3851,10 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S if ( (grp=getgrgid(gid)) == NULL) return NT_STATUS_NO_SUCH_GROUP; + /* delete mapping first */ + if(!pdb_delete_group_mapping_entry(group_sid)) + return NT_STATUS_ACCESS_DENIED; + /* we can delete the UNIX group */ smb_delete_group(grp->gr_name); @@ -3870,8 +3862,6 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S if ( (grp=getgrgid(gid)) != NULL) return NT_STATUS_ACCESS_DENIED; - if(!pdb_delete_group_mapping_entry(group_sid)) - return NT_STATUS_ACCESS_DENIED; if (!close_policy_hnd(p, &q_u->group_pol)) return NT_STATUS_OBJECT_NAME_INVALID; @@ -3886,12 +3876,6 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S NTSTATUS _samr_delete_dom_alias(pipes_struct *p, SAMR_Q_DELETE_DOM_ALIAS *q_u, SAMR_R_DELETE_DOM_ALIAS *r_u) { DOM_SID alias_sid; - DOM_SID dom_sid; - uint32 alias_rid; - fstring alias_sid_str; - gid_t gid; - struct group *grp; - GROUP_MAP map; uint32 acc_granted; DEBUG(5, ("_samr_delete_dom_alias: %d\n", __LINE__)); @@ -3903,38 +3887,18 @@ NTSTATUS _samr_delete_dom_alias(pipes_struct *p, SAMR_Q_DELETE_DOM_ALIAS *q_u, S 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; } - - sid_copy(&dom_sid, &alias_sid); - sid_to_string(alias_sid_str, &dom_sid); - sid_split_rid(&dom_sid, &alias_rid); - DEBUG(10, ("sid is %s\n", alias_sid_str)); + DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid))); - /* we check if it's our SID before deleting */ - if (!sid_equal(&dom_sid, get_global_sam_sid())) + if (!sid_check_is_in_our_domain(&alias_sid)) return NT_STATUS_NO_SUCH_ALIAS; - + DEBUG(10, ("lookup on Local SID\n")); - if(!get_local_group_from_sid(alias_sid, &map)) - return NT_STATUS_NO_SUCH_ALIAS; - - gid=map.gid; - - /* check if group really exists */ - if ( (grp=getgrgid(gid)) == NULL) - return NT_STATUS_NO_SUCH_ALIAS; - - /* we can delete the UNIX group */ - smb_delete_group(grp->gr_name); - - /* check if the group has been successfully deleted */ - if ( (grp=getgrgid(gid)) != NULL) + /* Have passdb delete the alias */ + if (!pdb_delete_alias(&alias_sid)) return NT_STATUS_ACCESS_DENIED; - /* don't check if we removed it as it could be an un-mapped group */ - pdb_delete_group_mapping_entry(alias_sid); - if (!close_policy_hnd(p, &q_u->alias_pol)) return NT_STATUS_OBJECT_NAME_INVALID; @@ -4012,11 +3976,11 @@ NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, S DOM_SID dom_sid; DOM_SID info_sid; fstring name; - fstring sid_string; struct group *grp; struct samr_info *info; uint32 acc_granted; gid_t gid; + NTSTATUS result; /* Find the policy handle. Open a policy on it. */ if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &dom_sid, &acc_granted)) @@ -4033,26 +3997,20 @@ NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, S unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1); - /* check if group already exists */ - if ( (grp=getgrnam(name)) != NULL) - return NT_STATUS_GROUP_EXISTS; + /* Have passdb create the alias */ + result = pdb_create_alias(name, &r_u->rid); - /* we can create the UNIX group */ - if (smb_create_group(name, &gid) != 0) - return NT_STATUS_ACCESS_DENIED; - - /* check if the group has been successfully created */ - if ((grp=getgrgid(gid)) == NULL) - return NT_STATUS_ACCESS_DENIED; - - r_u->rid=pdb_gid_to_group_rid(grp->gr_gid); + if (!NT_STATUS_IS_OK(result)) + return result; sid_copy(&info_sid, get_global_sam_sid()); sid_append_rid(&info_sid, r_u->rid); - sid_to_string(sid_string, &info_sid); - /* add the group to the mapping table */ - if(!add_initial_entry(grp->gr_gid, sid_string, SID_NAME_ALIAS, name, NULL)) + if (!NT_STATUS_IS_OK(sid_to_gid(&info_sid, &gid))) + return NT_STATUS_ACCESS_DENIED; + + /* check if the group has been successfully created */ + if ((grp=getgrgid(gid)) == NULL) return NT_STATUS_ACCESS_DENIED; if ((info = get_samr_info_by_sid(&info_sid)) == NULL) @@ -4076,10 +4034,12 @@ NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAM { DOM_SID group_sid; GROUP_MAP map; - uid_t *uid=NULL; - int num_uids=0; + DOM_SID *sids=NULL; + uid_t *uids; + int num=0; GROUP_INFO_CTR *ctr; uint32 acc_granted; + BOOL ret; if (!get_lsa_policy_samr_sid(p, &q_u->pol, &group_sid, &acc_granted)) return NT_STATUS_INVALID_HANDLE; @@ -4088,20 +4048,24 @@ NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAM return r_u->status; } - if (!get_domain_group_from_sid(group_sid, &map)) + become_root(); + ret = get_domain_group_from_sid(group_sid, &map); + unbecome_root(); + if (!ret) return NT_STATUS_INVALID_HANDLE; - ctr=(GROUP_INFO_CTR *)talloc_zero(p->mem_ctx, sizeof(GROUP_INFO_CTR)); + ctr=TALLOC_ZERO_P(p->mem_ctx, GROUP_INFO_CTR); if (ctr==NULL) return NT_STATUS_NO_MEMORY; switch (q_u->switch_level) { case 1: ctr->switch_value1 = 1; - if(!get_uid_list_of_group(map.gid, &uid, &num_uids)) + if(!get_memberuids(map.gid, &uids, &num)) return NT_STATUS_NO_SUCH_GROUP; - init_samr_group_info1(&ctr->group.info1, map.nt_name, map.comment, num_uids); - SAFE_FREE(uid); + SAFE_FREE(uids); + init_samr_group_info1(&ctr->group.info1, map.nt_name, map.comment, num); + SAFE_FREE(sids); break; case 3: ctr->switch_value1 = 3; @@ -4172,7 +4136,7 @@ NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_ NTSTATUS _samr_set_aliasinfo(pipes_struct *p, SAMR_Q_SET_ALIASINFO *q_u, SAMR_R_SET_ALIASINFO *r_u) { DOM_SID group_sid; - GROUP_MAP map; + struct acct_info info; ALIAS_INFO_CTR *ctr; uint32 acc_granted; @@ -4183,21 +4147,20 @@ NTSTATUS _samr_set_aliasinfo(pipes_struct *p, SAMR_Q_SET_ALIASINFO *q_u, SAMR_R_ return r_u->status; } - if (!get_local_group_from_sid(group_sid, &map)) - return NT_STATUS_NO_SUCH_GROUP; - ctr=&q_u->ctr; switch (ctr->switch_value1) { case 3: - unistr2_to_ascii(map.comment, &(ctr->alias.info3.uni_acct_desc), sizeof(map.comment)-1); + unistr2_to_ascii(info.acct_desc, + &(ctr->alias.info3.uni_acct_desc), + sizeof(info.acct_desc)-1); break; default: return NT_STATUS_INVALID_INFO_CLASS; } - if(!pdb_update_group_mapping_entry(&map)) { - return NT_STATUS_NO_SUCH_GROUP; + if(!pdb_set_aliasinfo(&group_sid, &info)) { + return NT_STATUS_ACCESS_DENIED; } return NT_STATUS_OK; @@ -4236,10 +4199,11 @@ NTSTATUS _samr_open_group(pipes_struct *p, SAMR_Q_OPEN_GROUP *q_u, SAMR_R_OPEN_G struct samr_info *info; SEC_DESC *psd = NULL; uint32 acc_granted; - uint32 des_access; + uint32 des_access = q_u->access_mask; size_t sd_size; NTSTATUS status; fstring sid_string; + BOOL ret; if (!get_lsa_policy_samr_sid(p, &q_u->domain_pol, &sid, &acc_granted)) return NT_STATUS_INVALID_HANDLE; @@ -4274,7 +4238,10 @@ NTSTATUS _samr_open_group(pipes_struct *p, SAMR_Q_OPEN_GROUP *q_u, SAMR_R_OPEN_G DEBUG(10, ("_samr_open_group:Opening SID: %s\n", sid_string)); /* check if that group really exists */ - if (!get_domain_group_from_sid(info->sid, &map)) + become_root(); + ret = get_domain_group_from_sid(info->sid, &map); + unbecome_root(); + if (!ret) return NT_STATUS_NO_SUCH_GROUP; /* get a (unique) handle. open a policy on it. */ @@ -4285,75 +4252,114 @@ NTSTATUS _samr_open_group(pipes_struct *p, SAMR_Q_OPEN_GROUP *q_u, SAMR_R_OPEN_G } /********************************************************************* - _samr_remove_user_foreign_domain + _samr_remove_sid_foreign_domain *********************************************************************/ -NTSTATUS _samr_remove_user_foreign_domain(pipes_struct *p, - SAMR_Q_REMOVE_USER_FOREIGN_DOMAIN *q_u, - SAMR_R_REMOVE_USER_FOREIGN_DOMAIN *r_u) +NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p, + SAMR_Q_REMOVE_SID_FOREIGN_DOMAIN *q_u, + SAMR_R_REMOVE_SID_FOREIGN_DOMAIN *r_u) { - DOM_SID user_sid, dom_sid; + DOM_SID delete_sid, alias_sid; SAM_ACCOUNT *sam_pass=NULL; uint32 acc_granted; + GROUP_MAP map; + BOOL is_user = False; + NTSTATUS result; + enum SID_NAME_USE type = SID_NAME_UNKNOWN; - sid_copy( &user_sid, &q_u->sid.sid ); + sid_copy( &delete_sid, &q_u->sid.sid ); - DEBUG(5,("_samr_remove_user_foreign_domain: removing user [%s]\n", - sid_string_static(&user_sid))); + DEBUG(5,("_samr_remove_sid_foreign_domain: removing SID [%s]\n", + sid_string_static(&delete_sid))); /* Find the policy handle. Open a policy on it. */ - if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &dom_sid, &acc_granted)) + if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &alias_sid, &acc_granted)) return NT_STATUS_INVALID_HANDLE; + + result = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS, + "_samr_remove_sid_foreign_domain"); - if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, - STD_RIGHT_DELETE_ACCESS, "_samr_remove_user_foreign_domain"))) - { - return r_u->status; - } + if (!NT_STATUS_IS_OK(result)) + return result; + + DEBUG(8, ("_samr_remove_sid_foreign_domain:sid is %s\n", + sid_string_static(&alias_sid))); - if ( !sid_check_is_in_our_domain(&user_sid) ) { - DEBUG(5,("_samr_remove_user_foreign_domain: user not is our domain!\n")); - return NT_STATUS_NO_SUCH_USER; + /* make sure we can handle this */ + + if ( sid_check_is_domain(&alias_sid) ) + type = SID_NAME_DOM_GRP; + else if ( sid_check_is_builtin(&alias_sid) ) + type = SID_NAME_ALIAS; + + if ( type == SID_NAME_UNKNOWN ) { + DEBUG(10, ("_samr_remove_sid_foreign_domain: can't operate on what we don't own!\n")); + return NT_STATUS_OK; } /* check if the user exists before trying to delete */ pdb_init_sam(&sam_pass); - if ( !pdb_getsampwsid(sam_pass, &user_sid) ) { + if ( pdb_getsampwsid(sam_pass, &delete_sid) ) { + is_user = True; + } else { + /* maybe it is a group */ + if( !pdb_getgrsid(&map, delete_sid) ) { + DEBUG(3,("_samr_remove_sid_foreign_domain: %s is not a user or a group!\n", + sid_string_static(&delete_sid))); + result = NT_STATUS_INVALID_SID; + goto done; + } + } - DEBUG(5,("_samr_remove_user_foreign_domain:User %s doesn't exist.\n", - sid_string_static(&user_sid))); - - pdb_free_sam(&sam_pass); + /* we can only delete a user from a group since we don't have + nested groups anyways. So in the latter case, just say OK */ + + if ( is_user ) { + GROUP_MAP *mappings = NULL; + int num_groups, i; + struct group *grp2; - return NT_STATUS_NO_SUCH_USER; - } + if ( pdb_enum_group_mapping(type, &mappings, &num_groups, False) && num_groups>0 ) { + + /* interate over the groups */ + for ( i=0; igr_name) ) + continue; + + smb_delete_user_group(grp2->gr_name, pdb_get_username(sam_pass)); + + if ( user_in_unix_group_list(pdb_get_username(sam_pass), grp2->gr_name) ) { + /* should we fail here ? */ + DEBUG(0,("_samr_remove_sid_foreign_domain: Delete user [%s] from group [%s] failed!\n", + pdb_get_username(sam_pass), grp2->gr_name )); + continue; + } + + DEBUG(10,("_samr_remove_sid_foreign_domain: Removed user [%s] from group [%s]!\n", + pdb_get_username(sam_pass), grp2->gr_name )); + } + + SAFE_FREE(mappings); + } } + result = NT_STATUS_OK; +done: + pdb_free_sam(&sam_pass); - return NT_STATUS_OK; + return result; } /******************************************************************* @@ -4379,7 +4385,7 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW uint32 account_policy_temp; - if ((ctr = (SAM_UNK_CTR *)talloc_zero(p->mem_ctx, sizeof(SAM_UNK_CTR))) == NULL) + if ((ctr = TALLOC_ZERO_P(p->mem_ctx, SAM_UNK_CTR)) == NULL) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(ctr); @@ -4434,9 +4440,14 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW num_groups=info->disp_info.num_group_account; free_samr_db(info); + account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp); + u_logout = account_policy_temp; + + unix_to_nt_time_abs(&nt_logout, u_logout); + /* The time call below is to get a sequence number for the sam. FIXME !!! JRA. */ - init_unk_info2(&ctr->info.inf2, lp_workgroup(), global_myname(), (uint32) time(NULL), - num_users, num_groups, num_aliases); + init_unk_info2(&ctr->info.inf2, "", lp_workgroup(), global_myname(), (uint32) time(NULL), + num_users, num_groups, num_aliases, nt_logout); break; case 0x03: account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp); @@ -4455,12 +4466,17 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW case 0x07: init_unk_info7(&ctr->info.inf7); break; + case 0x08: + init_unk_info8(&ctr->info.inf8, (uint32) time(NULL)); + break; case 0x0c: account_policy_get(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp); u_lock_duration = account_policy_temp; + if (u_lock_duration != -1) + u_lock_duration *= 60; account_policy_get(AP_RESET_COUNT_TIME, &account_policy_temp); - u_reset_time = account_policy_temp; + u_reset_time = account_policy_temp * 60; account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp); lockout = account_policy_temp; @@ -4526,7 +4542,9 @@ NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R break; case 0x0c: u_lock_duration=nt_time_to_unix_abs(&q_u->ctr->info.inf12.duration); - u_reset_time=nt_time_to_unix_abs(&q_u->ctr->info.inf12.reset_count); + if (u_lock_duration != -1) + u_lock_duration /= 60; + u_reset_time=nt_time_to_unix_abs(&q_u->ctr->info.inf12.reset_count)/60; account_policy_set(AP_LOCK_ACCOUNT_DURATION, (int)u_lock_duration); account_policy_set(AP_RESET_COUNT_TIME, (int)u_reset_time); @@ -4542,4 +4560,3 @@ NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R return r_u->status; } -