r10003: in the rush for 10k, I forgot to run add the rest of Chris' libmsrpc files
authorGerald Carter <jerry@samba.org>
Sat, 3 Sep 2005 16:55:45 +0000 (16:55 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:03:30 +0000 (11:03 -0500)
48 files changed:
examples/libmsrpc/cacusermgr/Makefile [new file with mode: 0644]
examples/libmsrpc/cacusermgr/cacusermgr.c [new file with mode: 0644]
examples/libmsrpc/cacusermgr/cacusermgr.h [new file with mode: 0644]
examples/libmsrpc/cacusermgr/mgr_group.c [new file with mode: 0644]
examples/libmsrpc/cacusermgr/mgr_user.c [new file with mode: 0644]
examples/libmsrpc/cacusermgr/util.c [new file with mode: 0644]
examples/libmsrpc/test/Makefile [new file with mode: 0644]
examples/libmsrpc/test/README [new file with mode: 0644]
examples/libmsrpc/test/lsa/ear.c [new file with mode: 0644]
examples/libmsrpc/test/lsa/lsaenum.c [new file with mode: 0644]
examples/libmsrpc/test/lsa/lsaenumprivs.c [new file with mode: 0644]
examples/libmsrpc/test/lsa/lsapol.c [new file with mode: 0644]
examples/libmsrpc/test/lsa/lsapriv.c [new file with mode: 0644]
examples/libmsrpc/test/lsa/lsaq.c [new file with mode: 0644]
examples/libmsrpc/test/lsa/lsatrust.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regdelete.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regkey.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regkeycreate.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regkeyenum.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regopen.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regopenkey.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regqueryval.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regsetval.c [new file with mode: 0644]
examples/libmsrpc/test/reg/regvalenum.c [new file with mode: 0644]
examples/libmsrpc/test/reg/security.c [new file with mode: 0644]
examples/libmsrpc/test/reg/shutdown.c [new file with mode: 0644]
examples/libmsrpc/test/sam/adduser.c [new file with mode: 0644]
examples/libmsrpc/test/sam/disable.c [new file with mode: 0644]
examples/libmsrpc/test/sam/dominfo.c [new file with mode: 0644]
examples/libmsrpc/test/sam/enable.c [new file with mode: 0644]
examples/libmsrpc/test/sam/samenum.c [new file with mode: 0644]
examples/libmsrpc/test/sam/samgroup.c [new file with mode: 0644]
examples/libmsrpc/test/sam/samlookup.c [new file with mode: 0644]
examples/libmsrpc/test/sam/samuser.c [new file with mode: 0644]
examples/libmsrpc/test/smbc_test/smbc.c [new file with mode: 0644]
examples/libmsrpc/test/svcctl/svc.c [new file with mode: 0644]
examples/libmsrpc/test/test_util.c [new file with mode: 0644]
examples/libmsrpc/test/test_util.h [new file with mode: 0644]
source/include/libmsrpc.h [new file with mode: 0644]
source/include/libmsrpc_internal.h [new file with mode: 0644]
source/libmsrpc/Doxyfile [new file with mode: 0644]
source/libmsrpc/cac_lsarpc.c [new file with mode: 0644]
source/libmsrpc/cac_samr.c [new file with mode: 0644]
source/libmsrpc/cac_svcctl.c [new file with mode: 0644]
source/libmsrpc/cac_winreg.c [new file with mode: 0644]
source/libmsrpc/libmsrpc.c [new file with mode: 0644]
source/libmsrpc/libmsrpc.po [new file with mode: 0644]
source/libmsrpc/libmsrpc_internal.c [new file with mode: 0644]

diff --git a/examples/libmsrpc/cacusermgr/Makefile b/examples/libmsrpc/cacusermgr/Makefile
new file mode 100644 (file)
index 0000000..ab8bea4
--- /dev/null
@@ -0,0 +1,22 @@
+CC=gcc
+INCLUDES= -I`pwd` -I../../../source/ -I../../../source/include -I../../../source/ubiqx
+
+DEFS= -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+
+CFLAGS= -g -Wall -ansi $(INCLUDES) 
+
+OBJ= util.o mgr_group.o mgr_user.o
+
+LDFLAGS=-L. -L../../bin/ 
+LIBS=../../../source/bin/libmsrpc.so
+
+all: cacusermgr
+
+cacusermgr: cacusermgr.o $(OBJ)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(OBJ) $(LIBS)
+
+.c.o:
+       $(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+       rm -f *.o cacusermgr
diff --git a/examples/libmsrpc/cacusermgr/cacusermgr.c b/examples/libmsrpc/cacusermgr/cacusermgr.c
new file mode 100644 (file)
index 0000000..77dd250
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Unix SMB/CIFS implementation. 
+ * cacusermgr main implementation.
+ *
+ * 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 "cacusermgr.h"
+
+#define DEFAULT_MENU_LINES 15
+
+
+void create_menu(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd) {
+   struct SamCreateUser  cu;
+   struct SamCreateGroup cg;
+
+   fstring in;
+   fstring tmp;
+
+   if(!hnd || !mem_ctx || !dom_hnd) {
+      printf("No Handle to SAM.\n");
+      return;
+   }
+
+   /*the menu*/
+   in[0] = '\0';
+   while(in[0] != 'c' && in[0] != 'C' && in[0] != 'q' && in[0] != 'Q') {
+      printf("\n");
+      printf("[u] Create User\n");
+      printf("[g] Create Group\n");
+      printf("[m] Create Machine Account\n");
+      printf("[c] Cancel\n\n");
+
+      printf("Command: ");
+      mgr_getline(in);
+
+      printf("\n");
+
+      switch(in[0]) {
+         case 'u': /*create user*/
+         case 'U':
+            ZERO_STRUCT(cu);
+            cu.in.dom_hnd = dom_hnd;
+            cu.in.acb_mask = ACB_NORMAL;
+
+            printf("Enter name: ");
+            mgr_getline(tmp);
+            cu.in.name = talloc_strdup(mem_ctx, tmp);
+
+            if(!cac_SamCreateUser(hnd, mem_ctx, &cu)) {
+               printerr("Could not create user.", hnd->status);
+            }
+            else {
+               user_menu(hnd, mem_ctx, dom_hnd, cu.out.user_hnd);
+            }
+
+            /*this will break the loop and send us back to the main menu*/
+            in[0] = 'c';
+            break;
+
+         case 'g': /*create group*/
+         case 'G':
+            ZERO_STRUCT(cg);
+            cg.in.dom_hnd = dom_hnd;
+            cg.in.access  = MAXIMUM_ALLOWED_ACCESS;
+
+            printf("Enter name: ");
+            mgr_getline(tmp);
+            cg.in.name = talloc_strdup(mem_ctx, tmp);
+
+            if(!cac_SamCreateGroup(hnd, mem_ctx, &cg)) {
+               printerr("Could not create group.", hnd->status);
+            }
+            else {
+               group_menu(hnd, mem_ctx, dom_hnd, cg.out.group_hnd);
+            }
+
+            /*this will break the loop and send us back to the main menu*/
+            in[0] = 'c';
+            break;
+
+         case 'm': /*create machine account*/
+         case 'M':
+            ZERO_STRUCT(cu);
+            cu.in.dom_hnd  = dom_hnd;
+            cu.in.acb_mask = ACB_WSTRUST;
+
+            printf("Enter machine name: ");
+            mgr_getline(tmp);
+
+            /*make sure we have a $ on the end*/
+            if(tmp[strlen(tmp) - 1] != '$')
+               cu.in.name = talloc_asprintf(mem_ctx, "%s$", tmp);
+            else
+               cu.in.name = talloc_strdup(mem_ctx, tmp);
+
+            strlower_m(cu.in.name);
+
+            printf("Creating account: %s\n", cu.in.name);
+
+            if(!cac_SamCreateUser(hnd, mem_ctx, &cu)) {
+               printerr("Could not create account.", hnd->status);
+            }
+            else {
+               user_menu(hnd, mem_ctx, dom_hnd, cu.out.user_hnd);
+            }
+
+            /*this will break the loop and send us back to the main menu*/
+            in[0] = 'c';
+            break;
+
+         case 'c': /*cancel*/
+         case 'C':
+         case 'q':
+         case 'Q':
+            /*do nothing*/
+            break;
+
+         default:
+            printf("Invalid option\n");
+      }
+   }
+
+   return;
+}
+
+void main_menu(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd) {
+   fstring in;
+   
+   uint32 rid_type = 0;
+
+   struct SamOpenUser   openu;
+   struct SamOpenGroup  openg;
+   struct SamEnumUsers  enumu;
+   struct SamEnumGroups enumg;
+   struct SamFlush      flush;
+
+   char *name = NULL;
+   uint32 rid = 0;
+
+   if(!hnd || !mem_ctx || !dom_hnd) {
+      printf("No handle to SAM.\n");
+      return;
+   }
+
+   /*initialize this here and don't worry about it later*/
+   ZERO_STRUCT(flush);
+   flush.in.dom_hnd = dom_hnd;
+
+   in[0] = '\0';
+
+   /*handle the menu and commands*/
+   while(in[0] != 'q' && in[0] != 'Q') {
+      printf("\n");
+
+      printf("[o] Open User or Group\n");
+      printf("[c] Create Account or Group\n");
+      printf("[u] List Users\n");
+      printf("[g] List Groups\n");
+      printf("[m] List Machine Accounts\n");
+      printf("[q] Quit\n\n");
+
+      printf("Command: ");
+
+      mgr_getline(in);
+
+      printf("\n");
+
+      switch(in[0]) {
+         case 'o': /*open user or group*/
+         case 'O':
+            printf("Enter RID or Name: ");
+            rid_type = rid_or_name(hnd, mem_ctx, dom_hnd, &rid, &name);
+
+            if(rid_type == CAC_USER_RID) {
+               ZERO_STRUCT(openu);
+               openu.in.dom_hnd = dom_hnd;
+               openu.in.rid     = rid;
+               openu.in.access  = MAXIMUM_ALLOWED_ACCESS;
+
+               if(!cac_SamOpenUser(hnd, mem_ctx, &openu))
+                  printerr("Could not open user.", hnd->status);
+               else {
+                  user_menu(hnd, mem_ctx, dom_hnd, openu.out.user_hnd);
+
+                  if(!cac_SamFlush(hnd, mem_ctx, &flush)) {
+                     printerr("Lost handle while flushing SAM.", hnd->status);
+                     /*we want to quit*/
+                     in[0] = 'q';
+                  }
+               }
+            }
+            else if(rid_type == CAC_GROUP_RID) {
+               ZERO_STRUCT(openg);
+               openg.in.dom_hnd = dom_hnd;
+               openg.in.rid     = rid;
+               openg.in.access  = MAXIMUM_ALLOWED_ACCESS;
+
+               if(!cac_SamOpenGroup(hnd, mem_ctx, &openg))
+                  printerr("Could not open group.", hnd->status);
+               else {
+                  group_menu(hnd, mem_ctx, dom_hnd, openg.out.group_hnd);
+
+                  if(!cac_SamFlush(hnd, mem_ctx, &flush)) {
+                     printerr("Lost handle while flushing SAM.", hnd->status);
+                     /*we want to quit*/
+                     in[0] = 'q';
+                  }
+               }
+            }
+            else {
+               printf("Unknown RID/Name.\n");
+            }
+               
+            break;
+
+         case 'c': /*create account/group*/
+         case 'C':
+            create_menu(hnd, mem_ctx, dom_hnd);
+            if(!cac_SamFlush(hnd, mem_ctx, &flush)) {
+               printerr("Lost handle while flushing SAM.", hnd->status);
+               /*we want to quit*/
+               in[0] = 'q';
+            }
+            break;
+
+         case 'u': /*list users*/
+         case 'U':
+            ZERO_STRUCT(enumu);
+            enumu.in.dom_hnd = dom_hnd;
+            enumu.in.acb_mask = ACB_NORMAL;
+
+            printf("Users:\n");
+            while(cac_SamEnumUsers(hnd, mem_ctx, &enumu)) {
+               print_rid_list(enumu.out.rids, enumu.out.names, enumu.out.num_users);
+            }
+            if(CAC_OP_FAILED(hnd->status))
+               printerr("Error occured while enumerating users.", hnd->status);
+            break;
+
+         case 'g': /*list groups*/
+         case 'G':
+            ZERO_STRUCT(enumg);
+            enumg.in.dom_hnd = dom_hnd;
+
+            while(cac_SamEnumGroups(hnd, mem_ctx, &enumg)) {
+               print_rid_list( enumg.out.rids, enumg.out.names, enumg.out.num_groups);
+            }
+
+            if(CAC_OP_FAILED(hnd->status))
+               printerr("Error occured while enumerating groups.", hnd->status);
+            break;
+
+         case 'm': /*list machine accounts*/
+         case 'M':
+            ZERO_STRUCT(enumu);
+            enumu.in.dom_hnd = dom_hnd;
+            enumu.in.acb_mask = ACB_WSTRUST;
+
+            printf("Users:\n");
+            while(cac_SamEnumUsers(hnd, mem_ctx, &enumu)) {
+               print_rid_list( enumu.out.rids, enumu.out.names, enumu.out.num_users);
+            }
+            if(CAC_OP_FAILED(hnd->status))
+               printerr("Error occured while enumerating accounts.", hnd->status);
+            break;
+
+         case 'q': /*quit*/
+         case 'Q':
+            /*just do nothing*/
+            break;
+
+         default:
+            printf("Invalid Command.\n");
+      }
+   }
+}
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   struct SamOpenDomain sod;
+
+   mem_ctx = talloc_init("cacusermgr");
+   if(!mem_ctx) {
+      printf("Could not initialize Talloc Context\n");
+      exit(-1);
+   }
+
+   /**first initialize the server handle with what we have*/
+   hnd = cac_NewServerHandle(True);
+   if(!hnd) {
+      printf("Could not create server handle\n");
+      exit(-1);
+   }
+
+   /*fill in the blanks*/
+   if(!process_cmd_line(hnd, mem_ctx, argc, argv))
+      usage();
+
+   if(!cac_Connect(hnd, NULL)) {
+      printf("Could not connect to server %s. %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   /*open the domain sam*/
+   ZERO_STRUCT(sod);
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS;
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      printf("Could not open handle to domain SAM. %s\n", nt_errstr(hnd->status));
+      goto cleanup;
+   }
+
+   main_menu(hnd, mem_ctx, sod.out.dom_hnd);
+
+cleanup:
+
+   if(sod.out.dom_hnd)
+      cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   if(sod.out.sam)
+      cac_SamClose(hnd, mem_ctx, sod.out.sam);
+
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/cacusermgr/cacusermgr.h b/examples/libmsrpc/cacusermgr/cacusermgr.h
new file mode 100644 (file)
index 0000000..01dbb60
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Unix SMB/CIFS implementation. 
+ * cacusermgr definitions and includes.
+ *
+ * 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.  */
+
+#ifndef CACUSERMGR_H_
+#define CACUSERMGR_H_
+
+#include "libmsrpc.h"
+#include "includes.h"
+
+/*used for the simple pager - mgr_page()*/
+#define DEFAULT_SCREEN_LINES 20 
+
+/**************
+ * prototypes *
+ **************/
+
+/*util.c*/
+void usage();
+int process_cmd_line(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, int argc, char **argv);
+void mgr_getline(fstring line);
+void mgr_page(uint32 line_count);
+uint32 rid_or_name(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd, uint32 *rid, char **name);
+char *get_new_password(TALLOC_CTX *mem_ctx);
+void printerr(const char *msg, NTSTATUS status);
+void print_rid_list(uint32 *rids, char **names, uint32 num_rids);
+void print_lookup_records(CacLookupRidsRecord *map, uint32 num_rids);
+int list_groups(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd);
+void list_privs(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, CacUserInfo *info);
+void add_privs(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, CacUserInfo *info);
+void list_users(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd);
+
+void mgr_GetAuthDataFn(const char * pServer,
+                 const char * pShare,
+                 char * pWorkgroup,
+                 int maxLenWorkgroup,
+                 char * pUsername,
+                 int maxLenUsername,
+                 char * pPassword,
+                 int maxLenPassword);
+
+
+/*mgr_group.c*/
+void group_menu(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd, POLICY_HND *group_hnd);
+
+/*mgr_user.c*/
+void user_menu(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd, POLICY_HND *user_hnd);
+
+#endif /*CACUSERMGR_H_*/
diff --git a/examples/libmsrpc/cacusermgr/mgr_group.c b/examples/libmsrpc/cacusermgr/mgr_group.c
new file mode 100644 (file)
index 0000000..a936433
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Unix SMB/CIFS implementation. 
+ * cacusermgr group implementation.
+ *
+ * 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 "cacusermgr.h"
+
+CacGroupInfo *get_group_info(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd) {
+   struct SamGetGroupInfo getinfo;
+
+   if(!hnd || !mem_ctx ||!group_hnd)
+      return NULL;
+
+   ZERO_STRUCT(getinfo);
+   getinfo.in.group_hnd = group_hnd;
+
+   if(!cac_SamGetGroupInfo(hnd, mem_ctx, &getinfo)) 
+      printerr("Could not get group info.", hnd->status);
+
+   return getinfo.out.info;
+}
+
+void print_group_info(CacGroupInfo *info) {
+   if(!info)
+      return;
+
+   printf(" Group Name        : %s\n", info->name);
+   printf(" Description       : %s\n", info->description);
+   printf(" Number of Members : %d\n", info->num_members);
+}
+
+CacGroupInfo *modify_group_info(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd) {
+   struct SamSetGroupInfo setinfo;
+   CacGroupInfo *info = NULL;
+   fstring tmp;
+
+   info = get_group_info(hnd, mem_ctx, group_hnd);
+
+   if(!info)
+      return NULL;
+
+   printf("Description [%s]: ", info->description);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->description = talloc_strdup(mem_ctx, tmp);
+
+   ZERO_STRUCT(setinfo);
+   setinfo.in.group_hnd = group_hnd;
+   setinfo.in.info = info;
+
+   if(!cac_SamSetGroupInfo(hnd, mem_ctx, &setinfo)) {
+      printerr("Could not set info.", hnd->status);
+      info = NULL;
+   }
+
+   return info;
+}
+
+void group_menu(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd, POLICY_HND *group_hnd) {
+   CacGroupInfo *info = NULL;
+   int rid_type = 0;
+
+   fstring in;
+
+   char *buf;
+
+   struct SamGetGroupMembers getmem;
+   struct SamGetNamesFromRids getnames;
+   struct SamAddGroupMember add;
+   struct SamRemoveGroupMember del;
+   info = get_group_info(hnd, mem_ctx, group_hnd);
+
+   printf("\n");
+   print_group_info(info);
+
+   while(in[0] != 'b' && in[0] != 'B' && in[0] != 'q' && in[0] != 'Q') {
+      printf("\n");
+      printf("[m] List Group Members\n");
+      printf("[a] Add User To Group\n");
+      printf("[r] Remove User From Group\n");
+      printf("[l] List Users\n");
+      printf("[v] View Group Info\n");
+      printf("[d] Set Group Description\n");
+      printf("[x] Delete Group\n");
+      printf("[b] Back\n\n");
+      
+      printf("Command: ");
+      mgr_getline(in);
+      
+      printf("\n");
+
+      switch(in[0]) {
+         case 'a': /*add member to group*/
+         case 'A':
+            ZERO_STRUCT(add);
+            add.in.group_hnd = group_hnd;
+
+            printf("Enter RID or Name: ");
+            rid_type = rid_or_name(hnd, mem_ctx, dom_hnd, &add.in.rid, &buf);
+
+            if(rid_type != CAC_USER_RID) {
+               printf("Invalid User.\n");
+               break;
+            }
+
+            if(!cac_SamAddGroupMember(hnd, mem_ctx, &add)) {
+               printerr("Could not add user to group.", hnd->status);
+            }
+            break;
+
+         case 'r': /*remove user from group*/
+         case 'R':
+            ZERO_STRUCT(del);
+            del.in.group_hnd = group_hnd;
+
+            printf("Enter RID or Name: ");
+            rid_type = rid_or_name(hnd, mem_ctx, dom_hnd, &del.in.rid, &buf);
+
+            if(rid_type != CAC_USER_RID) {
+               printf("Invalid User.\n");
+               break;
+            }
+
+            if(!cac_SamRemoveGroupMember(hnd, mem_ctx, &del)) {
+               printerr("Could not remove use from group.", hnd->status);
+            }
+            break;
+
+         case 'l': /*list users*/
+         case 'L':
+            list_users(hnd, mem_ctx, dom_hnd);
+            break;
+
+         case 'm': /*list members*/
+         case 'M':
+            ZERO_STRUCT(getmem);
+            getmem.in.group_hnd = group_hnd;
+
+            if(!cac_SamGetGroupMembers(hnd, mem_ctx, &getmem)) {
+               printerr("Could not get members.", hnd->status);
+               break;
+            }
+
+            ZERO_STRUCT(getnames);
+            getnames.in.dom_hnd = dom_hnd;
+            getnames.in.rids = getmem.out.rids;
+            getnames.in.num_rids = getmem.out.num_members;
+
+            if(!cac_SamGetNamesFromRids(hnd, mem_ctx, &getnames)) {
+               printerr("Could not lookup names.", hnd->status);
+               break;
+            }
+
+            printf("Group has %d members:\n", getnames.out.num_names);
+            print_lookup_records(getnames.out.map, getnames.out.num_names);
+
+            break;
+
+         case 'd': /*set description*/
+         case 'D':
+            info = modify_group_info(hnd, mem_ctx, group_hnd);
+
+            if(info)
+               printf("Set Group Info.\n");
+            break;
+
+         case 'v': /*view info*/
+         case 'V':
+            info = get_group_info(hnd, mem_ctx, group_hnd);
+            print_group_info(info);
+            break;
+
+         case 'x': /*delete group*/
+         case 'X': 
+            if(!cac_SamDeleteGroup(hnd, mem_ctx, group_hnd))
+               printerr("Could Not Delete Group.", hnd->status);
+
+            /*we want to go back to the main menu*/
+            in[0] = 'b';
+            break;
+
+         case 'b': /*back*/
+         case 'B':
+         case 'q':
+         case 'Q':
+            break;
+
+         default:
+            printf("Invalid Command.\n");
+      }
+   }
+
+   cac_SamClose(hnd, mem_ctx, group_hnd);
+}
diff --git a/examples/libmsrpc/cacusermgr/mgr_user.c b/examples/libmsrpc/cacusermgr/mgr_user.c
new file mode 100644 (file)
index 0000000..7e2e564
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Unix SMB/CIFS implementation. 
+ * cacusermgr user implementation.
+ *
+ * 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 "cacusermgr.h"
+
+void print_user_info(CacUserInfo *info) {
+   printf("\n");
+   printf(" User Name      : %s\n", info->username);
+   printf(" Full Name      : %s\n", info->full_name);
+   printf(" Home Dir       : %s\n", info->home_dir);
+   printf(" Home Drive     : %s\n", info->home_drive);
+   printf(" Profile Path   : %s\n", info->profile_path);
+   printf(" Logon Script   : %s\n", info->logon_script);
+   printf(" Description    : %s\n", info->description);
+   printf(" Workstations   : %s\n", info->workstations);
+   printf(" Remote Dial    : %s\n", info->dial);
+
+   printf(" Logon Time     : %s\n", http_timestring(info->logon_time));
+   printf(" Logoff Time    : %s\n", http_timestring(info->logoff_time));
+   printf(" Kickoff Time   : %s\n", http_timestring(info->kickoff_time));
+   printf(" Pass last set  : %s\n", http_timestring(info->pass_last_set_time));
+   printf(" Pass can set   : %s\n", http_timestring(info->pass_can_change_time));
+   printf(" Pass must set  : %s\n", http_timestring(info->pass_must_change_time));
+
+   printf(" User RID       : 0x%x\n", info->rid);
+   printf(" Group RID      : 0x%x\n", info->group_rid);
+   printf(" User Type      : ");
+
+   if(info->acb_mask & ACB_NORMAL)
+      printf("Normal User\n");
+   else if(info->acb_mask & ACB_TEMPDUP)
+      printf("Temporary Duplicate Account\n");
+   else if(info->acb_mask & ACB_DOMTRUST)
+      printf("Inter-Domain Trust Account\n");
+   else if(info->acb_mask & ACB_WSTRUST)
+      printf("Workstation Trust Account\n");
+   else if(info->acb_mask & ACB_SVRTRUST)
+      printf("Server Trust Account\n");
+   else
+      printf("\n");
+
+   printf(" Disabled       : %s\n", (info->acb_mask & ACB_DISABLED) ? "Yes" : "No");
+   printf(" Locked         : %s\n", (info->acb_mask & ACB_AUTOLOCK) ? "Yes" : "No");
+   printf(" Pass Expires   : %s\n", (info->acb_mask & ACB_PWNOEXP) ? "No" : "Yes");
+   printf(" Pass Required  : %s\n", (info->acb_mask & ACB_PWNOTREQ) ? "No" : "Yes");
+
+}
+
+CacUserInfo *modify_user_info(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd) {
+   CacUserInfo *info = NULL;
+   fstring tmp;
+
+   struct SamGetUserInfo getinfo;
+   struct SamSetUserInfo setinfo;
+
+   ZERO_STRUCT(getinfo);
+   ZERO_STRUCT(setinfo);
+
+   getinfo.in.user_hnd = user_hnd;
+
+   if(!cac_SamGetUserInfo(hnd, mem_ctx, &getinfo)) {
+      printerr("Could not get user info.", hnd->status);
+      return NULL;
+   }
+
+   info = getinfo.out.info;
+
+   printf("\n");
+   printf(" User Name [%s]: ", info->username);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->username = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Full Name [%s]: ", info->full_name);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->full_name = talloc_strdup(mem_ctx, tmp);
+   
+   printf(" Description  [%s]: ", info->description);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->description = talloc_strdup(mem_ctx, tmp);
+   
+   printf(" Home Dir  [%s]: ", info->home_dir);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->home_dir = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Home Drive [%s]: ", info->home_drive);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->home_drive = talloc_strdup(mem_ctx, tmp);
+   
+   printf(" Profile Path [%s]: ", info->profile_path);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->profile_path = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Logon Script [%s]: ", info->logon_script);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->logon_script = talloc_strdup(mem_ctx, tmp);
+   
+   printf(" Workstations [%s]: ", info->workstations);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->workstations = talloc_strdup(mem_ctx, tmp);
+   
+   printf(" Remote Dial [%s]: ", info->dial);
+   mgr_getline(tmp);
+   if(tmp[0] != '\0')
+      info->dial = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Disabled [%s] (y/n): ", (info->acb_mask & ACB_DISABLED) ? "Yes" : "No");
+   mgr_getline(tmp);
+   if(tmp[0] == 'y' || tmp[0] == 'Y')
+      info->acb_mask |= ACB_DISABLED;
+   else if(tmp[0] == 'n' || tmp[0] == 'N')
+      info->acb_mask ^= (info->acb_mask & ACB_DISABLED) ? ACB_DISABLED : 0x0;
+      
+   printf(" Pass Expires [%s] (y/n): ", (info->acb_mask & ACB_PWNOEXP) ? "No" : "Yes");
+   mgr_getline(tmp);
+   if(tmp[0] == 'n' || tmp[0] == 'N')
+      info->acb_mask |= ACB_PWNOEXP;
+   else if(tmp[0] == 'y' || tmp[0] == 'Y')
+      info->acb_mask ^= (info->acb_mask & ACB_PWNOEXP) ? ACB_PWNOEXP : 0x0;
+
+   printf(" Pass Required [%s] (y/n): ", (info->acb_mask & ACB_PWNOTREQ) ? "No" : "Yes");
+   mgr_getline(tmp);
+   if(tmp[0] == 'n' || tmp[0] == 'N')
+      info->acb_mask |= ACB_PWNOTREQ;
+   else if(tmp[0] == 'y' || tmp[0] == 'Y')
+      info->acb_mask ^= (info->acb_mask & ACB_PWNOTREQ) ? ACB_PWNOTREQ : 0x0;
+
+   setinfo.in.user_hnd = user_hnd;
+   setinfo.in.info     = info;
+
+   if(!cac_SamSetUserInfo(hnd, mem_ctx, &setinfo)) {
+      printerr("Could not set user info.", hnd->status);
+   }
+
+   return info;
+}
+
+void add_user_to_group(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, CacUserInfo *info, POLICY_HND *dom_hnd) {
+   int rid_type = 0;
+
+   char *tmp = NULL;
+
+   struct SamOpenGroup og;
+   struct SamAddGroupMember add;
+
+   ZERO_STRUCT(og);
+   ZERO_STRUCT(add);
+   
+   printf("Group RID or Name:");
+
+   og.in.dom_hnd = dom_hnd;
+   og.in.access = MAXIMUM_ALLOWED_ACCESS;
+   rid_type = rid_or_name(hnd, mem_ctx, dom_hnd, &og.in.rid, &tmp);
+
+   if(!cac_SamOpenGroup(hnd, mem_ctx, &og)) {
+      printerr("Could not open group.", hnd->status);
+      return;
+   }
+
+   add.in.group_hnd = og.out.group_hnd;
+   add.in.rid = info->rid;
+
+   if(!cac_SamAddGroupMember(hnd, mem_ctx, &add)) {
+      printerr("Could not add user to group.", hnd->status);
+   }
+
+   cac_SamClose(hnd, mem_ctx, og.out.group_hnd);
+}
+
+void remove_user_from_group(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, CacUserInfo *info, POLICY_HND *dom_hnd) {
+   int rid_type = 0;
+
+   char *tmp = NULL;
+
+   struct SamOpenGroup og;
+   struct SamRemoveGroupMember del;
+
+   ZERO_STRUCT(og);
+   ZERO_STRUCT(del);
+   
+   printf("Group RID or Name:");
+
+   og.in.dom_hnd = dom_hnd;
+   og.in.access = MAXIMUM_ALLOWED_ACCESS;
+   rid_type = rid_or_name(hnd, mem_ctx, dom_hnd, &og.in.rid, &tmp);
+
+   if(!cac_SamOpenGroup(hnd, mem_ctx, &og)) {
+      printerr("Could not open group.", hnd->status);
+      return;
+   }
+
+   del.in.group_hnd = og.out.group_hnd;
+   del.in.rid = info->rid;
+
+   if(!cac_SamRemoveGroupMember(hnd, mem_ctx, &del)) {
+      printerr("Could not add user to group.", hnd->status);
+   }
+
+   cac_SamClose(hnd, mem_ctx, og.out.group_hnd);
+}
+
+void user_menu(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd, POLICY_HND *user_hnd) {
+   fstring in;
+
+   struct SamGetUserInfo      getinfo;
+   struct SamSetPassword      setpass;
+   struct SamGetGroupsForUser groups;
+   struct SamGetNamesFromRids gnfr;
+
+   CacUserInfo *info = NULL;
+
+   if(!hnd || !mem_ctx || !user_hnd) {
+      printf("Must open user.\n");
+      return;
+   }
+
+   /*get the userinfo and print it out*/
+   ZERO_STRUCT(getinfo);
+   getinfo.in.user_hnd = user_hnd;
+
+   if(!cac_SamGetUserInfo(hnd, mem_ctx, &getinfo)) {
+      printerr("Could not get info.", hnd->status);
+      info = NULL;
+   }
+   else {
+      info = getinfo.out.info;
+      print_user_info(info);
+   }
+
+   /*now deal with the menu*/
+   in[0] = '\0';
+   while(in[0] != 'b' && in[0] != 'B' && in[0] != 'q' && in[0] != 'Q') {
+      printf("\n");
+      printf("[s] Set Password\n");
+
+      if(info && (info->acb_mask & ACB_DISABLED))
+         printf("[e] Enable User\n");
+      else if(info)
+         printf("[d] Disable User\n");
+
+      printf("[v] View User Info\n");
+      printf("[m] Modify User Info\n");
+      printf("[x] Delete User\n\n");
+
+      printf("[g] List Group Membership\n");
+      printf("[a] Add User To Group\n");
+      printf("[l] List Domain Groups\n");
+      printf("[r] Remove User From Group\n\n");
+
+      printf("[b] Back\n\n");
+
+      printf("Command: ");
+      mgr_getline(in);
+
+      printf("\n");
+
+      switch(in[0]) {
+         case 'g': /*list group membership*/
+         case 'G': 
+            ZERO_STRUCT(groups);
+            groups.in.user_hnd = user_hnd;
+
+            if(!cac_SamGetGroupsForUser(hnd, mem_ctx, &groups)) {
+               printerr("Could not get groups.", hnd->status);
+               break;
+            }
+
+            ZERO_STRUCT(gnfr);
+            gnfr.in.dom_hnd = dom_hnd;
+            gnfr.in.rids = groups.out.rids;
+            gnfr.in.num_rids = groups.out.num_groups;
+
+            if(!cac_SamGetNamesFromRids(hnd, mem_ctx, &gnfr)) {
+               printerr("Could not map RIDs to names.", hnd->status);
+               break;
+            }
+
+            print_lookup_records(gnfr.out.map, gnfr.out.num_names);
+
+            break;
+         case 's': /*reset password*/
+         case 'S':
+            ZERO_STRUCT(setpass);
+            setpass.in.user_hnd = user_hnd;
+            setpass.in.password = get_new_password(mem_ctx);
+            
+            if(!setpass.in.password) {
+               printf("Out of memory.\n");
+               break;
+            }
+
+            if(!cac_SamSetPassword(hnd, mem_ctx, &setpass)) {
+               printerr("Could not set password.", hnd->status);
+            }
+            else {
+               printf("Reset password.\n");
+            }
+            break;
+
+         case 'e': /*enable user*/
+         case 'E': 
+            if(info && !(info->acb_mask & ACB_DISABLED))
+               break;
+
+            if(!cac_SamEnableUser(hnd, mem_ctx, user_hnd)) {
+               printerr("Could not enable user.", hnd->status);
+            }
+            else {
+               printf("Enabled User.\n");
+               /*toggle the disabled ACB bit in our local copy of the info*/
+               info->acb_mask ^= ACB_DISABLED;
+            }
+            break;
+
+         case 'd': /*disable user*/
+         case 'D':
+            if(info && (info->acb_mask & ACB_DISABLED))
+               break;
+
+            if(!cac_SamDisableUser(hnd, mem_ctx, user_hnd)) {
+               printerr("Could not disable user.", hnd->status);
+            }
+            else {
+               printf("Disabled User.\n");
+               /*toggle the disabled ACB bit in our local copy of the info*/
+               info->acb_mask ^= ACB_DISABLED;
+            }
+            break;
+
+         case 'v': /*view user info*/
+         case 'V':
+            ZERO_STRUCT(getinfo);
+            getinfo.in.user_hnd = user_hnd;
+
+            if(!cac_SamGetUserInfo(hnd, mem_ctx, &getinfo)) {
+               printerr("Could not get info.", hnd->status);
+               info = NULL;
+            }
+            else {
+               info = getinfo.out.info;
+               print_user_info(info);
+            }
+
+            break;
+
+         case 'm': /*modify user info*/
+         case 'M':
+            info = modify_user_info(hnd, mem_ctx, user_hnd);
+
+            if(info)
+               printf("Updated user info.\n");
+            break;
+
+         case 'l': /*list domain groups*/
+         case 'L':
+            list_groups(hnd, mem_ctx, dom_hnd);
+            break;
+
+         case 'a': /*add user to group*/
+         case 'A':
+            add_user_to_group(hnd, mem_ctx, info, dom_hnd);
+            break;
+
+         case 'r': /*remove user from group*/
+         case 'R':
+            remove_user_from_group(hnd, mem_ctx, info, dom_hnd);
+            break;
+            
+         case 'x': /*delete user*/
+         case 'X':
+            if(!cac_SamDeleteUser(hnd, mem_ctx, user_hnd))
+               printerr("Could not delete user.", hnd->status);
+
+            /*we want to go back to the main menu*/
+            in[0] = 'b';
+            break;
+
+         case 'b': /*back*/
+         case 'B':
+         case 'q':
+         case 'Q':
+            /*do nothing*/
+            break;
+            
+         default:
+            printf("Invalid command.\n");
+      }
+   }
+
+   /*close the user before returning*/
+   cac_SamClose(hnd, mem_ctx, user_hnd);
+}
diff --git a/examples/libmsrpc/cacusermgr/util.c b/examples/libmsrpc/cacusermgr/util.c
new file mode 100644 (file)
index 0000000..1629911
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Unix SMB/CIFS implementation. 
+ * cacusermgr utility functions.
+ *
+ * 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 "cacusermgr.h"
+
+/*prints usage and quits*/
+void usage() {
+   printf("Usage:\n");
+   printf("    cacusermgr [options] server\n\n");
+   printf("options:\n");
+   printf("   -u USERNAME        Username to login with\n");
+   printf("   -d/-w DOMAIN       Domain name\n");
+   printf("   -D LEVEL           Debug level\n");
+   printf("   -h                 Print this message\n");
+
+   exit(1);
+}
+
+/*initializes values in the server handle from the command line returns 0 if there is a problem, non-zero if everything is ok*/
+int process_cmd_line(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, int argc, char **argv) {
+   char op;
+
+   if(!hnd || !mem_ctx || !argc)
+      return 0;
+
+   while( (op = getopt(argc, argv, "u:U:d:w:W:D:h")) != -1) {
+      switch(op) {
+         case 'u': /*username*/
+         case 'U': 
+            if(optarg)
+               strncpy(hnd->username, optarg, sizeof(fstring));
+            else
+               usage();
+            break;
+
+         case 'd': /*domain name*/
+         case 'w':
+         case 'W':
+            if(optarg)
+               strncpy(hnd->domain, optarg, sizeof(fstring));
+            else
+               usage();
+            break;
+
+         case 'D': /*debug level*/
+            if(optarg)
+               hnd->debug = atoi(optarg);
+            else
+               usage();
+            break;
+
+         case 'h': /*help*/
+            usage();
+            break;
+
+         case '?':
+         default:
+            printf("Unknown option -%c\n", op);
+            usage();
+      }
+   }
+
+   if(optind >= argc)
+      usage();
+
+   /*whatever is less should be the server*/
+   strncpy(hnd->server, argv[optind], sizeof(fstring));
+
+   return 1;
+}
+
+void mgr_getline(fstring line) {
+
+   fgets(line, sizeof(fstring), stdin);
+
+   if(line[strlen(line) - 1] == '\n')
+      line[strlen(line) - 1] = '\0';
+
+}
+
+/*this is pretty similar to the other get_auth_data_fn's*/
+void mgr_GetAuthDataFn(const char * pServer,
+                 const char * pShare,
+                 char * pWorkgroup,
+                 int maxLenWorkgroup,
+                 char * pUsername,
+                 int maxLenUsername,
+                 char * pPassword,
+                 int maxLenPassword)
+    
+{
+   char temp[sizeof(fstring)];
+
+   static char authUsername[sizeof(fstring)];
+   static char authWorkgroup[sizeof(fstring)];
+   static char authPassword[sizeof(fstring)];
+   static char authSet = 0;
+
+   char *pass = NULL;
+
+   if (authSet)
+   {
+      strncpy(pWorkgroup, authWorkgroup, maxLenWorkgroup - 1);
+      strncpy(pUsername, authUsername, maxLenUsername - 1);
+      strncpy(pPassword, authPassword, maxLenPassword - 1);
+   }
+   else
+   {
+      if(pWorkgroup[0] != '\0') {
+         strncpy(authWorkgroup, pWorkgroup, maxLenWorkgroup - 1);
+      }
+      else {
+         d_printf("Domain: [%s] ", pWorkgroup);
+         mgr_getline(pWorkgroup);
+
+         if (temp[0] != '\0')
+         {
+            strncpy(pWorkgroup, temp, maxLenWorkgroup - 1);
+            strncpy(authWorkgroup, temp, maxLenWorkgroup - 1);
+         }
+      }
+
+
+      if(pUsername[0] != '\0') {
+         strncpy(authUsername, pUsername, maxLenUsername - 1);
+      }
+      else {
+         d_printf("Username: [%s] ", pUsername);
+         mgr_getline(pUsername);
+
+         if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+         {
+            temp[strlen(temp) - 1] = '\0';
+         }
+
+         if (temp[0] != '\0')
+         {
+            strncpy(pUsername, temp, maxLenUsername - 1);
+            strncpy(authUsername, pUsername, maxLenUsername - 1);
+         }
+      }
+      if(pPassword[0] != '\0') {
+         strncpy(authPassword, pPassword, maxLenPassword - 1);
+      }
+      else {
+         pass = getpass("Password: ");
+         if (pass)
+            fstrcpy(temp, pass);
+         if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+         {
+            temp[strlen(temp) - 1] = '\0';
+         }        
+         if (temp[0] != '\0')
+         {
+            strncpy(pPassword, temp, maxLenPassword - 1);
+            strncpy(authPassword, pPassword, maxLenPassword - 1);
+         }    
+      }
+      authSet = 1;
+   }
+}
+
+void mgr_page(uint32 line_count) {
+
+   if( (line_count % DEFAULT_SCREEN_LINES) != 0)
+      return;
+
+   printf("--Press enter to continue--\n");
+   getchar();
+}
+
+/*reads a line from stdin, figures out if it is a RID or name, gets a CacLookupRidsRecord and then returns the type*/
+uint32 rid_or_name(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd, uint32 *rid, char **name) {
+   fstring line;
+
+   BOOL is_rid = False;
+   uint32 rid_type = 0;
+
+   struct SamGetNamesFromRids getnames;
+   struct SamGetRidsFromNames getrids;
+
+   mgr_getline(line);
+
+   if(strncmp(line, "0x", 2) == 0) {
+      /*then this is a RID*/
+      sscanf( (line + 2), "%x", rid);
+      is_rid = True;
+   }
+   else {
+      /*then this is a name*/
+      *name = talloc_strdup(mem_ctx, line);
+   }
+
+   if(is_rid) {
+      ZERO_STRUCT(getnames);
+
+      getnames.in.dom_hnd  = dom_hnd;
+      getnames.in.rids     = rid;
+      getnames.in.num_rids = 1;
+
+      cac_SamGetNamesFromRids(hnd, mem_ctx, &getnames);
+
+      if(getnames.out.num_names > 0)
+         rid_type = getnames.out.map[0].type;
+         
+   }
+   else {
+      ZERO_STRUCT(getrids);
+
+      getrids.in.dom_hnd   = dom_hnd;
+      getrids.in.names     = name;
+      getrids.in.num_names = 1;
+
+      cac_SamGetRidsFromNames(hnd, mem_ctx, &getrids);
+
+      if(getrids.out.num_rids > 0) {
+         rid_type = getrids.out.map[0].type;
+
+         /*send back the RID so cac_SamOpenXX() doesn't have to look it up*/
+         *rid = getrids.out.map[0].rid;
+      }
+   }
+
+   return rid_type;
+}
+
+/*print's out some common error messages*/
+void printerr(const char *msg, NTSTATUS status) {
+   if(NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED))
+      printf("%s You do not have sufficient rights.\n", msg);
+
+   else if(NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER))
+      printf("%s No such user.\n", msg);
+   
+   else if(NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_GROUP))
+      printf("%s No such group.\n", msg);
+
+   else if(NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
+      printf("%s User already exists.\n", msg);
+
+   else if(NT_STATUS_EQUAL(status, NT_STATUS_GROUP_EXISTS))
+      printf("%s Group already exists.\n", msg);
+
+   else
+      printf("%s %s.\n", msg, nt_errstr(status));
+}
+
+char *get_new_password(TALLOC_CTX *mem_ctx) {
+   char *pass1 = NULL;
+
+   pass1 = getpass("Enter new password: ");
+
+   return talloc_strdup(mem_ctx, pass1);
+}
+
+void print_rid_list(uint32 *rids, char **names, uint32 num_rids) {
+   uint32 i = 0;
+
+   if(!names || !rids)
+      return;
+
+   printf(" RID     Name\n");
+
+   while(i < num_rids) {
+      printf("[0x%x] [%s]\n", rids[i], names[i]);
+
+      i++;
+
+      mgr_page(i);
+   }
+}
+
+void print_lookup_records(CacLookupRidsRecord *map, uint32 num_rids) {
+   uint32 i = 0;
+
+   if(!map)
+      return;
+
+   printf("RID     Name\n");
+
+   while(i < num_rids) {
+      if(map[i].found) {
+         printf("[0x%x] [%s]\n", map[i].rid, map[i].name);
+      }
+
+      i++;
+
+      mgr_page(i);
+   }
+}
+
+int list_groups(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd) {
+   struct SamEnumGroups eg;
+   
+   if(!hnd || !mem_ctx || !dom_hnd)
+      return 0;
+
+   ZERO_STRUCT(eg);
+   eg.in.dom_hnd = dom_hnd;
+
+   while(cac_SamEnumGroups(hnd, mem_ctx, &eg))
+      print_rid_list(eg.out.rids, eg.out.names, eg.out.num_groups);
+
+   if(CAC_OP_FAILED(hnd->status)) {
+      printerr("Could not enumerate groups.", hnd->status);
+      return 0;
+   }
+
+   return 1;
+}
+
+void list_users(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *dom_hnd) {
+   struct SamEnumUsers eu;
+
+   if(!hnd || !mem_ctx || !dom_hnd)
+      return;
+
+   ZERO_STRUCT(eu);
+   eu.in.dom_hnd = dom_hnd;
+
+   while(cac_SamEnumUsers(hnd, mem_ctx, &eu))
+      print_rid_list(eu.out.rids, eu.out.names, eu.out.num_users);
+
+   if(CAC_OP_FAILED(hnd->status))
+      printerr("Could not enumerate users.", hnd->status);
+}
diff --git a/examples/libmsrpc/test/Makefile b/examples/libmsrpc/test/Makefile
new file mode 100644 (file)
index 0000000..95fa5ef
--- /dev/null
@@ -0,0 +1,99 @@
+CC=gcc
+INCLUDES= -I`pwd` -I../../../source/ -I../../../source/include -I../../../source/ubiqx
+
+DEFS= -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+#CFLAGS= -O -D_SAMBA_BUILD_ -gstabs -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wwrite-strings -DDEBUG_PASSWORD -DDEVELOPER -Wdeclaration-after-statement -g $(INCLUDES) $(DEFS) -fPIC
+
+CFLAGS= -g -Wall -ansi $(INCLUDES) 
+
+LDFLAGS=-L. -L../../bin/ 
+LIBS=../../../source/bin/libmsrpc.so
+
+TESTS= lsapol lsaq lsaenum lsaenumprivs lsapriv ear \
+       regkey regopenkey regkeyenum regvalenum regsetval regqueryval regdelete security \
+                adduser samenum samlookup samgroup enable disable dominfo samuser \
+                svc \
+                smbc
+
+all: $(TESTS)
+
+lsapol: lsa/lsapol.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+lsapriv: lsa/lsapriv.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+lsaq: lsa/lsaq.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+lsaenum: lsa/lsaenum.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+lsaenumprivs: lsa/lsaenumprivs.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+lsaaddrights: lsa/lsaaddrights.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+ear: lsa/ear.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+regkey: reg/regkey.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+regopenkey: reg/regopenkey.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+regkeyenum: reg/regkeyenum.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+regkeycreate: reg/regkeycreate.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+regvalenum: reg/regvalenum.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+regsetval: reg/regsetval.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+regqueryval: reg/regqueryval.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+regdelete: reg/regdelete.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+security: reg/security.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+adduser: sam/adduser.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+samenum: sam/samenum.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+samlookup: sam/samlookup.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+samgroup: sam/samgroup.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+enable: sam/enable.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+disable: sam/disable.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+samuser: sam/samuser.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+dominfo: sam/dominfo.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+svc: svcctl/svc.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS)
+
+smbc: smbc_test/smbc.o test_util.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test_util.o $(LIBS) ../../../source/bin/libsmbclient.so
+
+clean:
+       rm -f $(TESTS) *.o lsa/*.o reg/*.o sam/*.o
diff --git a/examples/libmsrpc/test/README b/examples/libmsrpc/test/README
new file mode 100644 (file)
index 0000000..9352905
--- /dev/null
@@ -0,0 +1,8 @@
+This code was written to test the different library functions. However, a simple example of almost every libmsrpc call can be found
+in this code.
+
+notes: most of the programs use a modified smbc_get_auth_data_fn which will not prompt for a user/domain/password so expect flaky results 
+if you run the tests with just a server, ie: svc remote_machine
+   
+
+If you get errors about the libmsrpc.so object, make sure your LD_LIBRARY_PATH points to /path/to/samba3/source/bin
diff --git a/examples/libmsrpc/test/lsa/ear.c b/examples/libmsrpc/test/lsa/ear.c
new file mode 100644 (file)
index 0000000..8a82025
--- /dev/null
@@ -0,0 +1,261 @@
+/* connects to an LSA, asks for a list of server names,  prints out their sids, then looks up their names from the sids and prints them out again
+ *  if you run as lsaq -p, then it will simulate a partial success for cac_GetNamesFromSids. It will try to lookup the server's local and domain sids
+ */
+
+
+#include "libmsrpc.h"
+#include "includes.h"
+
+void fill_conn_info(CacServerHandle *hnd) {
+   pstring domain;
+   pstring username;
+   pstring password;
+   pstring server;
+
+   fprintf(stdout, "Enter domain name: ");
+   fscanf(stdin, "%s", domain);
+
+   fprintf(stdout, "Enter username: ");
+   fscanf(stdin, "%s", username);
+
+   fprintf(stdout, "Enter password (no input masking): ");
+   fscanf(stdin, "%s", password);
+
+   fprintf(stdout, "Enter server (ip or name): ");
+   fscanf(stdin, "%s", server);
+
+   hnd->domain = SMB_STRDUP(domain);
+   hnd->username = SMB_STRDUP(username);
+   hnd->password = SMB_STRDUP(password);
+   hnd->server = SMB_STRDUP(server);
+}
+
+void get_server_names(TALLOC_CTX *mem_ctx, int *num_names, char ***names) {
+   int i = 0;
+   pstring tmp;
+   
+   fprintf(stdout, "How many names do you want to lookup?: ");
+   fscanf(stdin, "%d", num_names);
+
+   *names = TALLOC_ARRAY(mem_ctx, char *, *num_names);
+   if(*names == NULL) {
+      fprintf(stderr, "No memory for allocation\n");
+      exit(-1);
+   }
+
+   for(i = 0; i < *num_names; i++) {
+      fprintf(stdout, "Enter name: ");
+      fscanf(stdin, "%s", tmp);
+      (*names)[i] = talloc_strdup(mem_ctx, tmp);
+   }
+}
+
+int main(int argc, char **argv) {
+   int i;
+   int result;
+   char **names;
+   int num_names;
+   int num_sids;
+   CacServerHandle *hnd = NULL;
+   POLICY_HND *lsa_pol  = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   DOM_SID *sid_buf     = NULL;
+
+   BOOL sim_partial     = False;
+
+   if(argc > 1 && strcmp(argv[1], "-p") == 0)
+      sim_partial = True;
+
+   mem_ctx = talloc_init("lsaq");
+
+   hnd = cac_NewServerHandle(False);
+
+   fill_conn_info(hnd);
+
+   get_server_names(mem_ctx, &num_names, &names);
+
+   /*connect to the PDC and open a LSA handle*/
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server.\n Error %s.\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   fprintf(stdout, "Connected to server: %s\n", hnd->server);
+
+   struct LsaOpenPolicy lop;
+   ZERO_STRUCT(lop);
+
+   lop.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+   lop.in.security_qos = True;
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop)) {
+      fprintf(stderr, "Could not get lsa policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   fprintf(stdout, "Opened Policy Handle\n");
+
+   /*just to make things neater*/
+   lsa_pol = lop.out.pol;
+
+   /*fetch the local sid and domain sid for the pdc*/
+
+   struct LsaFetchSid fsop;
+   ZERO_STRUCT(fsop);
+
+   fsop.in.pol = lsa_pol;
+   fsop.in.info_class = (CAC_LOCAL_INFO|CAC_DOMAIN_INFO);
+
+   fprintf(stdout, "fetching SID info for %s\n", hnd->server);
+
+   result = cac_LsaFetchSid(hnd, mem_ctx, &fsop);
+   if(!result) {
+      fprintf(stderr, "Could not get sid for server: %s\n. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      talloc_destroy(mem_ctx);
+      exit(-1);
+   }
+
+   if(result == CAC_PARTIAL_SUCCESS) {
+      fprintf(stdout, "could not retrieve both domain and local information\n");
+   }
+   
+
+   fprintf(stdout, "Fetched SID info for %s\n", hnd->server);
+   if(fsop.out.local_sid != NULL)
+      fprintf(stdout, " domain: %s. Local SID: %s\n", fsop.out.local_sid->domain, sid_string_static(&fsop.out.local_sid->sid));
+
+   if(fsop.out.domain_sid != NULL)
+      fprintf(stdout, " domain: %s, Domain SID: %s\n", fsop.out.domain_sid->domain, sid_string_static(&fsop.out.domain_sid->sid));
+
+   fprintf(stdout, "Looking up sids\n");
+
+   
+   struct LsaGetSidsFromNames gsop;
+   ZERO_STRUCT(gsop);
+   
+   gsop.in.pol       = lsa_pol;
+   gsop.in.num_names = num_names;
+   gsop.in.names     = names;
+
+   result = cac_LsaGetSidsFromNames(hnd, mem_ctx, &gsop);
+
+   if(!result) {
+      fprintf(stderr, "Could not lookup any sids!\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   if(result == CAC_PARTIAL_SUCCESS) {
+      fprintf(stdout, "Not all names could be looked up.\nThe following names were not found:\n");
+      
+      for(i = 0; i < (num_names - gsop.out.num_found); i++) {
+         fprintf(stdout, " %s\n", gsop.out.unknown[i]);
+      }
+      
+      fprintf(stdout, "\n");
+   }
+
+   /*buffer the sids so we can look them up back to names*/
+   num_sids = (sim_partial) ? gsop.out.num_found + 2: gsop.out.num_found;
+   sid_buf = TALLOC_ARRAY(mem_ctx, DOM_SID, num_sids);
+
+   fprintf(stdout, "%d names were resolved: \n", gsop.out.num_found);
+
+
+   i = 0;
+   while(i < gsop.out.num_found) {
+      fprintf(stdout, " Name: %s\n SID: %s\n\n", gsop.out.sids[i].name, sid_string_static(&gsop.out.sids[i].sid));
+
+      sid_buf[i] = gsop.out.sids[i].sid;
+
+      printf("Attempting to open account\n");
+
+      struct LsaOpenAccount loa;
+      ZERO_STRUCT(loa);
+
+      loa.in.pol    = lsa_pol;
+      loa.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+      loa.in.sid    = &gsop.out.sids[i].sid;
+
+      if(!cac_LsaOpenAccount(hnd, mem_ctx, &loa)) {
+         fprintf(stderr, "Could not open account.\n Error: %s\n", nt_errstr(hnd->status));
+      }
+
+      printf("\nEnumerating privs:");
+      struct LsaEnumAccountRights earop;
+      ZERO_STRUCT(earop);
+
+      earop.in.pol = lsa_pol;
+
+      earop.in.sid = &gsop.out.sids[i].sid;
+
+      if(!cac_LsaEnumAccountRights(hnd, mem_ctx, &earop)) {
+         fprintf(stderr, "Could not enumerate account rights.\n Error: %s\n", nt_errstr(hnd->status));
+      }
+
+      int j;
+      printf( "Rights: ");
+      for(j = 0; j < earop.out.num_privs; j++) {
+         printf("  %s\n", earop.out.priv_names[j]);
+      }
+
+      printf("\n");
+
+
+      i++;
+   }
+
+   /*if we want a partial success to occur below, then add the server's SIDs to the end of the array*/
+   if(sim_partial) {
+      sid_buf[i] = fsop.out.local_sid->sid;
+      sid_buf[i+1] = fsop.out.domain_sid->sid;
+   }
+
+   fprintf(stdout, "Looking up Names from SIDs\n");
+
+   struct LsaGetNamesFromSids gnop;
+   ZERO_STRUCT(gnop);
+
+   gnop.in.pol       = lsa_pol;
+   gnop.in.num_sids  = num_sids;
+   gnop.in.sids      = sid_buf;
+
+   result = cac_LsaGetNamesFromSids(hnd, mem_ctx, &gnop);
+
+   if(!result) {
+      fprintf(stderr, "Could not lookup any names!.\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   if(result == CAC_PARTIAL_SUCCESS) {
+      fprintf(stdout, "\nNot all SIDs could be looked up.\n. The following SIDs were not found:\n");
+
+      for(i = 0; i < (num_sids - gnop.out.num_found); i++) {
+         fprintf(stdout, "SID: %s\n", sid_string_static(&gnop.out.unknown[i]));
+      }
+
+      fprintf(stdout, "\n");
+   }
+
+   fprintf(stdout, "%d SIDs were resolved: \n", gnop.out.num_found);
+   for(i = 0; i < gnop.out.num_found; i++) {
+      fprintf(stdout, " SID: %s\n Name: %s\n", sid_string_static(&gnop.out.sids[i].sid), gsop.out.sids[i].name);
+   }
+   
+done:
+
+   if(!cac_LsaClosePolicy(hnd, mem_ctx, lsa_pol)) {
+      fprintf(stderr, "Could not close LSA policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+   }
+   else {
+      fprintf(stdout, "Closed Policy handle.\n");
+   }
+
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/lsa/lsaenum.c b/examples/libmsrpc/test/lsa/lsaenum.c
new file mode 100644 (file)
index 0000000..d4ad4f7
--- /dev/null
@@ -0,0 +1,96 @@
+/*enumerates SIDs*/
+
+#include "libmsrpc.h"
+#include "includes.h"
+
+int main(int argc, char **argv) {
+
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   POLICY_HND *pol      = NULL;
+
+   int i;
+   int max_sids;
+
+   mem_ctx = talloc_init("lsaenum");
+
+   hnd = cac_NewServerHandle(True);
+   
+   printf("Enter server to connect to: ");
+   fscanf(stdin, "%s", hnd->server);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   printf("How many sids do you want to grab at a time? ");
+   fscanf(stdin, "%d", &max_sids);
+
+   struct LsaOpenPolicy lop;
+   ZERO_STRUCT(lop);
+
+   lop.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+   lop.in.security_qos = True;
+
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop)) {
+      fprintf(stderr, "Could not open policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   pol = lop.out.pol;
+
+
+   struct LsaEnumSids esop;
+   ZERO_STRUCT(esop);
+   esop.in.pol = pol;
+   /*grab a couple at a time to demonstrate multiple calls*/
+   esop.in.pref_max_sids = max_sids;
+
+   printf("Attempting to fetch SIDs %d at a time\n", esop.in.pref_max_sids);
+
+   while(cac_LsaEnumSids(hnd, mem_ctx, &esop)) {
+      
+      printf("\nEnumerated %d sids: \n", esop.out.num_sids);
+      for(i = 0; i < esop.out.num_sids; i++) {
+         printf(" SID: %s\n", sid_string_static(&esop.out.sids[i]));
+      }
+
+      printf("Resolving names\n");
+
+      struct LsaGetNamesFromSids gnop;
+      ZERO_STRUCT(gnop);
+
+      gnop.in.pol = pol;
+      gnop.in.sids = esop.out.sids;
+      gnop.in.num_sids = esop.out.num_sids;
+
+      if(!cac_LsaGetNamesFromSids(hnd, mem_ctx, &gnop)) {
+         fprintf(stderr, "Could not resolve names.\n Error: %s\n", nt_errstr(hnd->status));
+         goto done;
+      }
+
+      printf("\nResolved %d names: \n", gnop.out.num_found);
+      for(i = 0; i < gnop.out.num_found; i++) {
+         printf(" SID: %s\n", sid_string_static(&gnop.out.sids[i].sid));
+         printf(" Name: %s\n", gnop.out.sids[i].name);
+      }
+
+      /*clean up a little*/
+      talloc_free(gnop.out.sids);
+   }
+
+done:
+   if(!cac_LsaClosePolicy(hnd, mem_ctx, pol)) {
+      fprintf(stderr, "Could not close policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+   }
+
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/lsa/lsaenumprivs.c b/examples/libmsrpc/test/lsa/lsaenumprivs.c
new file mode 100644 (file)
index 0000000..8b5c9de
--- /dev/null
@@ -0,0 +1,79 @@
+/*enumerates privileges*/
+
+#include "libmsrpc.h"
+#include "includes.h"
+
+#define MAX_STRING_LEN 50;
+
+int main() {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+   POLICY_HND *lsa_pol  = NULL;
+
+   int i;
+
+   mem_ctx = talloc_init("lsatrust");
+
+   hnd = cac_NewServerHandle(True);
+
+   printf("Server: ");
+   fscanf(stdin, "%s", hnd->server);
+
+   printf("Connecting to server....\n");
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server.\n Error: %s\n errno %s\n", nt_errstr(hnd->status), strerror(errno));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   printf("Connected to server\n");
+
+   struct LsaOpenPolicy lop;
+   ZERO_STRUCT(lop);
+
+   lop.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+   lop.in.security_qos = True;
+
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop)) {
+      fprintf(stderr, "Could not open policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   lsa_pol = lop.out.pol;
+
+   printf("Enumerating Privileges\n");
+
+   struct LsaEnumPrivileges ep;
+   ZERO_STRUCT(ep);
+
+   ep.in.pol = lsa_pol;
+   ep.in.pref_max_privs = 50;
+
+   while(cac_LsaEnumPrivileges(hnd, mem_ctx, &ep)) {
+      printf(" Enumerated %d privileges\n", ep.out.num_privs);
+
+      for(i = 0; i < ep.out.num_privs; i++) {
+         printf("\"%s\"\n", ep.out.priv_names[i]);
+      }
+
+      printf("\n");
+   }
+
+   if(CAC_OP_FAILED(hnd->status)) {
+      fprintf(stderr, "Error while enumerating privileges.\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+done:
+   if(!cac_LsaClosePolicy(hnd, mem_ctx, lsa_pol)) {
+      fprintf(stderr, "Could not close policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+   }
+
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/lsa/lsapol.c b/examples/libmsrpc/test/lsa/lsapol.c
new file mode 100644 (file)
index 0000000..58407e4
--- /dev/null
@@ -0,0 +1,87 @@
+/* simple test code, opens and closes an LSA policy handle using libmsrpc, careful.. there's no password input masking*/
+
+#include "includes.h"
+#include "libmsrpc.h"
+
+void fill_conn_info(CacServerHandle *hnd) {
+   pstring domain;
+   pstring username;
+   pstring password;
+   pstring server;
+
+   fprintf(stdout, "Enter domain name: ");
+   fscanf(stdin, "%s", domain);
+
+   fprintf(stdout, "Enter username: ");
+   fscanf(stdin, "%s", username);
+
+   fprintf(stdout, "Enter password (no input masking): ");
+   fscanf(stdin, "%s", password);
+
+   fprintf(stdout, "Enter server (ip or name): ");
+   fscanf(stdin, "%s", server);
+
+   hnd->domain = SMB_STRDUP(domain);
+   hnd->username = SMB_STRDUP(username);
+   hnd->password = SMB_STRDUP(password);
+   hnd->server = SMB_STRDUP(server);
+}
+
+int main() {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx;
+   struct LsaOpenPolicy op;
+
+   mem_ctx = talloc_init("lsapol");
+
+   
+   hnd = cac_NewServerHandle(False);
+
+   /*this line is unnecesary*/
+   cac_SetAuthDataFn(hnd, cac_GetAuthDataFn);
+
+   hnd->debug = 0;
+
+   fill_conn_info(hnd);
+
+   /*connect to the server, its name/ip is already in the handle so just pass NULL*/
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server. \n Error %s\n errno(%d): %s\n", nt_errstr(hnd->status), errno, strerror(errno));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+   else {
+      fprintf(stdout, "Connected to server\n");
+   }
+
+   op.in.access = GENERIC_EXECUTE_ACCESS;
+   op.in.security_qos = True;
+
+   /*open the handle*/
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &op)) {
+      fprintf(stderr, "Could not open policy.\n Error: %s.errno: %d.\n", nt_errstr(hnd->status), errno);
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+   else {
+      fprintf(stdout, "Opened Policy handle\n");
+   }
+
+   /*close the handle*/
+   if(!cac_LsaClosePolicy(hnd, mem_ctx, op.out.pol)) {
+      fprintf(stderr, "Could not close policy. Error: %s\n", nt_errstr(hnd->status));
+   }
+   else {
+      fprintf(stdout, "Closed Policy handle\n");
+   }
+
+   /*cleanup*/
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   fprintf(stdout, "Free'd server handle\n");
+
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/lsa/lsapriv.c b/examples/libmsrpc/test/lsa/lsapriv.c
new file mode 100644 (file)
index 0000000..80b3ea1
--- /dev/null
@@ -0,0 +1,113 @@
+/*tries to set privileges for an account*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+#define BIGGEST_UINT32 0xffffffff
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+            
+   struct LsaOpenPolicy lop;
+   struct LsaEnumPrivileges ep;
+   struct LsaEnumAccountRights ar;
+   struct LsaAddPrivileges ap;
+   
+   fstring tmp;
+
+   uint32 i = 0;
+   
+   mem_ctx = talloc_init("lsapriv");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   ZERO_STRUCT(lop);
+
+   lop.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop)) {
+      fprintf(stderr, "Could not open LSA policy. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   /*first enumerate possible privileges*/
+   ZERO_STRUCT(ep);
+
+   ep.in.pol = lop.out.pol;
+   ep.in.pref_max_privs = BIGGEST_UINT32;
+
+   printf("Enumerating supported privileges:\n");
+   while(cac_LsaEnumPrivileges(hnd, mem_ctx, &ep)) {
+      for(i = 0; i < ep.out.num_privs; i++) {
+         printf("\t%s\n", ep.out.priv_names[i]);
+      }
+   }
+
+   if(CAC_OP_FAILED(hnd->status)) {
+      fprintf(stderr, "Could not enumerate privileges. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   printf("Enter account name: ");
+   cactest_readline(stdin, tmp);
+
+   ZERO_STRUCT(ar);
+
+   ar.in.pol = lop.out.pol;
+   ar.in.name = talloc_strdup(mem_ctx, tmp);
+   
+   printf("Enumerating privileges for %s:\n", ar.in.name);
+   if(!cac_LsaEnumAccountRights(hnd, mem_ctx, &ar)) {
+      fprintf(stderr, "Could not enumerate privileges. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   printf("Enumerated %d privileges:\n", ar.out.num_privs);
+
+   for(i = 0; i < ar.out.num_privs; i++) 
+      printf("\t%s\n", ar.out.priv_names[i]);
+
+   ZERO_STRUCT(ap);
+
+   ap.in.pol = lop.out.pol;
+   ap.in.name = ar.in.name;
+
+   printf("How many privileges will you set: ");
+   scanf("%d", &ap.in.num_privs);
+
+   ap.in.priv_names = talloc_array(mem_ctx, char *, ap.in.num_privs);
+   if(!ap.in.priv_names) {
+      fprintf(stderr, "No memory\n");
+      goto done;
+   }
+
+   for(i = 0; i < ap.in.num_privs; i++) {
+      printf("Enter priv %d: ", i);
+      cactest_readline(stdin, tmp);
+
+      ap.in.priv_names[i] = talloc_strdup(mem_ctx, tmp);
+   }
+
+   if(!cac_LsaSetPrivileges(hnd, mem_ctx, &ap)) {
+      fprintf(stderr, "Could not set privileges. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+done:
+   talloc_destroy(mem_ctx);
+   cac_FreeHandle(hnd);
+
+   return 0;
+
+}
+
diff --git a/examples/libmsrpc/test/lsa/lsaq.c b/examples/libmsrpc/test/lsa/lsaq.c
new file mode 100644 (file)
index 0000000..54c1849
--- /dev/null
@@ -0,0 +1,245 @@
+/* connects to an LSA, asks for a list of server names,  prints out their sids, then looks up their names from the sids and prints them out again
+ *  if you run as lsaq -p, then it will simulate a partial success for cac_GetNamesFromSids. It will try to lookup the server's local and domain sids
+ */
+
+
+#include "libmsrpc.h"
+#include "includes.h"
+
+void fill_conn_info(CacServerHandle *hnd) {
+   pstring domain;
+   pstring username;
+   pstring password;
+   pstring server;
+
+   fprintf(stdout, "Enter domain name: ");
+   fscanf(stdin, "%s", domain);
+
+   fprintf(stdout, "Enter username: ");
+   fscanf(stdin, "%s", username);
+
+   fprintf(stdout, "Enter password (no input masking): ");
+   fscanf(stdin, "%s", password);
+
+   fprintf(stdout, "Enter server (ip or name): ");
+   fscanf(stdin, "%s", server);
+
+   hnd->domain = SMB_STRDUP(domain);
+   hnd->username = SMB_STRDUP(username);
+   hnd->password = SMB_STRDUP(password);
+   hnd->server = SMB_STRDUP(server);
+}
+
+void get_server_names(TALLOC_CTX *mem_ctx, int *num_names, char ***names) {
+   int i = 0;
+   pstring tmp;
+   
+   fprintf(stdout, "How many names do you want to lookup?: ");
+   fscanf(stdin, "%d", num_names);
+
+   *names = TALLOC_ARRAY(mem_ctx, char *, *num_names);
+   if(*names == NULL) {
+      fprintf(stderr, "No memory for allocation\n");
+      exit(-1);
+   }
+
+   for(i = 0; i < *num_names; i++) {
+      fprintf(stdout, "Enter name: ");
+      fscanf(stdin, "%s", tmp);
+      (*names)[i] = talloc_strdup(mem_ctx, tmp);
+   }
+}
+
+int main(int argc, char **argv) {
+   int i;
+   int result;
+   char **names;
+   int num_names;
+   int num_sids;
+   CacServerHandle *hnd = NULL;
+   POLICY_HND *lsa_pol  = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   DOM_SID *sid_buf     = NULL;
+
+   BOOL sim_partial     = False;
+
+   if(argc > 1 && strcmp(argv[1], "-p") == 0)
+      sim_partial = True;
+
+   mem_ctx = talloc_init("lsaq");
+
+   hnd = cac_NewServerHandle(False);
+
+   fill_conn_info(hnd);
+
+   get_server_names(mem_ctx, &num_names, &names);
+
+   /*connect to the PDC and open a LSA handle*/
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server.\n Error %s.\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   fprintf(stdout, "Connected to server: %s\n", hnd->server);
+
+   struct LsaOpenPolicy lop;
+   ZERO_STRUCT(lop);
+
+   lop.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+   lop.in.security_qos = True;
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop)) {
+      fprintf(stderr, "Could not get lsa policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   fprintf(stdout, "Opened Policy Handle\n");
+
+   /*just to make things neater*/
+   lsa_pol = lop.out.pol;
+
+   /*fetch the local sid and domain sid for the pdc*/
+
+   struct LsaFetchSid fsop;
+   ZERO_STRUCT(fsop);
+
+   fsop.in.pol = lsa_pol;
+   fsop.in.info_class = (CAC_LOCAL_INFO|CAC_DOMAIN_INFO);
+
+   fprintf(stdout, "fetching SID info for %s\n", hnd->server);
+
+   result = cac_LsaFetchSid(hnd, mem_ctx, &fsop);
+   if(!result) {
+      fprintf(stderr, "Could not get sid for server: %s\n. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      talloc_destroy(mem_ctx);
+      exit(-1);
+   }
+
+   if(result == CAC_PARTIAL_SUCCESS) {
+      fprintf(stdout, "could not retrieve both domain and local information\n");
+   }
+   
+
+   fprintf(stdout, "Fetched SID info for %s\n", hnd->server);
+   if(fsop.out.local_sid != NULL)
+      fprintf(stdout, " domain: %s. Local SID: %s\n", fsop.out.local_sid->domain, sid_string_static(&fsop.out.local_sid->sid));
+
+   if(fsop.out.domain_sid != NULL)
+      fprintf(stdout, " domain: %s, Domain SID: %s\n", fsop.out.domain_sid->domain, sid_string_static(&fsop.out.domain_sid->sid));
+
+   fprintf(stdout, "\nAttempting to query info policy\n");
+
+   struct LsaQueryInfoPolicy qop;
+   ZERO_STRUCT(qop);
+
+   qop.in.pol = lsa_pol;
+
+   if(!cac_LsaQueryInfoPolicy(hnd, mem_ctx, &qop)) {
+      fprintf(stderr, "Could not query information policy!.\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   fprintf(stdout, "Query result: \n");
+   fprintf(stdout, " domain name: %s\n", qop.out.domain_name);
+   fprintf(stdout, " dns name:    %s\n", qop.out.dns_name);
+   fprintf(stdout, " forest name: %s\n", qop.out.forest_name);
+   fprintf(stdout, " domain guid: %s\n", smb_uuid_string_static(*qop.out.domain_guid));
+   fprintf(stdout, " domain sid:  %s\n", sid_string_static(qop.out.domain_sid));
+
+   fprintf(stdout, "\nLooking up sids\n");
+   
+   struct LsaGetSidsFromNames gsop;
+   ZERO_STRUCT(gsop);
+   
+   gsop.in.pol       = lsa_pol;
+   gsop.in.num_names = num_names;
+   gsop.in.names     = names;
+
+   result = cac_LsaGetSidsFromNames(hnd, mem_ctx, &gsop);
+
+   if(!result) {
+      fprintf(stderr, "Could not lookup any sids!\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   if(result == CAC_PARTIAL_SUCCESS) {
+      fprintf(stdout, "Not all names could be looked up.\nThe following names were not found:\n");
+      
+      for(i = 0; i < (num_names - gsop.out.num_found); i++) {
+         fprintf(stdout, " %s\n", gsop.out.unknown[i]);
+      }
+      
+      fprintf(stdout, "\n");
+   }
+
+   /*buffer the sids so we can look them up back to names*/
+   num_sids = (sim_partial) ? gsop.out.num_found + 2: gsop.out.num_found;
+   sid_buf = TALLOC_ARRAY(mem_ctx, DOM_SID, num_sids);
+
+   fprintf(stdout, "%d names were resolved: \n", gsop.out.num_found);
+
+
+   i = 0;
+   while(i < gsop.out.num_found) {
+      fprintf(stdout, " Name: %s\n SID: %s\n\n", gsop.out.sids[i].name, sid_string_static(&gsop.out.sids[i].sid));
+
+      sid_buf[i] = gsop.out.sids[i].sid;
+
+      i++;
+   }
+   
+   /*if we want a partial success to occur below, then add the server's SIDs to the end of the array*/
+   if(sim_partial) {
+      sid_buf[i] = fsop.out.local_sid->sid;
+      sid_buf[i+1] = fsop.out.domain_sid->sid;
+   }
+
+   fprintf(stdout, "Looking up Names from SIDs\n");
+
+   struct LsaGetNamesFromSids gnop;
+   ZERO_STRUCT(gnop);
+
+   gnop.in.pol       = lsa_pol;
+   gnop.in.num_sids  = num_sids;
+   gnop.in.sids      = sid_buf;
+
+   result = cac_LsaGetNamesFromSids(hnd, mem_ctx, &gnop);
+
+   if(!result) {
+      fprintf(stderr, "Could not lookup any names!.\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   if(result == CAC_PARTIAL_SUCCESS) {
+      fprintf(stdout, "\nNot all SIDs could be looked up.\n. The following SIDs were not found:\n");
+
+      for(i = 0; i < (num_sids - gnop.out.num_found); i++) {
+         fprintf(stdout, "SID: %s\n", sid_string_static(&gnop.out.unknown[i]));
+      }
+
+      fprintf(stdout, "\n");
+   }
+
+   fprintf(stdout, "%d SIDs were resolved: \n", gnop.out.num_found);
+   for(i = 0; i < gnop.out.num_found; i++) {
+      fprintf(stdout, " SID: %s\n Name: %s\n", sid_string_static(&gnop.out.sids[i].sid), gsop.out.sids[i].name);
+   }
+   
+done:
+
+   if(!cac_LsaClosePolicy(hnd, mem_ctx, lsa_pol)) {
+      fprintf(stderr, "Could not close LSA policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+   }
+   else {
+      fprintf(stdout, "Closed Policy handle.\n");
+   }
+
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/lsa/lsatrust.c b/examples/libmsrpc/test/lsa/lsatrust.c
new file mode 100644 (file)
index 0000000..6ad293f
--- /dev/null
@@ -0,0 +1,151 @@
+/*queries trusted domain information*/
+
+#include "libmsrpc.h"
+#include "includes.h"
+
+#define MAX_STRING_LEN 50;
+
+void print_info(LSA_TRUSTED_DOMAIN_INFO *info) {
+   switch(info->info_class) {
+      case CAC_INFO_TRUSTED_DOMAIN_FULL_INFO:
+      case CAC_INFO_TRUSTED_DOMAIN_INFO_ALL:
+         printf("     Domain Name:     %s\n", unistr2_static(&info->info_ex.domain_name.unistring));
+         printf("     Netbios Name:    %s\n", unistr2_static(&info->info_ex.netbios_name.unistring));
+         printf("     Domain Sid:      %s\n", sid_string_static(&info->info_ex.sid.sid));
+         printf("     Trust direction: %d\n", info->info_ex.trust_direction);
+         printf("     Trust Type:      %d\n", info->info_ex.trust_type);
+         printf("     Trust attr:      %d\n", info->info_ex.trust_attributes); 
+         printf("     Posix Offset:    %d\n", info->posix_offset.posix_offset);
+         break;
+   }
+}
+
+int main() {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+   POLICY_HND *lsa_pol  = NULL;
+
+   int i;
+
+   mem_ctx = talloc_init("lsatrust");
+
+   hnd = cac_NewServerHandle(False);
+
+   /*malloc some memory so get_auth_data_fn can work*/
+   hnd->username     = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   hnd->domain       = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   hnd->netbios_name = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   hnd->password     = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+
+   hnd->server       = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+
+
+   printf("Server: ");
+   fscanf(stdin, "%s", hnd->server);
+
+   printf("Connecting to server....\n");
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server.\n Error: %s\n errno %s\n", nt_errstr(hnd->status), strerror(errno));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   printf("Connected to server\n");
+
+   struct LsaOpenPolicy lop;
+   ZERO_STRUCT(lop);
+
+   lop.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+   lop.in.security_qos = True;
+
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop)) {
+      fprintf(stderr, "Could not open policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+   lsa_pol = lop.out.pol;
+
+   printf("Enumerating Trusted Domains\n");
+
+   struct LsaEnumTrustedDomains etd;
+   ZERO_STRUCT(etd);
+
+   etd.in.pol = lsa_pol;
+
+   while(cac_LsaEnumTrustedDomains(hnd, mem_ctx, &etd)) {
+      printf(" Enumerated %d domains\n", etd.out.num_domains);
+
+      for(i = 0; i < etd.out.num_domains; i++) {
+         printf("   Name: %s\n", etd.out.domain_names[i]);
+         printf("   SID:  %s\n", sid_string_static(&etd.out.domain_sids[i]));
+
+         printf("\n   Attempting to open domain...\n");
+
+         struct LsaOpenTrustedDomain otd;
+         ZERO_STRUCT(otd);
+
+         otd.in.pol = lsa_pol;
+         otd.in.domain_sid = &etd.out.domain_sids[i];
+         otd.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+
+         /*try to query trusted domain info by name*/
+         struct LsaQueryTrustedDomainInfo qtd;
+         ZERO_STRUCT(qtd);
+
+         qtd.in.pol = lsa_pol;
+         qtd.in.domain_name = etd.out.domain_names[i];
+
+         
+         int j;
+         for(j = 0; j < 100; j++ ) {
+            qtd.in.info_class = j;
+
+            printf("    Querying trustdom by name\n");
+            if(!cac_LsaQueryTrustedDomainInfo(hnd, mem_ctx, &qtd)) {
+               fprintf(stderr, "    could not query trusted domain info.\n    Error %s\n", nt_errstr(hnd->status));
+               continue;
+            }
+            
+            printf("    info_class %d succeeded\n", j); 
+            printf("    Query result:\n");    
+            printf("     size %d\n", sizeof(*qtd.out.info));
+         }
+
+         /*try to query trusted domain info by SID*/
+         printf("    Querying trustdom by sid\n");
+         qtd.in.domain_sid = &etd.out.domain_sids[i];
+         if(!cac_LsaQueryTrustedDomainInfo(hnd, mem_ctx, &qtd)) {
+            fprintf(stderr, "    could not query trusted domain info.\n    Error %s\n", nt_errstr(hnd->status));
+            continue;
+         }
+
+         printf("    Query result:\n");    
+/*         print_info(qtd.out.info);*/
+
+         if(CAC_OP_FAILED(hnd->status)) {
+            fprintf(stderr, "    Could not enum sids.\n    Error: %s\n", nt_errstr(hnd->status));
+            continue;
+         }
+      }
+
+      printf("\n");
+   }
+
+   if(CAC_OP_FAILED(hnd->status)) {
+      fprintf(stderr, "Error while enumerating trusted domains.\n Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+done:
+   if(!cac_LsaClosePolicy(hnd, mem_ctx, lsa_pol)) {
+      fprintf(stderr, "Could not close policy handle.\n Error: %s\n", nt_errstr(hnd->status));
+   }
+
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/reg/regdelete.c b/examples/libmsrpc/test/reg/regdelete.c
new file mode 100644 (file)
index 0000000..50b08ba
--- /dev/null
@@ -0,0 +1,102 @@
+/*tests deleting a key or value*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   fstring tmp;
+   char input = 'v';
+   
+   mem_ctx = talloc_init("regdelete");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   printf("enter key to open: \n");
+   cactest_readline(stdin, tmp);
+
+   struct RegOpenKey rok;
+   ZERO_STRUCT(rok);
+
+   rok.in.name = talloc_strdup(mem_ctx, tmp);
+   rok.in.access = REG_KEY_ALL;
+
+   if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+      fprintf(stderr, "Could not open key %s. Error %s\n", rok.in.name, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   printf("getting version (just for testing\n");
+
+   struct RegGetVersion rgv;
+   ZERO_STRUCT(rgv);
+
+   rgv.in.key = rok.out.key;
+
+   if(!cac_RegGetVersion(hnd, mem_ctx, &rgv))
+      fprintf(stderr, "Could not get version. Error: %s\n", nt_errstr(hnd->status));
+   else
+      printf("Version: %d\n", rgv.out.version);
+
+
+   while(input == 'v' || input == 'k') {
+      printf("Delete [v]alue [k]ey or [q]uit: ");
+      scanf("%c", &input);
+
+      switch(input) {
+         case 'v':
+            printf("Value to delete: ");
+            cactest_readline(stdin, tmp);
+            
+            struct RegDeleteValue rdv;
+            ZERO_STRUCT(rdv);
+            
+            rdv.in.parent_key = rok.out.key;
+            rdv.in.name   = talloc_strdup(mem_ctx, tmp);
+
+            if(!cac_RegDeleteValue(hnd, mem_ctx, &rdv))
+               fprintf(stderr, "Could not delete value %s. Error: %s\n", rdv.in.name, nt_errstr(hnd->status));
+
+            break;
+         case 'k':
+            printf("Key to delete: ");
+            cactest_readline(stdin, tmp);
+            
+            struct RegDeleteKey rdk;
+            ZERO_STRUCT(rdk);
+
+            rdk.in.parent_key = rok.out.key;
+            rdk.in.name   = talloc_strdup(mem_ctx, tmp);
+
+            printf("delete recursively? [y/n]: ");
+            cactest_readline(stdin, tmp);
+
+            rdk.in.recursive = (tmp[0] == 'y') ? True : False;
+
+            if(!cac_RegDeleteKey(hnd, mem_ctx, &rdk))
+               fprintf(stderr, "Could not delete key %s. Error %s\n", rdk.in.name, nt_errstr(hnd->status));
+
+            break;
+      }
+   }
+   cac_RegClose(hnd, mem_ctx, rok.out.key);
+
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
+
+
diff --git a/examples/libmsrpc/test/reg/regkey.c b/examples/libmsrpc/test/reg/regkey.c
new file mode 100644 (file)
index 0000000..a90d06c
--- /dev/null
@@ -0,0 +1,76 @@
+/*opens and closes a key*/
+
+#include "libmsrpc.h"
+
+int main() {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    fstring key;
+
+    mem_ctx = talloc_init("regkey");
+    hnd = cac_NewServerHandle(False);
+
+    /*allocate some memory so get_auth_data_fn can do it's magic*/
+    hnd->username = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+    hnd->domain   = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+    hnd->netbios_name = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+    hnd->password = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+    hnd->server   = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+    printf("Enter server to connect to: ");
+    fscanf(stdin, "%s", hnd->server);
+
+    printf("Enter key to open: ");
+    fscanf(stdin, "%s", key);
+
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    struct RegConnect rc;
+    ZERO_STRUCT(rc);
+
+    rc.in.access = REG_KEY_ALL;
+    rc.in.root   = HKEY_LOCAL_MACHINE;
+
+    if(!cac_RegConnect(hnd, mem_ctx, &rc)) {
+       fprintf(stderr, " Could not connect to registry. %s\n", nt_errstr(hnd->status));
+       goto done;
+    }
+
+    printf("trying to open key %s...\n", key);
+
+    
+    struct RegOpenKey rok;
+    ZERO_STRUCT(rok);
+
+    rok.in.parent_key = rc.out.key;
+    rok.in.name   = key;
+    rok.in.access = REG_KEY_ALL;
+
+    if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+       fprintf(stderr, "Could not open key %s\n Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+       goto done;
+    }
+
+    if(!cac_RegClose(hnd, mem_ctx, rok.out.key)) {
+       fprintf(stderr, "Could not close handle %s\n", nt_errstr(hnd->status));
+    }
+
+    if(!cac_RegClose(hnd, mem_ctx, rc.out.key)) {
+       fprintf(stderr, " Could not close handle. %s\n", nt_errstr(hnd->status));
+    }
+
+done:
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/regkeycreate.c b/examples/libmsrpc/test/reg/regkeycreate.c
new file mode 100644 (file)
index 0000000..50764f1
--- /dev/null
@@ -0,0 +1,115 @@
+/*tests creating a registry key*/
+
+#include "libmsrpc.h"
+
+#define MAX_KEYS_PER_ENUM 3
+
+int main() {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    fstring key_name;
+
+    fstring key_to_create;
+
+    mem_ctx = talloc_init("regcreatekey");
+    hnd = cac_NewServerHandle(True);
+
+    printf("Enter server to connect to: ");
+    fscanf(stdin, "%s", hnd->server);
+
+    printf("Enter key to open: ");
+    fscanf(stdin, "%s", key_name);
+
+    printf("Enter key to create: ");
+    fscanf(stdin, "%s", key_to_create);
+
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    printf("trying to open key %s...\n", key_name);
+
+    struct RegOpenKey rok;
+    ZERO_STRUCT(rok);
+
+    rok.in.parent_key = NULL;
+    rok.in.name   = key_name;
+    rok.in.access = REG_KEY_ALL;
+
+    if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+       fprintf(stderr, "Could not open key %s\n Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+       goto done;
+    }
+
+    printf("Creating key %s...\n", key_to_create);
+
+    struct RegCreateKey rck;
+    ZERO_STRUCT(rck);
+
+    rck.in.parent_key = rok.out.key;
+    rck.in.key_name = talloc_strdup(mem_ctx, key_to_create);
+    rck.in.class_name = talloc_strdup(mem_ctx, "");
+    rck.in.access = REG_KEY_ALL;
+
+    if(!cac_RegCreateKey(hnd, mem_ctx, &rck)) {
+       fprintf(stderr, "Could not create key. Error %s\n", nt_errstr(hnd->status));
+       goto done;
+    }
+
+    if(!cac_RegClose(hnd, mem_ctx, rck.out.key)) {
+       fprintf(stderr, "Could not close key.  Error %s\n", nt_errstr(hnd->status));
+       goto done;
+    }
+
+    /**enumerate all the subkeys*/
+    printf("Enumerating all subkeys:\n");
+
+    struct RegEnumKeys ek;
+    ZERO_STRUCT(ek);
+
+    ek.in.key = rok.out.key;
+    ek.in.max_keys = 50;
+
+    while(cac_RegEnumKeys(hnd, mem_ctx, &ek)) {
+       int j;
+
+       for(j = 0; j < ek.out.num_keys; j++) {
+          printf(" Key name: %s\n", ek.out.key_names[j]);
+       }
+    }
+
+    if(CAC_OP_FAILED(hnd->status)) {
+       fprintf(stderr, "Could not enumerate keys: %s\n", nt_errstr(hnd->status));
+       goto done;
+    }
+
+    printf("deleting key %s\n", key_to_create);
+
+    struct RegDeleteKey rdk;
+    ZERO_STRUCT(rdk);
+
+    rdk.in.parent_key = rok.out.key;
+    rdk.in.name   = key_to_create;
+
+    if(!cac_RegDeleteKey(hnd, mem_ctx, &rdk)) {
+       fprintf(stderr, "Could not delete key.  Error %s\n", nt_errstr(hnd->status));
+    }
+
+    printf("closing key %s...\n", key_name);
+
+    if(!cac_RegClose(hnd, mem_ctx, rok.out.key)) {
+       fprintf(stderr, "Could not close handle %s\n", nt_errstr(hnd->status));
+    }
+
+done:
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/regkeyenum.c b/examples/libmsrpc/test/reg/regkeyenum.c
new file mode 100644 (file)
index 0000000..f140d95
--- /dev/null
@@ -0,0 +1,99 @@
+/*tests enumerating keys or values*/
+
+#include "libmsrpc.h"
+
+#define MAX_KEYS_PER_ENUM 3
+
+int main() {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    int num_keys;
+
+    int max_enum;
+
+    int i;
+
+    fstring *key_names;
+
+    mem_ctx = talloc_init("regkeyenum");
+    hnd = cac_NewServerHandle(True);
+
+    printf("Enter server to connect to: ");
+    fscanf(stdin, "%s", hnd->server);
+
+    printf("How many keys do you want to open?: ");
+    fscanf(stdin, "%d", &num_keys);
+
+    printf("How many keys per enum?: ");
+    fscanf(stdin, "%d", &max_enum);
+
+    key_names = TALLOC_ARRAY(mem_ctx, fstring , num_keys);
+    if(!key_names) {
+       fprintf(stderr, "No memory\n");
+       exit(-1);
+    }
+
+    for(i = 0; i < num_keys; i++) {
+       printf("Enter key to open: ");
+       fscanf(stdin, "%s", key_names[i]);
+    }
+
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    for(i = 0; i < num_keys; i++) {
+       printf("trying to open key %s...\n", key_names[i]);
+
+       struct RegOpenKey rok;
+       ZERO_STRUCT(rok);
+
+       rok.in.parent_key = NULL;
+       rok.in.name   = key_names[i];
+       rok.in.access = REG_KEY_ALL;
+
+       if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+          fprintf(stderr, "Could not open key %s\n Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+          continue;
+       }
+
+       /**enumerate all the subkeys*/
+       printf("Enumerating all subkeys:\n");
+
+       struct RegEnumKeys ek;
+       ZERO_STRUCT(ek);
+
+       ek.in.key = rok.out.key;
+       ek.in.max_keys = max_enum;
+
+       while(cac_RegEnumKeys(hnd, mem_ctx, &ek)) {
+          int j;
+
+          for(j = 0; j < ek.out.num_keys; j++) {
+             printf(" Key name: %s\n", ek.out.key_names[j]);
+          }
+       }
+
+       if(CAC_OP_FAILED(hnd->status)) {
+          fprintf(stderr, "Could not enumerate keys: %s\n", nt_errstr(hnd->status));
+          continue;
+       }
+
+       printf("closing key %s...\n", key_names[i]);
+
+       if(!cac_RegClose(hnd, mem_ctx, rok.out.key)) {
+          fprintf(stderr, "Could not close handle %s\n", nt_errstr(hnd->status));
+       }
+    }
+
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/regopen.c b/examples/libmsrpc/test/reg/regopen.c
new file mode 100644 (file)
index 0000000..fedc52e
--- /dev/null
@@ -0,0 +1,66 @@
+/*opens and closes a registry handle*/
+
+#include "libmsrpc.h"
+
+int main() {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    POLICY_HND **keys      = NULL;
+
+    char roots[4][50] = { {CAC_HKCR}, {CAC_HKLM}, {CAC_HKU}, {CAC_HKPD} };
+
+    int i;
+
+    mem_ctx = talloc_init("regopen");
+    hnd = cac_NewServerHandle(True);
+
+    keys = TALLOC_ARRAY(mem_ctx, POLICY_HND *, 4);
+    
+    printf("Enter server to connect to: ");
+    fscanf(stdin, "%s", hnd->server);
+
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    struct RegConnect rc;
+    ZERO_STRUCT(rc);
+
+    rc.in.access = SEC_RIGHT_MAXIMUM_ALLOWED;
+
+    for(i = 0; i < 4; i++) {
+       printf("opening: %s\n", roots[i]);
+
+       rc.in.root = roots[i];
+
+       if(!cac_RegConnect(hnd, mem_ctx, &rc)) {
+          fprintf(stderr, " Could not connect to registry. %s\n", nt_errstr(hnd->status));
+          continue;
+       }
+
+       keys[i] = rc.out.key;
+    }
+
+    for(i = 3; i >= 0; i--) {
+       if(keys[i] == NULL)
+          continue;
+
+       printf("closing: %s\n", roots[i]);
+
+       if(!cac_RegClose(hnd, mem_ctx, keys[i])) {
+          fprintf(stderr, " Could not close handle. %s\n", nt_errstr(hnd->status));
+       }
+    }
+
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/regopenkey.c b/examples/libmsrpc/test/reg/regopenkey.c
new file mode 100644 (file)
index 0000000..732da17
--- /dev/null
@@ -0,0 +1,69 @@
+/*tests cac_RegOpenKey()*/
+
+#include "libmsrpc.h"
+
+int main() {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    int num_keys;
+    int i;
+
+    fstring *key_names;
+
+    mem_ctx = talloc_init("regopenkey");
+    hnd = cac_NewServerHandle(True);
+
+    printf("Enter server to connect to: ");
+    fscanf(stdin, "%s", hnd->server);
+
+    printf("How many keys do you want to open?: ");
+    fscanf(stdin, "%d", &num_keys);
+
+    key_names = TALLOC_ARRAY(mem_ctx, fstring , num_keys);
+    if(!key_names) {
+       fprintf(stderr, "No memory\n");
+       exit(-1);
+    }
+
+    for(i = 0; i < num_keys; i++) {
+       printf("Enter key to open: ");
+       fscanf(stdin, "%s", key_names[i]);
+    }
+
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    for(i = 0; i < num_keys; i++) {
+       printf("trying to open key %s...\n", key_names[i]);
+
+       struct RegOpenKey rok;
+       ZERO_STRUCT(rok);
+
+       rok.in.parent_key = NULL;
+       rok.in.name   = key_names[i];
+       rok.in.access = REG_KEY_ALL;
+
+       if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+          fprintf(stderr, "Could not open key %s\n Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+          continue;
+       }
+
+       printf("closing key %s...\n", key_names[i]);
+
+       if(!cac_RegClose(hnd, mem_ctx, rok.out.key)) {
+          fprintf(stderr, "Could not close handle %s\n", nt_errstr(hnd->status));
+       }
+    }
+
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/regqueryval.c b/examples/libmsrpc/test/reg/regqueryval.c
new file mode 100644 (file)
index 0000000..9989651
--- /dev/null
@@ -0,0 +1,79 @@
+/*tests cac_RegQueryValue()*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+#define MAX_KEYS_PER_ENUM 3
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    fstring key_name;
+
+    fstring val_name;
+
+    mem_ctx = talloc_init("regqueryval");
+    hnd = cac_NewServerHandle(True);
+
+    cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+    cac_parse_cmd_line(argc, argv, hnd);
+
+    printf("Enter key to open: ");
+    fscanf(stdin, "%s", key_name);
+
+    printf("Enter value to query: ");
+    fscanf(stdin, "%s", val_name);
+
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    printf("trying to open key %s...\n", key_name);
+
+    struct RegOpenKey rok;
+    ZERO_STRUCT(rok);
+
+    rok.in.parent_key = NULL;
+    rok.in.name       = key_name;
+    rok.in.access     = REG_KEY_ALL;
+
+    if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+       fprintf(stderr, "Could not open key %s\n Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+       goto done;
+    }
+
+    struct RegQueryValue rqv;
+    ZERO_STRUCT(rqv);
+
+    rqv.in.key = rok.out.key;
+    rqv.in.val_name = talloc_strdup(mem_ctx, val_name);
+
+    printf("querying value %s...\n", rqv.in.val_name);
+    if(!cac_RegQueryValue(hnd, mem_ctx, &rqv)) {
+       fprintf(stderr, "Could not query value. Error: %s\n", nt_errstr(hnd->status));
+    }
+    else {
+       printf("Queried value %s\n", rqv.in.val_name);
+       print_value(rqv.out.type, rqv.out.data);
+    }
+
+
+    printf("closing key %s...\n", key_name);
+
+    if(!cac_RegClose(hnd, mem_ctx, rok.out.key)) {
+       fprintf(stderr, "Could not close handle %s\n", nt_errstr(hnd->status));
+    }
+
+done:
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/regsetval.c b/examples/libmsrpc/test/reg/regsetval.c
new file mode 100644 (file)
index 0000000..e732791
--- /dev/null
@@ -0,0 +1,59 @@
+/*tests cac_RegSetVal()*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   fstring tmp;
+   
+   mem_ctx = talloc_init("regsetval");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   printf("enter key to open: \n");
+   scanf("%s", tmp);
+
+   struct RegOpenKey rok;
+   ZERO_STRUCT(rok);
+
+   rok.in.name = talloc_strdup(mem_ctx, tmp);
+   rok.in.access = REG_KEY_ALL;
+
+   if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+      fprintf(stderr, "Could not open key %s. Error %s\n", rok.in.name, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct RegSetValue rsv;
+   ZERO_STRUCT(rsv);
+
+   rsv.in.key = rok.out.key;
+
+   cactest_reg_input_val(mem_ctx, &rsv.in.type, &rsv.in.val_name, &rsv.in.value);
+
+   if(!cac_RegSetValue(hnd, mem_ctx, &rsv)) {
+      fprintf(stderr, "Could not set value. Error: %s\n", nt_errstr(hnd->status));
+   }
+
+   cac_RegClose(hnd, mem_ctx, rok.out.key);
+
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
+
+
diff --git a/examples/libmsrpc/test/reg/regvalenum.c b/examples/libmsrpc/test/reg/regvalenum.c
new file mode 100644 (file)
index 0000000..9778f4e
--- /dev/null
@@ -0,0 +1,103 @@
+/*tests enumerating registry values*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+#define MAX_KEYS_PER_ENUM 3
+
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+    TALLOC_CTX *mem_ctx  = NULL;
+    int num_keys;
+
+    int max_enum;
+
+    fstring *key_names;
+
+    int i;
+    mem_ctx = talloc_init("regvalenum");
+    hnd = cac_NewServerHandle(True);
+
+    cac_parse_cmd_line(argc, argv, hnd);
+
+    cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+    
+    if(!cac_Connect(hnd, NULL)) {
+       fprintf(stderr, "Could not connect to server.\n Error: %s.\n errno: %s\n", nt_errstr(hnd->status), strerror(errno));
+       cac_FreeHandle(hnd);
+       exit(-1);
+    }
+
+    printf("How many keys do you want to open?: ");
+    fscanf(stdin, "%d", &num_keys);
+
+    printf("How many values per enum?: ");
+    fscanf(stdin, "%d", &max_enum);
+
+    key_names = TALLOC_ARRAY(mem_ctx, fstring , num_keys);
+    if(!key_names) {
+       fprintf(stderr, "No memory\n");
+       exit(-1);
+    }
+
+    for(i = 0; i < num_keys; i++) {
+       printf("Enter key to open: ");
+       fscanf(stdin, "%s", key_names[i]);
+    }
+
+    for(i = 0; i < num_keys; i++) {
+       printf("trying to open key %s...\n", key_names[i]);
+
+       struct RegOpenKey rok;
+       ZERO_STRUCT(rok);
+
+       rok.in.parent_key = NULL;
+       rok.in.name   = key_names[i];
+       rok.in.access = REG_KEY_ALL;
+
+       if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+          fprintf(stderr, "Could not open key %s\n Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+          continue;
+       }
+
+       /**enumerate all the subkeys*/
+       printf("Enumerating all values:\n");
+
+       struct RegEnumValues rev;
+       ZERO_STRUCT(rev);
+
+       rev.in.key = rok.out.key;
+       rev.in.max_values = max_enum;
+
+       while(cac_RegEnumValues(hnd, mem_ctx, &rev)) {
+          int j;
+
+          for(j = 0; j < rev.out.num_values; j++) {
+             printf(" Value name: %s\n", rev.out.value_names[j]);
+             print_value(rev.out.types[j], rev.out.values[j]);
+          }
+       }
+
+       if(CAC_OP_FAILED(hnd->status)) {
+          fprintf(stderr, "Could not enumerate values: %s\n", nt_errstr(hnd->status));
+          continue;
+       }
+
+       printf("closing key %s...\n", key_names[i]);
+
+       if(!cac_RegClose(hnd, mem_ctx, rok.out.key)) {
+          fprintf(stderr, "Could not close handle %s\n", nt_errstr(hnd->status));
+       }
+    }
+
+    cac_FreeHandle(hnd);
+
+    talloc_destroy(mem_ctx);
+
+    return 0;
+
+}
diff --git a/examples/libmsrpc/test/reg/security.c b/examples/libmsrpc/test/reg/security.c
new file mode 100644 (file)
index 0000000..6808f8c
--- /dev/null
@@ -0,0 +1,74 @@
+/*tests cac_RegSetKeySecurity()*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   fstring tmp;
+   
+   mem_ctx = talloc_init("regsetval");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct RegOpenKey rok;
+   ZERO_STRUCT(rok);
+
+   printf("enter key to query: ");
+   cactest_readline(stdin, tmp);
+
+   rok.in.name = talloc_strdup(mem_ctx, tmp);
+   rok.in.access = REG_KEY_ALL;
+
+   if(!cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+      fprintf(stderr, "Could not open key %s. Error %s\n", rok.in.name, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct RegGetKeySecurity rks;
+   ZERO_STRUCT(rks);
+
+   rks.in.key = rok.out.key;
+   rks.in.info_type = ALL_SECURITY_INFORMATION;
+
+   if(!cac_RegGetKeySecurity(hnd, mem_ctx, &rks)) {
+      fprintf(stderr, "Could not query security for %s.  Error: %s\n", rok.in.name, nt_errstr(hnd->status));
+      goto done;
+   }
+
+   printf("resetting key security...\n");
+
+   struct RegSetKeySecurity rss;
+   ZERO_STRUCT(rss);
+
+   rss.in.key = rok.out.key;
+   rss.in.info_type = ALL_SECURITY_INFORMATION;
+   rss.in.size = rks.out.size;
+   rss.in.descriptor = rks.out.descriptor;
+
+   if(!cac_RegSetKeySecurity(hnd, mem_ctx, &rss)) {
+      fprintf(stderr, "Could not set security. Error %s\n", nt_errstr(hnd->status));
+   }
+
+done:
+   cac_RegClose(hnd, mem_ctx, rok.out.key);
+   
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
+
+
diff --git a/examples/libmsrpc/test/reg/shutdown.c b/examples/libmsrpc/test/reg/shutdown.c
new file mode 100644 (file)
index 0000000..6184fbd
--- /dev/null
@@ -0,0 +1,68 @@
+/*tries to shut down a remote pc*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx  = NULL;
+
+   fstring tmp;
+   
+   mem_ctx = talloc_init("cac_shutdown");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   hnd->_internal.srv_level = SRV_WIN_NT4;
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct Shutdown s;
+   ZERO_STRUCT(s);
+
+   printf("Message: ");
+   cactest_readline(stdin, tmp);
+
+   s.in.message = talloc_strdup(mem_ctx, tmp);
+
+   printf("timeout: ");
+   scanf("%d", &s.in.timeout);
+
+   printf("Reboot? [y/n]: ");
+   cactest_readline(stdin, tmp);
+
+   s.in.reboot = ( tmp[0] == 'y') ? True : False;
+
+   printf("Force? [y/n]: ");
+   cactest_readline(stdin, tmp);
+
+   s.in.force = (tmp[0] == 'y') ? True : False;
+
+   if(!cac_Shutdown(hnd, mem_ctx, &s)) {
+      fprintf(stderr, "could not shut down server: error %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   printf("Server %s is shutting down. Would you like to try to abort? [y/n]: ", hnd->server);
+   fscanf(stdin, "%s", tmp);
+
+   if(tmp[0] == 'y') {
+      if(!cac_AbortShutdown(hnd, mem_ctx)) {
+         fprintf(stderr, "Could not abort shutdown. Error %s\n", nt_errstr(hnd->status));
+      }
+   }
+
+done:
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/sam/adduser.c b/examples/libmsrpc/test/sam/adduser.c
new file mode 100644 (file)
index 0000000..94482d0
--- /dev/null
@@ -0,0 +1,92 @@
+/*add's a user to a domain*/
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+
+   fstring tmp;
+
+   struct SamOpenUser ou;
+
+   POLICY_HND *user_hnd = NULL;
+
+   mem_ctx = talloc_init("cac_adduser");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   struct SamCreateUser cdu;
+   ZERO_STRUCT(cdu);
+
+   printf("Enter account name: ");
+   cactest_readline(stdin, tmp);
+
+   cdu.in.dom_hnd = sod.out.dom_hnd;
+   cdu.in.name = talloc_strdup(mem_ctx, tmp);
+   cdu.in.acb_mask  = ACB_NORMAL;
+
+   if(!cac_SamCreateUser(hnd, mem_ctx, &cdu)) {
+      fprintf(stderr, "Could not create user %s. Error: %s\n", cdu.in.name, nt_errstr(hnd->status));
+   }
+
+   printf("would you like to delete this user? [y/n]: ");
+   cactest_readline(stdin, tmp);
+
+   if(tmp[0] == 'y') {
+
+      if(!cdu.out.user_hnd) {
+         ZERO_STRUCT(ou);
+         ou.in.dom_hnd = sod.out.dom_hnd;
+         ou.in.access  = MAXIMUM_ALLOWED_ACCESS;
+         ou.in.name    = talloc_strdup(mem_ctx, cdu.in.name);
+
+         if(!cac_SamOpenUser(hnd, mem_ctx, &ou)) {
+            fprintf(stderr, "Could not open user for deletion. Error: %s\n", nt_errstr(hnd->status));
+         }
+
+         user_hnd = ou.out.user_hnd;
+      }
+
+      else {
+         user_hnd = cdu.out.user_hnd;
+      }
+
+      if(!cac_SamDeleteUser(hnd, mem_ctx, user_hnd))
+         fprintf(stderr, "Could not delete user. Error: %s\n", nt_errstr(hnd->status));
+   }
+   else {
+      printf("Nope..ok\n");
+   }
+
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+   cac_SamClose(hnd, mem_ctx, sod.out.sam);
+
+done:
+   talloc_destroy(mem_ctx);
+
+   cac_FreeHandle(hnd);
+   
+   return 0;
+}
+
+/*TODO: add a function that will create a user and set userinfo and set the password*/
diff --git a/examples/libmsrpc/test/sam/disable.c b/examples/libmsrpc/test/sam/disable.c
new file mode 100644 (file)
index 0000000..f140bad
--- /dev/null
@@ -0,0 +1,63 @@
+/*disable a user*/
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+
+   struct SamOpenUser ou;
+
+   fstring tmp;
+
+   mem_ctx = talloc_init("cac_disable");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   ZERO_STRUCT(ou);
+   printf("Enter username: ");
+   cactest_readline(stdin, tmp);
+
+   ou.in.name = talloc_strdup(mem_ctx, tmp);
+   ou.in.access = MAXIMUM_ALLOWED_ACCESS;
+   ou.in.dom_hnd = sod.out.dom_hnd;
+
+   if(!cac_SamOpenUser(hnd, mem_ctx, &ou)) {
+      fprintf(stderr, "Could not open user. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   /*enable the user*/
+   if(!cac_SamDisableUser(hnd, mem_ctx, ou.out.user_hnd)) {
+      fprintf(stderr, "Could not disable user: %s\n", nt_errstr(hnd->status));
+   }
+
+done:
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+   
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/sam/dominfo.c b/examples/libmsrpc/test/sam/dominfo.c
new file mode 100644 (file)
index 0000000..cd2ecce
--- /dev/null
@@ -0,0 +1,55 @@
+/*gets domain info and prints it out*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+
+   mem_ctx = talloc_init("cac_dominfo");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   struct SamGetDomainInfo gdi;
+   ZERO_STRUCT(gdi);
+
+   gdi.in.dom_hnd = sod.out.dom_hnd;
+
+   if(!cac_SamGetDomainInfo(hnd, mem_ctx, &gdi)) {
+      fprintf(stderr, "Could not get domain info. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   printf("Got domain info:\n");
+   print_cac_domain_info(gdi.out.info);
+
+done:
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+   
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/sam/enable.c b/examples/libmsrpc/test/sam/enable.c
new file mode 100644 (file)
index 0000000..bb91fb2
--- /dev/null
@@ -0,0 +1,64 @@
+/*enable a user*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+
+   struct SamOpenUser ou;
+
+   fstring tmp;
+
+   mem_ctx = talloc_init("cac_samgroup");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   ZERO_STRUCT(ou);
+   printf("Enter username: ");
+   cactest_readline(stdin, tmp);
+
+   ou.in.name = talloc_strdup(mem_ctx, tmp);
+   ou.in.access = MAXIMUM_ALLOWED_ACCESS;
+   ou.in.dom_hnd = sod.out.dom_hnd;
+
+   if(!cac_SamOpenUser(hnd, mem_ctx, &ou)) {
+      fprintf(stderr, "Could not open user. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   /*enable the user*/
+   if(!cac_SamEnableUser(hnd, mem_ctx, ou.out.user_hnd)) {
+      fprintf(stderr, "Could not enable user: %s\n", nt_errstr(hnd->status));
+   }
+
+done:
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+   
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/sam/samenum.c b/examples/libmsrpc/test/sam/samenum.c
new file mode 100644 (file)
index 0000000..5b10475
--- /dev/null
@@ -0,0 +1,117 @@
+/*enumerate users/groups/aliases*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+            
+   
+   struct SamEnumUsers eu;
+   struct SamEnumGroups eg;
+   struct SamEnumAliases ea;
+
+   fstring tmp;
+   
+   int i;
+
+   mem_ctx = talloc_init("cac_samenum");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   tmp[0] = 0x00;
+   while(tmp[0] != 'q') {
+      printf("Enumerate [u]sers, [g]roups or [a]liases or [q]uit: ");
+      cactest_readline(stdin, tmp);
+
+      switch(tmp[0]) {
+         case 'u':
+            ZERO_STRUCT(eu);
+
+            eu.in.dom_hnd = sod.out.dom_hnd;
+            
+            printf("ACB mask (can be 0): ");
+            scanf("%hx", &eu.in.acb_mask);
+
+            while(cac_SamEnumUsers(hnd, mem_ctx, &eu)) {
+               printf("Enumerated %d users:\n", eu.out.num_users);
+               for(i = 0; i < eu.out.num_users; i++) {
+                  printf(" Name: %s\n", eu.out.names[i]);
+                  printf(" RID:  %d\n", eu.out.rids[i]);
+               }
+            }
+
+            if(CAC_OP_FAILED(hnd->status)) {
+               printf("Could not enumerate users. Error: %s\n", nt_errstr(hnd->status));
+            }
+            break;
+         case 'g':
+            ZERO_STRUCT(eg);
+            eg.in.dom_hnd = sod.out.dom_hnd;
+
+            printf("Enumerating groups...\n");
+            while(cac_SamEnumGroups(hnd, mem_ctx, &eg)) {
+               printf("Enumerated %d groups:\n", eg.out.num_groups);
+               for(i = 0; i < eg.out.num_groups; i++) {
+                  printf("RID:  %d\n", eg.out.rids[i]);
+                  printf("Name: %s\n", eg.out.names[i]);
+                  printf("Desc: %s\n", eg.out.descriptions[i]);
+               }
+            }
+
+            if(CAC_OP_FAILED(hnd->status)) {
+               printf("Could not enumerate Groups. Error: %s\n", nt_errstr(hnd->status));
+            }
+            break;
+         case 'a':
+            ZERO_STRUCT(ea);
+            ea.in.dom_hnd = sod.out.dom_hnd;
+
+            printf("Enumerating Aliases...\n");
+            while(cac_SamEnumAliases(hnd, mem_ctx, &ea)) {
+               printf("Enumerated %d aliases:\n", ea.out.num_aliases);
+
+               for(i = 0; i < ea.out.num_aliases; i++) {
+                  printf("RID:  %d\n", ea.out.rids[i]);
+                  printf("Name: %s\n", ea.out.names[i]);
+                  printf("Desc: %s\n", ea.out.descriptions[i]);
+               }
+            }
+            if(CAC_OP_FAILED(hnd->status)) {
+               printf("Could not enumerate Aliases. Error: %s\n", nt_errstr(hnd->status));
+            }
+            break;
+      }
+   }
+
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+   cac_SamClose(hnd, mem_ctx, sod.out.sam);
+
+done:
+   talloc_destroy(mem_ctx);
+   cac_FreeHandle(hnd);
+
+   return 0;
+
+}
+
diff --git a/examples/libmsrpc/test/sam/samgroup.c b/examples/libmsrpc/test/sam/samgroup.c
new file mode 100644 (file)
index 0000000..39d9fa1
--- /dev/null
@@ -0,0 +1,480 @@
+/*Some group management stuff*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+            
+   
+   struct SamEnumGroups eg;
+   struct SamEnumUsers eu;
+   struct SamCreateGroup cg;
+   struct SamOpenGroup og;
+   struct SamGetGroupMembers ggm;
+   struct SamGetNamesFromRids gn;
+   struct SamAddGroupMember add;
+   struct SamRemoveGroupMember del;
+   struct SamSetGroupMembers set;
+   struct SamGetGroupsForUser gg;
+   struct SamOpenUser         ou;
+   struct SamGetGroupInfo     gi;
+   struct SamSetGroupInfo     si;
+   struct SamRenameGroup      rg;
+   struct SamGetSecurityObject gso;
+
+   POLICY_HND *group_hnd = NULL;
+
+   fstring tmp;
+   fstring input;
+   
+   int i;
+
+   mem_ctx = talloc_init("cac_samgroup");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   tmp[0] = 0x00;
+   while(tmp[0] != 'q') {
+      printf("\n");
+      printf("[l]ist groups\n");
+      printf("[c]reate group\n");
+      printf("[o]pen group\n");
+      printf("[d]elete group\n");
+      printf("list [m]embers\n");
+      printf("list [u]sers\n");
+      printf("list [g]roup for users\n");
+      printf("[a]dd member\n");
+      printf("[r]emove member\n");
+      printf("[x] clear members\n");
+      printf("get group [i]nfo\n");
+      printf("[e]dit group info\n");
+      printf("[s]et members\n");
+      printf("re[n]ame group\n");
+      printf("[z] close group\n");
+      printf("[t] get security info\n");
+
+      printf("[q]uit\n\n");
+      printf("Enter option: ");
+      cactest_readline(stdin, tmp);
+
+      printf("\n");
+
+      switch(tmp[0]) {
+         case 'c': /*create group*/
+            if(group_hnd != NULL) {
+               /*then we have an open handle.. close it*/
+               cac_SamClose(hnd, mem_ctx, group_hnd);
+               group_hnd = NULL;
+            }
+
+            printf("Enter group name: ");
+            cactest_readline(stdin, input);
+
+            ZERO_STRUCT(cg);
+
+            cg.in.name      = talloc_strdup(mem_ctx, input);
+            cg.in.access    = MAXIMUM_ALLOWED_ACCESS;
+            cg.in.dom_hnd   = sod.out.dom_hnd;
+
+            if(!cac_SamCreateGroup(hnd, mem_ctx, &cg)) {
+               fprintf(stderr, "Could not create group. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Created group %s\n", cg.in.name);
+
+               group_hnd = cg.out.group_hnd;
+            }
+            break;
+
+         case 'o': /*open group*/
+            if(group_hnd != NULL) {
+               /*then we have an open handle.. close it*/
+               cac_SamClose(hnd, mem_ctx, group_hnd);
+               group_hnd = NULL;
+            }
+
+            ZERO_STRUCT(og);
+
+            og.in.dom_hnd = sod.out.dom_hnd;
+            og.in.access = MAXIMUM_ALLOWED_ACCESS;
+
+            printf("Enter RID: 0x");
+            scanf("%x", &og.in.rid);
+
+            if(!cac_SamOpenGroup(hnd, mem_ctx, &og)) {
+               fprintf(stderr, "Could not open group. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Opened group\n");
+               group_hnd = og.out.group_hnd;
+            }
+
+            break;
+
+         case 'l': /*list groups*/
+            ZERO_STRUCT(eg);
+            eg.in.dom_hnd = sod.out.dom_hnd;
+
+            while(cac_SamEnumGroups(hnd, mem_ctx, &eg)) {
+               for(i = 0; i < eg.out.num_groups; i++) {
+                  printf("RID: 0x%x Name: %s\n", eg.out.rids[i], eg.out.names[i]);
+               }
+            }
+
+            if(CAC_OP_FAILED(hnd->status)) {
+               printf("Could not enumerate Groups. Error: %s\n", nt_errstr(hnd->status));
+            }
+
+            break;
+            
+         case 'm': /*list group members*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(ggm);
+            ggm.in.group_hnd = group_hnd;
+
+            if(!cac_SamGetGroupMembers(hnd, mem_ctx, &ggm)) {
+               fprintf(stderr, "Could not get group members. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            printf("Group has %d members:\n", ggm.out.num_members);
+
+            if(ggm.out.num_members == 0) /*just skip the rest of this case*/
+               break;
+
+            /**get the user names*/
+            gn.in.dom_hnd = sod.out.dom_hnd;
+            gn.in.num_rids = ggm.out.num_members;
+            gn.in.rids = ggm.out.rids;
+
+            if(!cac_SamGetNamesFromRids(hnd, mem_ctx, &gn)) {
+               fprintf(stderr, "Could not lookup names. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            for(i = 0; i < gn.out.num_names; i++) {
+               printf("RID: 0x%x Name: %s\n", gn.out.map[i].rid, gn.out.map[i].name);
+            }
+
+            break;
+
+         case 'd': /*delete group*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            if(!cac_SamDeleteGroup(hnd, mem_ctx, group_hnd)) {
+               fprintf(stderr, "Could not delete group. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Deleted group.\n");
+               group_hnd = NULL;
+            }
+            break;
+
+         case 'u': /*list users*/
+            ZERO_STRUCT(eu);
+
+            eu.in.dom_hnd = sod.out.dom_hnd;
+            
+            while(cac_SamEnumUsers(hnd, mem_ctx, &eu)) {
+               for(i = 0; i < eu.out.num_users; i++) {
+                  printf(" RID: 0x%x Name: %s\n", eu.out.rids[i], eu.out.names[i]);
+               }
+            }
+
+            if(CAC_OP_FAILED(hnd->status)) {
+               printf("Could not enumerate users. Error: %s\n", nt_errstr(hnd->status));
+            }
+
+            break;
+
+         case 'a': /*add member to group*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(add);
+
+            add.in.group_hnd = group_hnd;
+
+            printf("Enter user RID: 0x");
+            scanf("%x", &add.in.rid);
+
+            if(!cac_SamAddGroupMember(hnd, mem_ctx, &add)) {
+               fprintf(stderr, "Could not add user to group. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Successfully added user to group\n");
+            }
+            break;
+
+         case 'r': /*remove user from group*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(del);
+            del.in.group_hnd = group_hnd;
+
+            printf("Enter RID: 0x");
+            scanf("%x", &del.in.rid);
+
+            if(!cac_SamRemoveGroupMember(hnd, mem_ctx, &del)) {
+               fprintf(stderr, "Could not remove user from group. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Removed user from group.\n");
+            }
+
+            break;
+
+         case 'x': /*clear group members*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            if(!cac_SamClearGroupMembers(hnd, mem_ctx, group_hnd)) {
+               fprintf(stderr, "Could not clear group members. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Cleared group members\n");
+            }
+
+            break;
+            
+         case 's': /*set members*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(set);
+
+            set.in.group_hnd = group_hnd;
+
+            printf("Enter the number of members: ");
+            scanf("%d", &set.in.num_members);
+
+            set.in.rids = TALLOC_ARRAY(mem_ctx, uint32, set.in.num_members);
+
+            for(i = 0; i < set.in.num_members; i++) {
+               printf("Enter RID #%d: 0x", (i+1));
+               scanf("%x", (set.in.rids + i));
+            }
+
+            if(!cac_SamSetGroupMembers(hnd, mem_ctx, &set)) {
+               printf("could not set members. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Set users\n");
+            }
+
+            break;
+            
+         case 'g': /*list groups for user*/
+            ZERO_STRUCT(ou);
+            ZERO_STRUCT(gg);
+
+            printf("Enter username: ");
+            cactest_readline(stdin, input);
+
+            if(input[0] != '\0') {
+               ou.in.name = talloc_strdup(mem_ctx, input);
+            }
+            else {
+               printf("Enter RID: 0x");
+               scanf("%x", &ou.in.rid);
+            }
+            
+            ou.in.access   = MAXIMUM_ALLOWED_ACCESS;
+            ou.in.dom_hnd  = sod.out.dom_hnd;
+
+            if(!cac_SamOpenUser(hnd, mem_ctx, &ou)) {
+               fprintf(stderr, "Could not open user %s. Error: %s\n", ou.in.name, nt_errstr(hnd->status));
+               break;
+            }
+
+            /*now find the groups*/
+            gg.in.user_hnd = ou.out.user_hnd;
+
+            if(!cac_SamGetGroupsForUser(hnd, mem_ctx, &gg)) {
+               fprintf(stderr, "Could not get groups for user. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            cac_SamClose(hnd, mem_ctx, ou.out.user_hnd);
+
+            ZERO_STRUCT(gn);
+
+            gn.in.dom_hnd = sod.out.dom_hnd;
+            gn.in.num_rids = gg.out.num_groups;
+            gn.in.rids  = gg.out.rids;
+
+            if(!cac_SamGetNamesFromRids(hnd, mem_ctx, &gn)) {
+               fprintf(stderr, "Could not get names from RIDs. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            printf("%d groups: \n", gn.out.num_names);
+
+            for(i = 0; i < gn.out.num_names; i++) {
+               printf("RID: 0x%x ", gn.out.map[i].rid);
+
+               if(gn.out.map[i].found)
+                  printf("Name: %s\n", gn.out.map[i].name);
+               else
+                  printf("Unknown RID\n");
+            }
+
+            break;
+
+         case 'z': /*close group*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            if(!cac_SamClose(hnd, mem_ctx, group_hnd)) {
+               printf("Could not close group\n");
+               break;
+            }
+
+            group_hnd = NULL;
+            break;
+
+         case 'i': /*get group info*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gi);
+            gi.in.group_hnd = group_hnd;
+
+            if(!cac_SamGetGroupInfo(hnd, mem_ctx, &gi)) {
+               printf("Could not get group info. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Retrieved Group info\n");
+               print_cac_group_info(gi.out.info);
+            }
+            
+            break;
+
+         case 'e': /*edit group info*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gi);
+            ZERO_STRUCT(si);
+
+            gi.in.group_hnd = group_hnd;
+            
+            if(!cac_SamGetGroupInfo(hnd, mem_ctx, &gi)) {
+               printf("Could not get group info. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            edit_cac_group_info(mem_ctx, gi.out.info);
+
+            si.in.group_hnd = group_hnd;
+            si.in.info      = gi.out.info;
+
+            if(!cac_SamSetGroupInfo(hnd, mem_ctx, &si)) {
+               printf("Could not set group info. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf(" Done.\n");
+            }
+
+            break;
+
+         case 'n': /*rename group*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(rg);
+
+            printf("Enter new group name: ");
+            cactest_readline(stdin, tmp);
+
+            rg.in.group_hnd = group_hnd;
+            rg.in.new_name = talloc_strdup(mem_ctx, tmp);
+
+            if(!cac_SamRenameGroup(hnd, mem_ctx, &rg)) 
+               printf("Could not rename group. Error: %s\n", nt_errstr(hnd->status));
+            else
+               printf("Done.\n");
+
+            break;
+         case 't': /*get security info*/
+            if(!group_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gso);
+
+            gso.in.pol = group_hnd;
+
+            if(!cac_SamGetSecurityObject(hnd, mem_ctx, &gso)) {
+               printf("Could not get security descriptor info. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Got it.\n");
+            }
+            break;
+            
+         case 'q':
+            break;
+
+         default:
+            printf("Invalid command\n");
+      }
+   }
+
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   if(group_hnd)
+      cac_SamClose(hnd, mem_ctx, group_hnd);
+
+done:
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/sam/samlookup.c b/examples/libmsrpc/test/sam/samlookup.c
new file mode 100644 (file)
index 0000000..32be50d
--- /dev/null
@@ -0,0 +1,140 @@
+/*lookup names or rids*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+            
+   
+   struct SamGetNamesFromRids sgn;
+   struct SamGetRidsFromNames sgr;
+
+   fstring tmp;
+   fstring input;
+   
+   int i;
+
+   mem_ctx = talloc_init("cac_samenum");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   tmp[0] = 0x00;
+   while(tmp[0] != 'q') {
+      printf("get [n]ames or get [r]ids or [q]uit: ");
+      cactest_readline(stdin, tmp);
+
+      switch(tmp[0]) {
+         case 'n':
+            ZERO_STRUCT(sgn);
+
+            sgn.in.dom_hnd = sod.out.dom_hnd;
+
+            printf("How many rids will you enter: ");
+            scanf("%d", &sgn.in.num_rids);
+
+            sgn.in.rids = talloc_array(mem_ctx, int, sgn.in.num_rids);
+            
+            for(i = 0; i < sgn.in.num_rids; i++) {
+               printf("  Enter RID %d: 0x", i);
+               scanf("%x", &sgn.in.rids[i]);
+            }
+
+            printf("Getting names...\n");
+
+            if(!cac_SamGetNamesFromRids(hnd, mem_ctx, &sgn)) {
+               fprintf(stderr, "could not lookup names. Error: %s\n", nt_errstr(hnd->status));
+               talloc_free(sgn.in.rids);
+               continue;
+            }
+
+            printf("Found %d names:\n", sgn.out.num_names);
+
+            for(i = 0; i < sgn.out.num_names; i++) {
+               printf(" RID:  0x%x ", sgn.out.map[i].rid);
+
+               if(sgn.out.map[i].found) {
+                  printf("Name: %s\n", sgn.out.map[i].name);
+               }
+               else {
+                  printf("Unknown RID\n");
+               }
+
+            }
+
+            break;
+
+         case 'r':
+            ZERO_STRUCT(sgr);
+
+            sgr.in.dom_hnd = sod.out.dom_hnd;
+
+            printf("How many names will you enter: ");
+            scanf("%d", &sgr.in.num_names);
+
+            sgr.in.names = talloc_array(mem_ctx, char *, sgr.in.num_names);
+
+            for(i = 0; i < sgr.in.num_names; i++) {
+               printf(" Enter name %d: ", (i+1));
+               cactest_readline(stdin, input);
+
+               sgr.in.names[i] = talloc_strdup(mem_ctx, input);
+            }
+
+            if(!cac_SamGetRidsFromNames(hnd, mem_ctx, &sgr)) {
+               fprintf(stderr, "Could not lookup names. Error: %s\n", nt_errstr(hnd->status));
+               continue;
+            }
+
+            printf("Found %d RIDs:\n", sgr.out.num_rids);
+
+            for(i = 0; i < sgr.out.num_rids; i++) {
+               printf(" Name: %s ", sgr.out.map[i].name);
+
+               if(sgr.out.map[i].found) {
+                  printf("RID: 0x%x\n", sgr.out.map[i].rid);
+               }
+               else {
+                  printf("Unknown name\n");
+               }
+            }
+
+            break;
+         case 'q':
+            printf("\n");
+            break;
+         default:
+            printf("Invalid command!\n");
+      }
+   }
+
+
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+   cac_SamClose(hnd, mem_ctx, sod.out.sam);
+
+done:
+   talloc_destroy(mem_ctx);
+   cac_FreeHandle(hnd);
+
+   return 0;
+
+}
+
diff --git a/examples/libmsrpc/test/sam/samuser.c b/examples/libmsrpc/test/sam/samuser.c
new file mode 100644 (file)
index 0000000..df56a2d
--- /dev/null
@@ -0,0 +1,294 @@
+/*Some user management stuff*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+            
+   
+   struct SamOpenUser    ou;
+   struct SamEnumUsers   eu;
+   struct SamCreateUser  cu;
+   struct SamGetUserInfo gi;
+   struct SamSetUserInfo si;
+   struct SamRenameUser  ru;
+   struct SamSetPassword sp;
+
+   POLICY_HND *user_hnd = NULL;
+
+   fstring tmp;
+   fstring input;
+
+   char *pass1 = NULL;
+   char *pass2 = NULL;
+   
+   int i;
+
+   mem_ctx = talloc_init("cac_samgroup");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   struct SamOpenDomain sod;
+   ZERO_STRUCT(sod);
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS; 
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod)) {
+      fprintf(stderr, "Could not open domain. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   tmp[0] = 0x00;
+   while(tmp[0] != 'q') {
+      printf("\n");
+      printf("[l]ist users\n");
+      printf("[c]reate user\n");
+      printf("[o]pen user\n");
+      printf("[d]elete user\n");
+      printf("[g]et user info\n");
+      printf("[e]dit user info\n");
+      printf("[r]ename user\n");
+      printf("reset [p]assword\n");
+      printf("[n] close user\n");
+
+      printf("[q]uit\n\n");
+      printf("Enter option: ");
+      cactest_readline(stdin, tmp);
+
+      printf("\n");
+
+      switch(tmp[0]) {
+         case 'c': /*create user*/
+            if(user_hnd != NULL) {
+               /*then we have an open handle.. close it*/
+               cac_SamClose(hnd, mem_ctx, user_hnd);
+               user_hnd = NULL;
+            }
+
+            printf("Enter user name: ");
+            cactest_readline(stdin, input);
+
+            ZERO_STRUCT(cu);
+
+            cu.in.name      = talloc_strdup(mem_ctx, input);
+            cu.in.dom_hnd   = sod.out.dom_hnd;
+            cu.in.acb_mask  = ACB_NORMAL;
+
+            if(!cac_SamCreateUser(hnd, mem_ctx, &cu)) {
+               printf("Could not create user. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Created user %s with RID 0x%x\n", cu.in.name, cu.out.rid);
+               user_hnd = cu.out.user_hnd;
+            }
+
+            break;
+
+         case 'o': /*open group*/
+            if(user_hnd != NULL) {
+               /*then we have an open handle.. close it*/
+               cac_SamClose(hnd, mem_ctx, user_hnd);
+               user_hnd = NULL;
+            }
+
+            ZERO_STRUCT(ou);
+
+            ou.in.dom_hnd = sod.out.dom_hnd;
+            ou.in.access = MAXIMUM_ALLOWED_ACCESS;
+
+            printf("Enter RID: 0x");
+            scanf("%x", &ou.in.rid);
+
+            if(!cac_SamOpenUser(hnd, mem_ctx, &ou)) {
+               fprintf(stderr, "Could not open user. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Opened user\n");
+               user_hnd = ou.out.user_hnd;
+            }
+
+            break;
+
+         case 'l': /*list users*/
+            ZERO_STRUCT(eu);
+            eu.in.dom_hnd = sod.out.dom_hnd;
+
+            while(cac_SamEnumUsers(hnd, mem_ctx, &eu)) {
+               for(i = 0; i < eu.out.num_users; i++) {
+                  printf("RID: 0x%x Name: %s\n", eu.out.rids[i], eu.out.names[i]);
+               }
+            }
+
+            if(CAC_OP_FAILED(hnd->status)) {
+               printf("Could not enumerate Users. Error: %s\n", nt_errstr(hnd->status));
+            }
+
+            break;
+            
+            break;
+
+         case 'd': /*delete group*/
+            if(!user_hnd) {
+               printf("Must open group first!\n");
+               break;
+            }
+
+            if(!cac_SamDeleteGroup(hnd, mem_ctx, user_hnd)) {
+               fprintf(stderr, "Could not delete group. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Deleted group.\n");
+               user_hnd = NULL;
+            }
+            break;
+
+         
+         case 'n':
+            if(!user_hnd) {
+               printf("Must open user first!\n");
+               break;
+            }
+
+            if(!cac_SamClose(hnd, mem_ctx, user_hnd)) {
+               printf("Could not user group\n");
+               break;
+            }
+
+            user_hnd = NULL;
+            break;
+
+         case 'g': /*get user info*/
+            if(!user_hnd) {
+               printf("Must open user first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gi);
+            gi.in.user_hnd = ou.out.user_hnd;
+
+            if(!cac_SamGetUserInfo(hnd, mem_ctx, &gi)) {
+               printf("Could not get user info. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Retrieved User information:\n");
+               print_cac_user_info(gi.out.info);
+            } 
+
+            break;
+
+         case 'e': /*edit user info*/
+            if(!user_hnd) {
+               printf("Must Open user first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gi);
+            gi.in.user_hnd = ou.out.user_hnd;
+            if(!cac_SamGetUserInfo(hnd, mem_ctx, &gi)) {
+               printf("Could not get user info. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+            
+            edit_cac_user_info(mem_ctx, gi.out.info);
+
+            printf("setting following info:\n");
+            print_cac_user_info(gi.out.info);
+
+            ZERO_STRUCT(si);
+
+            si.in.user_hnd = user_hnd;
+            si.in.info     = gi.out.info;
+
+            if(!cac_SamSetUserInfo(hnd, mem_ctx, &si)) {
+               printf("Could not set user info. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Done.\n");
+            }
+
+            break;
+
+         case 'r': /*rename user*/
+            if(!user_hnd) {
+               printf("Must open user first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(ru);
+
+            printf("Enter new username: ");
+            cactest_readline(stdin, tmp);
+
+            ru.in.user_hnd = user_hnd;
+            ru.in.new_name = talloc_strdup(mem_ctx, tmp);
+
+            if(!cac_SamRenameUser(hnd, mem_ctx, &ru)) {
+               printf("Could not rename user. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Renamed user\n");
+            }
+
+            break;
+
+         case 'p': /*reset password*/
+
+            if(!user_hnd) {
+               printf("Must open user first!\n");
+               break;
+            }
+
+            do {
+               if(pass1 && pass2) {
+                  printf("Passwords do not match. Please try again\n");
+               }
+
+               pass1 = getpass("Enter new password: ");
+               pass2 = getpass("Re-enter new password: ");
+            } while(strncmp(pass1, pass2, MAX_PASS_LEN));
+
+            ZERO_STRUCT(sp);
+            sp.in.user_hnd = user_hnd;
+            sp.in.password = talloc_strdup(mem_ctx, pass1);
+
+            if(!cac_SamSetPassword(hnd, mem_ctx, &sp)) {
+               printf("Could not set password. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Done.\n");
+            }
+
+            break;
+
+         case 'q':
+            break;
+
+         default:
+            printf("Invalid command\n");
+      }
+   }
+
+   cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   if(user_hnd)
+      cac_SamClose(hnd, mem_ctx, user_hnd);
+
+done:
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/smbc_test/smbc.c b/examples/libmsrpc/test/smbc_test/smbc.c
new file mode 100644 (file)
index 0000000..3db3cea
--- /dev/null
@@ -0,0 +1,87 @@
+/*simple test for libsmbclient compatibility. initialize a smbc context, open sessions on a couple pipes and quit*/
+
+#include "libmsrpc.h"
+#include "libsmbclient.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   SMBCCTX *ctx = NULL;
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+
+   struct LsaOpenPolicy lop;
+   struct RegConnect    rc;
+   struct SamOpenDomain sod;
+
+   ZERO_STRUCT(lop);
+   ZERO_STRUCT(rc);
+   ZERO_STRUCT(sod);
+
+   mem_ctx = talloc_init("cac_smbc");
+   if(!mem_ctx) {
+      printf("Could not initialize talloc context\n");
+      exit(-1);
+   }
+   
+   hnd = cac_NewServerHandle(True);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   /*initialize smbc context*/
+   if( (ctx = smbc_new_context()) == NULL) {
+      exit(1);
+   }
+
+   /*this probably isn't what someone would want to do, but it initializes the values we need*/
+   ctx->debug = hnd->debug;
+   ctx->callbacks.auth_fn = cac_GetAuthDataFn;
+   
+
+   if(smbc_init_context(ctx) == NULL)
+      exit(1);
+
+   cac_SetSmbcContext(hnd, ctx);
+
+   /*still have to call cac_Connect()*/
+   if(!cac_Connect(hnd, NULL)) {
+      printf("Could not connect to server\n");
+      exit(1);
+   }
+
+   lop.in.access = MAXIMUM_ALLOWED_ACCESS;
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop))
+      printf("Could not open LSA policy. Error: %s\n", nt_errstr(hnd->status));
+
+   printf("Opened LSA policy.\n");
+
+   rc.in.access = MAXIMUM_ALLOWED_ACCESS;
+   rc.in.root   = HKEY_LOCAL_MACHINE;
+   if(!cac_RegConnect(hnd, mem_ctx, &rc))
+      printf("Could not connect to registry. Error: %s\n", nt_errstr(hnd->status));
+
+   printf("Connceted to Registry.\n");
+
+   sod.in.access = MAXIMUM_ALLOWED_ACCESS;
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &sod))
+      printf("Could not open domain SAM. Error: %s\n", nt_errstr(hnd->status));
+
+   printf("Opened domain.\n");
+
+   if(lop.out.pol)
+      cac_LsaClosePolicy(hnd, mem_ctx, lop.out.pol);
+
+   if(rc.out.key)
+      cac_RegClose(hnd, mem_ctx, rc.out.key);
+
+   if(sod.out.sam)
+      cac_SamClose(hnd, mem_ctx, sod.out.sam);
+
+   if(sod.out.dom_hnd)
+      cac_SamClose(hnd, mem_ctx, sod.out.dom_hnd);
+
+   cac_FreeHandle(hnd);
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
diff --git a/examples/libmsrpc/test/svcctl/svc.c b/examples/libmsrpc/test/svcctl/svc.c
new file mode 100644 (file)
index 0000000..db5fa27
--- /dev/null
@@ -0,0 +1,303 @@
+/*Tests all of the svcctl calls (at least at time of writing)*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+int main(int argc, char **argv) {
+   CacServerHandle *hnd = NULL;
+   TALLOC_CTX *mem_ctx = NULL;
+            
+
+   struct SvcOpenScm      sos;
+   struct SvcEnumServices es;
+   struct SvcOpenService  os;
+   struct SvcGetStatus    gs;
+   struct SvcStartService start;
+   struct SvcStopService  stop;
+   struct SvcPauseService pause;
+   struct SvcContinueService res;
+   struct SvcGetDisplayName gdn;
+   struct SvcGetServiceConfig sgc;
+  
+   POLICY_HND *svc_hnd = NULL;
+
+   fstring tmp;
+   fstring input;
+   
+   int i;
+
+   mem_ctx = talloc_init("cac_samgroup");
+
+   hnd = cac_NewServerHandle(True);
+
+   cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn);
+
+   cac_parse_cmd_line(argc, argv, hnd);
+
+   if(!cac_Connect(hnd, NULL)) {
+      fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status));
+      exit(-1);
+   }
+
+   /*open a handle to the scm*/
+   ZERO_STRUCT(sos);
+
+   sos.in.access = SC_MANAGER_ALL_ACCESS;
+
+   if(!cac_SvcOpenScm(hnd, mem_ctx, &sos)) {
+      fprintf(stderr, "Could not open SCM. Error: %s\n", nt_errstr(hnd->status));
+      goto done;
+   }
+
+   printf("Opened SCM\n");
+
+   tmp[0] = 0x00;
+   while(tmp[0] != 'q') {
+      printf("\n");
+      printf("[e] Enum Services\n");
+      printf("[o] Open Service\n");
+      printf("[x] Close Service\n");
+      printf("[g] Get service status\n");
+      printf("[s] Start service\n");
+      printf("[t] Stop service\n");
+      printf("[p] Pause service\n");
+      printf("[r] Resume service\n");
+      printf("[c] Get service config\n");
+
+      printf("[d] Get display name\n");
+
+      printf("[q]uit\n\n");
+      printf("Enter option: ");
+      cactest_readline(stdin, tmp);
+
+      printf("\n");
+
+      switch(tmp[0]) {
+         case 'e': /*enum services*/
+            ZERO_STRUCT(es);
+            es.in.scm_hnd = sos.out.scm_hnd;
+
+            if(!cac_SvcEnumServices(hnd, mem_ctx, &es)) {
+               printf("Could not enumerate services. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            for(i = 0; i < es.out.num_services; i++) {
+               print_cac_service(es.out.services[i]);
+            }
+            printf("Enumerated %d services:\n", es.out.num_services);
+
+            break;
+
+         case 'o': /*Open service*/
+            ZERO_STRUCT(os);
+
+            printf("Enter service name: ");
+            cactest_readline(stdin, tmp);
+
+            os.in.name = talloc_strdup(mem_ctx, tmp);
+            os.in.scm_hnd = sos.out.scm_hnd;
+            os.in.access = SERVICE_ALL_ACCESS;
+
+            if(!cac_SvcOpenService(hnd, mem_ctx, &os)) {
+               printf("Could not open service. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+            
+            printf("Opened service.\n");
+            svc_hnd = os.out.svc_hnd;
+
+            break;
+         case 'x': /*close service*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            cac_SvcClose(hnd, mem_ctx, svc_hnd);
+            svc_hnd = NULL;
+            break;
+         case 'g': /*get svc status*/
+            
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gs);
+
+            gs.in.svc_hnd = svc_hnd;
+
+            if(!cac_SvcGetStatus(hnd, mem_ctx, &gs)) {
+               printf("Could not get status. Error: %s\n", nt_errstr(hnd->status));
+               break;
+            }
+
+            print_service_status(gs.out.status);
+            break;
+         case 's': /*start service*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(start);
+
+            start.in.svc_hnd = svc_hnd;
+
+            printf("Enter number of parameters: ");
+            scanf("%d", &start.in.num_parms);
+
+            start.in.parms = talloc_array(mem_ctx, char *, start.in.num_parms);
+
+            for(i = 0; i < start.in.num_parms; i++) {
+               printf("Parm %d: ", i);
+               cactest_readline(stdin, tmp);
+               start.in.parms[i] = talloc_strdup(mem_ctx, tmp);
+            }
+
+            printf("Timeout (seconds): ");
+            scanf("%d", &start.in.timeout);
+
+            if(!cac_SvcStartService(hnd, mem_ctx, &start)) {
+               printf("Could not start service. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("Started service.\n");
+            }
+
+            break;
+         case 't': /*stop service*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(stop);
+            stop.in.svc_hnd = svc_hnd;
+
+            printf("Timeout (seconds): ");
+            scanf("%d", &stop.in.timeout);
+
+            if(!cac_SvcStopService(hnd, mem_ctx, &stop)) {
+               if(CAC_OP_FAILED(hnd->status)) {
+                  printf("Error occured: %s\n", nt_errstr(hnd->status));
+               }
+               else {
+                  printf("Service was not stopped within %d seconds.\n", stop.in.timeout);
+                  print_service_status(stop.out.status);
+               }
+            }
+            else {
+               printf("Done.\n");
+               print_service_status(stop.out.status);
+            }
+            break;
+         case 'd': /*get display name*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(gdn);
+            gdn.in.svc_hnd = svc_hnd;
+
+            if(!cac_SvcGetDisplayName(hnd, mem_ctx, &gdn)) {
+               printf("Could not get display name. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               printf("\tDisplay Name: %s\n", gdn.out.display_name);
+            }
+            break;
+
+         case 'p': /*pause service*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(pause);
+            pause.in.svc_hnd = svc_hnd;
+
+            printf("Timeout (seconds): ");
+            scanf("%d", &pause.in.timeout);
+
+            if(!cac_SvcPauseService(hnd, mem_ctx, &pause)) {
+               if(CAC_OP_FAILED(hnd->status)) {
+                  printf("Error occured: %s\n", nt_errstr(hnd->status));
+               }
+               else {
+                  printf("Service was not paused within %d seconds.\n", pause.in.timeout);
+                  print_service_status(pause.out.status);
+               }
+            }
+            else {
+               printf("Done.\n");
+               print_service_status(pause.out.status);
+            }
+
+            break;
+            
+         case 'r': /*resume service*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(res);
+            res.in.svc_hnd = svc_hnd;
+
+            printf("Timeout (seconds): ");
+            scanf("%d", &res.in.timeout);
+
+            if(!cac_SvcContinueService(hnd, mem_ctx, &res)) {
+               if(CAC_OP_FAILED(hnd->status)) {
+                  printf("Error occured: %s\n", nt_errstr(hnd->status));
+               }
+               else {
+                  printf("Service was not resumed within %d seconds.\n", res.in.timeout);
+                  print_service_status(res.out.status);
+               }
+            }
+            else {
+               printf("Done.\n");
+               print_service_status(res.out.status);
+            }
+
+            break;
+
+         case 'c': /*get service config*/
+            if(!svc_hnd) {
+               printf("Must open service first!\n");
+               break;
+            }
+
+            ZERO_STRUCT(sgc);
+
+            sgc.in.svc_hnd = svc_hnd;
+
+            if(!cac_SvcGetServiceConfig(hnd, mem_ctx, &sgc)) {
+               printf("Could not get service config. Error: %s\n", nt_errstr(hnd->status));
+            }
+            else {
+               print_service_config(&sgc.out.config);
+            }
+            break;
+
+         case 'q': /*quit*/
+            break;
+         default:
+            printf("Invalid command\n");
+      }
+   }
+
+   cac_SvcClose(hnd, mem_ctx, sos.out.scm_hnd);
+
+   done:
+   cac_FreeHandle(hnd);
+
+   talloc_destroy(mem_ctx);
+
+   return 0;
+}
+
diff --git a/examples/libmsrpc/test/test_util.c b/examples/libmsrpc/test/test_util.c
new file mode 100644 (file)
index 0000000..81a9c92
--- /dev/null
@@ -0,0 +1,408 @@
+/*some utility functions for the registry tests*/
+
+#include "libmsrpc.h"
+#include "test_util.h"
+
+
+void cactest_print_usage(char **argv) {
+   printf("Usage:\n");
+   printf("  %s server [-U username] [-W domain] [-P passwprd] [-N netbios_name]\n", argv[0]);
+}
+
+/*allocates memory for auth info and parses domain/user/server out of command line*/
+void cac_parse_cmd_line(int argc, char **argv, CacServerHandle *hnd) {
+   int i = 0;
+
+   ZERO_STRUCTP(hnd->username);
+   ZERO_STRUCTP(hnd->domain);
+   ZERO_STRUCTP(hnd->netbios_name);
+   ZERO_STRUCTP(hnd->password);
+
+   for(i = 1; i < argc; i++) {
+      if( strncmp(argv[i], "-U", sizeof(fstring)) == 0) {
+         strncpy(hnd->username, argv[i+1], sizeof(fstring));
+         i++;
+      }
+
+      else if(strncmp(argv[i], "-W", sizeof(fstring)) == 0) {
+         strncpy(hnd->domain, argv[i+1], sizeof(fstring));
+         i++;
+
+      }
+
+      else if(strncmp(argv[i], "-P", sizeof(fstring)) == 0) {
+         strncpy(hnd->password, argv[i+1], sizeof(fstring));
+         i++;
+
+      }
+
+      else if(strncmp(argv[i], "-N", sizeof(fstring)) == 0) {
+         strncpy(hnd->netbios_name, argv[i+1], sizeof(fstring));
+         i++;
+      }
+
+      else if(strncmp(argv[i], "-d", sizeof(fstring)) == 0) {
+         sscanf(argv[i+1], "%d", &hnd->debug);
+         i++;
+      }
+
+      else { /*assume this is the server name*/
+         strncpy(hnd->server, argv[i], sizeof(fstring));
+      }
+   }
+
+   if(!hnd->server) {
+      cactest_print_usage(argv);
+      cac_FreeHandle(hnd);
+      exit(-1);
+   }
+
+}
+
+void print_value(uint32 type, REG_VALUE_DATA *data) {
+   int i = 0;
+
+   switch(type) {
+      case REG_SZ:
+         printf(" Type: REG_SZ\n");
+         printf(" Value: %s\n", data->reg_sz);
+         break;
+      case REG_EXPAND_SZ:
+         printf(" Type: REG_EXPAND_SZ\n");
+         printf(" Value: %s\n", data->reg_expand_sz);
+         break;
+      case REG_MULTI_SZ:
+         printf(" Type: REG_MULTI_SZ\n");
+         printf(" Values: ");
+
+         for(i = 0; i < data->reg_multi_sz.num_strings; i++) {
+            printf("     %d: %s\n", i, data->reg_multi_sz.strings[i]);
+         }
+         break;
+      case REG_DWORD:
+         printf(" Type: REG_DWORD\n");
+         printf(" Value: %d\n", data->reg_dword);
+         break;
+      case REG_DWORD_BE:
+         printf(" Type: REG_DWORD_BE\n");
+         printf(" Value: 0x%x\n", data->reg_dword_be);
+         break;
+      case REG_BINARY:
+         printf(" Type: REG_BINARY\n");
+         break;
+      default:
+         printf(" Invalid type: %d\n", type);
+         
+   }
+
+   printf("\n");
+   
+}
+
+void cactest_readline(FILE *in, fstring line) {
+
+   int c;
+   
+   c = fgetc(in);
+   if(c != '\n')
+      ungetc(c, in);
+
+   fgets(line, sizeof(fstring), in);
+
+   if(line[strlen(line) - 1] == '\n')
+      line[strlen(line) - 1] = '\0';
+
+}
+
+void cactest_GetAuthDataFn(const char * pServer,
+                 const char * pShare,
+                 char * pWorkgroup,
+                 int maxLenWorkgroup,
+                 char * pUsername,
+                 int maxLenUsername,
+                 char * pPassword,
+                 int maxLenPassword)
+    
+{
+   char temp[sizeof(fstring)];
+
+   static char authUsername[sizeof(fstring)];
+   static char authWorkgroup[sizeof(fstring)];
+   static char authPassword[sizeof(fstring)];
+   static char authSet = 0;
+
+   char *pass = NULL;
+
+   if (authSet)
+   {
+      strncpy(pWorkgroup, authWorkgroup, maxLenWorkgroup - 1);
+      strncpy(pUsername, authUsername, maxLenUsername - 1);
+      strncpy(pPassword, authPassword, maxLenPassword - 1);
+   }
+   else
+   {
+      if(pWorkgroup[0] != '\0') {
+         strncpy(authWorkgroup, pWorkgroup, maxLenWorkgroup - 1);
+      }
+      else {
+         d_printf("Domain: [%s] ", pWorkgroup);
+         fscanf(stdin, "%s", temp);
+
+         if (temp[0] != '\0')
+         {
+            strncpy(pWorkgroup, temp, maxLenWorkgroup - 1);
+            strncpy(authWorkgroup, temp, maxLenWorkgroup - 1);
+         }
+      }
+
+
+      if(pUsername[0] != '\0') {
+         strncpy(authUsername, pUsername, maxLenUsername - 1);
+      }
+      else {
+         d_printf("Username: [%s] ", pUsername);
+         fscanf(stdin, "%s", temp);
+
+         if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+         {
+            temp[strlen(temp) - 1] = '\0';
+         }
+
+         if (temp[0] != '\0')
+         {
+            strncpy(pUsername, temp, maxLenUsername - 1);
+            strncpy(authUsername, pUsername, maxLenUsername - 1);
+         }
+      }
+      if(pPassword[0] != '\0') {
+         strncpy(authPassword, pPassword, maxLenPassword - 1);
+      }
+      else {
+         pass = getpass("Password: ");
+         if (pass)
+            fstrcpy(temp, pass);
+         if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+         {
+            temp[strlen(temp) - 1] = '\0';
+         }        
+         if (temp[0] != '\0')
+         {
+            strncpy(pPassword, temp, maxLenPassword - 1);
+            strncpy(authPassword, pPassword, maxLenPassword - 1);
+         }    
+      }
+      authSet = 1;
+   }
+}
+
+void cactest_reg_input_val(TALLOC_CTX *mem_ctx, int *type, char **name, REG_VALUE_DATA *data) {
+   fstring tmp;
+   int i;
+
+   printf("Enter value name: \n");
+   cactest_readline(stdin, tmp);
+   *name = talloc_strdup(mem_ctx, tmp);
+
+   do {
+      printf("Enter type. %d = REG_SZ, %d = REG_DWORD, %d = REG_MULTI_SZ: ", REG_SZ, REG_DWORD, REG_MULTI_SZ);
+      scanf("%d", type);
+   } while(*type != REG_SZ && *type != REG_DWORD && *type != REG_MULTI_SZ);
+
+   switch(*type) {
+      case REG_SZ:
+         printf("Enter string:\n");
+         cactest_readline(stdin, tmp);
+
+         data->reg_sz = talloc_strdup(mem_ctx, tmp);
+         break;
+
+      case REG_DWORD:
+         printf("Enter dword: ");
+         scanf("%d", &data->reg_dword);
+         break;
+
+      case REG_MULTI_SZ:
+         printf("Enter number of strings: ");
+         scanf("%d", &data->reg_multi_sz.num_strings);
+         
+         data->reg_multi_sz.strings = talloc_array(mem_ctx, char *, data->reg_multi_sz.num_strings);
+
+         for(i = 0; i < data->reg_multi_sz.num_strings; i++) {
+            printf("String %d: ", i+1);
+            cactest_readline(stdin, tmp);
+
+            data->reg_multi_sz.strings[i] = talloc_strdup(mem_ctx, tmp);
+         }
+         break;
+   }
+}
+
+void print_cac_user_info(CacUserInfo *info) {
+   printf("    User Name    : %s\n", info->username);
+   printf("    Full Name    : %s\n", info->full_name);
+   printf("    Home Dir     : %s\n", info->home_dir);
+   printf("    Home Drive   : %s\n", info->home_drive);
+   printf("    Profile Path : %s\n", info->profile_path);
+   printf("    Logon Script : %s\n", info->logon_script);
+   printf("    Description  : %s\n", info->description);
+   printf("    Workstations : %s\n", info->workstations);
+   printf("    Remote Dial  : %s\n", info->dial);
+
+   printf("    Logon Time   : %s\n", http_timestring(info->logon_time));
+   printf("    Logoff Time  : %s\n", http_timestring(info->logoff_time));
+   printf("    Kickoff Time : %s\n", http_timestring(info->kickoff_time));
+   printf("    Pass last set: %s\n", http_timestring(info->pass_last_set_time));
+   printf("    Pass can set : %s\n", http_timestring(info->pass_can_change_time));
+   printf("    Pass must set: %s\n", http_timestring(info->pass_must_change_time));
+
+   printf("    User RID     : 0x%x\n", info->rid);
+   printf("    Group RID    : 0x%x\n", info->group_rid);
+   printf("    ACB Mask     : 0x%x\n", info->acb_mask);
+
+   printf("    Bad pwd count: %d\n", info->bad_passwd_count);
+   printf("    Logon Cuont  : %d\n", info->logon_count);
+
+   printf(" NT Password  : %s\n", info->nt_password);
+   printf(" LM Password  : %s\n", info->lm_password);
+
+}
+
+void edit_readline(fstring line) {
+   fgets(line, sizeof(fstring), stdin);
+
+   if(line[strlen(line)-1] == '\n')
+      line[strlen(line)-1] = '\0';
+}
+void edit_cac_user_info(TALLOC_CTX *mem_ctx, CacUserInfo *info) {
+   fstring tmp;
+
+   printf(" User Name [%s]: ", info->username);
+   edit_readline(tmp);
+
+   if(tmp[0] != '\0')
+      info->username = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Full Name [%s]: ", info->full_name);
+
+   edit_readline(tmp);
+   if(tmp[0] != '\0')
+      info->full_name = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Description [%s]: ", info->description);
+   edit_readline(tmp);
+   if(tmp[0] != '\0')
+      info->description = talloc_strdup(mem_ctx, tmp);
+
+   printf(" Remote Dial [%s]: ", info->dial);
+   edit_readline(tmp);
+   if(tmp[0] != '\0')
+      info->dial = talloc_strdup(mem_ctx, tmp);
+
+   printf(" ACB Mask [0x%x]: ", info->acb_mask);
+   edit_readline(tmp);
+   if(tmp[0] != '\0') 
+      sscanf(tmp, "%x", &info->acb_mask);
+
+   printf(" Must change pass at next logon? [y/N]: ");
+   edit_readline(tmp);
+
+   if(tmp[0] == 'y' || tmp[0] == 'Y')
+      info->pass_must_change= True;
+
+}
+   
+void print_cac_group_info(CacGroupInfo *info) {
+   printf(" Group Name  : %s\n", info->name);
+   printf(" Description : %s\n", info->description);
+   printf(" Num Members : %d\n", info->num_members);
+}
+
+void edit_cac_group_info(TALLOC_CTX *mem_ctx, CacGroupInfo *info) {
+   fstring tmp;
+
+   printf("Group Name [%s]: ", info->name);
+   edit_readline(tmp);
+   if(tmp[0] != '\0')
+      info->name = talloc_strdup(mem_ctx, tmp);
+
+   printf("Description [%s]: ", info->description);
+   edit_readline(tmp);
+   if(tmp[0] != '\0')
+      info->description = talloc_strdup(mem_ctx, tmp);
+}
+
+char *srv_role_str(uint32 role) {
+   switch(role) {
+      case ROLE_STANDALONE:
+         return "STANDALONE";
+         break;
+      case ROLE_DOMAIN_MEMBER:
+         return "DOMAIN_MEMBER";
+         break;
+      case ROLE_DOMAIN_BDC:
+         return "DOMAIN_BDC";
+         break;
+      case ROLE_DOMAIN_PDC:
+         return "DOMAIN_PDC";
+         break;
+   }
+
+   return "Invalid role!\n";
+}
+
+char *cactime_str(CacTime ctime, fstring tmp) {
+
+   snprintf(tmp, sizeof(fstring), "%u Days, %u Hours, %u Minutes, %u Seconds", ctime.days, ctime.hours, ctime.minutes, ctime.seconds);
+
+   return tmp;
+}
+
+void print_cac_domain_info(CacDomainInfo *info) {
+   fstring tmp;
+   
+   printf("  Server Role      : %s\n", srv_role_str(info->server_role));
+   printf("  Num Users        : %d\n", info->num_users);
+   printf("  Num Domain Groups: %d\n", info->num_domain_groups);
+   printf("  Num Local Groups : %d\n", info->num_local_groups);
+   printf("  Comment          : %s\n", info->comment);
+   printf("  Domain Name      : %s\n", info->domain_name);
+   printf("  Server Name      : %s\n", info->server_name);
+   printf("  Min. Pass. Length: %d\n", info->min_pass_length);
+   printf("  Password History : %d\n", info->pass_history);
+   printf("\n");
+   printf("  Passwords Expire In    : %s\n", cactime_str(info->expire, tmp));
+   printf("  Passwords Can Change in: %s\n", cactime_str(info->min_pass_age, tmp));
+   printf("  Lockouts last          : %s\n", cactime_str(info->lockout_duration, tmp));
+   printf("  Allowed Bad Attempts   : %d\n", info->num_bad_attempts);
+}
+
+void print_cac_service(CacService svc) {
+   printf("\tService Name: %s\n", svc.service_name);
+   printf("\tDisplay Name: %s\n", svc.display_name);
+   print_service_status(svc.status);
+}
+
+void print_service_status(SERVICE_STATUS status) {
+   printf("\tStatus:\n");
+   printf("\t Type:          0x%x\n", status.type); 
+   printf("\t State:         0x%x\n", status.state);
+   printf("\t Controls:      0x%x\n", status.controls_accepted);
+   printf("\t W32 Exit Code: 0x%x\n", status.win32_exit_code);
+   printf("\t SVC Exit Code: 0x%x\n", status.service_exit_code);
+   printf("\t Checkpoint:    0x%x\n", status.check_point);
+   printf("\t Wait Hint:     0x%x\n", status.wait_hint);
+   printf("\n");
+}
+
+void print_service_config(CacServiceConfig *config) {
+   printf("\tConfig:\n");
+   printf("\tType:             0x%x\n", config->type);
+   printf("\tStart Type:       0x%x\n", config->start_type);
+   printf("\tError config:     0x%x\n", config->error_control);
+   printf("\tExecutable Path:  %s\n", config->exe_path);
+   printf("\tLoad Order Group: %s\n", config->load_order_group);
+   printf("\tTag ID:           0x%x\n", config->tag_id);
+   printf("\tDependencies:     %s\n", config->dependencies);
+   printf("\tStart Name:       %s\n", config->start_name);
+   printf("\tDisplay Name:     %s\n", config->display_name);
+}
diff --git a/examples/libmsrpc/test/test_util.h b/examples/libmsrpc/test/test_util.h
new file mode 100644 (file)
index 0000000..9b27599
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef TEST_UTIL_H
+#define TEST_UTIL_H
+
+#include "libmsrpc.h"
+
+/*prototypes*/
+void cactest_GetAuthDataFn(const char * pServer,
+                 const char * pShare,
+                 char * pWorkgroup,
+                 int maxLenWorkgroup,
+                 char * pUsername,
+                 int maxLenUsername,
+                 char * pPassword,
+                 int maxLenPassword);
+
+
+void cactest_print_usage(char **argv);
+void cac_parse_cmd_line(int argc, char **argv, CacServerHandle *hnd);
+void print_value(uint32 type, REG_VALUE_DATA *data);
+void cactest_readline(FILE *in, fstring line);
+void cactest_reg_input_val(TALLOC_CTX *mem_ctx, int *type, char **name, REG_VALUE_DATA *data);
+void print_cac_user_info(CacUserInfo *info);
+void edit_cac_user_info(TALLOC_CTX *mem_ctx, CacUserInfo *info);
+void print_cac_group_info(CacGroupInfo *info);
+void edit_cac_group_info(TALLOC_CTX *mem_ctx, CacGroupInfo *info);
+void print_cac_domain_info(CacDomainInfo *info);
+void print_cac_service(CacService svc);
+void print_service_status(SERVICE_STATUS status);
+void print_service_config(CacServiceConfig *config);
+
+#endif /*TEST_UTIL_H*/
diff --git a/source/include/libmsrpc.h b/source/include/libmsrpc.h
new file mode 100644 (file)
index 0000000..611db4f
--- /dev/null
@@ -0,0 +1,3048 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client library API definitions/prototypes
+ *
+ *  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.
+ */
+
+#ifndef LIBMSRPC_H
+#define LIBMSRPC_H
+
+
+#include "includes.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+/*server capability levels*/
+#define SRV_WIN_NT4     1
+#define SRV_WIN_2K      2
+#define SRV_WIN_2K_SP3  3
+#define SRV_WIN_2K3     4
+
+/**@defgroup handle Server Handle*/
+/**@defgroup Library_Functions Library/Utility Functions*/
+/**@defgroup lsa_defs LSA Definitions*/
+/**@defgroup LSA_Functions LSA Functions*/
+/**@defgroup reg_defs Registry Definitions*/
+/**@defgroup Reg_Functions Registry Functions*/
+/**@defgroup sam_defs SAM Definitions*/
+/**@defgroup SAM_Functions SAM Functions*/
+/**@defgroup svc_defs Service Control Definitions*/
+/**@defgroup SCM_Functions Service Control Functions*/
+
+/**Operation was unsuccessful*/
+#define CAC_FAILURE           0
+/**Operation was successful*/
+#define CAC_SUCCESS           1
+/**Operation was only partially successful
+ *  an example of this is if you try to lookup a list of accounts to SIDs and not all accounts can be resolved*/
+#define CAC_PARTIAL_SUCCESS   2
+
+/**@ingroup CAC_errors Use this to see if the last operation failed - useful for enumeration functions that use multiple calls*/
+#define CAC_OP_FAILED(status) !NT_STATUS_IS_OK(status) && \
+                              NT_STATUS_V(status) != NT_STATUS_V(STATUS_SOME_UNMAPPED) && \
+                              NT_STATUS_V(status) != NT_STATUS_V(STATUS_NO_MORE_FILES) && \
+                              NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_NO_MORE_ENTRIES) && \
+                              NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_NONE_MAPPED) && \
+                              NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_GUIDS_EXHAUSTED)
+
+
+/**Privilege string constants*/
+#define CAC_SE_CREATE_TOKEN            "SeCreateTokenPrivilege"
+#define CAC_SE_ASSIGN_PRIMARY_TOKEN    "SeAssignPrimaryTokenPrivilege"
+#define CAC_SE_LOCK_MEMORY             "SeLockMemoryPrivilege"
+#define CAC_SE_INCREASE_QUOTA          "SeIncreaseQuotaPrivilege"
+#define CAC_SE_MACHINE_ACCOUNT         "SeMachineAccountPrivilege"
+#define CAC_SE_TCB                     "SeTcbPrivilege"
+#define CAC_SE_SECURITY                "SeSecurityPrivilege"
+#define CAC_SE_TAKE_OWNERSHIP          "SeTakeOwnershipPrivilege"
+#define CAC_SE_LOAD_DRIVER             "SeLoadDriverPrivilege"
+#define CAC_SE_SYSTEM_PROFILE          "SeSystemProfilePrivilege"
+#define CAC_SE_SYSTEM_TIME             "SeSystemtimePrivilege"
+#define CAC_SE_PROFILE_SINGLE_PROC     "SeProfileSingleProcessPrivilege"
+#define CAC_SE_INCREASE_BASE_PRIORITY  "SeIncreaseBasePriorityPrivilege"
+#define CAC_SE_CREATE_PAGEFILE         "SeCreatePagefilePrivilege"
+#define CAC_SE_CREATE_PERMANENT        "SeCreatePermanentPrivilege"
+#define CAC_SE_BACKUP                  "SeBackupPrivilege"
+#define CAC_SE_RESTORE                 "SeRestorePrivilege"
+#define CAC_SE_SHUTDOWN                "SeShutdownPrivilege"
+#define CAC_SE_DEBUG                   "SeDebugPrivilege"
+#define CAC_SE_AUDIT                   "SeAuditPrivilege"
+#define CAC_SE_SYSTEM_ENV              "SeSystemEnvironmentPrivilege"
+#define CAC_SE_CHANGE_NOTIFY           "SeChangeNotifyPrivilege"
+#define CAC_SE_REMOTE_SHUTDOWN         "SeRemoteShutdownPrivilege"
+#define CAC_SE_UNDOCK                  "SeUndockPrivilege"
+#define CAC_SE_SYNC_AGENT              "SeSyncAgentPrivilege"
+#define CAC_SE_ENABLE_DELEGATION       "SeEnableDelegationPrivilege"
+#define CAC_SE_MANAGE_VOLUME           "SeManageVolumePrivilege"
+#define CAC_SE_IMPERSONATE             "SeImpersonatePrivilege"
+#define CAC_SE_CREATE_GLOBAL           "SeCreateGlobalPrivilege"
+#define CAC_SE_PRINT_OPERATOR          "SePrintOperatorPrivilege"
+#define CAC_SE_NETWORK_LOGON           "SeNetworkLogonRight"
+#define CAC_SE_INTERACTIVE_LOGON       "SeInteractiveLogonRight"
+#define CAC_SE_BATCH_LOGON             "SeBatchLogonRight"
+#define CAC_SE_SERVICE_LOGON           "SeServiceLogonRight"
+#define CAC_SE_ADD_USERS               "SeAddUsersPrivilege"
+#define CAC_SE_DISK_OPERATOR           "SeDiskOperatorPrivilege"
+
+/**
+ * @addtogroup lsa_defs
+ * @{
+ */
+/**used to specify what data to retrieve using cac_LsaQueryTrustedDomainInformation*/
+#define CAC_INFO_TRUSTED_DOMAIN_NAME         0x1
+#define CAC_INFO_TRUSTED_DOMAIN_POSIX_OFFSET 0x3
+#define CAC_INFO_TRUSTED_DOMAIN_PASSWORD     0x4
+
+/**Used when requesting machine domain information*/
+#define CAC_DOMAIN_INFO 0x0003
+
+/**Used when requesting machine local information*/
+#define CAC_LOCAL_INFO  0x0005
+
+/**Stores information about a SID*/
+typedef struct _CACSIDINFO {
+   /**The actual SID*/
+   DOM_SID sid;
+   
+   /**The name of the object which maps to this SID*/
+   char *name;
+
+   /**The domain the SID belongs to*/
+   char *domain;
+} CacSidInfo;
+/* @} */
+
+/**
+ * @addtogroup reg_defs
+ * @{
+ */
+/**Null terminated string*/
+typedef char*  REG_SZ_DATA;
+
+/**Null terminated string with windows environment variables that should be expanded*/
+typedef char*  REG_EXPAND_SZ_DATA;
+
+/**Binary data of some kind*/
+typedef struct _REGBINARYDATA {
+   uint32 data_length;
+   uint8 * data;
+} REG_BINARY_DATA;
+   
+/**32-bit (little endian) number*/
+typedef uint32 REG_DWORD_DATA;
+
+/**32-bit big endian number*/
+typedef uint32 REG_DWORD_BE_DATA;
+
+/**array of strings*/
+typedef struct _REGMULTISZDATA {
+   uint32 num_strings;
+
+   char **strings;
+} REG_MULTI_SZ_DATA;
+
+typedef union _REGVALUEDATA {
+   REG_SZ_DATA          reg_sz;
+   REG_EXPAND_SZ_DATA   reg_expand_sz;
+   REG_BINARY_DATA      reg_binary;
+   REG_DWORD_DATA       reg_dword;
+   REG_DWORD_BE_DATA    reg_dword_be;
+   REG_MULTI_SZ_DATA    reg_multi_sz;
+} REG_VALUE_DATA;
+/**@}*/
+
+/**
+ * @addtogroup sam_defs
+ * @{
+ */
+
+#define CAC_USER_RID  0x1
+#define CAC_GROUP_RID 0x2
+
+typedef struct _CACLOOKUPRIDSRECORD {
+   char *name;
+   uint32 rid;
+
+   /**If found, this will be one of:
+    * - CAC_USER_RID
+    * - CAC_GROUP_RID
+    */
+   uint32 type;
+   
+   /*if the name or RID was looked up, then found = True*/
+   BOOL found;
+} CacLookupRidsRecord;
+
+typedef struct _CACUSERINFO {
+   /**Last logon time*/
+   time_t logon_time;
+
+   /**Last logoff time*/
+   time_t logoff_time;
+
+   /**Last kickoff time*/
+   time_t kickoff_time;
+
+   /**Last password set time*/
+   time_t pass_last_set_time;
+
+   /**Time password can change*/
+   time_t pass_can_change_time;
+
+   /**Time password must change*/
+   time_t pass_must_change_time;
+
+   /**LM user password*/
+   uint8 lm_password[8];
+
+   /**NT user password*/
+   uint8 nt_password[8];
+
+   /**User's RID*/
+   uint32 rid;
+
+   /**RID of primary group*/
+   uint32 group_rid;
+
+   /**User's ACB mask*/
+   uint32 acb_mask;
+
+   /**Bad password count*/
+   uint16 bad_passwd_count;
+
+   /**Number of logons*/
+   uint16 logon_count;
+
+   /**Change password at next logon?*/
+   BOOL pass_must_change;
+
+   /**Username*/
+   char *username;
+
+   /**User's full name*/
+   char *full_name;
+
+   /**User's home directory*/
+   char *home_dir;
+
+   /**Home directory drive*/
+   char *home_drive;
+
+   /**Logon script*/
+   char *logon_script;
+
+   /**Path to profile*/
+   char *profile_path;
+
+   /**Account description*/
+   char *description;
+
+   /**Login from workstations*/
+   char *workstations;
+
+   char *dial;
+
+   /**Possible logon hours*/
+   LOGON_HRS *logon_hours;
+
+} CacUserInfo;
+
+typedef struct _CACGROUPINFO {
+   /**Group name*/
+   char *name;
+
+   /**Description*/
+   char *description;
+   /**Number of members*/
+   uint32 num_members;
+} CacGroupInfo, CacAliasInfo;
+
+/**Represents a period (duration) of time*/
+typedef struct _CACTIME {
+   /**Number of days*/
+   uint32 days;
+
+   /**Number of hours*/
+   uint32 hours;
+
+   /**Number of minutes*/
+   uint32 minutes;
+
+   /**number of seconds*/
+   uint32 seconds;
+} CacTime;
+
+
+typedef struct _CACDOMINFO {
+   /**The server role. Should be one of:
+    *   ROLE_STANDALONE
+    *   ROLE_DOMAIN_MEMBER
+    *   ROLE_DOMAIN_BDC
+    *   ROLE_DOMAIN_PDC
+    *   see include/smb.h
+    */
+   uint32 server_role;
+
+   /**Number of domain users*/
+   uint32 num_users;
+
+   /**Number of domain groups*/
+   uint32 num_domain_groups;
+   
+   /**Number of local groups*/
+   uint32 num_local_groups;
+
+   /**Comment*/
+   char *comment;
+
+   /**Domain name*/
+   char *domain_name;
+
+   /**Server name*/
+   char *server_name;
+
+   /**Minimum password length*/
+   uint16 min_pass_length;
+
+   /**How many previous passwords to remember - ie, password cannot be the same as N previous passwords*/
+   uint16 pass_history;
+
+   /**How long (from now) before passwords expire*/
+   CacTime expire;
+
+   /**How long (from now) before passwords can be changed*/
+   CacTime min_pass_age;
+
+   /**How long users are locked out for too many bad password attempts*/
+   CacTime lockout_duration;
+
+   /**How long before lockouts are reset*/
+   CacTime lockout_reset;
+
+   /**How many bad password attempts before lockout occurs*/
+   uint16 num_bad_attempts;
+} CacDomainInfo;
+
+/**@}*/ /*sam_defs*/
+
+/**@addtogroup svc_defs
+ * @{
+ */
+typedef struct _CACSERVICE {
+   /**The service name*/
+   char *service_name;
+
+   /**The display name of the service*/
+   char *display_name;
+   
+   /**Current status of the service - see include/rpc_svcctl.h for SERVICE_STATUS definition*/
+   SERVICE_STATUS status;
+} CacService;
+
+typedef struct __CACSERVICECONFIG {
+   /**The service type*/
+   uint32 type;
+
+   /**The start type. Should be one of:
+    * - SVCCTL_BOOT_START
+    * - SVCCTL_SYSTEM_START
+    * - SVCCTL_AUTO_START
+    * - SVCCTL_DEMAND_START
+    */
+   uint32 start_type;
+
+   uint32 error_control;
+
+   /**Path to executable*/
+   char *exe_path;
+
+   /***/
+   char *load_order_group;
+
+   uint32 tag_id;
+
+   /**Any dependencies for the service*/
+   char *dependencies;
+
+   /**Run as...*/
+   char *start_name;
+
+   /**Service display name*/
+   char *display_name;
+   
+} CacServiceConfig;
+/**@}*/ /*svc_defs*/
+
+#include "libmsrpc_internal.h"
+
+/**
+ * @addtogroup handle
+ * @{
+ */
+
+/**
+ * Server handle used to keep track of client/server/pipe information. Use cac_NewServerHandle() to allocate. 
+ * Initiliaze as many values as possible before calling cac_Connect(). 
+ * 
+ * @note When allocating memory for the fields, use SMB_MALLOC() (or equivalent) instead of talloc() (or equivalent) -  
+ * If memory is not allocated for a field, cac_Connect will allocate sizeof(fstring) bytes for it.
+ * 
+ * @note It may be wise to allocate large buffers for these fields and strcpy data into them.
+ *
+ * @see cac_NewServerHandle()
+ * @see cac_FreeHandle()
+ */
+typedef struct _CACSERVERHANDLE {
+   /** debug level
+    */
+   int debug;
+
+   /** netbios name used to make connections
+    */
+   char *netbios_name;
+
+   /** domain name used to make connections
+    */
+   char *domain;
+
+   /** username used to make connections
+    */
+   char *username;
+
+   /** user's password plain text string
+    */
+   char *password;
+
+   /** name or IP address of server we are currently working with
+    */
+   char *server;
+
+   /**stores the latest NTSTATUS code
+    */
+   NTSTATUS status;
+   
+   /** internal. do not modify!
+    */
+   struct CacServerHandleInternal _internal;
+
+} CacServerHandle;
+
+/*@}*/
+
+/**internal function. do not call this function*/
+SMBCSRV *cac_GetServer(CacServerHandle *hnd);
+
+
+/** @addtogroup Library_Functions
+ * @{
+ */
+/**
+ * Initializes the library - do not need to call this function.  Open's smb.conf as well as initializes logging.
+ * @param debug Debug level for library to use
+ */
+
+void cac_Init(int debug);
+
+/**
+ * Creates an un-initialized CacServerHandle
+ * @param allocate_fields If True, the function will allocate sizeof(fstring) bytes for all char * fields in the handle
+ * @return - un-initialized server handle
+ *         - NULL if no memory could be allocated
+ */
+CacServerHandle * cac_NewServerHandle(BOOL allocate_fields);
+
+/**
+ * Specifies the smbc_get_auth_data_fn to use if you do not want to use the default.
+ * @param hnd non-NULL server handle
+ * @param auth_fn  auth_data_fn to set in server handle
+ */
+
+void cac_SetAuthDataFn(CacServerHandle *hnd, smbc_get_auth_data_fn auth_fn);
+
+/** Use your own libsmbclient context - not necessary. 
+ * @note You must still call cac_Connect() after specifying your own libsmbclient context
+ * @param hnd Initialized, but not connected CacServerHandle
+ * @param ctx The libsmbclient context you would like to use.
+ */
+void cac_SetSmbcContext(CacServerHandle *hnd, SMBCCTX *ctx);
+
+/** Connects to a specified server.  If there is already a connection to a different server, 
+ *    it will be cleaned up before connecting to the new server.
+ * @param hnd   Pre-initialized CacServerHandle
+ * @param srv   (Optional) Name or IP of the server to connect to.  If NULL, server from the CacServerHandle will be used.
+ *
+ * @return CAC_FAILURE if the operation could not be completed successfully (hnd->status will also be set with a NTSTATUS code)
+ * @return CAC_SUCCESS if the operation succeeded
+ */            
+int cac_Connect(CacServerHandle *hnd, const char *srv);
+
+
+/**
+ * Cleans up any data used by the CacServerHandle. If the libsmbclient context was set using cac_SetSmbcContext(), it will not be free'd. 
+ * @param hnd the CacServerHandle to destroy
+ */
+void cac_FreeHandle(CacServerHandle * hnd);
+
+/**
+ * Initializes a CacTime structure based on an NTTIME structure
+ *  If the function fails, then the CacTime structure will be zero'd out
+ */
+void cac_InitCacTime(CacTime *cactime, NTTIME nttime);
+
+/**
+ * Called by cac_NewServerHandle() if allocate_fields = True. You can call this if you want to, allocates sizeof(fstring) char's for every char * field
+ * @param hnd Uninitialized server handle
+ * @return CAC_FAILURE Memory could not be allocated
+ * @return CAC_SUCCESS Memory was allocated
+ */
+int cac_InitHandleMem(CacServerHandle *hnd);
+
+/**
+ * Default smbc_get_auth_data_fn for libmsrpc. This function is called when libmsrpc needs to get more information about the 
+ * client (username/password, workgroup). 
+ * This function provides simple prompts to the user to enter the information. This description his here so you know how to re-define this function.
+ * @see cac_SetAuthDataFn()
+ * @param pServer Name/IP of the server to connect to. 
+ * @param pShare Share name to connect to
+ * @param pWorkgroup libmsrpc passes in the workgroup/domain name from hnd->domain. It can be modified in the function.
+ * @param maxLenWorkgroup The maximum length of a string pWogroup can hold.
+ * @param pUsername libmsrpc passes in the username from hnd->username. It can be modified in the function.
+ * @param maxLenUsername The maximum length of a string pUsername can hold.
+ * @param pPassword libmsrpc pass in the password from hnd->password. It can be modified in the function.
+ * @param maxLenPassword The maximum length  of a string pPassword can hold.
+ */
+void cac_GetAuthDataFn(const char * pServer,
+                 const char * pShare,
+                 char * pWorkgroup,
+                 int maxLenWorkgroup,
+                 char * pUsername,
+                 int maxLenUsername,
+                 char * pPassword,
+                 int maxLenPassword);
+
+
+/**@}*/
+
+/*****************
+ * LSA Functions *
+ *****************/
+
+/** @addtogroup LSA_Functions
+ * @{
+ */
+
+struct LsaOpenPolicy {
+   /**Inputs*/
+   struct {
+      /**Access Mask. Refer to Security Access Masks in include/rpc_secdes.h*/
+      uint32 access;
+
+      /**Use security quality of service? (True/False)*/
+      BOOL security_qos;
+   } in;
+
+   /**Outputs*/
+   struct {
+      /**Handle to the open policy (needed for all other operations)*/
+      POLICY_HND *pol;
+   } out;
+};
+
+/** 
+ * Opens a policy handle on a remote machine.
+ * @param hnd fully initialized CacServerHandle for remote machine
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE if the policy could not be opened. hnd->status set with appropriate NTSTATUS
+ * @return CAC_SUCCESS if the policy could be opened, the policy handle can be found
+ */
+int cac_LsaOpenPolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenPolicy *op);
+
+
+/** 
+ * Closes an  LSA policy handle (Retrieved using cac_LsaOpenPolicy).
+ *   If successful, the handle will be closed on the server, and memory for pol will be freed
+ * @param hnd - An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param pol - the policy handle to close
+ * @return CAC_FAILURE could not close the policy handle, hnd->status is set to the appropriate NTSTATUS error code
+ * @return CAC_SUCCESS the policy handle was closed 
+ */
+int cac_LsaClosePolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *pol);
+
+
+struct LsaGetNamesFromSids {
+   struct {
+      /**handle to and open LSA policy*/
+      POLICY_HND *pol;
+      
+      /**the number of SIDs to lookup*/
+      uint32 num_sids;
+      
+      /**array of SIDs to lookup*/
+      DOM_SID *sids;
+   } in;
+
+   struct {
+      /**The number of names returned (in case of CAC_PARTIAL_SUCCESS)*/
+      uint32 num_found;
+
+      /**array of SID info each index is one sid */
+      CacSidInfo *sids;
+
+      /**in case of partial success, an array of SIDs that could not be looked up (NULL if all sids were looked up)*/
+      DOM_SID *unknown;
+   } out;
+};
+
+/** 
+ * Looks up the names for a list of SIDS
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op  input and output parameters 
+ * @return CAC_FAILURE none of the SIDs could be looked up hnd->status is set with appropriate NTSTATUS error code
+ * @return CAC_SUCCESS all of the SIDs were translated and a list of names has been output
+ * @return CAC_PARTIAL_SUCCESS not all of the SIDs were translated, as a result the number of returned names is less than the original list of SIDs
+ */
+int cac_LsaGetNamesFromSids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetNamesFromSids *op);
+
+struct LsaGetSidsFromNames {
+   struct {
+      /**handle to an open LSA policy*/
+      POLICY_HND *pol;
+
+      /**number of SIDs to lookup*/
+      uint32 num_names;
+
+      /**array of strings listing the names*/
+      char **names;
+   } in;
+
+   struct {
+      /**The number of SIDs returned (in case of partial success*/
+      uint32 num_found;
+
+      /**array of SID info for the looked up names*/
+      CacSidInfo *sids;
+
+      /**in case of partial success, the names that were not looked up*/
+      char **unknown;
+   } out;
+};
+
+/** 
+ * Looks up the SIDs for a list of names
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op  input and output parameters 
+ * @return CAC_FAILURE none of the SIDs could be looked up hnd->status is set with appropriate NTSTATUS error code
+ * @return CAC_SUCCESS all of the SIDs were translated and a list of names has been output
+ * @return CAC_PARTIAL_SUCCESS not all of the SIDs were translated, as a result the number of returned names is less than the original list of SIDs
+ */
+int cac_LsaGetSidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetSidsFromNames *op);
+
+struct LsaFetchSid {
+   struct {
+      /**handle to an open LSA policy*/
+      POLICY_HND *pol;
+
+      /**can be CAC_LOCAL_INFO, CAC_DOMAIN_INFO, or (CAC_LOCAL_INFO | CAC_DOMAIN_INFO)*/
+      uint16 info_class;
+   } in;
+
+   struct {
+      /**the machine's local SID and domain name (NULL if not asked for)*/
+      CacSidInfo *local_sid;
+
+      /**the machine's domain SID and name (NULL if not asked for)*/
+      CacSidInfo *domain_sid;
+      
+   } out;
+};
+
+/** 
+ * Looks up the domain or local sid of a machine with an open LSA policy handle
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op input and output parameters
+ * @return CAC_FAILURE if the SID could not be fetched
+ * @return CAC_SUCCESS if the SID was fetched
+ * @return CAC_PARTIAL_SUCCESS if you asked for both local and domain sids but only one was returned
+ */
+int cac_LsaFetchSid(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaFetchSid *op);
+
+struct LsaQueryInfoPolicy {
+   struct {
+      /**Open LSA policy handle on remote server*/
+      POLICY_HND *pol;
+   } in;
+
+   struct {
+      /**remote server's domain name*/
+      char *domain_name;
+
+      /**remote server's dns name*/
+      char *dns_name;
+
+      /**remote server's forest name*/
+      char *forest_name;
+
+      /**remote server's domain guid*/
+      struct uuid *domain_guid;
+
+      /**remote server's domain SID*/
+      DOM_SID *domain_sid;
+   } out;
+};
+
+/** 
+ * Retrieves information about the LSA machine/domain
+ * @param hnd initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op input and output parameters
+ *           Note: for pre-Windows 2000 machines, only op->out.SID and op->out.domain will be set. @see cac_LsaFetchSid
+ * @return - CAC_FAILURE if the operation was not successful. hnd->status will be set with an accurate NT_STATUS code
+ * @return CAC_SUCCESS the operation was successful.
+ */
+int cac_LsaQueryInfoPolicy(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaQueryInfoPolicy *op);
+
+struct LsaEnumSids {
+   struct {
+      /**Open LSA Policy handle*/
+      POLICY_HND *pol;
+
+      /**The prefered maximum number of SIDs returned per call*/
+      uint32 pref_max_sids;
+   } in;
+
+   struct {
+      /**used to keep track of how many sids have been retrieved over multiple calls
+       *  should be set to zero via ZERO_STRUCT() befrore the first call. Use the same struct LsaEnumSids for multiple calls*/
+      uint32 resume_idx;
+
+      /**The number of sids returned this call*/
+      uint32 num_sids;
+
+      /**Array of sids returned*/
+      DOM_SID *sids;
+
+   } out;
+};
+
+/** 
+ * Enumerates the SIDs in the LSA.  Can be enumerated in blocks by calling the function multiple times.
+ *  Example: while(cac_LsaEnumSids(hnd, mem_ctx, op) { ... }
+ * @param hnd - An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE there was an error during operations OR there are no more results
+ * @return CAC_SUCCESS the operation completed and results were returned
+ */
+int cac_LsaEnumSids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumSids *op);
+
+struct LsaEnumAccountRights {
+   struct {
+      /**Open LSA Policy handle*/
+      POLICY_HND *pol;
+
+      /**(Optional) SID of the account - must supply either sid or name*/
+      DOM_SID *sid;
+
+      /**(Optional) name of the account - must supply either sid or name*/
+      char *name;
+   } in;
+
+   struct {
+      /**Count of rights for this account*/
+      uint32 num_privs;
+
+      /**array of privilege names*/
+      char **priv_names;
+   } out;
+};
+
+/** 
+ * Enumerates rights assigned to a given account. Takes a SID instead of account handle as input
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the rights could not be retrieved. hnd->status is set with NT_STATUS code
+ * @return CAC_SUCCESS the operation was successful. 
+ */
+
+int cac_LsaEnumAccountRights(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumAccountRights *op);
+
+struct LsaEnumTrustedDomains {
+   struct {
+      /**Open LSA policy handle*/
+      POLICY_HND *pol;
+   } in;
+
+   struct {
+      /**used to keep track of how many domains have been retrieved over multiple calls
+       *  should be set to zero via ZERO_STRUCT() before the first call. Use the same struct LsaEnumSids for multiple calls*/
+      uint32 resume_idx;
+      
+      /**The number of domains returned by the remote server this call*/
+      uint32 num_domains;
+
+      /**array of trusted domain names returned by the remote server*/
+      char **domain_names;
+
+      /**array of trusted domain sids returned by the remote server*/
+      DOM_SID *domain_sids;
+   } out;
+};
+     
+/** 
+ * Enumerates the trusted domains in the LSA.  
+ * @param hnd - An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op - initialized parameters
+ * @return CAC_FAILURE there was an error during operations OR there are no more results
+ * @return CAC_SUCCESS the operation completed and results were returned
+ */
+int cac_LsaEnumTrustedDomains(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumTrustedDomains *op);
+
+struct LsaOpenTrustedDomain {
+   struct {
+      /**an open LSA policy handle*/
+      POLICY_HND *pol;
+
+      /**SID of the trusted domain to open*/
+      DOM_SID *domain_sid;
+
+      /**Desired access on the open domain*/
+      uint32 access;
+   } in;
+
+   struct {
+      /**A handle to the policy that is opened*/
+      POLICY_HND *domain_pol;
+   } out;
+};
+
+/** 
+ * Opens a trusted domain by SID.
+ * @param hnd An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op initialized I/O parameters
+ * @return CAC_FAILURE a handle to the domain could not be opened. hnd->status is set with approriate NT_STATUS code
+ * @return CAC_SUCCESS the domain was opened successfully
+ */
+int cac_LsaOpenTrustedDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenTrustedDomain *op);
+
+struct LsaQueryTrustedDomainInfo {
+   struct {
+      /**Open LSA policy handle*/
+      POLICY_HND *pol;
+
+      /**Info class of returned data*/
+      uint16 info_class;
+
+      /**(Optional)SID of trusted domain to query (must specify either SID or name of trusted domain)*/
+      DOM_SID *domain_sid;
+
+      /**(Optional)Name of trusted domain to query (must specify either SID or name of trusted domain)*/
+      char *domain_name;
+   } in;
+
+   struct {
+      /**information about the trusted domain*/
+      LSA_TRUSTED_DOMAIN_INFO *info;
+   } out;
+};
+
+/** 
+ * Retrieves information a trusted domain.
+ * @param hnd An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op initialized I/O parameters
+ * @return CAC_FAILURE a handle to the domain could not be opened. hnd->status is set with approriate NT_STATUS code
+ * @return CAC_SUCCESS the domain was opened successfully
+ */
+
+int cac_LsaQueryTrustedDomainInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaQueryTrustedDomainInfo *op);
+
+struct LsaEnumPrivileges {
+   struct {
+      /**An open LSA policy handle*/
+      POLICY_HND *pol;
+
+      /**The _preferred_ maxinum number of privileges returned per call*/
+      uint32 pref_max_privs;
+   } in;
+
+   struct {
+      /**Used to keep track of how many privileges have been retrieved over multiple calls. Do not modify this value between calls*/
+      uint32 resume_idx;
+
+      /**The number of privileges returned this call*/
+      uint32 num_privs;
+
+      /**Array of privilege names*/
+      char **priv_names;
+
+      /**Array of high bits for privilege LUID*/
+      uint32 *high_bits;
+
+      /**Array of low bits for privilege LUID*/
+      uint32 *low_bits;
+   } out; 
+};
+
+/** 
+ * Enumerates the Privileges supported by the LSA.  Can be enumerated in blocks by calling the function multiple times.
+ *  Example: while(cac_LsaEnumPrivileges(hnd, mem_ctx, op) { ... }
+ * @param hnd An initialized and connected server handle
+ * @param mem_ctx Talloc context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE there was an error during operations OR there are no more results
+ * @return CAC_SUCCESS the operation completed and results were returned
+ * @see CAC_OP_FAILED()
+ */
+int cac_LsaEnumPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaEnumPrivileges *op);
+
+struct LsaOpenAccount {
+   struct {
+      /**An open LSA policy handle*/
+      POLICY_HND *pol;
+
+      /**(Optional) account SID - must supply either sid or name*/
+      DOM_SID *sid;
+
+      /**(Optional) account name - must supply either sid or name*/
+      char *name;
+
+      /**desired access for the handle*/
+      uint32 access;
+   } in;
+
+   struct {
+      /**A handle to the opened user*/
+      POLICY_HND *user;
+   } out;
+};
+
+/** 
+ * Opens a handle to an account in the LSA
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the account could not be opened. hnd->status has appropriate NT_STATUS code
+ * @return CAC_SUCCESS the account was opened
+ */
+int cac_LsaOpenAccount(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaOpenAccount *op);
+
+struct LsaAddPrivileges {
+   struct {
+      /**An open LSA policy handle*/
+      POLICY_HND *pol;
+
+      /**(Optional) The user's SID (must specify at least sid or name)*/
+      DOM_SID *sid;
+
+      /**(Optional) The user's name (must specify at least sid or name)*/
+      char *name;
+
+      /**The privilege names of the privileges to add for the account*/
+      char **priv_names;
+      
+      /**The number of privileges in the priv_names array*/
+      uint32 num_privs;
+
+   } in;
+};
+
+/** 
+ * Adds Privileges an account.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the privileges could not be set. hnd->status has appropriate NT_STATUS code
+ * @return CAC_SUCCESS the privileges were set.
+ */
+int cac_LsaAddPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAddPrivileges *op);
+
+struct LsaRemovePrivileges {
+   struct {
+      /**An open handle to the LSA*/
+      POLICY_HND *pol;
+
+      /**(Optional) The account SID (must specify at least sid or name)*/
+      DOM_SID *sid;
+
+      /**(Optional) The account name (must specify at least sid or name)*/
+      char *name;
+
+      /**The privilege names of the privileges to remove from the account*/
+      char **priv_names;
+
+      /**The number of privileges in the priv_names array*/
+      uint32 num_privs;
+
+   } in;
+
+   struct {
+   } out;
+};
+
+/** 
+ * Removes a _specific_ set of privileges from an account
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the privileges could not be removed. hnd->status is set with NT_STATUS code
+ * @return CAC_SUCCESS the privileges were removed 
+ */
+int cac_LsaRemovePrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaRemovePrivileges *op);
+
+struct LsaClearPrivileges {
+   struct {
+      /**An open handle to the LSA*/
+      POLICY_HND *pol;
+
+      /**(Optional) The user's SID (must specify at least sid or name)*/
+      DOM_SID *sid;
+
+      /**(Optional) The user's name (must specify at least sid or name)*/
+      char *name;
+   } in;
+
+   struct {
+   } out;
+};
+
+/** 
+ * Removes ALL privileges from an account
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE the operation was not successful, hnd->status set with NT_STATUS code
+ * @return CAC_SUCCESS the opeartion was successful.
+ */
+int cac_LsaClearPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaClearPrivileges *op);
+
+/** 
+ * Sets an accounts priviliges. Removes all privileges and then adds specified privileges.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters 
+ * @return CAC_FAILURE The operation could not complete successfully
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_LsaSetPrivileges(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaAddPrivileges *op);
+
+struct LsaGetSecurityObject {
+   struct {
+      /**Open LSA policy handle*/
+      POLICY_HND *pol;
+   } in;
+
+   struct {
+      /**Returned security descriptor information*/
+      SEC_DESC_BUF *sec;
+   } out;
+};
+
+/**
+ * Retrieves Security Descriptor information about the LSA
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters 
+ * @return CAC_FAILURE The operation could not complete successfully
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_LsaGetSecurityObject(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct LsaGetSecurityObject *op);
+
+
+/**@}*/ /*LSA_Functions*/
+      
+/**********************
+ * Registry Functions *
+ *********************/
+
+/**@addtogroup Reg_Functions
+ * @{
+ */
+
+struct RegConnect {
+   struct {
+      /** must be one of : 
+       *    HKEY_CLASSES_ROOT, 
+       *    HKEY_LOCAL_MACHINE, 
+       *    HKEY_USERS, 
+       *    HKEY_PERFORMANCE_DATA,
+       */
+      int root;
+
+      /**desired access on the root key
+       * combination of: 
+       * REG_KEY_READ,
+       * REG_KEY_WRITE,
+       * REG_KEY_EXECUTE,
+       * REG_KEY_ALL,
+       * found in include/rpc_secdes.h*/
+      uint32 access;
+   } in;
+
+   struct {
+      POLICY_HND *key;
+   } out;
+};
+
+/** 
+ * Opens a handle to the registry on the server
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters 
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegConnect *op);
+
+/**
+ * Closes an open registry handle
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param key The Key/Handle to close 
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *key);
+
+struct RegOpenKey {
+   struct {
+      /**(Optional)parent key. 
+       * If this is NULL, then cac_RegOpenKey() will attempt to connect to the registry, name MUST start with something like:<br>
+       *  HKEY_LOCAL_MACHINE\  or an abbreviation like HKCR\
+       *
+       *  supported root names:
+       *   - HKEY_LOCAL_MACHINE\ or HKLM\
+       *   - HKEY_CLASSES_ROOT\ or HKCR\
+       *   - HKEY_USERS\ or HKU\
+       *   - HKEY_PERFORMANCE_DATA or HKPD\
+       */
+      POLICY_HND *parent_key;
+
+      /**name/path of key*/
+      char *name;
+
+      /**desired access on this key*/
+      uint32 access;
+   } in;
+
+   struct {
+      POLICY_HND *key;
+   } out;
+};
+      
+/**
+ * Opens a registry key
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegOpenKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegOpenKey *op);
+
+struct RegEnumKeys {
+   struct {
+      /**enumerate subkeys of this key*/
+      POLICY_HND *key;
+
+      /**maximum number of keys to enumerate each call*/
+      uint32 max_keys;
+   } in;
+
+   struct {
+      /**keeps track of the index to resume enumerating*/
+      uint32 resume_idx;
+
+      /**the number of keys returned this call*/
+      uint32 num_keys;
+
+      /**array of key names*/
+      char **key_names;
+
+      /**class names of the keys*/
+      char **class_names;
+
+      /**last modification time of the key*/
+      time_t *mod_times;
+   } out;
+};
+
+/**
+ * Enumerates Subkeys of a given key. Can be run in a loop. Example: while(cac_RegEnumKeys(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @see CAC_OP_FAILED()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegEnumKeys(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumKeys *op);
+
+
+struct RegCreateKey {
+   struct {
+      /**create a subkey of parent_key*/
+      POLICY_HND *parent_key;
+
+      /**name of the key to create*/
+      char *key_name;
+
+      /**class of the key*/
+      char *class_name;
+
+      /**Access mask to open the key with. See REG_KEY_* in include/rpc_secdes.h*/
+      uint32 access;
+   } in;
+
+   struct {
+      /**Open handle to the key*/
+      POLICY_HND *key;
+   } out;
+};
+
+/**
+ * Creates a registry key, if the key already exists, it will be opened __Creating keys is not currently working__.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parmeters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegCreateKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegCreateKey *op);
+
+struct RegDeleteKey {
+   struct {
+      /**handle to open registry key*/
+      POLICY_HND *parent_key;
+
+      /**name of the key to delete*/
+      char *name;
+
+      /**delete recursively. WARNING: this might not always work as planned*/
+      BOOL recursive;
+   } in;
+
+};
+
+/**
+ * Deletes a subkey of an open key. Note: if you run this with op->in.recursive == True, and the operation fails, it may leave the key in an inconsistent state.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegDeleteKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteKey *op);
+
+struct RegDeleteValue {
+   struct {
+      /**handle to open registry key*/
+      POLICY_HND *parent_key;
+
+      /**name of the value to delete*/
+      char *name;
+   } in;
+};
+
+/**
+ * Deletes a registry value.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegDeleteValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteValue *op);
+
+struct RegQueryKeyInfo {
+   struct {
+      /**Open handle to the key to query*/
+      POLICY_HND *key;
+   } in;
+
+   struct {
+      /**name of the key class*/
+      char *class_name;
+
+      /**number of subkeys of the key*/
+      uint32 num_subkeys;
+
+      /**length (in characters) of the longest subkey name*/
+      uint32 longest_subkey;
+
+      /**length (in characters) of the longest class name*/
+      uint32 longest_class;
+
+      /**number of values in this key*/
+      uint32 num_values;
+
+      /**length (in characters) of the longest value name*/
+      uint32 longest_value_name;
+
+      /**length (in bytes) of the biggest value data*/
+      uint32 longest_value_data;
+
+      /**size (in bytes) of the security descriptor*/
+      uint32 security_desc_size;
+
+      /**time of the last write*/
+      time_t last_write_time;
+   } out;
+};
+
+/**
+ * Retrieves information about an open key
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegQueryKeyInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryKeyInfo *op);
+
+struct RegSaveKey {
+   struct {
+      /**Open key to be saved*/
+      POLICY_HND *key;
+
+      /**The path (on the remote computer) to save the file to*/
+      char *filename;
+   } in;
+};
+
+/**
+ * Saves a key to a file on the remote machine __Not currently working__.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegSaveKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSaveKey *op);
+
+struct RegQueryValue {
+   struct {
+      /**handle to open registry key*/
+      POLICY_HND *key;
+
+      /**name of the value to query*/
+      char *val_name;
+   } in;
+
+   struct {
+      /**Value type.
+       * One of:
+       *  - REG_DWORD (equivalent to REG_DWORD_LE)
+       *  - REG_DWORD_BE
+       *  - REG_SZ
+       *  - REG_EXPAND_SZ
+       *  - REG_MULTI_SZ
+       *  - REG_BINARY
+       */
+      uint32 type;
+
+      /**The value*/
+      REG_VALUE_DATA *data;
+   } out;
+};
+
+/**
+ * Retrieves a value (type and data) _not currently working_.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegQueryValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryValue *op);
+
+struct RegEnumValues {
+   struct {
+      /**handle to open key*/
+      POLICY_HND *key;
+
+      /**max number of values returned per call*/
+      uint32 max_values;
+
+   } in;
+
+   struct {
+      /**keeps track of the index to resume from - used over multiple calls*/
+      uint32 resume_idx;
+
+      /**the number of values that were returned this call*/
+      uint32 num_values;
+
+      /**Array of value types. A type can be one of:
+       *  - REG_DWORD (equivalent to REG_DWORD_LE)
+       *  - REG_DWORD_BE
+       *  - REG_SZ
+       *  - REG_EXPAND_SZ
+       *  - REG_MULTI_SZ
+       *  - REG_BINARY
+       */
+      uint32 *types;
+
+      /**array of strings storing the names of the values*/
+      char **value_names;
+
+      /**array of pointers to the value data returned*/
+      REG_VALUE_DATA **values;
+   } out;
+};
+
+/**
+ * Enumerates a number of Registry values in an open registry key.
+ * Can be run in a loop. Example: while(cac_RegEnumValues(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @see CAC_OP_FAILED()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegEnumValues(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumValues *op);
+
+struct RegSetValue {
+   struct {
+      /**Handle to open registry key*/
+      POLICY_HND *key;
+
+      /**Name of the value*/
+      char *val_name;
+
+      /**Value type.
+       * One of:
+       *  - REG_DWORD (equivalent to REG_DWORD_LE)
+       *  - REG_DWORD_BE
+       *  - REG_SZ
+       *  - REG_EXPAND_SZ
+       *  - REG_MULTI_SZ
+       *  - REG_BINARY
+       */
+      uint32 type;
+
+      /**the value*/
+      REG_VALUE_DATA value;
+   } in;
+};
+
+/**
+ * Sets or creates value (type and data).
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegSetValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetValue *op);
+
+struct RegGetVersion {
+   struct {
+      /**open registry key*/
+      POLICY_HND *key;
+   } in;
+
+   struct {
+      /**version number*/
+      uint32 version;
+   } out;
+};
+
+/**
+ * Retrieves the registry version number
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegGetVersion(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetVersion *op);
+
+struct RegGetKeySecurity {
+   struct {
+      /**Handle to key to query*/
+      POLICY_HND *key;
+
+      /**Info that you want. Should be a combination of (1 or more or'd):
+       * - OWNER_SECURITY_INFORMATION
+       * - GROUP_SECURITY_INFORMATION
+       * - DACL_SECURITY_INFORMATION
+       * - SACL_SECURITY_INFORMATION
+       * - UNPROTECTED_SACL_SECURITY_INFORMATION
+       * - UNPROTECTED_DACL_SECURITY_INFORMATION
+       * - PROTECTED_SACL_SECURITY_INFORMATION
+       * - PROTECTED_DACL_SECURITY_INFORMATION
+       *
+       * or use:
+       * - ALL_SECURITY_INFORMATION
+       *
+       * all definitions from include/rpc_secdes.h
+       */
+      uint32 info_type;
+   } in;
+
+   struct {
+      /**size of the data returned*/
+      uint32 size;
+
+      /**Security descriptor*/
+      SEC_DESC *descriptor;
+   } out;
+};
+
+/**
+ * Retrieves a key security descriptor.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_RegGetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetKeySecurity *op);
+
+struct RegSetKeySecurity {
+   struct {
+      /**Handle to key to query*/
+      POLICY_HND *key;
+
+      /**Info that you want. Should be a combination of (1 or more or'd):
+       * - OWNER_SECURITY_INFORMATION
+       * - GROUP_SECURITY_INFORMATION
+       * - DACL_SECURITY_INFORMATION
+       * - SACL_SECURITY_INFORMATION
+       * - UNPROTECTED_SACL_SECURITY_INFORMATION
+       * - UNPROTECTED_DACL_SECURITY_INFORMATION
+       * - PROTECTED_SACL_SECURITY_INFORMATION
+       * - PROTECTED_DACL_SECURITY_INFORMATION
+       *
+       * or use:
+       * - ALL_SECURITY_INFORMATION
+       *
+       * all definitions from include/rpc_secdes.h
+       */
+      uint32 info_type;
+      
+      /**size of the descriptor*/
+      size_t size;
+
+      /**Security descriptor*/
+      SEC_DESC *descriptor;
+   } in;
+};
+
+/**
+ * Sets the key security descriptor.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_RegSetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetKeySecurity *op);
+
+/**@}*/ /*Reg_Functions*/
+
+struct Shutdown {
+   struct {
+      /**the message to display (can be NULL)*/
+      char *message;
+
+      /**timeout in seconds*/
+      uint32 timeout;
+
+      /**False = shutdown, True = reboot*/
+      BOOL reboot;
+      
+      /**force the*/
+      BOOL force;
+
+      /*FIXME: make this useful*/
+      uint32 reason;
+   } in;
+};
+
+
+/**
+ * Shutdown the server _not currently working_. 
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_Shutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Shutdown *op);
+
+/**
+ * Attempt to abort initiated shutdown on the server _not currently working_. 
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_AbortShutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx);
+
+/*****************
+ * SAM Functions *
+ *****************/
+
+/**@addtogroup SAM_Functions
+ * @{
+ */
+struct SamConnect {
+   struct {
+      /**Access mask to open with
+       * see generic access masks in include/smb.h*/
+      uint32 access;
+   } in;
+
+   struct {
+      POLICY_HND *sam;
+   } out;
+};
+
+/** 
+ * Connects to the SAM. This can be skipped by just calling cac_SamOpenDomain()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamConnect *op);
+
+
+/** 
+ * Closes any (SAM, domain, user, group, etc.) SAM handle. 
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param sam Handle to close
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *sam);
+
+struct SamOpenDomain {
+   struct {
+      /**The desired access. See generic access masks - include/smb.h*/
+      uint32 access;
+
+      /**(Optional) An open handle to the SAM. If it is NULL, the function will connect to the SAM with the access mask above*/
+      POLICY_HND *sam;
+
+      /**(Optional) The SID of the domain to open. 
+       *  If this this is NULL, the function will attempt to open the domain specified in hnd->domain */
+      DOM_SID *sid;
+   } in;
+
+   struct {
+      /**handle to the open domain*/
+      POLICY_HND *dom_hnd;
+
+      /**Handle to the open SAM*/
+      POLICY_HND *sam;
+   } out;
+};
+
+/** 
+ * Opens a handle to a domain. This must be called before any other SAM functions 
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenDomain *op);
+
+struct SamCreateUser {
+   struct {
+      /**Open domain handle*/
+      POLICY_HND *dom_hnd;
+
+      /**Username*/
+      char *name;
+
+      /**See Allowable account control bits in include/smb.h*/
+      uint32 acb_mask;
+   } in;
+
+   struct {
+      /**handle to the user*/
+      POLICY_HND *user_hnd;
+
+      /**rid of the user*/
+      uint32 rid;
+   } out;
+};
+
+/** 
+ * Creates a new domain user, if the account already exists it will _not_ be opened and hnd->status will be NT_STATUS_USER_EXISTS
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamCreateUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateUser *op);
+
+struct SamOpenUser {
+   struct {
+      /**Handle to open SAM connection*/
+      POLICY_HND *dom_hnd;
+
+      /**desired access - see generic access masks in include/smb.h*/
+      uint32 access;
+
+      /**RID of the user*/
+      uint32 rid;
+
+      /**(Optional) name of the user - must supply either RID or user name*/
+      char *name;
+   } in;
+
+   struct {
+      /**Handle to the user*/
+      POLICY_HND *user_hnd;
+   } out;    
+};
+
+/** 
+ * Opens a domain user.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenUser *op);
+
+/** 
+ * Deletes a domain user.  
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param user_hnd Open handle to the user
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDeleteUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd);
+
+
+struct SamEnumUsers {
+   struct {
+      /**Open handle to a domain*/
+      POLICY_HND *dom_hnd;
+
+      /**Enumerate users with specific ACB. If 0, all users will be enumerated*/
+      uint16 acb_mask;
+   } in;
+
+   struct {
+      /**where to resume from. Used over multiple calls*/
+      uint32 resume_idx;
+
+      /**the number of users returned this call*/
+      uint32 num_users;
+
+      /**Array storing the rids of the returned users*/
+      uint32 *rids;
+
+      /**Array storing the names of all the users returned*/
+      char **names;
+
+      BOOL done;
+   } out;
+};
+
+/** 
+ * Enumerates domain users. Can be used as a loop condition. Example: while(cac_SamEnumUsers(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnumUsers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumUsers *op);
+
+struct SamGetNamesFromRids {
+   struct {
+      /**An open handle to the domain SAM from cac_SamOpenDomain()*/
+      POLICY_HND *dom_hnd;
+
+      /**Number of RIDs to resolve*/
+      uint32 num_rids;
+
+      /**Array of RIDs to resolve*/
+      uint32 *rids;
+   } in;
+
+   struct {
+      /**the number of names returned - if this is 0, the map is NULL*/
+      uint32 num_names;
+
+      /**array contiaing the Names and RIDs*/
+      CacLookupRidsRecord *map;
+   } out;
+};
+
+/** 
+ * Returns a list of names which map to a list of RIDs.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetNamesFromRids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetNamesFromRids *op);
+
+struct SamGetRidsFromNames {
+   struct {
+      /**An open handle to the domain SAM from cac_SamOpenDomain()*/
+      POLICY_HND *dom_hnd;
+
+      /**Number of names to resolve*/
+      uint32 num_names;
+
+      /**Array of names to resolve*/
+      char **names;
+   } in;
+
+   struct {
+      /**the number of names returned - if this is 0, then map is NULL*/
+      uint32 num_rids;
+
+      /**array contiaing the Names and RIDs*/
+      CacLookupRidsRecord *map;
+   } out;
+};
+
+/** 
+ * Returns a list of RIDs which map to a list of names.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetRidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetRidsFromNames *op);
+
+struct SamGetGroupsForUser {
+   struct {
+      /**An open handle to the user*/
+      POLICY_HND *user_hnd;
+   } in;
+
+   struct {
+      /**The number of groups the user is a member of*/
+      uint32 num_groups;
+
+      /**The RIDs of the groups*/
+      uint32 *rids;
+
+      /**The attributes of the groups*/ 
+      uint32 *attributes;
+   } out;
+};
+/** 
+ * Retrieves a list of groups that a user is a member of.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetGroupsForUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupsForUser *op);
+
+struct SamOpenGroup {
+   struct {
+      /**Open handle to the domain SAM*/
+      POLICY_HND *dom_hnd;
+
+      /**Desired access to open the group with. See Generic access masks in include/smb.h*/
+      uint32 access;
+
+      /**rid of the group*/
+      uint32 rid;
+   } in;
+
+   struct {
+      /**Handle to the group*/
+      POLICY_HND *group_hnd;
+   } out;
+};
+
+/** 
+ * Opens a domain group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenGroup *op);
+
+struct SamCreateGroup {
+   struct {
+      /**Open handle to the domain SAM*/
+      POLICY_HND *dom_hnd;
+
+      /**Desired access to open the group with. See Generic access masks in include/smb.h*/
+      uint32 access;
+
+      /**The name of the group*/
+      char *name;
+   } in;
+
+   struct {
+      /**Handle to the group*/
+      POLICY_HND *group_hnd;
+   } out;
+};
+
+/** 
+ * Creates a group. If the group already exists it will not be opened.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamCreateGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateGroup *op);
+
+/** 
+ * Deletes a domain group.  
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param group_hnd Open handle to the group.
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDeleteGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd);
+
+struct SamGetGroupMembers {
+   struct {
+      /**Open handle to a group*/
+      POLICY_HND *group_hnd;
+   } in;
+
+   struct {
+      /**The number of members in the group*/
+      uint32 num_members;
+
+      /**An array storing the RIDs of the users*/
+      uint32 *rids;
+
+      /**The attributes*/
+      uint32 *attributes;
+   } out;
+};
+
+/** 
+ * Retrives a list of users in a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupMembers *op);
+
+struct SamAddGroupMember {
+   struct {
+      /**Open handle to a group*/
+      POLICY_HND *group_hnd;
+
+      /**RID of new member*/
+      uint32 rid;
+   } in;
+};
+
+/** 
+ * Adds a user to a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamAddGroupMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamAddGroupMember *op);
+
+struct SamRemoveGroupMember {
+   struct {
+      /**Open handle to a group*/
+      POLICY_HND *group_hnd;
+
+      /**RID of member to remove*/
+      uint32 rid;
+   } in;
+};
+
+/** 
+ * Removes a user from a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamRemoveGroupMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRemoveGroupMember *op);
+
+/**
+ * Removes all the members of a group - warning: if this function fails is is possible that some but not all members were removed
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param group_hnd Open handle to the group to clear
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamClearGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd);
+
+struct SamSetGroupMembers {
+   struct {
+      /**Open handle to the group*/
+      POLICY_HND *group_hnd;
+
+      /**Number of members in the group - if this is 0, all members of the group will be removed*/
+      uint32 num_members;
+
+      /**The RIDs of the users to add*/
+      uint32 *rids;
+   } in;
+};
+
+/**
+ * Clears the members of a group and adds a list of members to the group
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetGroupMembers *op);
+
+struct SamEnumGroups {
+   struct {
+      /**Open handle to a domain*/
+      POLICY_HND *dom_hnd;
+   } in;
+
+   struct {
+      /**Where to resume from _do not_ modify this value. Used over multiple calls.*/
+      uint32 resume_idx;
+
+      /**the number of users returned this call*/
+      uint32 num_groups;
+
+      /**Array storing the rids of the returned groups*/
+      uint32 *rids;
+
+      /**Array storing the names of all the groups returned*/
+      char **names;
+
+      /**Array storing the descriptions of all the groups returned*/
+      char **descriptions;
+
+      BOOL done;
+   } out;
+};
+
+/** 
+ * Enumerates domain groups. Can be used as a loop condition. Example: while(cac_SamEnumGroups(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnumGroups(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumGroups *op);
+
+struct SamEnumAliases {
+   struct {
+      /**Open handle to a domain*/
+      POLICY_HND *dom_hnd;
+   } in;
+
+   struct {
+      /**where to resume from. Used over multiple calls*/
+      uint32 resume_idx;
+
+      /**the number of users returned this call*/
+      uint32 num_aliases;
+
+      /**Array storing the rids of the returned groups*/
+      uint32 *rids;
+
+      /**Array storing the names of all the groups returned*/
+      char **names;
+
+      /**Array storing the descriptions of all the groups returned*/
+      char **descriptions;
+
+      BOOL done;
+   } out;
+};
+
+/** 
+ * Enumerates domain aliases. Can be used as a loop condition. Example: while(cac_SamEnumAliases(hnd, mem_ctx, op)) { ... }
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnumAliases(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumAliases *op);
+
+struct SamCreateAlias {
+   struct {
+      /**Open handle to the domain SAM*/
+      POLICY_HND *dom_hnd;
+
+      /**The name of the alias*/
+      char *name;
+   } in;
+
+   struct {
+      /**Handle to the group*/
+      POLICY_HND *alias_hnd;
+   } out;
+};
+
+/** 
+ * Creates an alias. If the alias already exists it will not be opened.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamCreateAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateAlias *op);
+
+struct SamOpenAlias {
+   struct {
+      /**Open handle to the domain SAM*/
+      POLICY_HND *dom_hnd;
+
+      /**Desired access to open the group with. See Generic access masks in include/smb.h*/
+      uint32 access;
+
+      /**rid of the alias*/
+      uint32 rid;
+   } in;
+
+   struct {
+      /**Handle to the alias*/
+      POLICY_HND *alias_hnd;
+   } out;
+};
+
+/** 
+ * Opens a handle to an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamOpenAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenAlias *op);
+
+/** 
+ * Deletes an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param alias_hnd Open handle to the alias
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDeleteAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *alias_hnd);
+
+struct SamAddAliasMember {
+   struct {
+      /**Open handle to a alias*/
+      POLICY_HND *alias_hnd;
+
+      /**SID of new member*/
+      DOM_SID *sid;
+   } in;
+};
+
+/** 
+ * Adds an account to an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamAddAliasMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamAddAliasMember *op);
+
+struct SamRemoveAliasMember {
+   struct {
+      /**Open handle to the alias*/
+      POLICY_HND *alias_hnd;
+
+      /**The SID of the member*/
+      DOM_SID *sid;
+   } in;
+};
+
+/** 
+ * Removes an account from an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamRemoveAliasMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRemoveAliasMember *op);
+
+struct SamGetAliasMembers {
+   struct {
+      /**Open handle to the alias*/
+      POLICY_HND *alias_hnd;
+   } in;
+
+   struct {
+      /**The number of members*/
+      uint32 num_members;
+
+      /**An array storing the SIDs of the accounts*/
+      DOM_SID *sids;
+   } out;
+};
+
+/** 
+ * Retrieves a list of all accounts in an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetAliasMembers *op);
+
+/**
+ * Removes all the members of an alias  - warning: if this function fails is is possible that some but not all members were removed
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param alias_hnd Handle to the alias to clear
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamClearAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *alias_hnd);
+
+struct SamSetAliasMembers {
+   struct {
+      /**Open handle to the group*/
+      POLICY_HND *alias_hnd;
+
+      /**Number of members in the group - if this is 0, all members of the group will be removed*/
+      uint32 num_members;
+
+      /**The SIDs of the accounts to add*/
+      DOM_SID *sids;
+   } in;
+};
+
+/**
+ * Clears the members of an alias and adds a list of members to the alias
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetAliasMembers *op);
+
+
+struct SamUserChangePasswd {
+   struct {
+      /**The username*/
+      char *username;
+
+      /**The current password*/
+      char *password;
+
+      /**The new password*/
+      char *new_password;
+   } in;
+};
+/**Used by a user to change their password*/
+int cac_SamUserChangePasswd(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamUserChangePasswd *op);
+
+/**
+ * Enables a user
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param user_hnd Open handle to the user to enable
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamEnableUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd);
+
+/**
+ * Disables a user
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param user_hnd Open handle to the user to disables
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamDisableUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd);
+
+struct SamSetPassword {
+   struct {
+      /**Open handle to a user*/
+      POLICY_HND *user_hnd;
+
+      /**The new password*/
+      char *password;
+   } in;
+};
+
+/**
+ * Sets a user's password
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamSetPassword(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetPassword *op);
+
+struct SamGetUserInfo {
+   struct {
+      /**Open Handle to a user*/
+      POLICY_HND *user_hnd;
+   } in;
+
+   struct {
+      CacUserInfo *info;
+   } out;
+};
+
+/**
+ * Retrieves user information using a CacUserInfo structure. If you would like to use a SAM_USERINFO_CTR directly, use cac_SamGetUserInfoCtr()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamGetUserInfoCtr()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetUserInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetUserInfo *op);
+
+struct SamSetUserInfo {
+   struct {
+      /**Open handle to a user*/
+      POLICY_HND *user_hnd;
+
+      /**Structure containing the data you would like to set*/
+      CacUserInfo *info;
+   } in;
+};
+
+/**
+ * Sets the user info using a CacUserInfo structure. If you would like to use a SAM_USERINFO_CTR directly use cac_SamSetUserInfoCtr().
+ * @note All fields in the CacUserInfo structure will be set. Best to call cac_GetUserInfo() modify fields that you want, and then call cac_SetUserInfo().
+ * @note When calling this, you _must_ set the user's password.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamSetUserInfoCtr()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetUserInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetUserInfo *op);
+
+struct SamGetUserInfoCtr {
+   struct {
+      /**Open handle to a user*/
+      POLICY_HND *user_hnd;
+
+      /**What USER_INFO structure you want. See include/rpc_samr.h*/
+      uint16 info_class;
+   } in;
+
+   struct {
+      /**returned user info*/
+      SAM_USERINFO_CTR *ctr;
+   } out;
+};
+
+/**
+ * Retrieves user information using a SAM_USERINFO_CTR structure. If you don't want to use this structure, user SamGetUserInfo()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamGetUserInfo()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetUserInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetUserInfoCtr *op);
+
+struct SamSetUserInfoCtr {
+   struct {
+      /**Open handle to a user*/
+      POLICY_HND *user_hnd;
+
+      /**user info - make sure ctr->switch_value is set properly*/
+      SAM_USERINFO_CTR *ctr;
+   } in;
+};
+
+/**
+ * Sets the user info using a SAM_USERINFO_CTR structure. If you don't want to use this structure, use cac_SamSetUserInfo()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see cac_SamSetUserInfo()
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamSetUserInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetUserInfoCtr *op);
+
+struct SamRenameUser {
+   struct {
+      /**Open handle to user*/
+      POLICY_HND *user_hnd;
+
+      /**New user name*/
+      char *new_name;
+   } in;
+};
+
+/**
+ * Changes the name of a user.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamRenameUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRenameUser *op);
+
+struct SamGetGroupInfo {
+   struct {
+      /**Open handle to a group*/
+      POLICY_HND *group_hnd;
+   } in;
+
+   struct {
+      /**Returned info about the group*/
+      CacGroupInfo *info;
+   } out;
+};
+
+/**
+ * Retrieves information about a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetGroupInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupInfo *op);
+
+struct SamSetGroupInfo {
+   struct {
+      /**Open handle to a group*/
+      POLICY_HND *group_hnd;
+
+      /**group info*/
+      CacGroupInfo *info;
+   } in;
+};
+
+/**
+ * Sets information about a group.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetGroupInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetGroupInfo *op);
+
+struct SamRenameGroup {
+   struct {
+      /**Open handle to a group*/
+      POLICY_HND *group_hnd;
+
+      /**New name*/
+      char *new_name;
+   } in;
+};
+
+/**
+ * Changes the name of a group
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+
+int cac_SamRenameGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRenameGroup *op);
+
+struct SamGetAliasInfo {
+   struct {
+      /**Open handle to an alias*/
+      POLICY_HND *alias_hnd;
+   } in;
+
+   struct {
+      /**Returned alias info*/
+      CacAliasInfo *info;
+   } out;
+};
+
+/**
+ * Retrieves information about an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamGetAliasInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetAliasInfo *op);
+
+struct SamSetAliasInfo {
+   struct {
+      /**Open handle to an alias*/
+      POLICY_HND *alias_hnd;
+      
+      /**Returned alias info*/
+      CacAliasInfo *info;
+   } in;
+};
+
+/**
+ * Sets information about an alias.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE The operation could not complete successfully. hnd->status is set with appropriate NTSTATUS code
+ * @return CAC_SUCCESS The operation completed successfully
+ */
+int cac_SamSetAliasInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetAliasInfo *op);
+
+struct SamGetDomainInfo {
+   struct {
+      /**Open handle to the domain SAM*/
+      POLICY_HND *dom_hnd;
+   } in;
+
+   struct {
+      /**Returned domain info*/
+      CacDomainInfo *info;
+   } out;
+};
+
+/**
+ * Gets domain information in the form of a CacDomainInfo structure. 
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see SamGetDomainInfoCtr()
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ * @return CAC_PARTIAL_SUCCESS - This function makes 3 rpc calls, if one or two fail and the rest succeed, 
+ *                                  not all fields in the CacDomainInfo structure will be filled
+ */
+int cac_SamGetDomainInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDomainInfo *op);
+
+struct SamGetDomainInfoCtr {
+   struct {
+      /**Open handle to domain*/
+      POLICY_HND *dom_hnd;
+
+      /**What info level you want*/
+      uint16 info_class;
+   } in;
+
+   struct {
+      SAM_UNK_CTR *info;
+   } out;
+};
+
+/**
+ * Gets domain information in the form of a SAM_UNK_CTR structure. 
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @see SamGetDomainInfo()
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamGetDomainInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDomainInfoCtr *op);
+
+struct SamGetDisplayInfo {
+   struct {
+      /**Open handle to domain*/
+      POLICY_HND *dom_hnd;
+
+      /**What type of data*/
+      uint16 info_class;
+
+      /**(Optional)If 0, max_entries and max_size will be filled in by the function*/
+      uint32 max_entries;
+      
+      /**(Optional)If 0, max_entries and max_size will be filled in by the function*/
+      uint32 max_size;
+   } in;
+
+   struct {
+      /**Do not modify this value, use the same value between multiple calls (ie in while loop)*/
+      uint32 resume_idx;
+
+      /**Number of entries returned*/
+      uint32 num_entries;
+
+      /**Returned display info*/
+      SAM_DISPINFO_CTR ctr;
+
+      /**Internal value. Do not modify.*/
+      uint32 loop_count;
+
+      BOOL done;
+   } out;
+};
+
+/**
+ * Gets dislpay information using a SAM_DISPINFO_CTR.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamGetDisplayInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDisplayInfo *op);
+
+struct SamLookupDomain {
+   struct {
+      /**Open handle to the sam (opened with cac_SamConnect() or cac_SamOpenDomain()*/
+      POLICY_HND *sam;
+
+      /**Name of the domain to lookup*/
+      char *name;
+   } in;
+
+   struct {
+      /**SID of the domain*/
+      DOM_SID *sid;
+   } out;
+};
+
+/**
+ * Looks up a Domain SID given it's name.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamLookupDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamLookupDomain *op);
+
+struct SamGetSecurityObject {
+   struct {
+      /**An open handle (SAM, domain or user)*/
+      POLICY_HND *pol;
+   } in;
+
+   struct {
+      SEC_DESC_BUF *sec;
+   } out;
+};
+
+/**
+ * Retrievies Security descriptor information for a SAM/Domain/user
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamGetSecurityObject(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetSecurityObject *op);
+
+struct SamFlush {
+   struct {
+      /**Open handle to the domain SAM*/
+      POLICY_HND *dom_hnd;
+
+      /**(Optional)Domain SID. If NULL, the domain in hnd->domain will be opened*/
+      DOM_SID *sid;
+
+      /**(Optional)Desired access to re-open the domain with. If 0, MAXIMUM_ALLOWED_ACCESS is used.*/
+      uint32 access;
+   } in;
+};
+
+/**
+ * Closes the domain handle, then re-opens it - effectively flushing any changes made.
+ * WARNING: if this fails you will no longer have an open handle to the domain SAM.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SamFlush(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamFlush *op);
+
+/**@}*/ /*SAM_Functions*/
+
+/**@addtogroup SCM_Functions
+ * @{
+ */
+
+struct SvcOpenScm {
+   struct {
+      /**Desired access to open the Handle with. See SC_RIGHT_MGR_* or SC_MANAGER_* in include/rpc_secdes.h*/
+      uint32 access;
+   } in;
+
+   struct {
+      /**Handle to the SCM*/
+      POLICY_HND *scm_hnd;
+   } out;
+};
+
+/**
+ * Opens a handle to the SCM on the remote machine.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcOpenScm(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenScm *op);
+
+/**
+ * Closes an Svc handle (SCM or Service)
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param scm_hnd The handle to close
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *scm_hnd);
+
+struct SvcEnumServices {
+   struct {
+      /**Open handle to the SCM*/
+      POLICY_HND *scm_hnd;
+
+      /**(Optional)Type of service to enumerate. Possible values:
+       *  - SVCCTL_TYPE_WIN32
+       *  - SVCCTL_TYPE_DRIVER
+       *  If this is 0, (SVCCTL_TYPE_DRIVER | SVCCTL_TYPE_WIN32) is assumed.
+       */
+      uint32 type;
+
+      /**(Optional)State of service to enumerate. Possible values:
+       *  - SVCCTL_STATE_ACTIVE
+       *  - SVCCTL_STATE_INACTIVE
+       *  - SVCCTL_STATE_ALL
+       *  If this is 0, SVCCTL_STATE_ALL is assumed.
+       */
+      uint32 state;
+   } in;
+   
+   struct {
+      /**Number of services returned*/
+      uint32 num_services;
+
+      /**Array of service structures*/
+      CacService *services;
+   } out;
+};
+
+/**
+ * Enumerates services on the remote machine.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcEnumServices(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcEnumServices *op);
+
+struct SvcOpenService {
+   struct {
+      /**Handle to the Service Control Manager*/
+      POLICY_HND *scm_hnd;
+
+      /**Access mask to open service with see SERVICE_* or SC_RIGHT_SVC_* in include/rpc_secdes.h*/
+      uint32 access;
+
+      /**The name of the service. _not_ the display name*/
+      char *name;
+   } in;
+
+   struct {
+      /**Handle to the open service*/
+      POLICY_HND *svc_hnd;
+   } out;
+};
+
+/**
+ * Opens a handle to a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+
+int cac_SvcOpenService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenService *op);
+
+struct SvcGetStatus {
+   struct {
+      /**Open handle to the service to query*/
+      POLICY_HND *svc_hnd;
+   } in;
+
+   struct {
+      /**The status of the service. See include/rpc_svcctl.h for SERVICE_STATUS definition.*/
+      SERVICE_STATUS status;
+   } out;
+};
+
+/**
+ * Retrieves the status of a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcGetStatus(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetStatus *op);
+
+struct SvcStartService {
+   struct {
+      /**open handle to the service*/
+      POLICY_HND *svc_hnd;
+
+      /**Array of parameters to start the service with. Can be NULL if num_parms is 0*/
+      char **parms;
+
+      /**Number of parameters in the parms array*/
+      uint32 num_parms;
+
+      /**Number of seconds to wait for the service to actually start. If this is 0, then the status will not be checked after the initial call*/
+      uint32 timeout;
+   } in;
+};
+
+/**
+ * Attempts to start a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+
+int cac_SvcStartService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStartService *op);
+
+struct SvcControlService {
+   struct {
+      /**Open handle to the service to control*/
+      POLICY_HND *svc_hnd;
+
+      /**The control operation to perform. Possible values (from include/rpc_svcctl.h):
+       * - SVCCTL_CONTROL_STOP
+       * - SVCCTL_CONTROL_PAUSE
+       * - SVCCTL_CONTROL_CONTINUE
+       * - SVCCTL_CONTROL_SHUTDOWN
+       */
+      uint32 control;
+   } in;
+
+   struct {
+      /**The returned status of the service, _immediately_ after the call*/
+      SERVICE_STATUS *status;
+   } out;
+};
+
+/**
+ * Performs a control operation on a service and _immediately_ returns.
+ * @see cac_SvcStopService()
+ * @see cac_SvcPauseService()
+ * @see cac_SvcContinueService()
+ * @see cac_SvcShutdownService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcControlService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcControlService *op);
+
+struct SvcStopService {
+   struct {
+      /**Open handle to the service*/
+      POLICY_HND *svc_hnd;
+
+      /**Number of seconds to wait for the service to actually start. 
+       * If this is 0, then the status will not be checked after the initial call and CAC_SUCCESS might be returned if the status isn't actually started
+       */
+      uint32 timeout;
+   } in;
+
+   struct {
+      /**Status of the service after the operation*/
+      SERVICE_STATUS status;
+   } out;
+};
+
+/**
+ * Attempts to stop a service.
+ * @see cacSvcControlService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful. If hnd->status is NT_STATUS_OK, then a timeout occured.
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcStopService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStopService *op);
+
+struct SvcPauseService {
+   struct {
+      /**Open handle to the service*/
+      POLICY_HND *svc_hnd;
+
+      /**Number of seconds to wait for the service to actually start. 
+       * If this is 0, then the status will not be checked after the initial call and CAC_SUCCESS might be returned if the status isn't actually started
+       */
+      uint32 timeout;
+   } in;
+
+   struct {
+      /**Status of the service after the operation*/
+      SERVICE_STATUS status;
+   } out;
+};
+
+/**
+ * Attempts to pause a service.
+ * @see cacSvcControlService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful. If hnd->status is NT_STATUS_OK, then a timeout occured.
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcPauseService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcPauseService *op);
+
+struct SvcContinueService {
+   struct {
+      /**Open handle to the service*/
+      POLICY_HND *svc_hnd;
+
+      /**Number of seconds to wait for the service to actually start. 
+       * If this is 0, then the status will not be checked after the initial call and CAC_SUCCESS might be returned if the status isn't actually started
+       */
+      uint32 timeout;
+   } in;
+
+   struct {
+      /**Status of the service after the operation*/
+      SERVICE_STATUS status;
+   } out;
+};
+
+/**
+ * Attempts to continue a paused service.
+ * @see cacSvcControlService()
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful. If hnd->status is NT_STATUS_OK, then a timeout occured.
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcContinueService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcContinueService *op);
+
+struct SvcGetDisplayName {
+   struct {
+      /**Open handle to the service*/
+      POLICY_HND *svc_hnd;
+   } in;
+
+   struct {
+      /**The returned display name of the service*/
+      char *display_name;
+   } out;
+};
+
+/**
+ * Retrieves the display name of a service _not currently working_
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcGetDisplayName(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetDisplayName *op);
+
+struct SvcGetServiceConfig {
+   struct {
+      /**Open handle to the service*/
+      POLICY_HND *svc_hnd;
+   } in;
+
+   struct {
+      /**Returned Configuration information*/
+      CacServiceConfig config;
+   } out;
+};
+
+/**
+ * Retrieves configuration information about a service.
+ * @param hnd Initialized and connected server handle
+ * @param mem_ctx Context for memory allocation
+ * @param op Initialized Parameters
+ * @return CAC_FAILURE - the operation was not successful hnd->status is set appropriately
+ * @return CAC_SUCCESS - the operation was successful
+ */
+int cac_SvcGetServiceConfig(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetServiceConfig *op);
+
+/**@}*/ /*SCM_Functions*/
+
+#endif /* LIBMSRPC_H */
+
+
diff --git a/source/include/libmsrpc_internal.h b/source/include/libmsrpc_internal.h
new file mode 100644 (file)
index 0000000..5073813
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client internal definitions
+ *  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.
+ */
+
+#ifndef LIBMSRPC_INTERNAL_H
+#define LIBMSRPC_INTERNAL_H
+
+#include "libmsrpc.h"
+
+/*definitions*/
+
+struct CacServerHandleInternal {
+   /*stores the os type of the server*/
+   uint16 srv_level;
+
+   /*stores the initialized/active pipes*/
+   BOOL pipes[PI_MAX_PIPES];
+
+   /*underlying smbc context*/
+   SMBCCTX *ctx;
+
+   /*did the user supply this SMBCCTX?*/
+   BOOL user_supplied_ctx;
+};
+
+/*nessecary prototypes*/
+BOOL rid_in_list(uint32 rid, uint32 *list, uint32 list_len);
+
+int cac_ParseRegPath(char *path, uint32 *reg_type, char **key_name);
+
+REG_VALUE_DATA *cac_MakeRegValueData(TALLOC_CTX *mem_ctx, uint32 data_type, REGVAL_BUFFER buf);
+
+RPC_DATA_BLOB *cac_MakeRpcDataBlob(TALLOC_CTX *mem_ctx, uint32 data_type, REG_VALUE_DATA data);
+
+SAM_USERINFO_CTR *cac_MakeUserInfoCtr(TALLOC_CTX *mem_ctx, CacUserInfo *info);
+
+CacUserInfo *cac_MakeUserInfo(TALLOC_CTX *mem_ctx, SAM_USERINFO_CTR *ctr);
+CacGroupInfo *cac_MakeGroupInfo(TALLOC_CTX *mem_ctx, GROUP_INFO_CTR *ctr);
+GROUP_INFO_CTR *cac_MakeGroupInfoCtr(TALLOC_CTX *mem_ctx, CacGroupInfo *info);
+CacAliasInfo *cac_MakeAliasInfo(TALLOC_CTX *mem_ctx, ALIAS_INFO_CTR ctr);
+ALIAS_INFO_CTR *cac_MakeAliasInfoCtr(TALLOC_CTX *mem_ctx, CacAliasInfo *info);
+CacDomainInfo *cac_MakeDomainInfo(TALLOC_CTX *mem_ctx, SAM_UNK_INFO_1 *info1, SAM_UNK_INFO_2 *info2, SAM_UNK_INFO_12 *info12);
+CacService *cac_MakeServiceArray(TALLOC_CTX *mem_ctx, ENUM_SERVICES_STATUS *svc, uint32 num_services);
+int cac_InitCacServiceConfig(TALLOC_CTX *mem_ctx, SERVICE_CONFIG *src, CacServiceConfig *dest);
+
+SMBCSRV *smbc_attr_server(SMBCCTX *context,
+                          const char *server, const char *share, 
+                          fstring workgroup,
+                          fstring username, fstring password,
+                          POLICY_HND *pol);
+
+
+#endif /* LIBMSRPC_INTERNAL_H */
diff --git a/source/libmsrpc/Doxyfile b/source/libmsrpc/Doxyfile
new file mode 100644 (file)
index 0000000..f4e6f5e
--- /dev/null
@@ -0,0 +1,173 @@
+# Doxyfile 0.1
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = libmsrpc
+PROJECT_NUMBER         = 
+
+# NOTE: By default, Doxygen writes into the dox/ subdirectory of the
+# invocation directory.  If you want to put it somewhere else, for
+# example, to write straight into a webserver directory, then override
+# this variable in a configuration concatenated to this one: Doxygen
+# doesn't mind variables being redefined.
+
+OUTPUT_DIRECTORY       = dox
+
+OUTPUT_LANGUAGE        = English
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = YES
+EXTRACT_STATIC         = YES
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ALWAYS_DETAILED_SEC    = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = $(PWD)/
+INTERNAL_DOCS          = YES
+CLASS_DIAGRAMS         = YES
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = YES
+STRIP_CODE_COMMENTS    = NO
+CASE_SENSE_NAMES       = YES
+SHORT_NAMES            = NO
+HIDE_SCOPE_NAMES       = YES
+VERBATIM_HEADERS       = YES
+SHOW_INCLUDE_FILES     = YES
+JAVADOC_AUTOBRIEF      = YES
+INHERIT_DOCS           = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = NO
+DISTRIBUTE_GROUP_DOC   = NO
+TAB_SIZE               = 8
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+ALIASES                = 
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+OPTIMIZE_OUTPUT_FOR_C  = YES
+SHOW_USED_FILES        = YES
+REFERENCED_BY_RELATION = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = YES
+WARNINGS               = NO
+WARN_IF_UNDOCUMENTED   = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = ../include/ 
+FILE_PATTERNS          = libmsrpc.h 
+RECURSIVE              = YES
+EXCLUDE                =
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = 
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 1
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = .
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 3
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = YES
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+#---------------------------------------------------------------------------
+# configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = NO
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = 
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+TEMPLATE_RELATIONS     = YES
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+GRAPHICAL_HIERARCHY    = YES
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
+CGI_NAME               = search.cgi
+CGI_URL                = 
+DOC_URL                = 
+DOC_ABSPATH            = 
+BIN_ABSPATH            = /usr/local/bin/
+EXT_DOC_PATHS          = 
diff --git a/source/libmsrpc/cac_lsarpc.c b/source/libmsrpc/cac_lsarpc.c
new file mode 100644 (file)
index 0000000..911dc90
--- /dev/null
@@ -0,0 +1,1111 @@
+/* 
+ *  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;
+
+   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]) {
+      if(!cli_nt_session_open(&srv->cli, PI_LSARPC)) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_LSARPC] = True;
+   }
+
+   /**make sure we are working with the right pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   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 = cli_lsa_open_policy2(&(srv->cli), 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 = cli_lsa_open_policy(&srv->cli, 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) {
+
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*make sure we're on the right pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   hnd->status = cli_lsa_close(&(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*make sure we're on the right pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   /*now actually lookup the names*/
+   hnd->status = cli_lsa_lookup_sids(&(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*make sure we're on the right pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   /*now actually lookup the names*/
+   hnd->status = cli_lsa_lookup_names( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*now make sure that it's set up for the LSA pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   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 = cli_lsa_query_info_policy( &srv->cli, 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 = cli_lsa_query_info_policy( &srv->cli, 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*make sure we're on the right pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   /*only works if info_class parm is 12*/
+   hnd->status = cli_lsa_query_info_policy2(&(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   hnd->status = cli_lsa_enum_sids(&(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*make sure we are set up for the lsa pipe*/
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   if(op->in.name && !op->in.sid) {
+      DOM_SID *user_sid = NULL;
+      uint32 *type;
+
+      /*lookup the SID*/
+      hnd->status = cli_lsa_lookup_names( &(srv->cli), 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 = cli_lsa_enum_account_rights( &(srv->cli), 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) {
+   SMBCSRV *srv;
+   
+   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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   hnd->status = cli_lsa_enum_trust_dom( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   dom_pol = talloc(mem_ctx, POLICY_HND);
+   if(!dom_pol) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      errno = ENOMEM;
+      return CAC_FAILURE;
+   }
+   
+   hnd->status = cli_lsa_open_trusted_domain( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   if(op->in.domain_sid) {
+      hnd->status = cli_lsa_query_trusted_domain_info_by_sid( &(srv->cli), mem_ctx, op->in.pol, op->in.info_class, op->in.domain_sid, &dom_info);
+   }
+   else if(op->in.domain_name) {
+      hnd->status = cli_lsa_query_trusted_domain_info_by_name( &(srv->cli), 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) {
+   SMBCSRV *srv = NULL;
+
+   int 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   hnd->status = cli_lsa_enum_privilege(&(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   /*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 = cli_lsa_lookup_names( &(srv->cli), 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 = cli_lsa_open_account(&(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = cli_lsa_lookup_names( &(srv->cli), 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 = cli_lsa_add_account_rights( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = cli_lsa_lookup_names( &(srv->cli), 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 = cli_lsa_remove_account_rights( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = cli_lsa_lookup_names( &(srv->cli), 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 = cli_lsa_remove_account_rights( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   if(op->in.name && !op->in.sid) {
+      /*lookup the SID*/
+      hnd->status = cli_lsa_lookup_names( &(srv->cli), 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 = cli_lsa_remove_account_rights( &(srv->cli), mem_ctx, op->in.pol, *(op->in.sid), True, 0, NULL);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_lsa_add_account_rights( &(srv->cli), 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) {
+   SMBCSRV *srv = 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;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_LSARPC;
+
+   hnd->status = cli_lsa_query_secobj( &(srv->cli), 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;
+}
diff --git a/source/libmsrpc/cac_samr.c b/source/libmsrpc/cac_samr.c
new file mode 100644 (file)
index 0000000..c6efaa2
--- /dev/null
@@ -0,0 +1,2460 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client library implementation (SAMR 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 "libmsrpc_internal.h"
+
+/*used by cac_SamGetNamesFromRids*/
+#define SAMR_RID_UNKNOWN 8
+
+#define SAMR_ENUM_MAX_SIZE 0xffff
+
+/*not sure what this is.. taken from rpcclient/cmd_samr.c*/
+#define SAMR_LOOKUP_FLAGS 0x000003e8
+
+int cac_SamConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamConnect *op) {
+   SMBCSRV *srv        = NULL;
+   POLICY_HND *sam_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || op->in.access == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*initialize for samr pipe if we have to*/
+   if(!hnd->_internal.pipes[PI_SAMR]) {
+      if(!cli_nt_session_open(&srv->cli, PI_SAMR)) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_SAMR] = True;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   sam_out = talloc(mem_ctx, POLICY_HND);
+   if(!sam_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   if(hnd->_internal.srv_level >= SRV_WIN_2K_SP3) {
+      hnd->status = cli_samr_connect4( &(srv->cli), mem_ctx, op->in.access, sam_out);
+   }
+
+   if(hnd->_internal.srv_level < SRV_WIN_2K_SP3 || !NT_STATUS_IS_OK(hnd->status)) {
+      /*if sam_connect4 failed, the use sam_connect and lower srv_level*/
+
+      hnd->status = cli_samr_connect( &(srv->cli), mem_ctx, op->in.access, sam_out);
+
+      if(NT_STATUS_IS_OK(hnd->status) && hnd->_internal.srv_level > SRV_WIN_2K) {
+         hnd->_internal.srv_level = SRV_WIN_2K;
+      }
+   }
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.sam = sam_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *sam) {
+   SMBCSRV *srv        = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!sam || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+   
+   hnd->status = cli_samr_close( &(srv->cli), mem_ctx, sam);
+   
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+/*this is an internal function. Due to a circular dependency, it must be prototyped in libmsrpc.h (which I don't want to do)
+ * cac_SamOpenDomain() is the only function that calls it, so I just put the definition here
+ */
+/*attempts to find the sid of the domain we are connected to*/
+DOM_SID *cac_get_domain_sid(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, uint32 des_access) {
+   struct LsaOpenPolicy lop;
+   struct LsaFetchSid fs;
+
+   DOM_SID *sid;
+   
+   ZERO_STRUCT(lop);
+   ZERO_STRUCT(fs);
+
+   lop.in.access = des_access;
+   lop.in.security_qos = True;
+
+   if(!cac_LsaOpenPolicy(hnd, mem_ctx, &lop))
+      return NULL;
+
+   fs.in.pol = lop.out.pol;
+   fs.in.info_class = CAC_DOMAIN_INFO;
+
+   if(!cac_LsaFetchSid(hnd, mem_ctx, &fs))
+      return NULL;
+   
+   cac_LsaClosePolicy(hnd, mem_ctx, lop.out.pol);
+
+   if(!fs.out.domain_sid)
+      return NULL;
+
+   sid = talloc_memdup(mem_ctx, &(fs.out.domain_sid->sid), sizeof(DOM_SID));
+
+   if(!sid) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+   }
+
+   return sid;
+
+}
+
+int cac_SamOpenDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenDomain *op) {
+   SMBCSRV *srv = NULL;
+
+   DOM_SID *sid_buf;
+   POLICY_HND *sam_out;
+   POLICY_HND *pol_out;
+
+   struct SamLookupDomain sld;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || op->in.access == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   
+   if(!op->in.sam) {
+      /*use cac_SamConnect() since it does the session setup*/
+      struct SamConnect sc;
+      ZERO_STRUCT(sc);
+
+      sc.in.access = op->in.access;
+
+      if(!cac_SamConnect(hnd, mem_ctx, &sc)) {
+         return CAC_FAILURE;
+      }
+
+      sam_out = sc.out.sam;
+   }
+   else {
+      sam_out = op->in.sam;
+   }
+
+   if(!op->in.sid) {
+      /*find the sid for the SAM's domain*/
+      
+      /*try using cac_SamLookupDomain() first*/
+      ZERO_STRUCT(sld);
+
+      sld.in.sam  = sam_out;
+      sld.in.name = hnd->domain;
+
+      if(cac_SamLookupDomain(hnd, mem_ctx, &sld)) {
+         /*then we got the sid*/
+         sid_buf = sld.out.sid;
+      }
+      else {
+         /*try to get it from the LSA*/
+         sid_buf = cac_get_domain_sid(hnd, mem_ctx, op->in.access);
+      }
+   }
+   else {
+      /*we already have the sid for the domain we want*/
+      sid_buf = op->in.sid;
+   }
+
+
+   pol_out = talloc(mem_ctx, POLICY_HND);
+   if(!pol_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   /*now open the domain*/
+   hnd->status = cli_samr_open_domain( &(srv->cli), mem_ctx, sam_out, op->in.access, sid_buf, pol_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.sam     = sam_out;
+   op->out.dom_hnd = pol_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamOpenUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenUser *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 *rid_buf = NULL;
+
+   uint32 num_rids   = 0;
+   uint32 *rid_types = NULL;
+
+   POLICY_HND *user_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || op->in.access == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.rid == 0 && op->in.name == NULL) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   if(op->in.rid == 0 && op->in.name) {
+      /*lookup the name and then set rid_buf*/
+
+      hnd->status = cli_samr_lookup_names( &(srv->cli), mem_ctx, op->in.dom_hnd, SAMR_LOOKUP_FLAGS, 1, (const char **)&op->in.name, 
+            &num_rids, &rid_buf, &rid_types); 
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      if(num_rids == 0 || rid_buf == NULL || rid_types[0] == SAMR_RID_UNKNOWN) {
+         hnd->status = NT_STATUS_INVALID_PARAMETER;
+         return CAC_FAILURE;
+      }
+
+      talloc_free(rid_types);
+
+   }
+   else {
+      rid_buf = &op->in.rid;
+   }
+
+   user_out = talloc(mem_ctx, POLICY_HND);
+   if(!user_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_open_user(&(srv->cli), mem_ctx, op->in.dom_hnd, op->in.access, *rid_buf, user_out);
+   
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.user_hnd = user_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamCreateUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateUser *op) {
+   SMBCSRV *srv = NULL;
+
+   POLICY_HND *user_out = NULL;
+   uint32 rid_out;
+
+   /**found in rpcclient/cmd_samr.c*/
+   uint32 unknown = 0xe005000b;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !op->in.name || op->in.acb_mask == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   user_out = talloc(mem_ctx, POLICY_HND);
+   if(!user_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_create_dom_user( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.name, op->in.acb_mask, unknown, user_out, &rid_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.user_hnd = user_out;
+   op->out.rid      = rid_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamDeleteUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!user_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_delete_dom_user( &(srv->cli), mem_ctx, user_hnd);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamEnumUsers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumUsers *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 resume_idx_out = 0;
+   char **names_out      = NULL;
+   uint32 *rids_out      = NULL;
+   uint32 num_users_out  = 0;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   /*this is a hack.. but is the only reliable way to know if everything has been enumerated*/
+   if(op->out.done == True)
+      return CAC_FAILURE;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   resume_idx_out = op->out.resume_idx;
+
+   hnd->status = cli_samr_enum_dom_users( &(srv->cli), mem_ctx, op->in.dom_hnd, &resume_idx_out, op->in.acb_mask, SAMR_ENUM_MAX_SIZE, 
+                                                &names_out, &rids_out, &num_users_out);
+
+
+   if(NT_STATUS_IS_OK(hnd->status))
+      op->out.done = True;
+
+   /*if there are no more entries, the operation will return NT_STATUS_OK. 
+    * We want to return failure if no results were returned*/
+   if(!NT_STATUS_IS_OK(hnd->status) && NT_STATUS_V(hnd->status) != NT_STATUS_V(STATUS_MORE_ENTRIES))
+      return CAC_FAILURE;
+
+   op->out.resume_idx= resume_idx_out;
+   op->out.num_users = num_users_out;
+   op->out.rids      = rids_out;
+   op->out.names     = names_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetNamesFromRids(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetNamesFromRids *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 num_names_out;
+   char **names_out;
+   uint32 *name_types_out;
+
+
+   uint32 i = 0;
+
+   CacLookupRidsRecord *map_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.rids && op->in.num_rids != 0) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.num_rids == 0) {
+      /*nothing to do*/
+      op->out.num_names = 0;
+      return CAC_SUCCESS;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_lookup_rids( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.num_rids, op->in.rids, &num_names_out, &names_out, &name_types_out); 
+
+   if(!NT_STATUS_IS_OK(hnd->status) && !NT_STATUS_EQUAL(hnd->status, STATUS_SOME_UNMAPPED))
+      return CAC_FAILURE;
+
+   map_out = TALLOC_ARRAY(mem_ctx, CacLookupRidsRecord, num_names_out);
+   if(!map_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   for(i = 0; i < num_names_out; i++) {
+      if(name_types_out[i] == SAMR_RID_UNKNOWN) {
+         map_out[i].found = False;
+         map_out[i].name  = NULL;
+         map_out[i].type  = 0;
+      }
+      else {
+         map_out[i].found = True;
+         map_out[i].name = talloc_strdup(mem_ctx, names_out[i]);
+         map_out[i].type = name_types_out[i];
+      }
+      map_out[i].rid = op->in.rids[i];
+   }
+
+   talloc_free(names_out);
+   talloc_free(name_types_out);
+   
+   op->out.num_names = num_names_out;
+   op->out.map       = map_out;
+   
+   if(NT_STATUS_EQUAL(hnd->status, STATUS_SOME_UNMAPPED))
+      return CAC_PARTIAL_SUCCESS;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetRidsFromNames(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetRidsFromNames *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 num_rids_out;
+   uint32 *rids_out;
+   uint32 *rid_types_out;
+
+   uint32 i = 0;
+
+   CacLookupRidsRecord *map_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.names && op->in.num_names != 0) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.num_names == 0) {
+      /*then we don't have to do anything*/
+      op->out.num_rids = 0;
+      return CAC_SUCCESS;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_lookup_names( &(srv->cli), mem_ctx, op->in.dom_hnd, SAMR_LOOKUP_FLAGS, op->in.num_names, (const char **)op->in.names, 
+                                          &num_rids_out, &rids_out, &rid_types_out); 
+
+   if(!NT_STATUS_IS_OK(hnd->status) && !NT_STATUS_EQUAL(hnd->status, STATUS_SOME_UNMAPPED))
+      return CAC_FAILURE;
+
+   map_out = TALLOC_ARRAY(mem_ctx, CacLookupRidsRecord, num_rids_out);
+   if(!map_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   for(i = 0; i < num_rids_out; i++) {
+
+      if(rid_types_out[i] == SAMR_RID_UNKNOWN) {
+         map_out[i].found = False;
+         map_out[i].rid   = 0;
+         map_out[i].type  = 0;
+      }
+      else {
+         map_out[i].found = True;
+         map_out[i].rid   = rids_out[i];
+         map_out[i].type  = rid_types_out[i];
+      }
+
+      map_out[i].name = talloc_strdup(mem_ctx, op->in.names[i]);
+   }
+
+   op->out.num_rids = num_rids_out;
+   op->out.map      = map_out;
+
+   talloc_free(rids_out);
+   talloc_free(rid_types_out);
+   
+   if(NT_STATUS_EQUAL(hnd->status, STATUS_SOME_UNMAPPED))
+      return CAC_PARTIAL_SUCCESS;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_SamGetGroupsForUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupsForUser *op) {
+   SMBCSRV *srv = NULL;
+
+   DOM_GID *groups = NULL;
+   uint32 num_groups_out = 0;
+
+   uint32 *rids_out = NULL;
+   uint32 *attr_out = NULL;
+
+   uint32 i;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.user_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_usergroups(&(srv->cli), mem_ctx, op->in.user_hnd, &num_groups_out, &groups);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+
+   rids_out = talloc_array(mem_ctx, uint32, num_groups_out);
+   if(!rids_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   attr_out = talloc_array(mem_ctx, uint32, num_groups_out);
+   if(!attr_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+   
+   for(i = 0; i < num_groups_out; i++) {
+      rids_out[i] = groups[i].g_rid;
+      attr_out[i] = groups[i].attr;
+   }
+
+   talloc_free(groups);
+
+   op->out.num_groups = num_groups_out;
+   op->out.rids = rids_out;
+   op->out.attributes = attr_out;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_SamOpenGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenGroup *op) {
+   SMBCSRV *srv = NULL;
+
+   POLICY_HND *group_hnd_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || op->in.access == 0 || op->in.rid == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   group_hnd_out = talloc(mem_ctx, POLICY_HND);
+   if(!group_hnd_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_open_group( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.access, op->in.rid, group_hnd_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.group_hnd = group_hnd_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamCreateGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateGroup *op) {
+   SMBCSRV *srv = NULL;
+
+   POLICY_HND *group_hnd_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.name || op->in.name[0] == '\0' || op->in.access == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   group_hnd_out = talloc(mem_ctx, POLICY_HND);
+   if(!group_hnd_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_create_dom_group( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.name, op->in.access, group_hnd_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.group_hnd = group_hnd_out;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamDeleteGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!group_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_delete_dom_group( &(srv->cli), mem_ctx, group_hnd);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamGetGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupMembers *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 num_mem_out;
+   uint32 *rids_out;
+   uint32 *attr_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.group_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_groupmem( &(srv->cli), mem_ctx, op->in.group_hnd, &num_mem_out, &rids_out, &attr_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.num_members = num_mem_out;
+   op->out.rids        = rids_out;
+   op->out.attributes  = attr_out;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_SamAddGroupMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamAddGroupMember *op) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.group_hnd || op->in.rid == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_add_groupmem( &(srv->cli), mem_ctx, op->in.group_hnd, op->in.rid);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamRemoveGroupMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRemoveGroupMember *op) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.group_hnd || op->in.rid == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_del_groupmem( &(srv->cli), mem_ctx, op->in.group_hnd, op->in.rid);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamClearGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *group_hnd) {
+   SMBCSRV *srv = NULL;
+
+   int result = CAC_SUCCESS;
+
+   uint32 i = 0;
+
+   uint32 num_mem = 0;
+   uint32 *rid    = NULL;
+   uint32 *attr   = NULL;
+
+   NTSTATUS status;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!group_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_groupmem(&(srv->cli), mem_ctx, group_hnd, &num_mem, &rid, &attr);
+   
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   /*try to delete the users one by one*/
+   for(i = 0; i < num_mem && NT_STATUS_IS_OK(hnd->status); i++) {
+      hnd->status = cli_samr_del_groupmem(&(srv->cli), mem_ctx, group_hnd, rid[i]);
+   }
+
+   /*if not all members could be removed, then try to re-add the members that were already deleted*/
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      status = NT_STATUS_OK;
+
+      for(i -= 1; i >= 0 && NT_STATUS_IS_OK(status); i--) {
+         status = cli_samr_add_groupmem( &(srv->cli), mem_ctx, group_hnd, rid[i]);
+      }
+
+      /*we return with the NTSTATUS error that we got when trying to delete users*/
+      if(!NT_STATUS_IS_OK(status))
+         result = CAC_FAILURE;
+   }
+
+   talloc_free(attr);
+
+   return result;
+}
+
+int cac_SamSetGroupMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetGroupMembers *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 i = 0;
+   
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.group_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   /*use cac_SamClearGroupMembers() to clear them*/
+   if(!cac_SamClearGroupMembers(hnd, mem_ctx, op->in.group_hnd))
+      return CAC_FAILURE; /*hnd->status is already set*/
+
+
+   for(i = 0; i < op->in.num_members && NT_STATUS_IS_OK(hnd->status); i++) {
+      hnd->status = cli_samr_add_groupmem( &(srv->cli), mem_ctx, op->in.group_hnd, op->in.rids[i]);
+   }
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamEnumGroups(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumGroups *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 i              = 0;
+
+   uint32 resume_idx_out = 0;
+   char **names_out      = NULL;
+   char **desc_out       = NULL;
+   uint32 *rids_out      = NULL;
+   uint32 num_groups_out = 0;
+
+   struct acct_info *acct_buf = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   /*using this BOOL is the only reliable way to know that we are done*/
+   if(op->out.done == True) /*we return failure so the call will break out of a loop*/
+      return CAC_FAILURE;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   resume_idx_out = op->out.resume_idx;
+
+   hnd->status = cli_samr_enum_dom_groups( &(srv->cli), mem_ctx, op->in.dom_hnd, &resume_idx_out, SAMR_ENUM_MAX_SIZE, 
+                                                &acct_buf, &num_groups_out);
+
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      op->out.done = True;
+   }
+   else if(NT_STATUS_V(hnd->status) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+      /*if there are no more entries, the operation will return NT_STATUS_OK. 
+       * We want to return failure if no results were returned*/
+      return CAC_FAILURE;
+   }
+
+   names_out = talloc_array(mem_ctx, char *, num_groups_out);
+   if(!names_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(acct_buf);
+      return CAC_FAILURE;
+   }
+
+   desc_out = talloc_array(mem_ctx, char *, num_groups_out);
+   if(!desc_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(acct_buf);
+      talloc_free(names_out);
+      return CAC_FAILURE;
+   }
+
+   rids_out = talloc_array(mem_ctx, uint32, num_groups_out);
+   if(!rids_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(acct_buf);
+      talloc_free(names_out);
+      talloc_free(desc_out);
+      return CAC_FAILURE;
+   }
+
+   for(i = 0; i < num_groups_out; i++) {
+      names_out[i] = talloc_strdup(mem_ctx, acct_buf[i].acct_name);
+      desc_out[i]  = talloc_strdup(mem_ctx, acct_buf[i].acct_desc);
+      rids_out[i]  = acct_buf[i].rid;
+
+      if(!names_out[i] || !desc_out[i]) {
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+   }
+
+   op->out.resume_idx   = resume_idx_out;
+   op->out.num_groups   = num_groups_out;
+   op->out.rids         = rids_out;
+   op->out.names        = names_out;
+   op->out.descriptions = desc_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamEnumAliases(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamEnumAliases *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 i              = 0;
+
+   uint32 resume_idx_out = 0;
+   char **names_out      = NULL;
+   char **desc_out       = NULL;
+   uint32 *rids_out      = NULL;
+   uint32 num_als_out    = 0;
+
+   struct acct_info *acct_buf = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   /*this is a hack.. but is the only reliable way to know if everything has been enumerated*/
+   if(op->out.done == True) {
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   resume_idx_out = op->out.resume_idx;
+
+   hnd->status = cli_samr_enum_als_groups( &(srv->cli), mem_ctx, op->in.dom_hnd, &resume_idx_out, SAMR_ENUM_MAX_SIZE, 
+                                               &acct_buf, &num_als_out);
+
+
+   if(NT_STATUS_IS_OK(hnd->status))
+      op->out.done = True;
+
+   /*if there are no more entries, the operation will return NT_STATUS_OK. 
+    * We want to return failure if no results were returned*/
+   if(!NT_STATUS_IS_OK(hnd->status) && NT_STATUS_V(hnd->status) != NT_STATUS_V(STATUS_MORE_ENTRIES))
+      return CAC_FAILURE;
+
+   names_out = talloc_array(mem_ctx, char *, num_als_out);
+   if(!names_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(acct_buf);
+      return CAC_FAILURE;
+   }
+
+   desc_out = talloc_array(mem_ctx, char *, num_als_out);
+   if(!desc_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(acct_buf);
+      talloc_free(names_out);
+      return CAC_FAILURE;
+   }
+
+   rids_out = talloc_array(mem_ctx, uint32, num_als_out);
+   if(!rids_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(acct_buf);
+      talloc_free(names_out);
+      talloc_free(desc_out);
+      return CAC_FAILURE;
+   }
+
+   for(i = 0; i < num_als_out; i++) {
+      names_out[i] = talloc_strdup(mem_ctx, acct_buf[i].acct_name);
+      desc_out[i]  = talloc_strdup(mem_ctx, acct_buf[i].acct_desc);
+      rids_out[i]  = acct_buf[i].rid;
+
+      if(!names_out[i] || !desc_out[i]) {
+         hnd->status = NT_STATUS_NO_MEMORY;
+         return CAC_FAILURE;
+      }
+   }
+
+   op->out.resume_idx   = resume_idx_out;
+   op->out.num_aliases  = num_als_out;
+   op->out.rids         = rids_out;
+   op->out.names        = names_out;
+   op->out.descriptions = desc_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamCreateAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamCreateAlias *op) {
+   SMBCSRV *srv = NULL;
+
+   POLICY_HND *als_hnd_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.name || op->in.name[0] == '\0' || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   als_hnd_out = talloc(mem_ctx, POLICY_HND);
+   if(!als_hnd_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_create_dom_alias( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.name, als_hnd_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.alias_hnd = als_hnd_out;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamOpenAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamOpenAlias *op) {
+   SMBCSRV *srv = NULL;
+
+   POLICY_HND *als_hnd_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || op->in.access == 0 || op->in.rid == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   als_hnd_out = talloc(mem_ctx, POLICY_HND);
+   if(!als_hnd_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_open_alias( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.access, op->in.rid, als_hnd_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.alias_hnd = als_hnd_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamDeleteAlias(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *alias_hnd) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!alias_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_delete_dom_alias( &(srv->cli), mem_ctx, alias_hnd);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamAddAliasMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamAddAliasMember *op) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.alias_hnd || !op->in.sid || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_add_aliasmem( &(srv->cli), mem_ctx, op->in.alias_hnd, op->in.sid);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamRemoveAliasMember(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRemoveAliasMember *op) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.alias_hnd || !op->in.sid || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_del_aliasmem( &(srv->cli), mem_ctx, op->in.alias_hnd, op->in.sid);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetAliasMembers *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 num_mem_out;
+   DOM_SID *sids_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.alias_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_aliasmem( &(srv->cli), mem_ctx, op->in.alias_hnd, &num_mem_out, &sids_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.num_members = num_mem_out;
+   op->out.sids        = sids_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamClearAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *alias_hnd) {
+   SMBCSRV *srv = NULL;
+
+   int result = CAC_SUCCESS;
+
+   uint32 i = 0;
+
+   uint32 num_mem = 0;
+   DOM_SID *sid   = NULL;
+
+   NTSTATUS status;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!alias_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_aliasmem(&(srv->cli), mem_ctx, alias_hnd, &num_mem, &sid);
+   
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   /*try to delete the users one by one*/
+   for(i = 0; i < num_mem && NT_STATUS_IS_OK(hnd->status); i++) {
+      hnd->status = cli_samr_del_aliasmem(&(srv->cli), mem_ctx, alias_hnd, &sid[i]);
+   }
+
+   /*if not all members could be removed, then try to re-add the members that were already deleted*/
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      status = NT_STATUS_OK;
+
+      for(i -= 1; i >= 0 && NT_STATUS_IS_OK(status); i--) {
+         status = cli_samr_add_aliasmem( &(srv->cli), mem_ctx, alias_hnd, &sid[i]);
+      }
+
+      /*we return with the NTSTATUS error that we got when trying to delete users*/
+      if(!NT_STATUS_IS_OK(status))
+         result = CAC_FAILURE;
+   }
+
+   talloc_free(sid);
+   return result;
+}
+
+int cac_SamSetAliasMembers(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetAliasMembers *op) {
+   SMBCSRV *srv = NULL;
+
+   uint32 i = 0;
+   
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.alias_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   /*use cac_SamClearAliasMembers() to clear them*/
+   if(!cac_SamClearAliasMembers(hnd, mem_ctx, op->in.alias_hnd))
+      return CAC_FAILURE; /*hnd->status is already set*/
+
+
+   for(i = 0; i < op->in.num_members && NT_STATUS_IS_OK(hnd->status); i++) {
+      hnd->status = cli_samr_add_aliasmem( &(srv->cli), mem_ctx, op->in.alias_hnd, &(op->in.sids[i]));
+   }
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamUserChangePasswd(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamUserChangePasswd *op) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.username || !op->in.password || !op->in.new_password || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*open a session on SAMR if we don't have one*/
+   if(!hnd->_internal.pipes[PI_SAMR]) {
+      if(!cli_nt_session_open(&srv->cli, PI_SAMR)) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_SAMR] = True;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_chgpasswd_user(&(srv->cli), mem_ctx, op->in.username, op->in.new_password, op->in.password);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamEnableUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR *ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!user_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   /*info_level = 21 is the only level that I have found to work reliably. It would be nice if user_level = 10 worked.*/
+   hnd->status = cli_samr_query_userinfo( &(srv->cli), mem_ctx, user_hnd, 0x10, &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   /**check the ACB mask*/
+   if((ctr->info.id16->acb_info & ACB_DISABLED) == ACB_DISABLED) {
+      /*toggle the disabled bit*/
+      ctr->info.id16->acb_info ^= ACB_DISABLED;
+   }
+   else {
+      /*the user is already enabled so just return success*/
+      return CAC_SUCCESS;
+   }
+
+   /*now set the userinfo*/
+   hnd->status = cli_samr_set_userinfo2( &(srv->cli), mem_ctx, user_hnd, 0x10, &(srv->cli.user_session_key), ctr);
+
+   /*this will only work properly if we use set_userinfo2 - fail if it is not supported*/
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamDisableUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *user_hnd) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR *ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!user_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_userinfo( &(srv->cli), mem_ctx, user_hnd, 0x10, &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   if((ctr->info.id16->acb_info & ACB_DISABLED) == ACB_DISABLED) {
+      /*then the user is already disabled*/
+      return CAC_SUCCESS;
+   }
+
+   /*toggle the disabled bit*/
+   ctr->info.id16->acb_info ^= ACB_DISABLED;
+
+   /*this will only work properly if we use set_userinfo2*/
+   hnd->status = cli_samr_set_userinfo2( &(srv->cli), mem_ctx, user_hnd, 0x10, &(srv->cli.user_session_key), ctr);
+
+   /*this will only work properly if we use set_userinfo2 fail if it is not supported*/
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamSetPassword(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetPassword *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR ctr;
+   SAM_USER_INFO_24 info24;
+   uint8 pw[516];
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.user_hnd || !op->in.password || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   ZERO_STRUCT(ctr);
+   ZERO_STRUCT(info24);
+
+   encode_pw_buffer(pw, op->in.password, STR_UNICODE);
+
+   init_sam_user_info24(&info24, (char *)pw, 24);
+
+   ctr.switch_value = 24;
+   ctr.info.id24 = &info24;
+
+   hnd->status = cli_samr_set_userinfo( &(srv->cli), mem_ctx, op->in.user_hnd, 24, &(srv->cli.user_session_key), &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetUserInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetUserInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR *ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.user_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_userinfo( &(srv->cli), mem_ctx, op->in.user_hnd, 21, &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.info = cac_MakeUserInfo(mem_ctx, ctr);
+
+   if(!op->out.info) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamSetUserInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetUserInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR *ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.user_hnd || !op->in.info || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   ctr = cac_MakeUserInfoCtr(mem_ctx, op->in.info);
+   if(!ctr) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   if(hnd->_internal.srv_level >= SRV_WIN_NT4) {
+      hnd->status = cli_samr_set_userinfo2( &(srv->cli), mem_ctx, op->in.user_hnd, 21, &(srv->cli.user_session_key), ctr);
+   }
+
+   if(hnd->_internal.srv_level < SRV_WIN_NT4 || !NT_STATUS_IS_OK(hnd->status)) {
+      hnd->status = cli_samr_set_userinfo( &(srv->cli), mem_ctx, op->in.user_hnd, 21, &(srv->cli.user_session_key), ctr);
+
+      if(NT_STATUS_IS_OK(hnd->status) && hnd->_internal.srv_level > SRV_WIN_NT4) {
+         hnd->_internal.srv_level = SRV_WIN_NT4;
+      }
+   }
+
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_SamGetUserInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetUserInfoCtr *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR *ctr_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.user_hnd || op->in.info_class == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_userinfo( &(srv->cli), mem_ctx, op->in.user_hnd, op->in.info_class, &ctr_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) 
+      return CAC_FAILURE;
+
+   op->out.ctr = ctr_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamSetUserInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetUserInfoCtr *op) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.user_hnd || !op->in.ctr || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+
+   hnd->status = cli_samr_set_userinfo( &(srv->cli), mem_ctx, op->in.user_hnd, op->in.ctr->switch_value, &(srv->cli.user_session_key), op->in.ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamRenameUser(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRenameUser *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_USERINFO_CTR ctr;
+   SAM_USER_INFO_7 info7;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.user_hnd || !op->in.new_name || op->in.new_name[0] == '\0' || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+   
+   ZERO_STRUCT(ctr);
+   ZERO_STRUCT(info7);
+
+   init_sam_user_info7(&info7, op->in.new_name);
+   
+   ctr.switch_value = 7;
+   ctr.info.id7 = &info7;
+
+   hnd->status = cli_samr_set_userinfo( &(srv->cli), mem_ctx, op->in.user_hnd, 7, &(srv->cli.user_session_key), &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_SamGetGroupInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetGroupInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   GROUP_INFO_CTR *ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.group_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   /*get a GROUP_INFO_1 structure*/
+   hnd->status = cli_samr_query_groupinfo( &(srv->cli), mem_ctx, op->in.group_hnd, 1, &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.info = cac_MakeGroupInfo(mem_ctx, ctr);
+   if(!op->out.info) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamSetGroupInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetGroupInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   GROUP_INFO_CTR *ctr = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.group_hnd || !op->in.info || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   ctr = cac_MakeGroupInfoCtr(mem_ctx, op->in.info);
+   if(!ctr) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_set_groupinfo(&(srv->cli), mem_ctx, op->in.group_hnd, ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamRenameGroup(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamRenameGroup *op) {
+   SMBCSRV *srv = NULL;
+
+   GROUP_INFO_CTR ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.group_hnd || !op->in.new_name || op->in.new_name[0] == '\0' || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+   
+   ZERO_STRUCT(ctr);
+
+   init_samr_group_info2(&ctr.group.info2, op->in.new_name);
+   ctr.switch_value1 = 2;
+   
+   hnd->status = cli_samr_set_groupinfo( &(srv->cli), mem_ctx, op->in.group_hnd, &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetAliasInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetAliasInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   ALIAS_INFO_CTR ctr;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.alias_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   /*get a GROUP_INFO_1 structure*/
+   hnd->status = cli_samr_query_alias_info( &(srv->cli), mem_ctx, op->in.alias_hnd, 1, &ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.info = cac_MakeAliasInfo(mem_ctx, ctr);
+   if(!op->out.info) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+
+}
+
+int cac_SamSetAliasInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamSetAliasInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   ALIAS_INFO_CTR *ctr = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.alias_hnd || !op->in.info || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   ctr = cac_MakeAliasInfoCtr(mem_ctx, op->in.info);
+   if(!ctr) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_set_aliasinfo(&(srv->cli), mem_ctx, op->in.alias_hnd, ctr);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetDomainInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDomainInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_UNK_CTR ctr;
+   SAM_UNK_INFO_1 info1;
+   SAM_UNK_INFO_2 info2;
+   SAM_UNK_INFO_12 info12;
+
+   /*use this to keep track of a failed call*/
+   NTSTATUS status_buf = NT_STATUS_OK;
+
+   uint16 fail_count = 0;
+
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   /*first try with info 1*/
+   hnd->status = cli_samr_query_dom_info( &(srv->cli), mem_ctx, op->in.dom_hnd, 1, &ctr);
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      /*then we buffer the SAM_UNK_INFO_1 structure*/
+      info1 = ctr.info.inf1;
+   }
+   else {
+      /*then the call failed, store the status and ZERO out the info structure*/
+      ZERO_STRUCT(info1);
+      status_buf = hnd->status;
+      fail_count++;
+   }
+
+   /*try again for the next one*/
+   hnd->status = cli_samr_query_dom_info( &(srv->cli), mem_ctx, op->in.dom_hnd, 2, &ctr);
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      /*store the info*/
+      info2 = ctr.info.inf2;
+   }
+   else {
+      /*ZERO out the structure and store the bad status*/
+      ZERO_STRUCT(info2);
+      status_buf = hnd->status;
+      fail_count++;
+   }
+
+   /*once more*/
+   hnd->status = cli_samr_query_dom_info( &(srv->cli), mem_ctx, op->in.dom_hnd, 12, &ctr);
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      info12 = ctr.info.inf12;
+   }
+   else {
+      ZERO_STRUCT(info12);
+      status_buf = hnd->status;
+      fail_count++;
+   }
+
+   /*return failure if all 3 calls failed*/
+   if(fail_count == 3)
+      return CAC_FAILURE;
+
+   op->out.info = cac_MakeDomainInfo(mem_ctx, &info1, &info2, &info12);
+
+   if(!op->out.info) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   if(fail_count > 0) {
+      hnd->status = status_buf;
+      return CAC_PARTIAL_SUCCESS;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetDomainInfoCtr(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDomainInfoCtr *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_UNK_CTR *ctr_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.dom_hnd || op->in.info_class == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   ctr_out = talloc(mem_ctx, SAM_UNK_CTR);
+   if(!ctr_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_query_dom_info( &(srv->cli), mem_ctx, op->in.dom_hnd, op->in.info_class, ctr_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.info = ctr_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetDisplayInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetDisplayInfo *op) {
+   SMBCSRV *srv = NULL;
+
+   SAM_DISPINFO_CTR ctr_out;
+
+   uint32 max_entries_buf = 0;
+   uint32 max_size_buf    = 0;
+
+   uint32 resume_idx_out;
+   uint32 num_entries_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.dom_hnd || op->in.info_class == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(op->out.done == True) /*this is done so we can use the function as a loop condition*/
+      return CAC_FAILURE;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   if(op->in.max_entries == 0 || op->in.max_size == 0) {
+      get_query_dispinfo_params(op->out.loop_count, &max_entries_buf, &max_size_buf);
+   }
+   else {
+      max_entries_buf = op->in.max_entries;
+      max_size_buf    = op->in.max_size;
+   }
+
+   resume_idx_out = op->out.resume_idx;
+
+   hnd->status = cli_samr_query_dispinfo( &(srv->cli), mem_ctx, op->in.dom_hnd, &resume_idx_out, op->in.info_class, 
+                                             &num_entries_out, max_entries_buf, max_size_buf, &ctr_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status) && !NT_STATUS_EQUAL(hnd->status, STATUS_MORE_ENTRIES)) {
+      /*be defensive, maybe they'll call again without zeroing the struct*/ 
+      op->out.loop_count = 0;       
+      op->out.resume_idx = 0;
+      return CAC_FAILURE;
+   }
+
+   if(NT_STATUS_IS_OK(hnd->status)) {
+      /*we want to quit once the function is called next. so it can be used in a loop*/
+      op->out.done = True;
+   }
+
+   op->out.resume_idx  = resume_idx_out;
+   op->out.num_entries = num_entries_out;
+   op->out.ctr         = ctr_out;
+   op->out.loop_count++;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamLookupDomain(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamLookupDomain *op) {
+   SMBCSRV *srv = NULL;
+
+   DOM_SID *sid_out = NULL;
+   
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.sam || !op->in.name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   sid_out = talloc(mem_ctx, DOM_SID);
+   if(!sid_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   hnd->status = cli_samr_lookup_domain( &(srv->cli), mem_ctx, op->in.sam, op->in.name, sid_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.sid = sid_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamGetSecurityObject(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamGetSecurityObject *op) {
+   SMBCSRV *srv = NULL;
+
+   /*this number taken from rpcclient/cmd_samr.c, I think it is the only supported level*/
+   uint16 info_level = 4;
+
+   SEC_DESC_BUF *sec_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.pol || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   hnd->status = cli_samr_query_sec_obj(&(srv->cli), mem_ctx, op->in.pol, info_level, mem_ctx, &sec_out);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.sec = sec_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SamFlush(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SamFlush *op) {
+   SMBCSRV *srv = NULL;
+
+   struct SamOpenDomain od;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.dom_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SAMR;
+
+   if(!cac_SamClose(hnd, mem_ctx, op->in.dom_hnd))
+      return CAC_FAILURE;
+
+   ZERO_STRUCT(od);
+   od.in.access = (op->in.access) ? op->in.access : MAXIMUM_ALLOWED_ACCESS;
+   od.in.sid    = op->in.sid;
+
+   if(!cac_SamOpenDomain(hnd, mem_ctx, &od))
+      return CAC_FAILURE;
+
+   /*this function does not use an output parameter to make it as convenient as possible to use*/
+   *op->in.dom_hnd = *od.out.dom_hnd;
+
+   talloc_free(od.out.dom_hnd);
+
+   return CAC_SUCCESS;
+}
diff --git a/source/libmsrpc/cac_svcctl.c b/source/libmsrpc/cac_svcctl.c
new file mode 100644 (file)
index 0000000..71c83eb
--- /dev/null
@@ -0,0 +1,583 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client library implementation (SVCCTL 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"
+
+#define WAIT_SLEEP_TIME 300
+
+int cac_SvcOpenScm(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenScm *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   POLICY_HND *scm_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || op->in.access == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*initialize for samr pipe if we have to*/
+   if(!hnd->_internal.pipes[PI_SVCCTL]) {
+      if(!cli_nt_session_open(&srv->cli, PI_SVCCTL)) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_SVCCTL] = True;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   scm_out = talloc(mem_ctx, POLICY_HND);
+   if(!scm_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   err = cli_svcctl_open_scm( &(srv->cli), mem_ctx, scm_out, op->in.access);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.scm_hnd = scm_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SvcClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *scm_hnd) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!scm_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_close_service( &(srv->cli), mem_ctx, scm_hnd);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SvcEnumServices(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcEnumServices *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   uint32 type_buf  = 0;
+   uint32 state_buf = 0;
+
+   uint32 num_svc_out = 0;
+
+   ENUM_SERVICES_STATUS *svc_buf = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.scm_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   type_buf = (op->in.type != 0) ? op->in.type : (SVCCTL_TYPE_DRIVER | SVCCTL_TYPE_WIN32);
+   state_buf = (op->in.state != 0) ? op->in.state : SVCCTL_STATE_ALL;
+
+   err = cli_svcctl_enumerate_services( &(srv->cli), mem_ctx, op->in.scm_hnd, type_buf, state_buf, &num_svc_out, &svc_buf);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.services = cac_MakeServiceArray(mem_ctx, svc_buf, num_svc_out);
+
+   if(!op->out.services) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   talloc_free(svc_buf);
+
+   op->out.num_services = num_svc_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SvcOpenService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenService *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   POLICY_HND *svc_hnd_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.scm_hnd || !op->in.name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   svc_hnd_out = talloc(mem_ctx, POLICY_HND);
+   if(!svc_hnd_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   err = cli_svcctl_open_service( &(srv->cli), mem_ctx, op->in.scm_hnd, svc_hnd_out, op->in.name, op->in.access);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.svc_hnd = svc_hnd_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SvcControlService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcControlService *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_STATUS status_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.control < SVCCTL_CONTROL_STOP || op->in.control > SVCCTL_CONTROL_SHUTDOWN) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_control_service( &(srv->cli), mem_ctx, op->in.svc_hnd, op->in.control, &status_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+int cac_SvcGetStatus(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetStatus *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_STATUS status_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_query_status( &(srv->cli), mem_ctx, op->in.svc_hnd, &status_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.status = status_out;
+
+   return CAC_SUCCESS;
+}
+
+
+
+/*Internal function - similar to code found in utils/net_rpc_service.c
+ * Waits for a service to reach a specific state.
+ * svc_hnd - Handle to the service
+ * state   - the state we are waiting for
+ * timeout - number of seconds to wait
+ * returns CAC_FAILURE if the state is never reached
+ *      or CAC_SUCCESS if the state is reached
+ */
+int cac_WaitForService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *svc_hnd, uint32 state, uint32 timeout, SERVICE_STATUS *status) {
+   SMBCSRV *srv = NULL;
+   /*number of milliseconds we have spent*/
+   uint32 time_spent = 0;
+   WERROR err;
+
+   if(!hnd || !mem_ctx || !svc_hnd || !status)
+      return CAC_FAILURE;
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   while(status->state != state && time_spent < (timeout * 1000) && NT_STATUS_IS_OK(hnd->status)) {
+      /*if this is the first call, then we _just_ got the status.. sleep now*/
+      usleep(WAIT_SLEEP_TIME);
+      time_spent += WAIT_SLEEP_TIME;
+
+      err = cli_svcctl_query_status(&(srv->cli), mem_ctx, svc_hnd, status);
+      hnd->status = werror_to_ntstatus(err);
+   }
+   
+   if(status->state == state) 
+      return CAC_SUCCESS;
+
+   return CAC_FAILURE;
+}
+
+int cac_SvcStartService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStartService *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_STATUS status_buf;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   if(op->in.num_parms != 0 && op->in.parms == NULL) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_start_service(&(srv->cli), mem_ctx, op->in.svc_hnd, (const char **)op->in.parms, op->in.num_parms);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   if(op->in.timeout == 0)
+      return CAC_SUCCESS;
+
+   return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_RUNNING, op->in.timeout, &status_buf);
+}
+
+int cac_SvcStopService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStopService *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_STATUS status_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_control_service( &(srv->cli), mem_ctx, op->in.svc_hnd, SVCCTL_CONTROL_STOP, &status_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.status = status_out;
+
+   if(op->in.timeout == 0)
+      return CAC_SUCCESS;
+
+   return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_STOPPED, op->in.timeout, &op->out.status);
+}
+
+int cac_SvcPauseService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcPauseService *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_STATUS status_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_control_service( &(srv->cli), mem_ctx, op->in.svc_hnd, SVCCTL_CONTROL_PAUSE, &status_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.status = status_out;
+
+   if(op->in.timeout == 0)
+      return CAC_SUCCESS;
+
+   return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_PAUSED, op->in.timeout, &op->out.status);
+}
+
+int cac_SvcContinueService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcContinueService *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_STATUS status_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_control_service( &(srv->cli), mem_ctx, op->in.svc_hnd, SVCCTL_CONTROL_CONTINUE, &status_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.status = status_out;
+
+   if(op->in.timeout == 0)
+      return CAC_SUCCESS;
+
+   return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_RUNNING, op->in.timeout, &op->out.status);
+}
+
+int cac_SvcGetDisplayName(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetDisplayName *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   fstring disp_name_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_get_dispname( &(srv->cli), mem_ctx, op->in.svc_hnd, disp_name_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.display_name = talloc_strdup(mem_ctx, disp_name_out);
+
+   if(!op->out.display_name) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_SvcGetServiceConfig(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetServiceConfig *op) {
+   SMBCSRV *srv        = NULL;
+   WERROR err;
+
+   SERVICE_CONFIG config_out;
+   
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.svc_hnd || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SVCCTL;
+
+   err = cli_svcctl_query_config( &(srv->cli), mem_ctx, op->in.svc_hnd, &config_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   if(!cac_InitCacServiceConfig(mem_ctx, &config_out, &op->out.config)) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+
+}
diff --git a/source/libmsrpc/cac_winreg.c b/source/libmsrpc/cac_winreg.c
new file mode 100644 (file)
index 0000000..3a90aa8
--- /dev/null
@@ -0,0 +1,1033 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client library implementation (WINREG 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 "libmsrpc_internal.h"
+
+
+int cac_RegConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegConnect *op) {
+   SMBCSRV *srv = NULL;
+   POLICY_HND *key = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.root || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*initialize for winreg pipe if we have to*/
+   if(!hnd->_internal.pipes[PI_WINREG]) {
+      if(!cli_nt_session_open(&srv->cli, PI_WINREG)) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_WINREG] = True;
+   }
+
+   key = talloc(mem_ctx, POLICY_HND);
+   if(!key) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+   }
+
+   err = cli_reg_connect( &(srv->cli), mem_ctx, op->in.root, op->in.access, key);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.key = key;
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *key) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!key || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   err = cli_reg_close(&srv->cli, mem_ctx, key);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegOpenKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegOpenKey *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   POLICY_HND *key_out;
+   POLICY_HND *parent_key;
+
+   char *key_name = NULL;
+   uint32 reg_type = 0;
+
+   struct RegConnect rc;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+
+   key_out = talloc(mem_ctx, POLICY_HND);
+   if(!key_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.parent_key) {
+      /*then we need to connect to the registry*/
+      if(!cac_ParseRegPath(op->in.name, &reg_type, &key_name)) {
+         hnd->status = NT_STATUS_INVALID_PARAMETER;
+         return CAC_FAILURE;
+      }
+
+      /*use cac_RegConnect because it handles the session setup*/
+      ZERO_STRUCT(rc);
+
+      rc.in.access = op->in.access;
+      rc.in.root   = reg_type;
+
+      if(!cac_RegConnect(hnd, mem_ctx, &rc)) {
+         return CAC_FAILURE;
+      }
+
+      /**if they only specified the root key, return the key we just opened*/
+      if(key_name == NULL) {
+         op->out.key = rc.out.key;
+         return CAC_SUCCESS;
+      }
+
+      parent_key = rc.out.key;
+   }
+   else {
+      parent_key  = op->in.parent_key;
+      key_name    = op->in.name;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_open_entry( &(srv->cli), mem_ctx, parent_key, key_name, op->in.access, key_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   if(!op->in.parent_key) {
+      /*then close the one that we opened above*/
+      err = cli_reg_close( &(srv->cli), mem_ctx, parent_key);
+      hnd->status = werror_to_ntstatus(err);
+
+      if(!NT_STATUS_IS_OK(hnd->status)) {
+         return CAC_FAILURE;
+      }
+   }
+
+   op->out.key = key_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegEnumKeys(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumKeys *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   /*buffers for cli_reg_enum_key call*/
+   fstring key_name_in;
+   fstring class_name_in;
+
+   /*output buffers*/
+   char **key_names_out   = NULL;
+   char **class_names_out = NULL;
+   time_t *mod_times_out   = NULL;
+   uint32 num_keys_out    = 0;
+   uint32 resume_idx      = 0;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   /*this is to avoid useless rpc calls, if the last call exhausted all the keys, then we don't need to go through everything again*/
+   if(NT_STATUS_V(hnd->status) == NT_STATUS_V(NT_STATUS_GUIDS_EXHAUSTED))
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || op->in.max_keys == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   /**the only way to know how many keys to expect is to assume max_keys keys will be found*/
+   key_names_out = TALLOC_ARRAY(mem_ctx, char *, op->in.max_keys);
+   if(!key_names_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   class_names_out = TALLOC_ARRAY(mem_ctx, char *, op->in.max_keys);
+   if(!class_names_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(key_names_out);
+      return CAC_FAILURE;
+   }
+
+   mod_times_out = TALLOC_ARRAY(mem_ctx, time_t, op->in.max_keys);
+   if(!mod_times_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      talloc_free(key_names_out);
+      talloc_free(class_names_out);
+
+      return CAC_FAILURE;
+   }
+   resume_idx = op->out.resume_idx;
+
+   do {
+      err = cli_reg_enum_key( &(srv->cli), mem_ctx, op->in.key, resume_idx, key_name_in, class_name_in, &mod_times_out[num_keys_out]);
+      hnd->status = werror_to_ntstatus(err);
+
+      if(!NT_STATUS_IS_OK(hnd->status)) {
+         /*don't increment any values*/
+         break;
+      }
+
+      key_names_out[num_keys_out] = talloc_strdup(mem_ctx, key_name_in);
+
+      class_names_out[num_keys_out] = talloc_strdup(mem_ctx, class_name_in);
+
+      if(!key_names_out[num_keys_out] || !class_names_out[num_keys_out]) {
+         hnd->status = NT_STATUS_NO_MEMORY;
+         break;
+      }
+      
+      resume_idx++;
+      num_keys_out++;
+   } while(num_keys_out < op->in.max_keys);
+
+   if(CAC_OP_FAILED(hnd->status)) {
+      op->out.num_keys = 0;
+      return CAC_FAILURE;
+   }
+
+   op->out.resume_idx   = resume_idx;
+   op->out.num_keys     = num_keys_out;
+   op->out.key_names    = key_names_out;
+   op->out.class_names  = class_names_out;
+   op->out.mod_times    = mod_times_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegCreateKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegCreateKey *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   POLICY_HND *key_out;
+
+   struct RegOpenKey rok;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.parent_key || !op->in.key_name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*first try to open the key - we use cac_RegOpenKey(). this doubles as a way to ensure the winreg pipe is initialized*/
+   ZERO_STRUCT(rok);
+
+   rok.in.name = op->in.key_name;
+   rok.in.access = op->in.access;
+   rok.in.parent_key = op->in.parent_key;
+
+   if(cac_RegOpenKey(hnd, mem_ctx, &rok)) {
+      /*then we got the key, return*/
+      op->out.key = rok.out.key;
+      return CAC_SUCCESS;
+   }
+
+   /*just be ultra-safe*/
+   srv->cli.pipe_idx = PI_WINREG;
+
+   key_out = talloc(mem_ctx, POLICY_HND);
+   if(!key_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   err = cli_reg_create_key_ex( &(srv->cli), mem_ctx, op->in.parent_key, op->in.key_name, op->in.class_name, op->in.access, key_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.key = key_out;
+
+   return CAC_SUCCESS;
+
+}
+
+WERROR cac_delete_subkeys_recursive(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *key) {
+   /*NOTE: using cac functions might result in a big(ger) memory bloat, and would probably be far less efficient 
+    * so we use the cli_reg functions directly*/
+
+   WERROR err = WERR_OK;
+
+   POLICY_HND subkey;
+   fstring subkey_name;
+   fstring class_buf;
+   time_t mod_time_buf;
+
+   int cur_key = 0;
+
+   while(W_ERROR_IS_OK(err)) {
+      err = cli_reg_enum_key( cli, mem_ctx, key, cur_key, subkey_name, class_buf, &mod_time_buf); 
+
+      if(!W_ERROR_IS_OK(err))
+         break;
+
+      /*try to open the key with full access*/
+      err = cli_reg_open_entry(cli, mem_ctx, key, subkey_name, REG_KEY_ALL, &subkey);
+
+      if(!W_ERROR_IS_OK(err))
+         break;
+
+      err = cac_delete_subkeys_recursive(cli, mem_ctx, &subkey);
+
+      if(!W_ERROR_EQUAL(err,WERR_NO_MORE_ITEMS) && !W_ERROR_IS_OK(err))
+         break;
+
+      /*flush the key just to be safe*/
+      cli_reg_flush_key(cli, mem_ctx, key);
+      
+      /*close the key that we opened*/
+      cli_reg_close(cli, mem_ctx, &subkey);
+
+      /*now we delete the subkey*/
+      err = cli_reg_delete_key(cli, mem_ctx, key, subkey_name);
+
+
+      cur_key++;
+   }
+
+
+   return err;
+}
+
+
+
+int cac_RegDeleteKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteKey *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.parent_key || !op->in.name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   if(op->in.recursive) {
+      /*first open the key, and then delete all of it's subkeys recursively*/
+      struct RegOpenKey rok;
+      ZERO_STRUCT(rok);
+
+      rok.in.parent_key = op->in.parent_key;
+      rok.in.name       = op->in.name;
+      rok.in.access     = REG_KEY_ALL;
+
+      if(!cac_RegOpenKey(hnd, mem_ctx, &rok))
+         return CAC_FAILURE;
+
+      err = cac_delete_subkeys_recursive(&(srv->cli), mem_ctx, rok.out.key);
+
+      /*close the key that we opened*/
+      cac_RegClose(hnd, mem_ctx, rok.out.key);
+
+      hnd->status = werror_to_ntstatus(err);
+
+      if(NT_STATUS_V(hnd->status) != NT_STATUS_V(NT_STATUS_GUIDS_EXHAUSTED) && !NT_STATUS_IS_OK(hnd->status))
+         return CAC_FAILURE;
+
+      /*now go on to actually delete the key*/
+   }
+
+   err = cli_reg_delete_key( &(srv->cli), mem_ctx, op->in.parent_key, op->in.name);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegDeleteValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteValue *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.parent_key || !op->in.name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_delete_val( &(srv->cli), mem_ctx, op->in.parent_key, op->in.name);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegQueryKeyInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryKeyInfo *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   char *class_name_out    = NULL;
+   uint32 class_len        = 0;
+   uint32 num_subkeys_out  = 0;
+   uint32 long_subkey_out  = 0;
+   uint32 long_class_out   = 0;
+   uint32 num_values_out   = 0;
+   uint32 long_value_out   = 0;
+   uint32 long_data_out    = 0;
+   uint32 secdesc_size     = 0;
+   NTTIME mod_time;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_query_key( &(srv->cli), mem_ctx, op->in.key,
+                              class_name_out,
+                              &class_len,
+                              &num_subkeys_out,
+                              &long_subkey_out,
+                              &long_class_out,
+                              &num_values_out,
+                              &long_value_out,
+                              &long_data_out,
+                              &secdesc_size,
+                              &mod_time);
+
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   if(!class_name_out) {
+      op->out.class_name = talloc_strdup(mem_ctx, "");
+   }
+   else if(class_len != 0 && class_name_out[class_len - 1] != '\0') {
+      /*then we need to add a '\0'*/
+      op->out.class_name = talloc_size(mem_ctx, sizeof(char)*(class_len + 1));
+
+      memcpy(op->out.class_name, class_name_out, class_len);
+
+      op->out.class_name[class_len] = '\0';
+   }
+   else { /*then everything worked out fine in the function*/
+      op->out.class_name = talloc_strdup(mem_ctx, class_name_out);
+   }
+
+   if(!op->out.class_name) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   op->out.num_subkeys        = num_subkeys_out;
+   op->out.longest_subkey     = long_subkey_out;
+   op->out.longest_class      = long_class_out;
+   op->out.num_values         = num_values_out;
+   op->out.longest_value_name = long_value_out;
+   op->out.longest_value_data = long_data_out;
+   op->out.security_desc_size = secdesc_size;
+   op->out.last_write_time    = nt_time_to_unix(&mod_time);
+
+   return CAC_FAILURE;
+}
+
+int cac_RegQueryValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryValue *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   uint32 val_type;
+   REGVAL_BUFFER buffer;
+   REG_VALUE_DATA *data_out = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || !op->in.val_name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_query_value(&srv->cli, mem_ctx, op->in.key, op->in.val_name, &val_type, &buffer);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   data_out = cac_MakeRegValueData(mem_ctx, val_type, buffer);
+   if(!data_out) {
+      if(errno == ENOMEM)
+         hnd->status = NT_STATUS_NO_MEMORY;
+      else
+         hnd->status = NT_STATUS_INVALID_PARAMETER;
+
+      return CAC_FAILURE;
+   }
+
+   op->out.type = val_type;
+   op->out.data = data_out;
+
+   return CAC_SUCCESS;
+}
+
+
+int cac_RegEnumValues(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumValues *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   /*buffers for cli_reg_enum_key call*/
+   fstring val_name_buf;
+   REGVAL_BUFFER val_buf;
+
+   /*output buffers*/
+   uint32 *types_out          = NULL;
+   REG_VALUE_DATA **values_out = NULL;
+   char **val_names_out       = NULL;
+   uint32 num_values_out      = 0;
+   uint32 resume_idx          = 0;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   /*this is to avoid useless rpc calls, if the last call exhausted all the keys, then we don't need to go through everything again*/
+   if(NT_STATUS_V(hnd->status) == NT_STATUS_V(NT_STATUS_GUIDS_EXHAUSTED))
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || op->in.max_values == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   /*we need to assume that the max number of values will be enumerated*/
+   types_out = talloc_array(mem_ctx, int, op->in.max_values);
+   if(!types_out) {
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   values_out = talloc_array(mem_ctx, REG_VALUE_DATA *, op->in.max_values);
+   if(!values_out) {
+      talloc_free(types_out);
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   val_names_out = talloc_array(mem_ctx, char *, op->in.max_values);
+   if(!val_names_out) {
+      talloc_free(types_out);
+      talloc_free(values_out);
+      hnd->status = NT_STATUS_NO_MEMORY;
+      return CAC_FAILURE;
+   }
+
+   resume_idx = op->out.resume_idx;
+   do {
+      ZERO_STRUCT(val_buf);
+
+      err = cli_reg_enum_val(&srv->cli, mem_ctx, op->in.key, resume_idx, val_name_buf, &types_out[num_values_out], &val_buf);
+      hnd->status = werror_to_ntstatus(err);
+
+      if(!NT_STATUS_IS_OK(hnd->status))
+         break;
+
+      values_out[num_values_out] = cac_MakeRegValueData(mem_ctx, types_out[num_values_out], val_buf);
+      val_names_out[num_values_out] = talloc_strdup(mem_ctx, val_name_buf);
+
+      if(!val_names_out[num_values_out] || !values_out[num_values_out]) {
+         hnd->status = NT_STATUS_NO_MEMORY;
+         break;
+      }
+
+      num_values_out++;
+      resume_idx++;
+   } while(num_values_out < op->in.max_values);
+
+   if(CAC_OP_FAILED(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.types        = types_out;
+   op->out.num_values   = num_values_out;
+   op->out.value_names  = val_names_out;
+   op->out.values       = values_out;
+   op->out.resume_idx   = resume_idx;
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegSetValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetValue *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   RPC_DATA_BLOB *buffer;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || !op->in.val_name || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   buffer = cac_MakeRpcDataBlob(mem_ctx, op->in.type, op->in.value);
+
+   if(!buffer) {
+      if(errno == ENOMEM)
+         hnd->status = NT_STATUS_NO_MEMORY;
+      else
+         hnd->status = NT_STATUS_INVALID_PARAMETER;
+
+      return CAC_FAILURE;
+   }
+
+   err = cli_reg_set_val(&srv->cli, mem_ctx, op->in.key, op->in.val_name, op->in.type, buffer);
+   hnd->status = werror_to_ntstatus(err);
+   
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   /*flush*/
+   err = cli_reg_flush_key(&(srv->cli), mem_ctx, op->in.key);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
+
+
+int cac_RegGetVersion(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetVersion *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   uint32 version_out;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_getversion( &(srv->cli), mem_ctx, op->in.key, &version_out);
+   hnd->status = werror_to_ntstatus(err);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   op->out.version = version_out;
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegGetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetKeySecurity *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   uint32 buf_size;
+   SEC_DESC_BUF *buf = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || op->in.info_type == 0 || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_get_key_sec(&(srv->cli), mem_ctx, op->in.key, op->in.info_type, &buf_size, buf);
+   hnd->status = werror_to_ntstatus(err);
+
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   op->out.size = buf->len;
+   op->out.descriptor = buf->sec;
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegSetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetKeySecurity *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || op->in.info_type == 0 || op->in.size == 0 || !op->in.descriptor || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_set_key_sec(&(srv->cli), mem_ctx, op->in.key, op->in.info_type, op->in.size, op->in.descriptor);
+   hnd->status = werror_to_ntstatus(err);
+
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_RegSaveKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSaveKey *op) {
+   SMBCSRV *srv = NULL;
+   WERROR err;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !op->in.key || !op->in.filename || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_WINREG;
+
+   err = cli_reg_save_key( &(srv->cli), mem_ctx, op->in.key, op->in.filename);
+   hnd->status = werror_to_ntstatus(err);
+
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_Shutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Shutdown *op) {
+   SMBCSRV *srv = NULL;
+
+   char *msg;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   if(!op || !mem_ctx) {
+      hnd->status = NT_STATUS_INVALID_PARAMETER;
+      return CAC_FAILURE;
+   }
+
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   /*initialize for winreg pipe if we have to*/
+   if(!hnd->_internal.pipes[PI_SHUTDOWN]) {
+      if(!cli_nt_session_open(&srv->cli, PI_SHUTDOWN)) {
+         hnd->status = NT_STATUS_UNSUCCESSFUL;
+         return CAC_FAILURE;
+      }
+
+      hnd->_internal.pipes[PI_SHUTDOWN] = True;
+   }
+
+   srv->cli.pipe_idx = PI_SHUTDOWN;
+
+   msg = (op->in.message != NULL) ? op->in.message : talloc_strdup(mem_ctx, "");
+
+   hnd->status = NT_STATUS_OK;
+
+   if(hnd->_internal.srv_level > SRV_WIN_NT4) {
+      hnd->status = cli_shutdown_init_ex( &(srv->cli), mem_ctx, msg, op->in.timeout, op->in.reboot, op->in.force, op->in.reason);
+   }
+
+   if(hnd->_internal.srv_level < SRV_WIN_2K || !NT_STATUS_IS_OK(hnd->status)) {
+      hnd->status = cli_shutdown_init( &(srv->cli), mem_ctx, msg, op->in.timeout, op->in.reboot, op->in.force);
+
+      hnd->_internal.srv_level = SRV_WIN_NT4;
+   }
+
+   if(!NT_STATUS_IS_OK(hnd->status)) {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+int cac_AbortShutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx) {
+   SMBCSRV *srv = NULL;
+
+   if(!hnd) 
+      return CAC_FAILURE;
+
+   if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_SHUTDOWN]) {
+      hnd->status = NT_STATUS_INVALID_HANDLE;
+      return CAC_FAILURE;
+   }
+
+   srv = cac_GetServer(hnd);
+   if(!srv) {
+      hnd->status = NT_STATUS_INVALID_CONNECTION;
+      return CAC_FAILURE;
+   }
+
+   srv->cli.pipe_idx = PI_SHUTDOWN;
+
+   hnd->status = cli_shutdown_abort(&(srv->cli), mem_ctx);
+
+   if(!NT_STATUS_IS_OK(hnd->status))
+      return CAC_FAILURE;
+
+   return CAC_SUCCESS;
+}
+
diff --git a/source/libmsrpc/libmsrpc.c b/source/libmsrpc/libmsrpc.c
new file mode 100644 (file)
index 0000000..05f2dfe
--- /dev/null
@@ -0,0 +1,352 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client library implementation
+ *  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 "libmsrpc_internal.h"
+#include "libsmbclient.h"
+#include "libsmb_internal.h"
+
+/*this function is based on code found in smbc_init_context() (libsmb/libsmbclient.c)*/
+void cac_Init(int debug) {
+   if(debug < 0 || debug > 99)
+      debug = 0;
+
+   DEBUGLEVEL = debug;
+
+   setup_logging("libmsrpc", True);
+}
+
+int cac_InitHandleMem(CacServerHandle *hnd) {
+   hnd->username       = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   if(!hnd->username)
+      return CAC_FAILURE;
+
+   hnd->username[0] = '\0';
+
+   hnd->domain         = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   if(!hnd->domain)
+      return CAC_FAILURE;
+   
+   hnd->domain[0] = '\0';
+
+   hnd->netbios_name   = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   if(!hnd->netbios_name)
+      return CAC_FAILURE;
+
+   hnd->netbios_name[0] = '\0';
+
+   hnd->password       = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   if(!hnd->password)
+      return CAC_FAILURE;
+
+   hnd->password[0] = '\0';
+
+   hnd->server         = SMB_MALLOC_ARRAY(char, sizeof(fstring));
+   if(!hnd->server)
+      return CAC_FAILURE;
+
+   hnd->server[0] = '\0';
+
+   return CAC_SUCCESS;
+}
+
+CacServerHandle *cac_NewServerHandle(BOOL allocate_fields) {
+   CacServerHandle * hnd;
+
+   hnd = SMB_MALLOC_P(CacServerHandle);
+
+   if(!hnd) {
+      errno = ENOMEM;
+      return NULL;
+   }
+   
+   ZERO_STRUCTP(hnd);
+
+   if(allocate_fields == True) {
+      if(!cac_InitHandleMem(hnd)) {
+         SAFE_FREE(hnd);
+         return NULL;
+      }
+   }
+
+   hnd->_internal.ctx = smbc_new_context();
+   if(!hnd->_internal.ctx) {
+      cac_FreeHandle(hnd);
+      return NULL;
+   }
+
+   hnd->_internal.ctx->callbacks.auth_fn = cac_GetAuthDataFn;
+   
+   /*add defaults*/
+   hnd->debug = 0;
+
+   /*start at the highest and it will fall down after trying the functions*/
+   hnd->_internal.srv_level = SRV_WIN_2K3;
+
+   hnd->_internal.user_supplied_ctx = False;
+
+   return hnd;
+}
+
+int cac_InitHandleData(CacServerHandle *hnd) {
+   /*store any automatically initialized values*/
+   if(!hnd->netbios_name) {
+      hnd->netbios_name = SMB_STRDUP(hnd->_internal.ctx->netbios_name);
+   }
+   else if(hnd->netbios_name[0] == '\0') {
+      strncpy(hnd->netbios_name, hnd->_internal.ctx->netbios_name, sizeof(fstring));
+   }
+
+   if(!hnd->username) {
+      hnd->username = SMB_STRDUP(hnd->_internal.ctx->user);
+   }
+   else if(hnd->username[0] == '\0') {
+      strncpy(hnd->username, hnd->_internal.ctx->user, sizeof(fstring));
+   }
+
+   if(!hnd->domain) {
+      hnd->domain = SMB_STRDUP(hnd->_internal.ctx->workgroup);
+   }
+   else if(hnd->domain[0] == '\0') {
+      strncpy(hnd->domain, hnd->_internal.ctx->workgroup, sizeof(fstring));
+   }
+
+   return CAC_SUCCESS;
+}
+
+void cac_SetAuthDataFn(CacServerHandle *hnd, smbc_get_auth_data_fn auth_fn) {
+   hnd->_internal.ctx->callbacks.auth_fn = auth_fn;
+}
+
+void cac_SetSmbcContext(CacServerHandle *hnd, SMBCCTX *ctx) {
+
+   SAFE_FREE(hnd->_internal.ctx);
+
+   hnd->_internal.user_supplied_ctx = True;
+
+   hnd->_internal.ctx = ctx;
+
+   /*_try_ to avoid any problems that might occur if cac_Connect() isn't called*/
+   /*cac_InitHandleData(hnd);*/
+}
+
+/*used internally*/
+SMBCSRV *cac_GetServer(CacServerHandle *hnd) {
+   SMBCSRV *srv;
+
+   if(!hnd || !hnd->_internal.ctx) {
+      return NULL;
+   }
+
+   srv = smbc_attr_server(hnd->_internal.ctx, hnd->server, "IPC$", hnd->domain, hnd->username, hnd->password, NULL);
+   if(!srv) {
+      hnd->status=NT_STATUS_UNSUCCESSFUL;
+      DEBUG(1, ("cac_GetServer: Could not find server connection.\n"));
+   }
+
+   return srv;
+}
+
+
+int cac_Connect(CacServerHandle *hnd, const char *srv) {
+   if(!hnd) {
+      return CAC_FAILURE;
+   }
+
+   /*these values should be initialized by the user*/
+   if(!hnd->server && !srv) {
+      return CAC_FAILURE;
+   }
+
+
+   /*change the server name in the server handle if necessary*/
+   if(srv && hnd->server && strcmp(hnd->server, srv) == 0) {
+      SAFE_FREE(hnd->server);
+      hnd->server = SMB_STRDUP(srv);
+   }
+
+
+   /*first see if the context has already been setup*/
+   if( !(hnd->_internal.ctx->internal->_initialized) ) {
+      hnd->_internal.ctx->debug = hnd->debug;
+
+      /*initialize the context*/
+      if(!smbc_init_context(hnd->_internal.ctx)) {
+         return CAC_FAILURE;
+      }
+   }
+
+   /*copy any uninitialized values out of the smbc context into the handle*/
+   if(!cac_InitHandleData(hnd)) {
+      return CAC_FAILURE;
+   }
+
+   DEBUG(3, ("cac_Connect: Username:     %s\n", hnd->username));
+   DEBUG(3, ("cac_Connect: Domain:       %s\n", hnd->domain));
+   DEBUG(3, ("cac_Connect: Netbios Name: %s\n", hnd->netbios_name));
+
+   if(!cac_GetServer(hnd)) {
+      return CAC_FAILURE;
+   }
+   
+   return CAC_SUCCESS;
+                                     
+}
+
+
+void cac_FreeHandle(CacServerHandle * hnd) {
+   SMBCSRV *srv = NULL;
+   uint32 i     = 0;
+
+   if(!hnd)
+      return;
+   
+   /*see if there are any sessions*/
+   while(i <= PI_MAX_PIPES && hnd->_internal.pipes[i] == False)
+      i++;
+
+   if(i < PI_MAX_PIPES) {
+      /*then one or more sessions are open*/
+      srv = cac_GetServer(hnd);
+
+      if(srv)
+         cli_nt_session_close(&(srv->cli));
+   }
+
+   /*only free the context if we created it*/
+   if(!hnd->_internal.user_supplied_ctx) {
+      smbc_free_context(hnd->_internal.ctx, True);
+   }
+
+   SAFE_FREE(hnd->netbios_name);
+   SAFE_FREE(hnd->domain);
+   SAFE_FREE(hnd->username);
+   SAFE_FREE(hnd->password);
+   SAFE_FREE(hnd->server);
+   SAFE_FREE(hnd);
+
+}
+
+void cac_InitCacTime(CacTime *cactime, NTTIME nttime) {
+   float high, low;
+   uint32 sec;
+
+   if(!cactime)
+      return;
+
+   ZERO_STRUCTP(cactime);
+
+   /*this code is taken from display_time() found in rpcclient/cmd_samr.c*/
+   if (nttime.high==0 && nttime.low==0)
+               return;
+
+       if (nttime.high==0x80000000 && nttime.low==0)
+               return;
+
+       high = 65536;   
+       high = high/10000;
+       high = high*65536;
+       high = high/1000;
+       high = high * (~nttime.high);
+
+       low = ~nttime.low;      
+       low = low/(1000*1000*10);
+
+       sec=high+low;
+
+       cactime->days=sec/(60*60*24);
+       cactime->hours=(sec - (cactime->days*60*60*24)) / (60*60);
+       cactime->minutes=(sec - (cactime->days*60*60*24) - (cactime->hours*60*60) ) / 60;
+       cactime->seconds=sec - (cactime->days*60*60*24) - (cactime->hours*60*60) - (cactime->minutes*60);
+}
+
+void cac_GetAuthDataFn(const char * pServer,
+                 const char * pShare,
+                 char * pWorkgroup,
+                 int maxLenWorkgroup,
+                 char * pUsername,
+                 int maxLenUsername,
+                 char * pPassword,
+                 int maxLenPassword)
+    
+{
+    char temp[sizeof(fstring)];
+    
+    static char authUsername[sizeof(fstring)];
+    static char authWorkgroup[sizeof(fstring)];
+    static char authPassword[sizeof(fstring)];
+    static char authSet = 0;
+
+    char *pass = NULL;
+
+    
+    if (authSet)
+    {
+        strncpy(pWorkgroup, authWorkgroup, maxLenWorkgroup - 1);
+        strncpy(pUsername, authUsername, maxLenUsername - 1);
+        strncpy(pPassword, authPassword, maxLenPassword - 1);
+    }
+    else
+    {
+        d_printf("Domain: [%s] ", pWorkgroup);
+        fgets(temp, sizeof(fstring), stdin);
+        
+        if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+        {
+            temp[strlen(temp) - 1] = '\0';
+        }
+        
+
+        if (temp[0] != '\0')
+        {
+            strncpy(pWorkgroup, temp, maxLenWorkgroup - 1);
+            strncpy(authWorkgroup, temp, maxLenWorkgroup - 1);
+        }
+        
+        d_printf("Username: [%s] ", pUsername);
+        fgets(temp, sizeof(fstring), stdin);
+        
+        if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+        {
+            temp[strlen(temp) - 1] = '\0';
+        }
+        
+        if (temp[0] != '\0')
+        {
+            strncpy(pUsername, temp, maxLenUsername - 1);
+            strncpy(authUsername, pUsername, maxLenUsername - 1);
+        }
+        
+        pass = getpass("Password: ");
+        if (pass)
+            fstrcpy(temp, pass);
+        if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+        {
+            temp[strlen(temp) - 1] = '\0';
+        }        
+        if (temp[0] != '\0')
+        {
+            strncpy(pPassword, temp, maxLenPassword - 1);
+            strncpy(authPassword, pPassword, maxLenPassword - 1);
+        }        
+        authSet = 1;
+    }
+}
+
diff --git a/source/libmsrpc/libmsrpc.po b/source/libmsrpc/libmsrpc.po
new file mode 100644 (file)
index 0000000..ca94f3d
Binary files /dev/null and b/source/libmsrpc/libmsrpc.po differ
diff --git a/source/libmsrpc/libmsrpc_internal.c b/source/libmsrpc/libmsrpc_internal.c
new file mode 100644 (file)
index 0000000..2560fd6
--- /dev/null
@@ -0,0 +1,684 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  MS-RPC client internal functions
+ *  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 "libmsrpc_internal.h"
+
+/*takes a string like HKEY_LOCAL_MACHINE\HARDWARE\ACPI and returns the reg_type code and then a pointer to the start of the path (HARDWARE)*/
+int cac_ParseRegPath(char *path, uint32 *reg_type, char **key_name) {
+
+   if(!path)
+      return CAC_FAILURE;
+
+   if(strncmp(path, "HKLM", 4) == 0) {
+      *reg_type = HKEY_LOCAL_MACHINE;
+      *key_name = (path[4] == '\\') ? path + 5 : NULL;
+   }
+   else if(strncmp(path, "HKEY_LOCAL_MACHINE", 18) == 0) {
+      *reg_type = HKEY_LOCAL_MACHINE;
+      *key_name = (path[18] == '\\') ? path + 19 : NULL;
+   }
+   else if(strncmp(path, "HKCR", 4) == 0) {
+      *reg_type = HKEY_CLASSES_ROOT;
+      *key_name = (path[4] == '\\') ? path + 5 : NULL;
+   }
+   else if(strncmp(path, "HKEY_CLASSES_ROOT", 17) == 0) {
+      *reg_type = HKEY_CLASSES_ROOT;
+      *key_name = (path[17] == '\\') ? path + 18 : NULL;
+   }
+   else if(strncmp(path, "HKU", 3) == 0) {
+      *reg_type = HKEY_USERS;
+      *key_name = (path[3] == '\\') ? path + 4 : NULL;
+   }
+   else if(strncmp(path, "HKEY_USERS", 10) == 0) {
+      *reg_type = HKEY_USERS;
+      *key_name = (path[10] == '\\') ? path + 11 : NULL;
+   }
+   else if(strncmp(path, "HKPD", 4) == 0) {
+      *reg_type = HKEY_PERFORMANCE_DATA;
+      *key_name = (path[4] == '\\') ? path + 5 : NULL;
+   }
+   else if(strncmp(path, "HKEY_PERFORMANCE_DATA", 21) == 0) {
+      *reg_type = HKEY_PERFORMANCE_DATA;
+      *key_name = (path[21] == '\\') ? path + 22 : NULL;
+   }
+   else {
+      return CAC_FAILURE;
+   }
+
+   return CAC_SUCCESS;
+}
+
+
+
+RPC_DATA_BLOB *cac_MakeRpcDataBlob(TALLOC_CTX *mem_ctx, uint32 data_type, REG_VALUE_DATA data) {
+   RPC_DATA_BLOB *blob = NULL;
+   int i;
+   uint32 size = 0;
+   uint32 len  = 0;
+   uint8 *multi = NULL;
+   uint32 multi_idx = 0;
+
+   blob = talloc(mem_ctx, RPC_DATA_BLOB);
+
+   if(!blob) {
+      errno = ENOMEM;
+      return NULL;
+   }
+
+   switch(data_type) {
+      case REG_SZ:
+         init_rpc_blob_str(blob, data.reg_sz, strlen(data.reg_sz ) + 1);
+         break;
+
+      case REG_EXPAND_SZ:
+         init_rpc_blob_str(blob, data.reg_expand_sz, strlen(data.reg_sz) + 1);
+         break;
+
+      case REG_BINARY:
+         init_rpc_blob_bytes(blob, data.reg_binary.data, data.reg_binary.data_length);
+         break;
+
+      case REG_DWORD:
+         init_rpc_blob_uint32(blob, data.reg_dword);
+         break;
+         
+      case REG_DWORD_BE:
+         init_rpc_blob_uint32(blob, data.reg_dword_be);
+         break;
+         
+      case REG_MULTI_SZ:
+         /*need to find the size*/
+         for(i = 0; i < data.reg_multi_sz.num_strings; i++) {
+            size += strlen(data.reg_multi_sz.strings[i]) + 1;
+         }
+
+         /**need a whole bunch of unicode strings in a row (seperated by null characters), with an extra null-character on the end*/
+
+         multi = TALLOC_ZERO_ARRAY(mem_ctx, uint8, (size + 1)*2); /*size +1 for the extra null character*/
+         if(!multi) {
+            errno = ENOMEM;
+            break;
+         }
+         
+         /*do it using rpcstr_push()*/
+         multi_idx = 0;
+         for(i = 0; i < data.reg_multi_sz.num_strings; i++) {
+            len = strlen(data.reg_multi_sz.strings[i]) + 1;
+
+            rpcstr_push((multi + multi_idx), data.reg_multi_sz.strings[i], len * 2, STR_TERMINATE);
+
+            /* x2 becuase it is a uint8 buffer*/
+            multi_idx += len * 2;
+         }
+            
+         /*now initialize the buffer as binary data*/
+         init_rpc_blob_bytes(blob, multi, (size + 1)*2);
+
+         break;
+
+      default:
+         talloc_free(blob);
+         blob = NULL;
+   }
+
+   if(!(blob->buffer)) {
+      talloc_free(blob);
+      return NULL;
+   }
+
+   return blob;
+}
+
+/*turns a string in a uint16 array to a char array*/
+char *cac_unistr_to_str(TALLOC_CTX *mem_ctx, uint16 *src, int num_bytes) {
+   char *buf;
+   
+   int i = 0;
+
+   uint32 str_len = 0;
+   
+   /*don't allocate more space than we need*/
+   while( (str_len) < num_bytes/2 && src[str_len] != 0x0000)
+      str_len++;
+
+   /*need room for a '\0'*/
+   str_len++;
+
+   buf = talloc_array(mem_ctx, char, str_len);
+   if(!buf) {
+      return NULL;
+   }
+
+   for(i = 0; i < num_bytes/2; i++) {
+      buf[i] = ((char *)src)[2*i];
+   }
+
+   buf[str_len - 1] = '\0';
+
+   return buf;
+}
+
+REG_VALUE_DATA *cac_MakeRegValueData(TALLOC_CTX *mem_ctx, uint32 data_type, REGVAL_BUFFER buf) {
+   REG_VALUE_DATA *data;
+
+   uint32 i;
+
+   /*all of the following used for MULTI_SZ data*/
+   uint32 size       = 0;
+   uint32 len        = 0;
+   uint32 multi_idx  = 0;
+   uint32 num_strings= 0;
+   char **strings    = NULL;
+
+   data = talloc(mem_ctx, REG_VALUE_DATA);
+   if(!data) {
+      errno = ENOMEM;
+      return NULL;
+   }
+
+   switch (data_type) {
+      case REG_SZ:
+         data->reg_sz = cac_unistr_to_str(mem_ctx, buf.buffer, buf.buf_len);
+         if(!data->reg_sz) {
+            talloc_free(data);
+            errno = ENOMEM;
+            data = NULL;
+         }
+            
+         break;
+
+      case REG_EXPAND_SZ:
+         data->reg_expand_sz = cac_unistr_to_str(mem_ctx, buf.buffer, buf.buf_len);
+
+         if(!data->reg_expand_sz) {
+            talloc_free(data);
+            errno = ENOMEM;
+            data = NULL;
+         }
+            
+         break;
+
+      case REG_BINARY:
+         size = buf.buf_len;
+
+         data->reg_binary.data_length = size;
+
+         data->reg_binary.data = talloc_memdup(mem_ctx, buf.buffer, size);
+         if(!data->reg_binary.data) {
+            talloc_free(data);
+            errno = ENOMEM;
+            data = NULL;
+         }
+         break;
+
+      case REG_DWORD:
+         data->reg_dword = *((uint32 *)buf.buffer);
+         break;
+
+      case REG_DWORD_BE:
+         data->reg_dword_be = *((uint32 *)buf.buffer);
+         break;
+
+      case REG_MULTI_SZ:
+         size = buf.buf_len;
+
+         /*find out how many strings there are. size is # of bytes and we want to work uint16*/
+         for(i = 0; i < (size/2 - 1); i++) {
+            if(buf.buffer[i] == 0x0000)
+               num_strings++;
+
+            /*buffer is suppsed to be terminated with \0\0, but it might not be*/
+            if(buf.buffer[i] == 0x0000 && buf.buffer[i + 1] == 0x0000)
+               break;
+         }
+         
+         strings = talloc_array(mem_ctx, char *, num_strings);
+         if(!strings) {
+            errno = ENOMEM;
+            talloc_free(data);
+            break;
+         }
+
+         if(num_strings == 0) /*then our work here is done*/
+            break;
+
+         for(i = 0; i < num_strings; i++) {
+            /*find out how many characters are in this string*/
+            len = 0;
+            /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0*/
+            while( multi_idx + len < size/2 && buf.buffer[multi_idx + len] != 0x0000)
+               len++;
+
+            /*stay aware of the \0\0*/
+            len++;
+
+            strings[i] = TALLOC_ZERO_ARRAY(mem_ctx, char, len);
+
+            /*pull out the unicode string*/
+            rpcstr_pull(strings[i], (buf.buffer + multi_idx) , len, -1, STR_TERMINATE);
+
+            /*keep track of where we are in the bigger array*/
+            multi_idx += len;
+         }
+
+         data->reg_multi_sz.num_strings = num_strings;
+         data->reg_multi_sz.strings     = strings;
+
+         break;
+
+      default:
+         talloc_free(data);
+         data = NULL;
+   }
+
+   return data;
+}
+
+SAM_USERINFO_CTR *cac_MakeUserInfoCtr(TALLOC_CTX *mem_ctx, CacUserInfo *info) {
+   SAM_USERINFO_CTR *ctr = NULL;
+
+   /*the flags we are 'setting'- include/passdb.h*/
+   uint32 flags = ACCT_USERNAME | ACCT_FULL_NAME | ACCT_PRIMARY_GID | ACCT_ADMIN_DESC | ACCT_DESCRIPTION |
+                     ACCT_HOME_DIR | ACCT_HOME_DRIVE | ACCT_LOGON_SCRIPT | ACCT_PROFILE | ACCT_WORKSTATIONS |
+                      ACCT_FLAGS;
+
+   NTTIME logon_time;
+   NTTIME logoff_time;
+   NTTIME kickoff_time;
+   NTTIME pass_last_set_time;
+   NTTIME pass_can_change_time;
+   NTTIME pass_must_change_time;
+
+   UNISTR2 user_name;
+   UNISTR2 full_name;
+   UNISTR2 home_dir;
+   UNISTR2 dir_drive;
+   UNISTR2 log_scr;
+   UNISTR2 prof_path;
+   UNISTR2 desc;
+   UNISTR2 wkstas;
+   UNISTR2 mung_dial;
+   UNISTR2 unk;
+
+   ctr = talloc(mem_ctx, SAM_USERINFO_CTR);
+   if(!ctr)
+      return NULL;
+
+   ZERO_STRUCTP(ctr->info.id23);
+
+   ctr->info.id21 = talloc(mem_ctx, SAM_USER_INFO_21);
+   if(!ctr->info.id21)
+      return NULL;
+
+   ctr->switch_value = 21;
+
+   ZERO_STRUCTP(ctr->info.id21);
+
+   unix_to_nt_time(&logon_time, info->logon_time);
+   unix_to_nt_time(&logoff_time, info->logoff_time);
+   unix_to_nt_time(&kickoff_time, info->kickoff_time);
+   unix_to_nt_time(&pass_last_set_time, info->pass_last_set_time);
+   unix_to_nt_time(&pass_can_change_time, info->pass_can_change_time);
+   unix_to_nt_time(&pass_must_change_time, info->pass_must_change_time);
+
+   /*initialize the strings*/
+   init_unistr2(&user_name, info->username, STR_TERMINATE);
+   init_unistr2(&full_name, info->full_name, STR_TERMINATE);
+   init_unistr2(&home_dir, info->home_dir, STR_TERMINATE);
+   init_unistr2(&dir_drive, info->home_drive, STR_TERMINATE);
+   init_unistr2(&log_scr, info->logon_script, STR_TERMINATE);
+   init_unistr2(&prof_path, info->profile_path, STR_TERMINATE);
+   init_unistr2(&desc, info->description, STR_TERMINATE);
+   init_unistr2(&wkstas, info->workstations, STR_TERMINATE);
+   init_unistr2(&unk, "\0", STR_TERMINATE);
+   init_unistr2(&mung_dial, info->dial, STR_TERMINATE);
+
+   /*manually set passmustchange*/
+   ctr->info.id21->passmustchange = (info->pass_must_change) ? 0x01 : 0x00;
+
+   init_sam_user_info21W(ctr->info.id21,
+                         &logon_time,
+                         &logoff_time,
+                         &kickoff_time,
+                         &pass_last_set_time,
+                         &pass_can_change_time,
+                         &pass_must_change_time,
+                         &user_name,
+                         &full_name,
+                         &home_dir,
+                         &dir_drive,
+                         &log_scr,
+                         &prof_path,
+                         &desc,
+                         &wkstas,
+                         &unk,
+                         &mung_dial,
+                         info->lm_password,
+                         info->nt_password,
+                         info->rid,
+                         info->group_rid,
+                         info->acb_mask,
+                         flags,
+                         168, /*logon divs*/
+                         info->logon_hours,
+                         info->bad_passwd_count,
+                         info->logon_count);
+
+   return ctr;
+   
+}
+
+char *talloc_unistr2_to_ascii(TALLOC_CTX *mem_ctx, UNISTR2 str) {
+   char *buf = NULL;
+
+   if(!mem_ctx)
+      return NULL;
+
+   buf = talloc_array(mem_ctx, char, (str.uni_str_len + 1));
+   if(!buf)
+      return NULL;
+
+   unistr2_to_ascii(buf, &str, str.uni_str_len + 1);
+
+   return buf;
+}
+
+CacUserInfo *cac_MakeUserInfo(TALLOC_CTX *mem_ctx, SAM_USERINFO_CTR *ctr) {
+   CacUserInfo *info = NULL;
+   SAM_USER_INFO_21 *id21 = NULL;
+
+   if(!ctr || ctr->switch_value != 21)
+      return NULL;
+
+   info = talloc(mem_ctx, CacUserInfo);
+   if(!info)
+      return NULL;
+
+   id21 = ctr->info.id21;
+
+   ZERO_STRUCTP(info);
+
+   info->logon_time = nt_time_to_unix(&id21->logon_time);
+   info->logoff_time = nt_time_to_unix(&id21->logoff_time);
+   info->kickoff_time = nt_time_to_unix(&id21->kickoff_time);
+   info->pass_last_set_time = nt_time_to_unix(&id21->pass_last_set_time);
+   info->pass_can_change_time = nt_time_to_unix(&id21->pass_can_change_time);
+   info->pass_must_change_time = nt_time_to_unix(&id21->pass_must_change_time);
+
+   info->username = talloc_unistr2_to_ascii(mem_ctx, id21->uni_user_name);
+   if(!info->username)
+      return NULL;
+
+   info->full_name = talloc_unistr2_to_ascii(mem_ctx, id21->uni_full_name);
+   if(!info->full_name)
+      return NULL;
+   
+   info->home_dir = talloc_unistr2_to_ascii(mem_ctx, id21->uni_home_dir);
+   if(!info->home_dir)
+      return NULL;
+   
+   info->home_drive = talloc_unistr2_to_ascii(mem_ctx, id21->uni_dir_drive);
+   if(!info->home_drive)
+      return NULL;
+
+   info->logon_script = talloc_unistr2_to_ascii(mem_ctx, id21->uni_logon_script);
+   if(!info->logon_script)
+      return NULL;
+
+   info->profile_path = talloc_unistr2_to_ascii(mem_ctx, id21->uni_profile_path);
+   if(!info->profile_path)
+      return NULL;
+   
+   info->description = talloc_unistr2_to_ascii(mem_ctx, id21->uni_acct_desc);
+   if(!info->description)
+      return NULL;
+   
+   info->workstations = talloc_unistr2_to_ascii(mem_ctx, id21->uni_workstations);
+   if(!info->workstations)
+      return NULL;
+
+   info->dial = talloc_unistr2_to_ascii(mem_ctx, id21->uni_munged_dial);
+   if(!info->dial)
+      return NULL;
+
+   info->rid = id21->user_rid;
+   info->group_rid = id21->group_rid;
+   info->acb_mask = id21->acb_info;
+   info->bad_passwd_count = id21->bad_password_count;
+   info->logon_count = id21->logon_count;
+
+   memcpy(info->nt_password, id21->nt_pwd, 8);
+   memcpy(info->lm_password, id21->lm_pwd, 8);
+   
+   info->logon_hours = talloc_memdup(mem_ctx, &(id21->logon_hrs), sizeof(LOGON_HRS));
+   if(!info->logon_hours)
+      return NULL;
+
+   info->pass_must_change = (id21->passmustchange) ? True : False;
+
+   return info;
+}
+
+CacGroupInfo *cac_MakeGroupInfo(TALLOC_CTX *mem_ctx, GROUP_INFO_CTR *ctr) {
+   CacGroupInfo *info = NULL;
+
+   if(!mem_ctx || !ctr || ctr->switch_value1 != 1)
+      return NULL;
+
+   info = talloc(mem_ctx, CacGroupInfo);
+   if(!info)
+      return NULL;
+
+   info->name = talloc_unistr2_to_ascii(mem_ctx, ctr->group.info1.uni_acct_name);
+   if(!info->name)
+      return NULL;
+
+   info->description = talloc_unistr2_to_ascii(mem_ctx, ctr->group.info1.uni_acct_desc);
+   if(!info->description)
+      return NULL;
+
+   info->num_members = ctr->group.info1.num_members;
+
+   return info;
+}
+
+GROUP_INFO_CTR *cac_MakeGroupInfoCtr(TALLOC_CTX *mem_ctx, CacGroupInfo *info) {
+   GROUP_INFO_CTR *ctr = NULL;
+
+   if(!mem_ctx || !info)
+      return NULL;
+
+   ctr = talloc(mem_ctx, GROUP_INFO_CTR);
+   if(!ctr)
+      return NULL;
+
+   ctr->switch_value1 = 1;
+
+   init_samr_group_info1(&(ctr->group.info1), info->name, info->description, info->num_members);
+
+   return ctr;
+}
+
+CacAliasInfo *cac_MakeAliasInfo(TALLOC_CTX *mem_ctx, ALIAS_INFO_CTR ctr) {
+   CacGroupInfo *info = NULL;
+
+   if(!mem_ctx || ctr.level != 1)
+      return NULL;
+
+   info = talloc(mem_ctx, CacAliasInfo);
+   if(!info)
+      return NULL;
+
+   info->name = talloc_unistr2_to_ascii(mem_ctx, *(ctr.alias.info1.name.string));
+   if(!info->name)
+      return NULL;
+
+   info->description = talloc_unistr2_to_ascii(mem_ctx, *(ctr.alias.info1.description.string));
+   if(!info->name)
+      return NULL;
+
+   info->num_members = ctr.alias.info1.num_member;
+
+   return info;
+}
+
+ALIAS_INFO_CTR *cac_MakeAliasInfoCtr(TALLOC_CTX *mem_ctx, CacAliasInfo *info) {
+   ALIAS_INFO_CTR *ctr = NULL;
+
+   if(!mem_ctx || !info)
+      return NULL;
+
+   ctr = talloc(mem_ctx, ALIAS_INFO_CTR);
+   if(!ctr)
+      return NULL;
+
+   ctr->level = 1;
+
+   init_samr_alias_info1(&(ctr->alias.info1), info->name, info->num_members, info->description);
+
+   return ctr;
+}
+
+CacDomainInfo *cac_MakeDomainInfo(TALLOC_CTX *mem_ctx, SAM_UNK_INFO_1 *info1, SAM_UNK_INFO_2 *info2, SAM_UNK_INFO_12 *info12) {
+   CacDomainInfo *info = NULL;
+
+   if(!mem_ctx || !info1 || !info2 || !info12)
+      return NULL;
+
+   info = talloc(mem_ctx, CacDomainInfo);
+   if(!info)
+      return NULL;
+
+   info->min_pass_length = info1->min_length_password;
+   info->pass_history    = info1->password_history;
+
+   cac_InitCacTime(&(info->expire), info1->expire);
+   cac_InitCacTime(&(info->min_pass_age), info1->min_passwordage);
+
+   info->server_role       = info2->server_role;
+   info->num_users         = info2->num_domain_usrs;
+   info->num_domain_groups = info2->num_domain_grps;
+   info->num_local_groups  = info2->num_local_grps;
+
+   /*if these have been ZERO'd out we need to know. uni_str_len will be 0*/
+   if(info2->uni_comment.uni_str_len == 0) {
+      info->comment = talloc_strdup(mem_ctx, "\0");
+   }
+   else {
+      info->comment = talloc_unistr2_to_ascii(mem_ctx, info2->uni_comment);
+   }
+
+   if(info2->uni_domain.uni_str_len == 0) {
+      info->domain_name = talloc_strdup(mem_ctx, "\0");
+   }
+   else {
+      info->domain_name = talloc_unistr2_to_ascii(mem_ctx, info2->uni_domain);
+   }
+
+   if(info2->uni_server.uni_str_len == 0) {
+      info->server_name = talloc_strdup(mem_ctx, "\0");
+   }
+   else {
+      info->server_name = talloc_unistr2_to_ascii(mem_ctx, info2->uni_server);
+   }
+
+
+   cac_InitCacTime(&(info->lockout_duration), info12->duration);
+   cac_InitCacTime(&(info->lockout_reset), info12->reset_count);
+   info->num_bad_attempts = info12->bad_attempt_lockout;
+
+   return info;
+}
+
+char *cac_unistr_ascii(TALLOC_CTX *mem_ctx, UNISTR src) {
+   char *buf;
+   uint32 len;
+
+   if(!mem_ctx || !src.buffer)
+      return NULL;
+
+   len = unistrlen(src.buffer) + 1;
+
+   buf = TALLOC_ZERO_ARRAY(mem_ctx, char, len);
+   if(!buf)
+      return NULL;
+
+   rpcstr_pull(buf, src.buffer, len, -1, STR_TERMINATE);
+
+   return buf;
+}
+
+CacService *cac_MakeServiceArray(TALLOC_CTX *mem_ctx, ENUM_SERVICES_STATUS *svc, uint32 num_services) {
+   int i;
+   CacService *services = NULL;
+
+   if(!mem_ctx || !svc)
+      return NULL;
+
+   services = TALLOC_ZERO_ARRAY(mem_ctx, CacService, num_services);
+   if(!services)
+      return NULL;
+
+   for(i = 0; i < num_services; i++) {
+      services[i].service_name = cac_unistr_ascii(mem_ctx, svc[i].servicename);
+      services[i].display_name = cac_unistr_ascii(mem_ctx, svc[i].displayname);
+
+      if(!services[i].service_name || !services[i].display_name)
+         return NULL;
+
+      services[i].status = svc[i].status;
+   }
+
+   return services;
+}
+
+int cac_InitCacServiceConfig(TALLOC_CTX *mem_ctx, SERVICE_CONFIG *src, CacServiceConfig *dest) {
+   if(!src || !dest)
+      return CAC_FAILURE;
+
+   dest->exe_path = talloc_unistr2_to_ascii(mem_ctx, *src->executablepath);
+   if(!dest->exe_path)
+      return CAC_FAILURE;
+
+   dest->load_order_group = talloc_unistr2_to_ascii(mem_ctx, *src->loadordergroup);
+   if(!dest->load_order_group)
+      return CAC_FAILURE;
+
+   dest->dependencies = talloc_unistr2_to_ascii(mem_ctx, *src->dependencies);
+   if(!dest->dependencies)
+      return CAC_FAILURE;
+
+   dest->start_name = talloc_unistr2_to_ascii(mem_ctx, *src->startname);
+   if(!dest->start_name)
+      return CAC_FAILURE;
+
+   dest->display_name = talloc_unistr2_to_ascii(mem_ctx, *src->displayname);
+   if(!dest->display_name)
+      return CAC_FAILURE;
+
+   dest->type = src->service_type;
+   dest->start_type = src->start_type;
+   dest->error_control = src->error_control;
+   dest->tag_id = src->tag_id;
+
+   return CAC_SUCCESS;
+}