Add "uint32_t access_granted" to policy handles
authorVolker Lendecke <vl@samba.org>
Sat, 18 Apr 2009 14:46:53 +0000 (16:46 +0200)
committerVolker Lendecke <vl@samba.org>
Sun, 19 Apr 2009 07:27:15 +0000 (09:27 +0200)
All policy handles have a mask of allowed operations attached that were
calculated at creation time, so they should carry this mask. This is the basis
for consolidating all our policy handle access checks.

If you want to do your own more complicated access checks further down, just
pass "0" to policy_handle_find.

source3/include/proto.h
source3/rpc_server/srv_lsa_hnd.c
source3/rpc_server/srv_samr_nt.c

index b99588f71706bcd9f6c4d1e26532c91d5db46d12..fa60e6de09524800c36e2cb2f6d74b078da0795e 100644 (file)
@@ -5885,16 +5885,21 @@ bool close_policy_hnd(pipes_struct *p, struct policy_handle *hnd);
 void close_policy_by_pipe(pipes_struct *p);
 bool pipe_access_check(pipes_struct *p);
 
-NTSTATUS _policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
-                              void *pdata, size_t size, const char *name);
-#define policy_handle_create(_p, _hnd, _ptr, _type) \
-       _policy_handle_create((_p), (_hnd), (_ptr), sizeof(_type), #_type)
+void *_policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
+                           uint32_t access_granted, size_t data_size,
+                           const char *type, NTSTATUS *pstatus);
+#define policy_handle_create(_p, _hnd, _access, _type, _pstatus) \
+       (_type *)_policy_handle_create((_p), (_hnd), (_access), sizeof(_type), #_type, \
+                                      (_pstatus))
 
 void *_policy_handle_find(struct pipes_struct *p,
                          const struct policy_handle *hnd,
-                         const char *type);
-#define policy_handle_find(_p, _hnd, _type) \
-       (_type *)_policy_handle_find((_p), (_hnd), #_type)
+                         uint32_t access_required, uint32_t *paccess_granted,
+                         const char *name, const char *location,
+                         NTSTATUS *pstatus);
+#define policy_handle_find(_p, _hnd, _access_required, _access_granted, _type, _pstatus) \
+       (_type *)_policy_handle_find((_p), (_hnd), (_access_required), \
+                                    (_access_granted), #_type, __location__, (_pstatus))
 
 
 /* The following definitions come from rpc_server/srv_pipe.c  */
index 9891ff39648e8f41962ba6a7c61e2e8fa182cc3c..2490ca30db568c564b8288c902b16506a097b514 100644 (file)
@@ -33,6 +33,8 @@ struct policy {
 
        struct policy_handle pol_hnd;
 
+       uint32_t access_granted;
+
        void *data_ptr;
 };
 
@@ -138,7 +140,9 @@ bool init_pipe_handle_list(pipes_struct *p, const struct ndr_syntax_id *syntax)
   data_ptr is TALLOC_FREE()'ed
 ****************************************************************************/
 
-bool create_policy_hnd(pipes_struct *p, struct policy_handle *hnd, void *data_ptr)
+static struct policy *create_policy_hnd_internal(pipes_struct *p,
+                                                struct policy_handle *hnd,
+                                                void *data_ptr)
 {
        static uint32 pol_hnd_low  = 0;
        static uint32 pol_hnd_high = 0;
@@ -149,13 +153,13 @@ bool create_policy_hnd(pipes_struct *p, struct policy_handle *hnd, void *data_pt
        if (p->pipe_handles->count > MAX_OPEN_POLS) {
                DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
                                (int)p->pipe_handles->count));
-               return False;
+               return NULL;
        }
 
        pol = TALLOC_ZERO_P(NULL, struct policy);
        if (!pol) {
                DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
-               return False;
+               return NULL;
        }
 
        if (data_ptr != NULL) {
@@ -186,7 +190,13 @@ bool create_policy_hnd(pipes_struct *p, struct policy_handle *hnd, void *data_pt
        DEBUG(4,("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
        dump_data(4, (uint8 *)hnd, sizeof(*hnd));
 
-       return True;
+       return pol;
+}
+
+bool create_policy_hnd(pipes_struct *p, struct policy_handle *hnd,
+                      void *data_ptr)
+{
+       return create_policy_hnd_internal(p, hnd, data_ptr) != NULL;
 }
 
 /****************************************************************************
@@ -307,47 +317,80 @@ bool pipe_access_check(pipes_struct *p)
        return True;
 }
 
-NTSTATUS _policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
-                              void *pdata, size_t data_size, const char *type)
+void *_policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
+                           uint32_t access_granted, size_t data_size,
+                           const char *type, NTSTATUS *pstatus)
 {
-       void **ppdata = (void **)pdata;
+       struct policy *pol;
        void *data;
 
        if (p->pipe_handles->count > MAX_OPEN_POLS) {
                DEBUG(0, ("policy_handle_create: ERROR: too many handles (%d) "
                          "on pipe %s.\n", (int)p->pipe_handles->count,
                          get_pipe_name_from_iface(&p->syntax)));
-               return NT_STATUS_INSUFFICIENT_RESOURCES;
+               *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
+               return NULL;
        }
 
        data = talloc_size(talloc_tos(), data_size);
        if (data == NULL) {
-               return NT_STATUS_NO_MEMORY;
+               *pstatus = NT_STATUS_NO_MEMORY;
+               return NULL;
        }
        talloc_set_name(data, type);
 
-       if (!create_policy_hnd(p, hnd, data)) {
+       pol = create_policy_hnd_internal(p, hnd, data);
+       if (pol == NULL) {
                TALLOC_FREE(data);
-               return NT_STATUS_NO_MEMORY;
+               *pstatus = NT_STATUS_NO_MEMORY;
+               return NULL;
        }
-       *ppdata = data;
-       return NT_STATUS_OK;
+       pol->access_granted = access_granted;
+       *pstatus = NT_STATUS_OK;
+       return data;
 }
 
 void *_policy_handle_find(struct pipes_struct *p,
                          const struct policy_handle *hnd,
-                         const char *name)
+                         uint32_t access_required,
+                         uint32_t *paccess_granted,
+                         const char *name, const char *location,
+                         NTSTATUS *pstatus)
 {
+       struct policy *pol;
        void *data;
 
-       if (find_policy_by_hnd_internal(p, hnd, &data) == NULL) {
+       pol = find_policy_by_hnd_internal(p, hnd, &data);
+       if (pol == NULL) {
+               *pstatus = NT_STATUS_INVALID_HANDLE;
                return NULL;
        }
        if (strcmp(name, talloc_get_name(data)) != 0) {
                DEBUG(10, ("expected %s, got %s\n", name,
                           talloc_get_name(data)));
+               *pstatus = NT_STATUS_INVALID_HANDLE;
                return NULL;
        }
+       if ((access_required & pol->access_granted) != access_required) {
+               if (geteuid() == sec_initial_uid()) {
+                       DEBUG(4, ("%s: ACCESS should be DENIED (granted: "
+                                 "%#010x; required: %#010x)\n", location,
+                                 pol->access_granted, access_required));
+                       DEBUGADD(4,("but overwritten by euid == 0\n"));
+                       goto okay;
+               }
+               DEBUG(2,("%s: ACCESS DENIED (granted: %#010x; required: "
+                        "%#010x)\n", location, pol->access_granted,
+                        access_required));
+               *pstatus = NT_STATUS_ACCESS_DENIED;
+               return NULL;
+       }
+
+ okay:
        DEBUG(10, ("found handle of type %s\n", talloc_get_name(data)));
+       if (paccess_granted != NULL) {
+               *paccess_granted = pol->access_granted;
+       }
+       *pstatus = NT_STATUS_OK;
        return data;
 }
index 159760c4c8326a576ae615843df0c2c8f8b1d87e..b18011c1f9db5bcbd57334a27a33da3674f6f5b1 100644 (file)
@@ -49,7 +49,7 @@
 #define MAX_SAM_ENTRIES_W95 50
 
 struct samr_connect_info {
-       uint32_t acc_granted;
+       uint8_t dummy;
 };
 
 typedef struct disp_info {
@@ -613,10 +613,10 @@ NTSTATUS _samr_OpenDomain(pipes_struct *p,
 
        /* find the connection policy handle. */
 
-       cinfo = policy_handle_find(p, r->in.connect_handle,
-                                  struct samr_connect_info);
-       if (cinfo == NULL) {
-               return NT_STATUS_INVALID_HANDLE;
+       cinfo = policy_handle_find(p, r->in.connect_handle, 0, NULL,
+                                  struct samr_connect_info, &status);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        /*check if access can be granted as requested by client. */
@@ -3198,6 +3198,7 @@ NTSTATUS _samr_Connect(pipes_struct *p,
                       struct samr_Connect *r)
 {
        struct samr_connect_info *info;
+       uint32_t acc_granted;
        struct policy_handle hnd;
        uint32    des_access = r->in.access_mask;
        NTSTATUS status;
@@ -3209,14 +3210,6 @@ NTSTATUS _samr_Connect(pipes_struct *p,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       /* set up the SAMR connect_anon response */
-
-       status = policy_handle_create(p, &hnd, &info,
-                                     struct samr_connect_info);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
        /* don't give away the farm but this is probably ok.  The SAMR_ACCESS_ENUM_DOMAINS
           was observed from a win98 client trying to enumerate users (when configured
           user level access control on shares)   --jerry */
@@ -3224,7 +3217,18 @@ NTSTATUS _samr_Connect(pipes_struct *p,
        map_max_allowed_access(p->server_info->ptok, &des_access);
 
        se_map_generic( &des_access, &sam_generic_mapping );
-       info->acc_granted = des_access & (SAMR_ACCESS_ENUM_DOMAINS|SAMR_ACCESS_LOOKUP_DOMAIN);
+
+       acc_granted = des_access & (SAMR_ACCESS_ENUM_DOMAINS
+                                   |SAMR_ACCESS_LOOKUP_DOMAIN);
+
+       /* set up the SAMR connect_anon response */
+
+       info = policy_handle_create(p, &hnd, acc_granted,
+                                   struct samr_connect_info,
+                                   &status);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        *r->out.connect_handle = hnd;
        return NT_STATUS_OK;
@@ -3281,14 +3285,12 @@ NTSTATUS _samr_Connect2(pipes_struct *p,
        if ( !NT_STATUS_IS_OK(nt_status) )
                return nt_status;
 
-       nt_status = policy_handle_create(p, &hnd, &info,
-                                        struct samr_connect_info);
+       info = policy_handle_create(p, &hnd, acc_granted,
+                                   struct samr_connect_info, &nt_status);
         if (!NT_STATUS_IS_OK(nt_status)) {
                 return nt_status;
         }
 
-       info->acc_granted = acc_granted;
-
        DEBUG(5,("%s: %d\n", fn, __LINE__));
 
        *r->out.connect_handle = hnd;
@@ -3363,23 +3365,18 @@ NTSTATUS _samr_Connect5(pipes_struct *p,
 NTSTATUS _samr_LookupDomain(pipes_struct *p,
                            struct samr_LookupDomain *r)
 {
-       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS status;
        struct samr_connect_info *info;
        const char *domain_name;
        DOM_SID *sid = NULL;
 
-       info = policy_handle_find(p, r->in.connect_handle,
-                                 struct samr_connect_info);
-       if (info == NULL) {
-               return NT_STATUS_INVALID_HANDLE;
-       }
-
        /* win9x user manager likes to use SAMR_ACCESS_ENUM_DOMAINS here.
           Reverted that change so we will work with RAS servers again */
 
-       status = access_check_samr_function(info->acc_granted,
-                                           SAMR_ACCESS_LOOKUP_DOMAIN,
-                                           "_samr_LookupDomain");
+       info = policy_handle_find(p, r->in.connect_handle,
+                                 SAMR_ACCESS_LOOKUP_DOMAIN, NULL,
+                                 struct samr_connect_info,
+                                 &status);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -3424,14 +3421,8 @@ NTSTATUS _samr_EnumDomains(pipes_struct *p,
        struct samr_SamArray *sam;
 
        info = policy_handle_find(p, r->in.connect_handle,
-                                 struct samr_connect_info);
-       if (info == NULL) {
-               return NT_STATUS_INVALID_HANDLE;
-       }
-
-       status = access_check_samr_function(info->acc_granted,
-                                           SAMR_ACCESS_ENUM_DOMAINS,
-                                           "_samr_EnumDomains");
+                                 SAMR_ACCESS_ENUM_DOMAINS, NULL,
+                                 struct samr_connect_info, &status);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }