summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/include/nt_status.h62
-rw-r--r--source3/include/sam.h282
-rw-r--r--source3/lib/gencache.c319
-rw-r--r--source3/lib/sendfile.c302
-rw-r--r--source3/libads/ads_utils.c171
-rw-r--r--source3/nsswitch/winbind_client.h16
-rw-r--r--source3/python/.cvsignore1
-rw-r--r--source3/python/README28
-rwxr-xr-xsource3/python/examples/spoolss/changeid.py34
-rwxr-xr-xsource3/python/examples/spoolss/enumprinters.py36
-rwxr-xr-xsource3/python/examples/spoolss/psec.py88
-rwxr-xr-xsource3/python/examples/tdbpack/tdbtimetrial.py12
-rwxr-xr-xsource3/python/examples/tdbpack/test_tdbpack.py195
-rwxr-xr-xsource3/python/gprinterdata39
-rwxr-xr-xsource3/python/gtdbtool39
-rwxr-xr-xsource3/python/gtkdictbrowser.py272
-rw-r--r--source3/python/py_common.c270
-rw-r--r--source3/python/py_conv.c184
-rw-r--r--source3/python/py_conv.h40
-rw-r--r--source3/python/py_samba.c56
-rw-r--r--source3/python/py_samr.c498
-rw-r--r--source3/python/py_samr_conv.c58
-rw-r--r--source3/python/py_spoolss.c490
-rw-r--r--source3/python/py_spoolss_drivers.c420
-rw-r--r--source3/python/py_spoolss_drivers_conv.c177
-rw-r--r--source3/python/py_spoolss_forms.c266
-rw-r--r--source3/python/py_spoolss_jobs.c377
-rw-r--r--source3/python/py_spoolss_printerdata.c393
-rw-r--r--source3/python/py_spoolss_printers.c475
-rw-r--r--source3/python/py_spoolss_printers_conv.c306
-rw-r--r--source3/python/py_spoolss_proto.h123
-rw-r--r--source3/python/py_tdbpack.c662
-rw-r--r--source3/python/py_winbind.c716
-rw-r--r--source3/python/py_winbind_conv.c42
-rw-r--r--source3/python/samba/.cvsignore1
-rw-r--r--source3/python/samba/__init__.py7
-rw-r--r--source3/python/samba/printerdata.py59
-rwxr-xr-xsource3/python/setup.py183
-rw-r--r--source3/registry/reg_objects.c372
-rw-r--r--source3/sam/account.c307
-rw-r--r--source3/sam/api.c322
-rw-r--r--source3/sam/get_set_account.c872
-rw-r--r--source3/sam/get_set_domain.c263
-rw-r--r--source3/sam/get_set_group.c106
-rw-r--r--source3/sam/group.c193
-rw-r--r--source3/sam/interface.c1238
-rw-r--r--source3/sam/sam_plugin.c79
-rwxr-xr-xsource3/script/find_missing_doc.pl43
-rw-r--r--source3/torture/cmd_sam.c301
-rw-r--r--source3/torture/cmd_vfs.c1045
-rw-r--r--source3/torture/samtest.c449
-rw-r--r--source3/torture/samtest.h38
-rw-r--r--source3/torture/vfstest.c593
-rw-r--r--source3/torture/vfstest.h45
-rw-r--r--source3/utils/net_ads_cldap.c274
-rw-r--r--source3/utils/net_cache.c328
-rw-r--r--source3/utils/net_rpc_samsync.c716
57 files changed, 15283 insertions, 0 deletions
diff --git a/source3/include/nt_status.h b/source3/include/nt_status.h
new file mode 100644
index 0000000000..1c80c5ecde
--- /dev/null
+++ b/source3/include/nt_status.h
@@ -0,0 +1,62 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Andrew Tridgell 2001
+
+ 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 _NT_STATUS_H
+#define _NT_STATUS_H
+
+/* The Splint code analysis tool doesn't like immediate structures. */
+
+#ifdef _SPLINT_ /* http://www.splint.org */
+#undef HAVE_IMMEDIATE_STRUCTURES
+#endif
+
+/* the following rather strange looking definitions of NTSTATUS and WERROR
+ and there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using BOOL for internal functions
+*/
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} NTSTATUS;
+#define NT_STATUS(x) ((NTSTATUS) { x })
+#define NT_STATUS_V(x) ((x).v)
+#else
+typedef uint32 NTSTATUS;
+#define NT_STATUS(x) (x)
+#define NT_STATUS_V(x) (x)
+#endif
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} WERROR;
+#define W_ERROR(x) ((WERROR) { x })
+#define W_ERROR_V(x) ((x).v)
+#else
+typedef uint32 WERROR;
+#define W_ERROR(x) (x)
+#define W_ERROR_V(x) (x)
+#endif
+
+#define NT_STATUS_IS_OK(x) (NT_STATUS_V(x) == 0)
+#define NT_STATUS_IS_ERR(x) ((NT_STATUS_V(x) & 0xc0000000) == 0xc0000000)
+#define NT_STATUS_EQUAL(x,y) (NT_STATUS_V(x) == NT_STATUS_V(y))
+#define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0)
+
+#endif
diff --git a/source3/include/sam.h b/source3/include/sam.h
new file mode 100644
index 0000000000..2157a37065
--- /dev/null
+++ b/source3/include/sam.h
@@ -0,0 +1,282 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM structures
+ Copyright (C) Kai Krueger 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Jelmer Vernooij 2002
+
+ 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 _SAM_H
+#define _SAM_H
+
+/* We want to track down bugs early */
+#if 1
+#define SAM_ASSERT(x) SMB_ASSERT(x)
+#else
+#define SAM_ASSERT(x) while (0) { \
+ if (!(x)) {
+ DEBUG(0, ("SAM_ASSERT failed!\n"))
+ return NT_STATUS_FAIL_CHECK;\
+ } \
+ }
+#endif
+
+
+/* let it be 0 until we have a stable interface --metze */
+#define SAM_INTERFACE_VERSION 0
+
+/* use this inside a passdb module */
+#define SAM_MODULE_VERSIONING_MAGIC \
+int sam_version(void)\
+{\
+ return SAM_INTERFACE_VERSION;\
+}
+
+/* Backend to use by default when no backend was specified */
+#define SAM_DEFAULT_BACKEND "plugin"
+
+typedef struct sam_domain_handle {
+ TALLOC_CTX *mem_ctx;
+ uint32 access_granted;
+ const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */
+ void (*free_fn)(struct sam_domain_handle **);
+ struct domain_data {
+ DOM_SID sid; /*SID of the domain. Should not be changed */
+ char *name; /* Name of the domain */
+ char *servername; /* */
+ NTTIME max_passwordage; /* time till next password expiration */
+ NTTIME min_passwordage; /* time till password can be changed again */
+ NTTIME lockout_duration; /* time till login is allowed again after lockout*/
+ NTTIME reset_count; /* time till bad login counter is reset */
+ uint16 min_passwordlength; /* minimum number of characters for a password */
+ uint16 password_history; /* number of passwords stored in history */
+ uint16 lockout_count; /* number of bad login attempts before lockout */
+ BOOL force_logoff; /* force logoff after logon hours have expired */
+ BOOL login_pwdchange; /* Users need to logon to change their password */
+ uint32 num_accounts; /* number of accounts in the domain */
+ uint32 num_groups; /* number of global groups */
+ uint32 num_aliases; /* number of local groups */
+ } private;
+} SAM_DOMAIN_HANDLE;
+
+typedef struct sam_account_handle {
+ TALLOC_CTX *mem_ctx;
+ uint32 access_granted;
+ const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */
+ void (*free_fn)(struct sam_account_handle **);
+ struct sam_account_data {
+ uint32 init_flag;
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+ char * account_name; /* account_name string */
+ SAM_DOMAIN_HANDLE * domain; /* domain of account */
+ char *full_name; /* account's full name string */
+ char *unix_home_dir; /* UNIX home directory string */
+ char *home_dir; /* home directory string */
+ char *dir_drive; /* home directory drive string */
+ char *logon_script; /* logon script string */
+ char *profile_path; /* profile path string */
+ char *acct_desc; /* account description string */
+ char *workstations; /* login from workstations string */
+ char *unknown_str; /* don't know what this is, yet. */
+ char *munged_dial; /* munged path name and dial-back tel number */
+ DOM_SID account_sid; /* Primary Account SID */
+ DOM_SID group_sid; /* Primary Group SID */
+ DATA_BLOB lm_pw; /* .data is Null if no password */
+ DATA_BLOB nt_pw; /* .data is Null if no password */
+ char *plaintext_pw; /* if Null not available */
+ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ uint32 unknown_1; /* 0x00ff ffff */
+ uint16 logon_divs; /* 168 - number of hours in a week */
+ uint32 hours_len; /* normally 21 bytes */
+ uint8 hours[MAX_HOURS_LEN];
+ uint32 unknown_2; /* 0x0002 0000 */
+ uint32 unknown_3; /* 0x0000 04ec */
+ } private;
+} SAM_ACCOUNT_HANDLE;
+
+typedef struct sam_group_handle {
+ TALLOC_CTX *mem_ctx;
+ uint32 access_granted;
+ const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */
+ void (*free_fn)(struct sam_group_handle **);
+ struct sam_group_data {
+ char *group_name;
+ char *group_desc;
+ DOM_SID sid;
+ uint16 group_ctrl; /* specifies if the group is a local group or a global group */
+ uint32 num_members;
+ } private;
+} SAM_GROUP_HANDLE;
+
+
+typedef struct sam_group_member {
+ DOM_SID sid;
+ BOOL group; /* specifies if it is a group or a account */
+} SAM_GROUP_MEMBER;
+
+typedef struct sam_account_enum {
+ DOM_SID sid;
+ char *account_name;
+ char *full_name;
+ char *account_desc;
+ uint16 acct_ctrl;
+} SAM_ACCOUNT_ENUM;
+
+typedef struct sam_group_enum {
+ DOM_SID sid;
+ char *group_name;
+ char *group_desc;
+ uint16 group_ctrl;
+} SAM_GROUP_ENUM;
+
+
+/* bits for group_ctrl: to spezify if the group is global group or alias */
+#define GCB_LOCAL_GROUP 0x0001
+#define GCB_ALIAS_GROUP (GCB_LOCAL_GROUP |GCB_BUILTIN)
+#define GCB_GLOBAL_GROUP 0x0002
+#define GCB_BUILTIN 0x1000
+
+typedef struct sam_context
+{
+ struct sam_methods *methods;
+ TALLOC_CTX *mem_ctx;
+
+ /* General API */
+
+ NTSTATUS (*sam_get_sec_desc) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd);
+ NTSTATUS (*sam_set_sec_desc) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd);
+
+ NTSTATUS (*sam_lookup_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type);
+ NTSTATUS (*sam_lookup_name) (const struct sam_context *, const NT_USER_TOKEN *access_token, const char *domain, const char *name, DOM_SID **sid, uint32 *type);
+
+
+ /* Domain API */
+
+ NTSTATUS (*sam_update_domain) (const struct sam_context *, const SAM_DOMAIN_HANDLE *domain);
+
+ NTSTATUS (*sam_enum_domains) (const struct sam_context *, const NT_USER_TOKEN *access_token, int32 *domain_count, DOM_SID **domains, char **domain_names);
+ NTSTATUS (*sam_lookup_domain) (const struct sam_context *, const NT_USER_TOKEN * access_token, const char *domain, DOM_SID **domainsid);
+
+ NTSTATUS (*sam_get_domain_by_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, SAM_DOMAIN_HANDLE **domain);
+
+
+ /* Account API */
+
+ NTSTATUS (*sam_create_account) (const struct sam_context *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account);
+ NTSTATUS (*sam_add_account) (const struct sam_context *, const DOM_SID *domainsid, const SAM_ACCOUNT_HANDLE *account);
+ NTSTATUS (*sam_update_account) (const struct sam_context *, const SAM_ACCOUNT_HANDLE *account);
+ NTSTATUS (*sam_delete_account) (const struct sam_context *, const SAM_ACCOUNT_HANDLE *account);
+ NTSTATUS (*sam_enum_accounts) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *domain, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts);
+
+ NTSTATUS (*sam_get_account_by_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account);
+ NTSTATUS (*sam_get_account_by_name) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain, const char *name, SAM_ACCOUNT_HANDLE **account);
+
+ /* Group API */
+
+ NTSTATUS (*sam_create_group) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group);
+ NTSTATUS (*sam_add_group) (const struct sam_context *, const DOM_SID *domainsid, const SAM_GROUP_HANDLE *group);
+ NTSTATUS (*sam_update_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group);
+ NTSTATUS (*sam_delete_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group);
+ NTSTATUS (*sam_enum_groups) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *domainsid, const uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups);
+ NTSTATUS (*sam_get_group_by_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group);
+ NTSTATUS (*sam_get_group_by_name) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain, const char *name, SAM_GROUP_HANDLE **group);
+
+ NTSTATUS (*sam_add_member_to_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
+ NTSTATUS (*sam_delete_member_from_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
+ NTSTATUS (*sam_enum_groupmembers) (const struct sam_context *, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members);
+
+ NTSTATUS (*sam_get_groups_of_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups);
+ void (*free_fn)(struct sam_context **);
+} SAM_CONTEXT;
+
+typedef struct sam_methods
+{
+ struct sam_context *parent;
+ struct sam_methods *next;
+ struct sam_methods *prev;
+ const char *backendname;
+ const char *domain_name;
+ DOM_SID domain_sid;
+ void *private_data;
+
+ /* General API */
+
+ NTSTATUS (*sam_get_sec_desc) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd);
+ NTSTATUS (*sam_set_sec_desc) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd);
+
+ NTSTATUS (*sam_lookup_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type);
+ NTSTATUS (*sam_lookup_name) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const char *name, DOM_SID **sid, uint32 *type);
+
+ /* Domain API */
+
+ NTSTATUS (*sam_update_domain) (const struct sam_methods *, const SAM_DOMAIN_HANDLE *domain);
+ NTSTATUS (*sam_get_domain_handle) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, SAM_DOMAIN_HANDLE **domain);
+
+ /* Account API */
+
+ NTSTATUS (*sam_create_account) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account);
+ NTSTATUS (*sam_add_account) (const struct sam_methods *, const SAM_ACCOUNT_HANDLE *account);
+ NTSTATUS (*sam_update_account) (const struct sam_methods *, const SAM_ACCOUNT_HANDLE *account);
+ NTSTATUS (*sam_delete_account) (const struct sam_methods *, const SAM_ACCOUNT_HANDLE *account);
+ NTSTATUS (*sam_enum_accounts) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts);
+
+ NTSTATUS (*sam_get_account_by_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account);
+ NTSTATUS (*sam_get_account_by_name) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *name, SAM_ACCOUNT_HANDLE **account);
+
+ /* Group API */
+
+ NTSTATUS (*sam_create_group) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group);
+ NTSTATUS (*sam_add_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group);
+ NTSTATUS (*sam_update_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group);
+ NTSTATUS (*sam_delete_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group);
+ NTSTATUS (*sam_enum_groups) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups);
+ NTSTATUS (*sam_get_group_by_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group);
+ NTSTATUS (*sam_get_group_by_name) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *name, SAM_GROUP_HANDLE **group);
+
+ NTSTATUS (*sam_add_member_to_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
+ NTSTATUS (*sam_delete_member_from_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
+ NTSTATUS (*sam_enum_groupmembers) (const struct sam_methods *, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members);
+
+ NTSTATUS (*sam_get_groups_of_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups);
+
+ void (*free_private_data)(void **);
+} SAM_METHODS;
+
+typedef NTSTATUS (*sam_init_function)(SAM_METHODS *, const char *);
+
+struct sam_init_function_entry {
+ char *module_name;
+ /* Function to create a member of the sam_methods list */
+ sam_init_function init;
+};
+
+typedef struct sam_backend_entry {
+ char *module_name;
+ char *module_params;
+ char *domain_name;
+ DOM_SID *domain_sid;
+} SAM_BACKEND_ENTRY;
+
+
+#endif /* _SAM_H */
diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c
new file mode 100644
index 0000000000..9e2009ad4a
--- /dev/null
+++ b/source3/lib/gencache.c
@@ -0,0 +1,319 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Generic, persistent and shared between processes cache mechanism for use
+ by various parts of the Samba code
+
+ Copyright (C) Rafal Szczesniak 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_TDB
+
+#define TIMEOUT_LEN 12
+#define CACHE_DATA_FMT "%12u/%s"
+
+static TDB_CONTEXT *cache;
+
+/**
+ * @file gencache.c
+ * @brief Generic, persistent and shared between processes cache mechanism
+ * for use by various parts of the Samba code
+ *
+ **/
+
+
+/**
+ * Cache initialisation function. Opens cache tdb file or creates
+ * it if does not exist.
+ *
+ * @return true on successful initialisation of the cache or
+ * false on failure
+ **/
+
+BOOL gencache_init(void)
+{
+ char* cache_fname = NULL;
+
+ /* skip file open if it's already opened */
+ if (cache) return True;
+
+ asprintf(&cache_fname, "%s/%s", lp_lockdir(), "gencache.tdb");
+ if (cache_fname)
+ DEBUG(5, ("Opening cache file at %s\n", cache_fname));
+ else {
+ DEBUG(0, ("Filename allocation failed.\n"));
+ return False;
+ }
+
+ cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
+ O_RDWR|O_CREAT, 0644);
+
+ SAFE_FREE(cache_fname);
+ if (!cache) {
+ DEBUG(0, ("Attempt to open the cache file has failed.\n"));
+ return False;
+ }
+ return True;
+}
+
+
+/**
+ * Cache shutdown function. Closes opened cache tdb file.
+ *
+ * @return true on successful closing the cache or
+ * false on failure during cache shutdown
+ **/
+
+BOOL gencache_shutdown(void)
+{
+ /* tdb_close routine returns 0 on successful close */
+ if (!cache) return False;
+ DEBUG(5, ("Closing cache file\n"));
+ return tdb_close(cache) ? False : True;
+}
+
+
+/**
+ * Add one entry to the cache file.
+ * (it part of tridge's proposed API)
+ *
+ * @param key string that represents a key of this entry
+ * @param value text representation value being cached
+ * @param timeout time when the value is expired
+ *
+ * @return true when entry is successfuly stored or
+ * false on the attempt's failure
+ **/
+
+BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
+{
+ int ret;
+ TDB_DATA keybuf, databuf;
+ char* valstr = NULL;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr && value);
+
+ if (!gencache_init()) return False;
+
+ asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value);
+ keybuf.dptr = strdup(keystr);
+ keybuf.dsize = strlen(keystr);
+ databuf.dptr = strdup(valstr);
+ databuf.dsize = strlen(valstr);
+ DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout \
+ = %s (%d seconds %s)\n", keybuf.dptr, value, ctime(&timeout),
+ (int)(timeout - time(NULL)), timeout > time(NULL) ? "ahead" : "in the past"));
+
+ ret = tdb_store(cache, keybuf, databuf, TDB_INSERT);
+ SAFE_FREE(valstr);
+ SAFE_FREE(keybuf.dptr);
+ SAFE_FREE(databuf.dptr);
+
+ return ret == 0 ? True : False;
+}
+
+
+/**
+ * Set existing entry to the cache file.
+ * (it part of tridge's proposed API)
+ *
+ * @param key string that represents a key of this entry
+ * @param value text representation value being cached
+ * @param timeout time when the value is expired
+ *
+ * @return true when entry is successfuly set or
+ * false on the attempt's failure
+ **/
+
+BOOL gencache_set(const char *keystr, const char *valstr, time_t timeout)
+{
+ int ret = -1;
+ TDB_DATA keybuf, databuf;
+ char *old_valstr, *datastr;
+ time_t old_timeout;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr && valstr);
+
+ if (!gencache_init()) return False;
+
+ /*
+ * Check whether entry exists in the cache
+ * Don't verify gencache_get exit code, since the entry may be expired
+ */
+ gencache_get(keystr, &old_valstr, &old_timeout);
+
+ if (!(old_valstr && old_timeout)) return False;
+
+ DEBUG(10, ("Setting cache entry with key = %s; old value = %s and old timeout \
+ = %s\n", keystr, old_valstr, ctime(&old_timeout)));
+
+ asprintf(&datastr, CACHE_DATA_FMT, (int)timeout, valstr);
+ keybuf.dptr = strdup(keystr);
+ keybuf.dsize = strlen(keystr);
+ databuf.dptr = strdup(datastr);
+ databuf.dsize = strlen(datastr);
+ DEBUGADD(10, ("New value = %s, new timeout = %s (%d seconds %s)", valstr,
+ ctime(&timeout), (int)(timeout - time(NULL)),
+ timeout > time(NULL) ? "ahead" : "in the past"));
+
+
+ ret = tdb_store(cache, keybuf, databuf, TDB_REPLACE);
+
+ SAFE_FREE(datastr);
+ SAFE_FREE(old_valstr);
+ SAFE_FREE(keybuf.dptr);
+ SAFE_FREE(databuf.dptr);
+
+ return ret == 0 ? True : False;
+}
+
+
+/**
+ * Delete one entry from the cache file.
+ * (it part of tridge's proposed API)
+ *
+ * @param key string that represents a key of this entry
+ *
+ * @return true upon successful deletion or
+ * false in case of failure
+ **/
+
+BOOL gencache_del(const char *keystr)
+{
+ int ret;
+ TDB_DATA keybuf;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr);
+
+ if (!gencache_init()) return False;
+
+ keybuf.dptr = strdup(keystr);
+ keybuf.dsize = strlen(keystr);
+ DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
+ ret = tdb_delete(cache, keybuf);
+
+ SAFE_FREE(keybuf.dptr);
+ return ret == 0 ? True : False;
+}
+
+
+/**
+ * Get existing entry from the cache file.
+ * (it part of tridge's proposed API)
+ *
+ * @param key string that represents a key of this entry
+ * @param value buffer that is allocated and filled with the entry value
+ * buffer's disposing is done outside
+ * @param timeout pointer to a time_t that is filled with entry's
+ * timeout
+ *
+ * @return true when entry is successfuly fetched or
+ * false on the failure
+ **/
+
+BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
+{
+ TDB_DATA keybuf, databuf;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(keystr && valstr && timeout);
+
+ if (!gencache_init()) return False;
+
+ keybuf.dptr = strdup(keystr);
+ keybuf.dsize = strlen(keystr);
+ databuf = tdb_fetch(cache, keybuf);
+
+ if (databuf.dptr) {
+ char* entry_buf = strndup(databuf.dptr, databuf.dsize);
+ *valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
+
+ sscanf(entry_buf, CACHE_DATA_FMT, (int*)timeout, *valstr);
+ SAFE_FREE(entry_buf);
+
+ DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, timeout = %s\n",
+ *timeout > time(NULL) ? "valid" : "expired", keystr, *valstr,
+ ctime(timeout)));
+ return *timeout > time(NULL);
+ } else {
+ *valstr = NULL;
+ timeout = NULL;
+ DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr));
+ return False;
+ }
+}
+
+
+/**
+ * Iterate through all entries which key matches to specified pattern
+ *
+ * @param fn pointer to the function that will be supplied with each single
+ * matching cache entry (key, value and timeout) as an arguments
+ * @param keystr_pattern pattern the existing entries' keys are matched to
+ *
+ **/
+
+void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout),
+ const char* keystr_pattern)
+{
+ TDB_LIST_NODE *node, *first_node;
+ TDB_DATA databuf;
+ char *keystr = NULL, *valstr = NULL, *entry = NULL;
+ time_t timeout = 0;
+
+ /* fail completely if get null pointers passed */
+ SMB_ASSERT(fn && keystr_pattern);
+
+ if (!gencache_init()) return;
+
+ DEBUG(5, ("Searching cache keys with pattern %s", keystr_pattern));
+ node = tdb_search_keys(cache, keystr_pattern);
+ first_node = node;
+
+ while (node) {
+ /* ensure null termination of the key string */
+ node->node_key.dptr[node->node_key.dsize] = '\0';
+ keystr = node->node_key.dptr;
+
+ /*
+ * We don't use gencache_get function, because we need to iterate through
+ * all of the entries. Validity verification is up to fn routine.
+ */
+ databuf = tdb_fetch(cache, node->node_key);
+ entry = strndup(databuf.dptr, databuf.dsize);
+ valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
+ sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr);
+
+ DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
+ keystr, valstr, ctime(&timeout)));
+ fn(keystr, valstr, timeout);
+
+ SAFE_FREE(valstr);
+ SAFE_FREE(entry);
+ node = node->next;
+ }
+
+ tdb_search_list_free(first_node);
+}
+
+
diff --git a/source3/lib/sendfile.c b/source3/lib/sendfile.c
new file mode 100644
index 0000000000..98a52608b8
--- /dev/null
+++ b/source3/lib/sendfile.c
@@ -0,0 +1,302 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.x / 3.0.x
+ sendfile implementations.
+ Copyright (C) Jeremy Allison 2002.
+
+ 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.
+*/
+
+/*
+ * This file handles the OS dependent sendfile implementations.
+ * The API is such that it returns -1 on error, else returns the
+ * number of bytes written.
+ */
+
+#include "includes.h"
+
+#if defined(LINUX_SENDFILE_API)
+
+#include <sys/sendfile.h>
+
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ ssize_t ret;
+ ssize_t hdr_len = 0;
+
+ /*
+ * Send the header first.
+ * Use MSG_MORE to cork the TCP output until sendfile is called.
+ */
+
+ if (header) {
+ hdr_len = header->length;
+ while (total < hdr_len) {
+ ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
+ if (ret == -1)
+ return -1;
+ total += ret;
+ }
+ }
+
+ total = count;
+ while (total) {
+ ssize_t nwritten;
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
+ nwritten = sendfile64(tofd, fromfd, &offset, total);
+#else
+ nwritten = sendfile(tofd, fromfd, &offset, total);
+#endif
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+ total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(LINUX_BROKEN_SENDFILE_API)
+
+/*
+ * We must use explicit 32 bit types here. This code path means Linux
+ * won't do proper 64-bit sendfile. JRA.
+ */
+
+extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
+
+
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ ssize_t ret;
+ ssize_t hdr_len = 0;
+ uint32 small_total = 0;
+ int32 small_offset;
+
+ /*
+ * Fix for broken Linux 2.4 systems with no working sendfile64().
+ * If the offset+count > 2 GB then pretend we don't have the
+ * system call sendfile at all. The upper layer catches this
+ * and uses a normal read. JRA.
+ */
+
+ if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /*
+ * Send the header first.
+ * Use MSG_MORE to cork the TCP output until sendfile is called.
+ */
+
+ if (header) {
+ hdr_len = header->length;
+ while (total < hdr_len) {
+ ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
+ if (ret == -1)
+ return -1;
+ total += ret;
+ }
+ }
+
+ small_total = (uint32)count;
+ small_offset = (int32)offset;
+
+ while (small_total) {
+ int32 nwritten;
+ do {
+ nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+ small_total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+
+#elif defined(SOLARIS_SENDFILE_API)
+
+/* Hmmm. Can't find Solaris sendfile API docs.... Where is it ? */
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+#elif defined(HPUX_SENDFILE_API)
+
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ struct iovec hdtrl[2];
+ size_t hdr_len = 0;
+
+ if (header) {
+ /* Set up the header/trailer iovec. */
+ hdtrl[0].iov_base = header->data;
+ hdtrl[0].iov_len = hdr_len = header->length;
+ } else {
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = hdr_len = 0;
+ }
+ hdtrl[1].iov_base = NULL;
+ hdtrl[1].iov_base = 0;
+
+ total = count;
+ while (total + hdtrl[0].iov_len) {
+ ssize_t nwritten;
+
+ /*
+ * HPUX guarantees that if any data was written before
+ * a signal interrupt then sendfile returns the number of
+ * bytes written (which may be less than requested) not -1.
+ * nwritten includes the header data sent.
+ */
+
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
+ nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
+#else
+ nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
+#endif
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than hdtrl[0].iov_len bytes.
+ * We change nwritten to be the number of file bytes written.
+ */
+
+ if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
+ if (nwritten >= hdtrl[0].iov_len) {
+ nwritten -= hdtrl[0].iov_len;
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = 0;
+ } else {
+ nwritten = 0;
+ /* iov_base is defined as a void *... */
+ hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten;
+ hdtrl[0].iov_len -= nwritten;
+ }
+ }
+ total -= nwritten;
+ offset += nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(FREEBSD_SENDFILE_API)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ struct sf_hdtr hdr;
+ struct iovec hdtrl;
+ size_t hdr_len = 0;
+
+ hdr.headers = &hdtrl;
+ hdr.hdr_cnt = 1;
+ hdr.trailers = NULL;
+ hdr.trl_cnt = 0;
+
+ /* Set up the header iovec. */
+ if (header) {
+ hdtrl.iov_base = header->data;
+ hdtrl.iov_len = hdr_len = header->length;
+ } else {
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ }
+
+ total = count;
+ while (total + hdtrl.iov_len) {
+ SMB_OFF_T nwritten;
+ int ret;
+
+ /*
+ * FreeBSD sendfile returns 0 on success, -1 on error.
+ * Remember, the tofd and fromfd are reversed..... :-).
+ * nwritten includes the header data sent.
+ */
+
+ do {
+ ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1)
+ return -1;
+
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than hdtrl.iov_len bytes.
+ * We change nwritten to be the number of file bytes written.
+ */
+
+ if (hdtrl.iov_base && hdtrl.iov_len) {
+ if (nwritten >= hdtrl.iov_len) {
+ nwritten -= hdtrl.iov_len;
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ } else {
+ nwritten = 0;
+ hdtrl.iov_base += nwritten;
+ hdtrl.iov_len -= nwritten;
+ }
+ }
+ total -= nwritten;
+ offset += nwritten;
+ }
+ return count + hdr_len;
+}
+
+#else /* No sendfile implementation. Return error. */
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ /* No sendfile syscall. */
+ errno = ENOSYS;
+ return -1;
+}
+#endif
diff --git a/source3/libads/ads_utils.c b/source3/libads/ads_utils.c
new file mode 100644
index 0000000000..fc8a270021
--- /dev/null
+++ b/source3/libads/ads_utils.c
@@ -0,0 +1,171 @@
+/*
+ Unix SMB/CIFS implementation.
+ ads (active directory) utility library
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ 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 "includes.h"
+
+#ifdef HAVE_ADS
+
+
+/*
+translated the ACB_CTRL Flags to UserFlags (userAccountControl)
+*/
+uint32 ads_acb2uf(uint16 acb)
+{
+ uint32 uf = 0x00000000;
+
+ if (acb & ACB_DISABLED) uf |= UF_ACCOUNTDISABLE;
+ if (acb & ACB_HOMDIRREQ) uf |= UF_HOMEDIR_REQUIRED;
+ if (acb & ACB_PWNOTREQ) uf |= UF_PASSWD_NOTREQD;
+ if (acb & ACB_TEMPDUP) uf |= UF_TEMP_DUPLICATE_ACCOUNT;
+ if (acb & ACB_NORMAL) uf |= UF_NORMAL_ACCOUNT;
+ if (acb & ACB_MNS) uf |= UF_MNS_LOGON_ACCOUNT;
+ if (acb & ACB_DOMTRUST) uf |= UF_INTERDOMAIN_TRUST_ACCOUNT;
+ if (acb & ACB_WSTRUST) uf |= UF_WORKSTATION_TRUST_ACCOUNT;
+ if (acb & ACB_SVRTRUST) uf |= UF_SERVER_TRUST_ACCOUNT;
+ if (acb & ACB_PWNOEXP) uf |= UF_DONT_EXPIRE_PASSWD;
+ if (acb & ACB_AUTOLOCK) uf |= UF_LOCKOUT;
+
+ return uf;
+}
+
+/*
+translated the UserFlags (userAccountControl) to ACB_CTRL Flags
+*/
+uint16 ads_uf2acb(uint32 uf)
+{
+ uint16 acb = 0x0000;
+
+ if (uf & UF_ACCOUNTDISABLE) acb |= ACB_DISABLED;
+ if (uf & UF_HOMEDIR_REQUIRED) acb |= ACB_HOMDIRREQ;
+ if (uf & UF_PASSWD_NOTREQD) acb |= ACB_PWNOTREQ;
+ if (uf & UF_MNS_LOGON_ACCOUNT) acb |= ACB_MNS;
+ if (uf & UF_DONT_EXPIRE_PASSWD) acb |= ACB_PWNOEXP;
+ if (uf & UF_LOCKOUT) acb |= ACB_AUTOLOCK;
+
+ switch (uf & UF_ACCOUNT_TYPE_MASK)
+ {
+ case UF_TEMP_DUPLICATE_ACCOUNT: acb |= ACB_TEMPDUP;break;
+ case UF_NORMAL_ACCOUNT: acb |= ACB_NORMAL;break;
+ case UF_INTERDOMAIN_TRUST_ACCOUNT: acb |= ACB_DOMTRUST;break;
+ case UF_WORKSTATION_TRUST_ACCOUNT: acb |= ACB_WSTRUST;break;
+ case UF_SERVER_TRUST_ACCOUNT: acb |= ACB_SVRTRUST;break;
+ /*Fix Me: what should we do here? */
+ default: acb |= ACB_NORMAL;break;
+ }
+
+ return acb;
+}
+
+/*
+get the accountType from the UserFlags
+*/
+uint32 ads_uf2atype(uint32 uf)
+{
+ uint32 atype = 0x00000000;
+
+ if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST;
+
+ return atype;
+}
+
+/*
+translated the GROUP_CTRL Flags to GroupType (groupType)
+*/
+uint32 ads_gcb2gtype(uint16 gcb)
+{
+ uint32 gtype = 0x00000000;
+
+ if (gcb & GCB_ALIAS_GROUP) gtype |= GTYPE_SECURITY_BUILTIN_LOCAL_GROUP;
+ else if(gcb & GCB_LOCAL_GROUP) gtype |= GTYPE_SECURITY_DOMAIN_LOCAL_GROUP;
+ if (gcb & GCB_GLOBAL_GROUP) gtype |= GTYPE_SECURITY_GLOBAL_GROUP;
+
+ return gtype;
+}
+
+/*
+translated the GroupType (groupType) to GROUP_CTRL Flags
+*/
+uint16 ads_gtype2gcb(uint32 gtype)
+{
+ uint16 gcb = 0x0000;
+
+ switch(gtype) {
+ case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+ gcb = GCB_ALIAS_GROUP;
+ break;
+ case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+ gcb = GCB_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_GLOBAL_GROUP:
+ gcb = GCB_GLOBAL_GROUP;
+ break;
+
+ case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
+ gcb = GCB_GLOBAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
+ gcb = GCB_LOCAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
+ gcb = GCB_GLOBAL_GROUP;
+ break;
+ }
+
+ return gcb;
+}
+
+/*
+get the accountType from the groupType
+*/
+uint32 ads_gtype2atype(uint32 gtype)
+{
+ uint32 atype = 0x00000000;
+
+ switch(gtype) {
+ case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_GLOBAL_GROUP:
+ atype = ATYPE_SECURITY_GLOBAL_GROUP;
+ break;
+
+ case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_LOCAL_GROUP;
+ break;
+ }
+
+ return atype;
+}
+
+#endif
diff --git a/source3/nsswitch/winbind_client.h b/source3/nsswitch/winbind_client.h
new file mode 100644
index 0000000000..4de2d57cc7
--- /dev/null
+++ b/source3/nsswitch/winbind_client.h
@@ -0,0 +1,16 @@
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+
+void init_request(struct winbindd_request *req,int rq_type);
+NSS_STATUS winbindd_send_request(int req_type,
+ struct winbindd_request *request);
+NSS_STATUS winbindd_get_response(struct winbindd_response *response);
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+int winbind_open_pipe_sock(void);
+int write_sock(void *buffer, int count);
+int read_reply(struct winbindd_response *response);
+void close_sock(void);
+void free_response(struct winbindd_response *response);
+
diff --git a/source3/python/.cvsignore b/source3/python/.cvsignore
new file mode 100644
index 0000000000..7e99e367f8
--- /dev/null
+++ b/source3/python/.cvsignore
@@ -0,0 +1 @@
+*.pyc \ No newline at end of file
diff --git a/source3/python/README b/source3/python/README
new file mode 100644
index 0000000000..04f794215a
--- /dev/null
+++ b/source3/python/README
@@ -0,0 +1,28 @@
+This directory contains Python bindings to allow you to access various
+aspects of Samba. At the moment their status is "experimental" and
+they are not built by default.
+
+In order to be able to compile samba-python you need to have python
+and the python-dev packages installed.
+
+Python libraries are always built for a particular version of Python
+(2.2, 2.1, etc), and libraries built for one version will not be seen
+by another. By default Samba's libraries are built for whatever is
+installed as "python" on your $PATH, but you can override this using
+the --with-python option. For example
+
+ $ ./configure --with-python=python2.2
+
+To build:
+
+$ autoconf
+$ ./configure
+$ make python_ext
+
+Now, you can install the modules:
+
+$ cp build/lib.*/*.so /usr/lib/python2.1/lib-dynload/
+
+(the directory /usr/lib/python2.1 may vary, depending on your installation)
+
+Samba-python should work now!
diff --git a/source3/python/examples/spoolss/changeid.py b/source3/python/examples/spoolss/changeid.py
new file mode 100755
index 0000000000..85fe0efe8a
--- /dev/null
+++ b/source3/python/examples/spoolss/changeid.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+#
+# Display the changeid for a list of printers given on the command line
+#
+# Sample usage:
+#
+# changeid.py '\\win2kdc1\magpie'
+#
+
+import sys
+from samba import spoolss
+
+if len(sys.argv) == 1:
+ print "Usage: changeid.py <printername>"
+ sys.exit(1)
+
+for printer in sys.argv[1:]:
+
+ # Open printer handle
+
+ try:
+ hnd = spoolss.openprinter(printer)
+ except:
+ print "error opening printer %s" % printer
+ sys.exit(1)
+
+ # Fetch and display changeid
+
+ info = hnd.getprinter(level = 0)
+ print info["change_id"]
+
+ # Clean up
+
+ spoolss.closeprinter(hnd)
diff --git a/source3/python/examples/spoolss/enumprinters.py b/source3/python/examples/spoolss/enumprinters.py
new file mode 100755
index 0000000000..478c46bc24
--- /dev/null
+++ b/source3/python/examples/spoolss/enumprinters.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# Display information on all printers on a print server. Defaults to
+# printer info level 1.
+#
+# Example: enumprinters.py win2kdc1
+#
+
+import sys
+from samba import spoolss
+
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+ print "Usage: enumprinters.py <servername> [infolevel]"
+ sys.exit(1)
+
+printserver = sys.argv[1]
+
+level = 1
+if len(sys.argv) == 3:
+ level = int(sys.argv[2])
+
+# Get list of printers
+
+try:
+ printer_list = spoolss.enumprinters("\\\\%s" % printserver)
+except:
+ print "error enumerating printers on %s" % printserver
+ sys.exit(1)
+
+# Display basic info
+
+for printer in printer_list:
+ h = spoolss.openprinter("\\\\%s\\%s" % (printserver, printer))
+ info = h.getprinter(level = level)
+ print "Printer info %d for %s: %s" % (level, printer, info)
+ print
diff --git a/source3/python/examples/spoolss/psec.py b/source3/python/examples/spoolss/psec.py
new file mode 100755
index 0000000000..498a0ef174
--- /dev/null
+++ b/source3/python/examples/spoolss/psec.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# Get or set the security descriptor on a printer
+#
+
+import sys, re, string
+from samba import spoolss
+
+if len(sys.argv) != 3:
+ print "Usage: psec.py getsec|setsec printername"
+ sys.exit(1)
+
+op = sys.argv[1]
+printername = sys.argv[2]
+
+# Display security descriptor
+
+if op == "getsec":
+
+ try:
+ hnd = spoolss.openprinter(printername)
+ except:
+ print "error opening printer %s" % printername
+ sys.exit(1)
+
+ secdesc = hnd.getprinter(level = 3)["security_descriptor"]
+
+ print secdesc["owner_sid"]
+ print secdesc["group_sid"]
+
+ for acl in secdesc["dacl"]["ace_list"]:
+ print "%d %d 0x%08x %s" % (acl["type"], acl["flags"],
+ acl["mask"], acl["trustee"])
+
+ spoolss.closeprinter(hnd)
+
+ sys.exit(0)
+
+# Set security descriptor
+
+if op == "setsec":
+
+ # Open printer
+
+ try:
+ hnd = spoolss.openprinter(printername,
+ creds = {"domain": "NPSD-TEST2",
+ "username": "Administrator",
+ "password": "penguin"})
+ except:
+ print "error opening printer %s" % printername
+ sys.exit(1)
+
+ # Read lines from standard input and build security descriptor
+
+ lines = sys.stdin.readlines()
+
+ secdesc = {}
+
+ secdesc["owner_sid"] = lines[0]
+ secdesc["group_sid"] = lines[1]
+
+ secdesc["revision"] = 1
+ secdesc["dacl"] = {}
+ secdesc["dacl"]["revision"] = 2
+ secdesc["dacl"]["ace_list"] = []
+
+ for acl in lines[2:]:
+ match = re.match("(\d+) (\d+) (0[xX][\dA-Fa-f]+) (\S+)", acl)
+ secdesc["dacl"]["ace_list"].append(
+ {"type": int(match.group(1)), "flags": int(match.group(2)),
+ "mask": string.atoi(match.group(3), 0), "trustee": match.group(4)})
+
+ # Build info3 structure
+
+ info3 = {}
+
+ info3["flags"] = 0x8004 # self-relative, dacl present
+ info3["level"] = 3
+ info3["security_descriptor"] = secdesc
+
+ hnd.setprinter(info3)
+
+ spoolss.closeprinter(hnd)
+ sys.exit(0)
+
+print "invalid operation %s" % op
+sys.exit(1)
diff --git a/source3/python/examples/tdbpack/tdbtimetrial.py b/source3/python/examples/tdbpack/tdbtimetrial.py
new file mode 100755
index 0000000000..be6404899d
--- /dev/null
+++ b/source3/python/examples/tdbpack/tdbtimetrial.py
@@ -0,0 +1,12 @@
+#! /usr/bin/python2.2
+
+def run_trial():
+ # import tdbutil
+ from samba.tdbpack import pack
+
+ for i in xrange(500000):
+ pack("ddffd", (10, 2, "mbp", "martin", 0))
+ #s = "\n\0\0\0" + "\x02\0\0\0" + "mbp\0" + "martin\0" + "\0\0\0\0"
+
+if __name__ == '__main__':
+ run_trial()
diff --git a/source3/python/examples/tdbpack/test_tdbpack.py b/source3/python/examples/tdbpack/test_tdbpack.py
new file mode 100755
index 0000000000..36fed881e3
--- /dev/null
+++ b/source3/python/examples/tdbpack/test_tdbpack.py
@@ -0,0 +1,195 @@
+#! /usr/bin/env python2.2
+
+__doc__ = """test case for samba.tdbkpack functions
+
+tdbpack provides a means of pickling values into binary formats
+compatible with that used by the samba tdbpack()/tdbunpack()
+functions.
+
+Numbers are always stored in little-endian format; strings are stored
+in either DOS or Unix codepage as appropriate.
+
+The format for any particular element is encoded as a short ASCII
+string, with one character per field."""
+
+# Copyright (C) 2002 Hewlett-Packard.
+
+__author__ = 'Martin Pool <mbp@sourcefrog.net>'
+
+import unittest
+# import tdbutil
+import samba.tdbpack
+
+packer = samba.tdbpack.pack
+unpacker = samba.tdbpack.unpack
+
+
+class PackTests(unittest.TestCase):
+ symm_cases = [('B', ['hello' * 51], '\xff\0\0\0' + 'hello' * 51),
+ ('w', [42], '\x2a\0'),
+ ('www', [42, 2, 69], '\x2a\0\x02\0\x45\0'),
+ ('wd', [42, 256], '\x2a\0\0\x01\0\0'),
+ ('w', [0], '\0\0'),
+ ('w', [255], '\xff\0'),
+ ('w', [256], '\0\x01'),
+ ('w', [0xdead], '\xad\xde'),
+ ('w', [0xffff], '\xff\xff'),
+ ('p', [0], '\0\0\0\0'),
+ ('p', [1], '\x01\0\0\0'),
+ ('d', [0x01020304], '\x04\x03\x02\x01'),
+ ('d', [0x7fffffff], '\xff\xff\xff\x7f'),
+ ('d', [0x80000000], '\x00\x00\x00\x80'),
+ ('d', [-1], '\xff\xff\xff\xff'),
+ ('d', [-255], '\x01\xff\xff\xff'),
+ ('d', [-256], '\x00\xff\xff\xff'),
+ ('ddd', [1, 10, 50], '\x01\0\0\0\x0a\0\0\0\x32\0\0\0'),
+ ('ff', ['hello', 'world'], 'hello\0world\0'),
+ ('fP', ['hello', 'world'], 'hello\0world\0'),
+ ('PP', ['hello', 'world'], 'hello\0world\0'),
+ ('B', [''], '\0\0\0\0'),
+ ('B', ['hello'], '\x05\0\0\0hello'),
+ ('BB', ['hello\0world', 'now'],
+ '\x0b\0\0\0hello\0world\x03\0\0\0now'),
+ ('pd', [1, 10], '\x01\0\0\0\x0a\0\0\0'),
+ ('BBB', ['hello', '', 'world'],
+ '\x05\0\0\0hello\0\0\0\0\x05\0\0\0world'),
+
+ # strings are sequences in Python, there's no getting away
+ # from it
+ ('ffff', 'evil', 'e\0v\0i\0l\0'),
+ ('BBBB', 'evil',
+ '\x01\0\0\0e'
+ '\x01\0\0\0v'
+ '\x01\0\0\0i'
+ '\x01\0\0\0l'),
+
+ ('', [], ''),
+
+ # exercise some long strings
+ ('PP', ['hello' * 255, 'world' * 255],
+ 'hello' * 255 + '\0' + 'world' * 255 + '\0'),
+ ('PP', ['hello' * 40000, 'world' * 50000],
+ 'hello' * 40000 + '\0' + 'world' * 50000 + '\0'),
+ ('B', ['hello' * 51], '\xff\0\0\0' + 'hello' * 51),
+ ('BB', ['hello' * 40000, 'world' * 50000],
+ '\x40\x0d\x03\0' + 'hello' * 40000 + '\x90\xd0\x03\x00' + 'world' * 50000),
+ ]
+
+ def test_symmetric(self):
+ """Cookbook of symmetric pack/unpack tests
+ """
+ for format, values, expected in self.symm_cases:
+ self.assertEquals(packer(format, values), expected)
+ out, rest = unpacker(format, expected)
+ self.assertEquals(rest, '')
+ self.assertEquals(list(values), list(out))
+
+
+ def test_pack(self):
+ """Cookbook of expected pack values
+
+ These can't be used for the symmetric test because the unpacked value is
+ not "canonical".
+ """
+ cases = [('w', (42,), '\x2a\0'),
+ ('p', [None], '\0\0\0\0'),
+ ('p', ['true'], '\x01\0\0\0'),
+
+ ('w', {1: 'fruit'}, '\x01\0'),
+ # passing a dictionary is dodgy, but it gets coerced to keys
+ # as if you called list()
+ ]
+
+ for format, values, expected in cases:
+ self.assertEquals(packer(format, values), expected)
+
+ def test_unpack_extra(self):
+ # Test leftover data
+ for format, values, packed in self.symm_cases:
+ out, rest = unpacker(format, packed + 'hello sailor!')
+ self.assertEquals(rest, 'hello sailor!')
+ self.assertEquals(list(values), list(out))
+
+
+ def test_unpack(self):
+ """Cookbook of tricky unpack tests"""
+ cases = [
+ ]
+ for format, values, expected in cases:
+ out, rest = unpacker(format, expected)
+ self.assertEquals(rest, '')
+ self.assertEquals(list(values), list(out))
+
+
+ def test_pack_failures(self):
+ """Expected errors for incorrect packing"""
+ cases = [('w', [], IndexError),
+ ('w', (), IndexError),
+ ('w', {}, IndexError),
+ ('ww', [2], IndexError),
+ ('w', 2, TypeError),
+ ('', [1, 2, 3], IndexError),
+ ('w', None, TypeError),
+ ('wwwwwwwwwwww', [], IndexError),
+ ('w', [2, 3], IndexError),
+ ('w', [0x60A15EC5L], TypeError),
+ ('w', [None], TypeError),
+ ('w', xrange(10000), IndexError),
+ ('d', [], IndexError),
+ ('d', [0L], TypeError),
+ ('p', [], IndexError),
+ ('f', [2], TypeError),
+ ('P', [None], TypeError),
+ ('P', (), IndexError),
+ ('f', [packer], TypeError),
+ ('fw', ['hello'], IndexError),
+ ('f', [u'hello'], TypeError),
+ ('B', [2], TypeError),
+ (None, [2, 3, 4], TypeError),
+ (ord('f'), [20], TypeError),
+ (['w', 'w'], [2, 2], TypeError),
+ ('Q', [2], ValueError),
+ ('fQ', ['2', 3], ValueError),
+ ('fQ', ['2'], IndexError),
+ (2, [2], TypeError),
+ ({}, {}, TypeError)]
+ for format, values, throwable_class in cases:
+ def do_pack():
+ packer(format, values)
+ self.assertRaises(throwable_class, do_pack)
+
+
+ def test_unpack_failures(self):
+ """Expected errors for incorrect unpacking"""
+ cases = [('$', '', ValueError),
+ ('Q', '', ValueError),
+ ('Q$', '', ValueError),
+ ('f', '', IndexError),
+ ('d', '', IndexError),
+ ('d', '2', IndexError),
+ ('d', '22', IndexError),
+ ('d', '222', IndexError),
+ ('w', '', IndexError),
+ ('w', '2', IndexError),
+ ('f', 'hello', IndexError),
+ ('f', '', IndexError),
+ ('p', '\x01\0', IndexError),
+ ('B', '\xff\0\0\0hello', IndexError),
+ ('B', '\xff\0', IndexError),
+ ('B', '\x01\0\0\0', IndexError),
+ ('B', '\x05\0\0\0hell', IndexError),
+ ('B', '\xff\xff\xff\xff', ValueError),
+ ('B', 'foobar', IndexError),
+ ('BB', '\x01\0\0\0a\x01', IndexError),
+ ]
+
+ for format, values, throwable_class in cases:
+ def do_unpack():
+ unpacker(format, values)
+ self.assertRaises(throwable_class, do_unpack)
+
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/source3/python/gprinterdata b/source3/python/gprinterdata
new file mode 100755
index 0000000000..cd062076c0
--- /dev/null
+++ b/source3/python/gprinterdata
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+import sys
+from gtkdictbrowser import GtkDictBrowser, hex_string
+import gtk
+from samba import spoolss
+import string
+import printerdata
+
+# Initialise printerdata dictionary
+
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+ print "Usage: gprinterdata [--ex] <printer>"
+ print "where <printer> is a UNC printer name."
+ sys.exit(1)
+
+try:
+ host = string.replace(sys.argv[len(sys.argv) - 1], "/", "\\")
+ if sys.argv[1] == "--ex":
+ t = printerdata.printerdata_ex(host)
+ else:
+ t = printerdata.printerdata(host)
+except:
+ print "gprinterdata: error opening %s" % sys.argv[len(sys.argv) - 1]
+ sys.exit(1)
+
+# Create interface
+
+db = GtkDictBrowser(t)
+db.register_get_value_text_fn("", hex_string)
+db.build_ui('gprinterdata')
+
+# Override Python's handling of ctrl-c so we can break out of the
+# gui from the command line.
+
+import signal
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+gtk.mainloop()
diff --git a/source3/python/gtdbtool b/source3/python/gtdbtool
new file mode 100755
index 0000000000..129f4fe0e2
--- /dev/null
+++ b/source3/python/gtdbtool
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+import sys
+from gtkdictbrowser import GtkDictBrowser
+import gtk
+from samba import tdb
+import string
+
+# Open handle on tdb
+
+if len(sys.argv) != 2:
+ print "Usage: gdbtool <tdbfile>"
+ sys.exit(1)
+
+try:
+ t = tdb.open(sys.argv[1])
+except tdb.error, t:
+ print "gtdbtool: error opening %s: %s" % (sys.argv[1], t)
+ sys.exit(1)
+
+# Create interface
+
+db = GtkDictBrowser(t)
+
+def display_key_x00(key):
+ """Remove \x00 from all keys as they mucks up GTK."""
+ return string.replace(key, "\x00", "")
+
+db.register_get_key_text_fn(display_key_x00)
+
+db.build_ui('gtdbtool')
+
+# Override Python's handling of ctrl-c so we can break out of the
+# gui from the command line.
+
+import signal
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+gtk.mainloop()
diff --git a/source3/python/gtkdictbrowser.py b/source3/python/gtkdictbrowser.py
new file mode 100755
index 0000000000..dd8bed8f47
--- /dev/null
+++ b/source3/python/gtkdictbrowser.py
@@ -0,0 +1,272 @@
+#!/usr/bin/python
+#
+# Browse a Python dictionary in a two pane graphical interface written
+# in GTK.
+#
+# The GtkDictBrowser class is supposed to be generic enough to allow
+# applications to override enough methods and produce a
+# domain-specific browser provided the information is presented as a
+# Python dictionary.
+#
+# Possible applications:
+#
+# - Windows registry browser
+# - SPOOLSS printerdata browser
+# - tdb file browser
+#
+
+from gtk import *
+import string, re
+
+class GtkDictBrowser:
+
+ def __init__(self, dict):
+ self.dict = dict
+
+ # This variable stores a list of (regexp, function) used to
+ # convert the raw value data to a displayable string.
+
+ self.get_value_text_fns = []
+ self.get_key_text = lambda x: x
+
+ # We can filter the list of keys displayed using a regex
+
+ self.filter_regex = ""
+
+ # Create and configure user interface widgets. A string argument is
+ # used to set the window title.
+
+ def build_ui(self, title):
+ win = GtkWindow()
+ win.set_title(title)
+
+ win.connect("destroy", mainquit)
+
+ hpaned = GtkHPaned()
+ win.add(hpaned)
+ hpaned.set_border_width(5)
+ hpaned.show()
+
+ vbox = GtkVBox()
+ hpaned.add1(vbox)
+ vbox.show()
+
+ scrolled_win = GtkScrolledWindow()
+ scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+ vbox.pack_start(scrolled_win)
+ scrolled_win.show()
+
+ hbox = GtkHBox()
+ vbox.pack_end(hbox, expand = 0, padding = 5)
+ hbox.show()
+
+ label = GtkLabel("Filter:")
+ hbox.pack_start(label, expand = 0, padding = 5)
+ label.show()
+
+ self.entry = GtkEntry()
+ hbox.pack_end(self.entry, padding = 5)
+ self.entry.show()
+
+ self.entry.connect("activate", self.filter_activated)
+
+ self.list = GtkList()
+ self.list.set_selection_mode(SELECTION_MULTIPLE)
+ self.list.set_selection_mode(SELECTION_BROWSE)
+ scrolled_win.add_with_viewport(self.list)
+ self.list.show()
+
+ self.list.connect("select_child", self.key_selected)
+
+ scrolled_win = GtkScrolledWindow()
+ scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+ hpaned.add2(scrolled_win)
+ scrolled_win.set_usize(500,400)
+ scrolled_win.show()
+
+ self.text = GtkText()
+ self.text.set_editable(FALSE)
+ scrolled_win.add_with_viewport(self.text)
+ self.text.show()
+
+ self.text.connect("event", self.event_handler)
+
+ self.menu = GtkMenu()
+ self.menu.show()
+
+ self.font = load_font("fixed")
+
+ self.update_keylist()
+
+ win.show()
+
+ # Add a key to the left hand side of the user interface
+
+ def add_key(self, key):
+ display_key = self.get_key_text(key)
+ list_item = GtkListItem(display_key)
+ list_item.set_data("raw_key", key) # Store raw key in item data
+ self.list.add(list_item)
+ list_item.show()
+
+ # Event handler registered by build_ui()
+
+ def event_handler(self, event, menu):
+ return FALSE
+
+ # Set the text to appear in the right hand side of the user interface
+
+ def set_value_text(self, item):
+
+ # Clear old old value in text window
+
+ self.text.delete_text(0, self.text.get_length())
+
+ if type(item) == str:
+
+ # The text widget has trouble inserting text containing NULL
+ # characters.
+
+ item = string.replace(item, "\x00", ".")
+
+ self.text.insert(self.font, None, None, item)
+
+ else:
+
+ # A non-text item
+
+ self.text.insert(self.font, None, None, repr(item))
+
+ # This function is called when a key is selected in the left hand side
+ # of the user interface.
+
+ def key_selected(self, list, list_item):
+ key = list_item.children()[0].get()
+
+ # Look for a match in the value display function list
+
+ text = self.dict[list_item.get_data("raw_key")]
+
+ for entry in self.get_value_text_fns:
+ if re.match(entry[0], key):
+ text = entry[1](text)
+ break
+
+ self.set_value_text(text)
+
+ # Refresh the key list by removing all items and re-inserting them.
+ # Items are only inserted if they pass through the filter regexp.
+
+ def update_keylist(self):
+ self.list.remove_items(self.list.children())
+ self.set_value_text("")
+ for k in self.dict.keys():
+ if re.match(self.filter_regex, k):
+ self.add_key(k)
+
+ # Invoked when the user hits return in the filter text entry widget.
+
+ def filter_activated(self, entry):
+ self.filter_regex = entry.get_text()
+ self.update_keylist()
+
+ # Register a key display function
+
+ def register_get_key_text_fn(self, fn):
+ self.get_key_text = fn
+
+ # Register a value display function
+
+ def register_get_value_text_fn(self, regexp, fn):
+ self.get_value_text_fns.append((regexp, fn))
+
+#
+# A utility function to convert a string to the standard hex + ascii format.
+# To display all values in hex do:
+# register_get_value_text_fn("", gtkdictbrowser.hex_string)
+#
+
+def hex_string(data):
+ """Return a hex dump of a string as a string.
+
+ The output produced is in the standard 16 characters per line hex +
+ ascii format:
+
+ 00000000: 40 00 00 00 00 00 00 00 40 00 00 00 01 00 04 80 @....... @.......
+ 00000010: 01 01 00 00 00 00 00 01 00 00 00 00 ........ ....
+ """
+
+ pos = 0 # Position in data
+ line = 0 # Line of data
+
+ hex = "" # Hex display
+ ascii = "" # ASCII display
+
+ result = ""
+
+ while pos < len(data):
+
+ # Start with header
+
+ if pos % 16 == 0:
+ hex = "%08x: " % (line * 16)
+ ascii = ""
+
+ # Add character
+
+ hex = hex + "%02x " % (ord(data[pos]))
+
+ if ord(data[pos]) < 32 or ord(data[pos]) > 176:
+ ascii = ascii + '.'
+ else:
+ ascii = ascii + data[pos]
+
+ pos = pos + 1
+
+ # Add separator if half way
+
+ if pos % 16 == 8:
+ hex = hex + " "
+ ascii = ascii + " "
+
+ # End of line
+
+ if pos % 16 == 0:
+ result = result + "%s %s\n" % (hex, ascii)
+ line = line + 1
+
+ # Leftover bits
+
+ if pos % 16 != 0:
+
+ # Pad hex string
+
+ for i in range(0, (16 - (pos % 16))):
+ hex = hex + " "
+
+ # Half way separator
+
+ if (pos % 16) < 8:
+ hex = hex + " "
+
+ result = result + "%s %s\n" % (hex, ascii)
+
+ return result
+
+# For testing purposes, create a fixed dictionary to browse with
+
+if __name__ == "__main__":
+
+ dict = {"chicken": "ham", "spam": "fun", "subdict": {"a": "b", "c": "d"}}
+
+ db = GtkDictBrowser(dict)
+
+ db.build_ui("GtkDictBrowser")
+
+ # Override Python's handling of ctrl-c so we can break out of the
+ # gui from the command line.
+
+ import signal
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+ mainloop()
diff --git a/source3/python/py_common.c b/source3/python/py_common.c
new file mode 100644
index 0000000000..e21858e072
--- /dev/null
+++ b/source3/python/py_common.c
@@ -0,0 +1,270 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "includes.h"
+#include "Python.h"
+
+#include "python/py_common_proto.h"
+
+/* Return a tuple of (error code, error string) from a WERROR */
+
+PyObject *py_werror_tuple(WERROR werror)
+{
+ return Py_BuildValue("[is]", W_ERROR_V(werror),
+ dos_errstr(werror));
+}
+
+/* Return a tuple of (error code, error string) from a WERROR */
+
+PyObject *py_ntstatus_tuple(NTSTATUS ntstatus)
+{
+ return Py_BuildValue("[is]", NT_STATUS_V(ntstatus),
+ nt_errstr(ntstatus));
+}
+
+/* Initialise samba client routines */
+
+static BOOL initialised;
+
+void py_samba_init(void)
+{
+ extern pstring global_myname;
+ char *p;
+
+ if (initialised)
+ return;
+
+ /* Load configuration file */
+
+ if (!lp_load(dyn_CONFIGFILE, True, False, False))
+ fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
+
+ /* Misc other stuff */
+
+ load_interfaces();
+
+ fstrcpy(global_myname, myhostname());
+ p = strchr(global_myname, '.');
+ if (p)
+ *p = 0;
+
+ initialised = True;
+}
+
+/* Debuglevel routines */
+
+PyObject *get_debuglevel(PyObject *self, PyObject *args)
+{
+ PyObject *debuglevel;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ debuglevel = PyInt_FromLong(DEBUGLEVEL);
+
+ return debuglevel;
+}
+
+PyObject *set_debuglevel(PyObject *self, PyObject *args)
+{
+ int debuglevel;
+
+ if (!PyArg_ParseTuple(args, "i", &debuglevel))
+ return NULL;
+
+ DEBUGLEVEL = debuglevel;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Initialise logging */
+
+PyObject *py_setup_logging(PyObject *self, PyObject *args, PyObject *kw)
+{
+ BOOL interactive = False;
+ char *logfilename = NULL;
+ static char *kwlist[] = {"interactive", "logfilename", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|is", kwlist, &interactive, &logfilename))
+ return NULL;
+
+ if (interactive && logfilename) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "can't be interactive and set log file name");
+ return NULL;
+ }
+
+ if (interactive)
+ setup_logging("spoolss", True);
+
+ if (logfilename) {
+ lp_set_logfile(logfilename);
+ setup_logging(logfilename, False);
+ reopen_logs();
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Parse credentials from a python dictionary. The dictionary can
+ only have the keys "username", "domain" and "password". Return
+ True for valid credentials in which case the username, domain and
+ password are set to pointers to their values from the dicationary.
+ If returns False, the errstr is set to point at some mallocated
+ memory describing the error. */
+
+BOOL py_parse_creds(PyObject *creds, char **username, char **domain,
+ char **password, char **errstr)
+{
+ /* Initialise anonymous credentials */
+
+ *username = "";
+ *domain = "";
+ *password = "";
+
+ if (creds && PyDict_Size(creds) > 0) {
+ PyObject *username_obj, *password_obj, *domain_obj;
+ PyObject *key, *value;
+ int i;
+
+ /* Check for presence of required fields */
+
+ username_obj = PyDict_GetItemString(creds, "username");
+ domain_obj = PyDict_GetItemString(creds, "domain");
+ password_obj = PyDict_GetItemString(creds, "password");
+
+ if (!username_obj) {
+ *errstr = strdup("no username field in credential");
+ return False;
+ }
+
+ if (!domain_obj) {
+ *errstr = strdup("no domain field in credential");
+ return False;
+ }
+
+ if (!password_obj) {
+ *errstr = strdup("no password field in credential");
+ return False;
+ }
+
+ /* Check type of required fields */
+
+ if (!PyString_Check(username_obj)) {
+ *errstr = strdup("username field is not string type");
+ return False;
+ }
+
+ if (!PyString_Check(domain_obj)) {
+ *errstr = strdup("domain field is not string type");
+ return False;
+ }
+
+ if (!PyString_Check(password_obj)) {
+ *errstr = strdup("password field is not string type");
+ return False;
+ }
+
+ /* Look for any extra fields */
+
+ i = 0;
+
+ while (PyDict_Next(creds, &i, &key, &value)) {
+ if (strcmp(PyString_AsString(key), "domain") != 0 &&
+ strcmp(PyString_AsString(key), "username") != 0 &&
+ strcmp(PyString_AsString(key), "password") != 0) {
+ asprintf(errstr,
+ "creds contain extra field '%s'",
+ PyString_AsString(key));
+ return False;
+ }
+ }
+
+ /* Assign values */
+
+ *username = PyString_AsString(username_obj);
+ *domain = PyString_AsString(domain_obj);
+ *password = PyString_AsString(password_obj);
+ }
+
+ *errstr = NULL;
+
+ return True;
+}
+
+/* Return a cli_state to a RPC pipe on the given server. Use the
+ credentials passed if not NULL. If an error occurs errstr is set to a
+ string describing the error and NULL is returned. If set, errstr must
+ be freed by calling free(). */
+
+struct cli_state *open_pipe_creds(char *server, PyObject *creds,
+ char *pipe_name, char **errstr)
+{
+ char *username, *password, *domain;
+ struct cli_state *cli;
+ NTSTATUS result;
+
+ /* Extract credentials from the python dictionary */
+
+ if (!py_parse_creds(creds, &username, &domain, &password, errstr))
+ return NULL;
+
+ /* Now try to connect */
+
+ result = cli_full_connection(
+ &cli, NULL, server, NULL, 0, "IPC$", "IPC",
+ username, domain, password, 0);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ *errstr = strdup("error connecting to IPC$ pipe");
+ return NULL;
+ }
+
+ if (!cli_nt_session_open(cli, pipe_name)) {
+ cli_shutdown(cli);
+ free(cli);
+ asprintf(errstr, "error opening %s", pipe_name);
+ return NULL;
+ }
+
+ *errstr = NULL;
+
+ return cli;
+}
+
+/* Return true if a dictionary contains a "level" key with an integer
+ value. Set the value if so. */
+
+BOOL get_level_value(PyObject *dict, uint32 *level)
+{
+ PyObject *obj;
+
+ if (!(obj = PyDict_GetItemString(dict, "level")) ||
+ !PyInt_Check(obj))
+ return False;
+
+ if (level)
+ *level = PyInt_AsLong(obj);
+
+ return True;
+}
diff --git a/source3/python/py_conv.c b/source3/python/py_conv.c
new file mode 100644
index 0000000000..20302c83e8
--- /dev/null
+++ b/source3/python/py_conv.c
@@ -0,0 +1,184 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "includes.h"
+#include "Python.h"
+#include "py_conv.h"
+
+/* Helper for rpcstr_pull() function */
+
+static void fstr_pull(fstring str, UNISTR *uni)
+{
+ rpcstr_pull(str, uni->buffer, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/* Convert a structure to a Python dict */
+
+PyObject *from_struct(void *s, struct pyconv *conv)
+{
+ PyObject *obj, *item;
+ int i;
+
+ obj = PyDict_New();
+
+ for (i = 0; conv[i].name; i++) {
+ switch (conv[i].type) {
+ case PY_UNISTR: {
+ UNISTR *u = (UNISTR *)((char *)s + conv[i].offset);
+ fstring s = "";
+
+ if (u->buffer)
+ fstr_pull(s, u);
+
+ item = PyString_FromString(s);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UINT32: {
+ uint32 *u = (uint32 *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*u);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UINT16: {
+ uint16 *u = (uint16 *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*u);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_STRING: {
+ char *str = (char *)s + conv[i].offset;
+
+ item = PyString_FromString(str);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UID: {
+ uid_t *uid = (uid_t *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*uid);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_GID: {
+ gid_t *gid = (gid_t *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*gid);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ default:
+
+ break;
+ }
+ }
+
+ return obj;
+}
+
+/* Convert a Python dict to a structure */
+
+BOOL to_struct(void *s, PyObject *dict, struct pyconv *conv)
+{
+ PyObject *visited, *key, *value;
+ BOOL result = False;
+ int i;
+
+ visited = PyDict_New();
+
+ for (i = 0; conv[i].name; i++) {
+ PyObject *obj;
+
+ obj = PyDict_GetItemString(dict, conv[i].name);
+
+ if (!obj)
+ goto done;
+
+ switch (conv[i].type) {
+ case PY_UNISTR: {
+ UNISTR *u = (UNISTR *)((char *)s + conv[i].offset);
+ char *s = "";
+
+ if (!PyString_Check(obj))
+ goto done;
+
+ s = PyString_AsString(obj);
+ init_unistr(u, s);
+
+ break;
+ }
+ case PY_UINT32: {
+ uint32 *u = (uint32 *)((char *)s + conv[i].offset);
+
+ if (!PyInt_Check(obj))
+ goto done;
+
+ *u = PyInt_AsLong(obj);
+
+ break;
+ }
+ case PY_UINT16: {
+ uint16 *u = (uint16 *)((char *)s + conv[i].offset);
+
+ if (!PyInt_Check(obj))
+ goto done;
+
+ *u = PyInt_AsLong(obj);
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Mark as visited */
+
+ PyDict_SetItemString(visited, conv[i].name,
+ PyInt_FromLong(1));
+ }
+
+ /* Iterate over each item in the input dictionary and see if it was
+ visited. If it wasn't then the user has added some extra crap
+ to the dictionary. */
+
+ i = 0;
+
+ while (PyDict_Next(dict, &i, &key, &value)) {
+ if (!PyDict_GetItem(visited, key))
+ goto done;
+ }
+
+ result = True;
+
+done:
+ /* We must decrement the reference count here or the visited
+ dictionary will not be freed. */
+
+ Py_DECREF(visited);
+
+ return result;
+}
diff --git a/source3/python/py_conv.h b/source3/python/py_conv.h
new file mode 100644
index 0000000000..24f5a66287
--- /dev/null
+++ b/source3/python/py_conv.h
@@ -0,0 +1,40 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 _PY_CONV_H
+#define _PY_CONV_H
+
+enum pyconv_types { PY_UNISTR, PY_UINT32, PY_UINT16, PY_STRING, PY_UID, PY_GID };
+
+struct pyconv {
+ char *name; /* Name of member */
+ enum pyconv_types type; /* Type */
+ size_t offset; /* Offset into structure */
+};
+
+PyObject *from_struct(void *s, struct pyconv *conv);
+BOOL to_struct(void *s, PyObject *dict, struct pyconv *conv);
+
+/* Another version of offsetof (-: */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* _PY_CONV_H */
diff --git a/source3/python/py_samba.c b/source3/python/py_samba.c
new file mode 100644
index 0000000000..c0ade12f65
--- /dev/null
+++ b/source3/python/py_samba.c
@@ -0,0 +1,56 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "Python.h"
+#include "python/py_common.h"
+
+/*
+ * Module initialisation
+ */
+
+static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ return NULL;
+}
+
+static PyMethodDef samba_methods[] = {
+ { NULL }
+};
+
+static PyMethodDef cheepy_methods[] = {
+ { "open_policy", (PyCFunction)lsa_open_policy, METH_VARARGS|METH_KEYWORDS,
+ "Foo"},
+ { NULL }
+};
+
+void initsamba(void)
+{
+ PyObject *module, *new_module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("samba", samba_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+}
diff --git a/source3/python/py_samr.c b/source3/python/py_samr.c
new file mode 100644
index 0000000000..917a90a2fb
--- /dev/null
+++ b/source3/python/py_samr.c
@@ -0,0 +1,498 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_samr.h"
+
+/*
+ * Exceptions raised by this module
+ */
+
+PyObject *samr_error; /* This indicates a non-RPC related error
+ such as name lookup failure */
+
+PyObject *samr_ntstatus; /* This exception is raised when a RPC call
+ returns a status code other than
+ NT_STATUS_OK */
+
+/* SAMR connect handle object */
+
+static void py_samr_connect_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+PyObject *new_samr_domain_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_domain_hnd_object *o;
+
+ o = PyObject_New(samr_domain_hnd_object, &samr_domain_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->domain_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+static PyObject *samr_open_domain(PyObject *self, PyObject *args, PyObject *kw)
+{
+ samr_connect_hnd_object *connect_hnd = (samr_connect_hnd_object *)self;
+ static char *kwlist[] = { "sid", "access", NULL };
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ char *sid_str;
+ DOM_SID sid;
+ TALLOC_CTX *mem_ctx = NULL;
+ POLICY_HND domain_pol;
+ NTSTATUS ntstatus;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|i", kwlist, &sid_str, &desired_access))
+ return NULL;
+
+ if (!string_to_sid(&sid, sid_str)) {
+ PyErr_SetString(PyExc_TypeError, "string is not a sid");
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(samr_error, "unable to init talloc context");
+ return NULL;
+ }
+
+ ntstatus = cli_samr_open_domain(
+ connect_hnd->cli, mem_ctx, &connect_hnd->connect_pol,
+ desired_access, &sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus));
+ goto done;
+ }
+
+ result = new_samr_domain_hnd_object(
+ connect_hnd->cli, mem_ctx, &domain_pol);
+
+done:
+ if (!result) {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ return result;
+}
+
+static PyMethodDef samr_connect_methods[] = {
+ { "open_domain", (PyCFunction)samr_open_domain,
+ METH_VARARGS | METH_KEYWORDS,
+ "Open a handle on a domain" },
+
+ { NULL }
+};
+
+static PyObject *py_samr_connect_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_connect_methods, self, attrname);
+}
+
+PyTypeObject samr_connect_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Connect Handle",
+ sizeof(samr_connect_hnd_object),
+ 0,
+ py_samr_connect_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_connect_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_connect_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_connect_hnd_object *o;
+
+ o = PyObject_New(samr_connect_hnd_object, &samr_connect_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->connect_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/* SAMR domain handle object */
+
+static void py_samr_domain_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *samr_enum_dom_groups(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ samr_domain_hnd_object *domain_hnd = (samr_domain_hnd_object *)self;
+ static char *kwlist[] = { NULL };
+ TALLOC_CTX *mem_ctx;
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ uint32 start_idx, size, num_dom_groups;
+ struct acct_info *dom_groups;
+ NTSTATUS result;
+ PyObject *py_result = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "", kwlist))
+ return NULL;
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(samr_error, "unable to init talloc context");
+ return NULL;
+ }
+
+ start_idx = 0;
+ size = 0xffff;
+
+ do {
+ result = cli_samr_enum_dom_groups(
+ domain_hnd->cli, mem_ctx, &domain_hnd->domain_pol,
+ &start_idx, size, &dom_groups, &num_dom_groups);
+
+ if (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ py_from_acct_info(&py_result, dom_groups,
+ num_dom_groups);
+ }
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
+
+ return py_result;
+}
+
+static PyMethodDef samr_domain_methods[] = {
+ { "enum_domain_groups", (PyCFunction)samr_enum_dom_groups,
+ METH_VARARGS | METH_KEYWORDS, "Enumerate domain groups" },
+ { NULL }
+};
+
+static PyObject *py_samr_domain_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_domain_methods, self, attrname);
+}
+
+PyTypeObject samr_domain_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Domain Handle",
+ sizeof(samr_domain_hnd_object),
+ 0,
+ py_samr_domain_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_domain_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+/* SAMR user handle object */
+
+static void py_samr_user_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyMethodDef samr_user_methods[] = {
+ { NULL }
+};
+
+static PyObject *py_samr_user_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_user_methods, self, attrname);
+}
+
+PyTypeObject samr_user_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR User Handle",
+ sizeof(samr_user_hnd_object),
+ 0,
+ py_samr_user_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_user_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_user_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_user_hnd_object *o;
+
+ o = PyObject_New(samr_user_hnd_object, &samr_user_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->user_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/* SAMR group handle object */
+
+static void py_samr_group_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyMethodDef samr_group_methods[] = {
+ { NULL }
+};
+
+static PyObject *py_samr_group_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_group_methods, self, attrname);
+}
+
+PyTypeObject samr_group_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Group Handle",
+ sizeof(samr_group_hnd_object),
+ 0,
+ py_samr_group_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_group_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_group_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_group_hnd_object *o;
+
+ o = PyObject_New(samr_group_hnd_object, &samr_group_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->group_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/* Alias handle object */
+
+static void py_samr_alias_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyMethodDef samr_alias_methods[] = {
+ { NULL }
+};
+
+static PyObject *py_samr_alias_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_alias_methods, self, attrname);
+}
+
+PyTypeObject samr_alias_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Alias Handle",
+ sizeof(samr_alias_hnd_object),
+ 0,
+ py_samr_alias_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_alias_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_alias_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_alias_hnd_object *o;
+
+ o = PyObject_New(samr_alias_hnd_object, &samr_alias_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->alias_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+static PyObject *samr_connect(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "server", "creds", "access", NULL };
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ char *server, *errstr;
+ struct cli_state *cli = NULL;
+ POLICY_HND hnd;
+ TALLOC_CTX *mem_ctx = NULL;
+ PyObject *result = NULL, *creds = NULL;
+ NTSTATUS ntstatus;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|Oi", kwlist, &server, &creds,
+ &desired_access))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SAMR, &errstr))) {
+ PyErr_SetString(samr_error, errstr);
+ free(errstr);
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(samr_ntstatus,
+ "unable to init talloc context\n");
+ goto done;
+ }
+
+ ntstatus = cli_samr_connect(cli, mem_ctx, desired_access, &hnd);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ cli_shutdown(cli);
+ SAFE_FREE(cli);
+ PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus));
+ goto done;
+ }
+
+ result = new_samr_connect_hnd_object(cli, mem_ctx, &hnd);
+
+done:
+ if (!result) {
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ return result;
+}
+
+/*
+ * Module initialisation
+ */
+
+static PyMethodDef samr_methods[] = {
+
+ /* Open/close samr connect handles */
+
+ { "connect", (PyCFunction)samr_connect,
+ METH_VARARGS | METH_KEYWORDS,
+ "Open a connect handle" },
+
+ { NULL }
+};
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+ { NULL }
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+void initsamr(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("samr", samr_methods);
+ dict = PyModule_GetDict(module);
+
+ samr_error = PyErr_NewException("samr.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", samr_error);
+
+ samr_ntstatus = PyErr_NewException("samr.ntstatus", NULL, NULL);
+ PyDict_SetItemString(dict, "ntstatus", samr_ntstatus);
+
+ /* Initialise policy handle object */
+
+ samr_connect_hnd_type.ob_type = &PyType_Type;
+ samr_domain_hnd_type.ob_type = &PyType_Type;
+ samr_user_hnd_type.ob_type = &PyType_Type;
+ samr_group_hnd_type.ob_type = &PyType_Type;
+ samr_alias_hnd_type.ob_type = &PyType_Type;
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ setup_logging("samr", True);
+ DEBUGLEVEL = 10;
+}
diff --git a/source3/python/py_samr_conv.c b/source3/python/py_samr_conv.c
new file mode 100644
index 0000000000..fdf71641e0
--- /dev/null
+++ b/source3/python/py_samr_conv.c
@@ -0,0 +1,58 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_samr.h"
+#include "python/py_conv.h"
+
+/*
+ * Convert between acct_info and Python
+ */
+
+BOOL py_from_acct_info(PyObject **array, struct acct_info *info, int num_accts)
+{
+ int i;
+
+ *array = PyList_New(num_accts);
+
+ for (i = 0; i < num_accts; i++) {
+ PyObject *obj;
+
+ obj = PyDict_New();
+
+ PyDict_SetItemString(
+ obj, "name", PyString_FromString(info[i].acct_name));
+
+ PyDict_SetItemString(
+ obj, "description",
+ PyString_FromString(info[i].acct_desc));
+
+ PyDict_SetItemString(obj, "rid", PyInt_FromLong(info[i].rid));
+
+ PyList_SetItem(*array, i, obj);
+ }
+
+ return True;
+}
+
+BOOL py_to_acct_info(PRINTER_INFO_3 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx)
+{
+ return False;
+}
diff --git a/source3/python/py_spoolss.c b/source3/python/py_spoolss.c
new file mode 100644
index 0000000000..4451cd87b2
--- /dev/null
+++ b/source3/python/py_spoolss.c
@@ -0,0 +1,490 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Exceptions this module can raise */
+
+PyObject *spoolss_error, *spoolss_werror;
+
+/*
+ * Routines to convert from python hashes to Samba structures
+ */
+
+PyObject *new_spoolss_policy_hnd_object(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, POLICY_HND *pol)
+{
+ spoolss_policy_hnd_object *o;
+
+ o = PyObject_New(spoolss_policy_hnd_object, &spoolss_policy_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/*
+ * Method dispatch table
+ */
+
+static PyMethodDef spoolss_methods[] = {
+
+ /* Open/close printer handles */
+
+ { "openprinter", (PyCFunction)spoolss_openprinter, METH_VARARGS | METH_KEYWORDS,
+ "Open a printer by name in UNC format.
+
+Optionally a dictionary of (domain, username, password) may be given in
+which case they are used when opening the RPC pipe. An access mask may
+also be given which defaults to MAXIMUM_ALLOWED_ACCESS.
+
+Example:
+
+>>> hnd = spoolss.openprinter(\"\\\\\\\\NPSD-PDC2\\\\meanie\")"},
+
+ { "closeprinter", spoolss_closeprinter, METH_VARARGS,
+ "Close a printer handle opened with openprinter or addprinter.
+
+Example:
+
+>>> spoolss.closeprinter(hnd)"},
+
+ { "addprinterex", (PyCFunction)spoolss_addprinterex, METH_VARARGS,
+ "addprinterex()"},
+
+ /* Server enumeratation functions */
+
+ { "enumprinters", (PyCFunction)spoolss_enumprinters,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printers on a print server.
+
+Return a list of printers on a print server. The credentials, info level
+and flags may be specified as keyword arguments.
+
+Example:
+
+>>> print spoolss.enumprinters(\"\\\\\\\\npsd-pdc2\")
+[{'comment': 'i am a comment', 'printer_name': 'meanie', 'flags': 8388608,
+ 'description': 'meanie,Generic / Text Only,i am a location'},
+ {'comment': '', 'printer_name': 'fileprint', 'flags': 8388608,
+ 'description': 'fileprint,Generic / Text Only,'}]"},
+
+ { "enumports", (PyCFunction)spoolss_enumports,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate ports on a print server.
+
+Return a list of ports on a print server.
+
+Example:
+
+>>> print spoolss.enumports(\"\\\\\\\\npsd-pdc2\")
+[{'name': 'LPT1:'}, {'name': 'LPT2:'}, {'name': 'COM1:'}, {'name': 'COM2:'},
+ {'name': 'FILE:'}, {'name': '\\\\nautilus1\\zpekt3r'}]"},
+
+ { "enumprinterdrivers", (PyCFunction)spoolss_enumprinterdrivers,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer drivers on a print server.
+
+Return a list of printer drivers."},
+ /* Miscellaneous other commands */
+
+ { "getprinterdriverdir", (PyCFunction)spoolss_getprinterdriverdir,
+ METH_VARARGS | METH_KEYWORDS,
+ "Return printer driver directory.
+
+Return the printer driver directory for a given architecture. The
+architecture defaults to \"Windows NT x86\"."},
+
+ /* Other stuff - this should really go into a samba config module
+ but for the moment let's leave it here. */
+
+ { "setup_logging", (PyCFunction)py_setup_logging,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set up debug logging.
+
+Initialises Samba's debug logging system. One argument is expected which
+is a boolean specifying whether debugging is interactive and sent to stdout
+or logged to a file.
+
+Example:
+
+>>> spoolss.setup_logging(interactive = 1)" },
+
+ { "get_debuglevel", (PyCFunction)get_debuglevel,
+ METH_VARARGS,
+ "Set the current debug level.
+
+Example:
+
+>>> spoolss.get_debuglevel()
+0" },
+
+ { "set_debuglevel", (PyCFunction)set_debuglevel,
+ METH_VARARGS,
+ "Get the current debug level.
+
+Example:
+
+>>> spoolss.set_debuglevel(10)" },
+
+ /* Printer driver routines */
+
+ { "addprinterdriver", (PyCFunction)spoolss_addprinterdriver,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a printer driver." },
+
+ { "addprinterdriverex", (PyCFunction)spoolss_addprinterdriverex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a printer driver." },
+
+ { "deleteprinterdriver", (PyCFunction)spoolss_deleteprinterdriver,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete a printer driver." },
+
+ { "deleteprinterdriverex", (PyCFunction)spoolss_deleteprinterdriverex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete a printer driver." },
+
+ { NULL }
+};
+
+/* Methods attached to a spoolss handle object */
+
+static PyMethodDef spoolss_hnd_methods[] = {
+
+ /* Printer info */
+
+ { "getprinter", (PyCFunction)spoolss_hnd_getprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get printer information.
+
+Return a dictionary of print information. The info level defaults to 1.
+
+Example:
+
+>>> hnd.getprinter()
+{'comment': 'i am a comment', 'printer_name': '\\\\NPSD-PDC2\\meanie',
+ 'description': '\\\\NPSD-PDC2\\meanie,Generic / Text Only,i am a location',
+ 'flags': 8388608}"},
+
+ { "setprinter", (PyCFunction)spoolss_hnd_setprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set printer information."},
+
+ /* Printer drivers */
+
+ { "getprinterdriver", (PyCFunction)spoolss_hnd_getprinterdriver,
+ METH_VARARGS | METH_KEYWORDS,
+ "Return printer driver information.
+
+Return a dictionary of printer driver information for the printer driver
+bound to this printer."},
+
+ /* Forms */
+
+ { "enumforms", (PyCFunction)spoolss_hnd_enumforms,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate supported forms.
+
+Return a list of forms supported by this printer or print server."},
+
+ { "setform", (PyCFunction)spoolss_hnd_setform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set form data.
+
+Set the form given by the dictionary argument."},
+
+ { "addform", (PyCFunction)spoolss_hnd_addform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a new form." },
+
+ { "getform", (PyCFunction)spoolss_hnd_getform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get form properties." },
+
+ { "deleteform", (PyCFunction)spoolss_hnd_deleteform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete a form." },
+
+ /* Job related methods */
+
+ { "enumjobs", (PyCFunction)spoolss_hnd_enumjobs,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate jobs." },
+
+ { "setjob", (PyCFunction)spoolss_hnd_setjob,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set job information." },
+
+ { "getjob", (PyCFunction)spoolss_hnd_getjob,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get job information." },
+
+ { "startpageprinter", (PyCFunction)spoolss_hnd_startpageprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a page is about to be printed." },
+
+ { "endpageprinter", (PyCFunction)spoolss_hnd_endpageprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a page is about to be printed." },
+
+ { "startdocprinter", (PyCFunction)spoolss_hnd_startdocprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a document is about to be printed." },
+
+ { "enddocprinter", (PyCFunction)spoolss_hnd_enddocprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a document is about to be printed." },
+
+ { "writeprinter", (PyCFunction)spoolss_hnd_writeprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Write job data to a printer." },
+
+ { "addjob", (PyCFunction)spoolss_hnd_addjob,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a job to the list of print jobs." },
+
+ /* Printer data */
+
+ { "getprinterdata", (PyCFunction)spoolss_hnd_getprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get printer data." },
+
+ { "setprinterdata", (PyCFunction)spoolss_hnd_setprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set printer data." },
+
+ { "enumprinterdata", (PyCFunction)spoolss_hnd_enumprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer data." },
+
+ { "deleteprinterdata", (PyCFunction)spoolss_hnd_deleteprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete printer data." },
+
+ { "getprinterdataex", (PyCFunction)spoolss_hnd_getprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get printer data." },
+
+ { "setprinterdataex", (PyCFunction)spoolss_hnd_setprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set printer data." },
+
+ { "enumprinterdataex", (PyCFunction)spoolss_hnd_enumprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer data." },
+
+ { "deleteprinterdataex", (PyCFunction)spoolss_hnd_deleteprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete printer data." },
+
+ { NULL }
+
+};
+
+static void py_policy_hnd_dealloc(PyObject* self)
+{
+ spoolss_policy_hnd_object *hnd;
+
+ /* Close down policy handle and free talloc context */
+
+ hnd = (spoolss_policy_hnd_object*)self;
+
+ cli_shutdown(hnd->cli);
+ talloc_destroy(hnd->mem_ctx);
+
+ PyObject_Del(self);
+}
+
+static PyObject *py_policy_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(spoolss_hnd_methods, self, attrname);
+}
+
+static char spoolss_type_doc[] =
+"Python wrapper for Windows NT SPOOLSS rpc pipe.";
+
+PyTypeObject spoolss_policy_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "spoolss.hnd",
+ sizeof(spoolss_policy_hnd_object),
+ 0,
+ py_policy_hnd_dealloc, /* tp_dealloc*/
+ 0, /* tp_print*/
+ py_policy_hnd_getattr, /* tp_getattr*/
+ 0, /* tp_setattr*/
+ 0, /* tp_compare*/
+ 0, /* tp_repr*/
+ 0, /* tp_as_number*/
+ 0, /* tp_as_sequence*/
+ 0, /* tp_as_mapping*/
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ spoolss_type_doc, /* tp_doc */
+};
+
+/* Initialise constants */
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+
+ /* Access permissions */
+
+ { "MAXIMUM_ALLOWED_ACCESS", MAXIMUM_ALLOWED_ACCESS },
+ { "SERVER_ALL_ACCESS", SERVER_ALL_ACCESS },
+ { "SERVER_READ", SERVER_READ },
+ { "SERVER_WRITE", SERVER_WRITE },
+ { "SERVER_EXECUTE", SERVER_EXECUTE },
+ { "SERVER_ACCESS_ADMINISTER", SERVER_ACCESS_ADMINISTER },
+ { "SERVER_ACCESS_ENUMERATE", SERVER_ACCESS_ENUMERATE },
+ { "PRINTER_ALL_ACCESS", PRINTER_ALL_ACCESS },
+ { "PRINTER_READ", PRINTER_READ },
+ { "PRINTER_WRITE", PRINTER_WRITE },
+ { "PRINTER_EXECUTE", PRINTER_EXECUTE },
+ { "PRINTER_ACCESS_ADMINISTER", PRINTER_ACCESS_ADMINISTER },
+ { "PRINTER_ACCESS_USE", PRINTER_ACCESS_USE },
+ { "JOB_ACCESS_ADMINISTER", JOB_ACCESS_ADMINISTER },
+ { "JOB_ALL_ACCESS", JOB_ALL_ACCESS },
+ { "JOB_READ", JOB_READ },
+ { "JOB_WRITE", JOB_WRITE },
+ { "JOB_EXECUTE", JOB_EXECUTE },
+ { "STANDARD_RIGHTS_ALL_ACCESS", STANDARD_RIGHTS_ALL_ACCESS },
+ { "STANDARD_RIGHTS_EXECUTE_ACCESS", STANDARD_RIGHTS_EXECUTE_ACCESS },
+ { "STANDARD_RIGHTS_READ_ACCESS", STANDARD_RIGHTS_READ_ACCESS },
+ { "STANDARD_RIGHTS_REQUIRED_ACCESS", STANDARD_RIGHTS_REQUIRED_ACCESS },
+ { "STANDARD_RIGHTS_WRITE_ACCESS", STANDARD_RIGHTS_WRITE_ACCESS },
+
+ /* Printer enumeration flags */
+
+ { "PRINTER_ENUM_DEFAULT", PRINTER_ENUM_DEFAULT },
+ { "PRINTER_ENUM_LOCAL", PRINTER_ENUM_LOCAL },
+ { "PRINTER_ENUM_CONNECTIONS", PRINTER_ENUM_CONNECTIONS },
+ { "PRINTER_ENUM_FAVORITE", PRINTER_ENUM_FAVORITE },
+ { "PRINTER_ENUM_NAME", PRINTER_ENUM_NAME },
+ { "PRINTER_ENUM_REMOTE", PRINTER_ENUM_REMOTE },
+ { "PRINTER_ENUM_SHARED", PRINTER_ENUM_SHARED },
+ { "PRINTER_ENUM_NETWORK", PRINTER_ENUM_NETWORK },
+
+ /* Form types */
+
+ { "FORM_USER", FORM_USER },
+ { "FORM_BUILTIN", FORM_BUILTIN },
+ { "FORM_PRINTER", FORM_PRINTER },
+
+ /* WERRORs */
+
+ { "WERR_OK", 0 },
+ { "WERR_BADFILE", 2 },
+ { "WERR_ACCESS_DENIED", 5 },
+ { "WERR_BADFID", 6 },
+ { "WERR_BADFUNC", 1 },
+ { "WERR_INSUFFICIENT_BUFFER", 122 },
+ { "WERR_NO_SUCH_SHARE", 67 },
+ { "WERR_ALREADY_EXISTS", 80 },
+ { "WERR_INVALID_PARAM", 87 },
+ { "WERR_NOT_SUPPORTED", 50 },
+ { "WERR_BAD_PASSWORD", 86 },
+ { "WERR_NOMEM", 8 },
+ { "WERR_INVALID_NAME", 123 },
+ { "WERR_UNKNOWN_LEVEL", 124 },
+ { "WERR_OBJECT_PATH_INVALID", 161 },
+ { "WERR_NO_MORE_ITEMS", 259 },
+ { "WERR_MORE_DATA", 234 },
+ { "WERR_UNKNOWN_PRINTER_DRIVER", 1797 },
+ { "WERR_INVALID_PRINTER_NAME", 1801 },
+ { "WERR_PRINTER_ALREADY_EXISTS", 1802 },
+ { "WERR_INVALID_DATATYPE", 1804 },
+ { "WERR_INVALID_ENVIRONMENT", 1805 },
+ { "WERR_INVALID_FORM_NAME", 1902 },
+ { "WERR_INVALID_FORM_SIZE", 1903 },
+ { "WERR_BUF_TOO_SMALL", 2123 },
+ { "WERR_JOB_NOT_FOUND", 2151 },
+ { "WERR_DEST_NOT_FOUND", 2152 },
+ { "WERR_NOT_LOCAL_DOMAIN", 2320 },
+ { "WERR_PRINTER_DRIVER_IN_USE", 3001 },
+ { "WERR_STATUS_MORE_ENTRIES ", 0x0105 },
+
+ /* Job control constants */
+
+ { "JOB_CONTROL_PAUSE", JOB_CONTROL_PAUSE },
+ { "JOB_CONTROL_RESUME", JOB_CONTROL_RESUME },
+ { "JOB_CONTROL_CANCEL", JOB_CONTROL_CANCEL },
+ { "JOB_CONTROL_RESTART", JOB_CONTROL_RESTART },
+ { "JOB_CONTROL_DELETE", JOB_CONTROL_DELETE },
+
+ { NULL },
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/* Module initialisation */
+
+void initspoolss(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("spoolss", spoolss_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Exceptions we can raise */
+
+ spoolss_error = PyErr_NewException("spoolss.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", spoolss_error);
+
+ spoolss_werror = PyErr_NewException("spoolss.werror", NULL, NULL);
+ PyDict_SetItemString(dict, "werror", spoolss_werror);
+
+ /* Initialise policy handle object */
+
+ spoolss_policy_hnd_type.ob_type = &PyType_Type;
+
+ PyDict_SetItemString(dict, "spoolss.hnd",
+ (PyObject *)&spoolss_policy_hnd_type);
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+}
diff --git a/source3/python/py_spoolss_drivers.c b/source3/python/py_spoolss_drivers.c
new file mode 100644
index 0000000000..0c242d9181
--- /dev/null
+++ b/source3/python/py_spoolss_drivers.c
@@ -0,0 +1,420 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Enumerate printer drivers */
+
+PyObject *spoolss_enumprinterdrivers(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ PRINTER_DRIVER_CTR ctr;
+ int level = 1, i;
+ uint32 needed, num_drivers;
+ char *arch = "Windows NT x86", *server, *errstr;
+ static char *kwlist[] = {"server", "level", "creds", "arch", NULL};
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|iOs", kwlist, &server, &level, &creds,
+ &arch))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ werror = cli_spoolss_enumprinterdrivers(
+ cli, mem_ctx, 0, &needed, level, arch,
+ &num_drivers, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enumprinterdrivers(
+ cli, mem_ctx, needed, NULL, level, arch,
+ &num_drivers, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ result = PyDict_New();
+
+ for (i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info1[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_1(&value, &ctr.info1[i]);
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 2:
+ result = PyDict_New();
+
+ for(i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info2[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_2(&value, &ctr.info2[i]);
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 3:
+ result = PyDict_New();
+
+ for(i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info3[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_3(&value, &ctr.info3[i]);
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 6:
+ result = PyDict_New();
+
+ for(i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info6[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_6(&value, &ctr.info6[i]);
+
+ PyList_SetItem(result, i, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+ done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Fetch printer driver */
+
+PyObject *spoolss_hnd_getprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result = Py_None;
+ PRINTER_DRIVER_CTR ctr;
+ int level = 1;
+ uint32 needed;
+ char *arch = "Windows NT x86";
+ static char *kwlist[] = {"level", "arch", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|is", kwlist, &level, &arch))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinterdriver(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level,
+ arch, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getprinterdriver(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ level, arch, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ py_from_DRIVER_INFO_1(&result, ctr.info1);
+ break;
+ case 2:
+ py_from_DRIVER_INFO_2(&result, ctr.info2);
+ break;
+ case 3:
+ py_from_DRIVER_INFO_3(&result, ctr.info3);
+ break;
+ case 6:
+ py_from_DRIVER_INFO_6(&result, ctr.info6);
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* Fetch printer driver directory */
+
+PyObject *spoolss_getprinterdriverdir(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ DRIVER_DIRECTORY_CTR ctr;
+ uint32 needed, level = 1;
+ char *arch = "Windows NT x86", *server, *errstr;
+ static char *kwlist[] = {"server", "level", "arch", "creds", NULL};
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|isO", kwlist, &server, &level,
+ &arch, &creds))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ werror = cli_spoolss_getprinterdriverdir(
+ cli, mem_ctx, 0, &needed, level, arch, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getprinterdriverdir(
+ cli, mem_ctx, needed, NULL, level, arch, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ py_from_DRIVER_DIRECTORY_1(&result, ctr.info1);
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+ done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+PyObject *spoolss_addprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ static char *kwlist[] = { "server", "info", "creds", NULL };
+ char *server, *errstr;
+ uint32 level;
+ PyObject *info, *result = NULL, *creds = NULL;
+ WERROR werror;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_state *cli = NULL;
+ PRINTER_DRIVER_CTR ctr;
+ union {
+ DRIVER_INFO_3 driver_3;
+ } dinfo;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "sO!|O", kwlist, &server, &PyDict_Type,
+ &info, &creds))
+ return NULL;
+
+ if (server[0] == '\\' || server[1] == '\\')
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ goto done;
+ }
+
+ if (level != 3) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ goto done;
+ }
+
+ ZERO_STRUCT(ctr);
+
+ switch(level) {
+ case 3:
+ ctr.info3 = &dinfo.driver_3;
+
+ if (!py_to_DRIVER_INFO_3(&dinfo.driver_3, info)) {
+ PyErr_SetString(spoolss_error,
+ "error converting to driver info 3");
+ goto done;
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ goto done;
+ }
+
+ werror = cli_spoolss_addprinterdriver(cli, mem_ctx, level, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ Py_INCREF(Py_None);
+ result = Py_None;
+
+done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+
+}
+
+PyObject *spoolss_addprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ /* Not supported by Samba server */
+
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
+
+PyObject *spoolss_deleteprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
+
+PyObject *spoolss_deleteprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
diff --git a/source3/python/py_spoolss_drivers_conv.c b/source3/python/py_spoolss_drivers_conv.c
new file mode 100644
index 0000000000..41ff38327e
--- /dev/null
+++ b/source3/python/py_spoolss_drivers_conv.c
@@ -0,0 +1,177 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+/* Structure/hash conversions */
+
+struct pyconv py_DRIVER_INFO_1[] = {
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_1, name) },
+ { NULL }
+};
+
+struct pyconv py_DRIVER_INFO_2[] = {
+ { "version", PY_UINT32, offsetof(DRIVER_INFO_2, version) },
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_2, name) },
+ { "architecture", PY_UNISTR, offsetof(DRIVER_INFO_2, architecture) },
+ { "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_2, driverpath) },
+ { "data_file", PY_UNISTR, offsetof(DRIVER_INFO_2, datafile) },
+ { "config_file", PY_UNISTR, offsetof(DRIVER_INFO_2, configfile) },
+ { NULL }
+};
+
+struct pyconv py_DRIVER_INFO_3[] = {
+ { "version", PY_UINT32, offsetof(DRIVER_INFO_3, version) },
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_3, name) },
+ { "architecture", PY_UNISTR, offsetof(DRIVER_INFO_3, architecture) },
+ { "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_3, driverpath) },
+ { "data_file", PY_UNISTR, offsetof(DRIVER_INFO_3, datafile) },
+ { "config_file", PY_UNISTR, offsetof(DRIVER_INFO_3, configfile) },
+ { "help_file", PY_UNISTR, offsetof(DRIVER_INFO_3, helpfile) },
+ { "monitor_name", PY_UNISTR, offsetof(DRIVER_INFO_3, monitorname) },
+ { "default_datatype", PY_UNISTR, offsetof(DRIVER_INFO_3, defaultdatatype) },
+ { NULL }
+};
+
+struct pyconv py_DRIVER_INFO_6[] = {
+ { "version", PY_UINT32, offsetof(DRIVER_INFO_6, version) },
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_6, name) },
+ { "architecture", PY_UNISTR, offsetof(DRIVER_INFO_6, architecture) },
+ { "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_6, driverpath) },
+ { "data_file", PY_UNISTR, offsetof(DRIVER_INFO_6, datafile) },
+ { "config_file", PY_UNISTR, offsetof(DRIVER_INFO_6, configfile) },
+ { "help_file", PY_UNISTR, offsetof(DRIVER_INFO_6, helpfile) },
+ { "monitor_name", PY_UNISTR, offsetof(DRIVER_INFO_6, monitorname) },
+ { "default_datatype", PY_UNISTR, offsetof(DRIVER_INFO_6, defaultdatatype) },
+ /* driver_date */
+ { "padding", PY_UINT32, offsetof(DRIVER_INFO_6, padding) },
+ { "driver_version_low", PY_UINT32, offsetof(DRIVER_INFO_6, driver_version_low) },
+ { "driver_version_high", PY_UINT32, offsetof(DRIVER_INFO_6, driver_version_high) },
+ { "mfg_name", PY_UNISTR, offsetof(DRIVER_INFO_6, mfgname) },
+ { "oem_url", PY_UNISTR, offsetof(DRIVER_INFO_6, oem_url) },
+ { "hardware_id", PY_UNISTR, offsetof(DRIVER_INFO_6, hardware_id) },
+ { "provider", PY_UNISTR, offsetof(DRIVER_INFO_6, provider) },
+
+ { NULL }
+};
+
+struct pyconv py_DRIVER_DIRECTORY_1[] = {
+ { "name", PY_UNISTR, offsetof(DRIVER_DIRECTORY_1, name) },
+ { NULL }
+};
+
+/* Convert a NULL terminated list of NULL terminated unicode strings
+ to a list of (char *) strings */
+
+static PyObject *from_dependentfiles(uint16 *dependentfiles)
+{
+ PyObject *list;
+ int offset = 0;
+
+ list = PyList_New(0);
+
+ while (*(dependentfiles + offset) != 0) {
+ fstring name;
+ int len;
+
+ len = rpcstr_pull(name, dependentfiles + offset,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ offset += len / 2;
+ PyList_Append(list, PyString_FromString(name));
+ }
+
+ return list;
+}
+
+BOOL py_from_DRIVER_INFO_1(PyObject **dict, DRIVER_INFO_1 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_1);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_1(DRIVER_INFO_1 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DRIVER_INFO_2(PyObject **dict, DRIVER_INFO_2 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_2);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(2));
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_2(DRIVER_INFO_2 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DRIVER_INFO_3(PyObject **dict, DRIVER_INFO_3 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_3);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(3));
+ PyDict_SetItemString(
+ *dict, "dependent_files",
+ from_dependentfiles(info->dependentfiles));
+
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_3(DRIVER_INFO_3 *info, PyObject *dict)
+{
+ PyObject *dict_copy = PyDict_Copy(dict);
+ BOOL result;
+
+ PyDict_DelItemString(dict_copy, "level");
+ result = to_struct(info, dict_copy, py_DRIVER_INFO_3);
+
+ Py_DECREF(dict_copy);
+ return result;
+}
+
+BOOL py_from_DRIVER_INFO_6(PyObject **dict, DRIVER_INFO_6 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_6);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(6));
+ PyDict_SetItemString(
+ *dict, "dependent_files",
+ from_dependentfiles (info->dependentfiles));
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_6(DRIVER_INFO_6 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DRIVER_DIRECTORY_1(PyObject **dict, DRIVER_DIRECTORY_1 *info)
+{
+ *dict = from_struct(info, py_DRIVER_DIRECTORY_1);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+ return True;
+}
+
+BOOL py_to_DRIVER_DIRECTORY_1(DRIVER_DIRECTORY_1 *info, PyObject *dict)
+{
+ return False;
+}
diff --git a/source3/python/py_spoolss_forms.c b/source3/python/py_spoolss_forms.c
new file mode 100644
index 0000000000..ef9ed94533
--- /dev/null
+++ b/source3/python/py_spoolss_forms.c
@@ -0,0 +1,266 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Add a form */
+
+PyObject *spoolss_hnd_addform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *info;
+ FORM form;
+ int level;
+ static char *kwlist[] = {"form", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ /* Call rpc function */
+
+ if (!py_to_FORM(&form, info)) {
+ PyErr_SetString(spoolss_error, "invalid form");
+ return NULL;
+ }
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level != 1) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ switch (level) {
+ case 1: {
+ PyObject *obj = PyDict_GetItemString(info, "name");
+ char *form_name = PyString_AsString(obj);
+
+ init_unistr2(&form.name, form_name, strlen(form_name) + 1);
+ break;
+ }
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ werror = cli_spoolss_addform(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ level, &form);
+
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Get form properties */
+
+PyObject *spoolss_hnd_getform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result;
+ char *form_name;
+ int level = 1;
+ static char *kwlist[] = {"form_name", "level", NULL};
+ uint32 needed;
+ FORM_1 form;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|i", kwlist, &form_name, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getform(hnd->cli, hnd->mem_ctx, 0, &needed,
+ &hnd->pol, form_name, level, &form);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getform(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ form_name, 1, &form);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ result = Py_None;
+
+ switch(level) {
+ case 1:
+ py_from_FORM_1(&result, &form);
+ break;
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* Set form properties */
+
+PyObject *spoolss_hnd_setform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *info, *form_name;
+ int level;
+ static char *kwlist[] = { "form", NULL};
+ FORM form;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level != 1) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ if (!py_to_FORM(&form, info)) {
+ PyErr_SetString(spoolss_error, "invalid form");
+ return NULL;
+ }
+
+ form_name = PyDict_GetItemString(info, "name");
+
+ werror = cli_spoolss_setform(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, level,
+ PyString_AsString(form_name), &form);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Delete a form */
+
+PyObject *spoolss_hnd_deleteform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = {"form_name", NULL};
+ char *form_name;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s", kwlist, &form_name))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_deleteform(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, form_name);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Enumerate forms */
+
+PyObject *spoolss_hnd_enumforms(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyObject *result;
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ uint32 level = 1, num_forms, needed, i;
+ static char *kwlist[] = {"level", NULL};
+ FORM_1 *forms;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|i", kwlist, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enumforms(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level,
+ &num_forms, &forms);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enumforms(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, level,
+ &num_forms, &forms);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ switch(level) {
+ case 1:
+ result = PyDict_New();
+
+ for (i = 0; i < num_forms; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, forms[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_FORM_1(&value, &forms[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(1));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ return NULL;
+ }
+
+ return result;
+}
diff --git a/source3/python/py_spoolss_jobs.c b/source3/python/py_spoolss_jobs.c
new file mode 100644
index 0000000000..59754bd36d
--- /dev/null
+++ b/source3/python/py_spoolss_jobs.c
@@ -0,0 +1,377 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Enumerate jobs */
+
+PyObject *spoolss_hnd_enumjobs(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result;
+ int level = 1;
+ uint32 i, needed, num_jobs;
+ static char *kwlist[] = {"level", NULL};
+ JOB_INFO_CTR ctr;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|i", kwlist, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enumjobs(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level, 0,
+ 1000, &num_jobs, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enumjobs(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ level, 0, 1000, &num_jobs, &ctr);
+
+ /* Return value */
+
+ result = Py_None;
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ result = PyList_New(num_jobs);
+
+ switch (level) {
+ case 1:
+ for (i = 0; i < num_jobs; i++) {
+ PyObject *value;
+
+ py_from_JOB_INFO_1(&value, &ctr.job.job_info_1[i]);
+
+ PyList_SetItem(result, i, value);
+ }
+
+ break;
+ case 2:
+ for(i = 0; i < num_jobs; i++) {
+ PyObject *value;
+
+ py_from_JOB_INFO_2(&value, &ctr.job.job_info_2[i]);
+
+ PyList_SetItem(result, i, value);
+ }
+
+ break;
+ }
+
+ done:
+ Py_INCREF(result);
+ return result;
+}
+
+/* Set job command */
+
+PyObject *spoolss_hnd_setjob(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ uint32 level = 0, command, jobid;
+ static char *kwlist[] = {"jobid", "command", "level", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "ii|i", kwlist, &jobid, &command, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setjob(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ jobid, level, command);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Get job */
+
+PyObject *spoolss_hnd_getjob(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result;
+ uint32 level = 1, jobid, needed;
+ static char *kwlist[] = {"jobid", "level", NULL};
+ JOB_INFO_CTR ctr;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "i|i", kwlist, &jobid, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getjob(hnd->cli, hnd->mem_ctx, 0, &needed,
+ &hnd->pol, jobid, level, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getjob(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ jobid, level, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ switch(level) {
+ case 1:
+ py_from_JOB_INFO_1(&result, &ctr.job.job_info_1[0]);
+ break;
+ case 2:
+ py_from_JOB_INFO_2(&result, &ctr.job.job_info_2[0]);
+ break;
+ }
+
+ return result;
+}
+
+/* Start page printer. This notifies the spooler that a page is about to be
+ printed on the specified printer. */
+
+PyObject *spoolss_hnd_startpageprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { NULL };
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_startpageprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* End page printer. This notifies the spooler that a page has finished
+ being printed on the specified printer. */
+
+PyObject *spoolss_hnd_endpageprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { NULL };
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_endpageprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Start doc printer. This notifies the spooler that a document is about to be
+ printed on the specified printer. */
+
+PyObject *spoolss_hnd_startdocprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { "document_info", NULL };
+ PyObject *info, *obj;
+ uint32 level, jobid;
+ char *document_name = NULL, *output_file = NULL, *data_type = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ /* Check document_info parameter */
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level != 1) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ if ((obj = PyDict_GetItemString(info, "document_name"))) {
+
+ if (!PyString_Check(obj) && obj != Py_None) {
+ PyErr_SetString(spoolss_error,
+ "document_name not a string");
+ return NULL;
+ }
+
+ if (PyString_Check(obj))
+ document_name = PyString_AsString(obj);
+
+ } else {
+ PyErr_SetString(spoolss_error, "no document_name present");
+ return NULL;
+ }
+
+ if ((obj = PyDict_GetItemString(info, "output_file"))) {
+
+ if (!PyString_Check(obj) && obj != Py_None) {
+ PyErr_SetString(spoolss_error,
+ "output_file not a string");
+ return NULL;
+ }
+
+ if (PyString_Check(obj))
+ output_file = PyString_AsString(obj);
+
+ } else {
+ PyErr_SetString(spoolss_error, "no output_file present");
+ return NULL;
+ }
+
+ if ((obj = PyDict_GetItemString(info, "data_type"))) {
+
+ if (!PyString_Check(obj) && obj != Py_None) {
+ PyErr_SetString(spoolss_error,
+ "data_type not a string");
+ return NULL;
+ }
+
+ if (PyString_Check(obj))
+ data_type = PyString_AsString(obj);
+
+ } else {
+ PyErr_SetString(spoolss_error, "no data_type present");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_startdocprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, document_name,
+ output_file, data_type, &jobid);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* The return value is zero for an error (where does the status
+ code come from now??) and the return value is the jobid
+ allocated for the new job. */
+
+ return Py_BuildValue("i", jobid);
+}
+
+/* End doc printer. This notifies the spooler that a document has finished
+ being printed on the specified printer. */
+
+PyObject *spoolss_hnd_enddocprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { NULL };
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enddocprinter(hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Write data to a printer */
+
+PyObject *spoolss_hnd_writeprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { "data", NULL };
+ PyObject *data;
+ uint32 num_written;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyString_Type, &data))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_writeprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, PyString_Size(data),
+ PyString_AsString(data), &num_written);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_addjob(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
diff --git a/source3/python/py_spoolss_printerdata.c b/source3/python/py_spoolss_printerdata.c
new file mode 100644
index 0000000000..bacc870d9d
--- /dev/null
+++ b/source3/python/py_spoolss_printerdata.c
@@ -0,0 +1,393 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+static BOOL py_from_printerdata(PyObject **dict, char *key, char *value,
+ uint16 data_type, uint8 *data,
+ uint32 data_size)
+{
+ *dict = PyDict_New();
+
+ PyDict_SetItemString(*dict, "key", Py_BuildValue("s", key ? key : ""));
+ PyDict_SetItemString(*dict, "value", Py_BuildValue("s", value));
+ PyDict_SetItemString(*dict, "type", Py_BuildValue("i", data_type));
+
+ PyDict_SetItemString(*dict, "data",
+ Py_BuildValue("s#", data, data_size));
+
+ return True;
+}
+
+static BOOL py_to_printerdata(char **key, char **value, uint16 *data_type,
+ uint8 **data, uint32 *data_size,
+ PyObject *dict)
+{
+ PyObject *obj;
+
+ if ((obj = PyDict_GetItemString(dict, "key"))) {
+
+ if (!PyString_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "key not a string");
+ return False;
+ }
+
+ if (key) {
+ *key = PyString_AsString(obj);
+
+ if (!key[0])
+ *key = NULL;
+ }
+ } else
+ *key = NULL;
+
+ if ((obj = PyDict_GetItemString(dict, "value"))) {
+
+ if (!PyString_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "value not a string");
+ return False;
+ }
+
+ *value = PyString_AsString(obj);
+ } else {
+ PyErr_SetString(spoolss_error, "no value present");
+ return False;
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "type"))) {
+
+ if (!PyInt_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "type not an integer");
+ return False;
+ }
+
+ *data_type = PyInt_AsLong(obj);
+ } else {
+ PyErr_SetString(spoolss_error, "no type present");
+ return False;
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "data"))) {
+
+ if (!PyString_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "data not a string");
+ return False;
+ }
+
+ *data = PyString_AsString(obj);
+ *data_size = PyString_Size(obj);
+ } else {
+ PyErr_SetString(spoolss_error, "no data present");
+ return False;
+ }
+
+ return True;
+}
+
+PyObject *spoolss_hnd_getprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "value", NULL };
+ char *valuename;
+ WERROR werror;
+ uint32 needed;
+ PyObject *result;
+ REGISTRY_VALUE value;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &valuename))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinterdata(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, valuename,
+ &value);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_getprinterdata(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ valuename, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ py_from_printerdata(
+ &result, NULL, valuename, value.type, value.data_p,
+ value.size);
+
+ return result;
+}
+
+PyObject *spoolss_hnd_setprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "data", NULL };
+ PyObject *py_data;
+ char *valuename;
+ WERROR werror;
+ REGISTRY_VALUE value;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &py_data))
+ return NULL;
+
+ if (!py_to_printerdata(
+ NULL, &valuename, &value.type, &value.data_p,
+ &value.size, py_data))
+ return NULL;
+
+ fstrcpy(value.valuename, valuename);
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_enumprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { NULL };
+ uint32 data_needed, value_needed, ndx = 0;
+ WERROR werror;
+ PyObject *result;
+ REGISTRY_VALUE value;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Get max buffer sizes for value and data */
+
+ werror = cli_spoolss_enumprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, ndx, 0, 0,
+ &value_needed, &data_needed, NULL);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* Iterate over all printerdata */
+
+ result = PyDict_New();
+
+ while (W_ERROR_IS_OK(werror)) {
+ PyObject *obj;
+
+ werror = cli_spoolss_enumprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, ndx,
+ value_needed, data_needed, NULL, NULL, &value);
+
+ if (py_from_printerdata(
+ &obj, NULL, value.valuename, value.type,
+ value.data_p, value.size))
+ PyDict_SetItemString(result, value.valuename, obj);
+
+ ndx++;
+ }
+
+ return result;
+}
+
+PyObject *spoolss_hnd_deleteprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "value", NULL };
+ char *value;
+ WERROR werror;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &value))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_deleteprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_getprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", "value", NULL };
+ char *key, *valuename;
+ WERROR werror;
+ uint32 needed;
+ PyObject *result;
+ REGISTRY_VALUE value;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "ss", kwlist, &key, &valuename))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinterdataex(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, key,
+ valuename, &value);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_getprinterdataex(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, key,
+ valuename, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ py_from_printerdata(
+ &result, key, valuename, value.type, value.data_p, value.size);
+
+ return result;
+}
+
+PyObject *spoolss_hnd_setprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "data", NULL };
+ PyObject *py_data;
+ char *keyname, *valuename;
+ WERROR werror;
+ REGISTRY_VALUE value;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &py_data))
+ return NULL;
+
+ if (!py_to_printerdata(
+ &keyname, &valuename, &value.type, &value.data_p, &value.size, py_data))
+ return NULL;
+
+ fstrcpy(value.valuename, valuename);
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setprinterdataex(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, keyname, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_enumprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", NULL };
+ uint32 needed, i;
+ char *key;
+ WERROR werror;
+ PyObject *result;
+ REGVAL_CTR ctr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &key))
+ return NULL;
+
+ /* Get max buffer sizes for value and data */
+
+ werror = cli_spoolss_enumprinterdataex(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, key, &ctr);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_enumprinterdataex(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, key,
+ &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* Iterate over all printerdata */
+
+ result = PyDict_New();
+
+ for (i = 0; i < regval_ctr_numvals(&ctr); i++) {
+ REGISTRY_VALUE *value;
+ PyObject *item;
+
+ item = PyDict_New();
+ value = regval_ctr_specific_value(&ctr, i);
+
+ if (py_from_printerdata(
+ &item, key, value->valuename, value->type,
+ value->data_p, value->size))
+ PyDict_SetItemString(result, value->valuename, item);
+ }
+
+ return result;
+}
+
+PyObject *spoolss_hnd_deleteprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", "value", NULL };
+ char *key, *value;
+ WERROR werror;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "ss", kwlist, &key, &value))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_deleteprinterdataex(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, key, value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
diff --git a/source3/python/py_spoolss_printers.c b/source3/python/py_spoolss_printers.c
new file mode 100644
index 0000000000..a300eada86
--- /dev/null
+++ b/source3/python/py_spoolss_printers.c
@@ -0,0 +1,475 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Open a printer */
+
+PyObject *spoolss_openprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ char *unc_name, *server, *errstr;
+ TALLOC_CTX *mem_ctx = NULL;
+ POLICY_HND hnd;
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ static char *kwlist[] = { "printername", "creds", "access", NULL };
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ struct cli_state *cli;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|Oi", kwlist, &unc_name, &creds,
+ &desired_access))
+ return NULL;
+
+ if (unc_name[0] != '\\' || unc_name[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server = strdup(unc_name + 2);
+
+ if (strchr(server, '\\')) {
+ char *c = strchr(server, '\\');
+ *c = 0;
+ }
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(spoolss_error,
+ "unable to init talloc context\n");
+ goto done;
+ }
+
+ werror = cli_spoolss_open_printer_ex(
+ cli, mem_ctx, unc_name, "", desired_access, server,
+ "", &hnd);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ result = new_spoolss_policy_hnd_object(cli, mem_ctx, &hnd);
+
+ done:
+ if (!result) {
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ SAFE_FREE(server);
+
+ return result;
+}
+
+/* Close a printer */
+
+PyObject *spoolss_closeprinter(PyObject *self, PyObject *args)
+{
+ PyObject *po;
+ spoolss_policy_hnd_object *hnd;
+ WERROR result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTuple(args, "O!", &spoolss_policy_hnd_type, &po))
+ return NULL;
+
+ hnd = (spoolss_policy_hnd_object *)po;
+
+ /* Call rpc function */
+
+ result = cli_spoolss_close_printer(hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ /* Return value */
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Fetch printer information */
+
+PyObject *spoolss_hnd_getprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result = NULL;
+ PRINTER_INFO_CTR ctr;
+ int level = 1;
+ uint32 needed;
+ static char *kwlist[] = {"level", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|i", kwlist, &level))
+ return NULL;
+
+ ZERO_STRUCT(ctr);
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinter(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getprinter(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ level, &ctr);
+
+ /* Return value */
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ result = Py_None;
+
+ switch (level) {
+
+ case 0:
+ py_from_PRINTER_INFO_0(&result, ctr.printers_0);
+ break;
+
+ case 1:
+ py_from_PRINTER_INFO_1(&result, ctr.printers_1);
+ break;
+
+ case 2:
+ py_from_PRINTER_INFO_2(&result, ctr.printers_2);
+ break;
+
+ case 3:
+ py_from_PRINTER_INFO_3(&result, ctr.printers_3);
+ break;
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* Set printer information */
+
+PyObject *spoolss_hnd_setprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *info;
+ PRINTER_INFO_CTR ctr;
+ uint32 level;
+ static char *kwlist[] = {"dict", NULL};
+ union {
+ PRINTER_INFO_1 printers_1;
+ PRINTER_INFO_2 printers_2;
+ PRINTER_INFO_3 printers_3;
+ } pinfo;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level < 1 && level > 3) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ /* Fill in printer info */
+
+ ZERO_STRUCT(ctr);
+
+ switch (level) {
+ case 1:
+ ctr.printers_1 = &pinfo.printers_1;
+
+ if (!py_to_PRINTER_INFO_1(ctr.printers_1, info)){
+ PyErr_SetString(spoolss_error,
+ "error converting printer to info 1");
+ return NULL;
+ }
+
+ break;
+ case 2:
+ ctr.printers_2 = &pinfo.printers_2;
+
+ if (!py_to_PRINTER_INFO_2(ctr.printers_2, info,
+ hnd->mem_ctx)){
+ PyErr_SetString(spoolss_error,
+ "error converting printer to info 2");
+ return NULL;
+ }
+
+ break;
+ case 3:
+ ctr.printers_3 = &pinfo.printers_3;
+
+ if (!py_to_PRINTER_INFO_3(ctr.printers_3, info,
+ hnd->mem_ctx)) {
+ PyErr_SetString(spoolss_error,
+ "error converting to printer info 3");
+ return NULL;
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setprinter(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ level, &ctr, 0);
+
+ /* Return value */
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Enumerate printers */
+
+PyObject *spoolss_enumprinters(PyObject *self, PyObject *args, PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ PRINTER_INFO_CTR ctr;
+ int level = 1, flags = PRINTER_ENUM_LOCAL, i;
+ uint32 needed, num_printers;
+ static char *kwlist[] = {"server", "name", "level", "flags",
+ "creds", NULL};
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_state *cli = NULL;
+ char *server, *errstr, *name = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|siiO", kwlist, &server, &name, &level,
+ &flags, &creds))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ /* This RPC is weird. By setting the server name to different
+ values we can get different behaviour. If however the server
+ name is not specified, we default it to being the full server
+ name as this is probably what the caller intended. To pass a
+ NULL name, pass a value of "" */
+
+ if (!name)
+ name = server;
+ else {
+ if (!name[0])
+ name = NULL;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enum_printers(
+ cli, mem_ctx, 0, &needed, name, flags, level,
+ &num_printers, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enum_printers(
+ cli, mem_ctx, needed, NULL, name, flags,
+ level, &num_printers, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 0:
+ result = PyDict_New();
+
+ for (i = 0; i < num_printers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.printers_0[i].printername.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PRINTER_INFO_0(&value, &ctr.printers_0[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(0));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 1:
+ result = PyDict_New();
+
+ for(i = 0; i < num_printers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.printers_1[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PRINTER_INFO_1(&value, &ctr.printers_1[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(1));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 2:
+ result = PyDict_New();
+
+ for(i = 0; i < num_printers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.printers_2[i].printername.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PRINTER_INFO_2(&value, &ctr.printers_2[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(2));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Add a printer */
+
+PyObject *spoolss_addprinterex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "server", "printername", "info", "creds",
+ NULL};
+ char *printername, *server, *errstr;
+ PyObject *info, *result = NULL, *creds = NULL;
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_2 info2;
+ WERROR werror;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "ssO!|O!", kwlist, &server, &printername,
+ &PyDict_Type, &info, &PyDict_Type, &creds))
+ return NULL;
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ if (!py_to_PRINTER_INFO_2(&info2, info, mem_ctx)) {
+ PyErr_SetString(spoolss_error,
+ "error converting to printer info 2");
+ goto done;
+ }
+
+ ctr.printers_2 = &info2;
+
+ werror = cli_spoolss_addprinterex(cli, mem_ctx, 2, &ctr);
+
+ Py_INCREF(Py_None);
+ result = Py_None;
+
+done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
diff --git a/source3/python/py_spoolss_printers_conv.c b/source3/python/py_spoolss_printers_conv.c
new file mode 100644
index 0000000000..9bef118f2b
--- /dev/null
+++ b/source3/python/py_spoolss_printers_conv.c
@@ -0,0 +1,306 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+struct pyconv py_PRINTER_INFO_0[] = {
+ { "name", PY_UNISTR, offsetof(PRINTER_INFO_0, printername) },
+ { "server_name", PY_UNISTR, offsetof(PRINTER_INFO_0, servername) },
+
+ { "cjobs", PY_UINT32, offsetof(PRINTER_INFO_0, cjobs) },
+ { "total_jobs", PY_UINT32, offsetof(PRINTER_INFO_0, total_jobs) },
+ { "total_bytes", PY_UINT32, offsetof(PRINTER_INFO_0, total_bytes) },
+
+ { "year", PY_UINT16, offsetof(PRINTER_INFO_0, year) },
+ { "month", PY_UINT16, offsetof(PRINTER_INFO_0, month) },
+ { "day_of_week", PY_UINT16, offsetof(PRINTER_INFO_0, dayofweek) },
+ { "day", PY_UINT16, offsetof(PRINTER_INFO_0, day) },
+ { "hour", PY_UINT16, offsetof(PRINTER_INFO_0, hour) },
+ { "minute", PY_UINT16, offsetof(PRINTER_INFO_0, minute) },
+ { "second", PY_UINT16, offsetof(PRINTER_INFO_0, second) },
+ { "milliseconds", PY_UINT16, offsetof(PRINTER_INFO_0, milliseconds) },
+
+ { "global_counter", PY_UINT32, offsetof(PRINTER_INFO_0, global_counter) },
+ { "total_pages", PY_UINT32, offsetof(PRINTER_INFO_0, total_pages) },
+
+ { "major_version", PY_UINT16, offsetof(PRINTER_INFO_0, major_version) },
+ { "build_version", PY_UINT16, offsetof(PRINTER_INFO_0, build_version) },
+
+ { "unknown7", PY_UINT32, offsetof(PRINTER_INFO_0, unknown7) },
+ { "unknown8", PY_UINT32, offsetof(PRINTER_INFO_0, unknown8) },
+ { "unknown9", PY_UINT32, offsetof(PRINTER_INFO_0, unknown9) },
+ { "session_counter", PY_UINT32, offsetof(PRINTER_INFO_0, session_counter)},
+ { "unknown11", PY_UINT32, offsetof(PRINTER_INFO_0, unknown11) },
+ { "printer_errors", PY_UINT32, offsetof(PRINTER_INFO_0, printer_errors) },
+ { "unknown13", PY_UINT32, offsetof(PRINTER_INFO_0, unknown13) },
+ { "unknown14", PY_UINT32, offsetof(PRINTER_INFO_0, unknown14) },
+ { "unknown15", PY_UINT32, offsetof(PRINTER_INFO_0, unknown15) },
+ { "unknown16", PY_UINT32, offsetof(PRINTER_INFO_0, unknown16) },
+ { "change_id", PY_UINT32, offsetof(PRINTER_INFO_0, change_id) },
+ { "unknown18", PY_UINT32, offsetof(PRINTER_INFO_0, unknown18) },
+ { "status", PY_UINT32, offsetof(PRINTER_INFO_0, status) },
+ { "unknown20", PY_UINT32, offsetof(PRINTER_INFO_0, unknown20) },
+ { "c_setprinter", PY_UINT32, offsetof(PRINTER_INFO_0, c_setprinter) },
+ { "unknown22", PY_UINT32, offsetof(PRINTER_INFO_0, unknown22) },
+ { "unknown23", PY_UINT32, offsetof(PRINTER_INFO_0, unknown23) },
+ { "unknown24", PY_UINT32, offsetof(PRINTER_INFO_0, unknown24) },
+ { "unknown25", PY_UINT32, offsetof(PRINTER_INFO_0, unknown25) },
+ { "unknown26", PY_UINT32, offsetof(PRINTER_INFO_0, unknown26) },
+ { "unknown27", PY_UINT32, offsetof(PRINTER_INFO_0, unknown27) },
+ { "unknown28", PY_UINT32, offsetof(PRINTER_INFO_0, unknown28) },
+ { "unknown29", PY_UINT32, offsetof(PRINTER_INFO_0, unknown29) },
+
+ { NULL }
+};
+
+struct pyconv py_PRINTER_INFO_1[] = {
+ { "name", PY_UNISTR, offsetof(PRINTER_INFO_1, name) },
+ { "description", PY_UNISTR, offsetof(PRINTER_INFO_1, description) },
+ { "comment", PY_UNISTR, offsetof(PRINTER_INFO_1, comment) },
+ { "flags", PY_UINT32, offsetof(PRINTER_INFO_1, flags) },
+ { NULL }
+};
+
+struct pyconv py_PRINTER_INFO_2[] = {
+ { "server_name", PY_UNISTR, offsetof(PRINTER_INFO_2, servername) },
+ { "name", PY_UNISTR, offsetof(PRINTER_INFO_2, printername) },
+ { "share_name", PY_UNISTR, offsetof(PRINTER_INFO_2, sharename) },
+ { "port_name", PY_UNISTR, offsetof(PRINTER_INFO_2, portname) },
+ { "driver_name", PY_UNISTR, offsetof(PRINTER_INFO_2, drivername) },
+ { "comment", PY_UNISTR, offsetof(PRINTER_INFO_2, comment) },
+ { "location", PY_UNISTR, offsetof(PRINTER_INFO_2, location) },
+ { "datatype", PY_UNISTR, offsetof(PRINTER_INFO_2, datatype) },
+ { "sepfile", PY_UNISTR, offsetof(PRINTER_INFO_2, sepfile) },
+ { "print_processor", PY_UNISTR, offsetof(PRINTER_INFO_2, printprocessor) },
+ { "parameters", PY_UNISTR, offsetof(PRINTER_INFO_2, parameters) },
+ { "attributes", PY_UINT32, offsetof(PRINTER_INFO_2, attributes) },
+ { "default_priority", PY_UINT32, offsetof(PRINTER_INFO_2, defaultpriority) },
+ { "priority", PY_UINT32, offsetof(PRINTER_INFO_2, priority) },
+ { "start_time", PY_UINT32, offsetof(PRINTER_INFO_2, starttime) },
+ { "until_time", PY_UINT32, offsetof(PRINTER_INFO_2, untiltime) },
+ { "status", PY_UINT32, offsetof(PRINTER_INFO_2, status) },
+ { "cjobs", PY_UINT32, offsetof(PRINTER_INFO_2, cjobs) },
+ { "average_ppm", PY_UINT32, offsetof(PRINTER_INFO_2, averageppm) },
+ { NULL }
+};
+
+struct pyconv py_PRINTER_INFO_3[] = {
+ { "flags", PY_UINT32, offsetof(PRINTER_INFO_3, flags) },
+ { NULL }
+};
+
+struct pyconv py_DEVICEMODE[] = {
+ { "device_name", PY_UNISTR, offsetof(DEVICEMODE, devicename) },
+ { "spec_version", PY_UINT16, offsetof(DEVICEMODE, specversion) },
+ { "driver_version", PY_UINT16, offsetof(DEVICEMODE, driverversion) },
+ { "size", PY_UINT16, offsetof(DEVICEMODE, size) },
+ { "fields", PY_UINT16, offsetof(DEVICEMODE, fields) },
+ { "orientation", PY_UINT16, offsetof(DEVICEMODE, orientation) },
+ { "paper_size", PY_UINT16, offsetof(DEVICEMODE, papersize) },
+ { "paper_width", PY_UINT16, offsetof(DEVICEMODE, paperwidth) },
+ { "paper_length", PY_UINT16, offsetof(DEVICEMODE, paperlength) },
+ { "scale", PY_UINT16, offsetof(DEVICEMODE, scale) },
+ { "copies", PY_UINT16, offsetof(DEVICEMODE, copies) },
+ { "default_source", PY_UINT16, offsetof(DEVICEMODE, defaultsource) },
+ { "print_quality", PY_UINT16, offsetof(DEVICEMODE, printquality) },
+ { "color", PY_UINT16, offsetof(DEVICEMODE, color) },
+ { "duplex", PY_UINT16, offsetof(DEVICEMODE, duplex) },
+ { "y_resolution", PY_UINT16, offsetof(DEVICEMODE, yresolution) },
+ { "tt_option", PY_UINT16, offsetof(DEVICEMODE, ttoption) },
+ { "collate", PY_UINT16, offsetof(DEVICEMODE, collate) },
+ { "form_name", PY_UNISTR, offsetof(DEVICEMODE, formname) },
+ { "log_pixels", PY_UINT16, offsetof(DEVICEMODE, logpixels) },
+ { "bits_per_pel", PY_UINT32, offsetof(DEVICEMODE, bitsperpel) },
+ { "pels_width", PY_UINT32, offsetof(DEVICEMODE, pelswidth) },
+ { "pels_height", PY_UINT32, offsetof(DEVICEMODE, pelsheight) },
+ { "display_flags", PY_UINT32, offsetof(DEVICEMODE, displayflags) },
+ { "display_frequency", PY_UINT32, offsetof(DEVICEMODE, displayfrequency) },
+ { "icm_method", PY_UINT32, offsetof(DEVICEMODE, icmmethod) },
+ { "icm_intent", PY_UINT32, offsetof(DEVICEMODE, icmintent) },
+ { "media_type", PY_UINT32, offsetof(DEVICEMODE, mediatype) },
+ { "dither_type", PY_UINT32, offsetof(DEVICEMODE, dithertype) },
+ { "reserved1", PY_UINT32, offsetof(DEVICEMODE, reserved1) },
+ { "reserved2", PY_UINT32, offsetof(DEVICEMODE, reserved2) },
+ { "panning_width", PY_UINT32, offsetof(DEVICEMODE, panningwidth) },
+ { "panning_height", PY_UINT32, offsetof(DEVICEMODE, panningheight) },
+ { NULL }
+};
+
+/*
+ * Convert between DEVICEMODE and Python
+ */
+
+BOOL py_from_DEVICEMODE(PyObject **dict, DEVICEMODE *devmode)
+{
+ *dict = from_struct(devmode, py_DEVICEMODE);
+
+ PyDict_SetItemString(*dict, "private",
+ PyString_FromStringAndSize(
+ devmode->private, devmode->driverextra));
+
+ return True;
+}
+
+BOOL py_to_DEVICEMODE(DEVICEMODE *devmode, PyObject *dict)
+{
+ PyObject *obj;
+
+ if (!to_struct(devmode, dict, py_DEVICEMODE))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "private")))
+ return False;
+
+ devmode->private = PyString_AsString(obj);
+ devmode->driverextra = PyString_Size(obj);
+
+ return True;
+}
+
+/*
+ * Convert between PRINTER_INFO_0 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_0(PyObject **dict, PRINTER_INFO_0 *info)
+{
+ *dict = from_struct(info, py_PRINTER_INFO_0);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(0));
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_0(PRINTER_INFO_0 *info, PyObject *dict)
+{
+ return False;
+}
+
+/*
+ * Convert between PRINTER_INFO_1 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_1(PyObject **dict, PRINTER_INFO_1 *info)
+{
+ *dict = from_struct(info, py_PRINTER_INFO_1);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_1(PRINTER_INFO_1 *info, PyObject *dict)
+{
+ PyObject *dict_copy = PyDict_Copy(dict);
+ BOOL result;
+
+ PyDict_DelItemString(dict_copy, "level");
+ result = to_struct(info, dict_copy, py_PRINTER_INFO_1);
+
+ Py_DECREF(dict_copy);
+ return result;
+}
+
+/*
+ * Convert between PRINTER_INFO_2 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_2(PyObject **dict, PRINTER_INFO_2 *info)
+{
+ PyObject *obj;
+
+ *dict = from_struct(info, py_PRINTER_INFO_2);
+
+ /* The security descriptor could be NULL */
+
+ if (info->secdesc) {
+ if (py_from_SECDESC(&obj, info->secdesc))
+ PyDict_SetItemString(*dict, "security_descriptor", obj);
+ }
+
+ /* Bong! The devmode could be NULL */
+
+ if (info->devmode)
+ py_from_DEVICEMODE(&obj, info->devmode);
+ else
+ obj = PyDict_New();
+
+ PyDict_SetItemString(*dict, "device_mode", obj);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(2));
+
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_2(PRINTER_INFO_2 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx)
+{
+ PyObject *obj;
+
+ if (!to_struct(info, dict, py_PRINTER_INFO_2))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "security_descriptor")))
+ return False;
+
+ if (!py_to_SECDESC(&info->secdesc, obj, mem_ctx))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "device_mode")))
+ return False;
+
+ info->devmode = talloc(mem_ctx, sizeof(DEVICEMODE));
+
+ if (!py_to_DEVICEMODE(info->devmode, obj))
+ return False;
+
+ return True;
+}
+
+/*
+ * Convert between PRINTER_INFO_1 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_3(PyObject **dict, PRINTER_INFO_3 *info)
+{
+ PyObject *obj;
+
+ *dict = from_struct(info, py_PRINTER_INFO_3);
+
+ if (py_from_SECDESC(&obj, info->secdesc))
+ PyDict_SetItemString(*dict, "security_descriptor", obj);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(3));
+
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_3(PRINTER_INFO_3 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx)
+{
+ PyObject *obj;
+
+ if (!to_struct(info, dict, py_PRINTER_INFO_3))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "security_descriptor")))
+ return False;
+
+ if (!py_to_SECDESC(&info->secdesc, obj, mem_ctx))
+ return False;
+
+ return True;
+}
diff --git a/source3/python/py_spoolss_proto.h b/source3/python/py_spoolss_proto.h
new file mode 100644
index 0000000000..b5c6a3239e
--- /dev/null
+++ b/source3/python/py_spoolss_proto.h
@@ -0,0 +1,123 @@
+#ifndef _PY_SPOOLSS_PROTO_H
+#define _PY_SPOOLSS_PROTO_H
+
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/* The following definitions come from python/py_spoolss.c */
+
+PyObject *new_spoolss_policy_hnd_object(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, POLICY_HND *pol);
+void initspoolss(void);
+
+/* The following definitions come from python/py_spoolss_drivers.c */
+
+PyObject *spoolss_enumprinterdrivers(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_hnd_getprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_getprinterdriverdir(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_addprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_addprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_deleteprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_deleteprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_drivers_conv.c */
+
+BOOL py_from_DRIVER_INFO_1(PyObject **dict, DRIVER_INFO_1 *info);
+BOOL py_to_DRIVER_INFO_1(DRIVER_INFO_1 *info, PyObject *dict);
+BOOL py_from_DRIVER_INFO_2(PyObject **dict, DRIVER_INFO_2 *info);
+BOOL py_to_DRIVER_INFO_2(DRIVER_INFO_2 *info, PyObject *dict);
+BOOL py_from_DRIVER_INFO_3(PyObject **dict, DRIVER_INFO_3 *info);
+BOOL py_to_DRIVER_INFO_3(DRIVER_INFO_3 *info, PyObject *dict);
+BOOL py_from_DRIVER_INFO_6(PyObject **dict, DRIVER_INFO_6 *info);
+BOOL py_to_DRIVER_INFO_6(DRIVER_INFO_6 *info, PyObject *dict);
+BOOL py_from_DRIVER_DIRECTORY_1(PyObject **dict, DRIVER_DIRECTORY_1 *info);
+BOOL py_to_DRIVER_DIRECTORY_1(DRIVER_DIRECTORY_1 *info, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_forms.c */
+
+PyObject *spoolss_hnd_addform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_getform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_deleteform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumforms(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_forms_conv.c */
+
+BOOL py_from_FORM_1(PyObject **dict, FORM_1 *form);
+BOOL py_to_FORM(FORM *form, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_jobs.c */
+
+PyObject *spoolss_hnd_enumjobs(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setjob(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_getjob(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_startpageprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_endpageprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_startdocprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enddocprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_writeprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_addjob(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_jobs_conv.c */
+
+BOOL py_from_JOB_INFO_1(PyObject **dict, JOB_INFO_1 *info);
+BOOL py_to_JOB_INFO_1(JOB_INFO_1 *info, PyObject *dict);
+BOOL py_from_JOB_INFO_2(PyObject **dict, JOB_INFO_2 *info);
+BOOL py_to_JOB_INFO_2(JOB_INFO_2 *info, PyObject *dict);
+BOOL py_from_DOC_INFO_1(PyObject **dict, DOC_INFO_1 *info);
+BOOL py_to_DOC_INFO_1(DOC_INFO_1 *info, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_ports.c */
+
+PyObject *spoolss_enumports(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_ports_conv.c */
+
+BOOL py_from_PORT_INFO_1(PyObject **dict, PORT_INFO_1 *info);
+BOOL py_to_PORT_INFO_1(PORT_INFO_1 *info, PyObject *dict);
+BOOL py_from_PORT_INFO_2(PyObject **dict, PORT_INFO_2 *info);
+BOOL py_to_PORT_INFO_2(PORT_INFO_2 *info, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_printerdata.c */
+
+PyObject *spoolss_hnd_getprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_deleteprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_getprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_deleteprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_printers.c */
+
+PyObject *spoolss_openprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_closeprinter(PyObject *self, PyObject *args);
+PyObject *spoolss_hnd_getprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_enumprinters(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_addprinterex(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_printers_conv.c */
+
+BOOL py_from_DEVICEMODE(PyObject **dict, DEVICEMODE *devmode);
+BOOL py_to_DEVICEMODE(DEVICEMODE *devmode, PyObject *dict);
+BOOL py_from_PRINTER_INFO_0(PyObject **dict, PRINTER_INFO_0 *info);
+BOOL py_to_PRINTER_INFO_0(PRINTER_INFO_0 *info, PyObject *dict);
+BOOL py_from_PRINTER_INFO_1(PyObject **dict, PRINTER_INFO_1 *info);
+BOOL py_to_PRINTER_INFO_1(PRINTER_INFO_1 *info, PyObject *dict);
+BOOL py_from_PRINTER_INFO_2(PyObject **dict, PRINTER_INFO_2 *info);
+BOOL py_to_PRINTER_INFO_2(PRINTER_INFO_2 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx);
+BOOL py_from_PRINTER_INFO_3(PyObject **dict, PRINTER_INFO_3 *info);
+BOOL py_to_PRINTER_INFO_3(PRINTER_INFO_3 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx);
+
+#endif /* _PY_SPOOLSS_PROTO_H */
diff --git a/source3/python/py_tdbpack.c b/source3/python/py_tdbpack.c
new file mode 100644
index 0000000000..e5044943be
--- /dev/null
+++ b/source3/python/py_tdbpack.c
@@ -0,0 +1,662 @@
+/* -*- c-file-style: "python"; indent-tabs-mode: nil; -*-
+
+ Python wrapper for Samba tdb pack/unpack functions
+ Copyright (C) Martin Pool 2002
+
+
+ NOTE PYTHON STYLE GUIDE
+ http://www.python.org/peps/pep-0007.html
+
+
+ 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 "Python.h"
+
+static int pytdbpack_calc_reqd_len(char *format_str,
+ PyObject *val_seq);
+
+static PyObject *pytdbpack_unpack_item(char,
+ char **pbuf,
+ int *plen);
+static int
+pytdbpack_calc_item_len(char format_ch,
+ PyObject *val_obj);
+
+static PyObject *pytdbpack_pack_data(const char *format_str,
+ PyObject *val_seq,
+ unsigned char *buf);
+
+
+
+static const char * pytdbpack_docstring =
+"Convert between Python values and Samba binary encodings.
+
+This module is conceptually similar to the standard 'struct' module, but it
+uses both a different binary format and a different description string.
+
+Samba's encoding is based on that used inside DCE-RPC and SMB: a
+little-endian, unpadded, non-self-describing binary format. It is intended
+that these functions be as similar as possible to the routines in Samba's
+tdb/tdbutil module, with appropriate adjustments for Python datatypes.
+
+Python strings are used to specify the format of data to be packed or
+unpacked.
+
+Strings in TDBs are typically stored in DOS codepages. The caller of this
+module must make appropriate translations if necessary, typically to and from
+Unicode objects.
+
+tdbpack format strings:
+
+ 'f': NULL-terminated string in DOS codepage
+
+ 'P': same as 'f'
+
+ 'd': 4 byte little-endian number
+
+ 'w': 2 byte little-endian number
+
+ 'P': \"Pointer\" value -- in the subset of DCERPC used by Samba, this is
+ really just an \"exists\" or \"does not exist\" flag. The boolean
+ value of the Python object is used.
+
+ 'B': 4-byte LE length, followed by that many bytes of binary data.
+ Corresponds to a Python byte string of the appropriate length.
+
+ '$': Special flag indicating that the preceding format code should be
+ repeated while data remains. This is only supported for unpacking.
+
+ Every code corresponds to a single Python object, except 'B' which
+ corresponds to two values (length and contents), and '$', which produces
+ however many make sense.
+";
+
+
+static char const pytdbpack_pack_doc[] =
+"pack(format, values) -> buffer
+Pack Python objects into Samba binary format according to format string.
+
+arguments:
+ format -- string of tdbpack format characters
+ values -- sequence of value objects corresponding 1:1 to format characters
+
+returns:
+ buffer -- string containing packed data
+
+raises:
+ IndexError -- if there are not the same number of format codes as of
+ values
+ ValueError -- if any of the format characters is illegal
+ TypeError -- if the format is not a string, or values is not a sequence,
+ or any of the values is of the wrong type for the corresponding
+ format character
+";
+
+
+static char const pytdbpack_unpack_doc[] =
+"unpack(format, buffer) -> (values, rest)
+Unpack Samba binary data according to format string.
+
+arguments:
+ format -- string of tdbpack characters
+ buffer -- string of packed binary data
+
+returns:
+ 2-tuple of:
+ values -- sequence of values corresponding 1:1 to format characters
+ rest -- string containing data that was not decoded, or '' if the
+ whole string was consumed
+
+raises:
+ IndexError -- if there is insufficient data in the buffer for the
+ format (or if the data is corrupt and contains a variable-length
+ field extending past the end)
+ ValueError -- if any of the format characters is illegal
+
+notes:
+ Because unconsumed data is returned, you can feed it back in to the
+ unpacker to extract further fields. Alternatively, if you wish to modify
+ some fields near the start of the data, you may be able to save time by
+ only unpacking and repacking the necessary part.
+";
+
+
+
+/*
+ Game plan is to first of all walk through the arguments and calculate the
+ total length that will be required. We allocate a Python string of that
+ size, then walk through again and fill it in.
+
+ We just borrow references to all the passed arguments, since none of them
+ need to be permanently stored. We transfer ownership to the returned
+ object.
+ */
+static PyObject *
+pytdbpack_pack(PyObject *self,
+ PyObject *args)
+{
+ char *format_str;
+ PyObject *val_seq, *fast_seq, *buf_str;
+ int reqd_len;
+ char *packed_buf;
+
+ /* TODO: Test passing wrong types or too many arguments */
+ if (!PyArg_ParseTuple(args, "sO", &format_str, &val_seq))
+ return NULL;
+
+ /* Convert into a list or tuple (if not already one), so that we can
+ * index more easily. */
+ fast_seq = PySequence_Fast(val_seq,
+ __FUNCTION__ ": argument 2 must be sequence");
+ if (!fast_seq)
+ return NULL;
+
+ reqd_len = pytdbpack_calc_reqd_len(format_str, fast_seq);
+ if (reqd_len == -1) /* exception was thrown */
+ return NULL;
+
+ /* Allocate space.
+
+ This design causes an unnecessary copying of the data when Python
+ constructs an object, and that might possibly be avoided by using a
+ Buffer object of some kind instead. I'm not doing that for now
+ though. */
+ packed_buf = malloc(reqd_len);
+ if (!packed_buf) {
+ PyErr_Format(PyExc_MemoryError,
+ "%s: couldn't allocate %d bytes for packed buffer",
+ __FUNCTION__, reqd_len);
+ return NULL;
+ }
+
+ if (!pytdbpack_pack_data(format_str, fast_seq, packed_buf)) {
+ free(packed_buf);
+ return NULL;
+ }
+
+ buf_str = PyString_FromStringAndSize(packed_buf, reqd_len);
+ free(packed_buf); /* get rid of tmp buf */
+
+ return buf_str;
+}
+
+
+
+static PyObject *
+pytdbpack_unpack(PyObject *self,
+ PyObject *args)
+{
+ char *format_str, *packed_str, *ppacked;
+ PyObject *val_list = NULL, *ret_tuple = NULL;
+ PyObject *rest_string = NULL;
+ int format_len, packed_len;
+ int i;
+ char last_format = '#';
+
+ /* get arguments */
+ if (!PyArg_ParseTuple(args, "ss#", &format_str, &packed_str, &packed_len))
+ return NULL;
+
+ format_len = strlen(format_str);
+
+ /* allocate list to hold results */
+ val_list = PyList_New(format_len);
+ if (!val_list)
+ goto failed;
+ ret_tuple = PyTuple_New(2);
+ if (!ret_tuple)
+ goto failed;
+
+ /* For every object, unpack. */
+ for (ppacked = packed_str, i = 0; i < format_len; i++) {
+ PyObject *val_obj;
+ char format;
+
+ format = format_str[i];
+ if (format == '$') {
+ if (i == 0) {
+ PyErr_Format(PyExc_ValueError,
+ "%s: '$' may not be first character in format",
+ __FUNCTION__);
+ goto failed;
+ }
+ else {
+ format = last_format; /* repeat */
+ }
+ }
+
+ val_obj = pytdbpack_unpack_item(format,
+ &ppacked,
+ &packed_len);
+ if (!val_obj)
+ goto failed;
+
+ PyList_SET_ITEM(val_list, i, val_obj);
+ last_format = format;
+ }
+
+ /* put leftovers in box for lunch tomorrow */
+ rest_string = PyString_FromStringAndSize(ppacked, packed_len);
+ if (!rest_string)
+ goto failed;
+
+ /* return (values, rest) tuple; give up references to them */
+ PyTuple_SET_ITEM(ret_tuple, 0, val_list);
+ val_list = NULL;
+ PyTuple_SET_ITEM(ret_tuple, 1, rest_string);
+ val_list = NULL;
+ return ret_tuple;
+
+ failed:
+ /* handle failure: deallocate anything */
+ Py_XDECREF(val_list);
+ Py_XDECREF(ret_tuple);
+ Py_XDECREF(rest_string);
+ return NULL;
+}
+
+
+/*
+ Internal routine that calculates how many bytes will be required to
+ encode the values in the format.
+
+ Also checks that the value list is the right size for the format list.
+
+ Returns number of bytes (may be 0), or -1 if there's something wrong, in
+ which case a Python exception has been raised.
+
+ Arguments:
+
+ val_seq: a Fast Sequence (list or tuple), being all the values
+*/
+static int
+pytdbpack_calc_reqd_len(char *format_str,
+ PyObject *val_seq)
+{
+ int len = 0;
+ char *p;
+ int val_i;
+ int val_len;
+
+ val_len = PySequence_Fast_GET_SIZE(val_seq);
+
+ for (p = format_str, val_i = 0; *p; p++, val_i++) {
+ char ch = *p;
+ PyObject *val_obj;
+ int item_len;
+
+ if (val_i >= val_len) {
+ PyErr_Format(PyExc_IndexError,
+ "samba.tdbpack.pack: value list is too short for format string");
+ return -1;
+ }
+
+ /* borrow a reference to the item */
+ val_obj = PySequence_Fast_GET_ITEM(val_seq, val_i);
+ if (!val_obj)
+ return -1;
+
+ item_len = pytdbpack_calc_item_len(ch, val_obj);
+ if (item_len == -1)
+ return -1;
+ else
+ len += item_len;
+ }
+
+ if (val_i != val_len) {
+ PyErr_Format(PyExc_IndexError,
+ "%s: value list is wrong length for format string",
+ __FUNCTION__);
+ return -1;
+ }
+
+ return len;
+}
+
+
+/*
+ Calculate the number of bytes required to pack a single value.
+*/
+static int
+pytdbpack_calc_item_len(char ch,
+ PyObject *val_obj)
+{
+ if (ch == 'd' || ch == 'w') {
+ if (!PyInt_Check(val_obj)) {
+ PyErr_Format(PyExc_TypeError,
+ "tdbpack: format '%c' requires an Int",
+ ch);
+ return -1;
+ }
+ if (ch == 'w')
+ return 2;
+ else
+ return 4;
+ } else if (ch == 'p') {
+ return 4;
+ }
+ else if (ch == 'f' || ch == 'P' || ch == 'B') {
+ /* nul-terminated 8-bit string */
+ if (!PyString_Check(val_obj)) {
+ PyErr_Format(PyExc_TypeError,
+ "tdbpack: format '%c' requires a String",
+ ch);
+ return -1;
+ }
+
+ if (ch == 'B') {
+ /* byte buffer; just use Python string's length, plus
+ a preceding word */
+ return 4 + PyString_GET_SIZE(val_obj);
+ }
+ else {
+ /* one nul character */
+ return 1 + PyString_GET_SIZE(val_obj);
+ }
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ __FUNCTION__ ": format character '%c' is not supported",
+ ch);
+
+ return -1;
+ }
+}
+
+
+/*
+ XXX: glib and Samba have quicker macro for doing the endianness conversions,
+ but I don't know of one in plain libc, and it's probably not a big deal. I
+ realize this is kind of dumb because we'll almost always be on x86, but
+ being safe is important.
+*/
+static void pack_int32(unsigned long val_long, unsigned char **pbuf)
+{
+ (*pbuf)[0] = val_long & 0xff;
+ (*pbuf)[1] = (val_long >> 8) & 0xff;
+ (*pbuf)[2] = (val_long >> 16) & 0xff;
+ (*pbuf)[3] = (val_long >> 24) & 0xff;
+ (*pbuf) += 4;
+}
+
+
+static void pack_bytes(long len, const char *from,
+ unsigned char **pbuf)
+{
+ memcpy(*pbuf, from, len);
+ (*pbuf) += len;
+}
+
+
+static void
+unpack_err_too_short(void)
+{
+ PyErr_Format(PyExc_IndexError,
+ __FUNCTION__ ": data too short for unpack format");
+}
+
+
+static PyObject *
+unpack_int32(char **pbuf, int *plen)
+{
+ long v;
+ unsigned char *b;
+
+ if (*plen < 4) {
+ unpack_err_too_short();
+ return NULL;
+ }
+
+ b = *pbuf;
+ v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
+
+ (*pbuf) += 4;
+ (*plen) -= 4;
+
+ return PyInt_FromLong(v);
+}
+
+
+static PyObject *unpack_int16(char **pbuf, int *plen)
+{
+ long v;
+ unsigned char *b;
+
+ if (*plen < 2) {
+ unpack_err_too_short();
+ return NULL;
+ }
+
+ b = *pbuf;
+ v = b[0] | b[1]<<8;
+
+ (*pbuf) += 2;
+ (*plen) -= 2;
+
+ return PyInt_FromLong(v);
+}
+
+
+static PyObject *
+unpack_string(char **pbuf, int *plen)
+{
+ int len;
+ char *nul_ptr, *start;
+
+ start = *pbuf;
+
+ nul_ptr = memchr(start, '\0', *plen);
+ if (!nul_ptr) {
+ unpack_err_too_short();
+ return NULL;
+ }
+
+ len = nul_ptr - start;
+
+ *pbuf += len + 1; /* skip \0 */
+ *plen -= len + 1;
+
+ return PyString_FromStringAndSize(start, len);
+}
+
+
+static PyObject *
+unpack_buffer(char **pbuf, int *plen)
+{
+ /* first get 32-bit len */
+ long slen;
+ unsigned char *b;
+ unsigned char *start;
+
+ if (*plen < 4) {
+ unpack_err_too_short();
+ return NULL;
+ }
+
+ b = *pbuf;
+ slen = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
+
+ if (slen < 0) { /* surely you jest */
+ PyErr_Format(PyExc_ValueError,
+ __FUNCTION__ ": buffer seems to have negative length");
+ return NULL;
+ }
+
+ (*pbuf) += 4;
+ (*plen) -= 4;
+ start = *pbuf;
+
+ if (*plen < slen) {
+ PyErr_Format(PyExc_IndexError,
+ __FUNCTION__ ": not enough data to unpack buffer: "
+ "need %d bytes, have %d",
+ (int) slen, *plen);
+ return NULL;
+ }
+
+ (*pbuf) += slen;
+ (*plen) -= slen;
+
+ return PyString_FromStringAndSize(start, slen);
+}
+
+
+/* Unpack a single field from packed data, according to format character CH.
+ Remaining data is at *PBUF, of *PLEN.
+
+ *PBUF is advanced, and *PLEN reduced to reflect the amount of data that has
+ been consumed.
+
+ Returns a reference to the unpacked Python object, or NULL for failure.
+*/
+static PyObject *pytdbpack_unpack_item(char ch,
+ char **pbuf,
+ int *plen)
+{
+ if (ch == 'w') { /* 16-bit int */
+ return unpack_int16(pbuf, plen);
+ }
+ else if (ch == 'd' || ch == 'p') { /* 32-bit int */
+ /* pointers can just come through as integers */
+ return unpack_int32(pbuf, plen);
+ }
+ else if (ch == 'f' || ch == 'P') { /* nul-term string */
+ return unpack_string(pbuf, plen);
+ }
+ else if (ch == 'B') { /* length, buffer */
+ return unpack_buffer(pbuf, plen);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ __FUNCTION__ ": format character '%c' is not supported",
+ ch);
+
+ return NULL;
+ }
+}
+
+
+
+/*
+ Pack a single item VAL_OBJ, encoded using format CH, into a buffer at *PBUF,
+ and advance the pointer. Buffer length has been pre-calculated so we are
+ sure that there is enough space.
+
+*/
+static PyObject *
+pytdbpack_pack_item(char ch,
+ PyObject *val_obj,
+ unsigned char **pbuf)
+{
+ if (ch == 'w') {
+ unsigned long val_long = PyInt_AsLong(val_obj);
+ (*pbuf)[0] = val_long & 0xff;
+ (*pbuf)[1] = (val_long >> 8) & 0xff;
+ (*pbuf) += 2;
+ }
+ else if (ch == 'd') {
+ /* 4-byte LE number */
+ pack_int32(PyInt_AsLong(val_obj), pbuf);
+ }
+ else if (ch == 'p') {
+ /* "Pointer" value -- in the subset of DCERPC used by Samba,
+ this is really just an "exists" or "does not exist"
+ flag. */
+ pack_int32(PyObject_IsTrue(val_obj), pbuf);
+ }
+ else if (ch == 'f' || ch == 'P') {
+ int size;
+ char *sval;
+
+ size = PyString_GET_SIZE(val_obj);
+ sval = PyString_AS_STRING(val_obj);
+ pack_bytes(size+1, sval, pbuf); /* include nul */
+ }
+ else if (ch == 'B') {
+ int size;
+ char *sval;
+
+ size = PyString_GET_SIZE(val_obj);
+ pack_int32(size, pbuf);
+ sval = PyString_AS_STRING(val_obj);
+ pack_bytes(size, sval, pbuf); /* do not include nul */
+ }
+ else {
+ /* this ought to be caught while calculating the length, but
+ just in case. */
+ PyErr_Format(PyExc_ValueError,
+ "%s: format character '%c' is not supported",
+ __FUNCTION__, ch);
+
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+
+/*
+ Pack data according to FORMAT_STR from the elements of VAL_SEQ into
+ PACKED_BUF.
+
+ The string has already been checked out, so we know that VAL_SEQ is large
+ enough to hold the packed data, and that there are enough value items.
+ (However, their types may not have been thoroughly checked yet.)
+
+ In addition, val_seq is a Python Fast sequence.
+
+ Returns NULL for error (with exception set), or None.
+*/
+PyObject *
+pytdbpack_pack_data(const char *format_str,
+ PyObject *val_seq,
+ unsigned char *packed_buf)
+{
+ int i;
+
+ for (i = 0; format_str[i]; i++) {
+ char ch = format_str[i];
+ PyObject *val_obj;
+
+ /* borrow a reference to the item */
+ val_obj = PySequence_Fast_GET_ITEM(val_seq, i);
+ if (!val_obj)
+ return NULL;
+
+ if (!pytdbpack_pack_item(ch, val_obj, &packed_buf))
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+
+
+
+
+static PyMethodDef pytdbpack_methods[] = {
+ { "pack", pytdbpack_pack, METH_VARARGS, (char *) pytdbpack_pack_doc },
+ { "unpack", pytdbpack_unpack, METH_VARARGS, (char *) pytdbpack_unpack_doc },
+};
+
+DL_EXPORT(void)
+inittdbpack(void)
+{
+ Py_InitModule3("tdbpack", pytdbpack_methods,
+ (char *) pytdbpack_docstring);
+}
diff --git a/source3/python/py_winbind.c b/source3/python/py_winbind.c
new file mode 100644
index 0000000000..ef6bc06233
--- /dev/null
+++ b/source3/python/py_winbind.c
@@ -0,0 +1,716 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python wrapper for winbind client functions.
+
+ Copyright (C) Tim Potter 2002
+
+ 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 "includes.h"
+#include "Python.h"
+
+#include "py_common_proto.h"
+
+/*
+ * Exceptions raised by this module
+ */
+
+PyObject *winbind_error; /* A winbind call returned WINBINDD_ERROR */
+
+/* Prototypes from common.h */
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+/*
+ * Name <-> SID conversion
+ */
+
+/* Convert a name to a sid */
+
+static PyObject *py_name_to_sid(PyObject *self, PyObject *args)
+
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ PyObject *result;
+ char *name, *p, *sep;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sep = lp_winbind_separator();
+
+ if ((p = strchr(name, sep[0]))) {
+ *p = 0;
+ fstrcpy(request.data.name.dom_name, name);
+ fstrcpy(request.data.name.name, p + 1);
+ } else {
+ fstrcpy(request.data.name.dom_name, lp_workgroup());
+ fstrcpy(request.data.name.name, name);
+ }
+
+ if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyString_FromString(response.data.sid.sid);
+
+ return result;
+}
+
+/* Convert a sid to a name */
+
+static PyObject *py_sid_to_name(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ PyObject *result;
+ char *sid, *name;
+
+ if (!PyArg_ParseTuple(args, "s", &sid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.sid, sid);
+
+ if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ asprintf(&name, "%s%s%s", response.data.name.dom_name,
+ lp_winbind_separator(), response.data.name.name);
+
+ result = PyString_FromString(name);
+
+ free(name);
+
+ return result;
+}
+
+/*
+ * Enumerate users/groups
+ */
+
+/* Enumerate domain users */
+
+static PyObject *py_enum_domain_users(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (response.extra_data) {
+ char *extra_data = response.extra_data;
+ fstring name;
+
+ while (next_token(&extra_data, name, ",", sizeof(fstring)))
+ PyList_Append(result, PyString_FromString(name));
+ }
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+static PyObject *py_enum_domain_groups(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (response.extra_data) {
+ char *extra_data = response.extra_data;
+ fstring name;
+
+ while (next_token(&extra_data, name, ",", sizeof(fstring)))
+ PyList_Append(result, PyString_FromString(name));
+ }
+
+ return result;
+}
+
+/*
+ * Miscellaneous domain related
+ */
+
+/* Enumerate domain groups */
+
+static PyObject *py_enum_trust_dom(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_TRUSTDOM, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (response.extra_data) {
+ char *extra_data = response.extra_data;
+ fstring name;
+
+ while (next_token(&extra_data, name, ",", sizeof(fstring)))
+ PyList_Append(result, PyString_FromString(name));
+ }
+
+ return result;
+}
+
+/* Check machine account password */
+
+static PyObject *py_check_secret(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_CHECK_MACHACC, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.num_entries);
+}
+
+/*
+ * Return a dictionary consisting of all the winbind related smb.conf
+ * parameters. This is stored in the module object.
+ */
+
+static PyObject *py_config_dict(void)
+{
+ PyObject *result;
+ uid_t ulow, uhi;
+ gid_t glow, ghi;
+
+ if (!(result = PyDict_New()))
+ return NULL;
+
+ /* Various string parameters */
+
+ PyDict_SetItemString(result, "workgroup",
+ PyString_FromString(lp_workgroup()));
+
+ PyDict_SetItemString(result, "separator",
+ PyString_FromString(lp_winbind_separator()));
+
+ PyDict_SetItemString(result, "template_homedir",
+ PyString_FromString(lp_template_homedir()));
+
+ PyDict_SetItemString(result, "template_shell",
+ PyString_FromString(lp_template_shell()));
+
+ /* Winbind uid/gid range */
+
+ if (lp_winbind_uid(&ulow, &uhi)) {
+ PyDict_SetItemString(result, "uid_low", PyInt_FromLong(ulow));
+ PyDict_SetItemString(result, "uid_high", PyInt_FromLong(uhi));
+ }
+
+ if (lp_winbind_gid(&glow, &ghi)) {
+ PyDict_SetItemString(result, "gid_low", PyInt_FromLong(glow));
+ PyDict_SetItemString(result, "gid_high", PyInt_FromLong(ghi));
+ }
+
+ return result;
+}
+
+/*
+ * ID mapping
+ */
+
+/* Convert a uid to a SID */
+
+static PyObject *py_uid_to_sid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int id;
+
+ if (!PyArg_ParseTuple(args, "i", &id))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = id;
+
+ if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyString_FromString(response.data.sid.sid);
+}
+
+/* Convert a gid to a SID */
+
+static PyObject *py_gid_to_sid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int id;
+
+ if (!PyArg_ParseTuple(args, "i", &id))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = id;
+
+ if (winbindd_request(WINBINDD_GID_TO_SID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyString_FromString(response.data.sid.sid);
+}
+
+/* Convert a sid to a uid */
+
+static PyObject *py_sid_to_uid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid;
+
+ if (!PyArg_ParseTuple(args, "s", &sid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.sid, sid);
+
+ if (winbindd_request(WINBINDD_SID_TO_UID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.uid);
+}
+
+/* Convert a sid to a gid */
+
+static PyObject *py_sid_to_gid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid;
+
+ if (!PyArg_ParseTuple(args, "s", &sid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.sid, sid);
+
+ if (winbindd_request(WINBINDD_SID_TO_GID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.gid);
+}
+
+/*
+ * PAM authentication functions
+ */
+
+/* Plaintext authentication */
+
+static PyObject *py_auth_plaintext(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *username, *password;
+
+ if (!PyArg_ParseTuple(args, "ss", &username, &password))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.auth.user, username);
+ fstrcpy(request.data.auth.pass, password);
+
+ if (winbindd_request(WINBINDD_PAM_AUTH, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+/* Challenge/response authentication */
+
+static PyObject *py_auth_crap(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *username, *password;
+
+ if (!PyArg_ParseTuple(args, "ss", &username, &password))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.auth_crap.user, username);
+
+ generate_random_buffer(request.data.auth_crap.chal, 8, False);
+
+ SMBencrypt((uchar *)password, request.data.auth_crap.chal,
+ (uchar *)request.data.auth_crap.lm_resp);
+ SMBNTencrypt((uchar *)password, request.data.auth_crap.chal,
+ (uchar *)request.data.auth_crap.nt_resp);
+
+ request.data.auth_crap.lm_resp_len = 24;
+ request.data.auth_crap.nt_resp_len = 24;
+
+ if (winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+/* Get user info from name */
+
+static PyObject *py_getpwnam(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *username;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "s", &username))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.username, username);
+
+ if (winbindd_request(WINBINDD_GETPWNAM, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ if (!py_from_winbind_passwd(&result, &response)) {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+}
+
+/* Get user info from uid */
+
+static PyObject *py_getpwuid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ uid_t uid;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "i", &uid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = uid;
+
+ if (winbindd_request(WINBINDD_GETPWUID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ if (!py_from_winbind_passwd(&result, &response)) {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+}
+
+/*
+ * Method dispatch table
+ */
+
+static PyMethodDef winbind_methods[] = {
+
+ { "getpwnam", py_getpwnam, METH_VARARGS, "getpwnam(3)" },
+ { "getpwuid", py_getpwuid, METH_VARARGS, "getpwuid(3)" },
+
+ /* Name <-> SID conversion */
+
+ { "name_to_sid", py_name_to_sid, METH_VARARGS,
+ "name_to_sid(s) -> string
+
+Return the SID for a name.
+
+Example:
+
+>>> winbind.name_to_sid('FOO/Administrator')
+'S-1-5-21-406022937-1377575209-526660263-500' " },
+
+ { "sid_to_name", py_sid_to_name, METH_VARARGS,
+ "sid_to_name(s) -> string
+
+Return the name for a SID.
+
+Example:
+
+>>> import winbind
+>>> winbind.sid_to_name('S-1-5-21-406022937-1377575209-526660263-500')
+'FOO/Administrator' " },
+
+ /* Enumerate users/groups */
+
+ { "enum_domain_users", py_enum_domain_users, METH_VARARGS,
+ "enum_domain_users() -> list of strings
+
+Return a list of domain users.
+
+Example:
+
+>>> winbind.enum_domain_users()
+['FOO/Administrator', 'FOO/anna', 'FOO/Anne Elk', 'FOO/build',
+'FOO/foo', 'FOO/foo2', 'FOO/foo3', 'FOO/Guest', 'FOO/user1',
+'FOO/whoops-ptang'] " },
+
+ { "enum_domain_groups", py_enum_domain_groups, METH_VARARGS,
+ "enum_domain_groups() -> list of strings
+
+Return a list of domain groups.
+
+Example:
+
+>>> winbind.enum_domain_groups()
+['FOO/cows', 'FOO/Domain Admins', 'FOO/Domain Guests',
+'FOO/Domain Users'] " },
+
+ /* ID mapping */
+
+ { "uid_to_sid", py_uid_to_sid, METH_VARARGS,
+ "uid_to_sid(int) -> string
+
+Return the SID for a UNIX uid.
+
+Example:
+
+>>> winbind.uid_to_sid(10000)
+'S-1-5-21-406022937-1377575209-526660263-500' " },
+
+ { "gid_to_sid", py_gid_to_sid, METH_VARARGS,
+ "gid_to_sid(int) -> string
+
+Return the UNIX gid for a SID.
+
+Example:
+
+>>> winbind.gid_to_sid(10001)
+'S-1-5-21-406022937-1377575209-526660263-512' " },
+
+ { "sid_to_uid", py_sid_to_uid, METH_VARARGS,
+ "sid_to_uid(string) -> int
+
+Return the UNIX uid for a SID.
+
+Example:
+
+>>> winbind.sid_to_uid('S-1-5-21-406022937-1377575209-526660263-500')
+10000 " },
+
+ { "sid_to_gid", py_sid_to_gid, METH_VARARGS,
+ "sid_to_gid(string) -> int
+
+Return the UNIX gid corresponding to a SID.
+
+Example:
+
+>>> winbind.sid_to_gid('S-1-5-21-406022937-1377575209-526660263-512')
+10001 " },
+
+ /* Miscellaneous */
+
+ { "check_secret", py_check_secret, METH_VARARGS,
+ "check_secret() -> int
+
+Check the machine trust account password. The NT status is returned
+with zero indicating success. " },
+
+ { "enum_trust_dom", py_enum_trust_dom, METH_VARARGS,
+ "enum_trust_dom() -> list of strings
+
+Return a list of trusted domains. The domain the server is a member
+of is not included.
+
+Example:
+
+>>> winbind.enum_trust_dom()
+['NPSD-TEST2', 'SP2NDOM'] " },
+
+ /* PAM authorisation functions */
+
+ { "auth_plaintext", py_auth_plaintext, METH_VARARGS,
+ "auth_plaintext(s, s) -> int
+
+Authenticate a username and password using plaintext authentication.
+The NT status code is returned with zero indicating success." },
+
+ { "auth_crap", py_auth_crap, METH_VARARGS,
+ "auth_crap(s, s) -> int
+
+Authenticate a username and password using the challenge/response
+protocol. The NT status code is returned with zero indicating
+success." },
+
+ { NULL }
+};
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+ char *docstring;
+} module_const_vals[] = {
+
+ /* Well known RIDs */
+
+ { "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN,
+ "Well-known RID for Administrator user" },
+
+ { "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST,
+ "Well-known RID for Guest user" },
+
+ { "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS,
+ "Well-known RID for Domain Admins group" },
+
+ { "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS,
+ "Well-known RID for Domain Users group" },
+
+ { "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS,
+ "Well-known RID for Domain Guests group" },
+
+ { NULL }
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/*
+ * Module initialisation
+ */
+
+static char winbind_module__doc__[] =
+"A python extension to winbind client functions.";
+
+void initwinbind(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule3("winbind", winbind_methods,
+ winbind_module__doc__);
+
+ dict = PyModule_GetDict(module);
+
+ winbind_error = PyErr_NewException("winbind.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", winbind_error);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Insert configuration dictionary */
+
+ PyDict_SetItemString(dict, "config", py_config_dict());
+}
diff --git a/source3/python/py_winbind_conv.c b/source3/python/py_winbind_conv.c
new file mode 100644
index 0000000000..c3e416171e
--- /dev/null
+++ b/source3/python/py_winbind_conv.c
@@ -0,0 +1,42 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "includes.h"
+#include "Python.h"
+#include "python/py_conv.h"
+
+/* Convert a struct passwd to a dictionary */
+
+static struct pyconv py_passwd[] = {
+ { "pw_name", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_name) },
+ { "pw_passwd", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_passwd) },
+ { "pw_uid", PY_UID, offsetof(struct winbindd_response, data.pw.pw_uid) },
+ { "pw_guid", PY_GID, offsetof(struct winbindd_response, data.pw.pw_gid) },
+ { "pw_gecos", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_gecos) },
+ { "pw_dir", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_dir) },
+ { "pw_shell", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_shell) },
+ { NULL}
+};
+
+BOOL py_from_winbind_passwd(PyObject **dict, struct winbindd_response *response)
+{
+ *dict = from_struct(response, py_passwd);
+ return True;
+}
diff --git a/source3/python/samba/.cvsignore b/source3/python/samba/.cvsignore
new file mode 100644
index 0000000000..0d20b6487c
--- /dev/null
+++ b/source3/python/samba/.cvsignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/source3/python/samba/__init__.py b/source3/python/samba/__init__.py
new file mode 100644
index 0000000000..c818ca3e04
--- /dev/null
+++ b/source3/python/samba/__init__.py
@@ -0,0 +1,7 @@
+"""samba
+
+Various Python modules for interfacing to Samba.
+
+Try using help() to examine their documentation.
+"""
+
diff --git a/source3/python/samba/printerdata.py b/source3/python/samba/printerdata.py
new file mode 100644
index 0000000000..33251f6a00
--- /dev/null
+++ b/source3/python/samba/printerdata.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+#
+# A python module that maps printerdata to a dictionary. We define
+# two classes. The printerdata class maps to Get/Set/Enum/DeletePrinterData
+# and the printerdata_ex class maps to Get/Set/Enum/DeletePrinterDataEx
+#
+
+#
+# TODO:
+#
+# - Implement __delitem__
+#
+
+from samba import spoolss
+
+class printerdata:
+ def __init__(self, host, creds = {}):
+ self.hnd = spoolss.openprinter(host, creds = creds)
+
+ def keys(self):
+ return self.hnd.enumprinterdata().keys()
+
+ def __getitem__(self, key):
+ return self.hnd.getprinterdata(key)['data']
+
+ def __setitem__(self, key, value):
+ # Store as REG_BINARY for now
+ self.hnd.setprinterdata({"key": "", "value": key, "type": 3,
+ "data": value})
+
+class printerdata_ex:
+ def __init__(self, host):
+ self.host = host
+ self.top_level_keys = ["PrinterDriverData", "DsSpooler", "DsDriver",
+ "DsUser"]
+
+ def keys(self):
+ return self.top_level_keys
+
+ def has_key(self, key):
+ for k in self.top_level_keys:
+ if k == key:
+ return 1
+ return 0
+
+ class printerdata_ex_subkey:
+ def __init__(self, host, key):
+ self.hnd = spoolss.openprinter(host)
+ self.key = key
+
+ def keys(self):
+ return self.hnd.enumprinterdataex(self.key).keys()
+
+ def __getitem__(self, key):
+ return self.hnd.getprinterdataex(self.key, key)['data']
+
+ def __getitem__(self, key):
+ return self.printerdata_ex_subkey(self.host, key)
diff --git a/source3/python/setup.py b/source3/python/setup.py
new file mode 100755
index 0000000000..6d03ca633a
--- /dev/null
+++ b/source3/python/setup.py
@@ -0,0 +1,183 @@
+# -*- mode: python -*-
+#
+# Unix SMB/CIFS implementation.
+# Module packaging setup for Samba python extensions
+#
+# Copyright (C) Tim Potter, 2002
+# Copyright (C) Martin Pool, 2002
+#
+# 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.
+#
+
+from distutils.core import setup
+from distutils.extension import Extension
+
+import sys, string, os
+
+# The Makefile passes in environment variable $PYTHON_OBJ as being the
+# list of Samba objects. This kind of goes against the distutils.cmd
+# method of adding setup commands and will also confuse people who are
+# familiar with the python Distutils module.
+
+samba_objs = os.environ.get("PYTHON_OBJS", "")
+
+samba_cflags = os.environ.get("PYTHON_CFLAGS", "")
+
+samba_srcdir = os.environ.get("SRCDIR", "")
+
+# These variables are filled in by configure
+
+samba_libs = os.environ.get("LIBS", "")
+
+# Convert libs and objs from space separated strings to lists of strings
+# for distutils to digest. Split "-l" prefix off library list.
+
+obj_list = string.split(samba_objs)
+
+lib_list = []
+
+for lib in string.split(samba_libs):
+ lib_list.append(string.replace(lib, "-l", ""))
+
+flags_list = string.split(samba_cflags)
+
+# Invoke distutils.setup
+
+setup(
+
+ # Overview information
+
+ name = "Samba Python Extensions",
+ version = "0.1",
+ author = "Tim Potter",
+ author_email = "tpot@samba.org",
+ license = "GPL",
+
+ # Get the "samba" directory of Python source. At the moment this
+ # just contains the __init__ file that makes it work as a
+ # subpackage. This is needed even though everything else is an
+ # extension module.
+ package_dir = {"samba": os.path.join(samba_srcdir, "python", "samba")},
+ packages = ["samba"],
+
+ # Module list
+ ext_package = "samba",
+ ext_modules = [
+
+ # SPOOLSS pipe module
+
+ Extension(name = "spoolss",
+ sources = [samba_srcdir + "python/py_spoolss.c",
+ samba_srcdir + "python/py_common.c",
+ samba_srcdir + "python/py_conv.c",
+ samba_srcdir + "python/py_ntsec.c",
+ samba_srcdir + "python/py_spoolss_forms.c",
+ samba_srcdir + "python/py_spoolss_forms_conv.c",
+ samba_srcdir + "python/py_spoolss_drivers.c",
+ samba_srcdir + "python/py_spoolss_drivers_conv.c",
+ samba_srcdir + "python/py_spoolss_printers.c",
+ samba_srcdir + "python/py_spoolss_printers_conv.c",
+ samba_srcdir + "python/py_spoolss_printerdata.c",
+ samba_srcdir + "python/py_spoolss_ports.c",
+ samba_srcdir + "python/py_spoolss_ports_conv.c",
+ samba_srcdir + "python/py_spoolss_jobs.c",
+ samba_srcdir + "python/py_spoolss_jobs_conv.c",
+ ],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # LSA pipe module
+
+ Extension(name = "lsa",
+ sources = [samba_srcdir + "python/py_lsa.c",
+ samba_srcdir + "python/py_common.c",
+ samba_srcdir + "python/py_ntsec.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # SAMR pipe module
+
+ Extension(name = "samr",
+ sources = [samba_srcdir + "python/py_samr.c",
+ samba_srcdir + "python/py_samr_conv.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # winbind client module
+
+ Extension(name = "winbind",
+ sources = [samba_srcdir + "python/py_winbind.c",
+ samba_srcdir + "python/py_winbind_conv.c",
+ samba_srcdir + "python/py_conv.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # WINREG pipe module
+
+ Extension(name = "winreg",
+ sources = [samba_srcdir + "python/py_winreg.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # tdb module
+
+ Extension(name = "tdb",
+ sources = [samba_srcdir + "python/py_tdb.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # libsmb module
+
+ Extension(name = "smb",
+ sources = [samba_srcdir + "python/py_smb.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # Moving to merge all individual extensions in to one big
+ # extension. This is to avoid the fact that each extension is 3MB
+ # in size due to the lack of proper depedency management in Samba.
+
+ Extension(name = "samba",
+ sources = [samba_srcdir + "python/py_samba.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # tdbpack/unpack extensions. Does not actually link to any Samba
+ # code, although it implements a compatible data format.
+ Extension(name = "tdbpack",
+ sources = [os.path.join(samba_srcdir, "python", "py_tdbpack.c")]),
+ ],
+)
diff --git a/source3/registry/reg_objects.c b/source3/registry/reg_objects.c
new file mode 100644
index 0000000000..be15e49a2f
--- /dev/null
+++ b/source3/registry/reg_objects.c
@@ -0,0 +1,372 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald Carter 2002.
+ *
+ * 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.
+ */
+
+/* Implementation of registry frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+
+/***********************************************************************
+ Init the talloc context held by a REGSUBKEY_CTR structure
+ **********************************************************************/
+
+void regsubkey_ctr_init( REGSUBKEY_CTR *ctr )
+{
+ if ( !ctr->ctx )
+ ctr->ctx = talloc_init();
+}
+
+/***********************************************************************
+ Add a new key to the array
+ **********************************************************************/
+
+int regsubkey_ctr_addkey( REGSUBKEY_CTR *ctr, char *keyname )
+{
+ uint32 len;
+ char **pp;
+
+ if ( keyname )
+ {
+ len = strlen( keyname );
+
+ /* allocate a space for the char* in the array */
+
+ if ( ctr->subkeys == 0 )
+ ctr->subkeys = talloc( ctr->ctx, sizeof(char*) );
+ else {
+ pp = talloc_realloc( ctr->ctx, ctr->subkeys, sizeof(char*)*(ctr->num_subkeys+1) );
+ if ( pp )
+ ctr->subkeys = pp;
+ }
+
+ /* allocate the string and save it in the array */
+
+ ctr->subkeys[ctr->num_subkeys] = talloc( ctr->ctx, len+1 );
+ strncpy( ctr->subkeys[ctr->num_subkeys], keyname, len+1 );
+ ctr->num_subkeys++;
+ }
+
+ return ctr->num_subkeys;
+}
+
+/***********************************************************************
+ How many keys does the container hold ?
+ **********************************************************************/
+
+int regsubkey_ctr_numkeys( REGSUBKEY_CTR *ctr )
+{
+ return ctr->num_subkeys;
+}
+
+/***********************************************************************
+ Retreive a specific key string
+ **********************************************************************/
+
+char* regsubkey_ctr_specific_key( REGSUBKEY_CTR *ctr, uint32 key_index )
+{
+ if ( ! (key_index < ctr->num_subkeys) )
+ return NULL;
+
+ return ctr->subkeys[key_index];
+}
+
+/***********************************************************************
+ free memory held by a REGSUBKEY_CTR structure
+ **********************************************************************/
+
+void regsubkey_ctr_destroy( REGSUBKEY_CTR *ctr )
+{
+ if ( ctr ) {
+ talloc_destroy( ctr->ctx );
+ ZERO_STRUCTP( ctr );
+ }
+}
+
+
+/*
+ * Utility functions for REGVAL_CTR
+ */
+
+/***********************************************************************
+ Init the talloc context held by a REGSUBKEY_CTR structure
+ **********************************************************************/
+
+void regval_ctr_init( REGVAL_CTR *ctr )
+{
+ if ( !ctr->ctx )
+ ctr->ctx = talloc_init();
+}
+
+/***********************************************************************
+ How many keys does the container hold ?
+ **********************************************************************/
+
+int regval_ctr_numvals( REGVAL_CTR *ctr )
+{
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ allocate memory for and duplicate a REGISTRY_VALUE.
+ This is malloc'd memory so the caller should free it when done
+ **********************************************************************/
+
+REGISTRY_VALUE* dup_registry_value( REGISTRY_VALUE *val )
+{
+ REGISTRY_VALUE *copy = NULL;
+
+ if ( !val )
+ return NULL;
+
+ if ( !(copy = malloc( sizeof(REGISTRY_VALUE) )) ) {
+ DEBUG(0,("dup_registry_value: malloc() failed!\n"));
+ return NULL;
+ }
+
+ /* copy all the non-pointer initial data */
+
+ memcpy( copy, val, sizeof(REGISTRY_VALUE) );
+ if ( val->data_p )
+ {
+ if ( !(copy->data_p = memdup( val->data_p, val->size )) ) {
+ DEBUG(0,("dup_registry_value: memdup() failed for [%d] bytes!\n",
+ val->size));
+ SAFE_FREE( copy );
+ }
+ }
+
+ return copy;
+}
+
+/**********************************************************************
+ free the memory allocated to a REGISTRY_VALUE
+ *********************************************************************/
+
+void free_registry_value( REGISTRY_VALUE *val )
+{
+ if ( !val )
+ return;
+
+ SAFE_FREE( val->data_p );
+ SAFE_FREE( val );
+
+ return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint8* regval_data_p( REGISTRY_VALUE *val )
+{
+ return val->data_p;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+int regval_size( REGISTRY_VALUE *val )
+{
+ return val->size;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+char* regval_name( REGISTRY_VALUE *val )
+{
+ return val->valuename;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint32 regval_type( REGISTRY_VALUE *val )
+{
+ return val->type;
+}
+
+/***********************************************************************
+ Retreive a pointer to a specific value. Caller shoud dup the structure
+ since this memory may go away with a regval_ctr_destroy()
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_specific_value( REGVAL_CTR *ctr, uint32 idx )
+{
+ if ( !(idx < ctr->num_values) )
+ return NULL;
+
+ return ctr->values[idx];
+}
+
+/***********************************************************************
+ Retrive the TALLOC_CTX associated with a REGISTRY_VALUE
+ **********************************************************************/
+
+TALLOC_CTX* regval_ctr_getctx( REGVAL_CTR *val )
+{
+ if ( !val )
+ return NULL;
+
+ return val->ctx;
+}
+
+/***********************************************************************
+ Add a new registry value to the array
+ **********************************************************************/
+
+int regval_ctr_addvalue( REGVAL_CTR *ctr, char *name, uint16 type,
+ char *data_p, size_t size )
+{
+ REGISTRY_VALUE **ppreg;
+
+ if ( name )
+ {
+ /* allocate a slot in the array of pointers */
+
+ if ( ctr->num_values == 0 )
+ ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
+ else {
+ ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
+ if ( ppreg )
+ ctr->values = ppreg;
+ }
+
+ /* allocate a new value and store the pointer in the arrya */
+
+ ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
+
+ /* init the value */
+
+ fstrcpy( ctr->values[ctr->num_values]->valuename, name );
+ ctr->values[ctr->num_values]->type = type;
+ ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, data_p, size );
+ ctr->values[ctr->num_values]->size = size;
+ ctr->num_values++;
+ }
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Add a new registry value to the array
+ **********************************************************************/
+
+int regval_ctr_copyvalue( REGVAL_CTR *ctr, REGISTRY_VALUE *val )
+{
+ REGISTRY_VALUE **ppreg;
+
+ if ( val )
+ {
+ /* allocate a slot in the array of pointers */
+
+ if ( ctr->num_values == 0 )
+ ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
+ else {
+ ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
+ if ( ppreg )
+ ctr->values = ppreg;
+ }
+
+ /* allocate a new value and store the pointer in the arrya */
+
+ ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
+
+ /* init the value */
+
+ fstrcpy( ctr->values[ctr->num_values]->valuename, val->valuename );
+ ctr->values[ctr->num_values]->type = val->type;
+ ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, val->data_p, val->size );
+ ctr->values[ctr->num_values]->size = val->size;
+ ctr->num_values++;
+ }
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+int regval_ctr_delvalue( REGVAL_CTR *ctr, char *name )
+{
+ int i;
+
+ /* search for the value */
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strcmp( ctr->values[i]->valuename, name ) == 0)
+ break;
+ }
+
+ /* just return if we don't find it */
+
+ if ( i == ctr->num_values )
+ return ctr->num_values;
+
+ /* just shift everything down one */
+
+ for ( /* use previous i */; i<(ctr->num_values-1); i++ )
+ memcpy( ctr->values[i], ctr->values[i+1], sizeof(REGISTRY_VALUE) );
+
+ /* paranoia */
+
+ ZERO_STRUCTP( ctr->values[i] );
+
+ ctr->num_values--;
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, char *name )
+{
+ int i;
+
+ /* search for the value */
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strequal( ctr->values[i]->valuename, name ) )
+ return ctr->values[i];
+ }
+
+ return NULL;
+}
+
+/***********************************************************************
+ free memory held by a REGVAL_CTR structure
+ **********************************************************************/
+
+void regval_ctr_destroy( REGVAL_CTR *ctr )
+{
+ if ( ctr ) {
+ talloc_destroy( ctr->ctx );
+ ZERO_STRUCTP( ctr );
+ }
+}
+
+
diff --git a/source3/sam/account.c b/source3/sam/account.c
new file mode 100644
index 0000000000..9144c23844
--- /dev/null
+++ b/source3/sam/account.c
@@ -0,0 +1,307 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2001
+ Copyright (C) Andrew Bartlett 2001-2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+/************************************************************
+ Fill the SAM_ACCOUNT_HANDLE with default values.
+ ***********************************************************/
+
+static void sam_fill_default_account(SAM_ACCOUNT_HANDLE *account)
+{
+ ZERO_STRUCT(account->private); /* Don't touch the talloc context */
+
+ /* Don't change these timestamp settings without a good reason.
+ They are important for NT member server compatibility. */
+
+ account->private.init_flag = FLAG_SAM_UNINIT;
+
+ /* FIXME: We should actually call get_nt_time_max() or sthng
+ * here */
+ unix_to_nt_time(&(account->private.logoff_time),get_time_t_max());
+ unix_to_nt_time(&(account->private.kickoff_time),get_time_t_max());
+ unix_to_nt_time(&(account->private.pass_must_change_time),get_time_t_max());
+ account->private.unknown_1 = 0x00ffffff; /* don't know */
+ account->private.logon_divs = 168; /* hours per week */
+ account->private.hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(account->private.hours, 0xff, account->private.hours_len); /* available at all hours */
+ account->private.unknown_2 = 0x00000000; /* don't know */
+ account->private.unknown_3 = 0x000004ec; /* don't know */
+}
+
+static void destroy_sam_talloc(SAM_ACCOUNT_HANDLE **account)
+{
+ if (*account) {
+ data_blob_clear_free(&((*account)->private.lm_pw));
+ data_blob_clear_free(&((*account)->private.nt_pw));
+ if((*account)->private.plaintext_pw!=NULL)
+ memset((*account)->private.plaintext_pw,'\0',strlen((*account)->private.plaintext_pw));
+
+ talloc_destroy((*account)->mem_ctx);
+ *account = NULL;
+ }
+}
+
+
+/**********************************************************************
+ Alloc memory and initialises a SAM_ACCOUNT_HANDLE on supplied mem_ctx.
+***********************************************************************/
+
+NTSTATUS sam_init_account_talloc(TALLOC_CTX *mem_ctx, SAM_ACCOUNT_HANDLE **account)
+{
+ SMB_ASSERT(*account != NULL);
+
+ if (!mem_ctx) {
+ DEBUG(0,("sam_init_account_talloc: mem_ctx was NULL!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *account=(SAM_ACCOUNT_HANDLE *)talloc(mem_ctx, sizeof(SAM_ACCOUNT_HANDLE));
+
+ if (*account==NULL) {
+ DEBUG(0,("sam_init_account_talloc: error while allocating memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*account)->mem_ctx = mem_ctx;
+
+ (*account)->free_fn = NULL;
+
+ sam_fill_default_account(*account);
+
+ return NT_STATUS_OK;
+}
+
+
+/*************************************************************
+ Alloc memory and initialises a struct sam_passwd.
+ ************************************************************/
+
+NTSTATUS sam_init_account(SAM_ACCOUNT_HANDLE **account)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS nt_status;
+
+ mem_ctx = talloc_init_named("sam internal SAM_ACCOUNT_HANDLE allocation");
+
+ if (!mem_ctx) {
+ DEBUG(0,("sam_init_account: error while doing talloc_init()\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_init_account_talloc(mem_ctx, account))) {
+ talloc_destroy(mem_ctx);
+ return nt_status;
+ }
+
+ (*account)->free_fn = destroy_sam_talloc;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Free the contents of the SAM_ACCOUNT_HANDLE, but not the structure.
+ *
+ * Also wipes the LM and NT hashes and plaintext password from
+ * memory.
+ *
+ * @param account SAM_ACCOUNT_HANDLE to free members of.
+ **/
+
+static void sam_free_account_contents(SAM_ACCOUNT_HANDLE *account)
+{
+
+ /* Kill off sensitive data. Free()ed by the
+ talloc mechinism */
+
+ data_blob_clear_free(&(account->private.lm_pw));
+ data_blob_clear_free(&(account->private.nt_pw));
+ if (account->private.plaintext_pw)
+ memset(account->private.plaintext_pw,'\0',strlen(account->private.plaintext_pw));
+}
+
+
+/************************************************************
+ Reset the SAM_ACCOUNT_HANDLE and free the NT/LM hashes.
+ ***********************************************************/
+
+NTSTATUS sam_reset_sam(SAM_ACCOUNT_HANDLE *account)
+{
+ SMB_ASSERT(account != NULL);
+
+ sam_free_account_contents(account);
+
+ sam_fill_default_account(account);
+
+ return NT_STATUS_OK;
+}
+
+
+/************************************************************
+ Free the SAM_ACCOUNT_HANDLE and the member pointers.
+ ***********************************************************/
+
+NTSTATUS sam_free_account(SAM_ACCOUNT_HANDLE **account)
+{
+ SMB_ASSERT(*account != NULL);
+
+ sam_free_account_contents(*account);
+
+ if ((*account)->free_fn) {
+ (*account)->free_fn(account);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************
+ Encode the account control bits into a string.
+ length = length of string to encode into (including terminating
+ null). length *MUST BE MORE THAN 2* !
+ **********************************************************/
+
+char *sam_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
+{
+ static fstring acct_str;
+ size_t i = 0;
+
+ acct_str[i++] = '[';
+
+ if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
+ if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
+ if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
+ if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
+ if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
+ if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
+ if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
+ if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
+ if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
+ if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
+ if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
+
+ for ( ; i < length - 2 ; i++ )
+ acct_str[i] = ' ';
+
+ i = length - 2;
+ acct_str[i++] = ']';
+ acct_str[i++] = '\0';
+
+ return acct_str;
+}
+
+/**********************************************************
+ Decode the account control bits from a string.
+ **********************************************************/
+
+uint16 sam_decode_acct_ctrl(const char *p)
+{
+ uint16 acct_ctrl = 0;
+ BOOL finished = False;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[')
+ return 0;
+
+ for (p++; *p && !finished; p++) {
+ switch (*p) {
+ case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
+ case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
+ case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
+ case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
+ case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
+ case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
+ case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
+ case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
+ case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
+ case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
+ case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
+ case ' ': { break; }
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default: { finished = True; }
+ }
+ }
+
+ return acct_ctrl;
+}
+
+/*************************************************************
+ Routine to set 32 hex password characters from a 16 byte array.
+**************************************************************/
+
+void sam_sethexpwd(char *p, const unsigned char *pwd, uint16 acct_ctrl)
+{
+ if (pwd != NULL) {
+ int i;
+ for (i = 0; i < 16; i++)
+ slprintf(&p[i*2], 3, "%02X", pwd[i]);
+ } else {
+ if (acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
+ else
+ safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
+ }
+}
+
+/*************************************************************
+ Routine to get the 32 hex characters and turn them
+ into a 16 byte array.
+**************************************************************/
+
+BOOL sam_gethexpwd(const char *p, unsigned char *pwd)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p)
+ return (False);
+
+ for (i = 0; i < 32; i += 2) {
+ hinybble = toupper(p[i]);
+ lonybble = toupper(p[i + 1]);
+
+ p1 = strchr(hexchars, hinybble);
+ p2 = strchr(hexchars, lonybble);
+
+ if (!p1 || !p2)
+ return (False);
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ pwd[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
diff --git a/source3/sam/api.c b/source3/sam/api.c
new file mode 100644
index 0000000000..fb2f015e95
--- /dev/null
+++ b/source3/sam/api.c
@@ -0,0 +1,322 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM interface API.
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+/* these functions should be used by the rest of SAMBA --metze */
+
+/* General API */
+
+NTSTATUS sam_get_sec_desc(const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_sec_desc(sam_context, access_token, sid, sd);
+}
+
+NTSTATUS sam_set_sec_desc(const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_set_sec_desc(sam_context, access_token, sid, sd);
+}
+
+NTSTATUS sam_lookup_sid(const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_lookup_sid(sam_context, access_token, sid, name, type);
+}
+
+NTSTATUS sam_lookup_name(const NT_USER_TOKEN *access_token, const char *domain, const char *name, DOM_SID **sid, uint32 *type)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_lookup_name(sam_context, access_token, domain, name, sid, type);
+}
+
+/* Domain API */
+
+NTSTATUS sam_update_domain(const SAM_DOMAIN_HANDLE *domain)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_update_domain(sam_context, domain);
+}
+
+NTSTATUS sam_enum_domains(const NT_USER_TOKEN *access_token, int32 *domain_count, DOM_SID **domains, char **domain_names)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_enum_domains(sam_context, access_token, domain_count, domains, domain_names);
+}
+
+NTSTATUS sam_lookup_domain(const NT_USER_TOKEN * access_token, const char *domain, DOM_SID **domainsid)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_lookup_domain(sam_context, access_token, domain, domainsid);
+}
+
+NTSTATUS sam_get_domain_by_sid(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *domainsid, SAM_DOMAIN_HANDLE **domain)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_domain_by_sid(sam_context, access_token, access_desired, domainsid, domain);
+}
+
+/* Account API */
+
+NTSTATUS sam_create_account(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *domainsid, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_create_account(sam_context, access_token, access_desired, domainsid, account_name, acct_ctrl, account);
+}
+
+NTSTATUS sam_add_account(const DOM_SID *domainsid, const SAM_ACCOUNT_HANDLE *account)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_add_account(sam_context, domainsid, account);
+}
+
+NTSTATUS sam_update_account(const SAM_ACCOUNT_HANDLE *account)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_update_account(sam_context, account);
+}
+
+NTSTATUS sam_delete_account(const SAM_ACCOUNT_HANDLE *account)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_delete_account(sam_context, account);
+}
+
+NTSTATUS sam_enum_accounts(const NT_USER_TOKEN *access_token, const DOM_SID *domain, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_enum_accounts(sam_context, access_token, domain, acct_ctrl, account_count, accounts);
+}
+
+NTSTATUS sam_get_account_by_sid(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_account_by_sid(sam_context, access_token, access_desired, accountsid, account);
+}
+
+NTSTATUS sam_get_account_by_name(const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *domain, const char *name, SAM_ACCOUNT_HANDLE **account)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_account_by_name(sam_context, access_token, access_desired, domain, name, account);
+}
+
+/* Group API */
+
+NTSTATUS sam_create_group(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *domainsid, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_create_group(sam_context, access_token, access_desired, domainsid, group_name, group_ctrl, group);
+}
+
+NTSTATUS sam_add_group(const DOM_SID *domainsid, const SAM_GROUP_HANDLE *group)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_add_group(sam_context, domainsid, group);
+}
+
+NTSTATUS sam_update_group(const SAM_GROUP_HANDLE *group)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_update_group(sam_context, group);
+}
+
+NTSTATUS sam_delete_group(const SAM_GROUP_HANDLE *group)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_delete_group(sam_context, group);
+}
+
+NTSTATUS sam_enum_groups(const NT_USER_TOKEN *access_token, const DOM_SID *domainsid, uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_enum_groups(sam_context, access_token, domainsid, group_ctrl, groups_count, groups);
+}
+
+NTSTATUS sam_get_group_by_sid(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_group_by_sid(sam_context, access_token, access_desired, groupsid, group);
+}
+
+NTSTATUS sam_get_group_by_name(const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *domain, const char *name, SAM_GROUP_HANDLE **group)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_group_by_name(sam_context, access_token, access_desired, domain, name, group);
+}
+
+NTSTATUS sam_add_member_to_group(const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_add_member_to_group(sam_context, group, member);
+}
+
+NTSTATUS sam_delete_member_from_group(const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_delete_member_from_group(sam_context, group, member);
+}
+
+NTSTATUS sam_enum_groupmembers(const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_enum_groupmembers(sam_context, group, members_count, members);
+}
+
+NTSTATUS sam_get_groups_of_sid(const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups)
+{
+ SAM_CONTEXT *sam_context = sam_get_static_context(False);
+
+ if (!sam_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return sam_context->sam_get_groups_of_sid(sam_context, access_token, sids, group_ctrl, group_count, groups);
+}
+
diff --git a/source3/sam/get_set_account.c b/source3/sam/get_set_account.c
new file mode 100644
index 0000000000..7bbfe39e14
--- /dev/null
+++ b/source3/sam/get_set_account.c
@@ -0,0 +1,872 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM_ACCOUNT_HANDLE access routines
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jelmer Vernooij 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+NTSTATUS sam_get_account_domain_sid(const SAM_ACCOUNT_HANDLE *sampass, const DOM_SID **sid)
+{
+ NTSTATUS status;
+ SAM_DOMAIN_HANDLE *domain;
+ SAM_ASSERT(!sampass || !sid);
+
+ if (!NT_STATUS_IS_OK(status = sam_get_account_domain(sampass, &domain))){
+ DEBUG(0, ("sam_get_account_domain_sid: Can't get domain for account\n"));
+ return status;
+ }
+
+ return sam_get_domain_sid(domain, sid);
+}
+
+NTSTATUS sam_get_account_domain_name(const SAM_ACCOUNT_HANDLE *sampass, const char **domain_name)
+{
+ NTSTATUS status;
+ SAM_DOMAIN_HANDLE *domain;
+ SAM_ASSERT(sampass && domain_name);
+
+ if (!NT_STATUS_IS_OK(status = sam_get_account_domain(sampass, &domain))){
+ DEBUG(0, ("sam_get_account_domain_name: Can't get domain for account\n"));
+ return status;
+ }
+
+ return sam_get_domain_name(domain, domain_name);
+}
+
+NTSTATUS sam_get_account_acct_ctrl(const SAM_ACCOUNT_HANDLE *sampass, uint16 *acct_ctrl)
+{
+ SAM_ASSERT(sampass && acct_ctrl);
+
+ *acct_ctrl = sampass->private.acct_ctrl;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_logon_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *logon_time)
+{
+ SAM_ASSERT(sampass && logon_time) ;
+
+ *logon_time = sampass->private.logon_time;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_logoff_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *logoff_time)
+{
+ SAM_ASSERT(sampass && logoff_time) ;
+
+ *logoff_time = sampass->private.logoff_time;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_kickoff_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *kickoff_time)
+{
+ SAM_ASSERT(sampass && kickoff_time);
+
+ *kickoff_time = sampass->private.kickoff_time;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_pass_last_set_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *pass_last_set_time)
+{
+ SAM_ASSERT(sampass && pass_last_set_time);
+
+ *pass_last_set_time = sampass->private.pass_last_set_time;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_pass_can_change_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *pass_can_change_time)
+{
+ SAM_ASSERT(sampass && pass_can_change_time);
+
+ *pass_can_change_time = sampass->private.pass_can_change_time;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_pass_must_change_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *pass_must_change_time)
+{
+ SAM_ASSERT(sampass && pass_must_change_time);
+
+ *pass_must_change_time = sampass->private.pass_must_change_time;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_logon_divs(const SAM_ACCOUNT_HANDLE *sampass, uint16 *logon_divs)
+{
+ SAM_ASSERT(sampass && logon_divs);
+
+ *logon_divs = sampass->private.logon_divs;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_hours_len(const SAM_ACCOUNT_HANDLE *sampass, uint32 *hours_len)
+{
+ SAM_ASSERT(sampass && hours_len);
+
+ *hours_len = sampass->private.hours_len;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_hours(const SAM_ACCOUNT_HANDLE *sampass, const uint8 **hours)
+{
+ SAM_ASSERT(sampass && hours);
+
+ *hours = sampass->private.hours;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_nt_pwd(const SAM_ACCOUNT_HANDLE *sampass, DATA_BLOB *nt_pwd)
+{
+ SAM_ASSERT(sampass);
+
+ SMB_ASSERT((!sampass->private.nt_pw.data)
+ || sampass->private.nt_pw.length == NT_HASH_LEN);
+
+ *nt_pwd = sampass->private.nt_pw;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_lm_pwd(const SAM_ACCOUNT_HANDLE *sampass, DATA_BLOB *lm_pwd)
+{
+ SAM_ASSERT(sampass);
+
+ SMB_ASSERT((!sampass->private.lm_pw.data)
+ || sampass->private.lm_pw.length == LM_HASH_LEN);
+
+ *lm_pwd = sampass->private.lm_pw;
+
+ return NT_STATUS_OK;
+}
+
+/* Return the plaintext password if known. Most of the time
+ it isn't, so don't assume anything magic about this function.
+
+ Used to pass the plaintext to sam backends that might
+ want to store more than just the NTLM hashes.
+*/
+
+NTSTATUS sam_get_account_plaintext_pwd(const SAM_ACCOUNT_HANDLE *sampass, char **plain_pwd)
+{
+ SAM_ASSERT(sampass && plain_pwd);
+
+ *plain_pwd = sampass->private.plaintext_pw;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_sid(const SAM_ACCOUNT_HANDLE *sampass, const DOM_SID **sid)
+{
+ SAM_ASSERT(sampass);
+
+ *sid = &(sampass->private.account_sid);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_pgroup(const SAM_ACCOUNT_HANDLE *sampass, const DOM_SID **sid)
+{
+ SAM_ASSERT(sampass);
+
+ *sid = &(sampass->private.group_sid);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Get flags showing what is initalised in the SAM_ACCOUNT_HANDLE
+ * @param sampass the SAM_ACCOUNT_HANDLE in question
+ * @return the flags indicating the members initialised in the struct.
+ **/
+
+NTSTATUS sam_get_account_init_flag(const SAM_ACCOUNT_HANDLE *sampass, uint32 *initflag)
+{
+ SAM_ASSERT(sampass);
+
+ *initflag = sampass->private.init_flag;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_name(const SAM_ACCOUNT_HANDLE *sampass, char **account_name)
+{
+ SAM_ASSERT(sampass);
+
+ *account_name = sampass->private.account_name;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_domain(const SAM_ACCOUNT_HANDLE *sampass, SAM_DOMAIN_HANDLE **domain)
+{
+ SAM_ASSERT(sampass);
+
+ *domain = sampass->private.domain;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_fullname(const SAM_ACCOUNT_HANDLE *sampass, char **fullname)
+{
+ SAM_ASSERT(sampass);
+
+ *fullname = sampass->private.full_name;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_homedir(const SAM_ACCOUNT_HANDLE *sampass, char **homedir)
+{
+ SAM_ASSERT(sampass);
+
+ *homedir = sampass->private.home_dir;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_unix_home_dir(const SAM_ACCOUNT_HANDLE *sampass, char **uhomedir)
+{
+ SAM_ASSERT(sampass);
+
+ *uhomedir = sampass->private.unix_home_dir;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_dir_drive(const SAM_ACCOUNT_HANDLE *sampass, char **dirdrive)
+{
+ SAM_ASSERT(sampass);
+
+ *dirdrive = sampass->private.dir_drive;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_logon_script(const SAM_ACCOUNT_HANDLE *sampass, char **logon_script)
+{
+ SAM_ASSERT(sampass);
+
+ *logon_script = sampass->private.logon_script;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_profile_path(const SAM_ACCOUNT_HANDLE *sampass, char **profile_path)
+{
+ SAM_ASSERT(sampass);
+
+ *profile_path = sampass->private.profile_path;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_description(const SAM_ACCOUNT_HANDLE *sampass, char **description)
+{
+ SAM_ASSERT(sampass);
+
+ *description = sampass->private.acct_desc;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_workstations(const SAM_ACCOUNT_HANDLE *sampass, char **workstations)
+{
+ SAM_ASSERT(sampass);
+
+ *workstations = sampass->private.workstations;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_unknown_str(const SAM_ACCOUNT_HANDLE *sampass, char **unknown_str)
+{
+ SAM_ASSERT(sampass);
+
+ *unknown_str = sampass->private.unknown_str;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_munged_dial(const SAM_ACCOUNT_HANDLE *sampass, char **munged_dial)
+{
+ SAM_ASSERT(sampass);
+
+ *munged_dial = sampass->private.munged_dial;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_unknown_1(const SAM_ACCOUNT_HANDLE *sampass, uint32 *unknown1)
+{
+ SAM_ASSERT(sampass && unknown1);
+
+ *unknown1 = sampass->private.unknown_1;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_unknown_2(const SAM_ACCOUNT_HANDLE *sampass, uint32 *unknown2)
+{
+ SAM_ASSERT(sampass && unknown2);
+
+ *unknown2 = sampass->private.unknown_2;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_account_unknown_3(const SAM_ACCOUNT_HANDLE *sampass, uint32 *unknown3)
+{
+ SAM_ASSERT(sampass && unknown3);
+
+ *unknown3 = sampass->private.unknown_3;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Collection of set...() functions for SAM_ACCOUNT_HANDLE_INFO.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_acct_ctrl(SAM_ACCOUNT_HANDLE *sampass, uint16 flags)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.acct_ctrl = flags;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_logon_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.logon_time = mytime;
+
+ if (store)
+ sam_set_account_init_flag(sampass, FLAG_SAM_LOGONTIME);
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS sam_set_account_logoff_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.logoff_time = mytime;
+
+ if (store)
+ sam_set_account_init_flag(sampass, FLAG_SAM_LOGOFFTIME);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_kickoff_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.kickoff_time = mytime;
+
+ if (store)
+ sam_set_account_init_flag(sampass, FLAG_SAM_KICKOFFTIME);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_pass_can_change_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.pass_can_change_time = mytime;
+
+ if (store)
+ sam_set_account_init_flag(sampass, FLAG_SAM_CANCHANGETIME);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_pass_must_change_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.pass_must_change_time = mytime;
+
+ if (store)
+ sam_set_account_init_flag(sampass, FLAG_SAM_MUSTCHANGETIME);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_pass_last_set_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.pass_last_set_time = mytime;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_hours_len(SAM_ACCOUNT_HANDLE *sampass, uint32 len)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.hours_len = len;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_logon_divs(SAM_ACCOUNT_HANDLE *sampass, uint16 hours)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.logon_divs = hours;
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set flags showing what is initalised in the SAM_ACCOUNT_HANDLE
+ * @param sampass the SAM_ACCOUNT_HANDLE in question
+ * @param flag The *new* flag to be set. Old flags preserved
+ * this flag is only added.
+ **/
+
+NTSTATUS sam_set_account_init_flag(SAM_ACCOUNT_HANDLE *sampass, uint32 flag)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.init_flag |= flag;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_sid(SAM_ACCOUNT_HANDLE *sampass, const DOM_SID *u_sid)
+{
+ SAM_ASSERT(sampass && u_sid);
+
+ sid_copy(&sampass->private.account_sid, u_sid);
+
+ DEBUG(10, ("sam_set_account_sid: setting account sid %s\n",
+ sid_string_static(&sampass->private.account_sid)));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_sid_from_string(SAM_ACCOUNT_HANDLE *sampass, const char *u_sid)
+{
+ DOM_SID new_sid;
+ SAM_ASSERT(sampass && u_sid);
+
+ DEBUG(10, ("sam_set_account_sid_from_string: setting account sid %s\n",
+ u_sid));
+
+ if (!string_to_sid(&new_sid, u_sid)) {
+ DEBUG(1, ("sam_set_account_sid_from_string: %s isn't a valid SID!\n", u_sid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(sam_set_account_sid(sampass, &new_sid))) {
+ DEBUG(1, ("sam_set_account_sid_from_string: could not set sid %s on SAM_ACCOUNT_HANDLE!\n", u_sid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_pgroup_sid(SAM_ACCOUNT_HANDLE *sampass, const DOM_SID *g_sid)
+{
+ SAM_ASSERT(sampass && g_sid);
+
+ sid_copy(&sampass->private.group_sid, g_sid);
+
+ DEBUG(10, ("sam_set_group_sid: setting group sid %s\n",
+ sid_string_static(&sampass->private.group_sid)));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_pgroup_string(SAM_ACCOUNT_HANDLE *sampass, const char *g_sid)
+{
+ DOM_SID new_sid;
+ SAM_ASSERT(sampass && g_sid);
+
+ DEBUG(10, ("sam_set_group_sid_from_string: setting group sid %s\n",
+ g_sid));
+
+ if (!string_to_sid(&new_sid, g_sid)) {
+ DEBUG(1, ("sam_set_group_sid_from_string: %s isn't a valid SID!\n", g_sid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(sam_set_account_pgroup_sid(sampass, &new_sid))) {
+ DEBUG(1, ("sam_set_group_sid_from_string: could not set sid %s on SAM_ACCOUNT_HANDLE!\n", g_sid));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the domain name.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_domain(SAM_ACCOUNT_HANDLE *sampass, SAM_DOMAIN_HANDLE *domain)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.domain = domain;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's NT name.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_name(SAM_ACCOUNT_HANDLE *sampass, const char *account_name)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_account_name: setting nt account_name %s, was %s\n", account_name, sampass->private.account_name));
+
+ sampass->private.account_name = talloc_strdup(sampass->mem_ctx, account_name);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's full name.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_fullname(SAM_ACCOUNT_HANDLE *sampass, const char *full_name)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_account_fullname: setting full name %s, was %s\n", full_name, sampass->private.full_name));
+
+ sampass->private.full_name = talloc_strdup(sampass->mem_ctx, full_name);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's logon script.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_logon_script(SAM_ACCOUNT_HANDLE *sampass, const char *logon_script, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_logon_script: from %s to %s\n", logon_script, sampass->private.logon_script));
+
+ sampass->private.logon_script = talloc_strdup(sampass->mem_ctx, logon_script);
+
+ sam_set_account_init_flag(sampass, FLAG_SAM_LOGONSCRIPT);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's profile path.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_profile_path(SAM_ACCOUNT_HANDLE *sampass, const char *profile_path, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_profile_path: setting profile path %s, was %s\n", profile_path, sampass->private.profile_path));
+
+ sampass->private.profile_path = talloc_strdup(sampass->mem_ctx, profile_path);
+
+ if (store) {
+ DEBUG(10, ("sam_set_profile_path: setting profile path sam flag!\n"));
+ sam_set_account_init_flag(sampass, FLAG_SAM_PROFILE);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's directory drive.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_dir_drive(SAM_ACCOUNT_HANDLE *sampass, const char *dir_drive, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_dir_drive: setting dir drive %s, was %s\n", dir_drive,
+ sampass->private.dir_drive));
+
+ sampass->private.dir_drive = talloc_strdup(sampass->mem_ctx, dir_drive);
+
+ if (store) {
+ DEBUG(10, ("sam_set_dir_drive: setting dir drive sam flag!\n"));
+ sam_set_account_init_flag(sampass, FLAG_SAM_DRIVE);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's home directory.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_homedir(SAM_ACCOUNT_HANDLE *sampass, const char *home_dir, BOOL store)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_homedir: setting home dir %s, was %s\n", home_dir,
+ sampass->private.home_dir));
+
+ sampass->private.home_dir = talloc_strdup(sampass->mem_ctx, home_dir);
+
+ if (store) {
+ DEBUG(10, ("sam_set_homedir: setting home dir sam flag!\n"));
+ sam_set_account_init_flag(sampass, FLAG_SAM_SMBHOME);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's unix home directory.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_unix_homedir(SAM_ACCOUNT_HANDLE *sampass, const char *unix_home_dir)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_unix_homedir: setting home dir %s, was %s\n", unix_home_dir,
+ sampass->private.unix_home_dir));
+
+ sampass->private.unix_home_dir = talloc_strdup(sampass->mem_ctx, unix_home_dir);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's account description.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_acct_desc(SAM_ACCOUNT_HANDLE *sampass, const char *acct_desc)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.acct_desc = talloc_strdup(sampass->mem_ctx, acct_desc);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's workstation allowed list.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_workstations(SAM_ACCOUNT_HANDLE *sampass, const char *workstations)
+{
+ SAM_ASSERT(sampass);
+
+ DEBUG(10, ("sam_set_workstations: setting workstations %s, was %s\n", workstations,
+ sampass->private.workstations));
+
+ sampass->private.workstations = talloc_strdup(sampass->mem_ctx, workstations);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's 'unknown_str', whatever the heck this actually is...
+ ********************************************************************/
+
+NTSTATUS sam_set_account_unknown_str(SAM_ACCOUNT_HANDLE *sampass, const char *unknown_str)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.unknown_str = talloc_strdup(sampass->mem_ctx, unknown_str);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's dial string.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_munged_dial(SAM_ACCOUNT_HANDLE *sampass, const char *munged_dial)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.munged_dial = talloc_strdup(sampass->mem_ctx, munged_dial);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's NT hash.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_nt_pwd(SAM_ACCOUNT_HANDLE *sampass, const DATA_BLOB data)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.nt_pw = data;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's LM hash.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_lm_pwd(SAM_ACCOUNT_HANDLE *sampass, const DATA_BLOB data)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.lm_pw = data;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's plaintext password only (base procedure, see helper
+ below)
+ ********************************************************************/
+
+NTSTATUS sam_set_account_plaintext_pwd(SAM_ACCOUNT_HANDLE *sampass, const char *plain_pwd)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.plaintext_pw = talloc_strdup(sampass->mem_ctx, plain_pwd);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_unknown_1(SAM_ACCOUNT_HANDLE *sampass, uint32 unkn)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.unknown_1 = unkn;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_unknown_2(SAM_ACCOUNT_HANDLE *sampass, uint32 unkn)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.unknown_2 = unkn;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_unknown_3(SAM_ACCOUNT_HANDLE *sampass, uint32 unkn)
+{
+ SAM_ASSERT(sampass);
+
+ sampass->private.unknown_3 = unkn;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_account_hours(SAM_ACCOUNT_HANDLE *sampass, const uint8 *hours)
+{
+ SAM_ASSERT(sampass);
+
+ if (!hours) {
+ memset ((char *)sampass->private.hours, 0, MAX_HOURS_LEN);
+ return NT_STATUS_OK;
+ }
+
+ memcpy(sampass->private.hours, hours, MAX_HOURS_LEN);
+
+ return NT_STATUS_OK;
+}
+
+/* Helpful interfaces to the above */
+
+/*********************************************************************
+ Sets the last changed times and must change times for a normal
+ password change.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_pass_changed_now(SAM_ACCOUNT_HANDLE *sampass)
+{
+ uint32 expire;
+ NTTIME temptime;
+
+ SAM_ASSERT(sampass);
+
+ unix_to_nt_time(&temptime, time(NULL));
+ if (!NT_STATUS_IS_OK(sam_set_account_pass_last_set_time(sampass, temptime)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire)
+ || (expire==(uint32)-1)) {
+
+ get_nttime_max(&temptime);
+ if (!NT_STATUS_IS_OK(sam_set_account_pass_must_change_time(sampass, temptime, False)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ } else {
+ /* FIXME: Add expire to temptime */
+
+ if (!NT_STATUS_IS_OK(sam_get_account_pass_last_set_time(sampass,&temptime)) || !NT_STATUS_IS_OK(sam_set_account_pass_must_change_time(sampass, temptime,True)))
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Set the account's PLAINTEXT password. Used as an interface to the above.
+ Also sets the last change time to NOW.
+ ********************************************************************/
+
+NTSTATUS sam_set_account_passwd(SAM_ACCOUNT_HANDLE *sampass, const char *plaintext)
+{
+ DATA_BLOB data;
+ uchar new_lanman_p16[16];
+ uchar new_nt_p16[16];
+
+ SAM_ASSERT(sampass && plaintext);
+
+ nt_lm_owf_gen(plaintext, new_nt_p16, new_lanman_p16);
+
+ data = data_blob(new_nt_p16, 16);
+ if (!NT_STATUS_IS_OK(sam_set_account_nt_pwd(sampass, data)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ data = data_blob(new_lanman_p16, 16);
+
+ if (!NT_STATUS_IS_OK(sam_set_account_lm_pwd(sampass, data)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (!NT_STATUS_IS_OK(sam_set_account_plaintext_pwd(sampass, plaintext)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (!NT_STATUS_IS_OK(sam_set_account_pass_changed_now(sampass)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source3/sam/get_set_domain.c b/source3/sam/get_set_domain.c
new file mode 100644
index 0000000000..c70a4a3f09
--- /dev/null
+++ b/source3/sam/get_set_domain.c
@@ -0,0 +1,263 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM_DOMAIN access routines
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jelmer Vernooij 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+NTSTATUS sam_get_domain_sid(SAM_DOMAIN_HANDLE *domain, const DOM_SID **sid)
+{
+ SAM_ASSERT(domain &&sid);
+
+ *sid = &(domain->private.sid);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_num_accounts(SAM_DOMAIN_HANDLE *domain, uint32 *num_accounts)
+{
+ SAM_ASSERT(domain &&num_accounts);
+
+ *num_accounts = domain->private.num_accounts;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_num_groups(SAM_DOMAIN_HANDLE *domain, uint32 *num_groups)
+{
+ SAM_ASSERT(domain &&num_groups);
+
+ *num_groups = domain->private.num_groups;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_num_aliases(SAM_DOMAIN_HANDLE *domain, uint32 *num_aliases)
+{
+ SAM_ASSERT(domain &&num_aliases);
+
+ *num_aliases = domain->private.num_aliases;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_name(SAM_DOMAIN_HANDLE *domain, const char **domain_name)
+{
+ SAM_ASSERT(domain &&domain_name);
+
+ *domain_name = domain->private.name;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_server(SAM_DOMAIN_HANDLE *domain, const char **server_name)
+{
+ SAM_ASSERT(domain &&server_name);
+
+ *server_name = domain->private.servername;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_max_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME *max_passwordage)
+{
+ SAM_ASSERT(domain &&max_passwordage);
+
+ *max_passwordage = domain->private.max_passwordage;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_min_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME *min_passwordage)
+{
+ SAM_ASSERT(domain &&min_passwordage);
+
+ *min_passwordage = domain->private.min_passwordage;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_lockout_duration(SAM_DOMAIN_HANDLE *domain, NTTIME *lockout_duration)
+{
+ SAM_ASSERT(domain &&lockout_duration);
+
+ *lockout_duration = domain->private.lockout_duration;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_reset_count(SAM_DOMAIN_HANDLE *domain, NTTIME *reset_lockout_count)
+{
+ SAM_ASSERT(domain &&reset_lockout_count);
+
+ *reset_lockout_count = domain->private.reset_count;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_min_pwdlength(SAM_DOMAIN_HANDLE *domain, uint16 *min_passwordlength)
+{
+ SAM_ASSERT(domain &&min_passwordlength);
+
+ *min_passwordlength = domain->private.min_passwordlength;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_pwd_history(SAM_DOMAIN_HANDLE *domain, uint16 *password_history)
+{
+ SAM_ASSERT(domain &&password_history);
+
+ *password_history = domain->private.password_history;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_lockout_count(SAM_DOMAIN_HANDLE *domain, uint16 *lockout_count)
+{
+ SAM_ASSERT(domain &&lockout_count);
+
+ *lockout_count = domain->private.lockout_count;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_domain_force_logoff(SAM_DOMAIN_HANDLE *domain, BOOL *force_logoff)
+{
+ SAM_ASSERT(domain &&force_logoff);
+
+ *force_logoff = domain->private.force_logoff;
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS sam_get_domain_login_pwdchange(SAM_DOMAIN_HANDLE *domain, BOOL *login_pwdchange)
+{
+ SAM_ASSERT(domain && login_pwdchange);
+
+ *login_pwdchange = domain->private.login_pwdchange;
+
+ return NT_STATUS_OK;
+}
+
+/* Set */
+
+NTSTATUS sam_set_domain_name(SAM_DOMAIN_HANDLE *domain, const char *domain_name)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.name = talloc_strdup(domain->mem_ctx, domain_name);
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS sam_set_domain_max_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME max_passwordage)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.max_passwordage = max_passwordage;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_min_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME min_passwordage)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.min_passwordage = min_passwordage;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_lockout_duration(SAM_DOMAIN_HANDLE *domain, NTTIME lockout_duration)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.lockout_duration = lockout_duration;
+
+ return NT_STATUS_OK;
+}
+NTSTATUS sam_set_domain_reset_count(SAM_DOMAIN_HANDLE *domain, NTTIME reset_lockout_count)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.reset_count = reset_lockout_count;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_min_pwdlength(SAM_DOMAIN_HANDLE *domain, uint16 min_passwordlength)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.min_passwordlength = min_passwordlength;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_pwd_history(SAM_DOMAIN_HANDLE *domain, uint16 password_history)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.password_history = password_history;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_lockout_count(SAM_DOMAIN_HANDLE *domain, uint16 lockout_count)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.lockout_count = lockout_count;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_force_logoff(SAM_DOMAIN_HANDLE *domain, BOOL force_logoff)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.force_logoff = force_logoff;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_login_pwdchange(SAM_DOMAIN_HANDLE *domain, BOOL login_pwdchange)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.login_pwdchange = login_pwdchange;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_domain_server(SAM_DOMAIN_HANDLE *domain, const char *server_name)
+{
+ SAM_ASSERT(domain);
+
+ domain->private.servername = talloc_strdup(domain->mem_ctx, server_name);
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/sam/get_set_group.c b/source3/sam/get_set_group.c
new file mode 100644
index 0000000000..11ea9258a7
--- /dev/null
+++ b/source3/sam/get_set_group.c
@@ -0,0 +1,106 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM_USER_HANDLE access routines
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jelmer Vernooij 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+/* sam group get functions */
+
+NTSTATUS sam_get_group_sid(const SAM_GROUP_HANDLE *group, const DOM_SID **sid)
+{
+ SAM_ASSERT(group && sid);
+
+ *sid = &(group->private.sid);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_group_ctrl(const SAM_GROUP_HANDLE *group, uint32 *group_ctrl)
+{
+ SAM_ASSERT(group && group_ctrl);
+
+ *group_ctrl = group->private.group_ctrl;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_get_group_name(const SAM_GROUP_HANDLE *group, const char **group_name)
+{
+ SAM_ASSERT(group);
+
+ *group_name = group->private.group_name;
+
+ return NT_STATUS_OK;
+
+}
+NTSTATUS sam_get_group_comment(const SAM_GROUP_HANDLE *group, const char **group_desc)
+{
+ SAM_ASSERT(group);
+
+ *group_desc = group->private.group_desc;
+
+ return NT_STATUS_OK;
+}
+
+/* sam group set functions */
+
+NTSTATUS sam_set_group_sid(SAM_GROUP_HANDLE *group, const DOM_SID *sid)
+{
+ SAM_ASSERT(group);
+
+ if (!sid)
+ ZERO_STRUCT(group->private.sid);
+ else
+ sid_copy(&(group->private.sid), sid);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_group_group_ctrl(SAM_GROUP_HANDLE *group, uint32 group_ctrl)
+{
+ SAM_ASSERT(group);
+
+ group->private.group_ctrl = group_ctrl;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_group_name(SAM_GROUP_HANDLE *group, const char *group_name)
+{
+ SAM_ASSERT(group);
+
+ group->private.group_name = talloc_strdup(group->mem_ctx, group_name);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS sam_set_group_description(SAM_GROUP_HANDLE *group, const char *group_desc)
+{
+ SAM_ASSERT(group);
+
+ group->private.group_desc = talloc_strdup(group->mem_ctx, group_desc);
+
+ return NT_STATUS_OK;
+
+}
diff --git a/source3/sam/group.c b/source3/sam/group.c
new file mode 100644
index 0000000000..7e4bcc1425
--- /dev/null
+++ b/source3/sam/group.c
@@ -0,0 +1,193 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM_GROUP_HANDLE /SAM_GROUP_ENUM helpers
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+/************************************************************
+ Fill the SAM_GROUP_HANDLE with default values.
+ ***********************************************************/
+
+static void sam_fill_default_group(SAM_GROUP_HANDLE *group)
+{
+ ZERO_STRUCT(group->private); /* Don't touch the talloc context */
+
+}
+
+static void destroy_sam_group_handle_talloc(SAM_GROUP_HANDLE **group)
+{
+ if (*group) {
+
+ talloc_destroy((*group)->mem_ctx);
+ *group = NULL;
+ }
+}
+
+
+/**********************************************************************
+ Alloc memory and initialises a SAM_GROUP_HANDLE on supplied mem_ctx.
+***********************************************************************/
+
+NTSTATUS sam_init_group_talloc(TALLOC_CTX *mem_ctx, SAM_GROUP_HANDLE **group)
+{
+ SMB_ASSERT(*group != NULL);
+
+ if (!mem_ctx) {
+ DEBUG(0,("sam_init_group_talloc: mem_ctx was NULL!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *group=(SAM_GROUP_HANDLE *)talloc(mem_ctx, sizeof(SAM_GROUP_HANDLE));
+
+ if (*group==NULL) {
+ DEBUG(0,("sam_init_group_talloc: error while allocating memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*group)->mem_ctx = mem_ctx;
+
+ (*group)->free_fn = NULL;
+
+ sam_fill_default_group(*group);
+
+ return NT_STATUS_OK;
+}
+
+
+/*************************************************************
+ Alloc memory and initialises a struct SAM_GROUP_HANDLE.
+ ************************************************************/
+
+NTSTATUS sam_init_group(SAM_GROUP_HANDLE **group)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS nt_status;
+
+ mem_ctx = talloc_init_named("sam internal SAM_GROUP_HANDLE allocation");
+
+ if (!mem_ctx) {
+ DEBUG(0,("sam_init_group: error while doing talloc_init()\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_init_group_talloc(mem_ctx, group))) {
+ talloc_destroy(mem_ctx);
+ return nt_status;
+ }
+
+ (*group)->free_fn = destroy_sam_group_handle_talloc;
+
+ return NT_STATUS_OK;
+}
+
+
+/************************************************************
+ Reset the SAM_GROUP_HANDLE.
+ ***********************************************************/
+
+NTSTATUS sam_reset_group(SAM_GROUP_HANDLE *group)
+{
+ SMB_ASSERT(group != NULL);
+
+ sam_fill_default_group(group);
+
+ return NT_STATUS_OK;
+}
+
+
+/************************************************************
+ Free the SAM_GROUP_HANDLE and the member pointers.
+ ***********************************************************/
+
+NTSTATUS sam_free_group(SAM_ACCOUNT_HANDLE **group)
+{
+ SMB_ASSERT(*group != NULL);
+
+ if ((*group)->free_fn) {
+ (*group)->free_fn(group);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/**********************************************************
+ Encode the group control bits into a string.
+ length = length of string to encode into (including terminating
+ null). length *MUST BE MORE THAN 2* !
+ **********************************************************/
+
+char *sam_encode_acct_ctrl(uint16 group_ctrl, size_t length)
+{
+ static fstring group_str;
+ size_t i = 0;
+
+ group_str[i++] = '[';
+
+ if (group_ctrl & GCB_LOCAL_GROUP ) group_str[i++] = 'L';
+ if (group_ctrl & GCB_GLOBAL_GROUP ) group_str[i++] = 'G';
+
+ for ( ; i < length - 2 ; i++ )
+ group_str[i] = ' ';
+
+ i = length - 2;
+ group_str[i++] = ']';
+ group_str[i++] = '\0';
+
+ return group_str;
+}
+
+/**********************************************************
+ Decode the group control bits from a string.
+ **********************************************************/
+
+uint16 sam_decode_group_ctrl(const char *p)
+{
+ uint16 group_ctrl = 0;
+ BOOL finished = False;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[')
+ return 0;
+
+ for (p++; *p && !finished; p++) {
+ switch (*p) {
+ case 'L': { group_ctrl |= GCB_LOCAL_GROUP; break; /* 'L'ocal Aliases Group. */ }
+ case 'G': { group_ctrl |= GCB_GLOBAL_GROUP; break; /* 'G'lobal Domain Group. */ }
+
+ case ' ': { break; }
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default: { finished = True; }
+ }
+ }
+
+ return group_ctrl;
+}
+
diff --git a/source3/sam/interface.c b/source3/sam/interface.c
new file mode 100644
index 0000000000..bb7b88b240
--- /dev/null
+++ b/source3/sam/interface.c
@@ -0,0 +1,1238 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Kai Krüger 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+extern DOM_SID global_sid_Builtin;
+
+/** List of various built-in sam modules */
+
+const struct sam_init_function_entry builtin_sam_init_functions[] = {
+ { "plugin", sam_init_plugin },
+ { NULL, NULL}
+};
+
+/******************************************************************
+ context_sam_* functions are used to link the external SAM interface
+ with the internal backends. These functions lookup the appropriate
+ backends for the domain and pass on to the function in sam_methods
+ in the selected backend
+ *******************************************************************/
+
+NTSTATUS sam_get_methods_by_sid(const SAM_CONTEXT *context, SAM_METHODS **sam_method, const DOM_SID *domainsid)
+{
+ SAM_METHODS *tmp_methods;
+
+ DEBUG(5,("sam_get_methods_by_sid: %d\n", __LINE__));
+
+ /* invalid sam_context specified */
+ SAM_ASSERT(context && context->methods);
+
+ tmp_methods = context->methods;
+
+ while (tmp_methods) {
+ if (sid_equal(domainsid, &(tmp_methods->domain_sid)))
+ {
+ (*sam_method) = tmp_methods;
+ return NT_STATUS_OK;
+ }
+ tmp_methods = tmp_methods->next;
+ }
+
+ DEBUG(3,("sam_get_methods_by_sid: There is no backend specified for domain %s\n", sid_string_static(domainsid)));
+
+ return NT_STATUS_NO_SUCH_DOMAIN;
+}
+
+NTSTATUS sam_get_methods_by_name(const SAM_CONTEXT *context, SAM_METHODS **sam_method, const char *domainname)
+{
+ SAM_METHODS *tmp_methods;
+
+ DEBUG(5,("sam_get_methods_by_name: %d\n", __LINE__));
+
+ /* invalid sam_context specified */
+ SAM_ASSERT(context && context->methods);
+
+ tmp_methods = context->methods;
+
+ while (tmp_methods) {
+ if (!strcmp(domainname, tmp_methods->domain_name))
+ {
+ (*sam_method) = tmp_methods;
+ return NT_STATUS_OK;
+ }
+ tmp_methods = tmp_methods->next;
+ }
+
+ DEBUG(3,("sam_get_methods_by_sid: There is no backend specified for domain %s\n", domainname));
+
+ return NT_STATUS_NO_SUCH_DOMAIN;
+}
+
+NTSTATUS context_sam_get_sec_desc(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_get_sec_desc: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, sid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_get_sec_desc) {
+ DEBUG(3, ("context_sam_get_sec_desc: sam_methods of the domain did not specify sam_get_sec_desc\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_sec_desc(tmp_methods, access_token, sid, sd))) {
+ DEBUG(4,("sam_get_sec_desc for %s in backend %s failed\n", sid_string_static(sid), tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_set_sec_desc(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_set_sec_desc: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, sid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_set_sec_desc) {
+ DEBUG(3, ("context_sam_set_sec_desc: sam_methods of the domain did not specify sam_set_sec_desc\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_set_sec_desc(tmp_methods, access_token, sid, sd))) {
+ DEBUG(4,("sam_set_sec_desc for %s in backend %s failed\n", sid_string_static(sid), tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS context_sam_lookup_name(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const char *domain, const char *name, DOM_SID **sid, uint32 *type)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_lookup_name: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_name(context, &tmp_methods, domain))) {
+ DEBUG(4,("sam_get_methods_by_name failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_lookup_name) {
+ DEBUG(3, ("context_sam_lookup_name: sam_methods of the domain did not specify sam_lookup_name\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_lookup_name(tmp_methods, access_token, name, sid, type))) {
+ DEBUG(4,("sam_lookup_name for %s\\%s in backend %s failed\n",
+ tmp_methods->domain_name, name, tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_lookup_sid(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type)
+{
+ SAM_METHODS *tmp_methods;
+ uint32 rid;
+ NTSTATUS nt_status;
+ DOM_SID domainsid;
+
+ DEBUG(5,("context_sam_lookup_sid: %d\n", __LINE__));
+
+ sid_copy(&domainsid, sid);
+ if (!sid_split_rid(&domainsid, &rid)) {
+ DEBUG(3,("context_sam_lookup_sid: failed to split the sid\n"));
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, &domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_lookup_sid) {
+ DEBUG(3, ("context_sam_lookup_sid: sam_methods of the domain did not specify sam_lookup_sid\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_lookup_sid(tmp_methods, access_token, sid, name, type))) {
+ DEBUG(4,("sam_lookup_name for %s in backend %s failed\n",
+ sid_string_static(sid), tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS context_sam_update_domain(const SAM_CONTEXT *context, const SAM_DOMAIN_HANDLE *domain)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_update_domain: %d\n", __LINE__));
+
+ /* invalid domain specified */
+ SAM_ASSERT(domain && domain->current_sam_methods);
+
+ tmp_methods = domain->current_sam_methods;
+
+ if (!tmp_methods->sam_update_domain) {
+ DEBUG(3, ("context_sam_update_domain: sam_methods of the domain did not specify sam_update_domain\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_update_domain(tmp_methods, domain))){
+ DEBUG(4,("sam_update_domain in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_enum_domains(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, int32 *domain_count, DOM_SID **domains, char ***domain_names)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ SEC_DESC *sd;
+ size_t sd_size;
+ uint32 acc_granted;
+ int i = 0;
+
+ DEBUG(5,("context_sam_enum_domains: %d\n", __LINE__));
+
+ /* invalid sam_context specified */
+ SAM_ASSERT(context && context->methods);
+
+ if (!NT_STATUS_IS_OK(nt_status = samr_make_sam_obj_sd(context->mem_ctx, &sd, &sd_size))) {
+ DEBUG(4,("samr_make_sam_obj_sd failed\n"));
+ return nt_status;
+ }
+
+ if (!se_access_check(sd, access_token, SAMR_ACCESS_ENUM_DOMAINS, &acc_granted, &nt_status)) {
+ DEBUG(3,("context_sam_enum_domains: ACCESS DENIED\n"));
+ return nt_status;
+ }
+
+ tmp_methods= context->methods;
+ *domain_count = 0;
+
+ while (tmp_methods) {
+ (*domain_count)++;
+ tmp_methods= tmp_methods->next;
+ }
+
+ DEBUG(6,("context_sam_enum_domains: enumerating %d domains\n", (*domain_count)));
+
+ tmp_methods = context->methods;
+
+ if (((*domains) = malloc( sizeof(DOM_SID) * (*domain_count))) == NULL) {
+ DEBUG(0,("context_sam_enum_domains: Out of memory allocating domain SID list\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (((*domain_names) = malloc( sizeof(char*) * (*domain_count))) == NULL) {
+ DEBUG(0,("context_sam_enum_domains: Out of memory allocating domain name list\n"));
+ SAFE_FREE((*domains));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (tmp_methods) {
+ DEBUGADD(7,(" [%d] %s: %s\n", i, tmp_methods->domain_name, sid_string_static(&tmp_methods->domain_sid)));
+ sid_copy(domains[i],&tmp_methods->domain_sid);
+ *domain_names[i] = smb_xstrdup(tmp_methods->domain_name);
+ i++;
+ tmp_methods= tmp_methods->next;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_lookup_domain(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const char *domain, DOM_SID **domainsid)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ SEC_DESC *sd;
+ size_t sd_size;
+ uint32 acc_granted;
+
+ DEBUG(5,("context_sam_lookup_domain: %d\n", __LINE__));
+
+ /* invalid sam_context specified */
+ SAM_ASSERT(context && context->methods);
+
+ if (!NT_STATUS_IS_OK(nt_status = samr_make_sam_obj_sd(context->mem_ctx, &sd, &sd_size))) {
+ DEBUG(4,("samr_make_sam_obj_sd failed\n"));
+ return nt_status;
+ }
+
+ if (!se_access_check(sd, access_token, SAMR_ACCESS_OPEN_DOMAIN, &acc_granted, &nt_status)) {
+ DEBUG(3,("context_sam_lookup_domain: ACCESS DENIED\n"));
+ return nt_status;
+ }
+
+ tmp_methods= context->methods;
+
+ while (tmp_methods) {
+ if (strcmp(domain, tmp_methods->domain_name) == 0) {
+ sid_copy((*domainsid), &tmp_methods->domain_sid);
+ return NT_STATUS_OK;
+ }
+ tmp_methods= tmp_methods->next;
+ }
+
+ return NT_STATUS_NO_SUCH_DOMAIN;
+}
+
+
+NTSTATUS context_sam_get_domain_by_sid(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, SAM_DOMAIN_HANDLE **domain)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_get_domain_by_sid: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_get_domain_handle) {
+ DEBUG(3, ("context_sam_get_domain_by_sid: sam_methods of the domain did not specify sam_get_domain_handle\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_domain_handle(tmp_methods, access_token, access_desired, domain))) {
+ DEBUG(4,("sam_get_domain_handle for %s in backend %s failed\n",
+ sid_string_static(domainsid), tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_create_account(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_create_account: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_create_account) {
+ DEBUG(3, ("context_sam_create_account: sam_methods of the domain did not specify sam_create_account\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_create_account(tmp_methods, access_token, access_desired, account_name, acct_ctrl, account))) {
+ DEBUG(4,("sam_create_account in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_add_account(const SAM_CONTEXT *context, const SAM_ACCOUNT_HANDLE *account)
+{
+ DOM_SID domainsid;
+ const DOM_SID *accountsid;
+ SAM_METHODS *tmp_methods;
+ uint32 rid;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_add_account: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_account_sid(account, &accountsid))) {
+ DEBUG(0,("Can't get account SID\n"));
+ return nt_status;
+ }
+
+ sid_copy(&domainsid, accountsid);
+ if (!sid_split_rid(&domainsid, &rid)) {
+ DEBUG(3,("context_sam_get_account_by_sid: failed to split the sid\n"));
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, &domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_add_account) {
+ DEBUG(3, ("context_sam_add_account: sam_methods of the domain did not specify sam_add_account\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_add_account(tmp_methods, account))){
+ DEBUG(4,("sam_add_account in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_update_account(const SAM_CONTEXT *context, const SAM_ACCOUNT_HANDLE *account)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_update_account: %d\n", __LINE__));
+
+ /* invalid account specified */
+ SAM_ASSERT(account && account->current_sam_methods);
+
+ tmp_methods = account->current_sam_methods;
+
+ if (!tmp_methods->sam_update_account) {
+ DEBUG(3, ("context_sam_update_account: sam_methods of the domain did not specify sam_update_account\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_update_account(tmp_methods, account))){
+ DEBUG(4,("sam_update_account in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_delete_account(const SAM_CONTEXT *context, const SAM_ACCOUNT_HANDLE *account)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_delete_account: %d\n", __LINE__));
+
+ /* invalid account specified */
+ SAM_ASSERT(account && account->current_sam_methods);
+
+ tmp_methods = account->current_sam_methods;
+
+ if (!tmp_methods->sam_delete_account) {
+ DEBUG(3, ("context_sam_delete_account: sam_methods of the domain did not specify sam_delete_account\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_delete_account(tmp_methods, account))){
+ DEBUG(4,("sam_delete_account in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_enum_accounts(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const DOM_SID *domainsid, uint16 acct_ctrl, int32 *account_count, SAM_ACCOUNT_ENUM **accounts)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_enum_accounts: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_enum_accounts) {
+ DEBUG(3, ("context_sam_enum_accounts: sam_methods of the domain did not specify sam_enum_accounts\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_enum_accounts(tmp_methods, access_token, acct_ctrl, account_count, accounts))) {
+ DEBUG(4,("sam_enum_accounts for domain %s in backend %s failed\n",
+ tmp_methods->domain_name, tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS context_sam_get_account_by_sid(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account)
+{
+ SAM_METHODS *tmp_methods;
+ uint32 rid;
+ DOM_SID domainsid;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_get_account_by_sid: %d\n", __LINE__));
+
+ sid_copy(&domainsid, accountsid);
+ if (!sid_split_rid(&domainsid, &rid)) {
+ DEBUG(3,("context_sam_get_account_by_sid: failed to split the sid\n"));
+ return NT_STATUS_INVALID_SID;
+ }
+
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, &domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_get_account_by_sid) {
+ DEBUG(3, ("context_sam_get_account_by_sid: sam_methods of the domain did not specify sam_get_account_by_sid\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_account_by_sid(tmp_methods, access_token, access_desired, accountsid, account))) {
+ DEBUG(4,("sam_get_account_by_sid for %s in backend %s failed\n",
+ sid_string_static(accountsid), tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_get_account_by_name(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain, const char *name, SAM_ACCOUNT_HANDLE **account)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_get_account_by_name: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_name(context, &tmp_methods, domain))) {
+ DEBUG(4,("sam_get_methods_by_name failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_get_account_by_name) {
+ DEBUG(3, ("context_sam_get_account_by_name: sam_methods of the domain did not specify sam_get_account_by_name\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_account_by_name(tmp_methods, access_token, access_desired, name, account))) {
+ DEBUG(4,("sam_get_account_by_name for %s\\%s in backend %s failed\n",
+ domain, name, tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_create_group(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_create_group: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_create_group) {
+ DEBUG(3, ("context_sam_create_group: sam_methods of the domain did not specify sam_create_group\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_create_group(tmp_methods, access_token, access_desired, group_name, group_ctrl, group))) {
+ DEBUG(4,("sam_create_group in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_add_group(const SAM_CONTEXT *context, const SAM_GROUP_HANDLE *group)
+{
+ DOM_SID domainsid;
+ const DOM_SID *groupsid;
+ SAM_METHODS *tmp_methods;
+ uint32 rid;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_add_group: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_group_sid(group, &groupsid))) {
+ DEBUG(0,("Can't get group SID\n"));
+ return nt_status;
+ }
+
+ sid_copy(&domainsid, groupsid);
+ if (!sid_split_rid(&domainsid, &rid)) {
+ DEBUG(3,("context_sam_get_group_by_sid: failed to split the sid\n"));
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, &domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_add_group) {
+ DEBUG(3, ("context_sam_add_group: sam_methods of the domain did not specify sam_add_group\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_add_group(tmp_methods, group))){
+ DEBUG(4,("sam_add_group in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_update_group(const SAM_CONTEXT *context, const SAM_GROUP_HANDLE *group)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_update_group: %d\n", __LINE__));
+
+ /* invalid group specified */
+ SAM_ASSERT(group && group->current_sam_methods);
+
+ tmp_methods = group->current_sam_methods;
+
+ if (!tmp_methods->sam_update_group) {
+ DEBUG(3, ("context_sam_update_group: sam_methods of the domain did not specify sam_update_group\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_update_group(tmp_methods, group))){
+ DEBUG(4,("sam_update_group in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_delete_group(const SAM_CONTEXT *context, const SAM_GROUP_HANDLE *group)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_delete_group: %d\n", __LINE__));
+
+ /* invalid group specified */
+ SAM_ASSERT(group && group->current_sam_methods);
+
+ tmp_methods = group->current_sam_methods;
+
+ if (!tmp_methods->sam_delete_group) {
+ DEBUG(3, ("context_sam_delete_group: sam_methods of the domain did not specify sam_delete_group\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_delete_group(tmp_methods, group))){
+ DEBUG(4,("sam_delete_group in backend %s failed\n",
+ tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_enum_groups(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const DOM_SID *domainsid, uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_enum_groups: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_enum_accounts) {
+ DEBUG(3, ("context_sam_enum_groups: sam_methods of the domain did not specify sam_enum_groups\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_enum_groups(tmp_methods, access_token, group_ctrl, groups_count, groups))) {
+ DEBUG(4,("sam_enum_groups for domain %s in backend %s failed\n",
+ tmp_methods->domain_name, tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_get_group_by_sid(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group)
+{
+ SAM_METHODS *tmp_methods;
+ uint32 rid;
+ NTSTATUS nt_status;
+ DOM_SID domainsid;
+
+ DEBUG(5,("context_sam_get_group_by_sid: %d\n", __LINE__));
+
+ sid_copy(&domainsid, groupsid);
+ if (!sid_split_rid(&domainsid, &rid)) {
+ DEBUG(3,("context_sam_get_group_by_sid: failed to split the sid\n"));
+ return NT_STATUS_INVALID_SID;
+ }
+
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_sid(context, &tmp_methods, &domainsid))) {
+ DEBUG(4,("sam_get_methods_by_sid failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_get_group_by_sid) {
+ DEBUG(3, ("context_sam_get_group_by_sid: sam_methods of the domain did not specify sam_get_group_by_sid\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_group_by_sid(tmp_methods, access_token, access_desired, groupsid, group))) {
+ DEBUG(4,("sam_get_group_by_sid for %s in backend %s failed\n",
+ sid_string_static(groupsid), tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_get_group_by_name(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain, const char *name, SAM_GROUP_HANDLE **group)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ DEBUG(5,("context_sam_get_group_by_name: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = sam_get_methods_by_name(context, &tmp_methods, domain))) {
+ DEBUG(4,("sam_get_methods_by_name failed\n"));
+ return nt_status;
+ }
+
+ if (!tmp_methods->sam_get_group_by_name) {
+ DEBUG(3, ("context_sam_get_group_by_name: sam_methods of the domain did not specify sam_get_group_by_name\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_group_by_name(tmp_methods, access_token, access_desired, name, group))) {
+ DEBUG(4,("sam_get_group_by_name for %s\\%s in backend %s failed\n",
+ domain, name, tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_add_member_to_group(const SAM_CONTEXT *context, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+
+ /* invalid group or member specified */
+ SAM_ASSERT(group && group->current_sam_methods && member);
+
+ tmp_methods = group->current_sam_methods;
+
+ if (!tmp_methods->sam_add_member_to_group) {
+ DEBUG(3, ("context_sam_add_member_to_group: sam_methods of the domain did not specify sam_add_member_to_group\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_add_member_to_group(tmp_methods, group, member))) {
+ DEBUG(4,("sam_add_member_to_group in backend %s failed\n", tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+
+}
+
+NTSTATUS context_sam_delete_member_from_group(const SAM_CONTEXT *context, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ /* invalid group or member specified */
+ SAM_ASSERT(group && group->current_sam_methods &&member);
+
+ tmp_methods = group->current_sam_methods;
+
+ if (!tmp_methods->sam_delete_member_from_group) {
+ DEBUG(3, ("context_sam_delete_member_from_group: sam_methods of the domain did not specify sam_delete_member_from_group\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_delete_member_from_group(tmp_methods, group, member))) {
+ DEBUG(4,("sam_delete_member_from_group in backend %s failed\n", tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_enum_groupmembers(const SAM_CONTEXT *context, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members)
+{
+ const SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ /* invalid group specified */
+ SAM_ASSERT(group && group->current_sam_methods);
+
+ tmp_methods = group->current_sam_methods;
+
+ if (!tmp_methods->sam_enum_groupmembers) {
+ DEBUG(3, ("context_sam_enum_groupmembers: sam_methods of the domain did not specify sam_enum_group_members\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_enum_groupmembers(tmp_methods, group, members_count, members))) {
+ DEBUG(4,("sam_enum_groupmembers in backend %s failed\n", tmp_methods->backendname));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS context_sam_get_groups_of_sid(const SAM_CONTEXT *context, const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups)
+{
+ SAM_METHODS *tmp_methods;
+ NTSTATUS nt_status;
+
+ uint32 tmp_group_count;
+ SAM_GROUP_ENUM *tmp_groups;
+
+ DEBUG(5,("context_sam_get_groups_of_sid: %d\n", __LINE__));
+
+ /* invalid sam_context specified */
+ SAM_ASSERT(context && context->methods);
+
+ *group_count = 0;
+
+ *groups = NULL;
+
+ tmp_methods= context->methods;
+
+ while (tmp_methods) {
+ DEBUG(5,("getting groups from domain \n"));
+ if (!tmp_methods->sam_get_groups_of_sid) {
+ DEBUG(3, ("context_sam_get_groups_of_sid: sam_methods of domain did not specify sam_get_groups_of_sid\n"));
+ SAFE_FREE(*groups);
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = tmp_methods->sam_get_groups_of_sid(tmp_methods, access_token, sids, group_ctrl, &tmp_group_count, &tmp_groups))) {
+ DEBUG(4,("sam_get_groups_of_sid in backend %s failed\n", tmp_methods->backendname));
+ SAFE_FREE(*groups);
+ return nt_status;
+ }
+
+ *groups = Realloc(*groups, ((*group_count) + tmp_group_count) * sizeof(SAM_GROUP_ENUM));
+
+ memcpy(&(*groups)[*group_count], tmp_groups, tmp_group_count);
+
+ SAFE_FREE(tmp_groups);
+
+ *group_count += tmp_group_count;
+
+ tmp_methods = tmp_methods->next;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/******************************************************************
+ Free and cleanup a sam context, any associated data and anything
+ that the attached modules might have associated.
+ *******************************************************************/
+
+void free_sam_context(SAM_CONTEXT **context)
+{
+ SAM_METHODS *sam_selected = (*context)->methods;
+
+ while (sam_selected) {
+ if (sam_selected->free_private_data) {
+ sam_selected->free_private_data(&(sam_selected->private_data));
+ }
+ sam_selected = sam_selected->next;
+ }
+
+ talloc_destroy((*context)->mem_ctx);
+ *context = NULL;
+}
+
+/******************************************************************
+ Make a sam_methods from scratch
+ *******************************************************************/
+
+static NTSTATUS make_backend_entry(SAM_BACKEND_ENTRY *backend_entry, char *sam_backend_string)
+{
+ char *tmp = NULL;
+ char *tmp_string = sam_backend_string;
+
+ DEBUG(5,("make_backend_entry: %d\n", __LINE__));
+
+ SAM_ASSERT(sam_backend_string && backend_entry);
+
+ backend_entry->module_name = sam_backend_string;
+
+ DEBUG(5,("makeing backend_entry for %s\n", backend_entry->module_name));
+
+ if ((tmp = strchr(tmp_string, '|')) != NULL) {
+ DEBUGADD(20,("a domain name has been specified\n"));
+ *tmp = 0;
+ backend_entry->domain_name = tmp + 1;
+ tmp_string = tmp + 1;
+ }
+
+ if ((tmp = strchr(tmp_string, ':')) != NULL) {
+ DEBUG(20,("options for the backend have been specified\n"));
+ *tmp = 0;
+ backend_entry->module_params = tmp + 1;
+ tmp_string = tmp + 1;
+ }
+
+ if (backend_entry->domain_name == NULL) {
+ DEBUG(10,("make_backend_entry: no domain was specified for sam module %s. Useing default domain %s\n",
+ backend_entry->module_name, lp_workgroup()));
+ backend_entry->domain_name = lp_workgroup();
+ }
+
+ if ((backend_entry->domain_sid = (DOM_SID *)malloc(sizeof(DOM_SID))) == NULL) {
+ DEBUG(0,("make_backend_entry: failed to malloc domain_sid\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(10,("looking up sid for domain %s\n", backend_entry->domain_name));
+
+ if (!secrets_fetch_domain_sid(backend_entry->domain_name, backend_entry->domain_sid)) {
+ DEBUG(2,("make_backend_entry: There is no SID stored for domain %s. Creating a new one.\n",
+ backend_entry->domain_name));
+ /* FIXME */
+ ZERO_STRUCTP(backend_entry->domain_sid);
+ }
+
+ DEBUG(5,("make_backend_entry: module name: %s, module parameters: %s, domain name: %s, domain sid: %s\n",
+ backend_entry->module_name, backend_entry->module_params, backend_entry->domain_name, sid_string_static(backend_entry->domain_sid)));
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************
+ create sam_methods struct based on sam_backend_entry
+ *****************************************************************/
+
+static NTSTATUS make_sam_methods_backend_entry(SAM_CONTEXT *context, SAM_METHODS **methods_ptr, SAM_BACKEND_ENTRY *backend_entry)
+{
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ SAM_METHODS *methods;
+ int i;
+
+ DEBUG(5,("make_sam_methods_backend_entry: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = make_sam_methods(context->mem_ctx, methods_ptr))) {
+ return nt_status;
+ }
+
+ methods = *methods_ptr;
+ methods->backendname = talloc_strdup(context->mem_ctx, backend_entry->module_name);
+ methods->domain_name = talloc_strdup(context->mem_ctx, backend_entry->domain_name);
+ sid_copy(&methods->domain_sid, backend_entry->domain_sid);
+ methods->parent = context;
+
+ DEBUG(5,("Attempting to find sam backend %s\n", backend_entry->module_name));
+ for (i = 0; builtin_sam_init_functions[i].module_name; i++)
+ {
+ if (strequal(builtin_sam_init_functions[i].module_name, backend_entry->module_name))
+ {
+ DEBUG(5,("Found sam backend %s (at pos %d)\n", backend_entry->module_name, i));
+ DEBUGADD(5,("initialising it with options=%s for domain %s\n", backend_entry->module_params, sid_string_static(backend_entry->domain_sid)));
+ nt_status = builtin_sam_init_functions[i].init(methods, backend_entry->module_params);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5,("sam backend %s has a valid init\n", backend_entry->module_name));
+ } else {
+ DEBUG(2,("sam backend %s did not correctly init (error was %s)\n",
+ backend_entry->module_name, nt_errstr(nt_status)));
+ }
+ return nt_status;
+ }
+ }
+
+ DEBUG(2,("could not find backend %s\n", backend_entry->module_name));
+
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+static NTSTATUS sam_context_check_default_backends(SAM_CONTEXT *context)
+{
+ SAM_BACKEND_ENTRY entry;
+ DOM_SID *global_sam_sid = get_global_sam_sid(); /* lp_workgroup doesn't play nicely with multiple domains */
+ SAM_METHODS *methods, *tmpmethods;
+ NTSTATUS ntstatus;
+
+ DEBUG(5,("sam_context_check_default_backends: %d\n", __LINE__));
+
+ /* Make sure domain lp_workgroup() is available */
+
+ ntstatus = sam_get_methods_by_sid(context, &methods, &global_sid_Builtin);
+
+ if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_NO_SUCH_DOMAIN)) {
+ DEBUG(4,("There was no backend specified for domain %s; using %s\n",
+ lp_workgroup(), SAM_DEFAULT_BACKEND));
+
+ SAM_ASSERT(global_sam_sid);
+
+ entry.module_name = SAM_DEFAULT_BACKEND;
+ entry.module_params = NULL;
+ entry.domain_name = lp_workgroup();
+ entry.domain_sid = (DOM_SID *)malloc(sizeof(DOM_SID));
+ sid_copy(entry.domain_sid, global_sam_sid);
+
+ if (!NT_STATUS_IS_OK(ntstatus = make_sam_methods_backend_entry(context, &methods, &entry))) {
+ DEBUG(4,("make_sam_methods_backend_entry failed\n"));
+ return ntstatus;
+ }
+
+ DLIST_ADD_END(context->methods, methods, tmpmethods);
+
+ } else if (!NT_STATUS_IS_OK(ntstatus)) {
+ DEBUG(2, ("sam_get_methods_by_sid failed for %s\n", lp_workgroup()));
+ return ntstatus;
+ }
+
+ /* Make sure the BUILTIN domain is available */
+
+ ntstatus = sam_get_methods_by_sid(context, &methods, global_sam_sid);
+
+ if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_NO_SUCH_DOMAIN)) {
+ DEBUG(4,("There was no backend specified for domain BUILTIN; using %s\n",
+ SAM_DEFAULT_BACKEND));
+ entry.module_name = SAM_DEFAULT_BACKEND;
+ entry.module_params = NULL;
+ entry.domain_name = "BUILTIN";
+ entry.domain_sid = (DOM_SID *)malloc(sizeof(DOM_SID));
+ sid_copy(entry.domain_sid, &global_sid_Builtin);
+
+ if (!NT_STATUS_IS_OK(ntstatus = make_sam_methods_backend_entry(context, &methods, &entry))) {
+ DEBUG(4,("make_sam_methods_backend_entry failed\n"));
+ return ntstatus;
+ }
+
+ DLIST_ADD_END(context->methods, methods, tmpmethods);
+ } else if (!NT_STATUS_IS_OK(ntstatus)) {
+ DEBUG(2, ("sam_get_methods_by_sid failed for BUILTIN\n"));
+ return ntstatus;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS check_duplicate_backend_entries(SAM_BACKEND_ENTRY **backend_entries, int *nBackends)
+{
+ int i, j;
+
+ DEBUG(5,("check_duplicate_backend_entries: %d\n", __LINE__));
+
+ for (i = 0; i < *nBackends; i++) {
+ for (j = i + 1; j < *nBackends; j++) {
+ if (sid_equal((*backend_entries)[i].domain_sid, (*backend_entries)[j].domain_sid)) {
+ DEBUG(0,("two backend modules claim the same domain %s\n",
+ sid_string_static((*backend_entries)[j].domain_sid)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS make_sam_context_list(SAM_CONTEXT **context, char **sam_backends_param)
+{
+ int i = 0, j = 0;
+ SAM_METHODS *curmethods, *tmpmethods;
+ int nBackends = 0;
+ SAM_BACKEND_ENTRY *backends = NULL;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ DEBUG(5,("make_sam_context_from_conf: %d\n", __LINE__));
+
+ if (!NT_STATUS_IS_OK(nt_status = make_sam_context(context))) {
+ DEBUG(4,("make_sam_context failed\n"));
+ return nt_status;
+ }
+
+ while (sam_backends_param[nBackends])
+ nBackends++;
+
+ DEBUG(6,("There are %d domains listed with there backends\n", nBackends));
+
+ if ((backends = (SAM_BACKEND_ENTRY *)malloc(sizeof(SAM_BACKEND_ENTRY)*nBackends)) == NULL) {
+ DEBUG(0,("make_sam_context_list: failed to allocate backends\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(backends);
+
+ for (i = 0; i < nBackends; i++) {
+ DEBUG(8,("processing %s\n",sam_backends_param[i]));
+ if (!NT_STATUS_IS_OK(nt_status = make_backend_entry(&backends[i], sam_backends_param[i]))) {
+ DEBUG(4,("make_backend_entry failed\n"));
+ for (j = 0; j < nBackends; j++) SAFE_FREE(backends[j].domain_sid);
+ SAFE_FREE(backends);
+ free_sam_context(context);
+ return nt_status;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = check_duplicate_backend_entries(&backends, &nBackends))) {
+ DEBUG(4,("check_duplicate_backend_entries failed\n"));
+ for (j = 0; j < nBackends; j++) SAFE_FREE(backends[j].domain_sid);
+ SAFE_FREE(backends);
+ free_sam_context(context);
+ return nt_status;
+ }
+
+ for (i = 0; i < nBackends; i++) {
+ if (!NT_STATUS_IS_OK(nt_status = make_sam_methods_backend_entry(*context, &curmethods, &backends[i]))) {
+ DEBUG(4,("make_sam_methods_backend_entry failed\n"));
+ for (j = 0; j < nBackends; j++) SAFE_FREE(backends[j].domain_sid);
+ SAFE_FREE(backends);
+ free_sam_context(context);
+ return nt_status;
+ }
+ DLIST_ADD_END((*context)->methods, curmethods, tmpmethods);
+ }
+
+ for (i = 0; i < nBackends; i++) SAFE_FREE(backends[i].domain_sid);
+
+ SAFE_FREE(backends);
+ return NT_STATUS_OK;
+}
+
+/******************************************************************
+ Make a sam_context from scratch.
+ *******************************************************************/
+
+NTSTATUS make_sam_context(SAM_CONTEXT **context)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init_named("sam_context internal allocation context");
+
+ if (!mem_ctx) {
+ DEBUG(0, ("make_sam_context: talloc init failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *context = talloc(mem_ctx, sizeof(**context));
+ if (!*context) {
+ DEBUG(0, ("make_sam_context: talloc failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*context);
+
+ (*context)->mem_ctx = mem_ctx;
+
+ /* FIXME */
+
+ (*context)->free_fn = free_sam_context;
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************
+ Return an already initialised sam_context, to facilitate backward
+ compatibility (see functions below).
+ *******************************************************************/
+
+struct sam_context *sam_get_static_context(BOOL reload)
+{
+ static SAM_CONTEXT *sam_context = NULL;
+
+ if ((sam_context) && (reload)) {
+ sam_context->free_fn(&sam_context);
+ sam_context = NULL;
+ }
+
+ if (!sam_context) {
+ if (!NT_STATUS_IS_OK(make_sam_context_list(&sam_context, lp_sam_backend()))) {
+ DEBUG(4,("make_sam_context_list failed\n"));
+ return NULL;
+ }
+
+ /* Make sure the required domains (default domain, builtin) are available */
+ if (!NT_STATUS_IS_OK(sam_context_check_default_backends(sam_context))) {
+ DEBUG(4,("sam_context_check_default_backends failed\n"));
+ return NULL;
+ }
+ }
+
+ return sam_context;
+}
+
+/***************************************************************
+ Initialize the static context (at smbd startup etc).
+
+ If uninitialised, context will auto-init on first use.
+ ***************************************************************/
+
+BOOL initialize_sam(BOOL reload)
+{
+ return (sam_get_static_context(reload) != NULL);
+}
+
+
+NTSTATUS make_sam_methods(TALLOC_CTX *mem_ctx, SAM_METHODS **methods)
+{
+ *methods = talloc(mem_ctx, sizeof(SAM_METHODS));
+
+ if (!*methods) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*methods);
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/sam/sam_plugin.c b/source3/sam/sam_plugin.c
new file mode 100644
index 0000000000..fd26c4b8d3
--- /dev/null
+++ b/source3/sam/sam_plugin.c
@@ -0,0 +1,79 @@
+/*
+ Unix SMB/CIFS implementation.
+ Loadable san module interface.
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ 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 "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SAM
+
+NTSTATUS sam_init_plugin(SAM_METHODS *sam_methods, const char *module_params)
+{
+ void *dl_handle;
+ char *plugin_params, *plugin_name, *p;
+ sam_init_function plugin_init;
+ int (*plugin_version)(void);
+
+ if (module_params == NULL) {
+ DEBUG(0, ("The plugin module needs an argument!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ plugin_name = smb_xstrdup(module_params);
+ p = strchr(plugin_name, ':');
+ if (p) {
+ *p = 0;
+ plugin_params = p+1;
+ trim_string(plugin_params, " ", " ");
+ } else plugin_params = NULL;
+ trim_string(plugin_name, " ", " ");
+
+ DEBUG(5, ("Trying to load sam plugin %s\n", plugin_name));
+ dl_handle = sys_dlopen(plugin_name, RTLD_NOW);
+ if (!dl_handle) {
+ DEBUG(0, ("Failed to load sam plugin %s using sys_dlopen (%s)\n", plugin_name, sys_dlerror()));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ plugin_version = sys_dlsym(dl_handle, "sam_version");
+ if (!plugin_version) {
+ sys_dlclose(dl_handle);
+ DEBUG(0, ("Failed to find function 'sam_version' using sys_dlsym in sam plugin %s (%s)\n", plugin_name, sys_dlerror()));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (plugin_version()!=SAM_INTERFACE_VERSION) {
+ sys_dlclose(dl_handle);
+ DEBUG(0, ("Wrong SAM_INTERFACE_VERSION! sam plugin has version %d and version %d is needed! Please update!\n",
+ plugin_version(),SAM_INTERFACE_VERSION));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ plugin_init = sys_dlsym(dl_handle, "sam_init");
+ if (!plugin_init) {
+ sys_dlclose(dl_handle);
+ DEBUG(0, ("Failed to find function 'sam_init' using sys_dlsym in sam plugin %s (%s)\n", plugin_name, sys_dlerror()));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(5, ("Starting sam plugin %s with parameters %s for domain %s\n", plugin_name, plugin_params, sam_methods->domain_name));
+ return plugin_init(sam_methods, plugin_params);
+}
diff --git a/source3/script/find_missing_doc.pl b/source3/script/find_missing_doc.pl
new file mode 100755
index 0000000000..89385baaa2
--- /dev/null
+++ b/source3/script/find_missing_doc.pl
@@ -0,0 +1,43 @@
+#!/usr/bin/perl -w
+
+#reads in the list of parameters from the source
+#compares this list to the list of parms documented in the docbook source
+#prints out the names of the parameters that are in need of documentation
+# (C) 2002 Bradley W. Langhorst" <brad@langhorst.com>
+
+my $doc_file = "./docs/docbook/manpages/smb.conf.5.sgml";
+my $source_file = "./source/param/loadparm.c";
+my $ln;
+my %params;
+
+open(SOURCE, "<$source_file") ||
+ die "Unable to open $source_file for input: $!\n";
+open(DOC, "<$doc_file") ||
+ die "Unable to open $doc_file for input: $!\n";
+
+while ($ln= <SOURCE>) {
+ last if $ln =~ m/^static\ struct\ parm_struct\ parm_table.*/;
+} #burn through the preceding lines
+
+while ($ln = <SOURCE>) {
+ last if $ln =~ m/^\s*\}\;\s*$/;
+ #pull in the param names only
+ next if $ln =~ m/.*P_SEPARATOR.*/;
+ $ln =~ m/.*\"(.*)\".*/;
+ $params{lc($1)}='not_found'; #not case sensitive
+}
+close SOURCE;
+#now read in the params list from the docs
+@doclines = <DOC>;
+
+foreach $ln (grep (/\<anchor\ id\=/, @doclines)) {
+ $ln =~ m/^.*\<anchor\ id\=\".*\"\>\s*(?:\<.*?\>)*\s*(.*?)(?:\s*\(?[S,G]?\)?\s*(\<\/term\>)?){1}\s*$/;
+ #print "got: $1 from: $ln";
+ if (exists $params{lc($1)}) {
+ $params{$1} = 'found';
+ }
+}
+
+foreach (keys %params) {
+ print "$_\n" if $params{$_} eq 'not_found' and $_ cmp "valid" and $_ eq "";
+}
diff --git a/source3/torture/cmd_sam.c b/source3/torture/cmd_sam.c
new file mode 100644
index 0000000000..3ebf91434e
--- /dev/null
+++ b/source3/torture/cmd_sam.c
@@ -0,0 +1,301 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM module functions
+
+ Copyright (C) Jelmer Vernooij 2002
+
+ 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 "includes.h"
+#include "samtest.h"
+
+static NTSTATUS cmd_load_module(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char *plugin_arg[2];
+ NTSTATUS status;
+ if (argc != 2 && argc != 3) {
+ printf("Usage: load <module path> [domain-sid]\n");
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 3)
+ asprintf(&plugin_arg[0], "%s|plugin:%s", argv[2], argv[1]);
+ else
+ asprintf(&plugin_arg[0], "plugin:%s", argv[1]);
+
+ plugin_arg[1] = NULL;
+
+ if(!NT_STATUS_IS_OK(status = make_sam_context_list(&st->context, plugin_arg))) {
+ free(plugin_arg[0]);
+ return status;
+ }
+
+ free(plugin_arg[0]);
+
+ printf("load: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_get_sec_desc(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_set_sec_desc(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_sid(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char *name;
+ uint32 type;
+ NTSTATUS status;
+ DOM_SID sid;
+ if (argc != 2) {
+ printf("Usage: lookup_sid <sid>\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!string_to_sid(&sid, argv[1])){
+ printf("Unparseable SID specified!\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_STATUS_IS_OK(status = context_sam_lookup_sid(st->context, st->token, &sid, &name, &type))) {
+ printf("context_sam_lookup_sid failed!\n");
+ return status;
+ }
+
+ printf("Name: %s\n", name);
+ printf("Type: %d\n", type); /* FIXME: What kind of an integer is type ? */
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_lookup_name(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ DOM_SID *sid;
+ uint32 type;
+ NTSTATUS status;
+ if (argc != 3) {
+ printf("Usage: lookup_name <domain> <name>\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_STATUS_IS_OK(status = context_sam_lookup_name(st->context, st->token, argv[1], argv[2], &sid, &type))) {
+ printf("context_sam_lookup_name failed!\n");
+ return status;
+ }
+
+ printf("SID: %s\n", sid_string_static(sid));
+ printf("Type: %d\n", type);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_lookup_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_domain(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ DOM_SID *sid;
+ NTSTATUS status;
+ if (argc != 2) {
+ printf("Usage: lookup_domain <domain>\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_STATUS_IS_OK(status = context_sam_lookup_domain(st->context, st->token, argv[1], &sid))) {
+ printf("context_sam_lookup_name failed!\n");
+ return status;
+ }
+
+ printf("SID: %s\n", sid_string_static(sid));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_enum_domains(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int32 domain_count, i;
+ DOM_SID *domain_sids;
+ char **domain_names;
+ NTSTATUS status;
+
+ if (!NT_STATUS_IS_OK(status = context_sam_enum_domains(st->context, st->token, &domain_count, &domain_sids, &domain_names))) {
+ printf("context_sam_enum_domains failed!\n");
+ return status;
+ }
+
+ for (i = 0; i < domain_count; i++) {
+ printf("%s %s\n", domain_names[i], sid_string_static(&domain_sids[i]));
+ }
+
+ SAFE_FREE(domain_sids);
+ SAFE_FREE(domain_names);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_update_domain(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_show_domain(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_create_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_update_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_delete_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_enum_accounts(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_account_sid(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_account_name(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_create_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_update_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_delete_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_enum_groups(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_group_sid(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_lookup_group_name(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_group_add_member(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS cmd_group_del_member(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+static NTSTATUS cmd_group_enum(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+static NTSTATUS cmd_get_sid_groups(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+struct cmd_set sam_general_commands[] = {
+
+ { "General SAM Commands" },
+
+ { "load", cmd_load_module, "Load a module", "load <module.so> [domain-sid]" },
+ { "get_sec_desc", cmd_get_sec_desc, "Get security descriptor info", "get_sec_desc <access-token> <sid>" },
+ { "set_sec_desc", cmd_set_sec_desc, "Set security descriptor info", "set_sec_desc <access-token> <sid>" },
+ { "lookup_sid", cmd_lookup_sid, "Lookup type of specified SID", "lookup_sid <sid>" },
+ { "lookup_name", cmd_lookup_name, "Lookup type of specified name", "lookup_name <sid>" },
+ { NULL }
+};
+
+struct cmd_set sam_domain_commands[] = {
+ { "Domain Commands" },
+ { "update_domain", cmd_update_domain, "Update domain information", "update_domain [domain-options] domain-name | domain-sid" },
+ { "show_domain", cmd_show_domain, "Show domain information", "show_domain domain-sid | domain-name" },
+ { "enum_domains", cmd_enum_domains, "Enumerate all domains", "enum_domains <token> <acct-ctrl>" },
+ { "lookup_domain", cmd_lookup_domain, "Lookup a domain by name", "lookup_domain domain-name" },
+ { NULL }
+};
+
+struct cmd_set sam_account_commands[] = {
+ { "Account Commands" },
+ { "create_account", cmd_create_account, "Create a new account with specified properties", "create_account [account-options]" },
+ { "update_account", cmd_update_account, "Update an existing account", "update_account [account-options] account-sid | account-name" },
+ { "delete_account", cmd_delete_account, "Delete an account", "delete_account account-sid | account-name" },
+ { "enum_accounts", cmd_enum_accounts, "Enumerate all accounts", "enum_accounts <token> <acct-ctrl>" },
+ { "lookup_account", cmd_lookup_account, "Lookup an account by either sid or name", "lookup_account account-sid | account-name" },
+ { "lookup_account_sid", cmd_lookup_account_sid, "Lookup an account by sid", "lookup_account_sid account-sid" },
+ { "lookup_account_name", cmd_lookup_account_name, "Lookup an account by name", "lookup_account_name account-name" },
+ { NULL }
+};
+
+struct cmd_set sam_group_commands[] = {
+ { "Group Commands" },
+ { "create_group", cmd_create_group, "Create a new group", "create_group [group-opts]" },
+ { "update_group", cmd_update_group, "Update an existing group", "update_group [group-opts] group-name | group-sid" },
+ { "delete_group", cmd_delete_group, "Delete an existing group", "delete_group group-name | group-sid" },
+ { "enum_groups", cmd_enum_groups, "Enumerate all groups", "enum_groups <token> <group-ctrl>" },
+ { "lookup_group", cmd_lookup_group, "Lookup a group by SID or name", "lookup_group group-sid | group-name" },
+ { "lookup_group_sid", cmd_lookup_group_sid, "Lookup a group by SID", "lookup_group_sid <sid>" },
+ { "lookup_group_name", cmd_lookup_group_name, "Lookup a group by name", "lookup_group_name <name>" },
+ { "group_add_member", cmd_group_add_member, "Add group member to group", "group_add_member <group-name | group-sid> <member-name | member-sid>" },
+ { "group_del_member", cmd_group_del_member, "Delete group member from group", "group_del_member <group-name | group-sid> <member-name | member-sid>" },
+ { "group_enum", cmd_group_enum, "Enumerate all members of specified group", "group_enum group-sid | group-name" },
+
+ { "get_sid_groups", cmd_get_sid_groups, "Get a list of groups specified sid is a member of", "group_enum <group-sid | group-name>" },
+ { NULL }
+};
diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c
new file mode 100644
index 0000000000..24601207e6
--- /dev/null
+++ b/source3/torture/cmd_vfs.c
@@ -0,0 +1,1045 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS module functions
+
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Eric Lorimer 2002
+
+ 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 "includes.h"
+#include "vfstest.h"
+
+static char *null_string = "";
+
+static NTSTATUS cmd_load_module(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ struct smb_vfs_handle_struct *handle;
+ char *path = lp_vfs_path(0);
+ char name[PATH_MAX];
+
+ if (argc != 2) {
+ printf("Usage: load <module path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (path != NULL && *path != '\0') {
+ snprintf(name, PATH_MAX, "%s/%s", path, argv[1]);
+ } else {
+ snprintf(name, PATH_MAX, "%s", argv[1]);
+ }
+ vfs->conn->vfs_private = NULL;
+ handle = (struct smb_vfs_handle_struct *) smb_xmalloc(sizeof(smb_vfs_handle_struct));
+ handle->handle = NULL;
+ DLIST_ADD(vfs->conn->vfs_private, handle)
+ if (!vfs_init_custom(vfs->conn, name)) {
+ DEBUG(0, ("load: error=-1 (vfs_init_custom failed for %s)\n", argv[1]));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ printf("load: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_populate(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char c;
+ size_t size;
+ if (argc != 3) {
+ printf("Usage: populate <char> <size>\n");
+ return NT_STATUS_OK;
+ }
+ c = argv[1][0];
+ size = atoi(argv[2]);
+ vfs->data = (char *)talloc(mem_ctx, size);
+ if (vfs->data == NULL) {
+ printf("populate: error=-1 (not enough memory)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ memset(vfs->data, c, size);
+ vfs->data_size = size;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_show_data(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ size_t offset;
+ size_t len;
+ if (argc != 1 && argc != 3) {
+ printf("Usage: showdata [<offset> <len>]\n");
+ return NT_STATUS_OK;
+ }
+ if (vfs->data == NULL || vfs->data_size == 0) {
+ printf("show_data: error=-1 (buffer empty)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (argc == 3) {
+ offset = atoi(argv[1]);
+ len = atoi(argv[2]);
+ } else {
+ offset = 0;
+ len = vfs->data_size;
+ }
+ if ((offset + len) > vfs->data_size) {
+ printf("show_data: error=-1 (not enough data in buffer)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ dump_data(0, (char *)(vfs->data) + offset, len);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_connect(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ vfs->conn->vfs_ops.connect(vfs->conn, lp_servicename(vfs->conn->service), "vfstest");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_disconnect(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ vfs->conn->vfs_ops.disconnect(vfs->conn);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_disk_free(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ SMB_BIG_UINT diskfree, bsize, dfree, dsize;
+ if (argc != 2) {
+ printf("Usage: disk_free <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ diskfree = vfs->conn->vfs_ops.disk_free(vfs->conn, argv[1], False, &bsize, &dfree, &dsize);
+ printf("disk_free: %ld, bsize = %ld, dfree = %ld, dsize = %ld\n", diskfree, bsize, dfree, dsize);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_opendir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: opendir <fname>\n");
+ return NT_STATUS_OK;
+ }
+
+ vfs->currentdir = vfs->conn->vfs_ops.opendir(vfs->conn, argv[1]);
+ if (vfs->currentdir == NULL) {
+ printf("opendir error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("opendir: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_readdir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ struct dirent *dent;
+
+ if (vfs->currentdir == NULL) {
+ printf("readdir: error=-1 (no open directory)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dent = vfs->conn->vfs_ops.readdir(vfs->conn, vfs->currentdir);
+ if (dent == NULL) {
+ printf("readdir: NULL\n");
+ return NT_STATUS_OK;
+ }
+
+ printf("readdir: %s\n", dent->d_name);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_mkdir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: mkdir <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.mkdir(vfs->conn, argv[1], 00755) == -1) {
+ printf("mkdir error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("mkdir: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_closedir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int ret;
+
+ if (vfs->currentdir == NULL) {
+ printf("closedir: failure (no directory open)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ret = vfs->conn->vfs_ops.closedir(vfs->conn, vfs->currentdir);
+ if (ret == -1) {
+ printf("closedir failure: %s\n", strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("closedir: ok\n");
+ vfs->currentdir = NULL;
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_open(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int flags, fd;
+ mode_t mode;
+ char *flagstr;
+
+ mode = 00400;
+
+ if (argc < 3 || argc > 5) {
+ printf("Usage: open <filename> <flags> <mode>\n");
+ printf(" flags: O = O_RDONLY\n");
+ printf(" R = O_RDWR\n");
+ printf(" W = O_WRONLY\n");
+ printf(" C = O_CREAT\n");
+ printf(" E = O_EXCL\n");
+ printf(" T = O_TRUNC\n");
+ printf(" A = O_APPEND\n");
+ printf(" N = O_NONBLOCK/O_NDELAY\n");
+#ifdef O_SYNC
+ printf(" S = O_SYNC\n");
+#endif
+#ifdef O_NOFOLLOW
+ printf(" F = O_NOFOLLOW\n");
+#endif
+ printf(" mode: see open.2\n");
+ printf(" mode is ignored if C flag not present\n");
+ printf(" mode defaults to 00400\n");
+ return NT_STATUS_OK;
+ }
+ flags = 0;
+ flagstr = argv[2];
+ while (*flagstr) {
+ switch (*flagstr) {
+ case 'O':
+ flags |= O_RDONLY;
+ break;
+ case 'R':
+ flags |= O_RDWR;
+ break;
+ case 'W':
+ flags |= O_WRONLY;
+ break;
+ case 'C':
+ flags |= O_CREAT;
+ break;
+ case 'E':
+ flags |= O_EXCL;
+ break;
+ case 'T':
+ flags |= O_TRUNC;
+ break;
+ case 'A':
+ flags |= O_APPEND;
+ break;
+ case 'N':
+ flags |= O_NONBLOCK;
+ break;
+#ifdef O_SYNC
+ case 'S':
+ flags |= O_SYNC;
+ break;
+#endif
+#ifdef O_NOFOLLOW
+ case 'F':
+ flags |= O_NOFOLLOW;
+ break;
+#endif
+ default:
+ printf("open: error=-1 (invalid flag!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ flagstr++;
+ }
+ if ((flags & O_CREAT) && argc == 4) {
+ if (sscanf(argv[3], "%o", &mode) == 0) {
+ printf("open: error=-1 (invalid mode!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ fd = vfs->conn->vfs_ops.open(vfs->conn, argv[1], flags, mode);
+ if (fd == -1) {
+ printf("open: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ vfs->files[fd] = (struct files_struct *)malloc(sizeof(struct files_struct));
+ vfs->files[fd]->fsp_name = strdup(argv[1]);
+ vfs->files[fd]->fd = fd;
+ vfs->files[fd]->conn = vfs->conn;
+ printf("open: fd=%d\n", fd);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_pathfunc(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int ret = -1;
+
+ if (argc != 2) {
+ printf("Usage: %s <path>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (strcmp("rmdir", argv[0]) == 0 ) {
+ ret = vfs->conn->vfs_ops.rmdir(vfs->conn, argv[1]);
+ } else if (strcmp("unlink", argv[0]) == 0 ) {
+ ret = vfs->conn->vfs_ops.unlink(vfs->conn, argv[1]);
+ } else if (strcmp("chdir", argv[0]) == 0 ) {
+ ret = vfs->conn->vfs_ops.chdir(vfs->conn, argv[1]);
+ } else {
+ printf("%s: error=%d (invalid function name!)\n", argv[0], errno);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (ret == -1) {
+ printf("%s: error=%d (%s)\n", argv[0], errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("%s: ok\n", argv[0]);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_close(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd, ret;
+
+ if (argc != 2) {
+ printf("Usage: close <fd>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ if (vfs->files[fd] == NULL) {
+ printf("close: error=-1 (invalid file descriptor)\n");
+ return NT_STATUS_OK;
+ }
+
+ ret = vfs->conn->vfs_ops.close(vfs->files[fd], fd);
+ if (ret == -1 )
+ printf("close: error=%d (%s)\n", errno, strerror(errno));
+ else
+ printf("close: ok\n");
+
+ SAFE_FREE(vfs->files[fd]->fsp_name);
+ SAFE_FREE(vfs->files[fd]);
+ vfs->files[fd] = NULL;
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_read(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd;
+ size_t size, rsize;
+
+ if (argc != 3) {
+ printf("Usage: read <fd> <size>\n");
+ return NT_STATUS_OK;
+ }
+
+ /* do some error checking on these */
+ fd = atoi(argv[1]);
+ size = atoi(argv[2]);
+ vfs->data = (char *)talloc(mem_ctx, size);
+ if (vfs->data == NULL) {
+ printf("read: error=-1 (not enough memory)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ vfs->data_size = size;
+
+ rsize = vfs->conn->vfs_ops.read(vfs->files[fd], fd, vfs->data, size);
+ if (rsize == -1) {
+ printf("read: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("read: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_write(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd, size, wsize;
+
+ if (argc != 3) {
+ printf("Usage: write <fd> <size>\n");
+ return NT_STATUS_OK;
+ }
+
+ /* some error checking should go here */
+ fd = atoi(argv[1]);
+ size = atoi(argv[2]);
+ if (vfs->data == NULL) {
+ printf("write: error=-1 (buffer empty, please populate it before writing)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (vfs->data_size < size) {
+ printf("write: error=-1 (buffer too small, please put some more data in)");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ wsize = vfs->conn->vfs_ops.write(vfs->files[fd], fd, vfs->data, size);
+
+ if (wsize == -1) {
+ printf("write: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("write: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_lseek(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd, offset, whence;
+ SMB_OFF_T pos;
+
+ if (argc != 4) {
+ printf("Usage: lseek <fd> <offset> <whence>\n...where whence is 1 => SEEK_SET, 2 => SEEK_CUR, 3 => SEEK_END\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ offset = atoi(argv[2]);
+ whence = atoi(argv[3]);
+ switch (whence) {
+ case 1: whence = SEEK_SET; break;
+ case 2: whence = SEEK_CUR; break;
+ default: whence = SEEK_END;
+ }
+
+ pos = vfs->conn->vfs_ops.lseek(vfs->files[fd], fd, offset, whence);
+ if (pos == (SMB_OFF_T)-1) {
+ printf("lseek: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("lseek: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_rename(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int ret;
+ if (argc != 3) {
+ printf("Usage: rename <old> <new>\n");
+ return NT_STATUS_OK;
+ }
+
+ ret = vfs->conn->vfs_ops.rename(vfs->conn, argv[1], argv[2]);
+ if (ret == -1) {
+ printf("rename: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("rename: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fsync(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int ret, fd;
+ if (argc != 2) {
+ printf("Usage: fsync <fd>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ ret = vfs->conn->vfs_ops.fsync(vfs->files[fd], fd);
+ if (ret == -1) {
+ printf("fsync: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("fsync: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_stat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int ret;
+ char *user;
+ char *group;
+ struct passwd *pwd;
+ struct group *grp;
+ SMB_STRUCT_STAT st;
+
+ if (argc != 2) {
+ printf("Usage: stat <fname>\n");
+ return NT_STATUS_OK;
+ }
+
+ ret = vfs->conn->vfs_ops.stat(vfs->conn, argv[1], &st);
+ if (ret == -1) {
+ printf("stat: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ pwd = sys_getpwuid(st.st_uid);
+ if (pwd != NULL) user = strdup(pwd->pw_name);
+ else user = null_string;
+ grp = sys_getgrgid(st.st_gid);
+ if (grp != NULL) group = strdup(grp->gr_name);
+ else group = null_string;
+
+ printf("stat: ok\n");
+ printf(" File: %s", argv[1]);
+ if (S_ISREG(st.st_mode)) printf(" Regular File\n");
+ else if (S_ISDIR(st.st_mode)) printf(" Directory\n");
+ else if (S_ISCHR(st.st_mode)) printf(" Character Device\n");
+ else if (S_ISBLK(st.st_mode)) printf(" Block Device\n");
+ else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n");
+ else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n");
+ else if (S_ISSOCK(st.st_mode)) printf(" Socket\n");
+ printf(" Size: %10d", st.st_size);
+ printf(" Blocks: %9d", st.st_blocks);
+ printf(" IO Block: %d\n", st.st_blksize);
+ printf(" Device: 0x%10x", st.st_dev);
+ printf(" Inode: %10d", st.st_ino);
+ printf(" Links: %10d\n", st.st_nlink);
+ printf(" Access: %05o", (st.st_mode) & 007777);
+ printf(" Uid: %5d/%.16s Gid: %5d/%.16s\n", st.st_uid, user, st.st_gid, group);
+ printf(" Access: %s", ctime(&(st.st_atime)));
+ printf(" Modify: %s", ctime(&(st.st_mtime)));
+ printf(" Change: %s", ctime(&(st.st_ctime)));
+ if (user != null_string) SAFE_FREE(user);
+ if (group!= null_string) SAFE_FREE(group);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fstat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd;
+ char *user;
+ char *group;
+ struct passwd *pwd;
+ struct group *grp;
+ SMB_STRUCT_STAT st;
+
+ if (argc != 2) {
+ printf("Usage: fstat <fd>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ if (fd < 0 || fd > 1024) {
+ printf("fstat: error=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->files[fd] == NULL) {
+ printf("fstat: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.fstat(vfs->files[fd], fd, &st) == -1) {
+ printf("fstat: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ pwd = sys_getpwuid(st.st_uid);
+ if (pwd != NULL) user = strdup(pwd->pw_name);
+ else user = null_string;
+ grp = sys_getgrgid(st.st_gid);
+ if (grp != NULL) group = strdup(grp->gr_name);
+ else group = null_string;
+
+ printf("fstat: ok\n");
+ if (S_ISREG(st.st_mode)) printf(" Regular File\n");
+ else if (S_ISDIR(st.st_mode)) printf(" Directory\n");
+ else if (S_ISCHR(st.st_mode)) printf(" Character Device\n");
+ else if (S_ISBLK(st.st_mode)) printf(" Block Device\n");
+ else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n");
+ else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n");
+ else if (S_ISSOCK(st.st_mode)) printf(" Socket\n");
+ printf(" Size: %10d", st.st_size);
+ printf(" Blocks: %9d", st.st_blocks);
+ printf(" IO Block: %d\n", st.st_blksize);
+ printf(" Device: 0x%10x", st.st_dev);
+ printf(" Inode: %10d", st.st_ino);
+ printf(" Links: %10d\n", st.st_nlink);
+ printf(" Access: %05o", (st.st_mode) & 007777);
+ printf(" Uid: %5d/%.16s Gid: %5d/%.16s\n", st.st_uid, user, st.st_gid, group);
+ printf(" Access: %s", ctime(&(st.st_atime)));
+ printf(" Modify: %s", ctime(&(st.st_mtime)));
+ printf(" Change: %s", ctime(&(st.st_ctime)));
+ if (user != null_string) SAFE_FREE(user);
+ if (group!= null_string) SAFE_FREE(group);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_lstat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char *user;
+ char *group;
+ struct passwd *pwd;
+ struct group *grp;
+ SMB_STRUCT_STAT st;
+
+ if (argc != 2) {
+ printf("Usage: lstat <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.lstat(vfs->conn, argv[1], &st) == -1) {
+ printf("lstat: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ pwd = sys_getpwuid(st.st_uid);
+ if (pwd != NULL) user = strdup(pwd->pw_name);
+ else user = null_string;
+ grp = sys_getgrgid(st.st_gid);
+ if (grp != NULL) group = strdup(grp->gr_name);
+ else group = null_string;
+
+ printf("lstat: ok\n");
+ if (S_ISREG(st.st_mode)) printf(" Regular File\n");
+ else if (S_ISDIR(st.st_mode)) printf(" Directory\n");
+ else if (S_ISCHR(st.st_mode)) printf(" Character Device\n");
+ else if (S_ISBLK(st.st_mode)) printf(" Block Device\n");
+ else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n");
+ else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n");
+ else if (S_ISSOCK(st.st_mode)) printf(" Socket\n");
+ printf(" Size: %10d", st.st_size);
+ printf(" Blocks: %9d", st.st_blocks);
+ printf(" IO Block: %d\n", st.st_blksize);
+ printf(" Device: 0x%10x", st.st_dev);
+ printf(" Inode: %10d", st.st_ino);
+ printf(" Links: %10d\n", st.st_nlink);
+ printf(" Access: %05o", (st.st_mode) & 007777);
+ printf(" Uid: %5d/%.16s Gid: %5d/%.16s\n", st.st_uid, user, st.st_gid, group);
+ printf(" Access: %s", ctime(&(st.st_atime)));
+ printf(" Modify: %s", ctime(&(st.st_mtime)));
+ printf(" Change: %s", ctime(&(st.st_ctime)));
+ if (user != null_string) SAFE_FREE(user);
+ if (group!= null_string) SAFE_FREE(group);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_chmod(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ mode_t mode;
+ if (argc != 3) {
+ printf("Usage: chmod <path> <mode>\n");
+ return NT_STATUS_OK;
+ }
+
+ mode = atoi(argv[2]);
+ if (vfs->conn->vfs_ops.chmod(vfs->conn, argv[1], mode) == -1) {
+ printf("chmod: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("chmod: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fchmod(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd;
+ mode_t mode;
+ if (argc != 3) {
+ printf("Usage: fchmod <fd> <mode>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ mode = atoi(argv[2]);
+ if (fd < 0 || fd > 1024) {
+ printf("fchmod: error=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->files[fd] == NULL) {
+ printf("fchmod: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.fchmod(vfs->files[fd], fd, mode) == -1) {
+ printf("fchmod: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("fchmod: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_chown(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ uid_t uid;
+ gid_t gid;
+ if (argc != 4) {
+ printf("Usage: chown <path> <uid> <gid>\n");
+ return NT_STATUS_OK;
+ }
+
+ uid = atoi(argv[2]);
+ gid = atoi(argv[3]);
+ if (vfs->conn->vfs_ops.chown(vfs->conn, argv[1], uid, gid) == -1) {
+ printf("chown: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("chown: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_fchown(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ uid_t uid;
+ gid_t gid;
+ int fd;
+ if (argc != 4) {
+ printf("Usage: fchown <fd> <uid> <gid>\n");
+ return NT_STATUS_OK;
+ }
+
+ uid = atoi(argv[2]);
+ gid = atoi(argv[3]);
+ fd = atoi(argv[1]);
+ if (fd < 0 || fd > 1024) {
+ printf("fchown: faliure=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->files[fd] == NULL) {
+ printf("fchown: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->conn->vfs_ops.fchown(vfs->files[fd], fd, uid, gid) == -1) {
+ printf("fchown error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("fchown: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_getwd(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char buf[PATH_MAX];
+ if (vfs->conn->vfs_ops.getwd(vfs->conn, buf) == NULL) {
+ printf("getwd: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("getwd: %s\n", buf);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_utime(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ struct utimbuf times;
+ if (argc != 4) {
+ printf("Usage: utime <path> <access> <modify>\n");
+ return NT_STATUS_OK;
+ }
+ times.actime = atoi(argv[2]);
+ times.modtime = atoi(argv[3]);
+ if (vfs->conn->vfs_ops.utime(vfs->conn, argv[1], &times) != 0) {
+ printf("utime: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("utime: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_ftruncate(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ int fd;
+ SMB_OFF_T off;
+ if (argc != 3) {
+ printf("Usage: ftruncate <fd> <length>\n");
+ return NT_STATUS_OK;
+ }
+
+ fd = atoi(argv[1]);
+ off = atoi(argv[2]);
+ if (fd < 0 || fd > 1024) {
+ printf("ftruncate: error=%d (file descriptor out of range)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+ if (vfs->files[fd] == NULL) {
+ printf("ftruncate: error=%d (invalid file descriptor)\n", EBADF);
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.ftruncate(vfs->files[fd], fd, off) == -1) {
+ printf("ftruncate: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("ftruncate: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_lock(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ BOOL ret;
+ int fd;
+ int op;
+ long offset;
+ long count;
+ int type;
+ char *typestr;
+
+ if (argc != 6) {
+ printf("Usage: lock <fd> <op> <offset> <count> <type>\n");
+ printf(" ops: G = F_GETLK\n");
+ printf(" S = F_SETLK\n");
+ printf(" W = F_SETLKW\n");
+ printf(" type: R = F_RDLCK\n");
+ printf(" W = F_WRLCK\n");
+ printf(" U = F_UNLCK\n");
+ return NT_STATUS_OK;
+ }
+
+ if (sscanf(argv[1], "%d", &fd) == 0) {
+ printf("lock: error=-1 (error parsing fd)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ op = 0;
+ switch (*argv[2]) {
+ case 'G':
+ op = F_GETLK;
+ break;
+ case 'S':
+ op = F_SETLK;
+ break;
+ case 'W':
+ op = F_SETLKW;
+ break;
+ default:
+ printf("lock: error=-1 (invalid op flag!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (sscanf(argv[3], "%ld", &offset) == 0) {
+ printf("lock: error=-1 (error parsing fd)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (sscanf(argv[4], "%ld", &count) == 0) {
+ printf("lock: error=-1 (error parsing fd)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ type = 0;
+ typestr = argv[5];
+ while(*typestr) {
+ switch (*typestr) {
+ case 'R':
+ type |= F_RDLCK;
+ break;
+ case 'W':
+ type |= F_WRLCK;
+ break;
+ case 'U':
+ type |= F_UNLCK;
+ break;
+ default:
+ printf("lock: error=-1 (invalid type flag!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ typestr++;
+ }
+
+ printf("lock: debug lock(fd=%d, op=%d, offset=%ld, count=%ld, type=%d))\n", fd, op, offset, count, type);
+
+ if ((ret = vfs->conn->vfs_ops.lock(vfs->files[fd], fd, op, offset, count, type)) == False) {
+ printf("lock: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("lock: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_symlink(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ if (argc != 3) {
+ printf("Usage: symlink <path> <link>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.symlink(vfs->conn, argv[1], argv[2]) == -1) {
+ printf("symlink: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("symlink: ok\n");
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_readlink(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char buffer[PATH_MAX];
+ int size;
+
+ if (argc != 2) {
+ printf("Usage: readlink <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if ((size = vfs->conn->vfs_ops.readlink(vfs->conn, argv[1], buffer, PATH_MAX)) == -1) {
+ printf("readlink: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ buffer[size] = '\0';
+ printf("readlink: %s\n", buffer);
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS cmd_link(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ if (argc != 3) {
+ printf("Usage: link <path> <link>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.link(vfs->conn, argv[1], argv[2]) == -1) {
+ printf("link: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("link: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_mknod(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ mode_t mode;
+ SMB_DEV_T dev;
+
+ if (argc != 4) {
+ printf("Usage: mknod <path> <mode> <dev>\n");
+ printf(" mode is octal\n");
+ printf(" dev is hex\n");
+ return NT_STATUS_OK;
+ }
+
+ if (sscanf(argv[2], "%o", &mode) == 0) {
+ printf("open: error=-1 (invalid mode!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (sscanf(argv[3], "%x", &dev) == 0) {
+ printf("open: error=-1 (invalid dev!)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (vfs->conn->vfs_ops.mknod(vfs->conn, argv[1], mode, dev) == -1) {
+ printf("mknod: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("mknod: ok\n");
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_realpath(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ char respath[PATH_MAX];
+
+ if (argc != 2) {
+ printf("Usage: realpath <path>\n");
+ return NT_STATUS_OK;
+ }
+
+ if (vfs->conn->vfs_ops.realpath(vfs->conn, argv[1], respath) == NULL) {
+ printf("realpath: error=%d (%s)\n", errno, strerror(errno));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ printf("realpath: ok\n");
+ return NT_STATUS_OK;
+}
+
+struct cmd_set vfs_commands[] = {
+
+ { "VFS Commands" },
+
+ { "load", cmd_load_module, "Load a module", "load <module.so>" },
+ { "populate", cmd_populate, "Populate a data buffer", "populate <char> <size>" },
+ { "showdata", cmd_show_data, "Show data currently in data buffer", "show_data [<offset> <len>]"},
+ { "connect", cmd_connect, "VFS connect()", "connect" },
+ { "disconnect", cmd_disconnect, "VFS disconnect()", "disconnect" },
+ { "disk_free", cmd_disk_free, "VFS disk_free()", "disk_free <path>" },
+ { "opendir", cmd_opendir, "VFS opendir()", "opendir <fname>" },
+ { "readdir", cmd_readdir, "VFS readdir()", "readdir" },
+ { "mkdir", cmd_mkdir, "VFS mkdir()", "mkdir <path>" },
+ { "rmdir", cmd_pathfunc, "VFS rmdir()", "rmdir <path>" },
+ { "closedir", cmd_closedir, "VFS closedir()", "closedir" },
+ { "open", cmd_open, "VFS open()", "open <fname>" },
+ { "close", cmd_close, "VFS close()", "close <fd>" },
+ { "read", cmd_read, "VFS read()", "read <fd> <size>" },
+ { "write", cmd_write, "VFS write()", "write <fd> <size>" },
+ { "lseek", cmd_lseek, "VFS lseek()", "lseek <fd> <offset> <whence>" },
+ { "rename", cmd_rename, "VFS rename()", "rename <old> <new>" },
+ { "fsync", cmd_fsync, "VFS fsync()", "fsync <fd>" },
+ { "stat", cmd_stat, "VFS stat()", "stat <fname>" },
+ { "fstat", cmd_fstat, "VFS fstat()", "fstat <fd>" },
+ { "lstat", cmd_lstat, "VFS lstat()", "lstat <fname>" },
+ { "unlink", cmd_pathfunc, "VFS unlink()", "unlink <fname>" },
+ { "chmod", cmd_chmod, "VFS chmod()", "chmod <path> <mode>" },
+ { "fchmod", cmd_fchmod, "VFS fchmod()", "fchmod <fd> <mode>" },
+ { "chown", cmd_chown, "VFS chown()", "chown <path> <uid> <gid>" },
+ { "fchown", cmd_fchown, "VFS fchown()", "fchown <fd> <uid> <gid>" },
+ { "chdir", cmd_pathfunc, "VFS chdir()", "chdir <path>" },
+ { "getwd", cmd_getwd, "VFS getwd()", "getwd" },
+ { "utime", cmd_utime, "VFS utime()", "utime <path> <access> <modify>" },
+ { "ftruncate", cmd_ftruncate, "VFS ftruncate()", "ftruncate <fd> <length>" },
+ { "lock", cmd_lock, "VFS lock()", "lock <f> <op> <offset> <count> <type>" },
+ { "symlink", cmd_symlink, "VFS symlink()", "symlink <old> <new>" },
+ { "readlink", cmd_readlink, "VFS readlink()", "readlink <path>" },
+ { "link", cmd_link, "VFS link()", "link <oldpath> <newpath>" },
+ { "mknod", cmd_mknod, "VFS mknod()", "mknod <path> <mode> <dev>" },
+ { "realpath", cmd_realpath, "VFS realpath()", "realpath <path>" },
+ { NULL }
+};
diff --git a/source3/torture/samtest.c b/source3/torture/samtest.c
new file mode 100644
index 0000000000..b5f7ed9f76
--- /dev/null
+++ b/source3/torture/samtest.c
@@ -0,0 +1,449 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM module tester
+
+ Copyright (C) 2002 Jelmer Vernooij
+
+ Parts of the code stolen from vfstest by Simo Sorce and Eric Lorimer
+ Parts of the code stolen from rpcclient by Tim Potter
+
+ 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 "includes.h"
+#include "samtest.h"
+
+struct func_entry {
+ char *name;
+ int (*fn)(struct connection_struct *conn, const char *path);
+};
+
+/* List to hold groups of commands */
+static struct cmd_list {
+ struct cmd_list *prev, *next;
+ struct cmd_set *cmd_set;
+} *cmd_list;
+
+static char* next_command (char** cmdstr)
+{
+ static pstring command;
+ char *p;
+
+ if (!cmdstr || !(*cmdstr))
+ return NULL;
+
+ p = strchr_m(*cmdstr, ';');
+ if (p)
+ *p = '\0';
+ pstrcpy(command, *cmdstr);
+ *cmdstr = p;
+
+ return command;
+}
+
+/* Load specified configuration file */
+static NTSTATUS cmd_conf(struct samtest_state *sam, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: %s <smb.conf>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (!lp_load(argv[1], False, True, False)) {
+ printf("Error loading \"%s\"\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ printf("\"%s\" successfully loaded\n", argv[1]);
+ return NT_STATUS_OK;
+}
+
+/* Display help on commands */
+static NTSTATUS cmd_help(struct samtest_state *st, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ struct cmd_list *tmp;
+ struct cmd_set *tmp_set;
+
+ /* Usage */
+ if (argc > 2) {
+ printf("Usage: %s [command]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Help on one command */
+
+ if (argc == 2) {
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+ if (strequal(argv[1], tmp_set->name)) {
+ if (tmp_set->usage &&
+ tmp_set->usage[0])
+ printf("%s\n", tmp_set->usage);
+ else
+ printf("No help for %s\n", tmp_set->name);
+
+ return NT_STATUS_OK;
+ }
+
+ tmp_set++;
+ }
+ }
+
+ printf("No such command: %s\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ /* List all commands */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+
+ printf("%20s\t%s\n", tmp_set->name,
+ tmp_set->description ? tmp_set->description:
+ "");
+
+ tmp_set++;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Change the debug level */
+static NTSTATUS cmd_debuglevel(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ if (argc > 2) {
+ printf("Usage: %s [debuglevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ DEBUGLEVEL = atoi(argv[1]);
+ }
+
+ printf("debuglevel is %d\n", DEBUGLEVEL);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_quit(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ /* Cleanup */
+ talloc_destroy(mem_ctx);
+
+ exit(0);
+ return NT_STATUS_OK; /* NOTREACHED */
+}
+
+static struct cmd_set samtest_commands[] = {
+
+ { "GENERAL OPTIONS" },
+
+ { "help", cmd_help, "Get help on commands", "" },
+ { "?", cmd_help, "Get help on commands", "" },
+ { "conf", cmd_conf, "Load smb configuration file", "conf <smb.conf>" },
+ { "debuglevel", cmd_debuglevel, "Set debug level", "" },
+ { "exit", cmd_quit, "Exit program", "" },
+ { "quit", cmd_quit, "Exit program", "" },
+
+ { NULL }
+};
+
+static struct cmd_set separator_command[] = {
+ { "---------------", NULL, "----------------------" },
+ { NULL }
+};
+
+
+/*extern struct cmd_set sam_commands[];*/
+extern struct cmd_set sam_general_commands[];
+extern struct cmd_set sam_domain_commands[];
+extern struct cmd_set sam_account_commands[];
+extern struct cmd_set sam_group_commands[];
+static struct cmd_set *samtest_command_list[] = {
+ samtest_commands,
+ sam_general_commands,
+ sam_domain_commands,
+ sam_account_commands,
+ sam_group_commands,
+ NULL
+};
+
+static void add_command_set(struct cmd_set *cmd_set)
+{
+ struct cmd_list *entry;
+
+ if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
+ DEBUG(0, ("out of memory\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(entry);
+
+ entry->cmd_set = cmd_set;
+ DLIST_ADD(cmd_list, entry);
+}
+
+static NTSTATUS do_cmd(struct samtest_state *st, struct cmd_set *cmd_entry, char *cmd)
+{
+ char *p = cmd, **argv = NULL;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ TALLOC_CTX *mem_ctx = NULL;
+ pstring buf;
+ int argc = 0, i;
+
+ /* Count number of arguments first time through the loop then
+ allocate memory and strdup them. */
+
+ again:
+ while(next_token(&p, buf, " ", sizeof(buf))) {
+ if (argv) {
+ argv[argc] = strdup(buf);
+ }
+
+ argc++;
+ }
+
+ if (!argv) {
+
+ /* Create argument list */
+
+ argv = (char **)malloc(sizeof(char *) * argc);
+ memset(argv, 0, sizeof(char *) * argc);
+
+ if (!argv) {
+ fprintf(stderr, "out of memory\n");
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p = cmd;
+ argc = 0;
+
+ goto again;
+ }
+
+ /* Call the function */
+
+ if (cmd_entry->fn) {
+
+ if (mem_ctx == NULL) {
+ /* Create mem_ctx */
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ goto done;
+ }
+ }
+
+ /* Run command */
+ result = cmd_entry->fn(st, mem_ctx, argc, argv);
+
+ } else {
+ fprintf (stderr, "Invalid command\n");
+ goto done;
+ }
+
+ done:
+
+ /* Cleanup */
+
+ if (argv) {
+ for (i = 0; i < argc; i++)
+ SAFE_FREE(argv[i]);
+
+ SAFE_FREE(argv);
+ }
+
+ return result;
+}
+
+/* Process a command entered at the prompt or as part of -c */
+static NTSTATUS process_cmd(struct samtest_state *st, char *cmd)
+{
+ struct cmd_list *temp_list;
+ BOOL found = False;
+ pstring buf;
+ char *p = cmd;
+ NTSTATUS result = NT_STATUS_OK;
+ int len = 0;
+
+ if (cmd[strlen(cmd) - 1] == '\n')
+ cmd[strlen(cmd) - 1] = '\0';
+
+ if (!next_token(&p, buf, " ", sizeof(buf))) {
+ return NT_STATUS_OK;
+ }
+
+ /* strip the trainly \n if it exsists */
+ len = strlen(buf);
+ if (buf[len-1] == '\n')
+ buf[len-1] = '\0';
+
+ /* Search for matching commands */
+
+ for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
+ struct cmd_set *temp_set = temp_list->cmd_set;
+
+ while(temp_set->name) {
+ if (strequal(buf, temp_set->name)) {
+ found = True;
+ result = do_cmd(st, temp_set, cmd);
+
+ goto done;
+ }
+ temp_set++;
+ }
+ }
+
+ done:
+ if (!found && buf[0]) {
+ printf("command not found: %s\n", buf);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ printf("result was %s\n", nt_errstr(result));
+ }
+
+ return result;
+}
+
+void exit_server(char *reason)
+{
+ DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
+ exit(0);
+}
+
+static int server_fd = -1;
+int last_message = -1;
+
+int smbd_server_fd(void)
+{
+ return server_fd;
+}
+
+BOOL reload_services(BOOL test)
+{
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char *argv[])
+{
+ BOOL interactive = True;
+ int opt;
+ static char *cmdstr = "";
+ static char *opt_logfile=NULL;
+ static char *config_file = dyn_CONFIGFILE;
+ pstring logfile;
+ struct cmd_set **cmd_set;
+ struct samtest_state st;
+
+
+ /* make sure the vars that get altered (4th field) are in
+ a fixed location or certain compilers complain */
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
+ {"command", 'e', POPT_ARG_STRING, &cmdstr, 'e', "Execute semicolon seperated cmds"},
+ {"logfile", 'l', POPT_ARG_STRING, &opt_logfile, 'l', "Logfile to use instead of stdout"},
+ {"configfile", 'c', POPT_ARG_STRING, &config_file, 0,"use different configuration file",NULL},
+ { 0, 0, 0, 0}
+ };
+
+ ZERO_STRUCT(st);
+
+ setlinebuf(stdout);
+
+ DEBUGLEVEL = 1;
+
+ pc = poptGetContext("samtest", argc, (const char **) argv,
+ long_options, 0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'l':
+ slprintf(logfile, sizeof(logfile) - 1, "%s.client",
+ opt_logfile);
+ lp_set_logfile(logfile);
+ interactive = False;
+ break;
+ }
+ }
+
+ if (!lp_load(config_file,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", config_file);
+ exit(1);
+ }
+
+ poptFreeContext(pc);
+
+ /* the following functions are part of the Samba debugging
+ facilities. See lib/debug.c */
+ setup_logging("samtest", interactive);
+ if (!interactive)
+ reopen_logs();
+
+ /* Load command lists */
+
+ cmd_set = samtest_command_list;
+
+ while(*cmd_set) {
+ add_command_set(*cmd_set);
+ add_command_set(separator_command);
+ cmd_set++;
+ }
+
+ /* Do anything specified with -c */
+ if (cmdstr[0]) {
+ char *cmd;
+ char *p = cmdstr;
+
+ while((cmd=next_command(&p)) != NULL) {
+ process_cmd(&st, cmd);
+ }
+
+ return 0;
+ }
+
+ /* Loop around accepting commands */
+
+ while(1) {
+ pstring prompt;
+ char *line;
+
+ slprintf(prompt, sizeof(prompt) - 1, "samtest $> ");
+
+ line = smb_readline(prompt, NULL, NULL);
+
+ if (line == NULL)
+ break;
+
+ if (line[0] != '\n')
+ process_cmd(&st, line);
+ }
+
+ return 0;
+}
diff --git a/source3/torture/samtest.h b/source3/torture/samtest.h
new file mode 100644
index 0000000000..a136ab191e
--- /dev/null
+++ b/source3/torture/samtest.h
@@ -0,0 +1,38 @@
+/*
+ Unix SMB/CIFS implementation.
+ SAM module tester
+
+ Copyright (C) Jelmer Vernooij 2002
+
+ Most of this code was ripped off of rpcclient.
+ Copyright (C) Tim Potter 2000-2001
+
+ 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.
+*/
+
+struct samtest_state {
+ SAM_CONTEXT *context;
+ NT_USER_TOKEN *token;
+};
+
+struct cmd_set {
+ char *name;
+ NTSTATUS (*fn)(struct samtest_state *sam, TALLOC_CTX *mem_ctx, int argc,
+ char **argv);
+ char *description;
+ char *usage;
+};
+
+
diff --git a/source3/torture/vfstest.c b/source3/torture/vfstest.c
new file mode 100644
index 0000000000..c68d2b04d2
--- /dev/null
+++ b/source3/torture/vfstest.c
@@ -0,0 +1,593 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS module tester
+
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Eric Lorimer 2002
+ Copyright (C) Jelmer Vernooij 2002
+
+ Most of this code was ripped off of rpcclient.
+ Copyright (C) Tim Potter 2000-2001
+
+ 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 "includes.h"
+#include "vfstest.h"
+
+/* List to hold groups of commands */
+static struct cmd_list {
+ struct cmd_list *prev, *next;
+ struct cmd_set *cmd_set;
+} *cmd_list;
+
+extern pstring user_socket_options;
+
+/****************************************************************************
+handle completion of commands for readline
+****************************************************************************/
+static char **completion_fn(char *text, int start, int end)
+{
+#define MAX_COMPLETIONS 100
+ char **matches;
+ int i, count=0;
+ struct cmd_list *commands = cmd_list;
+
+ if (start)
+ return NULL;
+
+ /* make sure we have a list of valid commands */
+ if (!commands)
+ return NULL;
+
+ matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
+ if (!matches) return NULL;
+
+ matches[count++] = strdup(text);
+ if (!matches[0]) return NULL;
+
+ while (commands && count < MAX_COMPLETIONS-1)
+ {
+ if (!commands->cmd_set)
+ break;
+
+ for (i=0; commands->cmd_set[i].name; i++)
+ {
+ if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
+ commands->cmd_set[i].fn)
+ {
+ matches[count] = strdup(commands->cmd_set[i].name);
+ if (!matches[count])
+ return NULL;
+ count++;
+ }
+ }
+
+ commands = commands->next;
+
+ }
+
+ if (count == 2) {
+ SAFE_FREE(matches[0]);
+ matches[0] = strdup(matches[1]);
+ }
+ matches[count] = NULL;
+ return matches;
+}
+
+static char* next_command(char** cmdstr)
+{
+ static pstring command;
+ char *p;
+
+ if (!cmdstr || !(*cmdstr))
+ return NULL;
+
+ p = strchr_m(*cmdstr, ';');
+ if (p)
+ *p = '\0';
+ pstrcpy(command, *cmdstr);
+ *cmdstr = p;
+
+ return command;
+}
+
+/* Load specified configuration file */
+static NTSTATUS cmd_conf(struct vfs_state *vfs, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: %s <smb.conf>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (!lp_load(argv[1], False, True, False)) {
+ printf("Error loading \"%s\"\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ printf("\"%s\" successfully loaded\n", argv[1]);
+ return NT_STATUS_OK;
+}
+
+/* Display help on commands */
+static NTSTATUS cmd_help(struct vfs_state *vfs, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ struct cmd_list *tmp;
+ struct cmd_set *tmp_set;
+
+ /* Usage */
+ if (argc > 2) {
+ printf("Usage: %s [command]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Help on one command */
+
+ if (argc == 2) {
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+ if (strequal(argv[1], tmp_set->name)) {
+ if (tmp_set->usage &&
+ tmp_set->usage[0])
+ printf("%s\n", tmp_set->usage);
+ else
+ printf("No help for %s\n", tmp_set->name);
+
+ return NT_STATUS_OK;
+ }
+
+ tmp_set++;
+ }
+ }
+
+ printf("No such command: %s\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ /* List all commands */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+
+ printf("%15s\t\t%s\n", tmp_set->name,
+ tmp_set->description ? tmp_set->description:
+ "");
+
+ tmp_set++;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Change the debug level */
+static NTSTATUS cmd_debuglevel(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ if (argc > 2) {
+ printf("Usage: %s [debuglevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ DEBUGLEVEL = atoi(argv[1]);
+ }
+
+ printf("debuglevel is %d\n", DEBUGLEVEL);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_freemem(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ /* Cleanup */
+ talloc_destroy(mem_ctx);
+ mem_ctx = NULL;
+ vfs->data = NULL;
+ vfs->data_size = 0;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_quit(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
+{
+ /* Cleanup */
+ talloc_destroy(mem_ctx);
+
+ exit(0);
+ return NT_STATUS_OK; /* NOTREACHED */
+}
+
+static struct cmd_set vfstest_commands[] = {
+
+ { "GENERAL OPTIONS" },
+
+ { "conf", cmd_conf, "Load smb configuration file", "conf <smb.conf>" },
+ { "help", cmd_help, "Get help on commands", "" },
+ { "?", cmd_help, "Get help on commands", "" },
+ { "debuglevel", cmd_debuglevel, "Set debug level", "" },
+ { "freemem", cmd_freemem, "Free currently allocated buffers", "" },
+ { "exit", cmd_quit, "Exit program", "" },
+ { "quit", cmd_quit, "Exit program", "" },
+
+ { NULL }
+};
+
+static struct cmd_set separator_command[] = {
+ { "---------------", NULL, "----------------------" },
+ { NULL }
+};
+
+
+extern struct cmd_set vfs_commands[];
+static struct cmd_set *vfstest_command_list[] = {
+ vfstest_commands,
+ vfs_commands,
+ NULL
+};
+
+static void add_command_set(struct cmd_set *cmd_set)
+{
+ struct cmd_list *entry;
+
+ if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
+ DEBUG(0, ("out of memory\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(entry);
+
+ entry->cmd_set = cmd_set;
+ DLIST_ADD(cmd_list, entry);
+}
+
+static NTSTATUS do_cmd(struct vfs_state *vfs, struct cmd_set *cmd_entry, char *cmd)
+{
+ char *p = cmd, **argv = NULL;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ pstring buf;
+ TALLOC_CTX *mem_ctx = NULL;
+ int argc = 0, i;
+
+ /* Count number of arguments first time through the loop then
+ allocate memory and strdup them. */
+
+ again:
+ while(next_token(&p, buf, " ", sizeof(buf))) {
+ if (argv) {
+ argv[argc] = strdup(buf);
+ }
+
+ argc++;
+ }
+
+ if (!argv) {
+
+ /* Create argument list */
+
+ argv = (char **)malloc(sizeof(char *) * argc);
+ memset(argv, 0, sizeof(char *) * argc);
+
+ if (!argv) {
+ fprintf(stderr, "out of memory\n");
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p = cmd;
+ argc = 0;
+
+ goto again;
+ }
+
+ /* Call the function */
+
+ if (cmd_entry->fn) {
+
+ if (mem_ctx == NULL) {
+ /* Create mem_ctx */
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ goto done;
+ }
+ }
+
+ /* Run command */
+ result = cmd_entry->fn(vfs, mem_ctx, argc, argv);
+
+ } else {
+ fprintf (stderr, "Invalid command\n");
+ goto done;
+ }
+
+ done:
+
+ /* Cleanup */
+
+ if (argv) {
+ for (i = 0; i < argc; i++)
+ SAFE_FREE(argv[i]);
+
+ SAFE_FREE(argv);
+ }
+
+ return result;
+}
+
+/* Process a command entered at the prompt or as part of -c */
+static NTSTATUS process_cmd(struct vfs_state *vfs, char *cmd)
+{
+ struct cmd_list *temp_list;
+ BOOL found = False;
+ pstring buf;
+ char *p = cmd;
+ NTSTATUS result = NT_STATUS_OK;
+ int len = 0;
+
+ if (cmd[strlen(cmd) - 1] == '\n')
+ cmd[strlen(cmd) - 1] = '\0';
+
+ if (!next_token(&p, buf, " ", sizeof(buf))) {
+ return NT_STATUS_OK;
+ }
+
+ /* strip the trainly \n if it exsists */
+ len = strlen(buf);
+ if (buf[len-1] == '\n')
+ buf[len-1] = '\0';
+
+ /* Search for matching commands */
+
+ for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
+ struct cmd_set *temp_set = temp_list->cmd_set;
+
+ while(temp_set->name) {
+ if (strequal(buf, temp_set->name)) {
+ found = True;
+ result = do_cmd(vfs, temp_set, cmd);
+
+ goto done;
+ }
+ temp_set++;
+ }
+ }
+
+ done:
+ if (!found && buf[0]) {
+ printf("command not found: %s\n", buf);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ printf("result was %s\n", nt_errstr(result));
+ }
+
+ return result;
+}
+
+static void process_file(struct vfs_state *pvfs, char *filename) {
+ FILE *file;
+ char command[3 * PATH_MAX];
+
+ if (*filename == '-') {
+ file = stdin;
+ } else {
+ file = fopen(filename, "r");
+ if (file == NULL) {
+ printf("vfstest: error reading file (%s)!", filename);
+ printf("errno n.%d: %s", errno, strerror(errno));
+ exit(-1);
+ }
+ }
+
+ while (fgets(command, 3 * PATH_MAX, file) != NULL) {
+ process_cmd(pvfs, command);
+ }
+}
+
+void exit_server(char *reason)
+{
+ DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
+ exit(0);
+}
+
+static int server_fd = -1;
+int last_message = -1;
+
+int smbd_server_fd(void)
+{
+ return server_fd;
+}
+
+/****************************************************************************
+ Reload the services file.
+**************************************************************************/
+
+BOOL reload_services(BOOL test)
+{
+ BOOL ret;
+
+ if (lp_loaded()) {
+ pstring fname;
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname, NULL) &&
+ !strcsequal(fname, dyn_CONFIGFILE)) {
+ pstrcpy(dyn_CONFIGFILE, fname);
+ test = False;
+ }
+ }
+
+ reopen_logs();
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ lp_killunused(conn_snum_used);
+
+ ret = lp_load(dyn_CONFIGFILE, False, False, True);
+
+ load_printers();
+
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(True);
+
+ reopen_logs();
+
+ load_interfaces();
+
+ {
+ if (smbd_server_fd() != -1) {
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(), user_socket_options);
+ }
+ }
+
+ mangle_reset_cache();
+ reset_stat_cache();
+
+ /* this forces service parameters to be flushed */
+ set_current_service(NULL,True);
+
+ return (ret);
+}
+
+/* Main function */
+
+int main(int argc, char *argv[])
+{
+ BOOL interactive = True;
+ int opt;
+ static char *cmdstr = "";
+ static char *opt_logfile=NULL;
+ static int opt_debuglevel;
+ pstring logfile;
+ struct cmd_set **cmd_set;
+ extern BOOL AllowDebugChange;
+ static struct vfs_state vfs;
+ int i;
+ static char *filename = "";
+
+ /* make sure the vars that get altered (4th field) are in
+ a fixed location or certain compilers complain */
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"file", 'f', POPT_ARG_STRING, &filename, 0, },
+ {"command", 'c', POPT_ARG_STRING, &cmdstr, 0, "Execute specified list of commands" },
+ {"logfile", 'l', POPT_ARG_STRING, &opt_logfile, 'l', "Write output to specified logfile" },
+ { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
+ { 0, 0, 0, 0}
+ };
+
+
+ setlinebuf(stdout);
+
+ DEBUGLEVEL = 1;
+ AllowDebugChange = False;
+
+ pc = poptGetContext("vfstest", argc, (const char **) argv,
+ long_options, 0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'l':
+ slprintf(logfile, sizeof(logfile) - 1, "%s.client",
+ opt_logfile);
+ lp_set_logfile(logfile);
+ interactive = False;
+ break;
+
+ case 'd':
+ DEBUGLEVEL = opt_debuglevel;
+ break;
+ }
+ }
+
+
+ poptFreeContext(pc);
+
+ /* TODO: check output */
+ reload_services(False);
+
+ /* the following functions are part of the Samba debugging
+ facilities. See lib/debug.c */
+ setup_logging("vfstest", interactive);
+ if (!interactive)
+ reopen_logs();
+
+ /* Load command lists */
+
+ cmd_set = vfstest_command_list;
+
+ while(*cmd_set) {
+ add_command_set(*cmd_set);
+ add_command_set(separator_command);
+ cmd_set++;
+ }
+
+ /* some basic initialization stuff */
+ vfs.conn = (struct connection_struct *)malloc(sizeof(struct connection_struct));
+ vfs.conn->user = "vfstest";
+ for (i=0; i < 1024; i++)
+ vfs.files[i] = NULL;
+
+ /* some advanced initiliazation stuff */
+ smbd_vfs_init(vfs.conn);
+
+ /* Do we have a file input? */
+ if (filename[0]) {
+ process_file(&vfs, filename);
+ return 0;
+ }
+
+ /* Do anything specified with -c */
+ if (cmdstr[0]) {
+ char *cmd;
+ char *p = cmdstr;
+
+ while((cmd=next_command(&p)) != NULL) {
+ process_cmd(&vfs, cmd);
+ }
+
+ return 0;
+ }
+
+ /* Loop around accepting commands */
+
+ while(1) {
+ pstring prompt;
+ char *line;
+
+ slprintf(prompt, sizeof(prompt) - 1, "vfstest $> ");
+
+ line = smb_readline(prompt, NULL, completion_fn);
+
+ if (line == NULL)
+ break;
+
+ if (line[0] != '\n')
+ process_cmd(&vfs, line);
+ }
+
+ free(vfs.conn);
+ return 0;
+}
diff --git a/source3/torture/vfstest.h b/source3/torture/vfstest.h
new file mode 100644
index 0000000000..b086faa402
--- /dev/null
+++ b/source3/torture/vfstest.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/CIFS implementation.
+ VFS module tester
+
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Eric Lorimer 2002
+
+ Most of this code was ripped off of rpcclient.
+ Copyright (C) Tim Potter 2000-2001
+
+ 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.
+*/
+
+struct func_entry {
+ char *name;
+ int (*fn)(struct connection_struct *conn, const char *path);
+};
+
+struct vfs_state {
+ struct connection_struct *conn;
+ struct files_struct *files[1024];
+ DIR *currentdir;
+ void *data;
+ size_t data_size;
+};
+
+struct cmd_set {
+ char *name;
+ NTSTATUS (*fn)(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc,
+ char **argv);
+ char *description;
+ char *usage;
+};
diff --git a/source3/utils/net_ads_cldap.c b/source3/utils/net_ads_cldap.c
new file mode 100644
index 0000000000..6821a5902e
--- /dev/null
+++ b/source3/utils/net_ads_cldap.c
@@ -0,0 +1,274 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads cldap functions
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+
+ 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 "includes.h"
+#include "../utils/net.h"
+
+#ifdef HAVE_ADS
+
+struct cldap_netlogon_reply {
+ uint32 version;
+ uint32 flags;
+ GUID guid;
+ char *domain;
+ char *server_name;
+ char *domain_flatname;
+ char *server_flatname;
+ char *dns_name;
+ uint32 unknown2[2];
+};
+
+
+/*
+ pull a length prefixed string from a packet
+ return number of bytes consumed
+*/
+static unsigned pull_len_string(char **ret, const char *p)
+{
+ unsigned len = *p;
+ (*ret) = NULL;
+ if (len == 0) return 1;
+ (*ret) = smb_xstrndup(p+1, len);
+ return len+1;
+}
+
+/*
+ pull a dotted string from a packet
+ return number of bytes consumed
+*/
+static unsigned pull_dotted_string(char **ret, const char *p)
+{
+ char *s;
+ unsigned len, total_len=0;
+
+ (*ret) = NULL;
+
+ while ((len = pull_len_string(&s, p)) > 1) {
+ if (total_len) {
+ char *s2;
+ asprintf(&s2, "%s.%s", *ret, s);
+ SAFE_FREE(*ret);
+ (*ret) = s2;
+ } else {
+ (*ret) = s;
+ }
+ total_len += len;
+ p += len;
+ }
+
+ return total_len + 1;
+}
+
+
+/*
+ do a cldap netlogon query
+*/
+static int send_cldap_netlogon(int sock, const char *domain,
+ const char *hostname, unsigned ntversion)
+{
+ ASN1_DATA data;
+ char ntver[4];
+
+ SIVAL(ntver, 0, ntversion);
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ asn1_write_Integer(&data, 4);
+ asn1_push_tag(&data, ASN1_APPLICATION(3));
+ asn1_write_OctetString(&data, NULL, 0);
+ asn1_write_enumerated(&data, 0);
+ asn1_write_enumerated(&data, 0);
+ asn1_write_Integer(&data, 0);
+ asn1_write_Integer(&data, 0);
+ asn1_write_BOOLEAN2(&data, False);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "DnsDomain", 9);
+ asn1_write_OctetString(&data, domain, strlen(domain));
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "Host", 4);
+ asn1_write_OctetString(&data, hostname, strlen(hostname));
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "NtVer", 5);
+ asn1_write_OctetString(&data, ntver, 4);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ asn1_write_OctetString(&data, "NetLogon", 8);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ d_printf("Failed to build cldap netlogon at offset %d\n", (int)data.ofs);
+ asn1_free(&data);
+ return -1;
+ }
+
+ if (write(sock, data.data, data.length) != data.length) {
+ d_printf("failed to send cldap query (%s)\n", strerror(errno));
+ }
+
+ file_save("cldap_query.dat", data.data, data.length);
+ asn1_free(&data);
+
+ return 0;
+}
+
+
+/*
+ receive a cldap netlogon reply
+*/
+static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
+{
+ int ret;
+ ASN1_DATA data;
+ DATA_BLOB blob;
+ DATA_BLOB os1, os2, os3;
+ uint32 i1;
+ char *p;
+
+ blob = data_blob(NULL, 8192);
+
+ ret = read(sock, blob.data, blob.length);
+
+ if (ret <= 0) {
+ d_printf("no reply received to cldap netlogon\n");
+ return -1;
+ }
+ blob.length = ret;
+
+ file_save("cldap_reply.dat", blob.data, blob.length);
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_read_Integer(&data, &i1);
+ asn1_start_tag(&data, ASN1_APPLICATION(4));
+ asn1_read_OctetString(&data, &os1);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_read_OctetString(&data, &os2);
+ asn1_start_tag(&data, ASN1_SET);
+ asn1_read_OctetString(&data, &os3);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ d_printf("Failed to parse cldap reply\n");
+ return -1;
+ }
+
+ file_save("cldap_reply_core.dat", os3.data, os3.length);
+
+ p = os3.data;
+
+ reply->version = IVAL(p, 0); p += 4;
+ reply->flags = IVAL(p, 0); p += 4;
+ memcpy(&reply->guid.info, p, GUID_SIZE);
+ p += GUID_SIZE;
+ p += pull_dotted_string(&reply->domain, p);
+ p += 2; /* 0xc018 - whats this? */
+ p += pull_len_string(&reply->server_name, p);
+ p += 2; /* 0xc018 - whats this? */
+ p += pull_len_string(&reply->domain_flatname, p);
+ p += 1;
+ p += pull_len_string(&reply->server_flatname, p);
+ p += 2;
+ p += pull_len_string(&reply->dns_name, p);
+
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+
+ return 0;
+}
+
+
+/*
+ free a cldap reply packet
+*/
+static void cldap_reply_free(struct cldap_netlogon_reply *reply)
+{
+ SAFE_FREE(reply->domain);
+ SAFE_FREE(reply->server_name);
+ SAFE_FREE(reply->domain_flatname);
+ SAFE_FREE(reply->server_flatname);
+ SAFE_FREE(reply->dns_name);
+}
+
+/*
+ do a cldap netlogon query
+*/
+int ads_cldap_netlogon(ADS_STRUCT *ads)
+{
+ int sock;
+ int ret;
+ extern pstring global_myname;
+ struct cldap_netlogon_reply reply;
+
+ sock = open_udp_socket(inet_ntoa(ads->ldap_ip), ads->ldap_port);
+ if (sock == -1) {
+ d_printf("Failed to open udp socket to %s:%u\n",
+ inet_ntoa(ads->ldap_ip),
+ ads->ldap_port);
+ return -1;
+ }
+
+ ret = send_cldap_netlogon(sock, ads->config.realm, global_myname, 6);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = recv_cldap_netlogon(sock, &reply);
+ close(sock);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ d_printf("Version: 0x%x\n", reply.version);
+ d_printf("GUID: ");
+ print_guid(&reply.guid);
+ d_printf("Flags: 0x%x\n", reply.flags);
+ d_printf("Domain: %s\n", reply.domain);
+ d_printf("Server Name: %s\n", reply.server_name);
+ d_printf("Flatname: %s\n", reply.domain_flatname);
+ d_printf("Server Name2: %s\n", reply.server_flatname);
+ d_printf("DNS Name: %s\n", reply.dns_name);
+
+ cldap_reply_free(&reply);
+
+ return ret;
+}
+
+
+#endif
diff --git a/source3/utils/net_cache.c b/source3/utils/net_cache.c
new file mode 100644
index 0000000000..359c06d1aa
--- /dev/null
+++ b/source3/utils/net_cache.c
@@ -0,0 +1,328 @@
+/*
+ Samba Unix/Linux SMB client library
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) Rafal Szczesniak 2002
+
+ 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 "includes.h"
+#include "net.h"
+
+/**
+ * @file net_cache.c
+ * @brief This is part of the net tool which is basically command
+ * line wrapper for gencache.c functions (mainly for testing)
+ *
+ **/
+
+
+/*
+ * These routines are used via gencache_iterate() to display the cache's contents
+ * (print_cache_entry) and to flush it (delete_cache_entry).
+ * Both of them are defined by first arg of gencache_iterate() routine.
+ */
+static void print_cache_entry(const char* keystr, const char* datastr, const time_t timeout)
+{
+ char* timeout_str = ctime(&timeout);
+ timeout_str[strlen(timeout_str) - 1] = '\0';
+ d_printf("Key: %s\t\t Value: %s\t\t Timeout: %s %s\n", keystr, datastr,
+ timeout_str, timeout > time(NULL) ? "": "(expired)");
+}
+
+static void delete_cache_entry(const char* keystr, const char* datastr, const time_t timeout)
+{
+ if (!gencache_del(keystr))
+ d_printf("Couldn't delete entry! key = %s", keystr);
+}
+
+
+/**
+ * Parse text representation of timeout value
+ *
+ * @param timeout_str string containing text representation of the timeout
+ * @return numeric timeout of time_t type
+ **/
+static time_t parse_timeout(const char* timeout_str)
+{
+ char sign = '\0', *number = NULL, unit = '\0';
+ int len, number_begin, number_end;
+ time_t timeout;
+
+ /* sign detection */
+ if (timeout_str[0] == '!' || timeout_str[0] == '+') {
+ sign = timeout_str[0];
+ number_begin = 1;
+ } else {
+ number_begin = 0;
+ }
+
+ /* unit detection */
+ len = strlen(timeout_str);
+ switch (timeout_str[len - 1]) {
+ case 's':
+ case 'm':
+ case 'h':
+ case 'd':
+ case 'w': unit = timeout_str[len - 1];
+ }
+
+ /* number detection */
+ len = (sign) ? strlen(&timeout_str[number_begin]) : len;
+ number_end = (unit) ? len - 1 : len;
+ number = strndup(&timeout_str[number_begin], number_end);
+
+ /* calculate actual timeout value */
+ timeout = (time_t)atoi(number);
+
+ switch (unit) {
+ case 'm': timeout *= 60; break;
+ case 'h': timeout *= 60*60; break;
+ case 'd': timeout *= 60*60*24; break;
+ case 'w': timeout *= 60*60*24*7; break; /* that's fair enough, I think :) */
+ }
+
+ switch (sign) {
+ case '!': timeout = time(NULL) - timeout; break;
+ case '+':
+ default: timeout += time(NULL); break;
+ }
+
+ if (number) SAFE_FREE(number);
+ return timeout;
+}
+
+
+/**
+ * Add an entry to the cache
+ *
+ * @param argv key, value and timeout are passed in command line
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_add(int argc, const char **argv)
+{
+ const char *keystr, *datastr, *timeout_str;
+ time_t timeout;
+
+ if (argc < 3) {
+ d_printf("\nUsage: net cache add <key string> <data string> <timeout>\n");
+ return -1;
+ }
+
+ keystr = argv[0];
+ datastr = argv[1];
+ timeout_str = argv[2];
+
+ /* parse timeout given in command line */
+ timeout = parse_timeout(timeout_str);
+ if (!timeout) {
+ d_printf("Invalid timeout argument.\n");
+ return -1;
+ }
+
+ if (gencache_add(keystr, datastr, timeout)) {
+ d_printf("New cache entry stored successfully.\n");
+ gencache_shutdown();
+ return 0;
+ }
+
+ d_printf("Entry couldn't be added. Perhaps there's already such a key.\n");
+ gencache_shutdown();
+ return -1;
+}
+
+
+/**
+ * Set new value of an existing entry in the cache
+ *
+ * @param argv key being searched and new value and timeout to set in the entry
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_set(int argc, const char **argv)
+{
+ const char *keystr, *datastr, *timeout_str;
+ time_t timeout;
+
+ if (argc < 3) {
+ d_printf("\nUsage: net cache set <key string> <data string> <timeout>\n");
+ return -1;
+ }
+
+ keystr = argv[0];
+ datastr = argv[1];
+ timeout_str = argv[2];
+
+ /* parse timeout given in command line */
+ timeout = parse_timeout(timeout_str);
+ if (!timeout) {
+ d_printf("Invalid timeout argument.\n");
+ return -1;
+ }
+
+ if (gencache_set(keystr, datastr, timeout)) {
+ d_printf("Cache entry set successfully.\n");
+ gencache_shutdown();
+ return 0;
+ }
+
+ d_printf("Entry couldn't be set. Perhaps there's no such a key.\n");
+ gencache_shutdown();
+ return -1;
+}
+
+
+/**
+ * Delete an entry in the cache
+ *
+ * @param argv key to delete an entry of
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_del(int argc, const char **argv)
+{
+ const char *keystr = argv[0];
+
+ if (argc < 1) {
+ d_printf("\nUsage: net cache add <key string>\n");
+ return -1;
+ }
+
+ if(gencache_del(keystr)) {
+ d_printf("Entry deleted.\n");
+ return 0;
+ }
+
+ d_printf("Couldn't delete specified entry\n");
+ return -1;
+}
+
+
+/**
+ * Get and display an entry from the cache
+ *
+ * @param argv key to search an entry of
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_get(int argc, const char **argv)
+{
+ const char* keystr = argv[0];
+ char* valuestr;
+ time_t timeout;
+
+ if (argc < 1) {
+ d_printf("\nUsage: net cache get <key>\n");
+ return -1;
+ }
+
+ if (gencache_get(keystr, &valuestr, &timeout)) {
+ print_cache_entry(keystr, valuestr, timeout);
+ return 0;
+ }
+
+ d_printf("Failed to find entry\n");
+ return -1;
+}
+
+
+/**
+ * Search an entry/entries in the cache
+ *
+ * @param argv key pattern to match the entries to
+ * @return 0 on success, otherwise failure
+ **/
+static int net_cache_search(int argc, const char **argv)
+{
+ const char* pattern;
+
+ if (argc < 1) {
+ d_printf("Usage: net cache search <pattern>\n");
+ return -1;
+ }
+
+ pattern = argv[0];
+ gencache_iterate(print_cache_entry, pattern);
+ return 0;
+}
+
+
+/**
+ * List the contents of the cache
+ *
+ * @param argv ignored in this functionailty
+ * @return always returns 0
+ **/
+static int net_cache_list(int argc, const char **argv)
+{
+ const char* pattern = "*";
+ gencache_iterate(print_cache_entry, pattern);
+ gencache_shutdown();
+ return 0;
+}
+
+
+/**
+ * Flush the whole cache
+ *
+ * @param argv ignored in this functionality
+ * @return always returns 0
+ **/
+static int net_cache_flush(int argc, const char **argv)
+{
+ const char* pattern = "*";
+ gencache_iterate(delete_cache_entry, pattern);
+ gencache_shutdown();
+ return 0;
+}
+
+
+/**
+ * Short help
+ *
+ * @param argv ignored in this functionality
+ * @return always returns -1
+ **/
+static int net_cache_usage(int argc, const char **argv)
+{
+ d_printf(" net cache add \t add add new cache entry\n");
+ d_printf(" net cache set \t set new value for existing cache entry\n");
+ d_printf(" net cache del \t delete existing cache entry by key\n");
+ d_printf(" net cache flush \t delete all entries existing in the cache\n");
+ d_printf(" net cache get \t get cache entry by key\n");
+ d_printf(" net cache search \t search for entries in the cache, by given pattern\n");
+ d_printf(" net cache list \t list all cache entries (just like search for \"*\")\n");
+ return -1;
+}
+
+
+/**
+ * Entry point to 'net cache' subfunctionality
+ *
+ * @param argv arguments passed to further called functions
+ * @return whatever further functions return
+ **/
+int net_cache(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"add", net_cache_add},
+ {"set", net_cache_set},
+ {"del", net_cache_del},
+ {"get", net_cache_get},
+ {"search", net_cache_search},
+ {"list", net_cache_list},
+ {"flush", net_cache_flush},
+ {NULL, NULL}
+ };
+
+ return net_run_function(argc, argv, func, net_cache_usage);
+}
diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c
new file mode 100644
index 0000000000..202d5b5c88
--- /dev/null
+++ b/source3/utils/net_rpc_samsync.c
@@ -0,0 +1,716 @@
+/*
+ Unix SMB/CIFS implementation.
+ dump the remote SAM using rpc samsync operations
+
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Tim Potter 2001,2002
+
+ 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 "includes.h"
+#include "../utils/net.h"
+
+extern DOM_SID global_sid_Builtin;
+
+static void display_group_mem_info(uint32 rid, SAM_GROUP_MEM_INFO *g)
+{
+ int i;
+ d_printf("Group mem %u: ", rid);
+ for (i=0;i<g->num_members;i++) {
+ d_printf("%u ", g->rids[i]);
+ }
+ d_printf("\n");
+}
+
+static void display_alias_info(uint32 rid, SAM_ALIAS_INFO *a)
+{
+ d_printf("Alias '%s' ", unistr2_static(&a->uni_als_name));
+ d_printf("desc='%s' rid=%u\n", unistr2_static(&a->uni_als_desc), a->als_rid);
+}
+
+static void display_alias_mem(uint32 rid, SAM_ALIAS_MEM_INFO *a)
+{
+ int i;
+ d_printf("Alias rid %u: ", rid);
+ for (i=0;i<a->num_members;i++) {
+ d_printf("%s ", sid_string_static(&a->sids[i].sid));
+ }
+ d_printf("\n");
+}
+
+static void display_account_info(uint32 rid, SAM_ACCOUNT_INFO *a)
+{
+ fstring hex_nt_passwd, hex_lm_passwd;
+ uchar lm_passwd[16], nt_passwd[16];
+
+ /* Decode hashes from password hash */
+ sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd, lm_passwd, 0);
+ sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd, nt_passwd, 0);
+
+ /* Encode as strings */
+ smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd, a->acb_info);
+ smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd, a->acb_info);
+
+ printf("%s:%d:%s:%s:%s:LCT-0\n", unistr2_static(&a->uni_acct_name),
+ a->user_rid, hex_lm_passwd, hex_nt_passwd,
+ smbpasswd_encode_acb_info(a->acb_info));
+}
+
+static void display_domain_info(SAM_DOMAIN_INFO *a)
+{
+ d_printf("Domain name: %s\n", unistr2_static(&a->uni_dom_name));
+}
+
+static void display_group_info(uint32 rid, SAM_GROUP_INFO *a)
+{
+ d_printf("Group '%s' ", unistr2_static(&a->uni_grp_name));
+ d_printf("desc='%s', rid=%u\n", unistr2_static(&a->uni_grp_desc), rid);
+}
+
+static void display_sam_entry(SAM_DELTA_HDR *hdr_delta, SAM_DELTA_CTR *delta)
+{
+ switch (hdr_delta->type) {
+ case SAM_DELTA_ACCOUNT_INFO:
+ display_account_info(hdr_delta->target_rid, &delta->account_info);
+ break;
+ case SAM_DELTA_GROUP_MEM:
+ display_group_mem_info(hdr_delta->target_rid, &delta->grp_mem_info);
+ break;
+ case SAM_DELTA_ALIAS_INFO:
+ display_alias_info(hdr_delta->target_rid, &delta->alias_info);
+ break;
+ case SAM_DELTA_ALIAS_MEM:
+ display_alias_mem(hdr_delta->target_rid, &delta->als_mem_info);
+ break;
+ case SAM_DELTA_DOMAIN_INFO:
+ display_domain_info(&delta->domain_info);
+ break;
+ case SAM_DELTA_GROUP_INFO:
+ display_group_info(hdr_delta->target_rid, &delta->group_info);
+ break;
+ default:
+ d_printf("Unknown delta record type %d\n", hdr_delta->type);
+ break;
+ }
+}
+
+
+static void dump_database(struct cli_state *cli, unsigned db_type, DOM_CRED *ret_creds)
+{
+ unsigned last_rid = -1;
+ NTSTATUS result;
+ int i;
+ TALLOC_CTX *mem_ctx;
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+ uint32 num_deltas;
+
+ if (!(mem_ctx = talloc_init())) {
+ return;
+ }
+
+ d_printf("Dumping database %u\n", db_type);
+
+ do {
+ result = cli_netlogon_sam_sync(cli, mem_ctx, ret_creds, db_type, last_rid+1,
+ &num_deltas, &hdr_deltas, &deltas);
+ clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), ret_creds);
+ last_rid = 0;
+ for (i = 0; i < num_deltas; i++) {
+ display_sam_entry(&hdr_deltas[i], &deltas[i]);
+ last_rid = hdr_deltas[i].target_rid;
+ }
+ } while (last_rid && NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ talloc_destroy(mem_ctx);
+}
+
+/* dump sam database via samsync rpc calls */
+int rpc_samdump(int argc, const char **argv)
+{
+ NTSTATUS result;
+ struct cli_state *cli = NULL;
+ uchar trust_password[16];
+ DOM_CRED ret_creds;
+ uint32 neg_flags = 0x000001ff;
+
+
+ ZERO_STRUCT(ret_creds);
+
+ /* Connect to remote machine */
+ if (!(cli = net_make_ipc_connection(NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC))) {
+ return 1;
+ }
+
+ if (!cli_nt_session_open(cli, PIPE_NETLOGON)) {
+ DEBUG(0,("Error connecting to NETLOGON pipe\n"));
+ goto fail;
+ }
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_password, NULL)) {
+ d_printf("Could not retrieve domain trust secret");
+ goto fail;
+ }
+
+ result = cli_nt_setup_creds(cli, SEC_CHAN_BDC, trust_password, &neg_flags, 2);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("Failed to setup BDC creds\n");
+ goto fail;
+ }
+
+ dump_database(cli, SAM_DATABASE_DOMAIN, &ret_creds);
+ dump_database(cli, SAM_DATABASE_BUILTIN, &ret_creds);
+ dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds);
+
+ cli_nt_session_close(cli);
+
+ return 0;
+
+fail:
+ if (cli) {
+ cli_nt_session_close(cli);
+ }
+ return -1;
+}
+
+/* Convert a SAM_ACCOUNT_DELTA to a SAM_ACCOUNT. */
+
+static NTSTATUS
+sam_account_from_delta(SAM_ACCOUNT *account, SAM_ACCOUNT_INFO *delta)
+{
+ DOM_SID sid;
+ fstring s;
+ uchar lm_passwd[16], nt_passwd[16];
+
+ /* Username, fullname, home dir, dir drive, logon script, acct
+ desc, workstations, profile. */
+
+ unistr2_to_ascii(s, &delta->uni_acct_name, sizeof(s) - 1);
+ pdb_set_nt_username(account, s);
+
+ /* Unix username is the same - for sainity */
+ pdb_set_username(account, s);
+
+ unistr2_to_ascii(s, &delta->uni_full_name, sizeof(s) - 1);
+ pdb_set_fullname(account, s);
+
+ unistr2_to_ascii(s, &delta->uni_home_dir, sizeof(s) - 1);
+ pdb_set_homedir(account, s, True);
+
+ unistr2_to_ascii(s, &delta->uni_dir_drive, sizeof(s) - 1);
+ pdb_set_dir_drive(account, s, True);
+
+ unistr2_to_ascii(s, &delta->uni_logon_script, sizeof(s) - 1);
+ pdb_set_logon_script(account, s, True);
+
+ unistr2_to_ascii(s, &delta->uni_acct_desc, sizeof(s) - 1);
+ pdb_set_acct_desc(account, s);
+
+ unistr2_to_ascii(s, &delta->uni_workstations, sizeof(s) - 1);
+ pdb_set_workstations(account, s);
+
+ unistr2_to_ascii(s, &delta->uni_profile, sizeof(s) - 1);
+ pdb_set_profile_path(account, s, True);
+
+ /* User and group sid */
+
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, delta->user_rid);
+ pdb_set_user_sid(account, &sid);
+
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, delta->group_rid);
+ pdb_set_group_sid(account, &sid);
+
+ /* Logon and password information */
+
+ pdb_set_logon_time(account, nt_time_to_unix(&delta->logon_time), True);
+ pdb_set_logoff_time(account, nt_time_to_unix(&delta->logoff_time),
+ True);
+ pdb_set_logon_divs(account, delta->logon_divs);
+
+ /* TODO: logon hours */
+ /* TODO: bad password count */
+ /* TODO: logon count */
+
+ pdb_set_pass_last_set_time(
+ account, nt_time_to_unix(&delta->pwd_last_set_time));
+
+ pdb_set_kickoff_time(account, get_time_t_max(), True);
+
+ /* Decode hashes from password hash */
+ sam_pwd_hash(delta->user_rid, delta->pass.buf_lm_pwd, lm_passwd, 0);
+ sam_pwd_hash(delta->user_rid, delta->pass.buf_nt_pwd, nt_passwd, 0);
+ pdb_set_nt_passwd(account, nt_passwd);
+ pdb_set_lanman_passwd(account, lm_passwd);
+
+ /* TODO: account expiry time */
+
+ pdb_set_acct_ctrl(account, delta->acb_info);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS
+fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta)
+{
+ NTSTATUS nt_ret;
+ fstring account;
+ pstring add_script;
+ SAM_ACCOUNT *sam_account=NULL;
+ GROUP_MAP map;
+ struct group *grp;
+
+ fstrcpy(account, unistr2_static(&delta->uni_acct_name));
+ d_printf("Creating account: %s\n", account);
+
+ if (!NT_STATUS_IS_OK(nt_ret = pdb_init_sam(&sam_account)))
+ return nt_ret;
+
+ if (!pdb_getsampwnam(sam_account, account)) {
+ struct passwd *pw;
+
+ pdb_free_sam(&sam_account);
+
+ /* Create appropriate user */
+ if (delta->acb_info & ACB_NORMAL) {
+ pstrcpy(add_script, lp_adduser_script());
+ } else if ( (delta->acb_info & ACB_WSTRUST) ||
+ (delta->acb_info & ACB_SVRTRUST) ) {
+ pstrcpy(add_script, lp_addmachine_script());
+ } else {
+ DEBUG(1, ("Unknown user type: %s\n",
+ smbpasswd_encode_acb_info(delta->acb_info)));
+ pdb_free_sam(&sam_account);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ if (*add_script) {
+ int add_ret;
+ all_string_sub(add_script, "%u", account,
+ sizeof(account));
+ add_ret = smbrun(add_script,NULL);
+ DEBUG(1,("fetch_account: Running the command `%s' "
+ "gave %d\n", add_script, add_ret));
+ }
+ pw = getpwnam_alloc(account);
+ if (pw) {
+ nt_ret = pdb_init_sam_pw(&sam_account, pw);
+
+ if (!NT_STATUS_IS_OK(nt_ret)) {
+ passwd_free(&pw);
+ pdb_free_sam(&sam_account);
+ return nt_ret;
+ }
+ passwd_free(&pw);
+ } else {
+ DEBUG(3, ("Could not create account %s\n", account));
+ pdb_free_sam(&sam_account);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ sam_account_from_delta(sam_account, delta);
+
+ if (!pdb_add_sam_account(sam_account)) {
+ DEBUG(1, ("SAM Account for %s already existed, updating\n",
+ account));
+ pdb_update_sam_account(sam_account);
+ }
+
+ if (!get_group_map_from_sid(*pdb_get_group_sid(sam_account),
+ &map, False)) {
+ DEBUG(0, ("Primary group of %s has no mapping!\n",
+ pdb_get_username(sam_account)));
+ pdb_free_sam(&sam_account);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (!(grp = getgrgid(map.gid))) {
+ DEBUG(0, ("Could not find unix group %d\n", map.gid));
+ pdb_free_sam(&sam_account);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
+
+ pdb_free_sam(&sam_account);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS
+fetch_group_info(uint32 rid, SAM_GROUP_INFO *delta)
+{
+ fstring name;
+ fstring comment;
+ struct group *grp = NULL;
+ DOM_SID group_sid;
+ fstring sid_string;
+ GROUP_MAP map;
+ int flag = TDB_INSERT;
+ gid_t gid;
+
+ unistr2_to_ascii(name, &delta->uni_grp_name, sizeof(name)-1);
+ unistr2_to_ascii(comment, &delta->uni_grp_desc, sizeof(comment)-1);
+
+ if ((grp = getgrnam(name)) == NULL)
+ smb_create_group(name, &gid);
+
+ if ((grp = getgrgid(gid)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* add the group to the mapping table */
+ sid_copy(&group_sid, get_global_sam_sid());
+ sid_append_rid(&group_sid, rid);
+ sid_to_string(sid_string, &group_sid);
+
+ if (get_group_map_from_sid(group_sid, &map, False)) {
+ grp = getgrgid(map.gid);
+ flag = 0; /* Don't TDB_INSERT, mapping exists */
+ }
+
+ if (grp == NULL)
+ {
+ gid_t new_gid;
+ /* No group found from mapping, find it from its name. */
+ if ((grp = getgrnam(name)) == NULL) {
+ /* No appropriate group found, create one */
+ d_printf("Creating unix group: '%s'\n", name);
+ if (smb_create_group(name, &new_gid) != 0)
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ((grp = getgrgid(new_gid)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ map.gid = grp->gr_gid;
+ map.sid = group_sid;
+ map.sid_name_use = SID_NAME_DOM_GRP;
+ fstrcpy(map.nt_name, name);
+ fstrcpy(map.comment, comment);
+
+ map.priv_set.count = 0;
+ map.priv_set.set = NULL;
+
+ add_mapping_entry(&map, flag);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS
+fetch_group_mem_info(uint32 rid, SAM_GROUP_MEM_INFO *delta)
+{
+ int i;
+ TALLOC_CTX *t = NULL;
+ char **nt_members = NULL;
+ char **unix_members;
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ struct group *grp;
+
+ if (delta->num_members == 0) {
+ return NT_STATUS_OK;
+ }
+
+ sid_copy(&group_sid, get_global_sam_sid());
+ sid_append_rid(&group_sid, rid);
+
+ if (!get_domain_group_from_sid(group_sid, &map, False)) {
+ DEBUG(0, ("Could not find global group %d\n", rid));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ if (!(grp = getgrgid(map.gid))) {
+ DEBUG(0, ("Could not find unix group %d\n", map.gid));
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ d_printf("Group members of %s: ", grp->gr_name);
+
+ if (!(t = talloc_init())) {
+ DEBUG(0, ("could not talloc_init\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_members = talloc_zero(t, sizeof(char *) * delta->num_members);
+
+ for (i=0; i<delta->num_members; i++) {
+ NTSTATUS nt_status;
+ SAM_ACCOUNT *member = NULL;
+ DOM_SID member_sid;
+
+ if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(t, &member))) {
+ talloc_destroy(t);
+ return nt_status;
+ }
+
+ sid_copy(&member_sid, get_global_sam_sid());
+ sid_append_rid(&member_sid, delta->rids[i]);
+
+ if (!pdb_getsampwsid(member, &member_sid)) {
+ DEBUG(1, ("Found bogus group member: %d\n",
+ delta->rids[i]));
+ pdb_free_sam(&member);
+ continue;
+ }
+
+ if (pdb_get_group_rid(member) == rid) {
+ d_printf("%s(primary),", pdb_get_username(member));
+ pdb_free_sam(&member);
+ continue;
+ }
+
+ d_printf("%s,", pdb_get_username(member));
+ nt_members[i] = talloc_strdup(t, pdb_get_username(member));
+ pdb_free_sam(&member);
+ }
+
+ d_printf("\n");
+
+ unix_members = grp->gr_mem;
+
+ while (*unix_members) {
+ BOOL is_nt_member = False;
+ for (i=0; i<delta->num_members; i++) {
+ if (nt_members[i] == NULL) {
+ /* This was a primary group */
+ continue;
+ }
+
+ if (strcmp(*unix_members, nt_members[i]) == 0) {
+ is_nt_member = True;
+ break;
+ }
+ }
+ if (!is_nt_member) {
+ /* We look at a unix group member that is not
+ an nt group member. So, remove it. NT is
+ boss here. */
+ smb_delete_user_group(grp->gr_name, *unix_members);
+ }
+ unix_members += 1;
+ }
+
+ for (i=0; i<delta->num_members; i++) {
+ BOOL is_unix_member = False;
+
+ if (nt_members[i] == NULL) {
+ /* This was the primary group */
+ continue;
+ }
+
+ unix_members = grp->gr_mem;
+
+ while (*unix_members) {
+ if (strcmp(*unix_members, nt_members[i]) == 0) {
+ is_unix_member = True;
+ break;
+ }
+ unix_members += 1;
+ }
+
+ if (!is_unix_member) {
+ /* We look at a nt group member that is not a
+ unix group member currently. So, add the nt
+ group member. */
+ smb_add_user_group(grp->gr_name, nt_members[i]);
+ }
+ }
+
+ talloc_destroy(t);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fetch_alias_info(uint32 rid, SAM_ALIAS_INFO *delta,
+ DOM_SID dom_sid)
+{
+ fstring name;
+ fstring comment;
+ struct group *grp = NULL;
+ DOM_SID alias_sid;
+ fstring sid_string;
+ GROUP_MAP map;
+ int insert_flag = TDB_INSERT;
+
+ unistr2_to_ascii(name, &delta->uni_als_name, sizeof(name)-1);
+ unistr2_to_ascii(comment, &delta->uni_als_desc, sizeof(comment)-1);
+
+ /* Find out whether the group is already mapped */
+ sid_copy(&alias_sid, &dom_sid);
+ sid_append_rid(&alias_sid, rid);
+ sid_to_string(sid_string, &alias_sid);
+
+ if (get_group_map_from_sid(alias_sid, &map, False)) {
+ grp = getgrgid(map.gid);
+ insert_flag = 0; /* Don't TDB_INSERT, mapping exists */
+ }
+
+ if (grp == NULL) {
+ gid_t new_gid;
+ /* No group found from mapping, find it from its name. */
+ if ((grp = getgrnam(name)) == NULL) {
+ /* No appropriate group found, create one */
+ d_printf("Creating unix group: '%s'\n", name);
+ if (smb_create_group(name, &new_gid) != 0)
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if ((grp = getgrgid(new_gid)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ map.gid = grp->gr_gid;
+ map.sid = alias_sid;
+ map.sid_name_use = SID_NAME_ALIAS;
+
+ fstrcpy(map.nt_name, name);
+ fstrcpy(map.comment, comment);
+
+ map.priv_set.count = 0;
+ map.priv_set.set = NULL;
+
+ add_mapping_entry(&map, insert_flag);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS
+fetch_alias_mem(uint32 rid, SAM_ALIAS_MEM_INFO *delta, DOM_SID dom_sid)
+{
+
+ return NT_STATUS_OK;
+}
+
+static void
+fetch_sam_entry(SAM_DELTA_HDR *hdr_delta, SAM_DELTA_CTR *delta,
+ DOM_SID dom_sid)
+{
+ switch(hdr_delta->type) {
+ case SAM_DELTA_ACCOUNT_INFO:
+ fetch_account_info(hdr_delta->target_rid,
+ &delta->account_info);
+ break;
+ case SAM_DELTA_GROUP_INFO:
+ fetch_group_info(hdr_delta->target_rid,
+ &delta->group_info);
+ break;
+ case SAM_DELTA_GROUP_MEM:
+ fetch_group_mem_info(hdr_delta->target_rid,
+ &delta->grp_mem_info);
+ break;
+ case SAM_DELTA_ALIAS_INFO:
+ fetch_alias_info(hdr_delta->target_rid,
+ &delta->alias_info, dom_sid);
+ break;
+ case SAM_DELTA_ALIAS_MEM:
+ fetch_alias_mem(hdr_delta->target_rid,
+ &delta->als_mem_info, dom_sid);
+ break;
+ default:
+ d_printf("Unknown delta record type %d\n", hdr_delta->type);
+ break;
+ }
+}
+
+static void
+fetch_database(struct cli_state *cli, unsigned db_type, DOM_CRED *ret_creds,
+ DOM_SID dom_sid)
+{
+ unsigned last_rid = -1;
+ NTSTATUS result;
+ int i;
+ TALLOC_CTX *mem_ctx;
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+ uint32 num_deltas;
+
+ if (!(mem_ctx = talloc_init())) {
+ return;
+ }
+
+ d_printf("Fetching database %u\n", db_type);
+
+ do {
+ result = cli_netlogon_sam_sync(cli, mem_ctx, ret_creds,
+ db_type, last_rid+1,
+ &num_deltas,
+ &hdr_deltas, &deltas);
+ clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred),
+ ret_creds);
+ last_rid = 0;
+ for (i = 0; i < num_deltas; i++) {
+ fetch_sam_entry(&hdr_deltas[i], &deltas[i], dom_sid);
+ last_rid = hdr_deltas[i].target_rid;
+ }
+ } while (last_rid && NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ talloc_destroy(mem_ctx);
+}
+
+/* dump sam database via samsync rpc calls */
+int rpc_vampire(int argc, const char **argv)
+{
+ NTSTATUS result;
+ struct cli_state *cli = NULL;
+ uchar trust_password[16];
+ DOM_CRED ret_creds;
+ uint32 neg_flags = 0x000001ff;
+ DOM_SID dom_sid;
+
+ ZERO_STRUCT(ret_creds);
+
+ /* Connect to remote machine */
+ if (!(cli = net_make_ipc_connection(NET_FLAGS_ANONYMOUS |
+ NET_FLAGS_PDC))) {
+ return 1;
+ }
+
+ if (!cli_nt_session_open(cli, PIPE_NETLOGON)) {
+ DEBUG(0,("Error connecting to NETLOGON pipe\n"));
+ goto fail;
+ }
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(),
+ trust_password, NULL)) {
+ d_printf("Could not retrieve domain trust secret");
+ goto fail;
+ }
+
+ result = cli_nt_setup_creds(cli, SEC_CHAN_BDC, trust_password,
+ &neg_flags, 2);
+ if (!NT_STATUS_IS_OK(result)) {
+ d_printf("Failed to setup BDC creds\n");
+ goto fail;
+ }
+
+ dom_sid = *get_global_sam_sid();
+ fetch_database(cli, SAM_DATABASE_DOMAIN, &ret_creds, dom_sid);
+
+ sid_copy(&dom_sid, &global_sid_Builtin);
+ fetch_database(cli, SAM_DATABASE_BUILTIN, &ret_creds, dom_sid);
+
+ /* Currently we crash on PRIVS somewhere in unmarshalling */
+ /* Dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds); */
+
+ cli_nt_session_close(cli);
+
+ return 0;
+
+fail:
+ if (cli) {
+ cli_nt_session_close(cli);
+ }
+ return -1;
+}