s4-dsdb: change samdb_replace() to dsdb_replace() and allow for dsdb_flags
[ira/wip.git] / source4 / rpc_server / samr / dcesrv_samr.c
index 5b9aa91ded980f12883e829144d8e59c5170eca7..61a9f1350ba964e8b1b40d9b6a47e976c3a34140 100644 (file)
@@ -37,6 +37,7 @@
 #include "rpc_server/samr/proto.h"
 #include "../lib/util/util_ldb.h"
 #include "param/param.h"
+#include "lib/util/tsort.h"
 
 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
 
@@ -165,7 +166,7 @@ static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_C
 
        ZERO_STRUCTP(r->out.connect_handle);
 
-       c_state = talloc(dce_call->conn, struct samr_connect_state);
+       c_state = talloc(mem_ctx, struct samr_connect_state);
        if (!c_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -398,7 +399,7 @@ static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLO
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       d_state = talloc(c_state, struct samr_domain_state);
+       d_state = talloc(mem_ctx, struct samr_domain_state);
        if (!d_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -518,14 +519,14 @@ static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state
        }
 
        /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
-       info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, 
+       info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn,
                                             "(objectClass=user)");
-       info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
-                                             "(&(objectClass=group)(sAMAccountType=%u))",
-                                             ATYPE_GLOBAL_GROUP);
-       info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
-                                              "(&(objectClass=group)(sAMAccountType=%u))",
-                                              ATYPE_LOCAL_GROUP);
+       info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn,
+                                             "(&(objectClass=group)(groupType=%u))",
+                                             GTYPE_SECURITY_GLOBAL_GROUP);
+       info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn,
+                                              "(&(objectClass=group)(groupType=%u))",
+                                              GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
 
        return NT_STATUS_OK;
 }
@@ -797,8 +798,10 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
                break;
        }
        case 9:
+       {
                attrs = NULL;
-               break;          
+               break;
+       }
        case 11:
        {
                static const char * const attrs2[] = { "oEMInformation",
@@ -828,6 +831,10 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
                attrs = attrs2;
                break;
        }
+       default:
+       {
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }
        }
 
        /* some levels don't need a search */
@@ -881,9 +888,9 @@ static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
        case 13:
                return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, 
                                                  &info->info13);
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
        }
-
-       return NT_STATUS_INVALID_INFO_CLASS;
 }
 
 
@@ -936,7 +943,28 @@ static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TA
                return NT_STATUS_OK;
 
        case 12:
