summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2005-09-03 16:55:45 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:03:30 -0500
commit3c6b0f965588aab0edbc4d115fb9e72c884ded3b (patch)
treece3740784555e729297955c924e4701feaf69d38 /source3
parenta44e97c99f61916db3f7cc02cd2581c8d64be73a (diff)
downloadsamba-3c6b0f965588aab0edbc4d115fb9e72c884ded3b.tar.gz
samba-3c6b0f965588aab0edbc4d115fb9e72c884ded3b.tar.bz2
samba-3c6b0f965588aab0edbc4d115fb9e72c884ded3b.zip
r10003: in the rush for 10k, I forgot to run add the rest of Chris' libmsrpc files
(This used to be commit 32bebc452dffa8348b94c5b866350b1fe761986f)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/libmsrpc.h3048
-rw-r--r--source3/include/libmsrpc_internal.h69
-rw-r--r--source3/libmsrpc/Doxyfile173
-rw-r--r--source3/libmsrpc/cac_lsarpc.c1111
-rw-r--r--source3/libmsrpc/cac_samr.c2460
-rw-r--r--source3/libmsrpc/cac_svcctl.c583
-rw-r--r--source3/libmsrpc/cac_winreg.c1033
-rw-r--r--source3/libmsrpc/libmsrpc.c352
-rw-r--r--source3/libmsrpc/libmsrpc.pobin0 -> 360324 bytes
-rw-r--r--source3/libmsrpc/libmsrpc_internal.c684
10 files changed, 9513 insertions, 0 deletions
diff --git a/source3/include/libmsrpc.h b/source3/include/libmsrpc.h
new file mode 100644
index 0000000000..611db4f849
--- /dev/null
+++ b/source3/include/libmsrpc.h
@@ -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/source3/include/libmsrpc_internal.h b/source3/include/libmsrpc_internal.h
new file mode 100644
index 0000000000..5073813e21
--- /dev/null
+++ b/source3/include/libmsrpc_internal.h
@@ -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/source3/libmsrpc/Doxyfile b/source3/libmsrpc/Doxyfile
new file mode 100644
index 0000000000..f4e6f5e51b
--- /dev/null
+++ b/source3/libmsrpc/Doxyfile
@@ -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/source3/libmsrpc/cac_lsarpc.c b/source3/libmsrpc/cac_lsarpc.c
new file mode 100644
index 0000000000..911dc906f0
--- /dev/null
+++ b/source3/libmsrpc/cac_lsarpc.c
@@ -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/source3/libmsrpc/cac_samr.c b/source3/libmsrpc/cac_samr.c
new file mode 100644
index 0000000000..c6efaa2d38
--- /dev/null
+++ b/source3/libmsrpc/cac_samr.c
@@ -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/source3/libmsrpc/cac_svcctl.c b/source3/libmsrpc/cac_svcctl.c
new file mode 100644
index 0000000000..71c83eba94
--- /dev/null
+++ b/source3/libmsrpc/cac_svcctl.c
@@ -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/source3/libmsrpc/cac_winreg.c b/source3/libmsrpc/cac_winreg.c
new file mode 100644
index 0000000000..3a90aa871e
--- /dev/null
+++ b/source3/libmsrpc/cac_winreg.c
@@ -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/source3/libmsrpc/libmsrpc.c b/source3/libmsrpc/libmsrpc.c
new file mode 100644
index 0000000000..05f2dfe627
--- /dev/null
+++ b/source3/libmsrpc/libmsrpc.c
@@ -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/source3/libmsrpc/libmsrpc.po b/source3/libmsrpc/libmsrpc.po
new file mode 100644
index 0000000000..ca94f3d25c
--- /dev/null
+++ b/source3/libmsrpc/libmsrpc.po
Binary files differ
diff --git a/source3/libmsrpc/libmsrpc_internal.c b/source3/libmsrpc/libmsrpc_internal.c
new file mode 100644
index 0000000000..2560fd602b
--- /dev/null
+++ b/source3/libmsrpc/libmsrpc_internal.c
@@ -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;
+}