s4-dsdb: change samdb_replace() to dsdb_replace() and allow for dsdb_flags
[ira/wip.git] / source4 / rpc_server / lsa / dcesrv_lsa.c
index 3b70f3e93460fca9ba145ce90b9e63a6e3bf47c4..53526ce15cc9a70f84e3a3fab54b985e05659fd2 100644 (file)
@@ -1,3 +1,5 @@
+/* need access mask/acl implementation */
+
 /* 
    Unix SMB/CIFS implementation.
 
 */
 
 #include "rpc_server/lsa/lsa.h"
-#include "util/util_ldb.h"
-#include "libcli/ldap/ldap_ndr.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "librpc/gen_ndr/ndr_lsa.h"
 #include "../lib/crypto/crypto.h"
+#include "lib/util/tsort.h"
 
 /*
   this type allows us to distinguish handle types
@@ -64,6 +65,65 @@ struct lsa_trusted_domain_state {
        struct ldb_dn *trusted_domain_user_dn;
 };
 
+/*
+  this is based on the samba3 function make_lsa_object_sd()
+  It uses the same logic, but with samba4 helper functions
+ */
+static NTSTATUS dcesrv_build_lsa_sd(TALLOC_CTX *mem_ctx, 
+                                   struct security_descriptor **sd,
+                                   struct dom_sid *sid, 
+                                   uint32_t sid_access)
+{
+       NTSTATUS status;
+       uint32_t rid;
+       struct dom_sid *domain_sid, *domain_admins_sid;
+       const char *domain_admins_sid_str, *sidstr;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+       status = dom_sid_split_rid(tmp_ctx, sid, &domain_sid, &rid);
+       NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
+
+       domain_admins_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ADMINS);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_admins_sid, tmp_ctx);
+
+       domain_admins_sid_str = dom_sid_string(tmp_ctx, domain_admins_sid);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_admins_sid_str, tmp_ctx);
+       
+       sidstr = dom_sid_string(tmp_ctx, sid);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidstr, tmp_ctx);
+                                                     
+       *sd = security_descriptor_dacl_create(mem_ctx,
+                                             0, sidstr, NULL,
+
+                                             SID_WORLD,
+                                             SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                             SEC_GENERIC_EXECUTE | SEC_GENERIC_READ, 0,
+                                             
+                                             SID_BUILTIN_ADMINISTRATORS,
+                                             SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                             SEC_GENERIC_ALL, 0,
+                                             
+                                             SID_BUILTIN_ACCOUNT_OPERATORS,
+                                             SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                             SEC_GENERIC_ALL, 0,
+                                             
+                                             domain_admins_sid_str,
+                                             SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                             SEC_GENERIC_ALL, 0,
+
+                                             sidstr,
+                                             SEC_ACE_TYPE_ACCESS_ALLOWED,
+                                             sid_access, 0,
+
+                                             NULL);
+       talloc_free(tmp_ctx);
+
+       NT_STATUS_HAVE_NO_MEMORY(*sd);
+
+       return NT_STATUS_OK;
+}
+
+
 static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call, 
                                      TALLOC_CTX *mem_ctx,
                                      struct lsa_EnumAccountRights *r);
@@ -133,7 +193,7 @@ static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALL
                ret = ldb_delete(secret_state->sam_ldb, 
                                 secret_state->secret_dn);
                talloc_free(h);
-               if (ret != 0) {
+               if (ret != LDB_SUCCESS) {
                        return NT_STATUS_INVALID_HANDLE;
                }
 
@@ -141,15 +201,16 @@ static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALL
 
                return NT_STATUS_OK;
        } else if (h->wire_handle.handle_type == LSA_HANDLE_TRUSTED_DOMAIN) {
-               struct lsa_trusted_domain_state *trusted_domain_state = h->data;
+               struct lsa_trusted_domain_state *trusted_domain_state = 
+                       talloc_get_type(h->data, struct lsa_trusted_domain_state);
                ret = ldb_transaction_start(trusted_domain_state->policy->sam_ldb);
-               if (ret != 0) {
+               if (ret != LDB_SUCCESS) {
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
 
                ret = ldb_delete(trusted_domain_state->policy->sam_ldb, 
                                 trusted_domain_state->trusted_domain_dn);
-               if (ret != 0) {
+               if (ret != LDB_SUCCESS) {
                        ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
                        return NT_STATUS_INVALID_HANDLE;
                }
@@ -157,14 +218,14 @@ static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALL
                if (trusted_domain_state->trusted_domain_user_dn) {
                        ret = ldb_delete(trusted_domain_state->policy->sam_ldb, 
                                         trusted_domain_state->trusted_domain_user_dn);
-                       if (ret != 0) {
+                       if (ret != LDB_SUCCESS) {
                                ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
                                return NT_STATUS_INVALID_HANDLE;
                        }
                }
 
                ret = ldb_transaction_commit(trusted_domain_state->policy->sam_ldb);
-               if (ret != 0) {
+               if (ret != LDB_SUCCESS) {
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
                talloc_free(h);
@@ -187,6 +248,9 @@ static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALL
                r2.in.sid = astate->account_sid;
                r2.out.rights = rights;
 
+               /* dcesrv_lsa_EnumAccountRights takes a LSA_HANDLE_POLICY,
+                  but we have a LSA_HANDLE_ACCOUNT here, so this call
+                  will always fail */
                status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
                if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
                        return NT_STATUS_OK;
@@ -261,9 +325,33 @@ static NTSTATUS dcesrv_lsa_EnumPrivs(struct dcesrv_call_state *dce_call, TALLOC_
   lsa_QuerySecObj 
 */
 static NTSTATUS dcesrv_lsa_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                                 struct lsa_QuerySecurity *r)
+                                        struct lsa_QuerySecurity *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       struct dcesrv_handle *h;
+       struct security_descriptor *sd;
+       NTSTATUS status;
+       struct dom_sid *sid;
+
+       DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
+
+       sid = dce_call->conn->auth_state.session_info->security_token->user_sid;
+
+       if (h->wire_handle.handle_type == LSA_HANDLE_POLICY) {
+               status = dcesrv_build_lsa_sd(mem_ctx, &sd, sid, 0);
+       } else  if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) {
+               status = dcesrv_build_lsa_sd(mem_ctx, &sd, sid, 
+                                            LSA_ACCOUNT_ALL_ACCESS);
+       } else {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       (*r->out.sdbuf) = talloc(mem_ctx, struct sec_desc_buf);
+       NT_STATUS_HAVE_NO_MEMORY(*r->out.sdbuf);
+
+       (*r->out.sdbuf)->sd = sd;
+       
+       return NT_STATUS_OK;
 }
 
 
@@ -393,7 +481,6 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
        return WERR_INVALID_PARAM;
 }
 
-
 /*
   fill in the AccountDomain info
 */
@@ -429,33 +516,66 @@ static NTSTATUS dcesrv_lsa_QueryInfoPolicy2(struct dcesrv_call_state *dce_call,
 {
        struct lsa_policy_state *state;
        struct dcesrv_handle *h;
+       union lsa_PolicyInformation *info;
 
-       r->out.info = NULL;
+       *r->out.info = NULL;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
 
        state = h->data;
 
-       r->out.info = talloc(mem_ctx, union lsa_PolicyInformation);
-       if (!r->out.info) {
+       info = talloc_zero(mem_ctx, union lsa_PolicyInformation);
+       if (!info) {
                return NT_STATUS_NO_MEMORY;
        }
-
-       ZERO_STRUCTP(r->out.info);
+       *r->out.info = info;
 
        switch (r->in.level) {
+       case LSA_POLICY_INFO_AUDIT_LOG:
+               /* we don't need to fill in any of this */
+               ZERO_STRUCT(info->audit_log);
+               return NT_STATUS_OK;
+       case LSA_POLICY_INFO_AUDIT_EVENTS:
+               /* we don't need to fill in any of this */
+               ZERO_STRUCT(info->audit_events);
+               return NT_STATUS_OK;
+       case LSA_POLICY_INFO_PD:
+               /* we don't need to fill in any of this */
+               ZERO_STRUCT(info->pd);
+               return NT_STATUS_OK;
+
        case LSA_POLICY_INFO_DOMAIN:
+               return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &info->domain);
        case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
-               return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &r->out.info->account_domain);
+               return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &info->account_domain);
+       case LSA_POLICY_INFO_L_ACCOUNT_DOMAIN:
+               return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &info->l_account_domain);
+
+       case LSA_POLICY_INFO_ROLE:
+               info->role.role = LSA_ROLE_PRIMARY;
+               return NT_STATUS_OK;
 
        case LSA_POLICY_INFO_DNS:
-               return dcesrv_lsa_info_DNS(state, mem_ctx, &r->out.info->dns);
-       case LSA_POLICY_INFO_DB:
+       case LSA_POLICY_INFO_DNS_INT:
+               return dcesrv_lsa_info_DNS(state, mem_ctx, &info->dns);
+
+       case LSA_POLICY_INFO_REPLICA:
+               ZERO_STRUCT(info->replica);
+               return NT_STATUS_OK;
+
+       case LSA_POLICY_INFO_QUOTA:
+               ZERO_STRUCT(info->quota);
+               return NT_STATUS_OK;
+
+       case LSA_POLICY_INFO_MOD:
        case LSA_POLICY_INFO_AUDIT_FULL_SET:
        case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+               /* windows gives INVALID_PARAMETER */
+               *r->out.info = NULL;
                return NT_STATUS_INVALID_PARAMETER;
        }
 
+       *r->out.info = NULL;
        return NT_STATUS_INVALID_INFO_CLASS;
 }
 
@@ -468,13 +588,14 @@ static NTSTATUS dcesrv_lsa_QueryInfoPolicy(struct dcesrv_call_state *dce_call, T
        struct lsa_QueryInfoPolicy2 r2;
        NTSTATUS status;
 
+       ZERO_STRUCT(r2);
+
        r2.in.handle = r->in.handle;
        r2.in.level = r->in.level;
+       r2.out.info = r->out.info;
        
        status = dcesrv_lsa_QueryInfoPolicy2(dce_call, mem_ctx, &r2);
 
-       r->out.info = r2.out.info;
-
        return status;
 }
 
@@ -484,6 +605,7 @@ static NTSTATUS dcesrv_lsa_QueryInfoPolicy(struct dcesrv_call_state *dce_call, T
 static NTSTATUS dcesrv_lsa_SetInfoPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                                  struct lsa_SetInfoPolicy *r)
 {
+       /* need to support this */
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
@@ -502,6 +624,13 @@ static NTSTATUS dcesrv_lsa_ClearAuditLog(struct dcesrv_call_state *dce_call, TAL
   lsa_CreateAccount 
 
   This call does not seem to have any long-term effects, hence no database operations
+
+  we need to talk to the MS product group to find out what this account database means!
+
+  answer is that the lsa database is totally separate from the SAM and
+  ldap databases. We are going to need a separate ldb to store these
+  accounts. The SIDs on this account bear no relation to the SIDs in
+  AD
 */
 static NTSTATUS dcesrv_lsa_CreateAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                                  struct lsa_CreateAccount *r)
@@ -565,7 +694,7 @@ static NTSTATUS dcesrv_lsa_EnumAccounts(struct dcesrv_call_state *dce_call, TALL
        /* NOTE: This call must only return accounts that have at least
           one privilege set 
        */
-       ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, 
+       ret = gendb_search(state->pdb, mem_ctx, NULL, &res, attrs, 
                           "(&(objectSid=*)(privilege=*))");
        if (ret < 0) {
                return NT_STATUS_NO_SUCH_USER;
@@ -626,7 +755,7 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dc
        const char *name;
        DATA_BLOB session_key = data_blob(NULL, 0);
        DATA_BLOB trustAuthIncoming, trustAuthOutgoing, auth_blob;
-       struct trustAuthInAndOutBlob auth_struct;
+       struct trustDomainPasswords auth_struct;
        int ret;
        NTSTATUS nt_status;
        enum ndr_err_code ndr_err;
@@ -648,7 +777,7 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dc
        
        dns_name = r->in.info->domain_name.string;
        
-       trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+       trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
        if (!trusted_domain_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -679,16 +808,49 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dc
                ndr_err = ndr_pull_struct_blob(&auth_blob, mem_ctx, 
                                               lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
                                               &auth_struct,
-                                              (ndr_pull_flags_fn_t)ndr_pull_trustAuthInAndOutBlob);
+                                              (ndr_pull_flags_fn_t)ndr_pull_trustDomainPasswords);
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        return NT_STATUS_INVALID_PARAMETER;
                }                               
+
+               if (op == NDR_LSA_CREATETRUSTEDDOMAINEX) {
+                       if (auth_struct.incoming.count > 1) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
        }
 
        if (auth_struct.incoming.count) {
+               int i;
+               struct trustAuthInOutBlob incoming;
+               
+               incoming.count = auth_struct.incoming.count;
+               incoming.current = talloc(mem_ctx, struct AuthenticationInformationArray);
+               if (!incoming.current) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               incoming.current->array = *auth_struct.incoming.current;
+               if (!incoming.current->array) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               incoming.previous = talloc(mem_ctx, struct AuthenticationInformationArray);
+               if (!incoming.previous) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               incoming.previous->array = talloc_array(mem_ctx, struct AuthenticationInformation, incoming.count);
+               if (!incoming.previous->array) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               for (i = 0; i < incoming.count; i++) {
+                       incoming.previous->array[i].LastUpdateTime = 0;
+                       incoming.previous->array[i].AuthType = 0;
+               }
                ndr_err = ndr_push_struct_blob(&trustAuthIncoming, mem_ctx, 
                                               lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
-                                              &auth_struct.incoming,
+                                              &incoming,
                                               (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -698,9 +860,36 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dc
        }
        
        if (auth_struct.outgoing.count) {
+               int i;
+               struct trustAuthInOutBlob outgoing;
+               
+               outgoing.count = auth_struct.outgoing.count;
+               outgoing.current = talloc(mem_ctx, struct AuthenticationInformationArray);
+               if (!outgoing.current) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               outgoing.current->array = *auth_struct.outgoing.current;
+               if (!outgoing.current->array) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               outgoing.previous = talloc(mem_ctx, struct AuthenticationInformationArray);
+               if (!outgoing.previous) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               outgoing.previous->array = talloc_array(mem_ctx, struct AuthenticationInformation, outgoing.count);
+               if (!outgoing.previous->array) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               for (i = 0; i < outgoing.count; i++) {
+                       outgoing.previous->array[i].LastUpdateTime = 0;
+                       outgoing.previous->array[i].AuthType = 0;
+               }
                ndr_err = ndr_push_struct_blob(&trustAuthOutgoing, mem_ctx, 
                                               lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
-                                              &auth_struct.outgoing,
+                                              &outgoing,
                                               (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -825,7 +1014,7 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dc
 
        if (r->in.info->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
                msg_user = ldb_msg_new(mem_ctx);
-               if (msg == NULL) {
+               if (msg_user == NULL) {
                        ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
                        return NT_STATUS_NO_MEMORY;
                }
@@ -859,24 +1048,19 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dc
                if (auth_struct.incoming.count) {
                        int i;
                        for (i=0; i < auth_struct.incoming.count; i++ ) {
-                               if (auth_struct.incoming.current->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
-                                       samdb_msg_add_hash(trusted_domain_state->policy->sam_ldb, 
-                                                          mem_ctx, msg_user, "unicodePwd", 
-                                                          &auth_struct.incoming.current->array[i].AuthInfo.nt4owf.password);
-                               } else if (auth_struct.incoming.current->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
-                                       struct samr_Password hash;
-/*
-                                      . We cannot do this, as windows chooses to send in random passwords here, that won't convert to UTF8 
-                                       samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, 
-                                                            mem_ctx, msg_user, "userPassword", 
-                                                            auth_struct.incoming.current->array[i].AuthInfo.clear.password);
-*/
-                                       mdfour(hash.hash, auth_struct.incoming.current->array[i].AuthInfo.clear.password,
-                                              auth_struct.incoming.current->array[i].AuthInfo.clear.size);
+                               if (auth_struct.incoming.current[i]->AuthType == TRUST_AUTH_TYPE_NT4OWF) {
                                        samdb_msg_add_hash(trusted_domain_state->policy->sam_ldb, 
                                                           mem_ctx, msg_user, "unicodePwd", 
-                                                          &hash);
-                               }
+                                                          &auth_struct.incoming.current[i]->AuthInfo.nt4owf.password);
+                               } else if (auth_struct.incoming.current[i]->AuthType == TRUST_AUTH_TYPE_CLEAR) {
+                                       DATA_BLOB new_password = data_blob_const(auth_struct.incoming.current[i]->AuthInfo.clear.password,
+                                                                                auth_struct.incoming.current[i]->AuthInfo.clear.size);
+                                       ret = ldb_msg_add_value(msg_user, "clearTextPassword", &new_password, NULL);
+                                       if (ret != LDB_SUCCESS) {
+                                               ldb_transaction_cancel(policy_state->sam_ldb);
+                                               return NT_STATUS_NO_MEMORY;
+                                       }
+                               } 
                        }
                }
 
@@ -1004,7 +1188,7 @@ static NTSTATUS dcesrv_lsa_OpenTrustedDomain(struct dcesrv_call_state *dce_call,
        ZERO_STRUCTP(r->out.trustdom_handle);
        policy_state = policy_handle->data;
 
-       trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+       trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
        if (!trusted_domain_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1088,7 +1272,7 @@ static NTSTATUS dcesrv_lsa_OpenTrustedDomainByName(struct dcesrv_call_state *dce
                return NT_STATUS_INVALID_PARAMETER;
        }
        
-       trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+       trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
        if (!trusted_domain_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1157,28 +1341,28 @@ static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_cal
                                      struct lsa_DeleteTrustedDomain *r)
 {
        NTSTATUS status;
-       struct lsa_OpenTrustedDomain open;
-       struct lsa_DeleteObject delete;
+       struct lsa_OpenTrustedDomain opn;
+       struct lsa_DeleteObject del;
        struct dcesrv_handle *h;
 
-       open.in.handle = r->in.handle;
-       open.in.sid = r->in.dom_sid;
-       open.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       open.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
-       if (!open.out.trustdom_handle) {
+       opn.in.handle = r->in.handle;
+       opn.in.sid = r->in.dom_sid;
+       opn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       opn.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
+       if (!opn.out.trustdom_handle) {
                return NT_STATUS_NO_MEMORY;
        }
-       status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &open);
+       status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &opn);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       DCESRV_PULL_HANDLE(h, open.out.trustdom_handle, DCESRV_HANDLE_ANY);
+       DCESRV_PULL_HANDLE(h, opn.out.trustdom_handle, DCESRV_HANDLE_ANY);
        talloc_steal(mem_ctx, h);
 
-       delete.in.handle = open.out.trustdom_handle;
-       delete.out.handle = open.out.trustdom_handle;
-       status = dcesrv_lsa_DeleteObject(dce_call, mem_ctx, &delete);
+       del.in.handle = opn.out.trustdom_handle;
+       del.out.handle = opn.out.trustdom_handle;
+       status = dcesrv_lsa_DeleteObject(dce_call, mem_ctx, &del);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1210,6 +1394,7 @@ static NTSTATUS fill_trust_domain_ex(TALLOC_CTX *mem_ctx,
 static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                                           struct lsa_QueryTrustedDomainInfo *r)
 {
+       union lsa_TrustedDomainInfo *info = NULL;
        struct dcesrv_handle *h;
        struct lsa_trusted_domain_state *trusted_domain_state;
        struct ldb_message *msg;
@@ -1228,7 +1413,7 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
 
        DCESRV_PULL_HANDLE(h, r->in.trustdom_handle, LSA_HANDLE_TRUSTED_DOMAIN);
 
-       trusted_domain_state = h->data;
+       trusted_domain_state = talloc_get_type(h->data, struct lsa_trusted_domain_state);
 
        /* pull all the user attributes */
        ret = gendb_search_dn(trusted_domain_state->policy->sam_ldb, mem_ctx,
@@ -1238,17 +1423,19 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
        }
        msg = res[0];
        
-       r->out.info = talloc(mem_ctx, union lsa_TrustedDomainInfo);
-       if (!r->out.info) {
+       info = talloc_zero(mem_ctx, union lsa_TrustedDomainInfo);
+       if (!info) {
                return NT_STATUS_NO_MEMORY;
        }
+       *r->out.info = info;
+
        switch (r->in.level) {
        case LSA_TRUSTED_DOMAIN_INFO_NAME:
-               r->out.info->name.netbios_name.string
+               info->name.netbios_name.string
                        = samdb_result_string(msg, "flatname", NULL);                                      
                break;
        case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
-               r->out.info->posix_offset.posix_offset
+               info->posix_offset.posix_offset
                        = samdb_result_uint(msg, "posixOffset", 0);                                        
                break;
 #if 0  /* Win2k3 doesn't implement this */
@@ -1260,33 +1447,33 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
                break;
 #endif
        case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
-               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->info_ex);
+               return fill_trust_domain_ex(mem_ctx, msg, &info->info_ex);
 
        case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
-               ZERO_STRUCT(r->out.info->full_info);
-               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info.info_ex);
+               ZERO_STRUCT(info->full_info);
+               return fill_trust_domain_ex(mem_ctx, msg, &info->full_info.info_ex);
 
        case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL:
-               ZERO_STRUCT(r->out.info->full_info2_internal);
-               r->out.info->full_info2_internal.posix_offset.posix_offset
+               ZERO_STRUCT(info->full_info2_internal);
+               info->full_info2_internal.posix_offset.posix_offset
                        = samdb_result_uint(msg, "posixOffset", 0);                                        
-               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info2_internal.info.info_ex);
+               return fill_trust_domain_ex(mem_ctx, msg, &info->full_info2_internal.info.info_ex);
                
-       case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRTYPION_TYPES:
-               r->out.info->enc_types.enc_types
+       case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES:
+               info->enc_types.enc_types
                        = samdb_result_uint(msg, "msDs-supportedEncryptionTypes", KERB_ENCTYPE_RC4_HMAC_MD5);
                break;
 
        case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS:
        case LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL:
                /* oops, we don't want to return the info after all */
-               talloc_free(r->out.info);
-               r->out.info = NULL;
+               talloc_free(info);
+               *r->out.info = NULL;
                return NT_STATUS_INVALID_PARAMETER;
        default:
                /* oops, we don't want to return the info after all */
-               talloc_free(r->out.info);
-               r->out.info = NULL;
+               talloc_free(info);
+               *r->out.info = NULL;
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
@@ -1301,33 +1488,34 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfoBySid(struct dcesrv_call_state
                                                struct lsa_QueryTrustedDomainInfoBySid *r)
 {
        NTSTATUS status;
-       struct lsa_OpenTrustedDomain open;
+       struct lsa_OpenTrustedDomain opn;
        struct lsa_QueryTrustedDomainInfo query;
        struct dcesrv_handle *h;
-       open.in.handle = r->in.handle;
-       open.in.sid = r->in.dom_sid;
-       open.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       open.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
-       if (!open.out.trustdom_handle) {
+
+       opn.in.handle = r->in.handle;
+       opn.in.sid = r->in.dom_sid;
+       opn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       opn.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
+       if (!opn.out.trustdom_handle) {
                return NT_STATUS_NO_MEMORY;
        }
-       status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &open);
+       status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &opn);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        /* Ensure this handle goes away at the end of this call */
-       DCESRV_PULL_HANDLE(h, open.out.trustdom_handle, DCESRV_HANDLE_ANY);
+       DCESRV_PULL_HANDLE(h, opn.out.trustdom_handle, DCESRV_HANDLE_ANY);
        talloc_steal(mem_ctx, h);
-       
-       query.in.trustdom_handle = open.out.trustdom_handle;
+
+       query.in.trustdom_handle = opn.out.trustdom_handle;
        query.in.level = r->in.level;
+       query.out.info = r->out.info;
        status = dcesrv_lsa_QueryTrustedDomainInfo(dce_call, mem_ctx, &query);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
-       
-       r->out.info = query.out.info;
+
        return NT_STATUS_OK;
 }
 
@@ -1349,33 +1537,34 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfoByName(struct dcesrv_call_state
                                                 struct lsa_QueryTrustedDomainInfoByName *r)
 {
        NTSTATUS status;
-       struct lsa_OpenTrustedDomainByName open;
+       struct lsa_OpenTrustedDomainByName opn;
        struct lsa_QueryTrustedDomainInfo query;
        struct dcesrv_handle *h;
-       open.in.handle = r->in.handle;
-       open.in.name = r->in.trusted_domain;
-       open.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       open.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
-       if (!open.out.trustdom_handle) {
+
+       opn.in.handle = r->in.handle;
+       opn.in.name = *r->in.trusted_domain;
+       opn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       opn.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
+       if (!opn.out.trustdom_handle) {
                return NT_STATUS_NO_MEMORY;
        }
-       status = dcesrv_lsa_OpenTrustedDomainByName(dce_call, mem_ctx, &open);
+       status = dcesrv_lsa_OpenTrustedDomainByName(dce_call, mem_ctx, &opn);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
        
        /* Ensure this handle goes away at the end of this call */
-       DCESRV_PULL_HANDLE(h, open.out.trustdom_handle, DCESRV_HANDLE_ANY);
+       DCESRV_PULL_HANDLE(h, opn.out.trustdom_handle, DCESRV_HANDLE_ANY);
        talloc_steal(mem_ctx, h);
 
-       query.in.trustdom_handle = open.out.trustdom_handle;
+       query.in.trustdom_handle = opn.out.trustdom_handle;
        query.in.level = r->in.level;
+       query.out.info = r->out.info;
        status = dcesrv_lsa_QueryTrustedDomainInfo(dce_call, mem_ctx, &query);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
        
-       r->out.info = query.out.info;
        return NT_STATUS_OK;
 }
 
@@ -1448,8 +1637,7 @@ static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALL
        }
 
        /* sort the results by name */
-       qsort(entries, count, sizeof(*entries), 
-             (comparison_fn_t)compare_DomainInfo);
+       TYPESAFE_QSORT(entries, count, compare_DomainInfo);
 
        if (*r->in.resume_handle >= count) {
                *r->out.resume_handle = -1;
@@ -1471,6 +1659,15 @@ static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALL
                return STATUS_MORE_ENTRIES;
        }
 
+       /* 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 */
+
+       *r->out.resume_handle = (uint32_t)-1;
+
        return NT_STATUS_OK;
 }
 
@@ -1535,8 +1732,7 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca
        }
 
        /* sort the results by name */
-       qsort(entries, count, sizeof(*entries), 
-             (comparison_fn_t)compare_TrustDomainInfoInfoEx);
+       TYPESAFE_QSORT(entries, count, compare_TrustDomainInfoInfoEx);
 
        if (*r->in.resume_handle >= count) {
                *r->out.resume_handle = -1;
@@ -1620,22 +1816,28 @@ static NTSTATUS dcesrv_lsa_EnumPrivsAccount(struct dcesrv_call_state *dce_call,
        const char * const attrs[] = { "privilege", NULL};
        struct ldb_message_element *el;
        const char *sidstr;
+       struct lsa_PrivilegeSet *privs;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
 
        astate = h->data;
 
-       r->out.privs = talloc(mem_ctx, struct lsa_PrivilegeSet);
-       r->out.privs->count = 0;
-       r->out.privs->unknown = 0;
-       r->out.privs->set = NULL;
+       privs = talloc(mem_ctx, struct lsa_PrivilegeSet);
+       if (privs == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       privs->count = 0;
+       privs->unknown = 0;
+       privs->set = NULL;
+
+       *r->out.privs = privs;
 
        sidstr = ldap_encode_ndr_dom_sid(mem_ctx, astate->account_sid);
        if (sidstr == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       ret = gendb_search(astate->policy->sam_ldb, mem_ctx, NULL, &res, attrs, 
+       ret = gendb_search(astate->policy->pdb, mem_ctx, NULL, &res, attrs, 
                           "objectSid=%s", sidstr);
        if (ret != 1) {
                return NT_STATUS_OK;
@@ -1646,9 +1848,9 @@ static NTSTATUS dcesrv_lsa_EnumPrivsAccount(struct dcesrv_call_state *dce_call,
                return NT_STATUS_OK;
        }
 
-       r->out.privs->set = talloc_array(r->out.privs, 
-                                        struct lsa_LUIDAttribute, el->num_values);
-       if (r->out.privs->set == NULL) {
+       privs->set = talloc_array(privs,
+                                 struct lsa_LUIDAttribute, el->num_values);
+       if (privs->set == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -1657,12 +1859,12 @@ static NTSTATUS dcesrv_lsa_EnumPrivsAccount(struct dcesrv_call_state *dce_call,
                if (id == -1) {
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
-               r->out.privs->set[i].attribute = 0;
-               r->out.privs->set[i].luid.low = id;
-               r->out.privs->set[i].luid.high = 0;
+               privs->set[i].attribute = 0;
+               privs->set[i].luid.low = id;
+               privs->set[i].luid.high = 0;
        }
 
-       r->out.privs->count = el->num_values;
+       privs->count = el->num_values;
 
        return NT_STATUS_OK;
 }
@@ -1691,7 +1893,7 @@ static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call,
                return NT_STATUS_NO_MEMORY;
        }
 
-       ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, 
+       ret = gendb_search(state->pdb, mem_ctx, NULL, &res, attrs, 
                           "(&(objectSid=%s)(privilege=*))", sidstr);
        if (ret == 0) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
@@ -1702,7 +1904,7 @@ static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call,
        if (ret == -1) {
                DEBUG(3, ("searching for account rights for SID: %s failed: %s", 
                          dom_sid_string(mem_ctx, r->in.sid),
-                         ldb_errstring(state->sam_ldb)));
+                         ldb_errstring(state->pdb)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -1737,15 +1939,17 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
                                           struct dom_sid *sid,
                                           const struct lsa_RightSet *rights)
 {
-       const char *sidstr;
+       const char *sidstr, *sidndrstr;
        struct ldb_message *msg;
        struct ldb_message_element *el;
        int i, ret;
        struct lsa_EnumAccountRights r2;
+       char *dnstr;
 
-       sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid);
-       if (sidstr == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       if (security_session_user_level(dce_call->conn->auth_state.session_info) < 
+           SECURITY_ADMINISTRATOR) {
+               DEBUG(0,("lsa_AddRemoveAccount refused for supplied security token\n"));
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        msg = ldb_msg_new(mem_ctx);
@@ -1753,24 +1957,17 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
                return NT_STATUS_NO_MEMORY;
        }
 
-       msg->dn = samdb_search_dn(state->sam_ldb, mem_ctx, 
-                                 NULL, "objectSid=%s", sidstr);
-       if (msg->dn == NULL) {
-               NTSTATUS status;
-               if (ldb_flag == LDB_FLAG_MOD_DELETE) {
-                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-               }
-               status = samdb_create_foreign_security_principal(state->sam_ldb, mem_ctx, 
-                                                                sid, &msg->dn);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-               return NT_STATUS_NO_SUCH_USER;
-       }
+       sidndrstr = ldap_encode_ndr_dom_sid(msg, sid);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidndrstr, msg);
 
-       if (ldb_msg_add_empty(msg, "privilege", ldb_flag, NULL)) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       sidstr = dom_sid_string(msg, sid);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidstr, msg);
+
+       dnstr = talloc_asprintf(msg, "sid=%s", sidstr);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dnstr, msg);
+
+       msg->dn = ldb_dn_new(msg, state->pdb, dnstr);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(msg->dn, msg);
 
        if (ldb_flag == LDB_FLAG_MOD_ADD) {
                NTSTATUS status;
@@ -1787,6 +1984,7 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
 
        for (i=0;i<rights->count;i++) {
                if (sec_privilege_id(rights->names[i].string) == -1) {
+                       talloc_free(msg);
                        return NT_STATUS_NO_SUCH_PRIVILEGE;
                }
 
@@ -1803,26 +2001,41 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
 
                ret = ldb_msg_add_string(msg, "privilege", rights->names[i].string);
                if (ret != LDB_SUCCESS) {
+                       talloc_free(msg);
                        return NT_STATUS_NO_MEMORY;
                }
        }
 
        el = ldb_msg_find_element(msg, "privilege");
        if (!el) {
+               talloc_free(msg);
                return NT_STATUS_OK;
        }
 
-       ret = ldb_modify(state->sam_ldb, msg);
-       if (ret != 0) {
+       el->flags = ldb_flag;
+
+       ret = ldb_modify(state->pdb, msg);
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               if (samdb_msg_add_dom_sid(state->pdb, msg, msg, "objectSid", sid) != LDB_SUCCESS) {
+                       talloc_free(msg);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               samdb_msg_add_string(state->pdb, msg, msg, "comment", "added via LSA");
+               ret = ldb_add(state->pdb, msg);         
+       }
+       if (ret != LDB_SUCCESS) {
                if (ldb_flag == LDB_FLAG_MOD_DELETE && ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
-                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       talloc_free(msg);
+                       return NT_STATUS_OK;
                }
                DEBUG(3, ("Could not %s attributes from %s: %s", 
                          ldb_flag == LDB_FLAG_MOD_DELETE ? "delete" : "add",
-                         ldb_dn_get_linearized(msg->dn), ldb_errstring(state->sam_ldb)));
+                         ldb_dn_get_linearized(msg->dn), ldb_errstring(state->pdb)));
+               talloc_free(msg);
                return NT_STATUS_UNEXPECTED_IO_ERROR;
        }
 
+       talloc_free(msg);
        return NT_STATUS_OK;
 }
 
@@ -1951,7 +2164,46 @@ static NTSTATUS dcesrv_lsa_SetQuotasForAccount(struct dcesrv_call_state *dce_cal
 static NTSTATUS dcesrv_lsa_GetSystemAccessAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct lsa_GetSystemAccessAccount *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       int i;
+       NTSTATUS status;
+       struct lsa_EnumPrivsAccount enumPrivs;
+       struct lsa_PrivilegeSet *privs;
+
+       privs = talloc(mem_ctx, struct lsa_PrivilegeSet);
+       if (!privs) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       privs->count = 0;
+       privs->unknown = 0;
+       privs->set = NULL;
+
+       enumPrivs.in.handle = r->in.handle;
+       enumPrivs.out.privs = &privs;
+
+       status = dcesrv_lsa_EnumPrivsAccount(dce_call, mem_ctx, &enumPrivs);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }       
+
+       *(r->out.access_mask) = 0x00000000;
+
+       for (i = 0; i < privs->count; i++) {
+               int priv = privs->set[i].luid.low;
+
+               switch (priv) {
+               case SEC_PRIV_INTERACTIVE_LOGON:
+                       *(r->out.access_mask) |= LSA_POLICY_MODE_INTERACTIVE;
+                       break;
+               case SEC_PRIV_NETWORK_LOGON:
+                       *(r->out.access_mask) |= LSA_POLICY_MODE_NETWORK;
+                       break;
+               case SEC_PRIV_REMOTE_INTERACTIVE_LOGON:
+                       *(r->out.access_mask) |= LSA_POLICY_MODE_REMOTE_INTERACTIVE;
+                       break;
+               }
+       }
+
+       return NT_STATUS_OK;
 }
 
 
@@ -1976,7 +2228,6 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
        struct lsa_secret_state *secret_state;
        struct dcesrv_handle *handle;
        struct ldb_message **msgs, *msg;
-       const char *errstr;
        const char *attrs[] = {
                NULL
        };
@@ -2020,7 +2271,7 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
                name = &r->in.name.string[2];
                        /* We need to connect to the database as system, as this is one of the rare RPC calls that must read the secrets (and this is denied otherwise) */
                secret_state->sam_ldb = talloc_reference(secret_state, 
-                                                        samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(secret_state, dce_call->conn->dce_ctx->lp_ctx))); 
+                                                        samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx))); 
                secret_state->global = true;
 
                if (strlen(name) < 1) {
@@ -2080,22 +2331,13 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
                samdb_msg_add_string(secret_state->sam_ldb, mem_ctx, msg, "cn", name);
        } 
 
-       /* pull in all the template attributes.  Note this is always from the global samdb */
-       ret = samdb_copy_template(secret_state->policy->sam_ldb, msg, 
-                                 "secret", &errstr);
-       if (ret != 0) {
-               DEBUG(0,("Failed to load TemplateSecret from samdb: %s\n",
-                        errstr));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
        samdb_msg_add_string(secret_state->sam_ldb, mem_ctx, msg, "objectClass", "secret");
        
        secret_state->secret_dn = talloc_reference(secret_state, msg->dn);
 
        /* create the secret */
        ret = ldb_add(secret_state->sam_ldb, msg);
-       if (ret != 0) {
+       if (ret != LDB_SUCCESS) {
                DEBUG(0,("Failed to create secret record %s: %s\n",
                         ldb_dn_get_linearized(msg->dn), 
                         ldb_errstring(secret_state->sam_ldb)));
@@ -2166,7 +2408,7 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
                name = &r->in.name.string[2];
                /* We need to connect to the database as system, as this is one of the rare RPC calls that must read the secrets (and this is denied otherwise) */
                secret_state->sam_ldb = talloc_reference(secret_state, 
-                                                        samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(secret_state, dce_call->conn->dce_ctx->lp_ctx))); 
+                                                        samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx))); 
                secret_state->global = true;
 
                if (strlen(name) < 1) {
@@ -2285,13 +2527,13 @@ static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_
                
                /* set value */
                if (samdb_msg_add_value(secret_state->sam_ldb, 
-                                       mem_ctx, msg, "priorValue", &val) != 0) {
+                                       mem_ctx, msg, "priorValue", &val) != LDB_SUCCESS) {
                        return NT_STATUS_NO_MEMORY; 
                }
                
                /* set old value mtime */
                if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                        mem_ctx, msg, "priorSetTime", nt_now) != 0) { 
+                                        mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
                        return NT_STATUS_NO_MEMORY; 
                }
 
@@ -2341,12 +2583,12 @@ static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_
                /* set old value mtime */
                if (ldb_msg_find_ldb_val(res[0], "lastSetTime")) {
                        if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                                mem_ctx, msg, "priorSetTime", last_set_time) != 0) { 
+                                                mem_ctx, msg, "priorSetTime", last_set_time) != LDB_SUCCESS) {
                                return NT_STATUS_NO_MEMORY; 
                        }
                } else {
                        if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                                mem_ctx, msg, "priorSetTime", nt_now) != 0) { 
+                                                mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
                                return NT_STATUS_NO_MEMORY; 
                        }
                }
@@ -2367,31 +2609,31 @@ static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_
                
                /* set value */
                if (samdb_msg_add_value(secret_state->sam_ldb, 
-                                       mem_ctx, msg, "currentValue", &val) != 0) {
+                                       mem_ctx, msg, "currentValue", &val) != LDB_SUCCESS) {
                        return NT_STATUS_NO_MEMORY; 
                }
                
                /* set new value mtime */
                if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                        mem_ctx, msg, "lastSetTime", nt_now) != 0) { 
+                                        mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
                        return NT_STATUS_NO_MEMORY; 
                }
                
        } else {
                /* NULL out the NEW value */
                if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                        mem_ctx, msg, "lastSetTime", nt_now) != 0) { 
+                                        mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
                        return NT_STATUS_NO_MEMORY; 
                }
                if (samdb_msg_add_delete(secret_state->sam_ldb, 
-                                        mem_ctx, msg, "currentValue")) {
+                                        mem_ctx, msg, "currentValue") != LDB_SUCCESS) {
                        return NT_STATUS_NO_MEMORY;
                }
        }
 
        /* modify the samdb record */
