X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Frpc_server%2Fsrv_lsa_nt.c;h=e5154dbb539204858bb00e5a976a7e68df2624c7;hb=46e5effea948931509283cb84b27007d34b521c8;hp=fb6538db39f9d8b14fa8ab8bc5945f906b5294f2;hpb=04858cd7025bb4c3fdb34a2795568a6b52004c3b;p=samba.git diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index fb6538db39f..e5154dbb539 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -1,4 +1,4 @@ -/* +/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-1997, @@ -6,7 +6,8 @@ * Copyright (C) Paul Ashton 1997, * Copyright (C) Jeremy Allison 2001, * Copyright (C) Rafal Szczesniak 2002, - * Copyright (C) Jim McDonough 2002. + * Copyright (C) Jim McDonough 2002, + * Copyright (C) Simo Sorce 2003. * * 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 @@ -61,7 +62,12 @@ Init dom_query static void init_dom_query(DOM_QUERY *d_q, const char *dom_name, DOM_SID *dom_sid) { - int domlen = (dom_name != NULL) ? strlen(dom_name) : 0; + d_q->buffer_dom_name = (dom_name != NULL) ? 1 : 0; /* domain buffer pointer */ + d_q->buffer_dom_sid = (dom_sid != NULL) ? 1 : 0; /* domain sid pointer */ + + /* this string is supposed to be non-null terminated. */ + /* But the maxlen in this UNISTR2 must include the terminating null. */ + init_unistr2(&d_q->uni_domain_name, dom_name, UNI_BROKEN_NON_NULL); /* * I'm not sure why this really odd combination of length @@ -71,14 +77,15 @@ static void init_dom_query(DOM_QUERY *d_q, const char *dom_name, DOM_SID *dom_si * a domain with both odd and even length names... JRA. */ - d_q->uni_dom_str_len = domlen ? ((domlen + 1) * 2) : 0; - d_q->uni_dom_max_len = domlen * 2; - d_q->buffer_dom_name = domlen != 0 ? 1 : 0; /* domain buffer pointer */ - d_q->buffer_dom_sid = dom_sid != NULL ? 1 : 0; /* domain sid pointer */ + /* + * IMPORTANT NOTE !!!! + * The two fields below probably are reversed in meaning, ie. + * the first field is probably the str_len, the second the max + * len. Both are measured in bytes anyway. + */ - /* this string is supposed to be character short */ - init_unistr2(&d_q->uni_domain_name, dom_name, domlen); - d_q->uni_domain_name.uni_max_len++; + d_q->uni_dom_str_len = d_q->uni_domain_name.uni_max_len * 2; + d_q->uni_dom_max_len = d_q->uni_domain_name.uni_str_len * 2; if (dom_sid != NULL) init_dom_sid2(&d_q->dom_sid, dom_sid); @@ -91,12 +98,11 @@ static void init_dom_query(DOM_QUERY *d_q, const char *dom_name, DOM_SID *dom_si static int init_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid) { int num = 0; - int len; if (dom_name != NULL) { for (num = 0; num < ref->num_ref_doms_1; num++) { fstring domname; - rpcstr_pull(domname, &ref->ref_dom[num].uni_dom_name, sizeof(domname), -1, 0); + rpcstr_pull(domname, ref->ref_dom[num].uni_dom_name.buffer, sizeof(domname), -1, 0); if (strequal(domname, dom_name)) return num; } @@ -114,14 +120,11 @@ static int init_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid) ref->max_entries = MAX_REF_DOMAINS; ref->num_ref_doms_2 = num+1; - len = (dom_name != NULL) ? strlen(dom_name) : 0; - if(dom_name != NULL && len == 0) - len = 1; - - init_uni_hdr(&ref->hdr_ref_dom[num].hdr_dom_name, len); ref->hdr_ref_dom[num].ptr_dom_sid = dom_sid != NULL ? 1 : 0; - init_unistr2(&ref->ref_dom[num].uni_dom_name, dom_name, len); + init_unistr2(&ref->ref_dom[num].uni_dom_name, dom_name, UNI_FLAGS_NONE); + init_uni_hdr(&ref->hdr_ref_dom[num].hdr_dom_name, &ref->ref_dom[num].uni_dom_name); + init_dom_sid2(&ref->ref_dom[num].ref_dom, dom_sid ); return num; @@ -163,6 +166,19 @@ static void init_lsa_rid2s(DOM_R_REF *ref, DOM_RID2 *rid2, 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); + } + +#if 0 /* This is not true. */ + if (name_type == SID_NAME_WKN_GRP) { + /* BUILTIN aliases are still aliases :-) */ + name_type = SID_NAME_ALIAS; + } +#endif + DEBUG(5, ("init_lsa_rid2s: %s\n", status ? "found" : "not found")); @@ -172,7 +188,7 @@ static void init_lsa_rid2s(DOM_R_REF *ref, DOM_RID2 *rid2, (*mapped_count)++; } else { dom_idx = -1; - rid = 0xffffffff; + rid = 0; name_type = SID_NAME_UNKNOWN; } @@ -200,11 +216,6 @@ static void init_reply_lookup_names(LSA_R_LOOKUP_NAMES *r_l, r_l->dom_rid = rid2; r_l->mapped_count = mapped_count; - - if (mapped_count == 0) - r_l->status = NT_STATUS_NONE_MAPPED; - else - r_l->status = NT_STATUS_OK; } /*************************************************************************** @@ -222,14 +233,12 @@ static void init_lsa_trans_names(TALLOC_CTX *ctx, DOM_R_REF *ref, LSA_TRANS_NAME /* Allocate memory for list of names */ if (num_entries > 0) { - if (!(trn->name = (LSA_TRANS_NAME *)talloc(ctx, sizeof(LSA_TRANS_NAME) * - num_entries))) { + if (!(trn->name = TALLOC_ARRAY(ctx, LSA_TRANS_NAME, num_entries))) { DEBUG(0, ("init_lsa_trans_names(): out of memory\n")); return; } - if (!(trn->uni_name = (UNISTR2 *)talloc(ctx, sizeof(UNISTR2) * - num_entries))) { + if (!(trn->uni_name = TALLOC_ARRAY(ctx, UNISTR2, num_entries))) { DEBUG(0, ("init_lsa_trans_names(): out of memory\n")); return; } @@ -250,9 +259,6 @@ static void init_lsa_trans_names(TALLOC_CTX *ctx, DOM_R_REF *ref, LSA_TRANS_NAME /* Lookup sid from winbindd */ - memset(dom_name, '\0', sizeof(dom_name)); - memset(name, '\0', sizeof(name)); - status = lookup_sid(&find_sid, dom_name, name, &sid_name_use); DEBUG(5, ("init_lsa_trans_names: %s\n", status ? "found" : @@ -260,21 +266,25 @@ static void init_lsa_trans_names(TALLOC_CTX *ctx, DOM_R_REF *ref, LSA_TRANS_NAME if (!status) { sid_name_use = SID_NAME_UNKNOWN; + memset(dom_name, '\0', sizeof(dom_name)); + sid_to_string(name, &find_sid); + dom_idx = -1; + + 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); - /* Store domain sid in ref array */ + 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 )); - if (find_sid.num_auths == 5) { - sid_split_rid(&find_sid, &rid); } - dom_idx = init_dom_ref(ref, dom_name, &find_sid); - - DEBUG(10,("init_lsa_trans_names: added user '%s\\%s' to " - "referenced list.\n", dom_name, name )); - init_lsa_trans_name(&trn->name[total], &trn->uni_name[total], sid_name_use, name, dom_idx); total++; @@ -299,11 +309,6 @@ static void init_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l, r_l->dom_ref = ref; r_l->names = names; r_l->mapped_count = mapped_count; - - if (mapped_count == 0) - r_l->status = NT_STATUS_NONE_MAPPED; - else - r_l->status = NT_STATUS_OK; } static NTSTATUS lsa_get_generic_sd(TALLOC_CTX *mem_ctx, SEC_DESC **sd, size_t *sd_size) @@ -334,7 +339,7 @@ static NTSTATUS lsa_get_generic_sd(TALLOC_CTX *mem_ctx, SEC_DESC **sd, size_t *s if((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 3, ace)) == NULL) return NT_STATUS_NO_MEMORY; - if((*sd = make_sec_desc(mem_ctx, SEC_DESC_REVISION, &adm_sid, NULL, NULL, psa, sd_size)) == NULL) + if((*sd = make_sec_desc(mem_ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &adm_sid, NULL, NULL, psa, sd_size)) == NULL) return NT_STATUS_NO_MEMORY; return NT_STATUS_OK; @@ -346,35 +351,32 @@ static NTSTATUS lsa_get_generic_sd(TALLOC_CTX *mem_ctx, SEC_DESC **sd, size_t *s static void init_dns_dom_info(LSA_DNS_DOM_INFO *r_l, const char *nb_name, const char *dns_name, const char *forest_name, - GUID *dom_guid, DOM_SID *dom_sid) + struct uuid *dom_guid, DOM_SID *dom_sid) { if (nb_name && *nb_name) { - init_uni_hdr(&r_l->hdr_nb_dom_name, strlen(nb_name)); - init_unistr2(&r_l->uni_nb_dom_name, nb_name, - strlen(nb_name)); + init_unistr2(&r_l->uni_nb_dom_name, nb_name, UNI_FLAGS_NONE); + init_uni_hdr(&r_l->hdr_nb_dom_name, &r_l->uni_nb_dom_name); r_l->hdr_nb_dom_name.uni_max_len += 2; r_l->uni_nb_dom_name.uni_max_len += 1; } if (dns_name && *dns_name) { - init_uni_hdr(&r_l->hdr_dns_dom_name, strlen(dns_name)); - init_unistr2(&r_l->uni_dns_dom_name, dns_name, - strlen(dns_name)); + init_unistr2(&r_l->uni_dns_dom_name, dns_name, UNI_FLAGS_NONE); + init_uni_hdr(&r_l->hdr_dns_dom_name, &r_l->uni_dns_dom_name); r_l->hdr_dns_dom_name.uni_max_len += 2; r_l->uni_dns_dom_name.uni_max_len += 1; } if (forest_name && *forest_name) { - init_uni_hdr(&r_l->hdr_forest_name, strlen(forest_name)); - init_unistr2(&r_l->uni_forest_name, forest_name, - strlen(forest_name)); + init_unistr2(&r_l->uni_forest_name, forest_name, UNI_FLAGS_NONE); + init_uni_hdr(&r_l->hdr_forest_name, &r_l->uni_forest_name); r_l->hdr_forest_name.uni_max_len += 2; r_l->uni_forest_name.uni_max_len += 1; } /* how do we init the guid ? probably should write an init fn */ if (dom_guid) { - memcpy(&r_l->dom_guid, dom_guid, sizeof(GUID)); + memcpy(&r_l->dom_guid, dom_guid, sizeof(struct uuid)); } if (dom_sid) { @@ -403,11 +405,22 @@ NTSTATUS _lsa_open_policy2(pipes_struct *p, LSA_Q_OPEN_POL2 *q_u, LSA_R_OPEN_POL /* get the generic lsa policy SD until we store it */ lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size); - if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status)) - return status; + if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status)) { + if (geteuid() != 0) { + return status; + } + DEBUG(4,("ACCESS should be DENIED (granted: %#010x; required: %#010x)\n", + acc_granted, des_access)); + DEBUGADD(4,("but overwritten by euid == 0\n")); + } + + /* This is needed for lsa_open_account and rpcclient .... :-) */ + + if (geteuid() == 0) + acc_granted = POLICY_ALL_ACCESS; /* associate the domain SID with the (unique) handle. */ - if ((info = (struct lsa_info *)malloc(sizeof(struct lsa_info))) == NULL) + if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(info); @@ -441,11 +454,18 @@ NTSTATUS _lsa_open_policy(pipes_struct *p, LSA_Q_OPEN_POL *q_u, LSA_R_OPEN_POL * /* get the generic lsa policy SD until we store it */ lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size); - if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status)) - return status; + if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status)) { + if (geteuid() != 0) { + return status; + } + DEBUG(4,("ACCESS should be DENIED (granted: %#010x; required: %#010x)\n", + acc_granted, des_access)); + DEBUGADD(4,("but overwritten by euid == 0\n")); + acc_granted = des_access; + } /* associate the domain SID with the (unique) handle. */ - if ((info = (struct lsa_info *)malloc(sizeof(struct lsa_info))) == NULL) + if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(info); @@ -487,7 +507,7 @@ NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, LSA_R_E if (!(info->access & POLICY_VIEW_LOCAL_INFORMATION)) return NT_STATUS_ACCESS_DENIED; - nt_status = secrets_get_trusted_domains(p->mem_ctx, &enum_context, max_num_domains, &num_domains, &trust_doms); + nt_status = secrets_get_trusted_domains(p->mem_ctx, (int *)&enum_context, max_num_domains, (int *)&num_domains, &trust_doms); if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES) && @@ -532,7 +552,7 @@ NTSTATUS _lsa_query_info(pipes_struct *p, LSA_Q_QUERY_INFO *q_u, LSA_R_QUERY_INF info->id2.auditing_enabled = 1; info->id2.count1 = 7; info->id2.count2 = 7; - if ((info->id2.auditsettings = (uint32 *)talloc(p->mem_ctx,7*sizeof(uint32))) == NULL) + if ((info->id2.auditsettings = TALLOC_ARRAY(p->mem_ctx,uint32, 7)) == NULL) return NT_STATUS_NO_MEMORY; for (i = 0; i < 7; i++) info->id2.auditsettings[i] = 3; @@ -547,7 +567,7 @@ NTSTATUS _lsa_query_info(pipes_struct *p, LSA_Q_QUERY_INFO *q_u, LSA_R_QUERY_INF switch (lp_server_role()) { case ROLE_DOMAIN_PDC: case ROLE_DOMAIN_BDC: - name = lp_workgroup(); + name = get_global_sam_name(); sid = get_global_sam_sid(); break; case ROLE_DOMAIN_MEMBER: @@ -573,23 +593,8 @@ NTSTATUS _lsa_query_info(pipes_struct *p, LSA_Q_QUERY_INFO *q_u, LSA_R_QUERY_INF return NT_STATUS_ACCESS_DENIED; /* Request PolicyAccountDomainInformation. */ - switch (lp_server_role()) { - case ROLE_DOMAIN_PDC: - case ROLE_DOMAIN_BDC: - name = lp_workgroup(); - sid = get_global_sam_sid(); - break; - case ROLE_DOMAIN_MEMBER: - name = global_myname(); - sid = get_global_sam_sid(); - break; - case ROLE_STANDALONE: - name = global_myname(); - sid = get_global_sam_sid(); - break; - default: - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } + name = get_global_sam_name(); + sid = get_global_sam_sid(); init_dom_query(&r_u->dom.id5, name, sid); break; case 0x06: @@ -645,9 +650,9 @@ NTSTATUS _lsa_lookup_sids(pipes_struct *p, LSA_Q_LOOKUP_SIDS *q_u, LSA_R_LOOKUP_ num_entries = MAX_LOOKUP_SIDS; DEBUG(5,("_lsa_lookup_sids: truncating SID lookup list to %d\n", num_entries)); } - - ref = (DOM_R_REF *)talloc_zero(p->mem_ctx, sizeof(DOM_R_REF)); - names = (LSA_TRANS_NAME_ENUM *)talloc_zero(p->mem_ctx, sizeof(LSA_TRANS_NAME_ENUM)); + + ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); + names = TALLOC_ZERO_P(p->mem_ctx, LSA_TRANS_NAME_ENUM); if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) { r_u->status = NT_STATUS_INVALID_HANDLE; @@ -666,6 +671,12 @@ done: /* set up the LSA Lookup SIDs response */ init_lsa_trans_names(p->mem_ctx, ref, names, num_entries, sid, &mapped_count); + if (NT_STATUS_IS_OK(r_u->status)) { + if (mapped_count == 0) + r_u->status = NT_STATUS_NONE_MAPPED; + else if (mapped_count != num_entries) + r_u->status = STATUS_SOME_UNMAPPED; + } init_reply_lookup_sids(r_u, ref, names, mapped_count); return r_u->status; @@ -689,8 +700,8 @@ NTSTATUS _lsa_lookup_names(pipes_struct *p,LSA_Q_LOOKUP_NAMES *q_u, LSA_R_LOOKUP DEBUG(5,("_lsa_lookup_names: truncating name lookup list to %d\n", num_entries)); } - ref = (DOM_R_REF *)talloc_zero(p->mem_ctx, sizeof(DOM_R_REF)); - rids = (DOM_RID2 *)talloc_zero(p->mem_ctx, sizeof(DOM_RID2)*num_entries); + ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); + rids = TALLOC_ZERO_ARRAY(p->mem_ctx, DOM_RID2, num_entries); if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) { r_u->status = NT_STATUS_INVALID_HANDLE; @@ -710,6 +721,12 @@ 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; + else if (mapped_count != num_entries) + r_u->status = STATUS_SOME_UNMAPPED; + } init_reply_lookup_names(r_u, ref, num_entries, rids, mapped_count); return r_u->status; @@ -745,49 +762,56 @@ NTSTATUS _lsa_enum_privs(pipes_struct *p, LSA_Q_ENUM_PRIVS *q_u, LSA_R_ENUM_PRIV { struct lsa_info *handle; uint32 i; + uint32 enum_context = q_u->enum_context; + int num_privs = count_all_privileges(); + LSA_PRIV_ENTRY *entries = NULL; + LUID_ATTR luid; - uint32 enum_context=q_u->enum_context; - LSA_PRIV_ENTRY *entry; - LSA_PRIV_ENTRY *entries=NULL; + /* remember that the enum_context starts at 0 and not 1 */ - if (enum_context >= PRIV_ALL_INDEX) + if ( enum_context >= num_privs ) return NT_STATUS_NO_MORE_ENTRIES; - - entries = (LSA_PRIV_ENTRY *)talloc_zero(p->mem_ctx, sizeof(LSA_PRIV_ENTRY) * (PRIV_ALL_INDEX)); - if (entries==NULL) + + DEBUG(10,("_lsa_enum_privs: enum_context:%d total entries:%d\n", + enum_context, num_privs)); + + if ( !(entries = TALLOC_ZERO_ARRAY(p->mem_ctx, LSA_PRIV_ENTRY, num_privs + 1))) return NT_STATUS_NO_MEMORY; if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) return NT_STATUS_INVALID_HANDLE; - /* check if the user have enough rights */ + /* check if the user have enough rights + I don't know if it's the right one. not documented. */ - /* - * I don't know if it's the right one. not documented. - */ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION)) return NT_STATUS_ACCESS_DENIED; - entry = entries; - - DEBUG(10,("_lsa_enum_privs: enum_context:%d total entries:%d\n", enum_context, PRIV_ALL_INDEX)); - - for (i = 0; i < PRIV_ALL_INDEX; i++, entry++) { - if( ihdr_name, 0); - init_unistr2(&entry->name, NULL, 0 ); - entry->luid_low = 0; - entry->luid_high = 0; + if ( !(entries = TALLOC_ZERO_ARRAY(p->mem_ctx, LSA_PRIV_ENTRY, num_privs )) ) + return NT_STATUS_NO_MEMORY; + + + for (i = 0; i < num_privs; i++) { + if( i < enum_context) { + init_unistr2(&entries[i].name, NULL, UNI_FLAGS_NONE); + init_uni_hdr(&entries[i].hdr_name, &entries[i].name); + + entries[i].luid_low = 0; + entries[i].luid_high = 0; } else { - init_uni_hdr(&entry->hdr_name, strlen(privs[i+1].priv)); - init_unistr2(&entry->name, privs[i+1].priv, strlen(privs[i+1].priv) ); - entry->luid_low = privs[i+1].se_priv; - entry->luid_high = 0; + init_unistr2(&entries[i].name, privs[i].name, UNI_FLAGS_NONE); + init_uni_hdr(&entries[i].hdr_name, &entries[i].name); + + luid = get_privilege_luid( &privs[i].se_priv ); + + entries[i].luid_low = luid.luid.low; + entries[i].luid_high = luid.luid.high; } } - enum_context = PRIV_ALL_INDEX; - init_lsa_r_enum_privs(r_u, enum_context, PRIV_ALL_INDEX, entries); + enum_context = num_privs; + + init_lsa_r_enum_privs(r_u, enum_context, num_privs, entries); return NT_STATUS_OK; } @@ -800,7 +824,7 @@ NTSTATUS _lsa_priv_get_dispname(pipes_struct *p, LSA_Q_PRIV_GET_DISPNAME *q_u, L { struct lsa_info *handle; fstring name_asc; - int i=1; + const char *description; if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) return NT_STATUS_INVALID_HANDLE; @@ -815,22 +839,25 @@ NTSTATUS _lsa_priv_get_dispname(pipes_struct *p, LSA_Q_PRIV_GET_DISPNAME *q_u, L unistr2_to_ascii(name_asc, &q_u->name, sizeof(name_asc)); - DEBUG(10,("_lsa_priv_get_dispname: %s", name_asc)); + DEBUG(10,("_lsa_priv_get_dispname: name = %s\n", name_asc)); - while (privs[i].se_priv!=SE_PRIV_ALL && strcmp(name_asc, privs[i].priv)) - i++; + description = get_privilege_dispname( name_asc ); - if (privs[i].se_priv!=SE_PRIV_ALL) { - DEBUG(10,(": %s\n", privs[i].description)); - init_uni_hdr(&r_u->hdr_desc, strlen(privs[i].description)); - init_unistr2(&r_u->desc, privs[i].description, strlen(privs[i].description) ); + if ( description ) { + DEBUG(10,("_lsa_priv_get_dispname: display name = %s\n", description)); + + init_unistr2(&r_u->desc, description, UNI_FLAGS_NONE); + init_uni_hdr(&r_u->hdr_desc, &r_u->desc); - r_u->ptr_info=0xdeadbeef; - r_u->lang_id=q_u->lang_id; + r_u->ptr_info = 0xdeadbeef; + r_u->lang_id = q_u->lang_id; + return NT_STATUS_OK; } else { DEBUG(10,("_lsa_priv_get_dispname: doesn't exist\n")); - r_u->ptr_info=0; + + r_u->ptr_info = 0; + return NT_STATUS_NO_SUCH_PRIVILEGE; } } @@ -842,46 +869,46 @@ _lsa_enum_accounts. NTSTATUS _lsa_enum_accounts(pipes_struct *p, LSA_Q_ENUM_ACCOUNTS *q_u, LSA_R_ENUM_ACCOUNTS *r_u) { struct lsa_info *handle; - GROUP_MAP *map=NULL; - int num_entries=0; + DOM_SID *sid_list; + int i, j, num_entries; LSA_SID_ENUM *sids=&r_u->sids; - int i=0,j=0; + NTSTATUS ret; if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) return NT_STATUS_INVALID_HANDLE; - /* check if the user have enough rights */ - - /* - * I don't know if it's the right one. not documented. - */ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION)) return NT_STATUS_ACCESS_DENIED; - /* get the list of mapped groups (domain, local, builtin) */ - if(!pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV)) - return NT_STATUS_OK; + sid_list = NULL; + num_entries = 0; + + /* The only way we can currently find out all the SIDs that have been + privileged is to scan all privileges */ + + if (!NT_STATUS_IS_OK(ret = privilege_enumerate_accounts(&sid_list, &num_entries))) { + return ret; + } if (q_u->enum_context >= num_entries) return NT_STATUS_NO_MORE_ENTRIES; - sids->ptr_sid = (uint32 *)talloc_zero(p->mem_ctx, (num_entries-q_u->enum_context)*sizeof(uint32)); - sids->sid = (DOM_SID2 *)talloc_zero(p->mem_ctx, (num_entries-q_u->enum_context)*sizeof(DOM_SID2)); + sids->ptr_sid = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_entries-q_u->enum_context); + sids->sid = TALLOC_ZERO_ARRAY(p->mem_ctx, DOM_SID2, num_entries-q_u->enum_context); if (sids->ptr_sid==NULL || sids->sid==NULL) { - SAFE_FREE(map); + SAFE_FREE(sid_list); return NT_STATUS_NO_MEMORY; } - for (i=q_u->enum_context, j=0; ienum_context, j = 0; i < num_entries; i++, j++) { + init_dom_sid2(&(*sids).sid[j], &sid_list[i]); + (*sids).ptr_sid[j] = 1; } - SAFE_FREE(map); + SAFE_FREE(sid_list); - init_lsa_r_enum_accounts(r_u, j); + init_lsa_r_enum_accounts(r_u, num_entries); return NT_STATUS_OK; } @@ -890,7 +917,6 @@ NTSTATUS _lsa_enum_accounts(pipes_struct *p, LSA_Q_ENUM_ACCOUNTS *q_u, LSA_R_ENU NTSTATUS _lsa_unk_get_connuser(pipes_struct *p, LSA_Q_UNK_GET_CONNUSER *q_u, LSA_R_UNK_GET_CONNUSER *r_u) { fstring username, domname; - int ulen, dlen; user_struct *vuser = get_valid_user_struct(p->vuid); if (vuser == NULL) @@ -899,18 +925,15 @@ NTSTATUS _lsa_unk_get_connuser(pipes_struct *p, LSA_Q_UNK_GET_CONNUSER *q_u, LSA fstrcpy(username, vuser->user.smb_name); fstrcpy(domname, vuser->user.domain); - ulen = strlen(username) + 1; - dlen = strlen(domname) + 1; - - init_uni_hdr(&r_u->hdr_user_name, ulen); r_u->ptr_user_name = 1; - init_unistr2(&r_u->uni2_user_name, username, ulen); + init_unistr2(&r_u->uni2_user_name, username, UNI_STR_TERMINATE); + init_uni_hdr(&r_u->hdr_user_name, &r_u->uni2_user_name); r_u->unk1 = 1; - init_uni_hdr(&r_u->hdr_dom_name, dlen); r_u->ptr_dom_name = 1; - init_unistr2(&r_u->uni2_dom_name, domname, dlen); + init_unistr2(&r_u->uni2_dom_name, domname, UNI_STR_TERMINATE); + init_uni_hdr(&r_u->hdr_dom_name, &r_u->uni2_dom_name); r_u->status = NT_STATUS_OK; @@ -918,15 +941,58 @@ NTSTATUS _lsa_unk_get_connuser(pipes_struct *p, LSA_Q_UNK_GET_CONNUSER *q_u, LSA } /*************************************************************************** - + Lsa Create Account ***************************************************************************/ -NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENACCOUNT *r_u) +NTSTATUS _lsa_create_account(pipes_struct *p, LSA_Q_CREATEACCOUNT *q_u, LSA_R_CREATEACCOUNT *r_u) { struct lsa_info *handle; struct lsa_info *info; - r_u->status = NT_STATUS_OK; + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) + return NT_STATUS_INVALID_HANDLE; + + /* check if the user have enough rights */ + + /* + * I don't know if it's the right one. not documented. + * but guessed with rpcclient. + */ + if (!(handle->access & POLICY_GET_PRIVATE_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + /* check to see if the pipe_user is a Domain Admin since + account_pol.tdb was already opened as root, this is all we have */ + + if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) + return NT_STATUS_ACCESS_DENIED; + + /* associate the user/group SID with the (unique) handle. */ + + if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) + return NT_STATUS_NO_MEMORY; + + ZERO_STRUCTP(info); + info->sid = q_u->sid.sid; + info->access = q_u->access; + + /* get a (unique) handle. open a policy on it. */ + if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + + return privilege_create_account( &info->sid ); +} + + +/*************************************************************************** + Lsa Open Account + ***************************************************************************/ + +NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENACCOUNT *r_u) +{ + struct lsa_info *handle; + struct lsa_info *info; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) @@ -941,8 +1007,13 @@ NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENAC if (!(handle->access & POLICY_GET_PRIVATE_INFORMATION)) return NT_STATUS_ACCESS_DENIED; + /* TODO: Fis the parsing routine before reenabling this check! */ + #if 0 + if (!lookup_sid(&handle->sid, dom_name, name, &type)) + return NT_STATUS_ACCESS_DENIED; + #endif /* associate the user/group SID with the (unique) handle. */ - if ((info = (struct lsa_info *)malloc(sizeof(struct lsa_info))) == NULL) + if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(info); @@ -953,50 +1024,39 @@ NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENAC if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info)) return NT_STATUS_OBJECT_NAME_NOT_FOUND; - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** For a given SID, enumerate all the privilege this account has. ***************************************************************************/ -NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, LSA_Q_ENUMPRIVSACCOUNT *q_u, LSA_R_ENUMPRIVSACCOUNT *r_u) +NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, prs_struct *ps, LSA_Q_ENUMPRIVSACCOUNT *q_u, LSA_R_ENUMPRIVSACCOUNT *r_u) { struct lsa_info *info=NULL; - GROUP_MAP map; - int i=0; - - LUID_ATTR *set=NULL; - - r_u->status = NT_STATUS_OK; + SE_PRIV mask; + PRIVILEGE_SET privileges; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid, MAPPING_WITH_PRIV)) - return NT_STATUS_NO_SUCH_GROUP; + if ( !get_privileges_for_sids( &mask, &info->sid, 1 ) ) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(10,("_lsa_enum_privsaccount: %d privileges\n", map.priv_set.count)); - if (map.priv_set.count!=0) { - - set=(LUID_ATTR *)talloc(p->mem_ctx, map.priv_set.count*sizeof(LUID_ATTR)); - if (set == NULL) { - free_privilege(&map.priv_set); - return NT_STATUS_NO_MEMORY; - } + privilege_set_init( &privileges ); - for (i=0; isid), privileges.count)); + + r_u->status = init_lsa_r_enum_privsaccount(ps->mem_ctx, r_u, privileges.set, privileges.count, 0); } + else + r_u->status = NT_STATUS_NO_SUCH_PRIVILEGE; - init_lsa_r_enum_privsaccount(r_u, set, map.priv_set.count, 0); - free_privilege(&map.priv_set); + privilege_set_free( &privileges ); return r_u->status; } @@ -1008,15 +1068,16 @@ NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, LSA_Q_ENUMPRIVSACCOUNT *q_u, LS NTSTATUS _lsa_getsystemaccount(pipes_struct *p, LSA_Q_GETSYSTEMACCOUNT *q_u, LSA_R_GETSYSTEMACCOUNT *r_u) { struct lsa_info *info=NULL; - GROUP_MAP map; - r_u->status = NT_STATUS_OK; + fstring name, dom_name; + enum SID_NAME_USE type; /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid, MAPPING_WITHOUT_PRIV)) - return NT_STATUS_NO_SUCH_GROUP; + if (!lookup_sid(&info->sid, dom_name, name, &type)) + return NT_STATUS_ACCESS_DENIED; /* 0x01 -> Log on locally @@ -1027,9 +1088,9 @@ NTSTATUS _lsa_getsystemaccount(pipes_struct *p, LSA_Q_GETSYSTEMACCOUNT *q_u, LSA they can be ORed together */ - r_u->access=map.systemaccount; + r_u->access = PR_LOG_ON_LOCALLY | PR_ACCESS_FROM_NETWORK; - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -1046,16 +1107,18 @@ NTSTATUS _lsa_setsystemaccount(pipes_struct *p, LSA_Q_SETSYSTEMACCOUNT *q_u, LSA if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid, MAPPING_WITH_PRIV)) - return NT_STATUS_NO_SUCH_GROUP; + /* check to see if the pipe_user is a Domain Admin since + account_pol.tdb was already opened as root, this is all we have */ + + if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) + return NT_STATUS_ACCESS_DENIED; - map.systemaccount=q_u->access; + if (!pdb_getgrsid(&map, info->sid)) + return NT_STATUS_NO_SUCH_GROUP; if(!pdb_update_group_mapping_entry(&map)) return NT_STATUS_NO_SUCH_GROUP; - free_privilege(&map.priv_set); - return r_u->status; } @@ -1065,42 +1128,34 @@ NTSTATUS _lsa_setsystemaccount(pipes_struct *p, LSA_Q_SETSYSTEMACCOUNT *q_u, LSA NTSTATUS _lsa_addprivs(pipes_struct *p, LSA_Q_ADDPRIVS *q_u, LSA_R_ADDPRIVS *r_u) { - struct lsa_info *info=NULL; - GROUP_MAP map; - int i=0; - - LUID_ATTR *luid_attr=NULL; - PRIVILEGE_SET *set=NULL; - - r_u->status = NT_STATUS_OK; + struct lsa_info *info = NULL; + SE_PRIV mask; + PRIVILEGE_SET *set = NULL; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; + + /* check to see if the pipe_user is a Domain Admin since + account_pol.tdb was already opened as root, this is all we have */ + + if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) + return NT_STATUS_ACCESS_DENIED; - if (!pdb_getgrsid(&map, info->sid, MAPPING_WITH_PRIV)) - return NT_STATUS_NO_SUCH_GROUP; + set = &q_u->set; - set=&q_u->set; + if ( !privilege_set_to_se_priv( &mask, set ) ) + return NT_STATUS_NO_SUCH_PRIVILEGE; - for (i=0; icount; i++) { - luid_attr=&set->set[i]; - - /* check if the privilege is already there */ - if (check_priv_in_privilege(&map.priv_set, *luid_attr)){ - free_privilege(&map.priv_set); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - add_privilege(&map.priv_set, *luid_attr); + if ( !grant_privilege( &info->sid, &mask ) ) { + DEBUG(3,("_lsa_addprivs: grant_privilege(%s) failed!\n", + sid_string_static(&info->sid) )); + DEBUG(3,("Privilege mask:\n")); + dump_se_priv( DBGC_ALL, 3, &mask ); + return NT_STATUS_NO_SUCH_PRIVILEGE; } - if(!pdb_update_group_mapping_entry(&map)) - return NT_STATUS_NO_SUCH_GROUP; - - free_privilege(&map.priv_set); - - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -1109,55 +1164,34 @@ NTSTATUS _lsa_addprivs(pipes_struct *p, LSA_Q_ADDPRIVS *q_u, LSA_R_ADDPRIVS *r_u NTSTATUS _lsa_removeprivs(pipes_struct *p, LSA_Q_REMOVEPRIVS *q_u, LSA_R_REMOVEPRIVS *r_u) { - struct lsa_info *info=NULL; - GROUP_MAP map; - int i=0; - - LUID_ATTR *luid_attr=NULL; - PRIVILEGE_SET *set=NULL; - - r_u->status = NT_STATUS_OK; + struct lsa_info *info = NULL; + SE_PRIV mask; + PRIVILEGE_SET *set = NULL; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid, MAPPING_WITH_PRIV)) - return NT_STATUS_NO_SUCH_GROUP; - - if (q_u->allrights!=0) { - /* log it and return, until I see one myself don't do anything */ - DEBUG(5,("_lsa_removeprivs: trying to remove all privileges ?\n")); - return NT_STATUS_OK; - } + /* check to see if the pipe_user is a Domain Admin since + account_pol.tdb was already opened as root, this is all we have */ + + if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) + return NT_STATUS_ACCESS_DENIED; - if (q_u->ptr==0) { - /* log it and return, until I see one myself don't do anything */ - DEBUG(5,("_lsa_removeprivs: no privileges to remove ?\n")); - return NT_STATUS_OK; - } + set = &q_u->set; - set=&q_u->set; + if ( !privilege_set_to_se_priv( &mask, set ) ) + return NT_STATUS_NO_SUCH_PRIVILEGE; - for (i=0; icount; i++) { - luid_attr=&set->set[i]; - - /* if we don't have the privilege, we're trying to remove, give up */ - /* what else can we do ??? JFM. */ - if (!check_priv_in_privilege(&map.priv_set, *luid_attr)){ - free_privilege(&map.priv_set); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - remove_privilege(&map.priv_set, *luid_attr); + if ( !revoke_privilege( &info->sid, &mask ) ) { + DEBUG(3,("_lsa_removeprivs: revoke_privilege(%s) failed!\n", + sid_string_static(&info->sid) )); + DEBUG(3,("Privilege mask:\n")); + dump_se_priv( DBGC_ALL, 3, &mask ); + return NT_STATUS_NO_SUCH_PRIVILEGE; } - if(!pdb_update_group_mapping_entry(&map)) - return NT_STATUS_NO_SUCH_GROUP; - - free_privilege(&map.priv_set); - - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -1213,6 +1247,8 @@ NTSTATUS _lsa_query_secobj(pipes_struct *p, LSA_Q_QUERY_SEC_OBJ *q_u, LSA_R_QUER return r_u->status; } +/*************************************************************************** + ***************************************************************************/ NTSTATUS _lsa_query_info2(pipes_struct *p, LSA_Q_QUERY_INFO2 *q_u, LSA_R_QUERY_INFO2 *r_u) { @@ -1221,7 +1257,8 @@ NTSTATUS _lsa_query_info2(pipes_struct *p, LSA_Q_QUERY_INFO2 *q_u, LSA_R_QUERY_I char *dns_name = NULL; char *forest_name = NULL; DOM_SID *sid = NULL; - GUID guid; + struct uuid guid; + fstring dnsdomname; ZERO_STRUCT(guid); r_u->status = NT_STATUS_OK; @@ -1239,10 +1276,17 @@ NTSTATUS _lsa_query_info2(pipes_struct *p, LSA_Q_QUERY_INFO2 *q_u, LSA_R_QUERY_I switch (lp_server_role()) { case ROLE_DOMAIN_PDC: case ROLE_DOMAIN_BDC: - nb_name = lp_workgroup(); + nb_name = get_global_sam_name(); /* ugly temp hack for these next two */ - dns_name = lp_realm(); - forest_name = lp_realm(); + + /* This should be a 'netbios domain -> DNS domain' mapping */ + dnsdomname[0] = '\0'; + get_mydnsdomname(dnsdomname); + strlower_m(dnsdomname); + + dns_name = dnsdomname; + forest_name = dnsdomname; + sid = get_global_sam_sid(); secrets_fetch_domain_guid(lp_workgroup(), &guid); break; @@ -1266,139 +1310,143 @@ NTSTATUS _lsa_query_info2(pipes_struct *p, LSA_Q_QUERY_INFO2 *q_u, LSA_R_QUERY_I return r_u->status; } - /*************************************************************************** - For a given SID, enumerate all the privilege this account has. ***************************************************************************/ -NTSTATUS _lsa_enum_acct_rights(pipes_struct *p, LSA_Q_ENUM_ACCT_RIGHTS *q_u, LSA_R_ENUM_ACCT_RIGHTS *r_u) -{ - struct lsa_info *info=NULL; - char **rights = NULL; - int num_rights = 0; - int i; - r_u->status = NT_STATUS_OK; +NTSTATUS _lsa_add_acct_rights(pipes_struct *p, LSA_Q_ADD_ACCT_RIGHTS *q_u, LSA_R_ADD_ACCT_RIGHTS *r_u) +{ + struct lsa_info *info = NULL; + int i = 0; + DOM_SID sid; + fstring privname; + UNISTR2_ARRAY *uni_privnames = &q_u->rights; + /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; + + /* check to see if the pipe_user is a Domain Admin since + account_pol.tdb was already opened as root, this is all we have */ + + if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) + return NT_STATUS_ACCESS_DENIED; - r_u->status = privilege_enum_account_rights(&q_u->sid.sid, &num_rights, &rights); - - init_r_enum_acct_rights(r_u, num_rights, (const char **)rights); - - for (i=0;isid.sid ); + + /* just a little sanity check */ + + if ( q_u->count != uni_privnames->count ) { + DEBUG(0,("_lsa_add_acct_rights: count != number of UNISTR2 elements!\n")); + return NT_STATUS_INVALID_HANDLE; + } + + for ( i=0; icount; i++ ) { + unistr2_to_ascii( privname, &uni_privnames->strings[i].string, sizeof(fstring)-1 ); + + /* only try to add non-null strings */ + + if ( *privname && !grant_privilege_by_name( &sid, privname ) ) { + DEBUG(2,("_lsa_add_acct_rights: Failed to add privilege [%s]\n", privname )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } } - safe_free(rights); - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** -return a list of SIDs for a particular privilege ***************************************************************************/ -NTSTATUS _lsa_enum_acct_with_right(pipes_struct *p, - LSA_Q_ENUM_ACCT_WITH_RIGHT *q_u, - LSA_R_ENUM_ACCT_WITH_RIGHT *r_u) -{ - struct lsa_info *info=NULL; - char *right; - DOM_SID *sids = NULL; - uint32 count = 0; - - r_u->status = NT_STATUS_OK; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) - return NT_STATUS_INVALID_HANDLE; - - right = unistr2_tdup(p->mem_ctx, &q_u->right); - - DEBUG(5,("lsa_enum_acct_with_right on right %s\n", right)); - r_u->status = privilege_enum_account_with_right(right, &count, &sids); - - init_r_enum_acct_with_right(r_u, count, sids); - - safe_free(sids); - - return r_u->status; -} - -/*************************************************************************** - add privileges to a acct by SID - ***************************************************************************/ -NTSTATUS _lsa_add_acct_rights(pipes_struct *p, LSA_Q_ADD_ACCT_RIGHTS *q_u, LSA_R_ADD_ACCT_RIGHTS *r_u) +NTSTATUS _lsa_remove_acct_rights(pipes_struct *p, LSA_Q_REMOVE_ACCT_RIGHTS *q_u, LSA_R_REMOVE_ACCT_RIGHTS *r_u) { - struct lsa_info *info=NULL; - int i; - - r_u->status = NT_STATUS_OK; + struct lsa_info *info = NULL; + int i = 0; + DOM_SID sid; + fstring privname; + UNISTR2_ARRAY *uni_privnames = &q_u->rights; + /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; + + /* check to see if the pipe_user is a Domain Admin since + account_pol.tdb was already opened as root, this is all we have */ + + if ( !nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ) ) + return NT_STATUS_ACCESS_DENIED; - DEBUG(5,("_lsa_add_acct_rights to %s (%d rights)\n", - sid_string_static(&q_u->sid.sid), q_u->rights.count)); + sid_copy( &sid, &q_u->sid.sid ); - for (i=0;irights.count;i++) { - DEBUG(5,("\t%s\n", unistr2_static(&q_u->rights.strings[i].string))); + if ( q_u->removeall ) { + if ( !revoke_all_privileges( &sid ) ) + return NT_STATUS_ACCESS_DENIED; + + return NT_STATUS_OK; } - - - for (i=0;irights.count;i++) { - r_u->status = privilege_add_account_right(unistr2_static(&q_u->rights.strings[i].string), - &q_u->sid.sid); - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(2,("Failed to add right '%s'\n", - unistr2_static(&q_u->rights.strings[i].string))); - break; + + /* just a little sanity check */ + + if ( q_u->count != uni_privnames->count ) { + DEBUG(0,("_lsa_add_acct_rights: count != number of UNISTR2 elements!\n")); + return NT_STATUS_INVALID_HANDLE; + } + + for ( i=0; icount; i++ ) { + unistr2_to_ascii( privname, &uni_privnames->strings[i].string, sizeof(fstring)-1 ); + + /* only try to add non-null strings */ + + if ( *privname && !revoke_privilege_by_name( &sid, privname ) ) { + DEBUG(2,("_lsa_remove_acct_rights: Failed to revoke privilege [%s]\n", privname )); + return NT_STATUS_NO_SUCH_PRIVILEGE; } } - init_r_add_acct_rights(r_u); - - return r_u->status; + return NT_STATUS_OK; } -/*************************************************************************** - remove privileges from a acct by SID - ***************************************************************************/ -NTSTATUS _lsa_remove_acct_rights(pipes_struct *p, LSA_Q_REMOVE_ACCT_RIGHTS *q_u, LSA_R_REMOVE_ACCT_RIGHTS *r_u) +NTSTATUS _lsa_enum_acct_rights(pipes_struct *p, LSA_Q_ENUM_ACCT_RIGHTS *q_u, LSA_R_ENUM_ACCT_RIGHTS *r_u) { - struct lsa_info *info=NULL; - int i; - - r_u->status = NT_STATUS_OK; + struct lsa_info *info = NULL; + DOM_SID sid; + PRIVILEGE_SET privileges; + SE_PRIV mask; + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; + + /* according to an NT4 PDC, you can add privileges to SIDs even without + call_lsa_create_account() first. And you can use any arbitrary SID. */ + + sid_copy( &sid, &q_u->sid.sid ); + + if ( !get_privileges_for_sids( &mask, &sid, 1 ) ) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + privilege_set_init( &privileges ); - DEBUG(5,("_lsa_remove_acct_rights from %s all=%d (%d rights)\n", - sid_string_static(&q_u->sid.sid), - q_u->removeall, - q_u->rights.count)); + if ( se_priv_to_privilege_set( &privileges, &mask ) ) { - for (i=0;irights.count;i++) { - DEBUG(5,("\t%s\n", unistr2_static(&q_u->rights.strings[i].string))); - } + DEBUG(10,("_lsa_enum_acct_rights: %s has %d privileges\n", + sid_string_static(&sid), privileges.count)); - for (i=0;irights.count;i++) { - r_u->status = privilege_remove_account_right(unistr2_static(&q_u->rights.strings[i].string), - &q_u->sid.sid); - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(2,("Failed to remove right '%s'\n", - unistr2_static(&q_u->rights.strings[i].string))); - break; - } + r_u->status = init_r_enum_acct_rights( r_u, &privileges ); } + else + r_u->status = NT_STATUS_NO_SUCH_PRIVILEGE; - init_r_remove_acct_rights(r_u); + privilege_set_free( &privileges ); return r_u->status; } + +