-               
+               /*
+                * It is not possible to set lockout_duration < lockout_window.
+                * (The test is the other way around since the negative numbers
+                *  are stored...)
+                *
+                * TODO:
+                *   This check should be moved to the backend, i.e. to some
+                *   ldb module under dsdb/samdb/ldb_modules/ .
+                *
+                * This constraint is documented here for the samr rpc service:
+                * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
+                * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
+                *
+                * And here for the ldap backend:
+                * MS-ADTS 3.1.1.5.3.2 Constraints
+                * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
+                */
+               if (r->in.info->info12.lockout_duration >
+                   r->in.info->info12.lockout_window)
+               {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
                SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
                SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
                SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
@@ -1040,7 +1068,7 @@ static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       a_state = talloc(d_state, struct samr_account_state);
+       a_state = talloc(mem_ctx, struct samr_account_state);
        if (!a_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1141,8 +1169,7 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call,
        }
 
        /* sort the results by rid */
-       qsort(entries, count, sizeof(struct samr_SamEntry), 
-             (comparison_fn_t)compare_SamEntry);
+       TYPESAFE_QSORT(entries, count, compare_SamEntry);
 
        /* find the first entry to return */
        for (first=0;
@@ -1333,7 +1360,7 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       a_state = talloc(d_state, struct samr_account_state);
+       a_state = talloc(mem_ctx, struct samr_account_state);
        if (!a_state) {
                ldb_transaction_cancel(d_state->sam_ctx);
                return NT_STATUS_NO_MEMORY;
@@ -1388,7 +1415,7 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL
        }
 
        /* modify the samdb record */
-       ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
+       ret = dsdb_replace(a_state->sam_ctx, msg, 0);
        if (ret != LDB_SUCCESS) {
                DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
                         ldb_dn_get_linearized(msg->dn),
@@ -1502,8 +1529,7 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call,
        }
 
        /* sort the results by rid */
-       qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), 
-             (comparison_fn_t)compare_SamEntry);
+       TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry);
 
        /* find the first entry to return */
        for (first=0;
@@ -1614,7 +1640,7 @@ static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, T
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       a_state = talloc(d_state, struct samr_account_state);
+       a_state = talloc(mem_ctx, struct samr_account_state);
        if (!a_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1712,8 +1738,7 @@ static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call
        }
 
        /* sort the results by rid */
-       qsort(entries, count, sizeof(struct samr_SamEntry), 
-             (comparison_fn_t)compare_SamEntry);
+       TYPESAFE_QSORT(entries, count, compare_SamEntry);
 
        /* find the first entry to return */
        for (first=0;
@@ -2043,7 +2068,7 @@ static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       a_state = talloc(d_state, struct samr_account_state);
+       a_state = talloc(mem_ctx, struct samr_account_state);
        if (!a_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -2300,6 +2325,7 @@ static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       talloc_free(h);
        ZERO_STRUCTP(r->out.group_handle);
 
        return NT_STATUS_OK;
@@ -2519,7 +2545,7 @@ static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       a_state = talloc(d_state, struct samr_account_state);
+       a_state = talloc(mem_ctx, struct samr_account_state);
        if (!a_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -2672,10 +2698,11 @@ static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, T
        a_state = h->data;
 
        ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
-       if (ret != 0) {
+       if (ret != LDB_SUCCESS) {
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       talloc_free(h);
        ZERO_STRUCTP(r->out.alias_handle);
 
        return NT_STATUS_OK;
@@ -2962,6 +2989,7 @@ static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLO
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       talloc_free(h);
        ZERO_STRUCTP(r->out.user_handle);
 
        return NT_STATUS_OK;
@@ -3145,6 +3173,10 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA
                attrs = attrs2;
                break;
        }
+       case 18:
+       {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
        case 20:
        {
                static const char * const attrs2[] = {"userParameters",
@@ -3180,6 +3212,17 @@ static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TA
                attrs = attrs2;
                break;
        }
+       case 23:
+       case 24:
+       case 25:
+       case 26:
+       {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       default:
+       {
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }
        }
 
        /* pull all the user attributes */
@@ -4024,10 +4067,10 @@ static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_sta
                }
 
                if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
-                                        "member", memberdn) != 0)
+                                        "member", memberdn) != LDB_SUCCESS)
                        return NT_STATUS_NO_MEMORY;
 
-               if (ldb_modify(d_state->sam_ctx, mod) != 0)
+               if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
                        return NT_STATUS_UNSUCCESSFUL;
 
                talloc_free(mod);
@@ -4176,7 +4219,9 @@ static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TAL
 
        ZERO_STRUCTP(r->out.info);
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info); 
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
+                                        dce_call->conn->dce_ctx->lp_ctx,
+                                        dce_call->conn->auth_state.session_info);
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }
@@ -4202,7 +4247,7 @@ static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TAL
                "pwdProperties", 1);
 
        talloc_free(msgs);
-       talloc_free(sam_ctx);
+       talloc_unlink(mem_ctx, sam_ctx);
 
        return NT_STATUS_OK;
 }
@@ -4351,15 +4396,56 @@ static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call,
 
 
 /* 
-  samr_ValidatePassword 
+  samr_ValidatePassword
+
+  For now the call checks the password complexity (if active) and the minimum
+  password length on level 2 and 3. Level 1 is ignored for now.
 */
-static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                                     struct samr_ValidatePassword *r)
+static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
+                                            TALLOC_CTX *mem_ctx,
+                                            struct samr_ValidatePassword *r)
 {
-       /* just say it's OK for now - we need to hook this into our
-          password strength code later */
-       DEBUG(0,(__location__ ": Faking samr_ValidatePassword reply\n"));
+       struct samr_GetDomPwInfo r2;
+       struct samr_PwInfo pwInfo;
+       DATA_BLOB password;
+       enum samr_ValidationStatus res;
+       NTSTATUS status;
+
        (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
+
+       r2.in.domain_name = NULL;
+       r2.out.info = &pwInfo;
+       status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       switch (r->in.level) {
+       case NetValidateAuthentication:
+               /* we don't support this yet */
+               return NT_STATUS_NOT_SUPPORTED;
+       break;
+       case NetValidatePasswordChange:
+               password = data_blob_const(r->in.req->req2.password.string,
+                                          r->in.req->req2.password.length);
+               res = samdb_check_password(&password,
+                                          pwInfo.password_properties,
+                                          pwInfo.min_password_length);
+               (*r->out.rep)->ctr2.status = res;
+       break;
+       case NetValidatePasswordReset:
+               password = data_blob_const(r->in.req->req3.password.string,
+                                          r->in.req->req3.password.length);
+               res = samdb_check_password(&password,
+                                          pwInfo.password_properties,
+                                          pwInfo.min_password_length);
+               (*r->out.rep)->ctr3.status = res;
+       break;
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+       break;
+       }
+
        return NT_STATUS_OK;
 }