s4-samr: Adapted SAMR calls to use system session, with access check for administrator aclsearch
authorNadezhda Ivanova <nivanova@samba.org>
Fri, 13 Aug 2010 09:26:55 +0000 (12:26 +0300)
committerNadezhda Ivanova <nivanova@samba.org>
Mon, 16 Aug 2010 18:00:45 +0000 (21:00 +0300)
The current acl module applies the access checks for the LDAP protocol. These should not be
applied to other protocols such as SAMR and LSA, and will break their operation. Therefore
SAMR will connect to LDB as system, and perform a check to disallow modify access to non-administrators.

source4/rpc_server/samr/dcesrv_samr.c

index e222a41d26412049306ae9d9545b299ca9c2212f..7bb014d40679bdbdbd94af58d90f5ca6f1090204 100644 (file)
@@ -39,6 +39,8 @@
 #include "../lib/util/util_ldb.h"
 #include "param/param.h"
 #include "lib/util/tsort.h"
+#include "auth/auth.h"
+#include "auth/session.h"
 
 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
 
        }                                                               \
 } while (0)
 
-
+static NTSTATUS dcesrv_samr_access_check(struct dcesrv_call_state *dce_call)
+{
+       if (security_token_is_system(dce_call->conn->auth_state.session_info->security_token) ||
+            security_token_has_builtin_administrators(dce_call->conn->auth_state.session_info->security_token)) {
+               return NT_STATUS_OK;
+       } else {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+}
 
 /* 
   samr_Connect 
@@ -173,7 +183,8 @@ static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_C
        }
 
        /* make sure the sam database is accessible */
-       c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+       c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
+                                        system_session(dce_call->conn->dce_ctx->lp_ctx));
        if (c_state->sam_ctx == NULL) {
                talloc_free(c_state);
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
@@ -187,7 +198,6 @@ static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_C
        }
 
        handle->data = talloc_steal(handle, c_state);
-
        c_state->access_mask = r->in.access_mask;
        *r->out.connect_handle = handle->wire_handle;
 
@@ -908,6 +918,7 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA
        struct ldb_message *msg;
        int ret;
        struct ldb_context *sam_ctx;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
 
@@ -978,6 +989,11 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
+       /* writes are only allowed to system or administrator */
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
        /* modify the samdb record */
        ret = ldb_modify(sam_ctx, msg);
        if (ret != LDB_SUCCESS) {
@@ -1885,6 +1901,7 @@ static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TAL
        struct ldb_message *msg;
        struct ldb_context *sam_ctx;
        int ret;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
 
@@ -1917,6 +1934,12 @@ static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TAL
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
+/* writes are only allowed to system or administrator */
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* modify the samdb record */
        ret = ldb_modify(g_state->sam_ctx, msg);
        if (ret != LDB_SUCCESS) {
@@ -1943,6 +1966,7 @@ static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, T
        struct ldb_result *res;
        const char * const attrs[] = { NULL };
        int ret;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
 
@@ -1990,6 +2014,11 @@ static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, T
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        ret = ldb_modify(a_state->sam_ctx, mod);
        switch (ret) {
        case LDB_SUCCESS:
@@ -2014,6 +2043,7 @@ static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call
        struct dcesrv_handle *h;
        struct samr_account_state *a_state;
        int ret;
+       NTSTATUS status;
 
         *r->out.group_handle = *r->in.group_handle;
 
@@ -2021,6 +2051,11 @@ static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call
 
        a_state = h->data;
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_UNSUCCESSFUL;
@@ -2048,6 +2083,7 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call
        struct ldb_result *res;
        const char * const attrs[] = { NULL };
        int ret;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
 
@@ -2095,6 +2131,10 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call
                return NT_STATUS_NO_MEMORY;
        }
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
        ret = ldb_modify(a_state->sam_ctx, mod);
        switch (ret) {
        case LDB_SUCCESS:
@@ -2337,6 +2377,7 @@ static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TAL
        struct ldb_message *msg;
        struct ldb_context *sam_ctx;
        int ret;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
 
@@ -2366,6 +2407,10 @@ static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TAL
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
        /* modify the samdb record */
        ret = ldb_modify(a_state->sam_ctx, msg);
        if (ret != LDB_SUCCESS) {
@@ -2386,6 +2431,7 @@ static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, T
        struct dcesrv_handle *h;
        struct samr_account_state *a_state;
        int ret;
+       NTSTATUS status;
 
         *r->out.alias_handle = *r->in.alias_handle;
 
@@ -2393,6 +2439,11 @@ static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, T
 
        a_state = h->data;
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
        if (ret != LDB_SUCCESS) {
                return NT_STATUS_UNSUCCESSFUL;
@@ -2462,6 +2513,11 @@ static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, T
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        ret = ldb_modify(a_state->sam_ctx, mod);
        switch (ret) {
        case LDB_SUCCESS:
@@ -2489,6 +2545,7 @@ static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call
        struct ldb_message *mod;
        const char *memberdn;
        int ret;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
 
@@ -2515,6 +2572,11 @@ static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        ret = ldb_modify(a_state->sam_ctx, mod);
        switch (ret) {
        case LDB_SUCCESS:
@@ -2663,6 +2725,7 @@ static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLO
        struct dcesrv_handle *h;
        struct samr_account_state *a_state;
        int ret;
+       NTSTATUS status;
 
        *r->out.user_handle = *r->in.user_handle;
 
@@ -2670,6 +2733,11 @@ static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLO
 
        a_state = h->data;
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
        if (ret != LDB_SUCCESS) {
                DEBUG(1, ("Failed to delete user: %s: %s\n", 
@@ -3525,6 +3593,11 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL
                return status;
        }
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* modify the samdb record */
        if (msg->num_elements > 0) {
                ret = ldb_modify(a_state->sam_ctx, msg);
@@ -3898,6 +3971,7 @@ static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_sta
        struct ldb_message **res;
        const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
        int i, count;
+       NTSTATUS status;
 
        DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
 
@@ -3926,6 +4000,11 @@ static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_sta
        if (count < 0)
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
+       status = dcesrv_samr_access_check(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        for (i=0; i<count; i++) {
                struct ldb_message *mod;
 
@@ -4095,7 +4174,7 @@ static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TAL
 
        sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
                                         dce_call->conn->dce_ctx->lp_ctx,
-                                        dce_call->conn->auth_state.session_info);
+                                        system_session(dce_call->conn->dce_ctx->lp_ctx));
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }