Make the updated RPC-LSA pass against Win2008, and Samba4 to match
[kai/samba.git] / source4 / rpc_server / lsa / dcesrv_lsa.c
index 326217e63fbebc7658f0d07cd0c262b04e129aab..b009d2f2f8a2466ab649876d5414ddd1a37b0c6c 100644 (file)
@@ -1,10 +1,12 @@
+/* need access mask/acl implementation */
+
 /* 
    Unix SMB/CIFS implementation.
 
    endpoint server for the lsarpc pipe
 
    Copyright (C) Andrew Tridgell 2004
-   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "rpc_server/dcerpc_server.h"
-#include "rpc_server/common/common.h"
-#include "auth/auth.h"
-#include "dsdb/samdb/samdb.h"
-#include "libcli/ldap/ldap.h"
-#include "lib/ldb/include/ldb_errors.h"
-#include "libcli/security/security.h"
-#include "libcli/auth/libcli_auth.h"
-#include "param/secrets.h"
-#include "db_wrap.h"
-#include "librpc/gen_ndr/ndr_dssetup.h"
+#include "rpc_server/lsa/lsa.h"
+#include "../lib/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"
 
 /*
   this type allows us to distinguish handle types
 */
-enum lsa_handle {
-       LSA_HANDLE_POLICY,
-       LSA_HANDLE_ACCOUNT,
-       LSA_HANDLE_SECRET,
-       LSA_HANDLE_TRUSTED_DOMAIN
-};
-
-/*
-  state associated with a lsa_OpenPolicy() operation
-*/
-struct lsa_policy_state {
-       struct dcesrv_handle *handle;
-       struct ldb_context *sam_ldb;
-       struct sidmap_context *sidmap;
-       uint32_t access_mask;
-       struct ldb_dn *domain_dn;
-       struct ldb_dn *forest_dn;
-       struct ldb_dn *builtin_dn;
-       struct ldb_dn *system_dn;
-       const char *domain_name;
-       const char *domain_dns;
-       const char *forest_dns;
-       struct dom_sid *domain_sid;
-       struct GUID domain_guid;
-       struct dom_sid *builtin_sid;
-       int mixed_domain;
-};
-
 
 /*
   state associated with a lsa_OpenAccount() operation
@@ -83,7 +53,7 @@ struct lsa_secret_state {
        uint32_t access_mask;
        struct ldb_dn *secret_dn;
        struct ldb_context *sam_ldb;
-       BOOL global;
+       bool global;
 };
 
 /*
@@ -93,6 +63,7 @@ struct lsa_trusted_domain_state {
        struct lsa_policy_state *policy;
        uint32_t access_mask;
        struct ldb_dn *trusted_domain_dn;
+       struct ldb_dn *trusted_domain_user_dn;
 };
 
 static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call, 
@@ -131,29 +102,77 @@ static NTSTATUS dcesrv_lsa_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX
 */
 static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                           struct lsa_Delete *r)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
