summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/include/adt_tree.h38
-rw-r--r--source3/include/ntioctl.h26
-rw-r--r--source3/lib/adt_tree.c464
-rw-r--r--source3/lib/popt_common.c49
-rw-r--r--source3/lib/system_smbd.c105
-rw-r--r--source3/lib/util_smbd.c65
-rw-r--r--source3/lib/util_uuid.c72
-rw-r--r--source3/libsmb/namecache.c252
-rw-r--r--source3/python/py_common_proto.h32
-rw-r--r--source3/python/py_lsa.c462
-rw-r--r--source3/python/py_smb.c224
-rw-r--r--source3/python/py_smb.h42
-rw-r--r--source3/registry/reg_cachehook.c112
-rw-r--r--source3/registry/reg_db.c311
-rw-r--r--source3/registry/reg_frontend.c575
-rw-r--r--source3/registry/reg_printing.c814
-rw-r--r--source3/rpc_client/cli_dfs.c245
-rw-r--r--source3/rpc_client/cli_lsarpc.c1256
-rw-r--r--source3/sam/SAM-interface_handles.txt123
-rwxr-xr-xsource3/script/cvslog.pl102
20 files changed, 5369 insertions, 0 deletions
diff --git a/source3/include/adt_tree.h b/source3/include/adt_tree.h
new file mode 100644
index 0000000000..b1bf7ad85d
--- /dev/null
+++ b/source3/include/adt_tree.h
@@ -0,0 +1,38 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generic Abstract Data Types
+ * 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.
+ */
+
+#ifndef ADT_TREE_H
+#define ADT_TREE_H
+
+typedef struct _tree_node {
+ struct _tree_node *parent;
+ struct _tree_node **children;
+ int num_children;
+ char *key;
+ void *data_p;
+} TREE_NODE;
+
+typedef struct _tree_root {
+ TREE_NODE *root;
+ int (*compare)(void* x, void *y);
+ void (*free)(void *p);
+} SORTED_TREE;
+
+#endif
diff --git a/source3/include/ntioctl.h b/source3/include/ntioctl.h
new file mode 100644
index 0000000000..4749842ddc
--- /dev/null
+++ b/source3/include/ntioctl.h
@@ -0,0 +1,26 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT ioctl code constants
+ Copyright (C) Andrew Tridgell 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.
+*/
+
+/*
+ I'm guessing we will need to support a bunch of these eventually. For now
+ we only need the sparse flag
+*/
+
+#define NTIOCTL_SET_SPARSE 0x900c4
diff --git a/source3/lib/adt_tree.c b/source3/lib/adt_tree.c
new file mode 100644
index 0000000000..2c18bb1198
--- /dev/null
+++ b/source3/lib/adt_tree.c
@@ -0,0 +1,464 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generic Abstract Data Types
+ * 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.
+ */
+
+#include "includes.h"
+
+
+/**************************************************************************
+ Initialize the tree's root. The cmp_fn is a callback function used
+ for comparision of two children
+ *************************************************************************/
+
+static BOOL trim_tree_keypath( char *path, char **base, char **new_path )
+{
+ char *p;
+
+ *new_path = *base = NULL;
+
+ if ( !path )
+ return False;
+
+ *base = path;
+
+ p = strchr( path, '/' );
+
+ if ( p ) {
+ *p = '\0';
+ *new_path = p+1;
+ }
+
+ return True;
+}
+
+
+/**************************************************************************
+ Initialize the tree's root. The cmp_fn is a callback function used
+ for comparision of two children
+ *************************************************************************/
+
+SORTED_TREE* sorted_tree_init( void *data_p,
+ int (cmp_fn)(void*, void*),
+ void (free_fn)(void*) )
+{
+ SORTED_TREE *tree = NULL;
+
+ if ( !(tree = (SORTED_TREE*)malloc( sizeof(SORTED_TREE) )) )
+ return NULL;
+
+ ZERO_STRUCTP( tree );
+
+ tree->compare = cmp_fn;
+ tree->free = free_fn;
+
+ if ( !(tree->root = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) ) {
+ SAFE_FREE( tree );
+ return NULL;
+ }
+
+ ZERO_STRUCTP( tree->root );
+ tree->root->data_p = data_p;
+
+ return tree;
+}
+
+
+/**************************************************************************
+ Delete a tree and free all allocated memory
+ *************************************************************************/
+
+static void sorted_tree_destroy_children( TREE_NODE *root )
+{
+ int i;
+
+ if ( !root )
+ return;
+
+ for ( i=0; i<root->num_children; i++ )
+ {
+ sorted_tree_destroy_children( root->children[i] );
+ }
+
+ SAFE_FREE( root->children );
+ SAFE_FREE( root->key );
+
+ return;
+}
+
+/**************************************************************************
+ Delete a tree and free all allocated memory
+ *************************************************************************/
+
+void sorted_tree_destroy( SORTED_TREE *tree )
+{
+ if ( tree->root )
+ sorted_tree_destroy_children( tree->root );
+
+ if ( tree->free )
+ tree->free( tree->root );
+
+ SAFE_FREE( tree );
+}
+
+/**************************************************************************
+ Find the next child given a key string
+ *************************************************************************/
+
+static TREE_NODE* sorted_tree_birth_child( TREE_NODE *node, char* key )
+{
+ TREE_NODE *infant = NULL;
+ TREE_NODE **siblings;
+ int i;
+
+ if ( !(infant = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) )
+ return NULL;
+
+ ZERO_STRUCTP( infant );
+
+ infant->key = strdup( key );
+ infant->parent = node;
+
+ siblings = Realloc( node->children, sizeof(TREE_NODE*)*(node->num_children+1) );
+
+ if ( siblings )
+ node->children = siblings;
+
+ node->num_children++;
+
+ /* first child */
+
+ if ( node->num_children == 1 ) {
+ DEBUG(11,("sorted_tree_birth_child: First child of node [%s]! [%s]\n",
+ node->key ? node->key : "NULL", infant->key ));
+ node->children[0] = infant;
+ }
+ else
+ {
+ /*
+ * multiple siblings .... (at least 2 children)
+ *
+ * work from the end of the list forward
+ * The last child is not set at this point
+ * Insert the new infanct in ascending order
+ * from left to right
+ */
+
+ for ( i = node->num_children-1; i>=1; i-- )
+ {
+ DEBUG(11,("sorted_tree_birth_child: Looking for crib; infant -> [%s], child -> [%s]\n",
+ infant->key, node->children[i-1]->key));
+
+ /* the strings should never match assuming that we
+ have called sorted_tree_find_child() first */
+
+ if ( StrCaseCmp( infant->key, node->children[i-1]->key ) > 0 ) {
+ DEBUG(11,("sorted_tree_birth_child: storing infant in i == [%d]\n",
+ i));
+ node->children[i] = infant;
+ break;
+ }
+
+ /* bump everything towards the end on slot */
+
+ node->children[i] = node->children[i-1];
+ }
+
+ DEBUG(11,("sorted_tree_birth_child: Exiting loop (i == [%d])\n", i ));
+
+ /* if we haven't found the correct slot yet, the child
+ will be first in the list */
+
+ if ( i == 0 )
+ node->children[0] = infant;
+ }
+
+ return infant;
+}
+
+/**************************************************************************
+ Find the next child given a key string
+ *************************************************************************/
+
+static TREE_NODE* sorted_tree_find_child( TREE_NODE *node, char* key )
+{
+ TREE_NODE *next = NULL;
+ int i, result;
+
+ if ( !node ) {
+ DEBUG(0,("sorted_tree_find_child: NULL node passed into function!\n"));
+ return NULL;
+ }
+
+ if ( !key ) {
+ DEBUG(0,("sorted_tree_find_child: NULL key string passed into function!\n"));
+ return NULL;
+ }
+
+ for ( i=0; i<node->num_children; i++ )
+ {
+ DEBUG(11,("sorted_tree_find_child: child key => [%s]\n",
+ node->children[i]->key));
+
+ result = StrCaseCmp( node->children[i]->key, key );
+
+ if ( result == 0 )
+ next = node->children[i];
+
+ /* if result > 0 then we've gone to far because
+ the list of children is sorted by key name
+ If result == 0, then we have a match */
+
+ if ( result > 0 )
+ break;
+ }
+
+ DEBUG(11,("sorted_tree_find_child: %s [%s]\n",
+ next ? "Found" : "Did not find", key ));
+
+ return next;
+}
+
+/**************************************************************************
+ Add a new node into the tree given a key path and a blob of data
+ *************************************************************************/
+
+BOOL sorted_tree_add( SORTED_TREE *tree, const char *path, void *data_p )
+{
+ char *str, *base, *path2;
+ TREE_NODE *current, *next;
+ BOOL ret = True;
+
+ DEBUG(8,("sorted_tree_add: Enter\n"));
+
+ if ( !path || *path != '/' ) {
+ DEBUG(0,("sorted_tree_add: Attempt to add a node with a bad path [%s]\n",
+ path ? path : "NULL" ));
+ return False;
+ }
+
+ if ( !tree ) {
+ DEBUG(0,("sorted_tree_add: Attempt to add a node to an uninitialized tree!\n"));
+ return False;
+ }
+
+ /* move past the first '/' */
+
+ path++;
+ path2 = strdup( path );
+ if ( !path2 ) {
+ DEBUG(0,("sorted_tree_add: strdup() failed on string [%s]!?!?!\n", path));
+ return False;
+ }
+
+
+ /*
+ * this works sort of like a 'mkdir -p' call, possibly
+ * creating an entire path to the new node at once
+ * The path should be of the form /<key1>/<key2>/...
+ */
+
+ base = path2;
+ str = path2;
+ current = tree->root;
+
+ do {
+ /* break off the remaining part of the path */
+
+ str = strchr( str, '/' );
+ if ( str )
+ *str = '\0';
+
+ /* iterate to the next child--birth it if necessary */
+
+ next = sorted_tree_find_child( current, base );
+ if ( !next ) {
+ next = sorted_tree_birth_child( current, base );
+ if ( !next ) {
+ DEBUG(0,("sorted_tree_add: Failed to create new child!\n"));
+ ret = False;
+ goto done;
+ }
+ }
+ current = next;
+
+ /* setup the next part of the path */
+
+ base = str;
+ if ( base ) {
+ *base = '/';
+ base++;
+ str = base;
+ }
+
+ } while ( base != NULL );
+
+ current->data_p = data_p;
+
+ DEBUG(10,("sorted_tree_add: Successfully added node [%s] to tree\n",
+ path ));
+
+ DEBUG(8,("sorted_tree_add: Exit\n"));
+
+done:
+ SAFE_FREE( path2 );
+ return ret;
+}
+
+
+/**************************************************************************
+ Recursive routine to print out all children of a TREE_NODE
+ *************************************************************************/
+
+static void sorted_tree_print_children( TREE_NODE *node, int debug, char *path )
+{
+ int i;
+ int num_children;
+ pstring path2;
+
+ if ( !node )
+ return;
+
+
+ if ( node->key )
+ DEBUG(debug,("%s: [%s] (%s)\n", path ? path : "NULL", node->key,
+ node->data_p ? "data" : "NULL" ));
+
+ *path2 = '\0';
+ if ( path )
+ pstrcpy( path2, path );
+ pstrcat( path2, node->key ? node->key : "NULL" );
+ pstrcat( path2, "/" );
+
+ num_children = node->num_children;
+ for ( i=0; i<num_children; i++ )
+ sorted_tree_print_children( node->children[i], debug, path2 );
+
+
+}
+
+/**************************************************************************
+ Dump the kys for a tree to the log file
+ *************************************************************************/
+
+void sorted_tree_print_keys( SORTED_TREE *tree, int debug )
+{
+ int i;
+ int num_children = tree->root->num_children;
+
+ if ( tree->root->key )
+ DEBUG(debug,("ROOT/: [%s] (%s)\n", tree->root->key,
+ tree->root->data_p ? "data" : "NULL" ));
+
+ for ( i=0; i<num_children; i++ ) {
+ sorted_tree_print_children( tree->root->children[i], debug,
+ tree->root->key ? tree->root->key : "ROOT/" );
+ }
+
+}
+
+/**************************************************************************
+ return the data_p for for the node in tree matching the key string
+ The key string is the full path. We must break it apart and walk
+ the tree
+ *************************************************************************/
+
+void* sorted_tree_find( SORTED_TREE *tree, char *key )
+{
+ char *keystr, *base, *str, *p;
+ TREE_NODE *current;
+ void *result = NULL;
+
+ DEBUG(10,("sorted_tree_find: Enter [%s]\n", key ? key : "NULL" ));
+
+ /* sanity checks first */
+
+ if ( !key ) {
+ DEBUG(0,("sorted_tree_find: Attempt to search tree using NULL search string!\n"));
+ return NULL;
+ }
+
+ if ( !tree ) {
+ DEBUG(0,("sorted_tree_find: Attempt to search an uninitialized tree using string [%s]!\n",
+ key ? key : "NULL" ));
+ return NULL;
+ }
+
+ if ( !tree->root )
+ return NULL;
+
+ /* make a copy to play with */
+
+ if ( *key == '/' )
+ keystr = strdup( key+1 );
+ else
+ keystr = strdup( key );
+
+ if ( !keystr ) {
+ DEBUG(0,("sorted_tree_find: strdup() failed on string [%s]!?!?!\n", key));
+ return NULL;
+ }
+
+ /* start breaking the path apart */
+
+ p = keystr;
+ current = tree->root;
+
+ if ( tree->root->data_p )
+ result = tree->root->data_p;
+
+ do
+ {
+ /* break off the remaining part of the path */
+
+ trim_tree_keypath( p, &base, &str );
+
+ DEBUG(11,("sorted_tree_find: [loop] base => [%s], new_path => [%s]\n",
+ base, str));
+
+ /* iterate to the next child */
+
+ current = sorted_tree_find_child( current, base );
+
+ /*
+ * the idea is that the data_p for a parent should
+ * be inherited by all children, but allow it to be
+ * overridden farther down
+ */
+
+ if ( current && current->data_p )
+ result = current->data_p;
+
+ /* reset the path pointer 'p' to the remaining part of the key string */
+
+ p = str;
+
+ } while ( str && current );
+
+ /* result should be the data_p from the lowest match node in the tree */
+ if ( result )
+ DEBUG(11,("sorted_tree_find: Found data_p!\n"));
+
+ SAFE_FREE( keystr );
+
+ DEBUG(10,("sorted_tree_find: Exit\n"));
+
+ return result;
+}
+
+
diff --git a/source3/lib/popt_common.c b/source3/lib/popt_common.c
new file mode 100644
index 0000000000..a3d6af4fbc
--- /dev/null
+++ b/source3/lib/popt_common.c
@@ -0,0 +1,49 @@
+/*
+ Unix SMB/CIFS implementation.
+ Common popt routines
+
+ 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"
+
+/* Handle -d,--debuglevel command line option */
+
+static void debug_callback(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+ extern BOOL AllowDebugChange;
+
+ switch(opt->val) {
+ case 'd':
+ if (arg) {
+ DEBUGLEVEL = atoi(arg);
+ AllowDebugChange = False;
+ }
+
+ break;
+ }
+}
+
+struct poptOption popt_common_debug[] = {
+ { NULL, 0, POPT_ARG_CALLBACK, debug_callback },
+ { "debuglevel", 'd', POPT_ARG_INT, NULL, 'd', "Set debug level",
+ "DEBUGLEVEL" },
+ { 0 }
+};
diff --git a/source3/lib/system_smbd.c b/source3/lib/system_smbd.c
new file mode 100644
index 0000000000..28ceaf3939
--- /dev/null
+++ b/source3/lib/system_smbd.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+ system call wrapper interface.
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) Andrew Barteltt 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 may assume linkage with smbd - for things like become_root()
+ etc.
+*/
+
+#include "includes.h"
+
+#ifndef HAVE_GETGROUPLIST
+/*
+ This is a *much* faster way of getting the list of groups for a user
+ without changing the current supplemenrary group list. The old
+ method used getgrent() which could take 20 minutes on a really big
+ network with hundeds of thousands of groups and users. The new method
+ takes a couple of seconds.
+
+ NOTE!! this function only works if it is called as root!
+ */
+static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
+{
+ gid_t *gids_saved;
+ int ret, ngrp_saved;
+
+ /* work out how many groups we need to save */
+ ngrp_saved = getgroups(0, NULL);
+ if (ngrp_saved == -1) {
+ /* this shouldn't happen */
+ return -1;
+ }
+
+ gids_saved = (gid_t *)malloc(sizeof(gid_t) * (ngrp_saved+1));
+ if (!gids_saved) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ngrp_saved = getgroups(ngrp_saved, gids_saved);
+ if (ngrp_saved == -1) {
+ free(gids_saved);
+ /* very strange! */
+ return -1;
+ }
+
+ if (initgroups(user, gid) != 0) {
+ free(gids_saved);
+ return -1;
+ }
+
+ /* this must be done to cope with systems that put the current egid in the
+ return from getgroups() */
+ save_re_gid();
+ set_effective_gid(gid);
+ setgid(gid);
+
+ ret = getgroups(*grpcnt, groups);
+ if (ret >= 0) {
+ *grpcnt = ret;
+ }
+
+ restore_re_gid();
+
+ if (setgroups(ngrp_saved, gids_saved) != 0) {
+ /* yikes! */
+ DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
+ smb_panic("getgrouplist: failed to reset group list!\n");
+ free(gids_saved);
+ return -1;
+ }
+
+ free(gids_saved);
+ return ret;
+}
+#endif
+
+int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
+{
+#ifdef HAVE_GETGROUPLIST
+ return getgrouplist(user, gid, groups, grpcnt);
+#else
+ int retval;
+ become_root();
+ retval = getgrouplist_internals(user, gid, groups, grpcnt);
+ unbecome_root();
+#endif
+}
diff --git a/source3/lib/util_smbd.c b/source3/lib/util_smbd.c
new file mode 100644
index 0000000000..071f20b416
--- /dev/null
+++ b/source3/lib/util_smbd.c
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions, used in smbd only
+ Copyright (C) Andrew Tridgell 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"
+
+/*
+ This function requires sys_getgrouplist - which is only
+ available in smbd due to it's use of become_root() in a
+ legacy systems hack.
+*/
+
+/*
+ return a full list of groups for a user
+
+ returns the number of groups the user is a member of. The return will include the
+ users primary group.
+
+ remember to free the resulting gid_t array
+
+ NOTE! uses become_root() to gain correct priviages on systems
+ that lack a native getgroups() call (uses initgroups and getgroups)
+*/
+int getgroups_user(const char *user, gid_t **groups)
+{
+ struct passwd *pwd;
+ int ngrp, max_grp;
+
+ pwd = getpwnam_alloc(user);
+ if (!pwd) return -1;
+
+ max_grp = groups_max();
+ (*groups) = (gid_t *)malloc(sizeof(gid_t) * max_grp);
+ if (! *groups) {
+ passwd_free(&pwd);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ngrp = sys_getgrouplist(user, pwd->pw_gid, *groups, &max_grp);
+ if (ngrp <= 0) {
+ passwd_free(&pwd);
+ free(*groups);
+ return ngrp;
+ }
+
+ passwd_free(&pwd);
+ return ngrp;
+}
diff --git a/source3/lib/util_uuid.c b/source3/lib/util_uuid.c
new file mode 100644
index 0000000000..63e2504982
--- /dev/null
+++ b/source3/lib/util_uuid.c
@@ -0,0 +1,72 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * UUID server routines
+ * Copyright (C) Theodore Ts'o 1996, 1997,
+ * Copyright (C) Jim McDonough 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"
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW 0x13814000
+
+struct uuid {
+ uint32 time_low;
+ uint16 time_mid;
+ uint16 time_hi_and_version;
+ uint16 clock_seq;
+ uint8 node[6];
+};
+
+
+static void uuid_pack(const struct uuid *uu, GUID *ptr)
+{
+ uint8 *out = ptr->info;
+
+ SIVAL(out, 0, uu->time_low);
+ SSVAL(out, 4, uu->time_mid);
+ SSVAL(out, 6, uu->time_hi_and_version);
+ SSVAL(out, 8, uu->clock_seq);
+ memcpy(out+10, uu->node, 6);
+}
+
+static void uuid_unpack(const GUID in, struct uuid *uu)
+{
+ const uint8 *ptr = in.info;
+
+ uu->time_low = IVAL(ptr, 0);
+ uu->time_mid = SVAL(ptr, 4);
+ uu->time_hi_and_version = SVAL(ptr, 6);
+ uu->clock_seq = SVAL(ptr, 8);
+ memcpy(uu->node, ptr+10, 6);
+}
+
+void uuid_generate_random(GUID *out)
+{
+ GUID tmp;
+ struct uuid uu;
+
+ generate_random_buffer(tmp.info, sizeof(tmp.info), True);
+ uuid_unpack(tmp, &uu);
+
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+ uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
+ uuid_pack(&uu, out);
+}
diff --git a/source3/libsmb/namecache.c b/source3/libsmb/namecache.c
new file mode 100644
index 0000000000..fc09d8eac2
--- /dev/null
+++ b/source3/libsmb/namecache.c
@@ -0,0 +1,252 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NetBIOS name cache module.
+
+ 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"
+
+static BOOL done_namecache_init;
+static BOOL enable_namecache;
+static TDB_CONTEXT *namecache_tdb;
+
+struct nc_value {
+ time_t expiry; /* When entry expires */
+ int count; /* Number of addresses */
+ struct in_addr ip_list[0]; /* Address list */
+};
+
+/* Initialise namecache system */
+
+void namecache_enable(void)
+{
+ /* Check if we have been here before, or name caching disabled
+ by setting the name cache timeout to zero. */
+
+ if (done_namecache_init)
+ return;
+
+ done_namecache_init = True;
+
+ if (lp_name_cache_timeout() == 0) {
+ DEBUG(5, ("namecache_init: disabling netbios name cache\n"));
+ return;
+ }
+
+ /* Open namecache tdb in read/write or readonly mode */
+
+ namecache_tdb = tdb_open_log(
+ lock_path("namecache.tdb"), 0,
+ TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
+
+ if (!namecache_tdb) {
+ DEBUG(5, ("namecache_init: could not open %s\n",
+ lock_path("namecache.tdb")));
+ return;
+ }
+
+ DEBUG(5, ("namecache_init: enabling netbios namecache, timeout %d "
+ "seconds\n", lp_name_cache_timeout()));
+
+ enable_namecache = True;
+}
+
+/* Return a key for a name and name type. The caller must free
+ retval.dptr when finished. */
+
+static TDB_DATA namecache_key(const char *name, int name_type)
+{
+ TDB_DATA retval;
+ char *keystr;
+
+ asprintf(&keystr, "%s#%02X", strupper_static(name), name_type);
+
+ retval.dsize = strlen(keystr) + 1;
+ retval.dptr = keystr;
+
+ return retval;
+}
+
+/* Return a data value for an IP list. The caller must free
+ retval.dptr when finished. */
+
+static TDB_DATA namecache_value(struct in_addr *ip_list, int num_names,
+ time_t expiry)
+{
+ TDB_DATA retval;
+ struct nc_value *value;
+ int size;
+
+ size = sizeof(struct nc_value) + sizeof(struct in_addr) *
+ num_names;
+
+ value = (struct nc_value *)malloc(size);
+
+ value->expiry = expiry;
+ value->count = num_names;
+
+ memcpy(value->ip_list, ip_list, num_names * sizeof(struct in_addr));
+
+ retval.dptr = (char *)value;
+ retval.dsize = size;
+
+ return retval;
+}
+
+/* Store a name in the name cache */
+
+void namecache_store(const char *name, int name_type,
+ int num_names, struct in_addr *ip_list)
+{
+ TDB_DATA key, value;
+ time_t expiry;
+ int i;
+
+ if (!enable_namecache)
+ return;
+
+ DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
+ num_names, num_names == 1 ? "": "es", name, name_type));
+
+ for (i = 0; i < num_names; i++)
+ DEBUGADD(5, ("%s%s", inet_ntoa(ip_list[i]),
+ i == (num_names - 1) ? "" : ", "));
+
+ DEBUGADD(5, ("\n"));
+
+ key = namecache_key(name, name_type);
+
+ /* Cache pdc location or dc lists for only a little while
+ otherwise if we lock on to a bad DC we can potentially be
+ out of action for the entire cache timeout time! */
+
+ if (name_type != 0x1b || name_type != 0x1c)
+ expiry = time(NULL) + 10;
+ else
+ expiry = time(NULL) + lp_name_cache_timeout();
+
+ value = namecache_value(ip_list, num_names, expiry);
+
+ tdb_store(namecache_tdb, key, value, TDB_REPLACE);
+
+ free(key.dptr);
+ free(value.dptr);
+}
+
+/* Look up a name in the name cache. Return a mallocated list of IP
+ addresses if the name is contained in the cache. */
+
+BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
+ int *num_names)
+{
+ TDB_DATA key, value;
+ struct nc_value *data;
+ time_t now;
+ int i;
+
+ if (!enable_namecache)
+ return False;
+
+ /* Read value */
+
+ key = namecache_key(name, name_type);
+
+ value = tdb_fetch(namecache_tdb, key);
+
+ if (!value.dptr) {
+ DEBUG(5, ("namecache_fetch: %s#%02x not found\n",
+ name, name_type));
+ goto done;
+ }
+
+ data = (struct nc_value *)value.dptr;
+
+ /* Check expiry time */
+
+ now = time(NULL);
+
+ if (now > data->expiry) {
+
+ DEBUG(5, ("namecache_fetch: entry for %s#%02x expired\n",
+ name, name_type));
+
+ tdb_delete(namecache_tdb, key);
+
+ value = tdb_null;
+
+ goto done;
+ }
+
+ if ((data->expiry - now) > lp_name_cache_timeout()) {
+
+ /* Someone may have changed the system time on us */
+
+ DEBUG(5, ("namecache_fetch: entry for %s#%02x has bad expiry\n",
+ name, name_type));
+
+ tdb_delete(namecache_tdb, key);
+
+ value = tdb_null;
+
+ goto done;
+ }
+
+ /* Extract and return namelist */
+
+ *ip_list = (struct in_addr *)malloc(
+ sizeof(struct in_addr) * data->count);
+
+ memcpy(*ip_list, data->ip_list, sizeof(struct in_addr) *
+ data->count);
+
+ *num_names = data->count;
+
+ DEBUG(5, ("namecache_fetch: returning %d address%s for %s#%02x: ",
+ *num_names, *num_names == 1 ? "" : "es", name, name_type));
+
+ for (i = 0; i < *num_names; i++)
+ DEBUGADD(5, ("%s%s", inet_ntoa((*ip_list)[i]),
+ i == (*num_names - 1) ? "" : ", "));
+
+ DEBUGADD(5, ("\n"));
+
+done:
+ SAFE_FREE(key.dptr);
+ SAFE_FREE(value.dptr);
+
+ return value.dsize > 0;
+}
+
+/* Flush all names from the name cache */
+
+void namecache_flush(void)
+{
+ int result;
+
+ if (!namecache_tdb)
+ return;
+
+ result = tdb_traverse(namecache_tdb, tdb_traverse_delete_fn, NULL);
+
+ if (result == -1)
+ DEBUG(5, ("namecache_flush: error deleting cache entries\n"));
+ else
+ DEBUG(5, ("namecache_flush: deleted %d cache entr%s\n",
+ result, result == 1 ? "y" : "ies"));
+}
diff --git a/source3/python/py_common_proto.h b/source3/python/py_common_proto.h
new file mode 100644
index 0000000000..89f0f35fc9
--- /dev/null
+++ b/source3/python/py_common_proto.h
@@ -0,0 +1,32 @@
+#ifndef _PY_COMMON_PROTO_H
+#define _PY_COMMON_PROTO_H
+
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/* The following definitions come from python/py_common.c */
+
+PyObject *py_werror_tuple(WERROR werror);
+PyObject *py_ntstatus_tuple(NTSTATUS ntstatus);
+void py_samba_init(void);
+PyObject *get_debuglevel(PyObject *self, PyObject *args);
+PyObject *set_debuglevel(PyObject *self, PyObject *args);
+PyObject *py_setup_logging(PyObject *self, PyObject *args, PyObject *kw);
+BOOL py_parse_creds(PyObject *creds, char **username, char **domain,
+ char **password, char **errstr);
+struct cli_state *open_pipe_creds(char *server, PyObject *creds,
+ char *pipe_name, char **errstr);
+BOOL get_level_value(PyObject *dict, uint32 *level);
+
+/* The following definitions come from python/py_ntsec.c */
+
+BOOL py_from_SID(PyObject **obj, DOM_SID *sid);
+BOOL py_to_SID(DOM_SID *sid, PyObject *obj);
+BOOL py_from_ACE(PyObject **dict, SEC_ACE *ace);
+BOOL py_to_ACE(SEC_ACE *ace, PyObject *dict);
+BOOL py_from_ACL(PyObject **dict, SEC_ACL *acl);
+BOOL py_to_ACL(SEC_ACL *acl, PyObject *dict, TALLOC_CTX *mem_ctx);
+BOOL py_from_SECDESC(PyObject **dict, SEC_DESC *sd);
+BOOL py_to_SECDESC(SEC_DESC **sd, PyObject *dict, TALLOC_CTX *mem_ctx);
+
+#endif /* _PY_COMMON_PROTO_H */
diff --git a/source3/python/py_lsa.c b/source3/python/py_lsa.c
new file mode 100644
index 0000000000..0584cf716b
--- /dev/null
+++ b/source3/python/py_lsa.c
@@ -0,0 +1,462 @@
+/*
+ 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_lsa.h"
+
+PyObject *new_lsa_policy_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ lsa_policy_hnd_object *o;
+
+ o = PyObject_New(lsa_policy_hnd_object, &lsa_policy_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/*
+ * Exceptions raised by this module
+ */
+
+PyObject *lsa_error; /* This indicates a non-RPC related error
+ such as name lookup failure */
+
+PyObject *lsa_ntstatus; /* This exception is raised when a RPC call
+ returns a status code other than
+ NT_STATUS_OK */
+
+/*
+ * Open/close lsa handles
+ */
+
+static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ static char *kwlist[] = { "servername", "creds", "access", NULL };
+ char *server, *errstr;
+ PyObject *creds = NULL, *result = NULL;
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ struct cli_state *cli = NULL;
+ NTSTATUS ntstatus;
+ TALLOC_CTX *mem_ctx = NULL;
+ POLICY_HND hnd;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|Oi", kwlist, &server, &creds, &desired_access))
+ return NULL;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (!(cli = open_pipe_creds(server, creds, PIPE_LSARPC, &errstr))) {
+ PyErr_SetString(lsa_error, errstr);
+ free(errstr);
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ PyErr_SetString(lsa_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ ntstatus = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &hnd);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ goto done;
+ }
+
+ result = new_lsa_policy_hnd_object(cli, mem_ctx, &hnd);
+
+done:
+ if (!result) {
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ return result;
+}
+
+static PyObject *lsa_close(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyObject *po;
+ lsa_policy_hnd_object *hnd;
+ NTSTATUS result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTuple(args, "O!", &lsa_policy_hnd_type, &po))
+ return NULL;
+
+ hnd = (lsa_policy_hnd_object *)po;
+
+ /* Call rpc function */
+
+ result = cli_lsa_close(hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ /* Cleanup samba stuff */
+
+ cli_shutdown(hnd->cli);
+ talloc_destroy(hnd->mem_ctx);
+
+ /* Return value */
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *lsa_lookup_names(PyObject *self, PyObject *args)
+{
+ PyObject *py_names, *result;
+ NTSTATUS ntstatus;
+ lsa_policy_hnd_object *hnd = (lsa_policy_hnd_object *)self;
+ int num_names, i;
+ const char **names;
+ DOM_SID *sids;
+ uint32 *name_types;
+
+ if (!PyArg_ParseTuple(args, "O", &py_names))
+ return NULL;
+
+ if (!PyList_Check(py_names) && !PyString_Check(py_names)) {
+ PyErr_SetString(PyExc_TypeError, "must be list or string");
+ return NULL;
+ }
+
+ if (PyList_Check(py_names)) {
+
+ /* Convert list to char ** array */
+
+ num_names = PyList_Size(py_names);
+ names = (const char **)talloc(
+ hnd->mem_ctx, num_names * sizeof(char *));
+
+ for (i = 0; i < num_names; i++) {
+ PyObject *obj = PyList_GetItem(py_names, i);
+
+ names[i] = talloc_strdup(hnd->mem_ctx, PyString_AsString(obj));
+ }
+
+ } else {
+
+ /* Just a single element */
+
+ num_names = 1;
+ names = (const char **)talloc(hnd->mem_ctx, sizeof(char *));
+
+ names[0] = PyString_AsString(py_names);
+ }
+
+ ntstatus = cli_lsa_lookup_names(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ num_names, names, &sids, &name_types);
+
+ if (!NT_STATUS_IS_OK(ntstatus) && NT_STATUS_V(ntstatus) != 0x107) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ return NULL;
+ }
+
+ result = PyList_New(num_names);
+
+ for (i = 0; i < num_names; i++) {
+ PyObject *sid_obj, *obj;
+
+ py_from_SID(&sid_obj, &sids[i]);
+
+ obj = Py_BuildValue("(Oi)", sid_obj, name_types[i]);
+
+ PyList_SetItem(result, i, obj);
+ }
+
+ return result;
+}
+
+static PyObject *lsa_lookup_sids(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ PyObject *py_sids, *result;
+ NTSTATUS ntstatus;
+ int num_sids, i;
+ char **domains, **names;
+ uint32 *types;
+ lsa_policy_hnd_object *hnd = (lsa_policy_hnd_object *)self;
+ DOM_SID *sids;
+
+ if (!PyArg_ParseTuple(args, "O", &py_sids))
+ return NULL;
+
+ if (!PyList_Check(py_sids) && !PyString_Check(py_sids)) {
+ PyErr_SetString(PyExc_TypeError, "must be list or string");
+ return NULL;
+ }
+
+ if (PyList_Check(py_sids)) {
+
+ /* Convert dictionary to char ** array */
+
+ num_sids = PyList_Size(py_sids);
+ sids = (DOM_SID *)talloc(hnd->mem_ctx, num_sids * sizeof(DOM_SID));
+
+ memset(sids, 0, num_sids * sizeof(DOM_SID));
+
+ for (i = 0; i < num_sids; i++) {
+ PyObject *obj = PyList_GetItem(py_sids, i);
+
+ string_to_sid(&sids[i], PyString_AsString(obj));
+ }
+
+ } else {
+
+ /* Just a single element */
+
+ num_sids = 1;
+ sids = (DOM_SID *)talloc(hnd->mem_ctx, sizeof(DOM_SID));
+
+ string_to_sid(&sids[0], PyString_AsString(py_sids));
+ }
+
+ ntstatus = cli_lsa_lookup_sids(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ num_sids, sids, &domains, &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ return NULL;
+ }
+
+ result = PyList_New(num_sids);
+
+ for (i = 0; i < num_sids; i++) {
+ PyObject *obj;
+
+ obj = Py_BuildValue("{sssssi}", "username", names[i],
+ "domain", domains[i], "name_type",
+ types[i]);
+
+ PyList_SetItem(result, i, obj);
+ }
+
+ return result;
+}
+
+static PyObject *lsa_enum_trust_dom(PyObject *self, PyObject *args)
+{
+ lsa_policy_hnd_object *hnd = (lsa_policy_hnd_object *)self;
+ NTSTATUS ntstatus;
+ uint32 enum_ctx = 0, num_domains, i;
+ char **domain_names;
+ DOM_SID *domain_sids;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ntstatus = cli_lsa_enum_trust_dom(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, &enum_ctx,
+ &num_domains, &domain_names, &domain_sids);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ return NULL;
+ }
+
+ result = PyList_New(num_domains);
+
+ for (i = 0; i < num_domains; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &domain_sids[i]);
+ PyList_SetItem(
+ result, i,
+ Py_BuildValue("(ss)", domain_names[i], sid_str));
+ }
+
+ return result;
+}
+
+/*
+ * Method dispatch tables
+ */
+
+static PyMethodDef lsa_hnd_methods[] = {
+
+ /* SIDs<->names */
+
+ { "lookup_sids", (PyCFunction)lsa_lookup_sids,
+ METH_VARARGS | METH_KEYWORDS,
+ "Convert sids to names." },
+
+ { "lookup_names", (PyCFunction)lsa_lookup_names,
+ METH_VARARGS | METH_KEYWORDS,
+ "Convert names to sids." },
+
+ /* Trusted domains */
+
+ { "enum_trusted_domains", (PyCFunction)lsa_enum_trust_dom,
+ METH_VARARGS,
+ "Enumerate trusted domains." },
+
+ { NULL }
+};
+
+static void py_lsa_policy_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *py_lsa_policy_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(lsa_hnd_methods, self, attrname);
+}
+
+PyTypeObject lsa_policy_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "LSA Policy Handle",
+ sizeof(lsa_policy_hnd_object),
+ 0,
+ py_lsa_policy_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_lsa_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 */
+};
+
+static PyMethodDef lsa_methods[] = {
+
+ /* Open/close lsa handles */
+
+ { "open_policy", (PyCFunction)lsa_open_policy,
+ METH_VARARGS | METH_KEYWORDS,
+ "Open a policy handle" },
+
+ { "close", (PyCFunction)lsa_close,
+ METH_VARARGS,
+ "Close a policy handle" },
+
+ /* 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)" },
+
+ { 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);
+ }
+}
+
+/*
+ * Module initialisation
+ */
+
+void initlsa(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("lsa", lsa_methods);
+ dict = PyModule_GetDict(module);
+
+ lsa_error = PyErr_NewException("lsa.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", lsa_error);
+
+ lsa_ntstatus = PyErr_NewException("lsa.ntstatus", NULL, NULL);
+ PyDict_SetItemString(dict, "ntstatus", lsa_ntstatus);
+
+ /* Initialise policy handle object */
+
+ lsa_policy_hnd_type.ob_type = &PyType_Type;
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ setup_logging("lsa", True);
+ DEBUGLEVEL = 10;
+}
diff --git a/source3/python/py_smb.c b/source3/python/py_smb.c
new file mode 100644
index 0000000000..77d7bb32fc
--- /dev/null
+++ b/source3/python/py_smb.c
@@ -0,0 +1,224 @@
+/*
+ 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_smb.h"
+
+/* Create a new cli_state python object */
+
+PyObject *new_cli_state_object(struct cli_state *cli)
+{
+ cli_state_object *o;
+
+ o = PyObject_New(cli_state_object, &cli_state_type);
+
+ o->cli = cli;
+
+ return (PyObject*)o;
+}
+
+static PyObject *py_smb_connect(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "server", NULL };
+ struct cli_state *cli;
+ char *server;
+ struct in_addr ip;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &server))
+ return NULL;
+
+ if (!(cli = cli_initialise(NULL)))
+ return NULL;
+
+ ZERO_STRUCT(ip);
+
+ if (!cli_connect(cli, server, &ip))
+ return NULL;
+
+ return new_cli_state_object(cli);
+}
+
+static PyObject *py_smb_session_request(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "called", "calling", NULL };
+ char *calling_name = NULL, *called_name;
+ struct nmb_name calling, called;
+ extern pstring global_myname;
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s", kwlist, &called_name,
+ &calling_name))
+ return NULL;
+
+ if (!calling_name)
+ calling_name = global_myname;
+
+ make_nmb_name(&calling, calling_name, 0x00);
+ make_nmb_name(&called, called_name, 0x20);
+
+ result = cli_session_request(cli->cli, &calling, &called);
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_negprot(PyObject *self, PyObject *args, PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { NULL };
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ result = cli_negprot(cli->cli);
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_session_setup(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "creds" };
+ PyObject *creds;
+ char *username, *domain, *password, *errstr;
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "O", kwlist, &creds))
+ return NULL;
+
+ if (!py_parse_creds(creds, &username, &domain, &password, &errstr)) {
+ free(errstr);
+ return NULL;
+ }
+
+ result = cli_session_setup(
+ cli->cli, username, password, strlen(password) + 1,
+ password, strlen(password) + 1, domain);
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_tconx(PyObject *self, PyObject *args, PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "service", "creds" };
+ PyObject *creds;
+ char *service, *username, *domain, *password, *errstr;
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "sO", kwlist, &service,
+ &creds))
+ return NULL;
+
+ if (!py_parse_creds(creds, &username, &domain, &password, &errstr)) {
+ free(errstr);
+ return NULL;
+ }
+
+ result = cli_send_tconX(
+ cli->cli, service, strequal(service, "IPC$") ? "IPC" : "?????",
+ password, strlen(password) + 1);
+
+ return Py_BuildValue("i", result);
+}
+
+static PyMethodDef smb_hnd_methods[] = {
+
+ { "session_request", (PyCFunction)py_smb_session_request,
+ METH_VARARGS | METH_KEYWORDS, "Request a session" },
+
+ { "negprot", (PyCFunction)py_smb_negprot,
+ METH_VARARGS | METH_KEYWORDS, "Protocol negotiation" },
+
+ { "session_setup", (PyCFunction)py_smb_session_setup,
+ METH_VARARGS | METH_KEYWORDS, "Session setup" },
+
+ { "tconx", (PyCFunction)py_smb_tconx,
+ METH_VARARGS | METH_KEYWORDS, "Tree connect" },
+
+ { NULL }
+};
+
+/*
+ * Method dispatch tables
+ */
+
+static PyMethodDef smb_methods[] = {
+
+ { "connect", (PyCFunction)py_smb_connect, METH_VARARGS | METH_KEYWORDS,
+ "Connect to a host" },
+
+ { NULL }
+};
+
+static void py_cli_state_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *py_cli_state_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(smb_hnd_methods, self, attrname);
+}
+
+PyTypeObject cli_state_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SMB client connection",
+ sizeof(cli_state_object),
+ 0,
+ py_cli_state_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_cli_state_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 */
+};
+
+/*
+ * Module initialisation
+ */
+
+void initsmb(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("smb", smb_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Initialise policy handle object */
+
+ cli_state_type.ob_type = &PyType_Type;
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ setup_logging("smb", True);
+ DEBUGLEVEL = 10;
+}
diff --git a/source3/python/py_smb.h b/source3/python/py_smb.h
new file mode 100644
index 0000000000..18677b4905
--- /dev/null
+++ b/source3/python/py_smb.h
@@ -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.
+*/
+
+#ifndef _PY_SMB_H
+#define _PY_SMB_H
+
+#include "includes.h"
+#include "Python.h"
+
+#include "python/py_common_proto.h"
+
+/* cli_state handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+} cli_state_object;
+
+/* Exceptions raised by this module */
+
+extern PyTypeObject cli_state_type;
+
+extern PyObject *smb_ntstatus;
+
+#endif /* _PY_SMB_H */
diff --git a/source3/registry/reg_cachehook.c b/source3/registry/reg_cachehook.c
new file mode 100644
index 0000000000..547eed392d
--- /dev/null
+++ b/source3/registry/reg_cachehook.c
@@ -0,0 +1,112 @@
+/*
+ * 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 hook cache tree */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static SORTED_TREE *cache_tree;
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+static REGISTRY_HOOK default_hook = { KEY_TREE_ROOT, &regdb_ops };
+
+/**********************************************************************
+ Initialize the cache tree
+ *********************************************************************/
+
+BOOL reghook_cache_init( void )
+{
+ cache_tree = sorted_tree_init( &default_hook, NULL, NULL );
+
+ return ( cache_tree == NULL );
+}
+
+/**********************************************************************
+ Add a new REGISTRY_HOOK to the cache. Note that the keyname
+ is not in the exact format that a SORTED_TREE expects.
+ *********************************************************************/
+
+BOOL reghook_cache_add( REGISTRY_HOOK *hook )
+{
+ pstring key;
+
+ if ( !hook )
+ return False;
+
+ pstrcpy( key, "\\");
+ pstrcat( key, hook->keyname );
+
+ pstring_sub( key, "\\", "/" );
+
+ DEBUG(10,("reghook_cache_add: Adding key [%s]\n", key));
+
+ return sorted_tree_add( cache_tree, key, hook );
+}
+
+/**********************************************************************
+ Initialize the cache tree
+ *********************************************************************/
+
+REGISTRY_HOOK* reghook_cache_find( char *keyname )
+{
+ char *key;
+ int len;
+ REGISTRY_HOOK *hook;
+
+ if ( !keyname )
+ return NULL;
+
+ /* prepend the string with a '\' character */
+
+ len = strlen( keyname );
+ if ( !(key = malloc( len + 2 )) ) {
+ DEBUG(0,("reghook_cache_find: malloc failed for string [%s] !?!?!\n",
+ keyname));
+ return NULL;
+ }
+
+ *key = '\\';
+ strncpy( key+1, keyname, len+1);
+
+ /* swap to a form understood by the SORTED_TREE */
+
+ string_sub( key, "\\", "/", 0 );
+
+ DEBUG(10,("reghook_cache_find: Searching for keyname [%s]\n", key));
+
+ hook = sorted_tree_find( cache_tree, key ) ;
+
+ SAFE_FREE( key );
+
+ return hook;
+}
+
+/**********************************************************************
+ Initialize the cache tree
+ *********************************************************************/
+
+void reghook_dump_cache( int debuglevel )
+{
+ DEBUG(debuglevel,("reghook_dump_cache: Starting cache dump now...\n"));
+
+ sorted_tree_print_keys( cache_tree, debuglevel );
+}
diff --git a/source3/registry/reg_db.c b/source3/registry/reg_db.c
new file mode 100644
index 0000000000..b0917c8f60
--- /dev/null
+++ b/source3/registry/reg_db.c
@@ -0,0 +1,311 @@
+/*
+ * 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 internal registry database functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static TDB_CONTEXT *tdb_reg;
+
+
+/***********************************************************************
+ Open the registry data in the tdb
+ ***********************************************************************/
+
+static BOOL init_registry_data( void )
+{
+ pstring keyname;
+ REGSUBKEY_CTR subkeys;
+
+ ZERO_STRUCTP( &subkeys );
+
+ /* HKEY_LOCAL_MACHINE */
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ regsubkey_ctr_addkey( &subkeys, "SYSTEM" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM" );
+ regsubkey_ctr_addkey( &subkeys, "CurrentControlSet" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet" );
+ regsubkey_ctr_addkey( &subkeys, "Control" );
+ regsubkey_ctr_addkey( &subkeys, "Services" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control" );
+ regsubkey_ctr_addkey( &subkeys, "Print" );
+ regsubkey_ctr_addkey( &subkeys, "ProductOptions" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/ProductOptions" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services" );
+ regsubkey_ctr_addkey( &subkeys, "Netlogon" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon" );
+ regsubkey_ctr_addkey( &subkeys, "Parameters" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon/Parameters" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+
+ /* HKEY_USER */
+
+ pstrcpy( keyname, KEY_HKU );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ) )
+ return False;
+
+ /* HKEY_CLASSES_ROOT*/
+
+ pstrcpy( keyname, KEY_HKCR );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ) )
+ return False;
+
+ return True;
+}
+
+/***********************************************************************
+ Open the registry database
+ ***********************************************************************/
+
+BOOL init_registry_db( void )
+{
+ static pid_t local_pid;
+
+ if (tdb_reg && local_pid == sys_getpid())
+ return True;
+
+ /*
+ * try to open first without creating so we can determine
+ * if we need to init the data in the registry
+ */
+
+ tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
+ if ( !tdb_reg )
+ {
+ tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if ( !tdb_reg ) {
+ DEBUG(0,("init_registry: Failed to open registry %s (%s)\n",
+ lock_path("registry.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ DEBUG(10,("init_registry: Successfully created registry tdb\n"));
+
+ /* create the registry here */
+ if ( !init_registry_data() ) {
+ DEBUG(0,("init_registry: Failed to initiailize data in registry!\n"));
+ return False;
+ }
+ }
+
+ local_pid = sys_getpid();
+
+ return True;
+}
+
+
+
+/***********************************************************************
+ Add subkey strings to the registry tdb under a defined key
+ fmt is the same format as tdb_pack except this function only supports
+ fstrings
+
+ The full path to the registry key is used as database after the
+ \'s are converted to /'s. Key string is also normalized to UPPER
+ case.
+ ***********************************************************************/
+
+BOOL regdb_store_reg_keys( char *keyname, REGSUBKEY_CTR *ctr )
+{
+ TDB_DATA kbuf, dbuf;
+ char *buffer, *tmpbuf;
+ int i = 0;
+ uint32 len, buflen;
+ BOOL ret = True;
+ uint32 num_subkeys = regsubkey_ctr_numkeys( ctr );
+
+ if ( !keyname )
+ return False;
+
+ strupper_m( keyname );
+
+ /* allocate some initial memory */
+
+ buffer = malloc(sizeof(pstring));
+ buflen = sizeof(pstring);
+ len = 0;
+
+ /* store the number of subkeys */
+
+ len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys );
+
+ /* pack all the strings */
+
+ for (i=0; i<num_subkeys; i++) {
+ len += tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
+ if ( len > buflen ) {
+ /* allocate some extra space */
+ if ((tmpbuf = Realloc( buffer, len*2 )) == NULL) {
+ DEBUG(0,("regdb_store_reg_keys: Failed to realloc memory of size [%d]\n", len*2));
+ ret = False;
+ goto done;
+ }
+ buffer = tmpbuf;
+ buflen = len*2;
+
+ len = tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
+ }
+ }
+
+ /* finally write out the data */
+
+ kbuf.dptr = keyname;
+ kbuf.dsize = strlen(keyname)+1;
+ dbuf.dptr = buffer;
+ dbuf.dsize = len;
+ if ( tdb_store( tdb_reg, kbuf, dbuf, TDB_REPLACE ) == -1) {
+ ret = False;
+ goto done;
+ }
+
+done:
+ SAFE_FREE( buffer );
+
+ return ret;
+}
+
+/***********************************************************************
+ Retrieve an array of strings containing subkeys. Memory should be
+ released by the caller. The subkeys are stored in a catenated string
+ of null terminated character strings
+ ***********************************************************************/
+
+int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr )
+{
+ pstring path;
+ uint32 num_items;
+ TDB_DATA dbuf;
+ char *buf;
+ uint32 buflen, len;
+ int i;
+ fstring subkeyname;
+
+ DEBUG(10,("regdb_fetch_reg_keys: Enter key => [%s]\n", key ? key : "NULL"));
+
+ pstrcpy( path, key );
+
+ /* convert to key format */
+ pstring_sub( path, "\\", "/" );
+ strupper_m( path );
+
+ dbuf = tdb_fetch_by_string( tdb_reg, path );
+
+ buf = dbuf.dptr;
+ buflen = dbuf.dsize;
+
+ if ( !buf ) {
+ DEBUG(5,("regdb_fetch_reg_keys: tdb lookup failed to locate key [%s]\n", key));
+ return -1;
+ }
+
+ len = tdb_unpack( buf, buflen, "d", &num_items);
+
+ for (i=0; i<num_items; i++) {
+ len += tdb_unpack( buf+len, buflen-len, "f", subkeyname );
+ regsubkey_ctr_addkey( ctr, subkeyname );
+ }
+
+ SAFE_FREE( dbuf.dptr );
+
+ DEBUG(10,("regdb_fetch_reg_keys: Exit [%d] items\n", num_items));
+
+ return num_items;
+}
+
+
+/***********************************************************************
+ Retrieve an array of strings containing subkeys. Memory should be
+ released by the caller. The subkeys are stored in a catenated string
+ of null terminated character strings
+ ***********************************************************************/
+
+int regdb_fetch_reg_values( char* key, REGVAL_CTR *val )
+{
+ return 0;
+}
+
+/***********************************************************************
+ Stub function since we do not currently support storing registry
+ values in the registry.tdb
+ ***********************************************************************/
+
+BOOL regdb_store_reg_values( char *key, REGVAL_CTR *val )
+{
+ return False;
+}
+
+
+/*
+ * Table of function pointers for default access
+ */
+
+REGISTRY_OPS regdb_ops = {
+ regdb_fetch_reg_keys,
+ regdb_fetch_reg_values,
+ regdb_store_reg_keys,
+ regdb_store_reg_values
+};
+
+
diff --git a/source3/registry/reg_frontend.c b/source3/registry/reg_frontend.c
new file mode 100644
index 0000000000..45c1f24001
--- /dev/null
+++ b/source3/registry/reg_frontend.c
@@ -0,0 +1,575 @@
+/*
+ * 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
+
+extern REGISTRY_OPS printing_ops;
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+
+/* array of REGISTRY_HOOK's which are read into a tree for easy access */
+
+
+REGISTRY_HOOK reg_hooks[] = {
+ { KEY_PRINTING, &printing_ops },
+ { NULL, NULL }
+};
+
+
+/*
+ * Utility functions for REGSUBKEY_CTR
+ */
+
+/***********************************************************************
+ 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;
+ uint16 len;
+
+ if ( name )
+ {
+ len = strlen( 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;
+}
+
+/***********************************************************************
+ 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 ( strcmp( ctr->values[i]->valuename, name ) == 0)
+ 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 );
+ }
+}
+
+/***********************************************************************
+ Open the registry database and initialize the REGISTRY_HOOK cache
+ ***********************************************************************/
+
+BOOL init_registry( void )
+{
+ int i;
+
+ if ( !init_registry_db() ) {
+ DEBUG(0,("init_registry: failed to initialize the registry tdb!\n"));
+ return False;
+ }
+
+ /* build the cache tree of registry hooks */
+
+ reghook_cache_init();
+
+ for ( i=0; reg_hooks[i].keyname; i++ ) {
+ if ( !reghook_cache_add(&reg_hooks[i]) )
+ return False;
+ }
+
+ if ( DEBUGLEVEL >= 20 )
+ reghook_dump_cache(20);
+
+ return True;
+}
+
+
+
+
+/***********************************************************************
+ High level wrapper function for storing registry subkeys
+ ***********************************************************************/
+
+BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
+{
+ if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys_fn )
+ return key->hook->ops->store_subkeys_fn( key->name, subkeys );
+ else
+ return False;
+
+}
+
+/***********************************************************************
+ High level wrapper function for storing registry values
+ ***********************************************************************/
+
+BOOL store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
+{
+ if ( key->hook && key->hook->ops && key->hook->ops->store_values_fn )
+ return key->hook->ops->store_values_fn( key->name, val );
+ else
+ return False;
+}
+
+
+/***********************************************************************
+ High level wrapper function for enumerating registry subkeys
+ Initialize the TALLOC_CTX if necessary
+ ***********************************************************************/
+
+int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
+{
+ int result = -1;
+
+ if ( key->hook && key->hook->ops && key->hook->ops->subkey_fn )
+ result = key->hook->ops->subkey_fn( key->name, subkey_ctr );
+
+ return result;
+}
+
+/***********************************************************************
+ retreive a specific subkey specified by index. Caller is
+ responsible for freeing memory
+ ***********************************************************************/
+
+BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index )
+{
+ static REGSUBKEY_CTR ctr;
+ static pstring save_path;
+ static BOOL ctr_init = False;
+ char *s;
+
+ *subkey = NULL;
+
+ /* simple caching for performance; very basic heuristic */
+
+ if ( !ctr_init ) {
+ DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name));
+ ZERO_STRUCTP( &ctr );
+ regsubkey_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_keys( key, &ctr) == -1 )
+ return False;
+
+ ctr_init = True;
+ }
+ /* clear the cache when key_index == 0 or the path has changed */
+ else if ( !key_index || StrCaseCmp( save_path, key->name) ) {
+
+ DEBUG(8,("fetch_reg_keys_specific: Updating cache of subkeys for [%s]\n", key->name));
+
+ regsubkey_ctr_destroy( &ctr );
+ regsubkey_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_keys( key, &ctr) == -1 )
+ return False;
+ }
+
+ if ( !(s = regsubkey_ctr_specific_key( &ctr, key_index )) )
+ return False;
+
+ *subkey = strdup( s );
+
+ return True;
+}
+
+
+/***********************************************************************
+ High level wrapper function for enumerating registry values
+ Initialize the TALLOC_CTX if necessary
+ ***********************************************************************/
+
+int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
+{
+ int result = -1;
+
+ if ( key->hook && key->hook->ops && key->hook->ops->value_fn )
+ result = key->hook->ops->value_fn( key->name, val );
+
+ return result;
+}
+
+
+/***********************************************************************
+ retreive a specific subkey specified by index. Caller is
+ responsible for freeing memory
+ ***********************************************************************/
+
+BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 val_index )
+{
+ static REGVAL_CTR ctr;
+ static pstring save_path;
+ static BOOL ctr_init = False;
+ REGISTRY_VALUE *v;
+
+ *val = NULL;
+
+ /* simple caching for performance; very basic heuristic */
+
+ if ( !ctr_init ) {
+ DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name));
+
+ ZERO_STRUCTP( &ctr );
+ regval_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_values( key, &ctr) == -1 )
+ return False;
+
+ ctr_init = True;
+ }
+ /* clear the cache when val_index == 0 or the path has changed */
+ else if ( !val_index || StrCaseCmp(save_path, key->name) ) {
+
+ DEBUG(8,("fetch_reg_values_specific: Updating cache of values for [%s]\n", key->name));
+
+ regval_ctr_destroy( &ctr );
+ regval_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_values( key, &ctr) == -1 )
+ return False;
+ }
+
+ if ( !(v = regval_ctr_specific_value( &ctr, val_index )) )
+ return False;
+
+ *val = dup_registry_value( v );
+
+ return True;
+}
+
+/***********************************************************************
+ Utility function for splitting the base path of a registry path off
+ by setting base and new_path to the apprapriate offsets withing the
+ path.
+
+ WARNING!! Does modify the original string!
+ ***********************************************************************/
+
+BOOL reg_split_path( char *path, char **base, char **new_path )
+{
+ char *p;
+
+ *new_path = *base = NULL;
+
+ if ( !path)
+ return False;
+
+ *base = path;
+
+ p = strchr( path, '\\' );
+
+ if ( p ) {
+ *p = '\0';
+ *new_path = p+1;
+ }
+
+ return True;
+}
+
+
+
diff --git a/source3/registry/reg_printing.c b/source3/registry/reg_printing.c
new file mode 100644
index 0000000000..8f53fe9ea5
--- /dev/null
+++ b/source3/registry/reg_printing.c
@@ -0,0 +1,814 @@
+/*
+ * 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 virtual views for printing information */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#define MAX_TOP_LEVEL_KEYS 3
+
+/* some symbolic indexes into the top_level_keys */
+
+#define KEY_INDEX_ENVIR 0
+#define KEY_INDEX_FORMS 1
+#define KEY_INDEX_PRINTER 2
+
+static char *top_level_keys[MAX_TOP_LEVEL_KEYS] = {
+ "Environments",
+ "Forms",
+ "Printers"
+};
+
+
+/**********************************************************************
+ It is safe to assume that every registry path passed into on of
+ the exported functions here begins with KEY_PRINTING else
+ these functions would have never been called. This is a small utility
+ function to strip the beginning of the path and make a copy that the
+ caller can modify. Note that the caller is responsible for releasing
+ the memory allocated here.
+ **********************************************************************/
+
+static char* trim_reg_path( char *path )
+{
+ char *p;
+ uint16 key_len = strlen(KEY_PRINTING);
+
+ /*
+ * sanity check...this really should never be True.
+ * It is only here to prevent us from accessing outside
+ * the path buffer in the extreme case.
+ */
+
+ if ( strlen(path) < key_len ) {
+ DEBUG(0,("trim_reg_path: Registry path too short! [%s]\n", path));
+ DEBUG(0,("trim_reg_path: KEY_PRINTING => [%s]!\n", KEY_PRINTING));
+ return NULL;
+ }
+
+
+ p = path + strlen( KEY_PRINTING );
+
+ if ( *p == '\\' )
+ p++;
+
+ if ( *p )
+ return strdup(p);
+ else
+ return NULL;
+}
+
+/**********************************************************************
+ handle enumeration of subkeys below KEY_PRINTING\Environments
+ *********************************************************************/
+
+static int print_subpath_environments( char *key, REGSUBKEY_CTR *subkeys )
+{
+ char *environments[] = {
+ "Windows 4.0",
+ "Windows NT x86",
+ "Windows NT R4000",
+ "Windows NT Alpha_AXP",
+ "Windows NT PowerPC",
+ NULL };
+ fstring *drivers = NULL;
+ int i, env_index, num_drivers;
+ BOOL valid_env = False;
+ char *base, *new_path;
+ char *keystr;
+ char *key2 = NULL;
+ int num_subkeys = -1;
+
+ DEBUG(10,("print_subpath_environments: key=>[%s]\n", key ? key : "NULL" ));
+
+ /* listed architectures of installed drivers */
+
+ if ( !key )
+ {
+ /* Windows 9x drivers */
+
+ if ( get_ntdrivers( &drivers, environments[0], 0 ) )
+ regsubkey_ctr_addkey( subkeys, environments[0] );
+ SAFE_FREE( drivers );
+
+ /* Windows NT/2k intel drivers */
+
+ if ( get_ntdrivers( &drivers, environments[1], 2 )
+ || get_ntdrivers( &drivers, environments[1], 3 ) )
+ {
+ regsubkey_ctr_addkey( subkeys, environments[1] );
+ }
+ SAFE_FREE( drivers );
+
+ /* Windows NT 4.0; non-intel drivers */
+ for ( i=2; environments[i]; i++ ) {
+ if ( get_ntdrivers( &drivers, environments[i], 2 ) )
+ regsubkey_ctr_addkey( subkeys, environments[i] );
+
+ }
+ SAFE_FREE( drivers );
+
+ num_subkeys = regsubkey_ctr_numkeys( subkeys );
+ goto done;
+ }
+
+ /* we are dealing with a subkey of "Environments */
+
+ key2 = strdup( key );
+ keystr = key2;
+ reg_split_path( keystr, &base, &new_path );
+
+ /* sanity check */
+
+ for ( env_index=0; environments[env_index]; env_index++ ) {
+ if ( StrCaseCmp( environments[env_index], base ) == 0 ) {
+ valid_env = True;
+ break;
+ }
+ }
+
+ if ( !valid_env )
+ return -1;
+
+ /* enumerate driver versions; environment is environments[env_index] */
+
+ if ( !new_path ) {
+ switch ( env_index ) {
+ case 0: /* Win9x */
+ if ( get_ntdrivers( &drivers, environments[0], 0 ) ) {
+ regsubkey_ctr_addkey( subkeys, "0" );
+ SAFE_FREE( drivers );
+ }
+ break;
+ case 1: /* Windows NT/2k - intel */
+ if ( get_ntdrivers( &drivers, environments[1], 2 ) ) {
+ regsubkey_ctr_addkey( subkeys, "2" );
+ SAFE_FREE( drivers );
+ }
+ if ( get_ntdrivers( &drivers, environments[1], 3 ) ) {
+ regsubkey_ctr_addkey( subkeys, "3" );
+ SAFE_FREE( drivers );
+ }
+ break;
+ default: /* Windows NT - nonintel */
+ if ( get_ntdrivers( &drivers, environments[env_index], 2 ) ) {
+ regsubkey_ctr_addkey( subkeys, "2" );
+ SAFE_FREE( drivers );
+ }
+
+ }
+
+ num_subkeys = regsubkey_ctr_numkeys( subkeys );
+ goto done;
+ }
+
+ /* we finally get to enumerate the drivers */
+
+ keystr = new_path;
+ reg_split_path( keystr, &base, &new_path );
+
+ if ( !new_path ) {
+ num_drivers = get_ntdrivers( &drivers, environments[env_index], atoi(base) );
+ for ( i=0; i<num_drivers; i++ )
+ regsubkey_ctr_addkey( subkeys, drivers[i] );
+
+ num_subkeys = regsubkey_ctr_numkeys( subkeys );
+ goto done;
+ }
+
+done:
+ SAFE_FREE( key2 );
+
+ return num_subkeys;
+}
+
+/***********************************************************************
+ simple function to prune a pathname down to the basename of a file
+ **********************************************************************/
+
+static char* dos_basename ( char *path )
+{
+ char *p;
+
+ p = strrchr( path, '\\' );
+ if ( p )
+ p++;
+ else
+ p = path;
+
+ return p;
+}
+
+/**********************************************************************
+ handle enumeration of values below
+ KEY_PRINTING\Environments\<arch>\<version>\<drivername>
+ *********************************************************************/
+
+static int print_subpath_values_environments( char *key, REGVAL_CTR *val )
+{
+ char *keystr;
+ char *key2 = NULL;
+ char *base, *new_path;
+ fstring env;
+ fstring driver;
+ int version;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver_ctr;
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
+ WERROR w_result;
+ char *buffer = NULL;
+ char *buffer2 = NULL;
+ int buffer_size = 0;
+ int i, length;
+ char *filename;
+
+ DEBUG(8,("print_subpath_values_environments: Enter key => [%s]\n", key ? key : "NULL"));
+
+ if ( !key )
+ return 0;
+
+ /*
+ * The only key below KEY_PRINTING\Environments that
+ * posseses values is each specific printer driver
+ * First get the arch, version, & driver name
+ */
+
+ /* env */
+
+ key2 = strdup( key );
+ keystr = key2;
+ reg_split_path( keystr, &base, &new_path );
+ if ( !base || !new_path )
+ return 0;
+ fstrcpy( env, base );
+
+ /* version */
+
+ keystr = new_path;
+ reg_split_path( keystr, &base, &new_path );
+ if ( !base || !new_path )
+ return 0;
+ version = atoi( base );
+
+ /* printer driver name */
+
+ keystr = new_path;
+ reg_split_path( keystr, &base, &new_path );
+ /* new_path should be NULL here since this must be the last key */
+ if ( !base || new_path )
+ return 0;
+ fstrcpy( driver, base );
+
+ w_result = get_a_printer_driver( &driver_ctr, 3, driver, env, version );
+
+ if ( !W_ERROR_IS_OK(w_result) )
+ return -1;
+
+ /* build the values out of the driver information */
+ info3 = driver_ctr.info_3;
+
+ filename = dos_basename( info3->driverpath );
+ regval_ctr_addvalue( val, "Driver", REG_SZ, filename, strlen(filename)+1 );
+ filename = dos_basename( info3->configfile );
+ regval_ctr_addvalue( val, "Configuration File", REG_SZ, filename, strlen(filename)+1 );
+ filename = dos_basename( info3->datafile );
+ regval_ctr_addvalue( val, "Data File", REG_SZ, filename, strlen(filename)+1 );
+ filename = dos_basename( info3->helpfile );
+ regval_ctr_addvalue( val, "Help File", REG_SZ, filename, strlen(filename)+1 );
+
+ regval_ctr_addvalue( val, "Data Type", REG_SZ, info3->defaultdatatype, strlen(info3->defaultdatatype)+1 );
+
+ regval_ctr_addvalue( val, "Version", REG_DWORD, (char*)&info3->cversion, sizeof(info3->cversion) );
+
+ if ( info3->dependentfiles )
+ {
+ /* place the list of dependent files in a single
+ character buffer, separating each file name by
+ a NULL */
+
+ for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ )
+ {
+ /* strip the path to only the file's base name */
+
+ filename = dos_basename( info3->dependentfiles[i] );
+
+ length = strlen(filename);
+
+ buffer2 = Realloc( buffer, buffer_size + length + 1 );
+ if ( !buffer2 )
+ break;
+ buffer = buffer2;
+
+ memcpy( buffer+buffer_size, filename, length+1 );
+
+ buffer_size += length + 1;
+ }
+
+ /* terminated by double NULL. Add the final one here */
+
+ buffer2 = Realloc( buffer, buffer_size + 1 );
+ if ( !buffer2 ) {
+ SAFE_FREE( buffer );
+ buffer_size = 0;
+ }
+ else {
+ buffer = buffer2;
+ buffer[buffer_size++] = '\0';
+ }
+ }
+
+ regval_ctr_addvalue( val, "Dependent Files", REG_MULTI_SZ, buffer, buffer_size );
+
+ free_a_printer_driver( driver_ctr, 3 );
+ SAFE_FREE( key2 );
+ SAFE_FREE( buffer );
+
+ DEBUG(8,("print_subpath_values_environments: Exit\n"));
+
+ return regval_ctr_numvals( val );
+}
+
+
+/**********************************************************************
+ handle enumeration of subkeys below KEY_PRINTING\Forms
+ Really just a stub function, but left here in case it needs to
+ be expanded later on
+ *********************************************************************/
+
+static int print_subpath_forms( char *key, REGSUBKEY_CTR *subkeys )
+{
+ DEBUG(10,("print_subpath_forms: key=>[%s]\n", key ? key : "NULL" ));
+
+ /* there are no subkeys */
+
+ if ( key )
+ return -1;
+
+ return 0;
+}
+
+/**********************************************************************
+ handle enumeration of values below KEY_PRINTING\Forms
+ *********************************************************************/
+
+static int print_subpath_values_forms( char *key, REGVAL_CTR *val )
+{
+ int num_values = 0;
+ uint32 data[8];
+ int form_index = 1;
+
+ DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
+
+ /* handle ..\Forms\ */
+
+ if ( !key )
+ {
+ nt_forms_struct *forms_list = NULL;
+ nt_forms_struct *form = NULL;
+ int i;
+
+ if ( (num_values = get_ntforms( &forms_list )) == 0 )
+ return 0;
+
+ DEBUG(10,("print_subpath_values_forms: [%d] user defined forms returned\n",
+ num_values));
+
+ /* handle user defined forms */
+
+ for ( i=0; i<num_values; i++ )
+ {
+ form = &forms_list[i];
+
+ data[0] = form->width;
+ data[1] = form->length;
+ data[2] = form->left;
+ data[3] = form->top;
+ data[4] = form->right;
+ data[5] = form->bottom;
+ data[6] = form_index++;
+ data[7] = form->flag;
+
+ regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
+
+ }
+
+ SAFE_FREE( forms_list );
+ forms_list = NULL;
+
+ /* handle built-on forms */
+
+ if ( (num_values = get_builtin_ntforms( &forms_list )) == 0 )
+ return 0;
+
+ DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
+ num_values));
+
+ for ( i=0; i<num_values; i++ )
+ {
+ form = &forms_list[i];
+
+ data[0] = form->width;
+ data[1] = form->length;
+ data[2] = form->left;
+ data[3] = form->top;
+ data[4] = form->right;
+ data[5] = form->bottom;
+ data[6] = form_index++;
+ data[7] = form->flag;
+
+ regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
+ }
+
+ SAFE_FREE( forms_list );
+ }
+
+ return num_values;
+}
+
+/**********************************************************************
+ handle enumeration of subkeys below KEY_PRINTING\Printers
+ *********************************************************************/
+
+static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys )
+{
+ int n_services = lp_numservices();
+ int snum;
+ fstring sname;
+ int num_subkeys = 0;
+ char *keystr, *key2 = NULL;
+ char *base, *new_path;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+
+ DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
+
+ if ( !key )
+ {
+ /* enumerate all printers */
+
+ for (snum=0; snum<n_services; snum++) {
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
+ continue;
+
+ fstrcpy( sname, lp_servicename(snum) );
+
+ regsubkey_ctr_addkey( subkeys, sname );
+ }
+
+ num_subkeys = regsubkey_ctr_numkeys( subkeys );
+ goto done;
+ }
+
+ /* get information for a specific printer */
+
+ key2 = strdup( key );
+ keystr = key2;
+ reg_split_path( keystr, &base, &new_path );
+
+
+ if ( !new_path ) {
+ /* sanity check on the printer name */
+ if ( !W_ERROR_IS_OK( get_a_printer(&printer, 2, base) ) )
+ goto done;
+
+ free_a_printer( &printer, 2 );
+
+ regsubkey_ctr_addkey( subkeys, SPOOL_PRINTERDATA_KEY );
+ }
+
+ /* no other subkeys below here */
+
+done:
+ SAFE_FREE( key2 );
+ return num_subkeys;
+}
+
+/**********************************************************************
+ handle enumeration of values below KEY_PRINTING\Printers
+ *********************************************************************/
+
+static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
+{
+ int num_values = 0;
+ char *keystr, *key2 = NULL;
+ char *base, *new_path;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_INFO_LEVEL_2 *info2;
+ DEVICEMODE *devmode;
+ prs_struct prs;
+ uint32 offset;
+ int snum;
+ int i;
+ fstring valuename;
+ uint8 *data;
+ uint32 type, data_len;
+ fstring printername;
+
+ /*
+ * There are tw cases to deal with here
+ * (1) enumeration of printer_info_2 values
+ * (2) enumeration of the PrinterDriverData subney
+ */
+
+ if ( !key ) {
+ /* top level key has no values */
+ goto done;
+ }
+
+ key2 = strdup( key );
+ keystr = key2;
+ reg_split_path( keystr, &base, &new_path );
+
+ fstrcpy( printername, base );
+
+ if ( !new_path )
+ {
+ /* we are dealing with the printer itself */
+
+ if ( !W_ERROR_IS_OK( get_a_printer(&printer, 2, printername) ) )
+ goto done;
+
+ info2 = printer->info_2;
+
+
+ regval_ctr_addvalue( val, "Attributes", REG_DWORD, (char*)&info2->attributes, sizeof(info2->attributes) );
+ regval_ctr_addvalue( val, "Priority", REG_DWORD, (char*)&info2->priority, sizeof(info2->attributes) );
+ regval_ctr_addvalue( val, "ChangeID", REG_DWORD, (char*)&info2->changeid, sizeof(info2->changeid) );
+ regval_ctr_addvalue( val, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
+ regval_ctr_addvalue( val, "Status", REG_DWORD, (char*)&info2->status, sizeof(info2->status) );
+ regval_ctr_addvalue( val, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) );
+ regval_ctr_addvalue( val, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) );
+ regval_ctr_addvalue( val, "cjobs", REG_DWORD, (char*)&info2->cjobs, sizeof(info2->cjobs) );
+ regval_ctr_addvalue( val, "AveragePPM", REG_DWORD, (char*)&info2->averageppm, sizeof(info2->averageppm) );
+
+ regval_ctr_addvalue( val, "Name", REG_SZ, info2->printername, sizeof(info2->printername)+1 );
+ regval_ctr_addvalue( val, "Location", REG_SZ, info2->location, sizeof(info2->location)+1 );
+ regval_ctr_addvalue( val, "Comment", REG_SZ, info2->comment, sizeof(info2->comment)+1 );
+ regval_ctr_addvalue( val, "Parameters", REG_SZ, info2->parameters, sizeof(info2->parameters)+1 );
+ regval_ctr_addvalue( val, "Port", REG_SZ, info2->portname, sizeof(info2->portname)+1 );
+ regval_ctr_addvalue( val, "Server", REG_SZ, info2->servername, sizeof(info2->servername)+1 );
+ regval_ctr_addvalue( val, "Share", REG_SZ, info2->sharename, sizeof(info2->sharename)+1 );
+ regval_ctr_addvalue( val, "Driver", REG_SZ, info2->drivername, sizeof(info2->drivername)+1 );
+ regval_ctr_addvalue( val, "Separator File", REG_SZ, info2->sepfile, sizeof(info2->sepfile)+1 );
+ regval_ctr_addvalue( val, "Print Processor", REG_SZ, "winprint", sizeof("winprint")+1 );
+
+
+ /* use a prs_struct for converting the devmode and security
+ descriptor to REG_BIARY */
+
+ prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(val), MARSHALL);
+
+ /* stream the device mode */
+
+ snum = lp_servicenumber(info2->sharename);
+ if ( (devmode = construct_dev_mode( snum )) != NULL )
+ {
+ if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
+
+ offset = prs_offset( &prs );
+
+ regval_ctr_addvalue( val, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
+ }
+
+
+ }
+
+ prs_mem_clear( &prs );
+ prs_set_offset( &prs, 0 );
+
+ if ( info2->secdesc_buf && info2->secdesc_buf->len )
+ {
+ if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
+
+ offset = prs_offset( &prs );
+
+ regval_ctr_addvalue( val, "Security", REG_BINARY, prs_data_p(&prs), offset );
+ }
+ }
+
+
+ prs_mem_free( &prs );
+ free_a_printer( &printer, 2 );
+
+ num_values = regval_ctr_numvals( val );
+ goto done;
+
+ }
+
+
+ keystr = new_path;
+ reg_split_path( keystr, &base, &new_path );
+
+ /* here should be no more path components here */
+
+ if ( new_path || strcmp(base, SPOOL_PRINTERDATA_KEY) )
+ goto done;
+
+ /* now enumerate the PrinterDriverData key */
+ if ( !W_ERROR_IS_OK( get_a_printer(&printer, 2, printername) ) )
+ goto done;
+
+ info2 = printer->info_2;
+
+
+ /* iterate over all printer data and fill the regval container */
+
+#if 0 /* JERRY */
+ for ( i=0; get_specific_param_by_index(*printer, 2, i, valuename, &data, &type, &data_len); i++ )
+ {
+ regval_ctr_addvalue( val, valuename, type, data, data_len );
+ }
+#endif
+
+ free_a_printer( &printer, 2 );
+
+ num_values = regval_ctr_numvals( val );
+
+done:
+ SAFE_FREE( key2 );
+
+ return num_values;
+}
+
+/**********************************************************************
+ Routine to handle enumeration of subkeys and values
+ below KEY_PRINTING (depending on whether or not subkeys/val are
+ valid pointers.
+ *********************************************************************/
+
+static int handle_printing_subpath( char *key, REGSUBKEY_CTR *subkeys, REGVAL_CTR *val )
+{
+ int result = 0;
+ char *p, *base;
+ int i;
+
+ DEBUG(10,("handle_printing_subpath: key=>[%s]\n", key ));
+
+ /*
+ * break off the first part of the path
+ * topmost base **must** be one of the strings
+ * in top_level_keys[]
+ */
+
+ reg_split_path( key, &base, &p);
+
+ for ( i=0; i<MAX_TOP_LEVEL_KEYS; i++ ) {
+ if ( StrCaseCmp( top_level_keys[i], base ) == 0 )
+ break;
+ }
+
+ DEBUG(10,("handle_printing_subpath: base=>[%s], i==[%d]\n", base, i));
+
+ if ( !(i < MAX_TOP_LEVEL_KEYS) )
+ return -1;
+
+ /* Call routine to handle each top level key */
+ switch ( i )
+ {
+ case KEY_INDEX_ENVIR:
+ if ( subkeys )
+ print_subpath_environments( p, subkeys );
+ if ( val )
+ print_subpath_values_environments( p, val );
+ break;
+
+ case KEY_INDEX_FORMS:
+ if ( subkeys )
+ print_subpath_forms( p, subkeys );
+ if ( val )
+ print_subpath_values_forms( p, val );
+ break;
+
+ case KEY_INDEX_PRINTER:
+ if ( subkeys )
+ print_subpath_printers( p, subkeys );
+ if ( val )
+ print_subpath_values_printers( p, val );
+ break;
+
+ /* default case for top level key that has no handler */
+
+ default:
+ break;
+ }
+
+
+
+ return result;
+
+}
+/**********************************************************************
+ Enumerate registry subkey names given a registry path.
+ Caller is responsible for freeing memory to **subkeys
+ *********************************************************************/
+
+int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr )
+{
+ char *path;
+ BOOL top_level = False;
+ int num_subkeys = 0;
+
+ DEBUG(10,("printing_subkey_info: key=>[%s]\n", key));
+
+ path = trim_reg_path( key );
+
+ /* check to see if we are dealing with the top level key */
+
+ if ( !path )
+ top_level = True;
+
+ if ( top_level ) {
+ for ( num_subkeys=0; num_subkeys<MAX_TOP_LEVEL_KEYS; num_subkeys++ )
+ regsubkey_ctr_addkey( subkey_ctr, top_level_keys[num_subkeys] );
+ }
+ else
+ num_subkeys = handle_printing_subpath( path, subkey_ctr, NULL );
+
+ SAFE_FREE( path );
+
+ return num_subkeys;
+}
+
+/**********************************************************************
+ Enumerate registry values given a registry path.
+ Caller is responsible for freeing memory
+ *********************************************************************/
+
+int printing_value_info( char *key, REGVAL_CTR *val )
+{
+ char *path;
+ BOOL top_level = False;
+ int num_values = 0;
+
+ DEBUG(10,("printing_value_info: key=>[%s]\n", key));
+
+ path = trim_reg_path( key );
+
+ /* check to see if we are dealing with the top level key */
+
+ if ( !path )
+ top_level = True;
+
+ /* fill in values from the getprinterdata_printer_server() */
+ if ( top_level )
+ num_values = 0;
+ else
+ num_values = handle_printing_subpath( path, NULL, val );
+
+
+ return num_values;
+}
+
+/**********************************************************************
+ Stub function which always returns failure since we don't want
+ people storing printing information directly via regostry calls
+ (for now at least)
+ *********************************************************************/
+
+BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
+{
+ return False;
+}
+
+/**********************************************************************
+ Stub function which always returns failure since we don't want
+ people storing printing information directly via regostry calls
+ (for now at least)
+ *********************************************************************/
+
+BOOL printing_store_value( char *key, REGVAL_CTR *val )
+{
+ return False;
+}
+
+/*
+ * Table of function pointers for accessing printing data
+ */
+
+REGISTRY_OPS printing_ops = {
+ printing_subkey_info,
+ printing_value_info,
+ printing_store_subkey,
+ printing_store_value
+};
+
+
diff --git a/source3/rpc_client/cli_dfs.c b/source3/rpc_client/cli_dfs.c
new file mode 100644
index 0000000000..7fc27b9c3b
--- /dev/null
+++ b/source3/rpc_client/cli_dfs.c
@@ -0,0 +1,245 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ 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"
+
+/* Query DFS support */
+
+NTSTATUS cli_dfs_exist(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL *dfs_exists)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_EXIST q;
+ DFS_R_DFS_EXIST r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_exist(&q);
+
+ if (!dfs_io_q_dfs_exist("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_EXIST, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_exist("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ *dfs_exists = (r.status != 0);
+
+ result = NT_STATUS_OK;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_add(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename,
+ char *comment, uint32 flags)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_ADD q;
+ DFS_R_DFS_ADD r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_add(&q, entrypath, servername, sharename, comment,
+ flags);
+
+ if (!dfs_io_q_dfs_add("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_ADD, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_add("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_remove(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_REMOVE q;
+ DFS_R_DFS_REMOVE r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_remove(&q, entrypath, servername, sharename);
+
+ if (!dfs_io_q_dfs_remove("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_REMOVE, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_remove("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_get_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename,
+ uint32 info_level, DFS_INFO_CTR *ctr)
+
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_GET_INFO q;
+ DFS_R_DFS_GET_INFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_get_info(&q, entrypath, servername, sharename,
+ info_level);
+
+ if (!dfs_io_q_dfs_get_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_GET_INFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_get_info("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+ *ctr = r.ctr;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate dfs shares */
+
+NTSTATUS cli_dfs_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 info_level, DFS_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_ENUM q;
+ DFS_R_DFS_ENUM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_enum(&q, info_level, ctr);
+
+ if (!dfs_io_q_dfs_enum("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_ENUM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!dfs_io_r_dfs_enum("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
new file mode 100644
index 0000000000..5555f4bd52
--- /dev/null
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -0,0 +1,1256 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997,2000,
+ Copyright (C) Paul Ashton 1997,2000,
+ Copyright (C) Elrond 2000,
+ 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"
+
+/** @defgroup lsa LSA - Local Security Architecture
+ * @ingroup rpc_client
+ *
+ * @{
+ **/
+
+/**
+ * @file cli_lsarpc.c
+ *
+ * RPC client routines for the LSA RPC pipe. LSA means "local
+ * security authority", which is half of a password database.
+ **/
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPEN_POL q;
+ LSA_R_OPEN_POL r;
+ LSA_SEC_QOS qos;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 2, 1, 0);
+ init_q_open_pol(&q, '\\', 0, des_access, &qos);
+ } else {
+ init_q_open_pol(&q, '\\', 0, des_access, NULL);
+ }
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_pol("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENPOLICY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_pol("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+#ifdef __INSURE__
+ pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection
+ */
+
+NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPEN_POL2 q;
+ LSA_R_OPEN_POL2 r;
+ LSA_SEC_QOS qos;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 2, 1, 0);
+ init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access,
+ &qos);
+ } else {
+ init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access,
+ NULL);
+ }
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_pol2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_pol2("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+#ifdef __INSURE__
+ pol->marker = (char *)malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Close a LSA policy handle */
+
+NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_CLOSE q;
+ LSA_R_CLOSE r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_close(&q, pol);
+
+ if (!lsa_io_q_close("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_CLOSE, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_close("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+#ifdef __INSURE__
+ SAFE_FREE(pol->marker);
+#endif
+ *pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Lookup a list of sids */
+
+NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_sids, DOM_SID *sids,
+ char ***domains, char ***names, uint32 **types)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUP_SIDS q;
+ LSA_R_LOOKUP_SIDS r;
+ DOM_R_REF ref;
+ LSA_TRANS_NAME_ENUM t_names;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
+
+ if (!lsa_io_q_lookup_sids("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ ZERO_STRUCT(ref);
+ ZERO_STRUCT(t_names);
+
+ r.dom_ref = &ref;
+ r.names = &t_names;
+
+ if (!lsa_io_r_lookup_sids("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
+
+ /* An actual error occured */
+
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (r.mapped_count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ if (!((*domains) = (char **)talloc(mem_ctx, sizeof(char *) *
+ num_sids))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*names) = (char **)talloc(mem_ctx, sizeof(char *) *
+ num_sids))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*types) = (uint32 *)talloc(mem_ctx, sizeof(uint32) *
+ num_sids))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < num_sids; i++) {
+ fstring name, dom_name;
+ uint32 dom_idx = t_names.name[i].domain_idx;
+
+ /* Translate optimised name through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ rpcstr_pull_unistr2_fstring(
+ dom_name, &ref.ref_dom[dom_idx].uni_dom_name);
+ rpcstr_pull_unistr2_fstring(
+ name, &t_names.uni_name[i]);
+
+ (*names)[i] = talloc_strdup(mem_ctx, name);
+ (*domains)[i] = talloc_strdup(mem_ctx, dom_name);
+ (*types)[i] = t_names.name[i].sid_name_use;
+
+ if (((*names)[i] == NULL) || ((*domains)[i] == NULL)) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ } else {
+ (*names)[i] = NULL;
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Lookup a list of names */
+
+NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_names,
+ const char **names, DOM_SID **sids,
+ uint32 **types)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUP_NAMES q;
+ LSA_R_LOOKUP_NAMES r;
+ DOM_R_REF ref;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
+
+ if (!lsa_io_q_lookup_names("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ ZERO_STRUCT(ref);
+ r.dom_ref = &ref;
+
+ if (!lsa_io_r_lookup_names("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
+ NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
+
+ /* An actual error occured */
+
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (r.mapped_count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ if (!((*sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) *
+ num_names)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*types = (uint32 *)talloc(mem_ctx, sizeof(uint32) *
+ num_names)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < num_names; i++) {
+ DOM_RID2 *t_rids = r.dom_rid;
+ uint32 dom_idx = t_rids[i].rid_idx;
+ uint32 dom_rid = t_rids[i].rid;
+ DOM_SID *sid = &(*sids)[i];
+
+ /* Translate optimised sid through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ sid_copy(sid, &ref.ref_dom[dom_idx].ref_dom.sid);
+
+ if (dom_rid != 0xffffffff) {
+ sid_append_rid(sid, dom_rid);
+ }
+
+ (*types)[i] = t_rids[i].type;
+ } else {
+ ZERO_STRUCTP(sid);
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query info policy
+ *
+ * @param domain_sid - returned remote server's domain sid */
+
+NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint16 info_class,
+ fstring domain_name, DOM_SID *domain_sid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_INFO q;
+ LSA_R_QUERY_INFO r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query(&q, pol, info_class);
+
+ if (!lsa_io_q_query("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ ZERO_STRUCTP(domain_sid);
+ domain_name[0] = '\0';
+
+ switch (info_class) {
+
+ case 3:
+ if (r.dom.id3.buffer_dom_name != 0) {
+ unistr2_to_ascii(domain_name,
+ &r.dom.id3.
+ uni_domain_name,
+ sizeof (fstring) - 1);
+ }
+
+ if (r.dom.id3.buffer_dom_sid != 0) {
+ *domain_sid = r.dom.id3.dom_sid.sid;
+ }
+
+ break;
+
+ case 5:
+
+ if (r.dom.id5.buffer_dom_name != 0) {
+ unistr2_to_ascii(domain_name, &r.dom.id5.
+ uni_domain_name,
+ sizeof (fstring) - 1);
+ }
+
+ if (r.dom.id5.buffer_dom_sid != 0) {
+ *domain_sid = r.dom.id5.dom_sid.sid;
+ }
+
+ break;
+
+ default:
+ DEBUG(3, ("unknown info class %d\n", info_class));
+ break;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query info policy2
+ *
+ * @param domain_name - returned remote server's domain name
+ * @param dns_name - returned remote server's dns domain name
+ * @param forest_name - returned remote server's forest name
+ * @param domain_guid - returned remote server's domain guid
+ * @param domain_sid - returned remote server's domain sid */
+
+NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint16 info_class,
+ fstring domain_name, fstring dns_name,
+ fstring forest_name, GUID *domain_guid,
+ DOM_SID *domain_sid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_INFO2 q;
+ LSA_R_QUERY_INFO2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (info_class != 12)
+ goto done;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query2(&q, pol, info_class);
+
+ if (!lsa_io_q_query_info2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYINFO2, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query_info2("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ ZERO_STRUCTP(domain_sid);
+ ZERO_STRUCTP(domain_guid);
+ domain_name[0] = '\0';
+
+ if (r.info.dns_dom_info.hdr_nb_dom_name.buffer) {
+ unistr2_to_ascii(domain_name,
+ &r.info.dns_dom_info.uni_nb_dom_name,
+ sizeof(fstring) - 1);
+ }
+ if (r.info.dns_dom_info.hdr_dns_dom_name.buffer) {
+ unistr2_to_ascii(dns_name,
+ &r.info.dns_dom_info.uni_dns_dom_name,
+ sizeof(fstring) - 1);
+ }
+ if (r.info.dns_dom_info.hdr_forest_name.buffer) {
+ unistr2_to_ascii(forest_name,
+ &r.info.dns_dom_info.uni_forest_name,
+ sizeof(fstring) - 1);
+ }
+
+ memcpy(domain_guid, &r.info.dns_dom_info.dom_guid, sizeof(GUID));
+
+ if (r.info.dns_dom_info.ptr_dom_sid != 0) {
+ *domain_sid = r.info.dns_dom_info.dom_sid.sid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/**
+ * Enumerate list of trusted domains
+ *
+ * @param cli client state (cli_state) structure of the connection
+ * @param mem_ctx memory context
+ * @param pol opened lsa policy handle
+ * @param enum_ctx enumeration context ie. index of first returned domain entry
+ * @param pref_num_domains preferred max number of entries returned in one response
+ * @param num_domains total number of trusted domains returned by response
+ * @param domain_names returned trusted domain names
+ * @param domain_sids returned trusted domain sids
+ *
+ * @return nt status code of response
+ **/
+
+NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_ctx,
+ uint32 *num_domains,
+ char ***domain_names, DOM_SID **domain_sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_TRUST_DOM q;
+ LSA_R_ENUM_TRUST_DOM r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ /* 64k is enough for about 2000 trusted domains */
+ init_q_enum_trust_dom(&q, pol, *enum_ctx, 0x10000);
+
+ if (!lsa_io_q_enum_trust_dom("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUMTRUSTDOM, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_trust_dom("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
+
+ /* An actual error ocured */
+
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (r.num_domains) {
+
+ /* Allocate memory for trusted domain names and sids */
+
+ *domain_names = (char **)talloc(mem_ctx, sizeof(char *) *
+ r.num_domains);
+
+ if (!*domain_names) {
+ DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ *domain_sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) *
+ r.num_domains);
+ if (!domain_sids) {
+ DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /* Copy across names and sids */
+
+ for (i = 0; i < r.num_domains; i++) {
+ fstring tmp;
+
+ unistr2_to_ascii(tmp, &r.uni_domain_name[i],
+ sizeof(tmp) - 1);
+ (*domain_names)[i] = talloc_strdup(mem_ctx, tmp);
+ sid_copy(&(*domain_sids)[i], &r.domain_sid[i].sid);
+ }
+ }
+
+ *num_domains = r.num_domains;
+ *enum_ctx = r.enum_context;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+
+/** Enumerate privileges*/
+
+NTSTATUS cli_lsa_enum_privilege(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_context, uint32 pref_max_length,
+ uint32 *count, char ***privs_name, uint32 **privs_high, uint32 **privs_low)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_PRIVS q;
+ LSA_R_ENUM_PRIVS r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_enum_privs(&q, pol, *enum_context, pref_max_length);
+
+ if (!lsa_io_q_enum_privs("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUM_PRIVS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_privs("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ *enum_context = r.enum_context;
+ *count = r.count;
+
+ if (!((*privs_name = (char **)talloc(mem_ctx, sizeof(char *) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*privs_high = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*privs_low = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.count; i++) {
+ fstring name;
+
+ rpcstr_pull_unistr2_fstring( name, &r.privs[i].name);
+
+ (*privs_name)[i] = talloc_strdup(mem_ctx, name);
+
+ (*privs_high)[i] = r.privs[i].luid_high;
+ (*privs_low)[i] = r.privs[i].luid_low;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get privilege name */
+
+NTSTATUS cli_lsa_get_dispname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char *name, uint16 lang_id, uint16 lang_id_sys,
+ fstring description, uint16 *lang_id_desc)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_PRIV_GET_DISPNAME q;
+ LSA_R_PRIV_GET_DISPNAME r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_priv_get_dispname(&q, pol, name, lang_id, lang_id_sys);
+
+ if (!lsa_io_q_priv_get_dispname("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_PRIV_GET_DISPNAME, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_priv_get_dispname("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ rpcstr_pull_unistr2_fstring(description , &r.desc);
+ *lang_id_desc = r.lang_id;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate list of SIDs */
+
+NTSTATUS cli_lsa_enum_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_ctx, uint32 pref_max_length,
+ uint32 *num_sids, DOM_SID **sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_ACCOUNTS q;
+ LSA_R_ENUM_ACCOUNTS r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_enum_accounts(&q, pol, *enum_ctx, pref_max_length);
+
+ if (!lsa_io_q_enum_accounts("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUM_ACCOUNTS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_accounts("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.sids.num_entries==0)
+ goto done;
+
+ /* Return output parameters */
+
+ *sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) * r.sids.num_entries);
+ if (!*sids) {
+ DEBUG(0, ("(cli_lsa_enum_sids): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Copy across names and sids */
+
+ for (i = 0; i < r.sids.num_entries; i++) {
+ sid_copy(&(*sids)[i], &r.sids.sid[i].sid);
+ }
+
+ *num_sids= r.sids.num_entries;
+ *enum_ctx = r.enum_context;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Open a LSA user handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_open_account(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *dom_pol, DOM_SID *sid, uint32 des_access,
+ POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPENACCOUNT q;
+ LSA_R_OPENACCOUNT r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_lsa_q_open_account(&q, dom_pol, sid, des_access);
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_account("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENACCOUNT, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_account("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *user_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate user privileges
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_enum_privsaccount(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *count, LUID_ATTR **set)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUMPRIVSACCOUNT q;
+ LSA_R_ENUMPRIVSACCOUNT r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_lsa_q_enum_privsaccount(&q, pol);
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_enum_privsaccount("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUMPRIVSACCOUNT, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_privsaccount("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.count == 0)
+ goto done;
+
+ if (!((*set = (LUID_ATTR *)talloc(mem_ctx, sizeof(LUID_ATTR) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privsaccount): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i=0; i<r.count; i++) {
+ (*set)[i].luid.low = r.set.set[i].luid.low;
+ (*set)[i].luid.high = r.set.set[i].luid.high;
+ (*set)[i].attr = r.set.set[i].attr;
+ }
+
+ *count=r.count;
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get a privilege value given its name */
+
+NTSTATUS cli_lsa_lookupprivvalue(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char *name, LUID *luid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUPPRIVVALUE q;
+ LSA_R_LOOKUPPRIVVALUE r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_lookupprivvalue(&q, pol, name);
+
+ if (!lsa_io_q_lookupprivvalue("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPPRIVVALUE, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_lookupprivvalue("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ (*luid).low=r.luid.low;
+ (*luid).high=r.luid.high;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query LSA security object */
+
+NTSTATUS cli_lsa_query_secobj(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 sec_info,
+ SEC_DESC_BUF **psdb)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_SEC_OBJ q;
+ LSA_R_QUERY_SEC_OBJ r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query_sec_obj(&q, pol, sec_info);
+
+ if (!lsa_io_q_query_sec_obj("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYSECOBJ, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query_sec_obj("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (psdb)
+ *psdb = r.buf;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+#if 0
+
+/** An example of how to use the routines in this file. Fetch a DOMAIN
+ sid. Does complete cli setup / teardown anonymously. */
+
+BOOL fetch_domain_sid( char *domain, char *remote_machine, DOM_SID *psid)
+{
+ extern pstring global_myname;
+ struct cli_state cli;
+ NTSTATUS result;
+ POLICY_HND lsa_pol;
+ BOOL ret = False;
+
+ ZERO_STRUCT(cli);
+ if(cli_initialise(&cli) == False) {
+ DEBUG(0,("fetch_domain_sid: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
+ DEBUG(0,("fetch_domain_sid: Can't resolve address for %s\n", remote_machine));
+ goto done;
+ }
+
+ if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("fetch_domain_sid: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (!attempt_netbios_session_request(&cli, global_myname, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the NetBIOS session request.\n",
+ remote_machine));
+ goto done;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (cli.protocol != PROTOCOL_NT1) {
+ DEBUG(0,("fetch_domain_sid: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ goto done;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (!(cli.sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
+ DEBUG(0,("fetch_domain_sid: machine %s isn't in user level security mode\n",
+ remote_machine));
+ goto done;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ /* Fetch domain sid */
+
+ if (!cli_nt_session_open(&cli, PIPE_LSARPC)) {
+ DEBUG(0, ("fetch_domain_sid: Error connecting to SAM pipe\n"));
+ goto done;
+ }
+
+ result = cli_lsa_open_policy(&cli, cli.mem_ctx, True, SEC_RIGHTS_QUERY_VALUE, &lsa_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("fetch_domain_sid: Error opening lsa policy handle. %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+ result = cli_lsa_query_info_policy(&cli, cli.mem_ctx, &lsa_pol, 5, domain, psid);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("fetch_domain_sid: Error querying lsa policy handle. %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+ ret = True;
+
+ done:
+
+ cli_shutdown(&cli);
+ return ret;
+}
+
+#endif
+
+/** @} **/
diff --git a/source3/sam/SAM-interface_handles.txt b/source3/sam/SAM-interface_handles.txt
new file mode 100644
index 0000000000..1c164bd198
--- /dev/null
+++ b/source3/sam/SAM-interface_handles.txt
@@ -0,0 +1,123 @@
+SAM API
+
+NTSTATUS sam_get_sec_obj(NT_USER_TOKEN *access, DOM_SID *sid, SEC_DESC **sd)
+NTSTATUS sam_set_sec_obj(NT_USER_TOKEN *access, DOM_SID *sid, SEC_DESC *sd)
+
+NTSTATUS sam_lookup_name(NT_USER_TOKEN *access, DOM_SID *domain, char *name, DOM_SID **sid, uint32 *type)
+NTSTATUS sam_lookup_sid(NT_USER_TOKEN *access, DOM_SID *sid, char **name, uint32 *type)
+
+
+Domain API
+
+NTSTATUS sam_update_domain(SAM_DOMAIN_HANDLE *domain)
+
+NTSTATUS sam_enum_domains(NT_USER_TOKEN *access, int32 *domain_count, DOM_SID **domains, char **domain_names)
+NTSTATUS sam_lookup_domain(NT_USER_TOKEN *access, char *domain, DOM_SID **domainsid)
+
+NTSTATUS sam_get_domain_by_sid(NT_USER_TOKEN *access, uint32 access_desired, DOM_SID *domainsid, SAM_DOMAIN_HANDLE **domain)
+
+
+User API
+
+NTSTATUS sam_create_user(NT_USER_TOKEN *access, uint32 access_desired, SAM_USER_HANDLE **user)
+NTSTATUS sam_add_user(SAM_USER_HANDLE *user)
+NTSTATUS sam_update_user(SAM_USER_HANDLE *user)
+NTSTATUS sam_delete_user(SAM_USER_HANDLE * user)
+
+NTSTATUS sam_enum_users(NT_USER_TOKEN *access, DOM_SID *domain, int32 *user_count, SAM_USER_ENUM **users)
+
+NTSTATUS sam_get_user_by_sid(NT_USER_TOKEN *access, uint32 access_desired, DOM_SID *usersid, SAM_USER_HANDLE **user)
+NTSTATUS sam_get_user_by_name(NT_USER_TOKEN *access, uint32 access_desired, char *domain, char *name, SAM_USER_HANDLE **user)
+
+
+Group API
+
+NTSTATUS sam_create_group(NT_USER_TOKEN *access, uint32 access_desired, uint32 typ, SAM_GROUP_HANDLE **group)
+NTSTATUS sam_add_group(SAM_GROUP_HANDLE *samgroup)
+NTSTATUS sam_update_group(SAM_GROUP_HANDLE *samgroup)
+NTSTATUS sam_delete_group(SAM_GROUP_HANDLE *groupsid)
+
+NTSTATUS sam_enum_groups(NT_USER_TOKEN *access, DOM_SID *domainsid, uint32 typ, uint32 *groups_count, SAM_GROUP_ENUM **groups)
+
+NTSTATUS sam_get_group_by_sid(NT_USER_TOKEN *access, uint32 access_desired, DOM_SID *groupsid, SAM_GROUP_HANDLE **group)
+NTSTATUS sam_get_group_by_name(NT_USER_TOKEN *access, uint32 access_desired, char *domain, char *name, SAM_GROUP_HANDLE **group)
+
+NTSTATUS sam_add_member_to_group(SAM_GROUP_HANDLE *group, SAM_GROUP_MEMBER *member)
+NTSTATUS sam_delete_member_from_group(SAM_GROUP_HANDLE *group, SAM_GROUP_MEMBER *member)
+NTSTATUS sam_enum_groupmembers(SAM_GROUP_HANLDE *group, uint32 *members_count, SAM_GROUP_MEMBER **members)
+
+NTSTATUS sam_get_groups_of_user(SAM_USER_HANDLE *user, uint32 typ, uint32 *group_count, SAM_GROUP_ENUM **groups)
+
+
+
+structures
+
+typedef _SAM_GROUP_MEMBER {
+ DOM_SID sid;
+ BOOL group; /* specifies if it is a group or a user */
+
+} SAM_GROUP_MEMBER
+
+typedef struct sam_user_enum {
+ DOM_SID sid;
+ char *username;
+ char *full_name;
+ char *user_desc;
+ uint16 acc_ctrl;
+} SAM_USER_ENUM;
+
+typedef struct sam_group_enum {
+ DOM_SID sid;
+ char *groupname;
+ char *comment;
+} SAM_GROUP_ENUM
+
+NTSTATUS sam_get_domain_sid(SAM_DOMAIN_HANDLE *domain, DOM_SID **sid)
+NTSTATUS sam_get_domain_num_users(SAM_DOMAIN_HANDLE *domain, uint32 *num_users)
+NTSTATUS sam_get_domain_num_groups(SAM_DOMAIN_HANDLE *domain, uint32 *num_groups)
+NTSTATUS sam_get_domain_num_aliases(SAM_DOMAIN_HANDLE *domain, uint32 *num_aliases)
+NTSTATUS sam_{get,set}_domain_name(SAM_DOMAIN_HANDLE *domain, char **domain_name)
+NTSTATUS sam_{get,set}_domain_server(SAM_DOMAIN_HANDLE *domain, char **server_name)
+NTSTATUS sam_{get,set}_domain_max_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME *max_passwordage)
+NTSTATUS sam_{get,set}_domain_min_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME *min_passwordage)
+NTSTATUS sam_{get,set}_domain_lockout_duration(SAM_DOMAIN_HANDLE *domain, NTTIME *lockout_duration)
+NTSTATUS sam_{get,set}_domain_reset_count(SAM_DOMAIN_HANDLE *domain, NTTIME *reset_lockout_count)
+NTSTATUS sam_{get,set}_domain_min_pwdlength(SAM_DOMAIN_HANDLE *domain, uint16 *min_passwordlength)
+NTSTATUS sam_{get,set}_domain_pwd_history(SAM_DOMAIN_HANDLE *domain, uin16 *password_history)
+NTSTATUS sam_{get,set}_domain_lockout_count(SAM_DOMAIN_HANDLE *domain, uint16 *lockout_count)
+NTSTATUS sam_{get,set}_domain_force_logoff(SAM_DOMAIN_HANDLE *domain, BOOL *force_logoff)
+NTSTATUS sam_{get,set}_domain_login_pwdchange(SAM_DOMAIN_HANDLE *domain, BOOL *login_pwdchange)
+
+NTSTATUS sam_get_user_sid(SAM_USER_HANDLE *user, DOM_SID **sid)
+NTSTATUS sam_{get,set}_user_pgroup(SAM_USER_HANDLE *user, DOM_SID **pgroup)
+NTSTATUS sam_{get,set}_user_name(SAM_USER_HANDLE *user, char **username)
+NTSTATUS sam_{get,set}_user_fullname(SAM_USER_HANDLE *user, char** fullname)
+NTSTATUS sam_{get,set}_user_description(SAM_USER_HANDLE *user, char **description)
+NTSTATUS sam_{get,set}_user_home_dir(SAM_USER_HANDLE *user, char **home_dir)
+NTSTATUS sam_{get,set}_user_dir_drive(SAM_USER_HANDLE *user, char **dir_drive)
+NTSTATUS sam_{get,set}_user_logon_script(SAM_USER_HANDLE *user, char **logon_script)
+NTSTATUS sam_{get,set}_user_profile_path(SAM_USER_HANDLE *user, char **profile_path)
+NTSTATUS sam_{get,set}_user_workstations(SAM_USER_HANDLE *user, char **workstations)
+NTSTATUS sam_{get,set}_user_munged_dial(SAM_USER_HANDLE *user, char **munged_dial)
+NTSTATUS sam_{get,set}_user_lm_pwd(SAM_USER_HANDLE *user, DATA_BLOB *lm_pwd)
+NTSTATUS sam_{get,set}_user_nt_pwd(SAM_USER_HANDLE *user, DATA_BLOB *nt_pwd)
+NTSTATUS sam_{get,set}_user_plain_pwd(SAM_USER_HANDLE *user, DATA_BLOB *plaintext_pwd)
+NTSTATUS sam_{get,set}_user_acct_ctrl(SAM_USER_HANDLE *user, uint16 *acct_ctrl)
+NTSTATUS sam_{get,set}_user_logon_divs(SAM_USER_HANDLE *user, uint16 *logon_divs)
+NTSTATUS sam_{get,set}_user_hours(SAM_USER_HANDLE *user, uint32 *hours_len, uint8 **hours)
+NTSTATUS sam_{get,set}_user_logon_time(SAM_USER_HANDLE *user, NTTIME *logon_time)
+NTSTATUS sam_{get,set}_user_logoff_time(SAM_USER_HANDLE *user, NTTIME *logoff_time)
+NTSTATUS sam_{get,set}_user_kickoff_time(SAM_USER_HANDLE *user, NTTIME kickoff_time)
+NTSTATUS sam_{get,set}_user_pwd_last_set(SAM_USER_HANDLE *user, NTTIME pwd_last_set)
+NTSTATUS sam_{get,set}_user_pwd_can_change(SAM_USER_HANDLE *user, NTTIME pwd_can_change)
+NTSTATUS sam_{get,set}_user_pwd_must_change(SAM_USER_HANDLE *user, NTTIME pwd_must_change)
+NTSTATUS sam_{get,set}_user_unknown_1(SAM_USER_HANDLE *user, char **unknown_1)
+NTSTATUS sam_{get,set}_user_unknown_2(SAM_USER_HANDLE *user, uint32 *unknown_2)
+NTSTATUS sam_{get,set}_user_unknown_3(SAM_USER_HANDLE *user, uint32 *unknown_3)
+NTSTATUS sam_{get,set}_user_unknown_4(SAM_USER_HANDLE *user, uint32 *unknown_4)
+
+NTSTATUS sam_get_group_sid(SAM_GROUP_HANDLE *group, DOM_SID **sid)
+NTSTATUS sam_get_group_typ(SAM_GROUP_HANDLE *group, uint32 *typ)
+NTSTATUS sam_{get,set}_group_name(SAM_GROUP_HANDLE *group, char **group_name)
+NTSTATUS sam_{get,set}_group_comment(SAM_GROUP_HANDLE *group, char **comment)
+NTSTATUS sam_{get,set}_group_priv_set(SAM_GROUP_HANDLE *group, PRIVILEGE_SET *priv_set) \ No newline at end of file
diff --git a/source3/script/cvslog.pl b/source3/script/cvslog.pl
new file mode 100755
index 0000000000..f3d020aa72
--- /dev/null
+++ b/source3/script/cvslog.pl
@@ -0,0 +1,102 @@
+#!/usr/bin/perl -w
+
+my ( $tag, $filename, $date );
+my ( $tmp, $change_flag );
+
+if ( $#ARGV != 2 ) {
+
+ print "Usage: ", $0, " cvstag date file\n";
+ exit 1;
+}
+
+$tag = $ARGV[0];
+$date = $ARGV[1];
+$filename = $ARGV[2];
+
+print STDERR "$filename\n";
+
+open ( CVSLOG, "cvs log -d\"$date\" $filename |" ) || die $!;
+
+##
+## First get the branch revision number
+##
+undef $revision;
+while ( !defined($revision) ) {
+ if ( eof( \*CVSLOG ) ) {
+ print STDERR "Premature end of cvs log output!\n";
+ exit (1);
+ }
+
+ $string = <CVSLOG>;
+ chomp( $string );
+
+ if ( $string =~ /$tag:/ ) {
+ ( $tmp, $revision ) = split( /:/, $string );
+ $revision =~ s/\s+//g;
+ $revision =~ s/\.0\./\./g;
+ }
+}
+
+##
+## Setup the beginning of the first record
+##
+$string = "";
+while ( $string !~ /^-+/ ) {
+ $string = <CVSLOG>;
+ exit(0) if ( eof(\*CVSLOG) );
+}
+
+##
+## Loop starting at the revision number for the entry
+##
+
+while ( $string = <CVSLOG> ) {
+
+ ($tmp, $entry_rev) = split( /\s+/, $string );
+ if ( equal_revision( $revision, $entry_rev ) ) {
+ if ( ! defined($change_flag) ) {
+ print "++++++++++++++++++++++++++++++++++++++++++++++++++\n";
+ print "## $filename\n";
+ print "++\n";
+ $change_flag = 1;
+ }
+
+ while ( $string !~ /^-+/ && !eof(CVSLOG) ) {
+ print "$string";
+ $string = <CVSLOG>;
+ }
+ }
+ else {
+ while ( ($string !~ /^-+/) && !eof(CVSLOG) ) {
+ $string = <CVSLOG>;
+ }
+ }
+}
+
+close( CVSLOG );
+exit 0;
+
+##############################################################
+##
+sub equal_revision {
+ my ( $branch, $newfile ) = @_;
+ my ( $indx );
+ my ( @branch_rev, @file_rev );
+
+ @branch_rev = split( /\./, $branch );
+ @file_rev = split( /\./, $newfile );
+
+ return 0 if ( $#branch_rev != ($#file_rev - 1) );
+
+ $indx = 0;
+ while( $indx <= $#branch_rev ) {
+ if ( $branch_rev[$indx] != $file_rev[$indx] ) {
+ return 0;
+ }
+ $indx++;
+ }
+
+ return 1;
+}
+
+