diff options
author | cvs2svn Import User <samba-bugs@samba.org> | 2002-08-17 07:09:23 +0000 |
---|---|---|
committer | cvs2svn Import User <samba-bugs@samba.org> | 2002-08-17 07:09:23 +0000 |
commit | 592dd249579511f7ce863a42030d9a51ca026c27 (patch) | |
tree | 805985e633b375fd0a88a564a35c38410093a1dd /source3 | |
parent | 08663f11ed5bc05ff352bda74774d5e7045da1e5 (diff) | |
parent | 8690b271a6a4feb112e0a6c03fe99ee25f86430b (diff) | |
download | samba-592dd249579511f7ce863a42030d9a51ca026c27.tar.gz samba-592dd249579511f7ce863a42030d9a51ca026c27.tar.bz2 samba-592dd249579511f7ce863a42030d9a51ca026c27.zip |
This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to be commit 6938b5b98abd9ba055a46583a05c4fc07e32f529)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/adt_tree.h | 38 | ||||
-rw-r--r-- | source3/include/ntioctl.h | 26 | ||||
-rw-r--r-- | source3/lib/adt_tree.c | 464 | ||||
-rw-r--r-- | source3/lib/popt_common.c | 49 | ||||
-rw-r--r-- | source3/lib/system_smbd.c | 105 | ||||
-rw-r--r-- | source3/lib/util_smbd.c | 65 | ||||
-rw-r--r-- | source3/lib/util_uuid.c | 72 | ||||
-rw-r--r-- | source3/libsmb/namecache.c | 252 | ||||
-rw-r--r-- | source3/python/py_common_proto.h | 32 | ||||
-rw-r--r-- | source3/python/py_lsa.c | 462 | ||||
-rw-r--r-- | source3/python/py_smb.c | 224 | ||||
-rw-r--r-- | source3/python/py_smb.h | 42 | ||||
-rw-r--r-- | source3/registry/reg_cachehook.c | 112 | ||||
-rw-r--r-- | source3/registry/reg_db.c | 311 | ||||
-rw-r--r-- | source3/registry/reg_frontend.c | 575 | ||||
-rw-r--r-- | source3/registry/reg_printing.c | 814 | ||||
-rw-r--r-- | source3/rpc_client/cli_dfs.c | 245 | ||||
-rw-r--r-- | source3/rpc_client/cli_lsarpc.c | 1256 | ||||
-rw-r--r-- | source3/sam/SAM-interface_handles.txt | 123 | ||||
-rwxr-xr-x | source3/script/cvslog.pl | 102 |
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, ®db_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(®_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; +} + + |