+
+/* 
+  lsa_DeleteObject
+*/
+static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct lsa_DeleteObject *r)
 {
        struct dcesrv_handle *h;
        int ret;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
+
        if (h->wire_handle.handle_type == LSA_HANDLE_SECRET) {
                struct lsa_secret_state *secret_state = h->data;
-               ret = samdb_delete(secret_state->sam_ldb, mem_ctx, secret_state->secret_dn);
+
+               /* Ensure user is permitted to delete this... */
+               switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+               {
+               case SECURITY_SYSTEM:
+               case SECURITY_ADMINISTRATOR:
+                       break;
+               default:
+                       /* Users and annonymous are not allowed delete things */
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+
+               ret = ldb_delete(secret_state->sam_ldb, 
+                                secret_state->secret_dn);
                talloc_free(h);
                if (ret != 0) {
                        return NT_STATUS_INVALID_HANDLE;
                }
 
+               ZERO_STRUCTP(r->out.handle);
+
                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;
-               ret = samdb_delete(trusted_domain_state->policy->sam_ldb, mem_ctx, 
-                                  trusted_domain_state->trusted_domain_dn);
-               talloc_free(h);
+               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) {
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+
+               ret = ldb_delete(trusted_domain_state->policy->sam_ldb, 
+                                trusted_domain_state->trusted_domain_dn);
+               if (ret != 0) {
+                       ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
                        return NT_STATUS_INVALID_HANDLE;
                }
 
+               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) {
+                               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) {
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+               talloc_free(h);
+               ZERO_STRUCTP(r->out.handle);
+
                return NT_STATUS_OK;
        } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) {
                struct lsa_RightSet *rights;
@@ -171,6 +190,9 @@ static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX
                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;
@@ -190,6 +212,8 @@ static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
+
+               ZERO_STRUCTP(r->out.handle);
        } 
        
        return NT_STATUS_INVALID_HANDLE;
@@ -268,162 +292,6 @@ static NTSTATUS dcesrv_lsa_ChangePassword(struct dcesrv_call_state *dce_call, TA
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
-static NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                                    struct lsa_policy_state **_state)
-{
-       struct lsa_policy_state *state;
-       struct ldb_dn *partitions_basedn;
-       struct ldb_result *dom_res;
-       const char *dom_attrs[] = {
-               "objectSid", 
-               "objectGUID", 
-               "nTMixedDomain",
-               "fSMORoleOwner",
-               NULL
-       };
-       struct ldb_result *ref_res;
-       struct ldb_result *forest_ref_res;
-       const char *ref_attrs[] = {
-               "nETBIOSName",
-               "dnsRoot",
-               NULL
-       };
-       int ret;
-
-       state = talloc(mem_ctx, struct lsa_policy_state);
-       if (!state) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* make sure the sam database is accessible */
-       state->sam_ldb = samdb_connect(state, dce_call->conn->auth_state.session_info); 
-       if (state->sam_ldb == NULL) {
-               return NT_STATUS_INVALID_SYSTEM_SERVICE;
-       }
-
-       partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx);
-
-       state->sidmap = sidmap_open(state);
-       if (state->sidmap == NULL) {
-               return NT_STATUS_INVALID_SYSTEM_SERVICE;
-       }
-
-       /* work out the domain_dn - useful for so many calls its worth
-          fetching here */
-       state->domain_dn = samdb_base_dn(state->sam_ldb);
-       if (!state->domain_dn) {
-               return NT_STATUS_NO_MEMORY;             
-       }
-
-       /* work out the forest root_dn - useful for so many calls its worth
-          fetching here */
-       state->forest_dn = samdb_root_dn(state->sam_ldb);
-       if (!state->forest_dn) {
-               return NT_STATUS_NO_MEMORY;             
-       }
-
-       ret = ldb_search(state->sam_ldb, state->domain_dn, LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
-       
-       if (ret != LDB_SUCCESS) {
-               return NT_STATUS_INVALID_SYSTEM_SERVICE;
-       }
-       talloc_steal(mem_ctx, dom_res);
-       if (dom_res->count != 1) {
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid");
-       if (!state->domain_sid) {
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID");
-       if (!state->domain_sid) {
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0);
-       
-       talloc_free(dom_res);
-
-       ret = ldb_search_exp_fmt(state->sam_ldb, state, &ref_res,
-                                partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs,
-                                "(&(objectclass=crossRef)(ncName=%s))",
-                                ldb_dn_get_linearized(state->domain_dn));
-       
-       if (ret != LDB_SUCCESS) {
-               talloc_free(ref_res);
-               return NT_STATUS_INVALID_SYSTEM_SERVICE;
-       }
-       if (ref_res->count != 1) {
-               talloc_free(ref_res);
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       state->domain_name = ldb_msg_find_attr_as_string(ref_res->msgs[0], "nETBIOSName", NULL);
-       if (!state->domain_name) {
-               talloc_free(ref_res);
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-       talloc_steal(state, state->domain_name);
-
-       state->domain_dns = ldb_msg_find_attr_as_string(ref_res->msgs[0], "dnsRoot", NULL);
-       if (!state->domain_dns) {
-               talloc_free(ref_res);
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-       talloc_steal(state, state->domain_dns);
-
-       talloc_free(ref_res);
-
-       ret = ldb_search_exp_fmt(state->sam_ldb, state, &forest_ref_res,
-                                partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs,
-                                "(&(objectclass=crossRef)(ncName=%s))",
-                                ldb_dn_get_linearized(state->forest_dn));
-       
-       if (ret != LDB_SUCCESS) {
-               talloc_free(forest_ref_res);
-               return NT_STATUS_INVALID_SYSTEM_SERVICE;
-       }
-       if (forest_ref_res->count != 1) {
-               talloc_free(forest_ref_res);
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       state->forest_dns = ldb_msg_find_attr_as_string(forest_ref_res->msgs[0], "dnsRoot", NULL);
-       if (!state->forest_dns) {
-               talloc_free(forest_ref_res);
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-       talloc_steal(state, state->forest_dns);
-
-       talloc_free(forest_ref_res);
-
-       /* work out the builtin_dn - useful for so many calls its worth
-          fetching here */
-       state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)");
-       if (!state->builtin_dn) {
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       /* work out the system_dn - useful for so many calls its worth
-          fetching here */
-       state->system_dn = samdb_search_dn(state->sam_ldb, state,
-                                          state->domain_dn, "(&(objectClass=container)(cn=System))");
-       if (!state->system_dn) {
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN);
-       if (!state->builtin_sid) {
-               return NT_STATUS_NO_SUCH_DOMAIN;                
-       }
-
-       *_state = state;
-
-       return NT_STATUS_OK;
-}
-
 /* 
   dssetup_DsRoleGetPrimaryDomainInformation 
 
@@ -457,7 +325,7 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
 
                ZERO_STRUCT(domain_guid);
 
-               switch (lp_server_role()) {
+               switch (lp_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
                case ROLE_STANDALONE:
                        role            = DS_ROLE_STANDALONE_SERVER;
                        break;
@@ -473,13 +341,13 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
                        break;
                }
 
-               switch (lp_server_role()) {
+               switch (lp_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
                case ROLE_STANDALONE:
-                       domain          = talloc_strdup(mem_ctx, lp_workgroup());
+                       domain          = talloc_strdup(mem_ctx, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
                        W_ERROR_HAVE_NO_MEMORY(domain);
                        break;
                case ROLE_DOMAIN_MEMBER:
-                       domain          = talloc_strdup(mem_ctx, lp_workgroup());
+                       domain          = talloc_strdup(mem_ctx, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
                        W_ERROR_HAVE_NO_MEMORY(domain);
                        /* TODO: what is with dns_domain and forest and guid? */
                        break;
@@ -531,61 +399,6 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
        return WERR_INVALID_PARAM;
 }
 
-/* 
-  lsa_OpenPolicy2
-*/
-static NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                              struct lsa_OpenPolicy2 *r)
-{
-       NTSTATUS status;
-       struct lsa_policy_state *state;
-       struct dcesrv_handle *handle;
-
-       ZERO_STRUCTP(r->out.handle);
-
-       status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_POLICY);
-       if (!handle) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       handle->data = talloc_steal(handle, state);
-
-       state->access_mask = r->in.access_mask;
-       state->handle = handle;
-       *r->out.handle = handle->wire_handle;
-
-       /* note that we have completely ignored the attr element of
-          the OpenPolicy. As far as I can tell, this is what w2k3
-          does */
-
-       return NT_STATUS_OK;
-}
-
-/* 
-  lsa_OpenPolicy
-  a wrapper around lsa_OpenPolicy2
-*/
-static NTSTATUS dcesrv_lsa_OpenPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                               struct lsa_OpenPolicy *r)
-{
-       struct lsa_OpenPolicy2 r2;
-
-       r2.in.system_name = NULL;
-       r2.in.attr = r->in.attr;
-       r2.in.access_mask = r->in.access_mask;
-       r2.out.handle = r->out.handle;
-
-       return dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &r2);
-}
-
-
-
-
 /*
   fill in the AccountDomain info
 */
@@ -636,14 +449,52 @@ static NTSTATUS dcesrv_lsa_QueryInfoPolicy2(struct dcesrv_call_state *dce_call,
        ZERO_STRUCTP(r->out.info);
 
        switch (r->in.level) {
+       case LSA_POLICY_INFO_AUDIT_LOG:
+               /* we don't need to fill in any of this */
+               ZERO_STRUCT(r->out.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(r->out.info->audit_events);
+               return NT_STATUS_OK;
+       case LSA_POLICY_INFO_PD:
+               /* we don't need to fill in any of this */
+               ZERO_STRUCT(r->out.info->pd);
+               return NT_STATUS_OK;
+
        case LSA_POLICY_INFO_DOMAIN:
+               return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &r->out.info->domain);
        case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
                return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &r->out.info->account_domain);
+       case LSA_POLICY_INFO_L_ACCOUNT_DOMAIN:
+               return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &r->out.info->l_account_domain);
+
+
+       case LSA_POLICY_INFO_ROLE:
+               r->out.info->role.role = LSA_ROLE_PRIMARY;
+               return NT_STATUS_OK;
 
        case LSA_POLICY_INFO_DNS:
+       case LSA_POLICY_INFO_DNS_INT:
                return dcesrv_lsa_info_DNS(state, mem_ctx, &r->out.info->dns);
+
+       case LSA_POLICY_INFO_REPLICA:
+               ZERO_STRUCT(r->out.info->replica);
+               return NT_STATUS_OK;
+
+       case LSA_POLICY_INFO_QUOTA:
+               ZERO_STRUCT(r->out.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;
 }
 
@@ -656,6 +507,8 @@ 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;
        
@@ -672,6 +525,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);
 }
 
@@ -688,6 +542,15 @@ 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)
@@ -794,86 +657,221 @@ static NTSTATUS dcesrv_lsa_EnumAccounts(struct dcesrv_call_state *dce_call, TALL
 /*
   lsa_CreateTrustedDomainEx2
 */
-static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx2(struct dcesrv_call_state *dce_call,
-                                          TALLOC_CTX *mem_ctx,
-                                          struct lsa_CreateTrustedDomainEx2 *r)
-{
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
-}
-
-/*
-  lsa_CreateTrustedDomainEx
-*/
-static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx(struct dcesrv_call_state *dce_call,
-                                         TALLOC_CTX *mem_ctx,
-                                         struct lsa_CreateTrustedDomainEx *r)
-{
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
-}
-
-/* 
-  lsa_CreateTrustedDomain 
-*/
-static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                                       struct lsa_CreateTrustedDomain *r)
+static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dce_call,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   struct lsa_CreateTrustedDomainEx2 *r,
+                                                   int op)
 {
        struct dcesrv_handle *policy_handle;
        struct lsa_policy_state *policy_state;
        struct lsa_trusted_domain_state *trusted_domain_state;
        struct dcesrv_handle *handle;
-       struct ldb_message **msgs, *msg;
+       struct ldb_message **msgs, *msg, *msg_user;
        const char *attrs[] = {
                NULL
        };
+       const char *netbios_name;
+       const char *dns_name;
        const char *name;
+       DATA_BLOB session_key = data_blob(NULL, 0);
+       DATA_BLOB trustAuthIncoming, trustAuthOutgoing, auth_blob;
+       struct trustDomainPasswords auth_struct;
        int ret;
-
-       DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+       NTSTATUS nt_status;
+       enum ndr_err_code ndr_err;
+       
+       DCESRV_PULL_HANDLE(policy_handle, r->in.policy_handle, LSA_HANDLE_POLICY);
        ZERO_STRUCTP(r->out.trustdom_handle);
        
        policy_state = policy_handle->data;
 
-       if (!r->in.info->name.string) {
+       nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
+
+       netbios_name = r->in.info->netbios_name.string;
+       if (!netbios_name) {
                return NT_STATUS_INVALID_PARAMETER;
        }
-       name = r->in.info->name.string;
        
-       trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+       dns_name = r->in.info->domain_name.string;
+       
+       trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
        if (!trusted_domain_state) {
                return NT_STATUS_NO_MEMORY;
        }
        trusted_domain_state->policy = policy_state;
 
-       msg = ldb_msg_new(mem_ctx);
-       if (msg == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       if (strcasecmp(netbios_name, "BUILTIN") == 0
+           || (dns_name && strcasecmp(dns_name, "BUILTIN") == 0) 
+           || (dom_sid_in_domain(policy_state->builtin_sid, r->in.info->sid))) {
+               return NT_STATUS_INVALID_PARAMETER;;
        }
 
-       /* search for the trusted_domain record */
-       ret = gendb_search(trusted_domain_state->policy->sam_ldb,
-                          mem_ctx, policy_state->system_dn, &msgs, attrs,
-                          "(&(cn=%s)(objectclass=trustedDomain))", 
-                          ldb_binary_encode_string(mem_ctx, r->in.info->name.string));
-       if (ret > 0) {
-               return NT_STATUS_OBJECT_NAME_COLLISION;
+       if (strcasecmp(netbios_name, policy_state->domain_name) == 0
+           || strcasecmp(netbios_name, policy_state->domain_dns) == 0
+           || (dns_name && strcasecmp(dns_name, policy_state->domain_dns) == 0) 
+           || (dns_name && strcasecmp(dns_name, policy_state->domain_name) == 0)
+           || (dom_sid_equal(policy_state->domain_sid, r->in.info->sid))) {
+               return NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED;
+       }
+
+       /* While this is a REF pointer, some of the functions that wrap this don't provide this */
+       if (op == NDR_LSA_CREATETRUSTEDDOMAIN) {
+               /* No secrets are created at this time, for this function */
+               auth_struct.outgoing.count = 0;
+               auth_struct.incoming.count = 0;
+       } else {
+               auth_blob = data_blob_const(r->in.auth_info->auth_blob.data, r->in.auth_info->auth_blob.size);
+               arcfour_crypt_blob(auth_blob.data, auth_blob.length, &session_key);
+               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_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),
+                                              &incoming,
+                                              (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       } else {
+               trustAuthIncoming = data_blob(NULL, 0);
        }
        
-       if (ret < 0 || ret > 1) {
-               DEBUG(0,("Found %d records matching DN %s\n", ret,
-                        ldb_dn_get_linearized(policy_state->system_dn)));
+       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),
+                                              &outgoing,
+                                              (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       } else {
+               trustAuthOutgoing = data_blob(NULL, 0);
+       }
+
+       ret = ldb_transaction_start(policy_state->sam_ldb);
+       if (ret != LDB_SUCCESS) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       if (dns_name) {
+               char *dns_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
+               char *netbios_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
+               /* search for the trusted_domain record */
+               ret = gendb_search(policy_state->sam_ldb,
+                                  mem_ctx, policy_state->system_dn, &msgs, attrs,
+                                  "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)(trustPartner=%s))(objectclass=trustedDomain))", 
+                                  dns_encoded, dns_encoded, dns_encoded, netbios_encoded, netbios_encoded, netbios_encoded);
+               if (ret > 0) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+       } else {
+               char *netbios_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
+               /* search for the trusted_domain record */
+               ret = gendb_search(policy_state->sam_ldb,
+                                  mem_ctx, policy_state->system_dn, &msgs, attrs,
+                                  "(&(|(flatname=%s)(cn=%s)(trustPartner=%s))(objectclass=trustedDomain))", 
+                                  netbios_encoded, netbios_encoded, netbios_encoded);
+               if (ret > 0) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+       }
+       
+       if (ret < 0 ) {
+               ldb_transaction_cancel(policy_state->sam_ldb);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
        
+       name = dns_name ? dns_name : netbios_name;
+
+       msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        msg->dn = ldb_dn_copy(mem_ctx, policy_state->system_dn);
        if ( ! ldb_dn_add_child_fmt(msg->dn, "cn=%s", name)) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
                return NT_STATUS_NO_MEMORY;
        }
        
-       samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "flatname", name);
+       samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "flatname", netbios_name);
 
        if (r->in.info->sid) {
                const char *sid_string = dom_sid_string(mem_ctx, r->in.info->sid);
                if (!sid_string) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
                        return NT_STATUS_NO_MEMORY;
                }
                        
@@ -881,14 +879,139 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_cal
        }
 
        samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "objectClass", "trustedDomain");
