s4-lsa: Fix dcesrv_lsa_EnumTrustDom() and avoid infite windows client loop.
[ira/wip.git] / source4 / rpc_server / lsa / dcesrv_lsa.c
index 5c03584fa79d7bbe9538afd6343f5c74971f71f4..e35f2d8bf6fb8635f9b3916ab7b6fcb2354eda47 100644 (file)
@@ -1,14 +1,16 @@
+/* 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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#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"
-
-/*
-  this type allows us to distinguish handle types
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
-enum lsa_handle {
-       LSA_HANDLE_POLICY,
-       LSA_HANDLE_ACCOUNT,
-       LSA_HANDLE_SECRET,
-       LSA_HANDLE_TRUSTED_DOMAIN
-};
+
+#include "rpc_server/lsa/lsa.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"
 
 /*
-  state associated with a lsa_OpenPolicy() operation
+  this type allows us to distinguish handle types
 */
-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 *builtin_dn;
-       struct ldb_dn *system_dn;
-       const char *domain_name;
-       const char *domain_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
@@ -82,7 +51,7 @@ struct lsa_secret_state {
        uint32_t access_mask;
        struct ldb_dn *secret_dn;
        struct ldb_context *sam_ldb;
-       BOOL global;
+       bool global;
 };
 
 /*
@@ -92,8 +61,68 @@ 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;
 };
 
+/*
+  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);
@@ -130,29 +159,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;
@@ -170,6 +247,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;
@@ -189,6 +269,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;
@@ -242,9 +324,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;
 }
 
 
@@ -267,131 +373,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;
-       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;             
-       }
-
-       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);
-
-       /* 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 
 
@@ -425,7 +406,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;
@@ -441,13 +422,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;
@@ -460,7 +441,7 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
                        
                        domain          = state->domain_name;
                        dns_domain      = state->domain_dns;
-                       forest          = state->domain_dns;
+                       forest          = state->forest_dns;
 
                        domain_guid     = state->domain_guid;
                        flags   |= DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT;
@@ -499,61 +480,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
 */
@@ -575,7 +501,7 @@ static NTSTATUS dcesrv_lsa_info_DNS(struct lsa_policy_state *state, TALLOC_CTX *
        info->name.string = state->domain_name;
        info->sid         = state->domain_sid;
        info->dns_domain.string = state->domain_dns;
-       info->dns_forest.string = state->domain_dns;
+       info->dns_forest.string = state->forest_dns;
        info->domain_guid       = state->domain_guid;
 
        return NT_STATUS_OK;
@@ -589,29 +515,67 @@ 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_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;
 }
 
@@ -624,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;
 }
 
@@ -640,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);
 }
 
@@ -656,6 +622,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)
@@ -719,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;
@@ -762,101 +737,361 @@ 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;
+               }
+                       
+               samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "securityIdentifier", sid_string);
+       }
+
+       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;
                }
-                       
-               samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "securityIdentifier", sid_string);
        }
 
-       samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "objectClass", "trustedDomain");
-       
        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_user == 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;
        }
 
@@ -875,6 +1110,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
 */
@@ -888,6 +1176,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
        };
 
@@ -898,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;
        }
@@ -925,7 +1215,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;
@@ -969,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;
        }
@@ -1038,27 +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_Delete 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;
-       status = dcesrv_lsa_Delete(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;
        }
@@ -1090,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;
@@ -1102,12 +1407,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,
@@ -1117,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 */
@@ -1139,26 +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_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(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, &info->full_info2_internal.info.info_ex);
+               
+       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_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;
+               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;
        }
 
@@ -1173,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;
 }
 
@@ -1221,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;
 }
 
@@ -1308,9 +1625,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);
@@ -1346,6 +1660,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;
 }
 
@@ -1396,9 +1719,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);
@@ -1440,311 +1760,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca
 }
 
 
-/*
-  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;
-       }
-
-       return status;
-}
-
-
 /* 
   lsa_OpenAccount 
 */
@@ -1803,22 +1818,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;
@@ -1829,9 +1850,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;
        }
 
@@ -1840,12 +1861,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;
 }
@@ -1874,7 +1895,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;
@@ -1885,7 +1906,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;
        }
 
@@ -1920,15 +1941,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);
@@ -1936,24 +1959,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;
@@ -1970,6 +1986,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;
                }
 
@@ -1986,26 +2003,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 = samdb_modify(state->sam_ldb, mem_ctx, msg);
+
+       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 != 0) {
                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;
 }
 
@@ -2134,7 +2166,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;
 }
 
 
@@ -2159,7 +2230,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
        };
@@ -2171,6 +2241,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) {
@@ -2191,8 +2271,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;
@@ -2222,14 +2304,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"),
@@ -2250,26 +2333,17 @@ 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, 
-                                 "(&(cn=TemplateSecret)(objectclass=secretTemplate))", &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 = 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), 
                         ldb_errstring(secret_state->sam_ldb)));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
@@ -2316,6 +2390,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;
@@ -2324,8 +2408,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;
@@ -2347,9 +2433,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;
@@ -2366,8 +2453,8 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
                }
                
                if (ret != 1) {
-                       DEBUG(0,("Found %d records matching DN %s\n", ret,
-                                ldb_dn_get_linearized(policy_state->system_dn)));
+                       DEBUG(0,("Found %d records matching CN=%s\n", 
+                                ret, ldb_binary_encode_string(mem_ctx, name)));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        } 
@@ -2452,23 +2539,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; 
                        }
                }
        }
@@ -2498,50 +2621,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;
                }
        }
 
@@ -2581,6 +2669,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 */
@@ -2707,6 +2806,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);
@@ -2722,11 +2822,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;    
 }
@@ -2741,6 +2844,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);
@@ -2751,28 +2855,21 @@ 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;
        }
 
-       return NT_STATUS_OK;
-}
-
+       *r->out.disp_name = disp_name;
+       *r->out.returned_language_id = 0;
 
-/* 
-  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);
+       return NT_STATUS_OK;
 }
 
 
@@ -2803,7 +2900,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;
@@ -2897,19 +2994,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;
        }
 
@@ -2921,15 +3022,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;
 }
@@ -2941,6 +3042,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);
 }
 
@@ -2951,7 +3053,45 @@ static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state
                                                 TALLOC_CTX *mem_ctx,
                                                 struct lsa_QueryDomainInformationPolicy *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       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(info);
+               *r->out.info = NULL;
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+       {
+               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(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);
+               *r->out.info = info;
+               return NT_STATUS_OK;
+       }
+       default:
+               talloc_free(info);
+               *r->out.info = NULL;
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }
 }
 
 /*
@@ -2974,293 +3114,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 
 */
@@ -3382,10 +3235,10 @@ static NTSTATUS dcesrv_lsa_LSARUNREGISTERAUDITEVENT(struct dcesrv_call_state *dc
 
 
 /* 
-  lsa_LSARQUERYFORESTTRUSTINFORMATION 
+  lsa_lsaRQueryForestTrustInformation 
 */
-static NTSTATUS dcesrv_lsa_LSARQUERYFORESTTRUSTINFORMATION(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_LSARQUERYFORESTTRUSTINFORMATION *r)
+static NTSTATUS dcesrv_lsa_lsaRQueryForestTrustInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct lsa_lsaRQueryForestTrustInformation *r)
 {
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }