Fix self granting privileges in security=ads.
[samba.git] / source3 / rpc_server / srv_lsa_nt.c
index cc5d23ce71fc3e3f3682ed3b0040637ce1f83fae..b9ea2d2e94d596980aba3f55a87536ab6e60bfd1 100644 (file)
@@ -29,6 +29,7 @@
 /* This is the implementation of the lsa server code. */
 
 #include "includes.h"
+#include "../librpc/gen_ndr/srv_lsa.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
@@ -41,8 +42,10 @@ enum lsa_handle_type { LSA_HANDLE_POLICY_TYPE = 1, LSA_HANDLE_ACCOUNT_TYPE };
 
 struct lsa_info {
        DOM_SID sid;
+       const char *name;
        uint32 access;
        enum lsa_handle_type type;
+       struct security_descriptor *sd;
 };
 
 const struct generic_mapping lsa_account_mapping = {
@@ -59,6 +62,20 @@ const struct generic_mapping lsa_policy_mapping = {
        LSA_POLICY_ALL_ACCESS
 };
 
+const struct generic_mapping lsa_secret_mapping = {
+       LSA_SECRET_READ,
+       LSA_SECRET_WRITE,
+       LSA_SECRET_EXECUTE,
+       LSA_SECRET_ALL_ACCESS
+};
+
+const struct generic_mapping lsa_trusted_domain_mapping = {
+       LSA_TRUSTED_DOMAIN_READ,
+       LSA_TRUSTED_DOMAIN_WRITE,
+       LSA_TRUSTED_DOMAIN_EXECUTE,
+       LSA_TRUSTED_DOMAIN_ALL_ACCESS
+};
+
 /***************************************************************************
  init_lsa_ref_domain_list - adds a domain if it's not already in, returns the index.
 ***************************************************************************/
@@ -159,9 +176,13 @@ static NTSTATUS lookup_lsa_rids(TALLOC_CTX *mem_ctx,
 
                /* Split name into domain and user component */
 
-               full_name = name[i].string;
-               if (full_name == NULL) {
-                       return NT_STATUS_NO_MEMORY;
+               /* follow w2k8 behavior and return the builtin domain when no
+                * input has been passed in */
+
+               if (name[i].string) {
+                       full_name = name[i].string;
+               } else {
+                       full_name = "BUILTIN";
                }
 
                DEBUG(5, ("lookup_lsa_rids: looking up name %s\n", full_name));
@@ -192,7 +213,11 @@ static NTSTATUS lookup_lsa_rids(TALLOC_CTX *mem_ctx,
                dom_idx = -1;
 
                if (type != SID_NAME_UNKNOWN) {
-                       sid_split_rid(&sid, &rid);
+                       if (type == SID_NAME_DOMAIN) {
+                               rid = (uint32_t)-1;
+                       } else {
+                               sid_split_rid(&sid, &rid);
+                       }
                        dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &sid);
                        mapped_count++;
                }
@@ -364,9 +389,8 @@ NTSTATUS _lsa_OpenPolicy2(pipes_struct *p,
        }
 
        status = access_check_object(psd, p->server_info->ptok,
-               NULL, 0, des_access,
-               &acc_granted, "_lsa_OpenPolicy2" );
-
+                                    NULL, 0, des_access,
+                                    &acc_granted, "_lsa_OpenPolicy2" );
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -415,22 +439,11 @@ NTSTATUS _lsa_EnumTrustDom(pipes_struct *p,
                           struct lsa_EnumTrustDom *r)
 {
        struct lsa_info *info;
-       uint32 next_idx;
+       uint32_t count;
        struct trustdom_info **domains;
-       struct lsa_DomainInfo *lsa_domains = NULL;
+       struct lsa_DomainInfo *entries;
        int i;
-
-       /*
-        * preferred length is set to 5 as a "our" preferred length
-        * nt sets this parameter to 2
-        * update (20.08.2002): it's not preferred length, but preferred size!
-        * it needs further investigation how to optimally choose this value
-        */
-       uint32 max_num_domains =
-               r->in.max_size < 5 ? r->in.max_size : 10;
-       uint32 num_domains;
        NTSTATUS nt_status;
-       uint32 num_thistime;
 
        if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info))
                return NT_STATUS_INVALID_HANDLE;
@@ -444,48 +457,52 @@ NTSTATUS _lsa_EnumTrustDom(pipes_struct *p,
                return NT_STATUS_ACCESS_DENIED;
 
        become_root();
-       nt_status = pdb_enum_trusteddoms(p->mem_ctx, &num_domains, &domains);
+       nt_status = pdb_enum_trusteddoms(p->mem_ctx, &count, &domains);
        unbecome_root();
 
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
        }
 
-       if (*r->in.resume_handle < num_domains) {
-               num_thistime = MIN(num_domains, max_num_domains);
-
-               nt_status = STATUS_MORE_ENTRIES;
+       entries = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_DomainInfo, count);
+       if (!entries) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
-               if (*r->in.resume_handle + num_thistime > num_domains) {
-                       num_thistime = num_domains - *r->in.resume_handle;
-                       nt_status = NT_STATUS_OK;
-               }
+       for (i=0; i<count; i++) {
+               init_lsa_StringLarge(&entries[i].name, domains[i]->name);
+               entries[i].sid = &domains[i]->sid;
+       }
 
-               next_idx = *r->in.resume_handle + num_thistime;
-       } else {
-               num_thistime = 0;
-               next_idx = 0xffffffff;
-               nt_status = NT_STATUS_NO_MORE_ENTRIES;
+       if (*r->in.resume_handle >= count) {
+               *r->out.resume_handle = -1;
+               TALLOC_FREE(entries);
+               return NT_STATUS_NO_MORE_ENTRIES;
        }
 
-       /* set up the lsa_enum_trust_dom response */
+       /* return the rest, limit by max_size. Note that we
+          use the w2k3 element size value of 60 */
+       r->out.domains->count = count - *r->in.resume_handle;
+       r->out.domains->count = MIN(r->out.domains->count,
+                                1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_MULTIPLIER));
 
-       lsa_domains = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_DomainInfo,
-                                       num_thistime);
-       if (!lsa_domains) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       r->out.domains->domains = entries + *r->in.resume_handle;
 
-       for (i=0; i<num_thistime; i++) {
-               init_lsa_StringLarge(&lsa_domains[i].name, domains[i]->name);
-               lsa_domains[i].sid = &domains[i]->sid;
+       if (r->out.domains->count < count - *r->in.resume_handle) {
+               *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
+               return STATUS_MORE_ENTRIES;
        }
 
-       *r->out.resume_handle = next_idx;
-       r->out.domains->count = num_thistime;
-       r->out.domains->domains = lsa_domains;
+       /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
+        * always be larger than the previous input resume handle, in
+        * particular when hitting the last query it is vital to set the
+        * resume handle correctly to avoid infinite client loops, as
+        * seen e.g. with Windows XP SP3 when resume handle is 0 and
+        * status is NT_STATUS_OK - gd */
 
-       return nt_status;
+       *r->out.resume_handle = (uint32_t)-1;
+
+       return NT_STATUS_OK;
 }
 
 #define LSA_AUDIT_NUM_CATEGORIES_NT4   7
@@ -561,6 +578,38 @@ NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p,
        }
 
        switch (r->in.level) {
+       /* according to MS-LSAD 3.1.4.4.3 */
+       case LSA_POLICY_INFO_MOD:
+       case LSA_POLICY_INFO_AUDIT_FULL_SET:
+       case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+               return NT_STATUS_INVALID_PARAMETER;
+       case LSA_POLICY_INFO_AUDIT_LOG:
+               info->audit_log.percent_full            = 0;
+               info->audit_log.maximum_log_size        = 0;
+               info->audit_log.retention_time          = 0;
+               info->audit_log.shutdown_in_progress    = 0;
+               info->audit_log.time_to_shutdown        = 0;
+               info->audit_log.next_audit_record       = 0;
+               status = NT_STATUS_OK;
+               break;
+       case LSA_POLICY_INFO_PD:
+               info->pd.name.string                    = NULL;
+               status = NT_STATUS_OK;
+               break;
+       case LSA_POLICY_INFO_REPLICA:
+               info->replica.source.string             = NULL;
+               info->replica.account.string            = NULL;
+               status = NT_STATUS_OK;
+               break;
+       case LSA_POLICY_INFO_QUOTA:
+               info->quota.paged_pool                  = 0;
+               info->quota.non_paged_pool              = 0;
+               info->quota.min_wss                     = 0;
+               info->quota.max_wss                     = 0;
+               info->quota.pagefile                    = 0;
+               info->quota.unknown                     = 0;
+               status = NT_STATUS_OK;
+               break;
        case LSA_POLICY_INFO_AUDIT_EVENTS:
                {
 
@@ -1016,23 +1065,24 @@ NTSTATUS _lsa_LookupSids3(pipes_struct *p,
 /***************************************************************************
  ***************************************************************************/
 
-static int lsa_lookup_level_to_flags(uint16 level)
+static int lsa_lookup_level_to_flags(enum lsa_LookupNamesLevel level)
 {
        int flags;
 
        switch (level) {
-               case 1:
+               case LSA_LOOKUP_NAMES_ALL: /* 1 */
                        flags = LOOKUP_NAME_ALL;
                        break;
-               case 2:
+               case LSA_LOOKUP_NAMES_DOMAINS_ONLY: /* 2 */
                        flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_REMOTE|LOOKUP_NAME_ISOLATED;
                        break;
-               case 3:
+               case LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY: /* 3 */
                        flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED;
                        break;
-               case 4:
-               case 5:
-               case 6:
+               case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY: /* 4 */
+               case LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY: /* 5 */
+               case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2: /* 6 */
+               case LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC: /* 7 */
                default:
                        flags = LOOKUP_NAME_NONE;
                        break;
@@ -1641,6 +1691,10 @@ NTSTATUS _lsa_CreateAccount(pipes_struct *p,
        struct lsa_info *handle;
        struct lsa_info *info;
        uint32_t acc_granted;
+       uint32_t owner_access = (LSA_ACCOUNT_ALL_ACCESS &
+                       ~(LSA_ACCOUNT_ADJUST_PRIVILEGES|
+                       LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|
+                       STD_RIGHT_DELETE_ACCESS));
        struct security_descriptor *psd;
        size_t sd_size;
 
@@ -1658,19 +1712,24 @@ NTSTATUS _lsa_CreateAccount(pipes_struct *p,
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       /* Work out max allowed. */
+       map_max_allowed_access(p->server_info->ptok,
+                              &p->server_info->utok,
+                              &r->in.access_mask);
+
        /* map the generic bits to the lsa policy ones */
        se_map_generic(&r->in.access_mask, &lsa_account_mapping);
 
        status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size,
                                    &lsa_account_mapping,
-                                   r->in.sid, LSA_POLICY_ALL_ACCESS);
+                                   r->in.sid, owner_access);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-        status = access_check_object(psd, p->server_info->ptok,
-                NULL, 0, r->in.access_mask,
-                &acc_granted, "_lsa_CreateAccount");
+       status = access_check_object(psd, p->server_info->ptok,
+                                    NULL, 0, r->in.access_mask,
+                                    &acc_granted, "_lsa_CreateAccount");
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1709,6 +1768,10 @@ NTSTATUS _lsa_OpenAccount(pipes_struct *p,
        size_t sd_size;
        uint32_t des_access = r->in.access_mask;
        uint32_t acc_granted;
+       uint32_t owner_access = (LSA_ACCOUNT_ALL_ACCESS &
+                       ~(LSA_ACCOUNT_ADJUST_PRIVILEGES|
+                       LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|
+                       STD_RIGHT_DELETE_ACCESS));
        NTSTATUS status;
 
        /* find the connection policy handle. */
@@ -1733,15 +1796,14 @@ NTSTATUS _lsa_OpenAccount(pipes_struct *p,
        /* get the generic lsa account SD until we store it */
        status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size,
                                &lsa_account_mapping,
-                               r->in.sid, LSA_ACCOUNT_ALL_ACCESS);
+                               r->in.sid, owner_access);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        status = access_check_object(psd, p->server_info->ptok,
-               NULL, 0, des_access,
-               &acc_granted, "_lsa_OpenAccount" );
-
+                                    NULL, 0, des_access,
+                                    &acc_granted, "_lsa_OpenAccount" );
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2070,15 +2132,19 @@ NTSTATUS _lsa_QuerySecurity(pipes_struct *p,
        if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle))
                return NT_STATUS_INVALID_HANDLE;
 
-       if (handle->type == LSA_HANDLE_POLICY_TYPE) {
+       switch (handle->type) {
+       case LSA_HANDLE_POLICY_TYPE:
                status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size,
                                &lsa_policy_mapping, NULL, 0);
-       } else if (handle->type == LSA_HANDLE_ACCOUNT_TYPE) {
+               break;
+       case LSA_HANDLE_ACCOUNT_TYPE:
                status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size,
                                &lsa_account_mapping,
                                &handle->sid, LSA_ACCOUNT_ALL_ACCESS);
-       } else {
+               break;
+       default:
                status = NT_STATUS_INVALID_HANDLE;
+               break;
        }
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -2116,10 +2182,10 @@ NTSTATUS _lsa_AddAccountRights(pipes_struct *p,
                return NT_STATUS_INVALID_HANDLE;
        }
 
-        /* get the generic lsa account SD for this SID until we store it */
+        /* get the generic lsa account SD until we store it */
         status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size,
                                 &lsa_account_mapping,
-                                r->in.sid, LSA_ACCOUNT_ALL_ACCESS);
+                                NULL, 0);
         if (!NT_STATUS_IS_OK(status)) {
                 return status;
         }