+
+       samdb_msg_add_int(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustType", r->in.info->trust_type);
+
+       samdb_msg_add_int(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustAttributes", r->in.info->trust_attributes);
+
+       samdb_msg_add_int(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustDirection", r->in.info->trust_direction);
        
+       if (dns_name) {
+               samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustPartner", dns_name);
+       }
+
+       if (trustAuthIncoming.data) {
+               ret = ldb_msg_add_value(msg, "trustAuthIncoming", &trustAuthIncoming, NULL);
+               if (ret != LDB_SUCCESS) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+       if (trustAuthOutgoing.data) {
+               ret = ldb_msg_add_value(msg, "trustAuthOutgoing", &trustAuthOutgoing, NULL);
+               if (ret != LDB_SUCCESS) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
        trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msg->dn);
 
        /* create the trusted_domain */
        ret = ldb_add(trusted_domain_state->policy->sam_ldb, msg);
+       switch (ret) {
+       case  LDB_SUCCESS:
+               break;
+       case  LDB_ERR_ENTRY_ALREADY_EXISTS:
+               ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+               DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+               return NT_STATUS_DOMAIN_EXISTS;
+       case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+               ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+               DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+               return NT_STATUS_ACCESS_DENIED;
+       default:
+               ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+               DEBUG(0,("Failed to create user record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       if (r->in.info->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
+               msg_user = ldb_msg_new(mem_ctx);
+               if (msg == NULL) {
+                       ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               /* Inbound trusts must also create a cn=users object to match */
+
+               trusted_domain_state->trusted_domain_user_dn = msg_user->dn
+                       = ldb_dn_copy(trusted_domain_state, policy_state->domain_dn);
+               if ( ! ldb_dn_add_child_fmt(msg_user->dn, "cn=users")) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       
+               if ( ! ldb_dn_add_child_fmt(msg_user->dn, "cn=%s", netbios_name)) {
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               ldb_msg_add_string(msg_user, "objectClass", "user");
+
+               ldb_msg_add_steal_string(msg_user, "samAccountName", 
+                                        talloc_asprintf(mem_ctx, "%s$", netbios_name));
+
+               if (samdb_msg_add_uint(trusted_domain_state->policy->sam_ldb, mem_ctx, msg_user, 
+                                      "userAccountControl", 
+                                      UF_INTERDOMAIN_TRUST_ACCOUNT) != 0) { 
+                       ldb_transaction_cancel(policy_state->sam_ldb);
+                       return NT_STATUS_NO_MEMORY; 
+               }
+
+               if (auth_struct.incoming.count) {
+                       int i;
+                       for (i=0; i < auth_struct.incoming.count; i++ ) {
+                               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", 
+                                                          &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;
+                                       }
+                               } 
+                       }
+               }
+
+               /* create the cn=users trusted_domain account */
+               ret = ldb_add(trusted_domain_state->policy->sam_ldb, msg_user);
+               switch (ret) {
+               case  LDB_SUCCESS:
+                       break;
+               case  LDB_ERR_ENTRY_ALREADY_EXISTS:
+                       ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+                       DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+                                ldb_dn_get_linearized(msg_user->dn),
+                                ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+                       return NT_STATUS_DOMAIN_EXISTS;
+               case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+                       ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+                       DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+                                ldb_dn_get_linearized(msg_user->dn),
+                                ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+                       return NT_STATUS_ACCESS_DENIED;
+               default:
+                       ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+                       DEBUG(0,("Failed to create user record %s: %s\n",
+                                ldb_dn_get_linearized(msg_user->dn),
+                                ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       }
+
+       ret = ldb_transaction_commit(policy_state->sam_ldb);
        if (ret != LDB_SUCCESS) {
-               DEBUG(0,("Failed to create trusted_domain record %s: %s\n",
-                        ldb_dn_get_linearized(msg->dn), ldb_errstring(trusted_domain_state->policy->sam_ldb)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -907,6 +1030,59 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_cal
        return NT_STATUS_OK;
 }
 
+/*
+  lsa_CreateTrustedDomainEx2
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx2(struct dcesrv_call_state *dce_call,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct lsa_CreateTrustedDomainEx2 *r)
+{
+       return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, r, NDR_LSA_CREATETRUSTEDDOMAINEX2);
+}
+/*
+  lsa_CreateTrustedDomainEx
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx(struct dcesrv_call_state *dce_call,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct lsa_CreateTrustedDomainEx *r)
+{
+       struct lsa_CreateTrustedDomainEx2 r2;
+
+       r2.in.policy_handle = r->in.policy_handle;
+       r2.in.info = r->in.info;
+       r2.in.auth_info = r->in.auth_info;
+       r2.out.trustdom_handle = r->out.trustdom_handle;
+       return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, &r2, NDR_LSA_CREATETRUSTEDDOMAINEX);
+}
+
+/* 
+  lsa_CreateTrustedDomain 
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                       struct lsa_CreateTrustedDomain *r)
+{
+       struct lsa_CreateTrustedDomainEx2 r2;
+
+       r2.in.policy_handle = r->in.policy_handle;
+       r2.in.info = talloc(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
+       if (!r2.in.info) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       r2.in.info->domain_name.string = NULL;
+       r2.in.info->netbios_name = r->in.info->name;
+       r2.in.info->sid = r->in.info->sid;
+       r2.in.info->trust_direction = LSA_TRUST_DIRECTION_OUTBOUND;
+       r2.in.info->trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+       r2.in.info->trust_attributes = 0;
+       
+       r2.in.access_mask = r->in.access_mask;
+       r2.out.trustdom_handle = r->out.trustdom_handle;
+
+       return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, &r2, NDR_LSA_CREATETRUSTEDDOMAIN);
+                        
+}
+
 /* 
   lsa_OpenTrustedDomain
 */
@@ -920,6 +1096,8 @@ static NTSTATUS dcesrv_lsa_OpenTrustedDomain(struct dcesrv_call_state *dce_call,
        struct dcesrv_handle *handle;
        struct ldb_message **msgs;
        const char *attrs[] = {
+               "trustDirection",
+               "flatname",
                NULL
        };
 
@@ -930,7 +1108,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;
        }
@@ -957,7 +1135,20 @@ static NTSTATUS dcesrv_lsa_OpenTrustedDomain(struct dcesrv_call_state *dce_call,
        }
 
        trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msgs[0]->dn);
-       
+
+       trusted_domain_state->trusted_domain_user_dn = NULL;
+
+       if (ldb_msg_find_attr_as_int(msgs[0], "trustDirection", 0) & LSA_TRUST_DIRECTION_INBOUND) {
+               const char *flatname = ldb_binary_encode_string(mem_ctx, ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL));
+               /* search for the trusted_domain record */
+               ret = gendb_search(trusted_domain_state->policy->sam_ldb,
+                                  mem_ctx, policy_state->domain_dn, &msgs, attrs,
+                                  "(&(samaccountname=%s$)(objectclass=user)(userAccountControl:1.2.840.113556.1.4.803:=%d))", 
+                                  flatname, UF_INTERDOMAIN_TRUST_ACCOUNT);
+               if (ret == 1) {
+                       trusted_domain_state->trusted_domain_user_dn = talloc_steal(trusted_domain_state, msgs[0]->dn);
+               }
+       }
        handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
        if (!handle) {
                return NT_STATUS_NO_MEMORY;
@@ -1001,7 +1192,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;
        }
@@ -1071,7 +1262,7 @@ static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_cal
 {
        NTSTATUS status;
        struct lsa_OpenTrustedDomain open;
-       struct lsa_Delete delete;
+       struct lsa_DeleteObject delete;
        struct dcesrv_handle *h;
 
        open.in.handle = r->in.handle;
@@ -1090,7 +1281,8 @@ static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_cal
        talloc_steal(mem_ctx, h);
 
        delete.in.handle = open.out.trustdom_handle;
-       status = dcesrv_lsa_Delete(dce_call, mem_ctx, &delete);
+       delete.out.handle = open.out.trustdom_handle;
+       status = dcesrv_lsa_DeleteObject(dce_call, mem_ctx, &delete);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1134,12 +1326,13 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
                "trustDirection",
                "trustType",
                "trustAttributes", 
+               "msDs-supportedEncryptionTypes",
                NULL
        };
 
        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,
@@ -1177,12 +1370,19 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
                ZERO_STRUCT(r->out.info->full_info);
                return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info.info_ex);
 
-       case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL:
-               ZERO_STRUCT(r->out.info->info_all);
-               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->info_all.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
+                       = samdb_result_uint(msg, "posixOffset", 0);                                        
+               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info2_internal.info.info_ex);
+               
+       case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRTYPION_TYPES:
+               r->out.info->enc_types.enc_types
+                       = samdb_result_uint(msg, "msDs-supportedEncryptionTypes", KERB_ENCTYPE_RC4_HMAC_MD5);
+               break;
 
-       case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO:
-       case LSA_TRUSTED_DOMAIN_INFO_11:
+       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;
@@ -1340,9 +1540,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALL
        if (count == -1) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       if (count == 0 || r->in.max_size == 0) {
-               return NT_STATUS_OK;
-       }
 
        /* convert to lsa_TrustInformation format */
        entries = talloc_array(mem_ctx, struct lsa_DomainInfo, count);
@@ -1428,9 +1625,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca
        if (count == -1) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       if (count == 0 || r->in.max_size == 0) {
-               return NT_STATUS_OK;
-       }
 
        /* convert to lsa_DomainInformation format */
        entries = talloc_array(mem_ctx, struct lsa_TrustDomainInfoInfoEx, count);
@@ -1460,320 +1654,15 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca
        r->out.domains->count = MIN(r->out.domains->count, 
                                 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER));
 
-       r->out.domains->domains = entries + *r->in.resume_handle;
-       r->out.domains->count = r->out.domains->count;
-
-       if (r->out.domains->count < count - *r->in.resume_handle) {
-               *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
-               return STATUS_MORE_ENTRIES;
-       }
-
-       return NT_STATUS_OK;
-}
-
-
-/*
-  return the authority name and authority sid, given a sid
-*/
-static NTSTATUS dcesrv_lsa_authority_name(struct lsa_policy_state *state,
-                                  TALLOC_CTX *mem_ctx, struct dom_sid *sid,
-                                  const char **authority_name,
-                                  struct dom_sid **authority_sid)
-{
-       if (dom_sid_in_domain(state->domain_sid, sid)) {
-               *authority_name = state->domain_name;
-               *authority_sid = state->domain_sid;
-               return NT_STATUS_OK;
-       }
-
-       if (dom_sid_in_domain(state->builtin_sid, sid)) {
-               *authority_name = "BUILTIN";
-               *authority_sid = state->builtin_sid;
-               return NT_STATUS_OK;
-       }
-
-       *authority_sid = dom_sid_dup(mem_ctx, sid);
-       if (*authority_sid == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       (*authority_sid)->num_auths = 0;
-       *authority_name = dom_sid_string(mem_ctx, *authority_sid);
-       if (*authority_name == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       return NT_STATUS_OK;
-}
-
-/*
-  add to the lsa_RefDomainList for LookupSids and LookupNames
-*/
-static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, 
-                                  struct dom_sid *sid, 
-                                  struct lsa_RefDomainList *domains,
-                                  uint32_t *sid_index)
-{
-       NTSTATUS status;
-       const char *authority_name;
-       struct dom_sid *authority_sid;
-       int i;
-
-       /* work out the authority name */
-       status = dcesrv_lsa_authority_name(state, mem_ctx, sid, 
-                                   &authority_name, &authority_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       
-       /* see if we've already done this authority name */
-       for (i=0;i<domains->count;i++) {
-               if (strcmp(authority_name, domains->domains[i].name.string) == 0) {
-                       *sid_index = i;
-                       return NT_STATUS_OK;
-               }
-       }
-
-       domains->domains = talloc_realloc(domains, 
-                                         domains->domains,
-                                         struct lsa_DomainInfo,
-                                         domains->count+1);
-       if (domains->domains == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       domains->domains[i].name.string = authority_name;
-       domains->domains[i].sid         = authority_sid;
-       domains->count++;
-       domains->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER * domains->count;
-       *sid_index = i;
-       
-       return NT_STATUS_OK;
-}
-
-/*
-  lookup a name for 1 SID
-*/
-static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
-                              struct dom_sid *sid, const char *sid_str,
-                              const char **name, uint32_t *atype)
-{
-       int ret;
-       struct ldb_message **res;
-       const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "name", NULL};
-       NTSTATUS status;
-
-       ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, 
-                          "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid));
-       if (ret == 1) {
-               *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL);
-               if (!*name) {
-                       *name = ldb_msg_find_attr_as_string(res[0], "name", NULL);
-                       if (!*name) {
-                               *name = talloc_strdup(mem_ctx, sid_str);
-                               NT_STATUS_HAVE_NO_MEMORY(*name);
-                       }
-               }
-
-               *atype = samdb_result_uint(res[0], "sAMAccountType", 0);
-
-               return NT_STATUS_OK;
-       }
-
-       status = sidmap_allocated_sid_lookup(state->sidmap, mem_ctx, sid, name, atype);
-
-       return status;
-}
-
-
-/*
-  lsa_LookupSids2
-*/
-static NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call,
-                               TALLOC_CTX *mem_ctx,
-                               struct lsa_LookupSids2 *r)
-{
-       struct lsa_policy_state *state;
-       int i;
-       NTSTATUS status = NT_STATUS_OK;
-
-       r->out.domains = NULL;
-
-       status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
-       if (r->out.domains == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       r->out.names = talloc_zero(mem_ctx,  struct lsa_TransNameArray2);
-       if (r->out.names == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       *r->out.count = 0;
-
-       r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2, 
-                                            r->in.sids->num_sids);
-       if (r->out.names->names == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       for (i=0;i<r->in.sids->num_sids;i++) {
-               struct dom_sid *sid = r->in.sids->sids[i].sid;
-               char *sid_str = dom_sid_string(mem_ctx, sid);
-               const char *name;
-               uint32_t atype, rtype, sid_index;
-               NTSTATUS status2;
-
-               r->out.names->count++;
-               (*r->out.count)++;
-
-               r->out.names->names[i].sid_type    = SID_NAME_UNKNOWN;
-               r->out.names->names[i].name.string = sid_str;
-               r->out.names->names[i].sid_index   = 0xFFFFFFFF;
-               r->out.names->names[i].unknown     = 0;
-
-               if (sid_str == NULL) {
-                       r->out.names->names[i].name.string = "(SIDERROR)";
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               /* work out the authority name */
-               status2 = dcesrv_lsa_authority_list(state, mem_ctx, sid, r->out.domains, &sid_index);
-               if (!NT_STATUS_IS_OK(status2)) {
-                       return status2;
-               }
-
-               status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str, 
-                                        &name, &atype);
-               if (!NT_STATUS_IS_OK(status2)) {
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               rtype = samdb_atype_map(atype);
-               if (rtype == SID_NAME_UNKNOWN) {
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               r->out.names->names[i].sid_type    = rtype;
-               r->out.names->names[i].name.string = name;
-               r->out.names->names[i].sid_index   = sid_index;
-               r->out.names->names[i].unknown     = 0;
-       }
-       
-       return status;
-}
-
-
-/*
-  lsa_LookupSids3
-
-  Identical to LookupSids2, but doesn't take a policy handle
-  
-*/
-static NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
-                               TALLOC_CTX *mem_ctx,
-                               struct lsa_LookupSids3 *r)
-{
-       struct lsa_LookupSids2 r2;
-       struct lsa_OpenPolicy2 pol;
-       NTSTATUS status;
-       struct dcesrv_handle *h;
-
-       /* No policy handle on the wire, so make one up here */
-       r2.in.handle = talloc(mem_ctx, struct policy_handle);
-       if (!r2.in.handle) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       pol.out.handle = r2.in.handle;
-       pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       pol.in.attr = NULL;
-       pol.in.system_name = NULL;
-       status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       /* ensure this handle goes away at the end of this call */
-       DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
-       talloc_steal(mem_ctx, h);
-
-       r2.in.sids     = r->in.sids;
-       r2.in.names    = r->in.names;
-       r2.in.level    = r->in.level;
-       r2.in.count    = r->in.count;
-       r2.in.unknown1 = r->in.unknown1;
-       r2.in.unknown2 = r->in.unknown2;
-       r2.out.count   = r->out.count;
-       r2.out.names   = r->out.names;
-
-       status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
-
-       r->out.domains = r2.out.domains;
-       r->out.names   = r2.out.names;
-       r->out.count   = r2.out.count;
-
-       return status;
-}
-
-
-/* 
-  lsa_LookupSids 
-*/
-static NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                              struct lsa_LookupSids *r)
-{
-       struct lsa_LookupSids2 r2;
-       NTSTATUS status;
-       int i;
-
-       r2.in.handle   = r->in.handle;
-       r2.in.sids     = r->in.sids;
-       r2.in.names    = NULL;
-       r2.in.level    = r->in.level;
-       r2.in.count    = r->in.count;
-       r2.in.unknown1 = 0;
-       r2.in.unknown2 = 0;
-       r2.out.count   = r->out.count;
-       r2.out.names   = NULL;
-
-       status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
-
-       r->out.domains = r2.out.domains;
-       if (!r2.out.names) {
-               r->out.names = NULL;
-               return status;
-       }
-
-       r->out.names = talloc(mem_ctx, struct lsa_TransNameArray);
-       if (r->out.names == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       r->out.names->count = r2.out.names->count;
-       r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName, 
-                                            r->out.names->count);
-       if (r->out.names->names == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       for (i=0;i<r->out.names->count;i++) {
-               r->out.names->names[i].sid_type    = r2.out.names->names[i].sid_type;
-               r->out.names->names[i].name.string = r2.out.names->names[i].name.string;
-               r->out.names->names[i].sid_index   = r2.out.names->names[i].sid_index;
+       r->out.domains->domains = entries + *r->in.resume_handle;
+       r->out.domains->count = r->out.domains->count;
+
+       if (r->out.domains->count < count - *r->in.resume_handle) {
+               *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
+               return STATUS_MORE_ENTRIES;
        }
 
-       return status;
+       return NT_STATUS_OK;
 }
 
 
@@ -2027,7 +1916,7 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
                return NT_STATUS_OK;
        }
 
-       ret = samdb_modify(state->sam_ldb, mem_ctx, msg);
+       ret = ldb_modify(state->sam_ldb, msg);
        if (ret != 0) {
                if (ldb_flag == LDB_FLAG_MOD_DELETE && ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
                        return NT_STATUS_OBJECT_NAME_NOT_FOUND;
@@ -2166,7 +2055,36 @@ 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;
+
+       enumPrivs.in.handle = r->in.handle;
+
+       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 < enumPrivs.out.privs->count; i++) {
+               int priv = enumPrivs.out.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;
 }
 
 
@@ -2203,6 +2121,16 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
        DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
        ZERO_STRUCTP(r->out.sec_handle);
        
+       switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+       {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               break;
+       default:
+               /* Users and annonymous are not allowed create secrets */
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        policy_state = policy_handle->data;
 
        if (!r->in.name.string) {
@@ -2223,8 +2151,10 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
        if (strncmp("G$", r->in.name.string, 2) == 0) {
                const char *name2;
                name = &r->in.name.string[2];
-               secret_state->sam_ldb = talloc_reference(secret_state, policy_state->sam_ldb);
-               secret_state->global = True;
+                       /* 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))); 
+               secret_state->global = true;
 
                if (strlen(name) < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -2254,14 +2184,15 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
                samdb_msg_add_string(secret_state->sam_ldb, mem_ctx, msg, "cn", name2);
        
        } else {
-               secret_state->global = False;
+               secret_state->global = false;
 
                name = r->in.name.string;
                if (strlen(name) < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
-               secret_state->sam_ldb = talloc_reference(secret_state, secrets_db_connect(mem_ctx));
+               secret_state->sam_ldb = talloc_reference(secret_state, 
+                                                        secrets_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx));
                /* search for the secret record */
                ret = gendb_search(secret_state->sam_ldb, mem_ctx,
                                   ldb_dn_new(mem_ctx, secret_state->sam_ldb, "cn=LSA Secrets"),
@@ -2296,7 +2227,7 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
        secret_state->secret_dn = talloc_reference(secret_state, msg->dn);
 
        /* create the secret */
-       ret = samdb_add(secret_state->sam_ldb, mem_ctx, msg);
+       ret = ldb_add(secret_state->sam_ldb, msg);
        if (ret != 0) {
                DEBUG(0,("Failed to create secret record %s: %s\n",
                         ldb_dn_get_linearized(msg->dn), 
@@ -2348,6 +2279,16 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
                return NT_STATUS_INVALID_PARAMETER;
        }
        
+       switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+       {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               break;
+       default:
+               /* Users and annonymous are not allowed to access secrets */
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        secret_state = talloc(mem_ctx, struct lsa_secret_state);
        if (!secret_state) {
                return NT_STATUS_NO_MEMORY;
@@ -2356,8 +2297,10 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
 
        if (strncmp("G$", r->in.name.string, 2) == 0) {
                name = &r->in.name.string[2];
-               secret_state->sam_ldb = talloc_reference(secret_state, policy_state->sam_ldb);
-               secret_state->global = True;
+               /* 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))); 
+               secret_state->global = true;
 
                if (strlen(name) < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -2379,9 +2322,10 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
                }
        
        } else {
-               secret_state->sam_ldb = talloc_reference(secret_state, secrets_db_connect(mem_ctx));
+               secret_state->global = false;
+               secret_state->sam_ldb = talloc_reference(secret_state, 
+                                secrets_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx));
 
-               secret_state->global = False;
                name = r->in.name.string;
                if (strlen(name) < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -2484,23 +2428,59 @@ static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_
                        return NT_STATUS_NO_MEMORY; 
                }
 
-               if (!r->in.new_val) {
-                       /* This behaviour varies depending of if this is a local, or a global secret... */
-                       if (secret_state->global) {
-                               /* set old value mtime */
-                               if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                                        mem_ctx, msg, "lastSetTime", nt_now) != 0) { 
-                                       return NT_STATUS_NO_MEMORY; 
-                               }
-                       } else {
-                               if (samdb_msg_add_delete(secret_state->sam_ldb, 
-                                                        mem_ctx, msg, "currentValue")) {
-                                       return NT_STATUS_NO_MEMORY;
-                               }
-                               if (samdb_msg_add_delete(secret_state->sam_ldb, 
-                                                        mem_ctx, msg, "lastSetTime")) {
-                                       return NT_STATUS_NO_MEMORY;
-                               }
+       } else {
+               /* If the old value is not set, then migrate the
+                * current value to the old value */
+               const struct ldb_val *old_val;
+               NTTIME last_set_time;
+               struct ldb_message **res;
+               const char *attrs[] = {
+                       "currentValue",
+                       "lastSetTime",
+                       NULL
+               };
+               
+               /* search for the secret record */
+               ret = gendb_search_dn(secret_state->sam_ldb,mem_ctx,
+                                     secret_state->secret_dn, &res, attrs);
+               if (ret == 0) {
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               }
+               
+               if (ret != 1) {
+                       DEBUG(0,("Found %d records matching dn=%s\n", ret,
+                                ldb_dn_get_linearized(secret_state->secret_dn)));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+               
+               old_val = ldb_msg_find_ldb_val(res[0], "currentValue");
+               last_set_time = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);
+               
+               if (old_val) {
+                       /* set old value */
+                       if (samdb_msg_add_value(secret_state->sam_ldb, 
+                                               mem_ctx, msg, "priorValue", 
+                                               old_val) != 0) {
+                               return NT_STATUS_NO_MEMORY; 
+                       }
+               } else {
+                       if (samdb_msg_add_delete(secret_state->sam_ldb, 
+                                                mem_ctx, msg, "priorValue")) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       
+               }
+               
+               /* 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) { 
+                               return NT_STATUS_NO_MEMORY; 
+                       }
+               } else {
+                       if (samdb_msg_add_uint64(secret_state->sam_ldb, 
+                                                mem_ctx, msg, "priorSetTime", nt_now) != 0) { 
+                               return NT_STATUS_NO_MEMORY; 
                        }
                }
        }
@@ -2530,50 +2510,15 @@ static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_
                        return NT_STATUS_NO_MEMORY; 
                }
                
-               /* If the old value is not set, then migrate the
-                * current value to the old value */
-               if (!r->in.old_val) {
-                       const struct ldb_val *new_val;
-                       NTTIME last_set_time;
-                       struct ldb_message **res;
-                       const char *attrs[] = {
-                               "currentValue",
-                               "lastSetTime",
-                               NULL
-                       };
-                       
-                       /* search for the secret record */
-                       ret = gendb_search_dn(secret_state->sam_ldb,mem_ctx,
-                                             secret_state->secret_dn, &res, attrs);
-                       if (ret == 0) {
-                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                       }
-                       
-                       if (ret != 1) {
-                               DEBUG(0,("Found %d records matching dn=%s\n", ret,
-                                        ldb_dn_get_linearized(secret_state->secret_dn)));
-                               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-                       }
-
-                       new_val = ldb_msg_find_ldb_val(res[0], "currentValue");
-                       last_set_time = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);
-                       
-                       if (new_val) {
-                               /* set value */
-                               if (samdb_msg_add_value(secret_state->sam_ldb, 
-                                                       mem_ctx, msg, "priorValue", 
-                                                       new_val) != 0) {
-                                       return NT_STATUS_NO_MEMORY; 
-                               }
-                       }
-                       
-                       /* set new 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) { 
-                                       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) { 
+                       return NT_STATUS_NO_MEMORY; 
+               }
+               if (samdb_msg_add_delete(secret_state->sam_ldb, 
+                                        mem_ctx, msg, "currentValue")) {
+                       return NT_STATUS_NO_MEMORY;
                }
        }
 
@@ -2613,6 +2558,17 @@ static NTSTATUS dcesrv_lsa_QuerySecret(struct dcesrv_call_state *dce_call, TALLO
 
        DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
 
+       /* Ensure user is permitted to read this... */
+       switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+       {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               break;
+       default:
+               /* Users and annonymous are not allowed to read secrets */
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        secret_state = h->data;
 
        /* pull all the user attributes */
@@ -2798,16 +2754,6 @@ static NTSTATUS dcesrv_lsa_LookupPrivDisplayName(struct dcesrv_call_state *dce_c
 }
 
 
-/* 
-  lsa_DeleteObject
-*/
-static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_DeleteObject *r)
-{
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
-}
-
-
 /* 
   lsa_EnumAccountsWithUserRight
 */
@@ -2973,6 +2919,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);
 }
 
@@ -2983,7 +2930,42 @@ static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state
                                                 TALLOC_CTX *mem_ctx,
                                                 struct lsa_QueryDomainInformationPolicy *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       r->out.info = talloc(mem_ctx, union lsa_DomainInformationPolicy);
+       if (!r->out.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;
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+       {
+               struct lsa_DomainInfoKerberos *k = &r->out.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;
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               k->enforce_restrictions = 0; /* FIXME, details missing from MS-LSAD 2.2.53 */
+               k->service_tkt_lifetime = 0; /* Need to find somewhere to store this, and query in KDC too */
+               k->user_tkt_lifetime = 0;    /* Need to find somewhere to store this, and query in KDC too */
+               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);
+               return NT_STATUS_OK;
+       }
+       default:
+               talloc_free(r->out.info);
+               r->out.info = NULL;
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }
 }
 
 /*
@@ -3006,293 +2988,6 @@ static NTSTATUS dcesrv_lsa_TestCall(struct dcesrv_call_state *dce_call,
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
-/*
-  lookup a SID for 1 name
-*/
-static NTSTATUS dcesrv_lsa_lookup_name(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
-                               const char *name, struct dom_sid **sid, uint32_t *atype)
-{
-       int ret;
-       struct ldb_message **res;
-       const char * const attrs[] = { "objectSid", "sAMAccountType", NULL};
-       const char *p;
-
-       p = strchr_m(name, '\\');
-       if (p != NULL) {
-               /* TODO: properly parse the domain prefix here, and use it to 
-                  limit the search */
-               name = p + 1;
-       }
-
-       ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, "sAMAccountName=%s", ldb_binary_encode_string(mem_ctx, name));
-       if (ret == 1) {
-               *sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
-               if (*sid == NULL) {
-                       return NT_STATUS_INVALID_SID;
-               }
-
-               *atype = samdb_result_uint(res[0], "sAMAccountType", 0);
-
-               return NT_STATUS_OK;
-       }
-
-       /* need to add a call into sidmap to check for a allocated sid */
-
-       return NT_STATUS_INVALID_SID;
-}
-
-
-/*
-  lsa_LookupNames3
-*/
-static NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
-                                TALLOC_CTX *mem_ctx,
-                                struct lsa_LookupNames3 *r)
-{
-       struct lsa_policy_state *policy_state;
-       struct dcesrv_handle *policy_handle;
-       int i;
-       NTSTATUS status = NT_STATUS_OK;
-
-       DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
-
-       policy_state = policy_handle->data;
-
-       r->out.domains = NULL;
-
-       r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
-       if (r->out.domains == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray3);
-       if (r->out.sids == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       *r->out.count = 0;
-
-       r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3, 
-                                          r->in.num_names);
-       if (r->out.sids->sids == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       for (i=0;i<r->in.num_names;i++) {
-               const char *name = r->in.names[i].string;
-               struct dom_sid *sid;
-               uint32_t atype, rtype, sid_index;
-               NTSTATUS status2;
-
-               r->out.sids->count++;
-               (*r->out.count)++;
-
-               r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
-               r->out.sids->sids[i].sid         = NULL;
-               r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
-               r->out.sids->sids[i].unknown     = 0;
-
-               status2 = dcesrv_lsa_lookup_name(policy_state, mem_ctx, name, &sid, &atype);
-               if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) {
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               rtype = samdb_atype_map(atype);
-               if (rtype == SID_NAME_UNKNOWN) {
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, sid, r->out.domains, &sid_index);
-               if (!NT_STATUS_IS_OK(status2)) {
-                       return status2;
-               }
-
-               r->out.sids->sids[i].sid_type    = rtype;
-               r->out.sids->sids[i].sid         = sid;
-               r->out.sids->sids[i].sid_index   = sid_index;
-               r->out.sids->sids[i].unknown     = 0;
-       }
-       
-       return status;
-}
-
-/* 
-  lsa_LookupNames4
-
-  Identical to LookupNames3, but doesn't take a policy handle
-  
-*/
-static NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                                struct lsa_LookupNames4 *r)
-{
-       struct lsa_LookupNames3 r2;
-       struct lsa_OpenPolicy2 pol;
-       NTSTATUS status;
-       struct dcesrv_handle *h;
-
-       /* No policy handle on the wire, so make one up here */
-       r2.in.handle = talloc(mem_ctx, struct policy_handle);
-       if (!r2.in.handle) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       pol.out.handle = r2.in.handle;
-       pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       pol.in.attr = NULL;
-       pol.in.system_name = NULL;
-       status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       /* ensure this handle goes away at the end of this call */
-       DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
-       talloc_steal(mem_ctx, h);
-
-       r2.in.num_names = r->in.num_names;
-       r2.in.names = r->in.names;
-       r2.in.sids = r->in.sids;
-       r2.in.count = r->in.count;
-       r2.in.unknown1 = r->in.unknown1;
-       r2.in.unknown2 = r->in.unknown2;
-       r2.out.domains = r->out.domains;
-       r2.out.sids = r->out.sids;
-       r2.out.count = r->out.count;
-       
-       status = dcesrv_lsa_LookupNames3(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
-       
-       r->out.domains = r2.out.domains;
-       r->out.sids = r2.out.sids;
-       r->out.count = r2.out.count;
-       return status;
-}
-
-/*
-  lsa_LookupNames2
-*/
-static NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call,
-                                TALLOC_CTX *mem_ctx,
-                                struct lsa_LookupNames2 *r)
-{
-       struct lsa_policy_state *state;
-       struct dcesrv_handle *h;
-       int i;
-       NTSTATUS status = NT_STATUS_OK;
-
-       r->out.domains = NULL;
-
-       DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
-
-       state = h->data;
-
-       r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
-       if (r->out.domains == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray2);
-       if (r->out.sids == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       *r->out.count = 0;
-
-       r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2, 
-                                          r->in.num_names);
-       if (r->out.sids->sids == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       for (i=0;i<r->in.num_names;i++) {
-               const char *name = r->in.names[i].string;
-               struct dom_sid *sid;
-               uint32_t atype, rtype, sid_index;
-               NTSTATUS status2;
-
-               r->out.sids->count++;
-               (*r->out.count)++;
-
-               r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
-               r->out.sids->sids[i].rid         = 0xFFFFFFFF;
-               r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
-               r->out.sids->sids[i].unknown     = 0;
-
-               status2 = dcesrv_lsa_lookup_name(state, mem_ctx, name, &sid, &atype);
-               if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) {
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               rtype = samdb_atype_map(atype);
-               if (rtype == SID_NAME_UNKNOWN) {
-                       status = STATUS_SOME_UNMAPPED;
-                       continue;
-               }
-
-               status2 = dcesrv_lsa_authority_list(state, mem_ctx, sid, r->out.domains, &sid_index);
-               if (!NT_STATUS_IS_OK(status2)) {
-                       return status2;
-               }
-
-               r->out.sids->sids[i].sid_type    = rtype;
-               r->out.sids->sids[i].rid         = sid->sub_auths[sid->num_auths-1];
-               r->out.sids->sids[i].sid_index   = sid_index;
-               r->out.sids->sids[i].unknown     = 0;
-       }
-       
-       return status;
-}
-
-/* 
-  lsa_LookupNames 
-*/
-static NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_LookupNames *r)
-{
-       struct lsa_LookupNames2 r2;
-       NTSTATUS status;
-       int i;
-
-       r2.in.handle    = r->in.handle;
-       r2.in.num_names = r->in.num_names;
-       r2.in.names     = r->in.names;
-       r2.in.sids      = NULL;
-       r2.in.level     = r->in.level;
-       r2.in.count     = r->in.count;
-       r2.in.unknown1  = 0;
-       r2.in.unknown2  = 0;
-       r2.out.count    = r->out.count;
-
-       status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
-
-       r->out.domains = r2.out.domains;
-       r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray);
-       if (r->out.sids == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       r->out.sids->count = r2.out.sids->count;
-       r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid, 
-                                          r->out.sids->count);
-       if (r->out.sids->sids == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       for (i=0;i<r->out.sids->count;i++) {
-               r->out.sids->sids[i].sid_type    = r2.out.sids->sids[i].sid_type;
-               r->out.sids->sids[i].rid         = r2.out.sids->sids[i].rid;
-               r->out.sids->sids[i].sid_index   = r2.out.sids->sids[i].sid_index;
-       }
-
-       return status;
-}
-
 /* 
   lsa_CREDRWRITE 
 */