-       ret = samdb_replace(secret_state->sam_ldb, mem_ctx, msg);
-       if (ret != 0) {
+       ret = dsdb_replace(secret_state->sam_ldb, msg, 0);
+       if (ret != LDB_SUCCESS) {
                /* we really need samdb.c to return NTSTATUS */
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -2562,6 +2804,7 @@ static NTSTATUS dcesrv_lsa_LookupPrivName(struct dcesrv_call_state *dce_call,
 {
        struct dcesrv_handle *h;
        struct lsa_policy_state *state;
+       struct lsa_StringLarge *name;
        const char *privname;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
@@ -2577,11 +2820,14 @@ static NTSTATUS dcesrv_lsa_LookupPrivName(struct dcesrv_call_state *dce_call,
                return NT_STATUS_NO_SUCH_PRIVILEGE;
        }
 
-       r->out.name = talloc(mem_ctx, struct lsa_StringLarge);
-       if (r->out.name == NULL) {
+       name = talloc(mem_ctx, struct lsa_StringLarge);
+       if (name == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       r->out.name->string = privname;
+
+       name->string = privname;
+
+       *r->out.name = name;
 
        return NT_STATUS_OK;    
 }
@@ -2596,6 +2842,7 @@ static NTSTATUS dcesrv_lsa_LookupPrivDisplayName(struct dcesrv_call_state *dce_c
 {
        struct dcesrv_handle *h;
        struct lsa_policy_state *state;
+       struct lsa_StringLarge *disp_name = NULL;
        int id;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
@@ -2606,17 +2853,20 @@ static NTSTATUS dcesrv_lsa_LookupPrivDisplayName(struct dcesrv_call_state *dce_c
        if (id == -1) {
                return NT_STATUS_NO_SUCH_PRIVILEGE;
        }
-       
-       r->out.disp_name = talloc(mem_ctx, struct lsa_StringLarge);
-       if (r->out.disp_name == NULL) {
+
+       disp_name = talloc(mem_ctx, struct lsa_StringLarge);
+       if (disp_name == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       r->out.disp_name->string = sec_privilege_display_name(id, r->in.language_id);
-       if (r->out.disp_name->string == NULL) {
+       disp_name->string = sec_privilege_display_name(id, &r->in.language_id);
+       if (disp_name->string == NULL) {
                return NT_STATUS_INTERNAL_ERROR;
        }
 
+       *r->out.disp_name = disp_name;
+       *r->out.returned_language_id = 0;
+
        return NT_STATUS_OK;
 }
 
@@ -2648,7 +2898,7 @@ static NTSTATUS dcesrv_lsa_EnumAccountsWithUserRight(struct dcesrv_call_state *d
                return NT_STATUS_NO_SUCH_PRIVILEGE;
        }
 
-       ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, 
+       ret = gendb_search(state->pdb, mem_ctx, NULL, &res, attrs, 
                           "privilege=%s", privname);
        if (ret == -1) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
@@ -2742,19 +2992,23 @@ static NTSTATUS dcesrv_lsa_GetUserName(struct dcesrv_call_state *dce_call, TALLO
        const char *account_name;
        const char *authority_name;
        struct lsa_String *_account_name;
-       struct lsa_StringPointer *_authority_name = NULL;
+       struct lsa_String *_authority_name = NULL;
 
        /* this is what w2k3 does */
        r->out.account_name = r->in.account_name;
        r->out.authority_name = r->in.authority_name;
 
-       if (r->in.account_name && r->in.account_name->string) {
+       if (r->in.account_name
+           && *r->in.account_name
+           /* && *(*r->in.account_name)->string */
+           ) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (r->in.authority_name &&
-           r->in.authority_name->string &&
-           r->in.authority_name->string->string) {
+       if (r->in.authority_name
+           && *r->in.authority_name
+           /* && *(*r->in.authority_name)->string */
+           ) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -2766,15 +3020,15 @@ static NTSTATUS dcesrv_lsa_GetUserName(struct dcesrv_call_state *dce_call, TALLO
        _account_name->string = account_name;
 
        if (r->in.authority_name) {
-               _authority_name = talloc(mem_ctx, struct lsa_StringPointer);
+               _authority_name = talloc(mem_ctx, struct lsa_String);
                NT_STATUS_HAVE_NO_MEMORY(_authority_name);
-               _authority_name->string = talloc(mem_ctx, struct lsa_String);
-               NT_STATUS_HAVE_NO_MEMORY(_authority_name->string);
-               _authority_name->string->string = authority_name;
+               _authority_name->string = authority_name;
        }
 
-       r->out.account_name = _account_name;
-       r->out.authority_name = _authority_name;
+       *r->out.account_name = _account_name;
+       if (r->out.authority_name) {
+               *r->out.authority_name = _authority_name;
+       }
 
        return status;
 }
@@ -2786,6 +3040,7 @@ static NTSTATUS dcesrv_lsa_SetInfoPolicy2(struct dcesrv_call_state *dce_call,
                                   TALLOC_CTX *mem_ctx,
                                   struct lsa_SetInfoPolicy2 *r)
 {
+       /* need to support these */
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
@@ -2796,27 +3051,29 @@ static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state
                                                 TALLOC_CTX *mem_ctx,
                                                 struct lsa_QueryDomainInformationPolicy *r)
 {
-       r->out.info = talloc(mem_ctx, union lsa_DomainInformationPolicy);
-       if (!r->out.info) {
+       union lsa_DomainInformationPolicy *info;
+
+       info = talloc(r->out.info, union lsa_DomainInformationPolicy);
+       if (!info) {
                return NT_STATUS_NO_MEMORY;
        }
 
        switch (r->in.level) {
        case LSA_DOMAIN_INFO_POLICY_EFS:
-               talloc_free(r->out.info);
-               r->out.info = NULL;
+               talloc_free(info);
+               *r->out.info = NULL;
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        case LSA_DOMAIN_INFO_POLICY_KERBEROS:
        {
-               struct lsa_DomainInfoKerberos *k = &r->out.info->kerberos_info;
+               struct lsa_DomainInfoKerberos *k = &info->kerberos_info;
                struct smb_krb5_context *smb_krb5_context;
                int ret = smb_krb5_init_context(mem_ctx, 
                                                        dce_call->event_ctx, 
                                                        dce_call->conn->dce_ctx->lp_ctx,
                                                        &smb_krb5_context);
                if (ret != 0) {
-                       talloc_free(r->out.info);
-                       r->out.info = NULL;
+                       talloc_free(info);
+                       *r->out.info = NULL;
                        return NT_STATUS_INTERNAL_ERROR;
                }
                k->enforce_restrictions = 0; /* FIXME, details missing from MS-LSAD 2.2.53 */
@@ -2825,11 +3082,12 @@ static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state
                k->user_tkt_renewaltime = 0; /* Need to find somewhere to store this, and query in KDC too */
                k->clock_skew = krb5_get_max_time_skew(smb_krb5_context->krb5_context);
                talloc_free(smb_krb5_context);
+               *r->out.info = info;
                return NT_STATUS_OK;
        }
        default:
-               talloc_free(r->out.info);
-               r->out.info = NULL;
+               talloc_free(info);
+               *r->out.info = NULL;
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 }