@@ -2131,10 +2197,10 @@ NTSTATUS _lsa_AddAccountRights(pipes_struct *p,
         * on the account sid. We don't check here so just use the latter. JRA.
         */
 
-        status = access_check_object(psd, p->server_info->ptok,
-                NULL, 0, LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW,
-                &acc_granted, "_lsa_AddAccountRights" );
-
+       status = access_check_object(psd, p->server_info->ptok,
+                                    NULL, 0,
+                                    LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW,
+                                    &acc_granted, "_lsa_AddAccountRights" );
         if (!NT_STATUS_IS_OK(status)) {
                 return status;
         }
@@ -2187,10 +2253,10 @@ NTSTATUS _lsa_RemoveAccountRights(pipes_struct *p,
                return NT_STATUS_INVALID_HANDLE;
        }
 
-        /* get the generic lsa account SD for this SID until we store it */
+        /* get the generic lsa account SD until we store it */
         status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size,
                                 &lsa_account_mapping,
-                                r->in.sid, LSA_ACCOUNT_ALL_ACCESS);
+                                NULL, 0);
         if (!NT_STATUS_IS_OK(status)) {
                 return status;
         }
@@ -2201,11 +2267,11 @@ NTSTATUS _lsa_RemoveAccountRights(pipes_struct *p,
         * and DELETE on the account sid.
         */
 
-        status = access_check_object(psd, p->server_info->ptok,
-                NULL, 0, LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|
-                       LSA_ACCOUNT_VIEW|STD_RIGHT_DELETE_ACCESS,
-                &acc_granted, "_lsa_AddAccountRights" );
-
+       status = access_check_object(psd, p->server_info->ptok,
+                                    NULL, 0,
+                                    LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|
+                                    LSA_ACCOUNT_VIEW|STD_RIGHT_DELETE_ACCESS,
+                                    &acc_granted, "_lsa_RemoveAccountRights");
         if (!NT_STATUS_IS_OK(status)) {
                 return status;
         }