Initial import
[samba] / source / libmsrpc / cac_lsarpc.c
diff --git a/source/libmsrpc/cac_lsarpc.c b/source/libmsrpc/cac_lsarpc.c
new file mode 100644 (file)
index 0000000..d2e52f0
--- /dev/null
@@ -0,0 +1,1071 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client library implementation (LSA pipe)
+ *  Copyright (C) Chris Nicholls              2005.
+ *  
+ *  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
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  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 "libmsrpc.h"
+#include "libsmb_internal.h"
+
+int cac_LsaOpenPolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenPolicy *op) {
+   SMBCSRV *srv = NULL;
+   POLICY_HND *policy = NULL;
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   if(!hnd)
+      return CAC_FAILURE;
+         
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!mem_ctx || !op) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   op->out.pol = NULL;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE; 
+   }
+
+   /*see if there is already an active session on this pipe, if not then open one*/
+   if(!hnd->_internal.pipes[PI_LSARPC]) {
+      pipe_hnd = cli_rpc_pipe_open_noauth(&(srv->cli), PI_LSARPC, &(hnd->status));
+
+      if(!pipe_hnd) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_LSARPC] = True;
+   }
+
+   policy = SMB_MALLOC_P(POLICY_HND);
+   if(!policy) {
+      errno = ENOMEM;
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   /*need to make sure that our nt status is good otherwise check might fail below*/
+   hnd->status = NT_STATUS_OK;
+   
+   if(hnd->_internal.srv_level >= SRV_WIN_2K) { 
+
+      /*try using open_policy2, if this fails try again in next block using open_policy, if that works then adjust hnd->_internal.srv_level*/
+
+      /*we shouldn't need to modify the access mask to make it work here*/
+      hnd->status = rpccli_lsa_open_policy2(pipe_hnd, mem_ctx, op->in.security_qos, op->in.access, policy);
+
+   }
+
+   if(hnd->_internal.srv_level < SRV_WIN_2K || !NT_STATUS_IS_OK(hnd->status)) {
+      hnd->status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, op->in.security_qos, op->in.access, policy);
+
+      if(hnd->_internal.srv_level > SRV_WIN_NT4 && NT_STATUS_IS_OK(hnd->status)) {
+         /*change the server level to 1*/
+         hnd->_internal.srv_level = SRV_WIN_NT4;
+      }
+      
+   }
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      SAFE_FREE(policy);
+      return CAC_FAILURE;
+   }
+
+   op->out.pol = policy;
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaClosePolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *pol) {
+
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   if(!hnd)
+      return CAC_FAILURE;
+   
+   if(!pol)
+      return CAC_SUCCESS; /*if the policy handle doesnt exist then it's already closed*/
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+
+   hnd->status = rpccli_lsa_close(pipe_hnd, mem_ctx, pol);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   SAFE_FREE(pol);
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaGetNamesFromSids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetNamesFromSids *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   int result   = -1;
+
+   int i;
+
+   /*buffers for outputs*/
+   char **domains   = NULL;
+   char **names     = NULL;
+   uint32 *types    = NULL;
+
+   CacSidInfo *sids_out   = NULL;
+   DOM_SID *unknown_out   = NULL;
+   int num_unknown         = 0;
+
+   int num_sids;
+
+   int found_idx;
+   int unknown_idx;
+
+   if(!hnd)
+      return CAC_FAILURE;
+      
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!mem_ctx || !op || !op->in.pol || !op->in.sids) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   num_sids = op->in.num_sids;
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+
+
+   /*now actually lookup the names*/
+   hnd->status = rpccli_lsa_lookup_sids(pipe_hnd, mem_ctx, op->in.pol, op->in.num_sids,
+                                       op->in.sids, &domains, &names, &types);
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      /*this is the easy part, just make the out.sids array*/
+      sids_out = TALLOC_ARRAY(mem_ctx, CacSidInfo, num_sids);
+      if(!sids_out) {
+         errno = ENOMEM;
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+
+      for(i = 0; i < num_sids; i++) {
+         sids_out[i].sid    = op->in.sids[i];
+         sids_out[i].name   = names[i];
+         sids_out[i].domain = domains[i];
+      }
+
+      result = CAC_SUCCESS;
+   }
+   else if(NT_STATUS_V(hnd->status) == NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
+      /*first find out how many couldn't be looked up*/
+
+      for(i = 0; i < num_sids; i++) {
+         if(names[i] == NULL) {
+            num_unknown++;
+         }
+      }
+
+      if( num_unknown >= num_sids) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      sids_out = TALLOC_ARRAY(mem_ctx, CacSidInfo, (num_sids - num_unknown));
+      if(!sids_out) {
+         errno = ENOMEM;
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+
+      unknown_out = TALLOC_ARRAY(mem_ctx, DOM_SID, num_unknown);
+      if(!unknown_out) {
+         errno = ENOMEM;
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+
+      found_idx = unknown_idx = 0;
+
+      /*now we can actually do the real work*/
+      for(i = 0; i < num_sids; i++) {
+         if(names[i] != NULL) {
+            sids_out[found_idx].sid    = op->in.sids[i];
+            sids_out[found_idx].name   = names[i];
+            sids_out[found_idx].domain = domains[i];
+
+            found_idx++;
+         }
+         else { /*then this one didnt work out*/
+            unknown_out[unknown_idx] = op->in.sids[i];
+
+            unknown_idx++;
+         }
+      }
+
+      result = CAC_PARTIAL_SUCCESS;
+   }
+   else { /*then it failed for some reason*/
+      return CAC_FAILURE;
+   }
+
+   op->out.num_found    = num_sids - num_unknown;
+   op->out.sids         = sids_out;
+   op->out.unknown      = unknown_out;
+
+   return result;
+   
+}
+
+int cac_LsaGetSidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetSidsFromNames *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+   int result   = -1;
+
+   int i;
+
+   /*buffers for outputs*/
+   DOM_SID *sids     = NULL;
+   uint32 *types     = NULL;
+
+   CacSidInfo *sids_out  = NULL;
+   char **unknown_out     = NULL;
+   int num_unknown        = 0;
+
+   int num_names;
+
+   int found_idx          = 0;
+   int unknown_idx        = 0;
+
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!mem_ctx || !op || !op->in.pol || !op->in.names) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   num_names = op->in.num_names;
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+
+   /*now actually lookup the names*/
+   hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, num_names,
+                                          (const char **)op->in.names, &sids, &types);
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      /*this is the easy part, just make the out.sids array*/
+      sids_out = TALLOC_ARRAY(mem_ctx, CacSidInfo, num_names);
+      if(!sids_out) {
+         errno = ENOMEM;
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+
+      for(i = 0; i < num_names; i++) {
+         sids_out[i].sid    = sids[i];
+         sids_out[i].name   = talloc_strdup(mem_ctx, op->in.names[i]);
+         sids_out[i].domain = NULL;
+      }
+      
+      result = CAC_SUCCESS;
+   }
+   else if(NT_STATUS_V(hnd->status) == NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
+      /*first find out how many couldn't be looked up*/
+
+      for(i = 0; i < num_names; i++) {
+         if(types[i] == SID_NAME_UNKNOWN) {
+            num_unknown++;
+         }
+      }
+
+      if( num_unknown >= num_names) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      sids_out = TALLOC_ARRAY(mem_ctx, CacSidInfo, (num_names - num_unknown));
+      if(!sids_out) {
+         errno = ENOMEM;
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+
+      unknown_out = TALLOC_ARRAY(mem_ctx, char *, num_unknown);
+      if(!unknown_out) {
+         errno = ENOMEM;
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+
+      unknown_idx = found_idx = 0;
+
+      /*now we can actually do the real work*/
+      for(i = 0; i < num_names; i++) {
+         if(types[i] != SID_NAME_UNKNOWN) {
+            sids_out[found_idx].sid    = sids[i];
+            sids_out[found_idx].name   = talloc_strdup(mem_ctx, op->in.names[i]);
+            sids_out[found_idx].domain = NULL;
+
+            found_idx++;
+         }
+         else { /*then this one didnt work out*/
+            unknown_out[unknown_idx] = talloc_strdup(mem_ctx, op->in.names[i]);
+
+            unknown_idx++;
+         }
+      }
+
+      result = CAC_PARTIAL_SUCCESS;
+   }
+   else { /*then it failed for some reason*/
+      return CAC_FAILURE;
+   }
+
+   op->out.num_found    = num_names - num_unknown;
+   op->out.sids         = sids_out;
+   op->out.unknown      = unknown_out;
+
+   return result;
+   
+}
+
+int cac_LsaFetchSid(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaFetchSid *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+   int result   = -1;
+
+   if(!hnd)
+      return CAC_FAILURE;
+   
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC] ) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!mem_ctx || !op || !op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   op->out.local_sid  = NULL;
+   op->out.domain_sid = NULL;
+
+   if( (op->in.info_class & CAC_LOCAL_INFO) == CAC_LOCAL_INFO) {
+      DOM_SID *local_sid = NULL;
+      char *dom_name     = NULL;
+
+      hnd->status = rpccli_lsa_query_info_policy( pipe_hnd, mem_ctx, op->in.pol, CAC_LOCAL_INFO, &dom_name, &local_sid);
+
+      if(!NT_STATUS_IS_OK(hnd->status)) {
+         result = CAC_FAILURE;
+         goto domain;
+      }
+
+      op->out.local_sid = talloc(mem_ctx, CacSidInfo);
+      if(!op->out.local_sid) {
+         hnd->status = NT_STATUS_NO_MEMORY;
+         result = CAC_FAILURE;
+         goto domain;
+      }
+
+      op->out.local_sid->domain = dom_name;
+      
+      sid_copy(&op->out.local_sid->sid, local_sid);
+      talloc_free(local_sid);
+   }
+
+domain:
+
+   if( (op->in.info_class & CAC_DOMAIN_INFO) == CAC_DOMAIN_INFO) {
+      DOM_SID *domain_sid;
+      char *dom_name;
+
+      hnd->status = rpccli_lsa_query_info_policy( pipe_hnd, mem_ctx, op->in.pol, CAC_DOMAIN_INFO, &dom_name, &domain_sid);
+      if(!NT_STATUS_IS_OK(hnd->status)) {
+         /*if we succeeded above, report partial success*/
+         result = (result == CAC_SUCCESS) ? CAC_PARTIAL_SUCCESS : CAC_FAILURE;
+         goto done;
+      }
+      else if(result == CAC_FAILURE) {
+         /*if we failed above but succeded here then report partial success*/
+         result = CAC_PARTIAL_SUCCESS;
+      }
+
+      op->out.domain_sid = talloc(mem_ctx, CacSidInfo);
+      if(!op->out.domain_sid) {
+         hnd->status = NT_STATUS_NO_MEMORY;
+         result = CAC_FAILURE;
+         goto done;
+      }
+
+      op->out.domain_sid->domain = dom_name;
+      sid_copy(&op->out.domain_sid->sid, domain_sid);
+      talloc_free(domain_sid);
+   }
+   
+done:
+   return result;
+}
+
+int cac_LsaQueryInfoPolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaQueryInfoPolicy *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   char *domain_name    = NULL;
+   char *dns_name       = NULL;
+   char *forest_name     = NULL;
+   struct uuid *domain_guid    = NULL;
+   DOM_SID *domain_sid  = NULL;
+
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   /*only works if info_class parm is 12*/
+   hnd->status = rpccli_lsa_query_info_policy2(pipe_hnd, mem_ctx, op->in.pol, 12,
+                                             &domain_name, &dns_name, &forest_name, &domain_guid, &domain_sid);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+   
+   op->out.domain_name    = domain_name;
+   op->out.dns_name       = dns_name;
+   op->out.forest_name    = forest_name;
+   op->out.domain_guid    = domain_guid;
+   op->out.domain_sid     = domain_sid;
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaEnumSids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumSids *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   uint32 num_sids;
+   DOM_SID *sids;
+
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = rpccli_lsa_enum_sids(pipe_hnd, mem_ctx, op->in.pol, &(op->out.resume_idx), op->in.pref_max_sids, &num_sids, &sids);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.num_sids  = num_sids;
+   op->out.sids      = sids;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_LsaEnumAccountRights(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumAccountRights *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   uint32 count = 0;
+   char **privs = NULL;
+
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.name && !op->in.sid) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.name && !op->in.sid) {
+      DOM_SID *user_sid = NULL;
+      uint32 *type;
+
+      /*lookup the SID*/
+      hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      op->in.sid = user_sid;
+   }
+   
+   hnd->status = rpccli_lsa_enum_account_rights( pipe_hnd, mem_ctx, op->in.pol, op->in.sid,
+                                                   &count, &privs);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.num_privs = count;
+   op->out.priv_names = privs;
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaEnumTrustedDomains(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumTrustedDomains *op) {
+   struct rpc_pipe_client *pipe_hnd;
+   
+   uint32 num_domains;
+   char **domain_names;
+   DOM_SID *domain_sids;
+   
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = rpccli_lsa_enum_trust_dom( pipe_hnd, mem_ctx, op->in.pol, &(op->out.resume_idx), &num_domains, &domain_names, &domain_sids);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.num_domains = num_domains;
+   op->out.domain_names = domain_names;
+   op->out.domain_sids  = domain_sids;
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaOpenTrustedDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenTrustedDomain *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   POLICY_HND *dom_pol = NULL;
+
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.pol || !op->in.access || !op->in.domain_sid) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   dom_pol = talloc(mem_ctx, POLICY_HND);
+   if(!dom_pol) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      errno = ENOMEM;
+      return CAC_FAILURE;
+   }
+   
+   hnd->status = rpccli_lsa_open_trusted_domain( pipe_hnd, mem_ctx, op->in.pol, op->in.domain_sid, op->in.access, dom_pol);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.domain_pol = dom_pol;
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaQueryTrustedDomainInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaQueryTrustedDomainInfo *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   LSA_TRUSTED_DOMAIN_INFO *dom_info;
+
+   if(!hnd)
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.pol || !op->in.info_class) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.domain_sid && !op->in.domain_name) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.domain_sid) {
+      hnd->status = rpccli_lsa_query_trusted_domain_info_by_sid( pipe_hnd, mem_ctx, op->in.pol, op->in.info_class, op->in.domain_sid, &dom_info);
+   }
+   else if(op->in.domain_name) {
+      hnd->status = rpccli_lsa_query_trusted_domain_info_by_name( pipe_hnd, mem_ctx, op->in.pol, op->in.info_class, op->in.domain_name, &dom_info);
+   }
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.info = dom_info;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_LsaEnumPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumPrivileges *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   uint32 num_privs;
+   char **priv_names;
+   uint32 *high_bits;
+   uint32 *low_bits;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = rpccli_lsa_enum_privilege(pipe_hnd, mem_ctx, op->in.pol, &(op->out.resume_idx), op->in.pref_max_privs,
+                                             &num_privs, &priv_names, &high_bits, &low_bits);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.num_privs  = num_privs;
+   op->out.priv_names = priv_names;
+   op->out.high_bits  = high_bits;
+   op->out.low_bits   = low_bits;
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaOpenAccount(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenAccount *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   POLICY_HND *user_pol = NULL;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.sid && !op->in.name) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+
+   /*look up the user's SID if we have to*/
+   if(op->in.name && !op->in.sid) {
+      DOM_SID *user_sid = NULL;
+      uint32 *type;
+
+      /*lookup the SID*/
+      hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      op->in.sid = user_sid;
+   }
+
+   user_pol = talloc(mem_ctx, POLICY_HND);
+   if(!user_pol) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = rpccli_lsa_open_account(pipe_hnd, mem_ctx, op->in.pol, op->in.sid, op->in.access, user_pol);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      talloc_free(user_pol);
+      return CAC_FAILURE;
+   }
+
+   op->out.user = user_pol;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_LsaAddPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAddPrivileges *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   DOM_SID *user_sid = NULL;
+   uint32  *type     = NULL;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol || !op->in.priv_names) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.sid && !op->in.name) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      op->in.sid = user_sid;
+   }
+
+   hnd->status = rpccli_lsa_add_account_rights( pipe_hnd, mem_ctx, op->in.pol, *(op->in.sid), op->in.num_privs, (const char **)op->in.priv_names);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaRemovePrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaRemovePrivileges *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   DOM_SID *user_sid = NULL;
+   uint32  *type     = NULL;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol || !op->in.priv_names) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.sid && !op->in.name) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      op->in.sid = user_sid;
+   }
+
+   hnd->status = rpccli_lsa_remove_account_rights( pipe_hnd, mem_ctx, op->in.pol, *(op->in.sid), False, op->in.num_privs, (const char **)op->in.priv_names);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaClearPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaClearPrivileges *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   DOM_SID *user_sid = NULL;
+   uint32  *type     = NULL;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.sid && !op->in.name) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      op->in.sid = user_sid;
+   }
+
+   hnd->status = rpccli_lsa_remove_account_rights( pipe_hnd, mem_ctx, op->in.pol, *(op->in.sid), True, 0, NULL);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaSetPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAddPrivileges *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   DOM_SID *user_sid = NULL;
+   uint32  *type     = NULL;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol || !op->in.priv_names) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.sid && !op->in.name) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = rpccli_lsa_lookup_names( pipe_hnd, mem_ctx, op->in.pol, 1, (const char **)&(op->in.name), &user_sid, &type);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      op->in.sid = user_sid;
+   }
+
+   /*first remove all privileges*/
+   hnd->status = rpccli_lsa_remove_account_rights( pipe_hnd, mem_ctx, op->in.pol, *(op->in.sid), True, 0, NULL);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   hnd->status = rpccli_lsa_add_account_rights( pipe_hnd, mem_ctx, op->in.pol, *(op->in.sid), op->in.num_privs, (const char **)op->in.priv_names);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_LsaGetSecurityObject(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetSecurityObject *op) {
+   struct rpc_pipe_client *pipe_hnd = NULL;
+
+   /*this is taken from rpcclient/cmd_lsarpc.c*/
+   uint16 info_level = 4;
+
+   SEC_DESC_BUF *sec_out = NULL;
+
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_LSARPC]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.pol) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   pipe_hnd = cac_GetPipe(hnd, PI_LSARPC);
+   if(!pipe_hnd) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = rpccli_lsa_query_secobj( pipe_hnd, mem_ctx, op->in.pol, info_level, &sec_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.sec = sec_out;
+
+   return CAC_FAILURE;
+}