diff options
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/editreg.c | 2056 | ||||
-rw-r--r-- | source3/utils/net.c | 23 | ||||
-rw-r--r-- | source3/utils/net_ads.c | 11 | ||||
-rw-r--r-- | source3/utils/net_help.c | 5 | ||||
-rw-r--r-- | source3/utils/net_rpc.c | 8 | ||||
-rw-r--r-- | source3/utils/net_rpc_samsync.c | 2 | ||||
-rw-r--r-- | source3/utils/nmblookup.c | 224 | ||||
-rw-r--r-- | source3/utils/ntlm_auth.c | 3 | ||||
-rw-r--r-- | source3/utils/pdbedit.c | 9 | ||||
-rw-r--r-- | source3/utils/profiles.c | 126 | ||||
-rw-r--r-- | source3/utils/smbcacls.c | 166 | ||||
-rw-r--r-- | source3/utils/smbcontrol.c | 1121 | ||||
-rw-r--r-- | source3/utils/smbtree.c | 191 | ||||
-rw-r--r-- | source3/utils/status.c | 6 | ||||
-rw-r--r-- | source3/utils/testparm.c | 17 |
15 files changed, 1059 insertions, 2909 deletions
diff --git a/source3/utils/editreg.c b/source3/utils/editreg.c deleted file mode 100644 index 6b3b4516bb..0000000000 --- a/source3/utils/editreg.c +++ /dev/null @@ -1,2056 +0,0 @@ -/* - Samba Unix/Linux SMB client utility editreg.c - Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com - Copyright (C) 2003 Jelmer Vernooij (conversion to popt) - - 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. */ - -/************************************************************************* - - A utility to edit a Windows NT/2K etc registry file. - - Many of the ideas in here come from other people and software. - I first looked in Wine in misc/registry.c and was also influenced by - http://www.wednesday.demon.co.uk/dosreg.html - - Which seems to contain comments from someone else. I reproduce them here - incase the site above disappears. It actually comes from - http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt. - - The goal here is to read the registry into memory, manipulate it, and then - write it out if it was changed by any actions of the user. - -The windows NT registry has 2 different blocks, where one can occur many -times... - -the "regf"-Block -================ - -"regf" is obviosly the abbreviation for "Registry file". "regf" is the -signature of the header-block which is always 4kb in size, although only -the first 64 bytes seem to be used and a checksum is calculated over -the first 0x200 bytes only! - -Offset Size Contents -0x00000000 D-Word ID: ASCII-"regf" = 0x66676572 -0x00000004 D-Word ???? //see struct REGF -0x00000008 D-Word ???? Always the same value as at 0x00000004 -0x0000000C Q-Word last modify date in WinNT date-format -0x00000014 D-Word 1 -0x00000018 D-Word 3 -0x0000001C D-Word 0 -0x00000020 D-Word 1 -0x00000024 D-Word Offset of 1st key record -0x00000028 D-Word Size of the data-blocks (Filesize-4kb) -0x0000002C D-Word 1 -0x000001FC D-Word Sum of all D-Words from 0x00000000 to -0x000001FB //XOR of all words. Nigel - -I have analyzed more registry files (from multiple machines running -NT 4.0 german version) and could not find an explanation for the values -marked with ???? the rest of the first 4kb page is not important... - -the "hbin"-Block -================ -I don't know what "hbin" stands for, but this block is always a multiple -of 4kb in size. - -Inside these hbin-blocks the different records are placed. The memory- -management looks like a C-compiler heap management to me... - -hbin-Header -=========== -Offset Size Contents -0x0000 D-Word ID: ASCII-"hbin" = 0x6E696268 -0x0004 D-Word Offset from the 1st hbin-Block -0x0008 D-Word Offset to the next hbin-Block -0x001C D-Word Block-size - -The values in 0x0008 and 0x001C should be the same, so I don't know -if they are correct or swapped... - -From offset 0x0020 inside a hbin-block data is stored with the following -format: - -Offset Size Contents -0x0000 D-Word Data-block size //this size must be a -multiple of 8. Nigel -0x0004 ???? Data - -If the size field is negative (bit 31 set), the corresponding block -is free and has a size of -blocksize! - -That does not seem to be true. All block lengths seem to be negative! (Richard Sharpe) - -The data is stored as one record per block. Block size is a multiple -of 4 and the last block reaches the next hbin-block, leaving no room. - -Records in the hbin-blocks -========================== - -nk-Record - - The nk-record can be treated as a kombination of tree-record and - key-record of the win 95 registry. - -lf-Record - - The lf-record is the counterpart to the RGKN-record (the - hash-function) - -vk-Record - - The vk-record consists information to a single value. - -sk-Record - - sk (? Security Key ?) is the ACL of the registry. - -Value-Lists - - The value-lists contain information about which values are inside a - sub-key and don't have a header. - -Datas - - The datas of the registry are (like the value-list) stored without a - header. - -All offset-values are relative to the first hbin-block and point to the -block-size field of the record-entry. to get the file offset, you have to add -the header size (4kb) and the size field (4 bytes)... - -the nk-Record -============= -Offset Size Contents -0x0000 Word ID: ASCII-"nk" = 0x6B6E -0x0002 Word for the root-key: 0x2C, otherwise 0x20 //key symbolic links 0x10. Nigel -0x0004 Q-Word write-date/time in windows nt notation -0x0010 D-Word Offset of Owner/Parent key -0x0014 D-Word number of sub-Keys -0x001C D-Word Offset of the sub-key lf-Records -0x0024 D-Word number of values -0x0028 D-Word Offset of the Value-List -0x002C D-Word Offset of the sk-Record - -0x0030 D-Word Offset of the Class-Name //see NK structure for the use of these fields. Nigel -0x0044 D-Word Unused (data-trash) //some kind of run time index. Does not appear to be important. Nigel -0x0048 Word name-length -0x004A Word class-name length -0x004C ???? key-name - -the Value-List -============== -Offset Size Contents -0x0000 D-Word Offset 1st Value -0x0004 D-Word Offset 2nd Value -0x???? D-Word Offset nth Value - -To determine the number of values, you have to look at the owner-nk-record! - -Der vk-Record -============= -Offset Size Contents -0x0000 Word ID: ASCII-"vk" = 0x6B76 -0x0002 Word name length -0x0004 D-Word length of the data //if top bit is set when offset contains data. Nigel -0x0008 D-Word Offset of Data -0x000C D-Word Type of value -0x0010 Word Flag -0x0012 Word Unused (data-trash) -0x0014 ???? Name - -If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default) - -If the data-size is lower 5, the data-offset value is used to store the data itself! - -The data-types -============== -Wert Beteutung -0x0001 RegSZ: character string (in UNICODE!) -0x0002 ExpandSZ: string with "%var%" expanding (UNICODE!) -0x0003 RegBin: raw-binary value -0x0004 RegDWord: Dword -0x0007 RegMultiSZ: multiple strings, seperated with 0 - (UNICODE!) - -The "lf"-record -=============== -Offset Size Contents -0x0000 Word ID: ASCII-"lf" = 0x666C -0x0002 Word number of keys -0x0004 ???? Hash-Records - -Hash-Record -=========== -Offset Size Contents -0x0000 D-Word Offset of corresponding "nk"-Record -0x0004 D-Word ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv! - -Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the -key-name you have to change the hash-value too! - -//These hashrecords must be sorted low to high within the lf record. Nigel. - -The "sk"-block -============== -(due to the complexity of the SAM-info, not clear jet) -(This is just a security descriptor in the data. R Sharpe.) - - -Offset Size Contents -0x0000 Word ID: ASCII-"sk" = 0x6B73 -0x0002 Word Unused -0x0004 D-Word Offset of previous "sk"-Record -0x0008 D-Word Offset of next "sk"-Record -0x000C D-Word usage-counter -0x0010 D-Word Size of "sk"-record in bytes -???? //standard self -relative security desciptor. Nigel -???? ???? Security and auditing settings... -???? - -The usage counter counts the number of references to this -"sk"-record. You can use one "sk"-record for the entire registry! - -Windows nt date/time format -=========================== -The time-format is a 64-bit integer which is incremented every -0,0000001 seconds by 1 (I don't know how accurate it realy is!) -It starts with 0 at the 1st of january 1601 0:00! All values are -stored in GMT time! The time-zone is important to get the real -time! - -Common values for win95 and win-nt -================================== -Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF). -If a value has no name (length=0, flag(bit 0)=0), it is treated as the -"Default" entry... -If a value has no data (length=0), it is displayed as empty. - -simplyfied win-3.?? registry: -============================= - -+-----------+ -| next rec. |---+ +----->+------------+ -| first sub | | | | Usage cnt. | -| name | | +-->+------------+ | | length | -| value | | | | next rec. | | | text |------->+-------+ -+-----------+ | | | name rec. |--+ +------------+ | xxxxx | - +------------+ | | value rec. |-------->+------------+ +-------+ - v | +------------+ | Usage cnt. | -+-----------+ | | length | -| next rec. | | | text |------->+-------+ -| first sub |------+ +------------+ | xxxxx | -| name | +-------+ -| value | -+-----------+ - -Greatly simplyfied structure of the nt-registry: -================================================ - -+---------------------------------------------------------------+ -| | -v | -+---------+ +---------->+-----------+ +----->+---------+ | -| "nk" | | | lf-rec. | | | nk-rec. | | -| ID | | | # of keys | | | parent |---+ -| Date | | | 1st key |--+ | .... | -| parent | | +-----------+ +---------+ -| suk-keys|-----+ -| values |--------------------->+----------+ -| SK-rec. |---------------+ | 1. value |--> +----------+ -| class |--+ | +----------+ | vk-rec. | -+---------+ | | | .... | - v | | data |--> +-------+ - +------------+ | +----------+ | xxxxx | - | Class name | | +-------+ - +------------+ | - v - +---------+ +---------+ - +----->| next sk |--->| Next sk |--+ - | +---| prev sk |<---| prev sk | | - | | | .... | | ... | | - | | +---------+ +---------+ | - | | ^ | - | | | | - | +--------------------+ | - +----------------------------------+ - ---------------------------------------------------------------------------- - -Hope this helps.... (Although it was "fun" for me to uncover this things, - it took me several sleepless nights ;) - - B.D. - -*************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <sys/mman.h> -#include <string.h> -#include <fcntl.h> -#include "popt.h" - -static int verbose = 0; - -/* - * These definitions are for the in-memory registry structure. - * It is a tree structure that mimics what you see with tools like regedit - */ - -/* - * DateTime struct for Windows - */ - -typedef struct date_time_s { - unsigned int low, high; -} NTTIME; - -/* - * Definition of a Key. It has a name, classname, date/time last modified, - * sub-keys, values, and a security descriptor - */ - -#define REG_ROOT_KEY 1 -#define REG_SUB_KEY 2 -#define REG_SYM_LINK 3 - -typedef struct reg_key_s { - char *name; /* Name of the key */ - char *class_name; - int type; /* One of REG_ROOT_KEY or REG_SUB_KEY */ - NTTIME last_mod; /* Time last modified */ - struct reg_key_s *owner; - struct key_list_s *sub_keys; - struct val_list_s *values; - struct key_sec_desc_s *security; -} REG_KEY; - -/* - * The KEY_LIST struct lists sub-keys. - */ - -typedef struct key_list_s { - int key_count; - REG_KEY *keys[1]; -} KEY_LIST; - -typedef struct val_key_s { - char *name; - int has_name; - int data_type; - int data_len; - void *data_blk; /* Might want a separate block */ -} VAL_KEY; - -typedef struct val_list_s { - int val_count; - VAL_KEY *vals[1]; -} VAL_LIST; - -#ifndef MAXSUBAUTHS -#define MAXSUBAUTHS 15 -#endif - -typedef struct dom_sid_s { - unsigned char ver, auths; - unsigned char auth[6]; - unsigned int sub_auths[MAXSUBAUTHS]; -} DOM_SID; - -typedef struct ace_struct_s { - unsigned char type, flags; - unsigned int perms; /* Perhaps a better def is in order */ - DOM_SID *trustee; -} ACE; - -typedef struct acl_struct_s { - unsigned short rev, refcnt; - unsigned short num_aces; - ACE *aces[1]; -} ACL; - -typedef struct sec_desc_s { - unsigned int rev, type; - DOM_SID *owner, *group; - ACL *sacl, *dacl; -} SEC_DESC; - -#define SEC_DESC_NON 0 -#define SEC_DESC_RES 1 -#define SEC_DESC_OCU 2 - -typedef struct key_sec_desc_s { - struct key_sec_desc_s *prev, *next; - int ref_cnt; - int state; - SEC_DESC *sec_desc; -} KEY_SEC_DESC; - - -/* - * An API for accessing/creating/destroying items above - */ - -/* - * Iterate over the keys, depth first, calling a function for each key - * and indicating if it is terminal or non-terminal and if it has values. - * - * In addition, for each value in the list, call a value list function - */ - -/* - * There should eventually be one to deal with security keys as well - */ - -typedef int (*key_print_f)(const char *path, char *key_name, char *class_name, - int root, int terminal, int values); - -typedef int (*val_print_f)(const char *path, char *val_name, int val_type, - int data_len, void *data_blk, int terminal, - int first, int last); - -typedef int (*sec_print_f)(SEC_DESC *sec_desc); - -typedef struct regf_struct_s REGF; - -int nt_key_iterator(REGF *regf, REG_KEY *key_tree, int bf, const char *path, - key_print_f key_print, sec_print_f sec_print, - val_print_f val_print); - -int nt_val_list_iterator(REGF *regf, VAL_LIST *val_list, int bf, char *path, - int terminal, val_print_f val_print) -{ - int i; - - if (!val_list) return 1; - - if (!val_print) return 1; - - for (i=0; i<val_list->val_count; i++) { - if (!val_print(path, val_list->vals[i]->name, val_list->vals[i]->data_type, - val_list->vals[i]->data_len, val_list->vals[i]->data_blk, - terminal, - (i == 0), - (i == val_list->val_count))) { - - return 0; - - } - } - - return 1; -} - -int nt_key_list_iterator(REGF *regf, KEY_LIST *key_list, int bf, - const char *path, - key_print_f key_print, sec_print_f sec_print, - val_print_f val_print) -{ - int i; - - if (!key_list) return 1; - - for (i=0; i< key_list->key_count; i++) { - if (!nt_key_iterator(regf, key_list->keys[i], bf, path, key_print, - sec_print, val_print)) { - return 0; - } - } - return 1; -} - -int nt_key_iterator(REGF *regf, REG_KEY *key_tree, int bf, const char *path, - key_print_f key_print, sec_print_f sec_print, - val_print_f val_print) -{ - int path_len = strlen(path); - char *new_path; - - if (!regf || !key_tree) - return -1; - - /* List the key first, then the values, then the sub-keys */ - - if (key_print) { - - if (!(*key_print)(path, key_tree->name, - key_tree->class_name, - (key_tree->type == REG_ROOT_KEY), - (key_tree->sub_keys == NULL), - (key_tree->values?(key_tree->values->val_count):0))) - return 0; - } - - /* - * If we have a security print routine, call it - * If the security print routine returns false, stop. - */ - if (sec_print) { - if (key_tree->security && !(*sec_print)(key_tree->security->sec_desc)) - return 0; - } - - new_path = (char *)malloc(path_len + 1 + strlen(key_tree->name) + 1); - if (!new_path) return 0; /* Errors? */ - new_path[0] = '\0'; - strcat(new_path, path); - strcat(new_path, "\\"); - strcat(new_path, key_tree->name); - - /* - * Now, iterate through the values in the val_list - */ - - if (key_tree->values && - !nt_val_list_iterator(regf, key_tree->values, bf, new_path, - (key_tree->values!=NULL), - val_print)) { - - free(new_path); - return 0; - } - - /* - * Now, iterate through the keys in the key list - */ - - if (key_tree->sub_keys && - !nt_key_list_iterator(regf, key_tree->sub_keys, bf, new_path, key_print, - sec_print, val_print)) { - free(new_path); - return 0; - } - - free(new_path); - return 1; -} - -/* Make, delete keys */ - -int nt_delete_val_key(VAL_KEY *val_key) -{ - - if (val_key) { - if (val_key->data_blk) free(val_key->data_blk); - free(val_key); - }; - return 1; -} - -int nt_delete_val_list(VAL_LIST *vl) -{ - int i; - - if (vl) { - for (i=0; i<vl->val_count; i++) - nt_delete_val_key(vl->vals[i]); - free(vl); - } - return 1; -} - -int nt_delete_reg_key(REG_KEY *key); -int nt_delete_key_list(KEY_LIST *key_list) -{ - int i; - - if (key_list) { - for (i=0; i<key_list->key_count; i++) - nt_delete_reg_key(key_list->keys[i]); - free(key_list); - } - return 1; -} - -int nt_delete_sid(DOM_SID *sid) -{ - - if (sid) free(sid); - return 1; - -} - -int nt_delete_ace(ACE *ace) -{ - - if (ace) { - nt_delete_sid(ace->trustee); - free(ace); - } - return 1; - -} - -int nt_delete_acl(ACL *acl) -{ - - if (acl) { - int i; - - for (i=0; i<acl->num_aces; i++) - nt_delete_ace(acl->aces[i]); - - free(acl); - } - return 1; -} - -int nt_delete_sec_desc(SEC_DESC *sec_desc) -{ - - if (sec_desc) { - - nt_delete_sid(sec_desc->owner); - nt_delete_sid(sec_desc->group); - nt_delete_acl(sec_desc->sacl); - nt_delete_acl(sec_desc->dacl); - free(sec_desc); - - } - return 1; -} - -int nt_delete_key_sec_desc(KEY_SEC_DESC *key_sec_desc) -{ - - if (key_sec_desc) { - key_sec_desc->ref_cnt--; - if (key_sec_desc->ref_cnt<=0) { - /* - * There should always be a next and prev, even if they point to us - */ - key_sec_desc->next->prev = key_sec_desc->prev; - key_sec_desc->prev->next = key_sec_desc->next; - nt_delete_sec_desc(key_sec_desc->sec_desc); - } - } - return 1; -} - -int nt_delete_reg_key(REG_KEY *key) -{ - - if (key) { - if (key->name) free(key->name); - if (key->class_name) free(key->class_name); - - /* - * Do not delete the owner ... - */ - - if (key->sub_keys) nt_delete_key_list(key->sub_keys); - if (key->values) nt_delete_val_list(key->values); - if (key->security) nt_delete_key_sec_desc(key->security); - free(key); - } - return 1; -} - -/* - * Create/delete key lists and add delete keys to/from a list, count the keys - */ - - -/* - * Create/delete value lists, add/delete values, count them - */ - - -/* - * Create/delete security descriptors, add/delete SIDS, count SIDS, etc. - * We reference count the security descriptors. Any new reference increments - * the ref count. If we modify an SD, we copy the old one, dec the ref count - * and make the change. We also want to be able to check for equality so - * we can reduce the number of SDs in use. - */ - -/* - * Code to parse registry specification from command line or files - * - * Format: - * [cmd:]key:type:value - * - * cmd = a|d|c|add|delete|change|as|ds|cs - * - */ - - -/* - * Load and unload a registry file. - * - * Load, loads it into memory as a tree, while unload sealizes/flattens it - */ - -/* - * Get the starting record for NT Registry file - */ - -/* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */ -typedef struct sk_map_s { - int sk_off; - KEY_SEC_DESC *key_sec_desc; -} SK_MAP; - -/* - * Where we keep all the regf stuff for one registry. - * This is the structure that we use to tie the in memory tree etc - * together. By keeping separate structs, we can operate on different - * registries at the same time. - * Currently, the SK_MAP is an array of mapping structure. - * Since we only need this on input and output, we fill in the structure - * as we go on input. On output, we know how many SK items we have, so - * we can allocate the structure as we need to. - * If you add stuff here that is dynamically allocated, add the - * appropriate free statements below. - */ - -#define REGF_REGTYPE_NONE 0 -#define REGF_REGTYPE_NT 1 -#define REGF_REGTYPE_W9X 2 - -#define TTTONTTIME(r, t1, t2) (r)->last_mod_time.low = (t1); \ - (r)->last_mod_time.high = (t2); - -#define REGF_HDR_BLKSIZ 0x1000 - -struct regf_struct_s { - int reg_type; - char *regfile_name, *outfile_name; - int fd; - struct stat sbuf; - char *base; - int modified; - NTTIME last_mod_time; - REG_KEY *root; /* Root of the tree for this file */ - int sk_count, sk_map_size; - SK_MAP *sk_map; -}; - -/* - * Structures for dealing with the on-disk format of the registry - */ - -#define IVAL(buf) ((unsigned int) \ - (unsigned int)*((unsigned char *)(buf)+3)<<24| \ - (unsigned int)*((unsigned char *)(buf)+2)<<16| \ - (unsigned int)*((unsigned char *)(buf)+1)<<8| \ - (unsigned int)*((unsigned char *)(buf)+0)) - -#define SVAL(buf) ((unsigned short) \ - (unsigned short)*((unsigned char *)(buf)+1)<<8| \ - (unsigned short)*((unsigned char *)(buf)+0)) - -#define CVAL(buf) ((unsigned char)*((unsigned char *)(buf))) - -#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4) -#define LOCN(base, f) ((base) + OFF(f)) - -/* - * All of the structures below actually have a four-byte lenght before them - * which always seems to be negative. The following macro retrieves that - * size as an integer - */ - -#define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1)) - -typedef unsigned int DWORD; -typedef unsigned short WORD; - -#define REG_REGF_ID 0x66676572 - -typedef struct regf_block { - DWORD REGF_ID; /* regf */ - DWORD uk1; - DWORD uk2; - DWORD tim1, tim2; - DWORD uk3; /* 1 */ - DWORD uk4; /* 3 */ - DWORD uk5; /* 0 */ - DWORD uk6; /* 1 */ - DWORD first_key; /* offset */ - unsigned int dblk_size; - DWORD uk7[116]; /* 1 */ - DWORD chksum; -} REGF_HDR; - -typedef struct hbin_sub_struct { - DWORD dblocksize; - char data[1]; -} HBIN_SUB_HDR; - -#define REG_HBIN_ID 0x6E696268 - -typedef struct hbin_struct { - DWORD HBIN_ID; /* hbin */ - DWORD next_off; - DWORD prev_off; - DWORD uk1; - DWORD uk2; - DWORD uk3; - DWORD uk4; - DWORD blk_size; - HBIN_SUB_HDR hbin_sub_hdr; -} HBIN_HDR; - -#define REG_NK_ID 0x6B6E - -typedef struct nk_struct { - WORD NK_ID; - WORD type; - DWORD t1, t2; - DWORD uk1; - DWORD own_off; - DWORD subk_num; - DWORD uk2; - DWORD lf_off; - DWORD uk3; - DWORD val_cnt; - DWORD val_off; - DWORD sk_off; - DWORD clsnam_off; - DWORD unk4[4]; - DWORD unk5; - WORD nam_len; - WORD clsnam_len; - char key_nam[1]; /* Actual length determined by nam_len */ -} NK_HDR; - -#define REG_SK_ID 0x6B73 - -typedef struct sk_struct { - WORD SK_ID; - WORD uk1; - DWORD prev_off; - DWORD next_off; - DWORD ref_cnt; - DWORD rec_size; - char sec_desc[1]; -} SK_HDR; - -typedef struct ace_struct { - unsigned char type; - unsigned char flags; - unsigned short length; - unsigned int perms; - DOM_SID trustee; -} REG_ACE; - -typedef struct acl_struct { - WORD rev; - WORD size; - DWORD num_aces; - REG_ACE *aces; /* One or more ACEs */ -} REG_ACL; - -typedef struct sec_desc_rec { - WORD rev; - WORD type; - DWORD owner_off; - DWORD group_off; - DWORD sacl_off; - DWORD dacl_off; -} REG_SEC_DESC; - -typedef struct hash_struct { - DWORD nk_off; - char hash[4]; -} HASH_REC; - -#define REG_LF_ID 0x666C - -typedef struct lf_struct { - WORD LF_ID; - WORD key_count; - struct hash_struct hr[1]; /* Array of hash records, depending on key_count */ -} LF_HDR; - -typedef DWORD VL_TYPE[1]; /* Value list is an array of vk rec offsets */ - -#define REG_VK_ID 0x6B76 - -typedef struct vk_struct { - WORD VK_ID; - WORD nam_len; - DWORD dat_len; /* If top-bit set, offset contains the data */ - DWORD dat_off; - DWORD dat_type; - WORD flag; /* =1, has name, else no name (=Default). */ - WORD unk1; - char dat_name[1]; /* Name starts here ... */ -} VK_HDR; - -#define REG_TYPE_REGSZ 1 -#define REG_TYPE_EXPANDSZ 2 -#define REG_TYPE_BIN 3 -#define REG_TYPE_DWORD 4 -#define REG_TYPE_MULTISZ 7 - -typedef struct _val_str { - unsigned int val; - const char * str; -} VAL_STR; - -const VAL_STR reg_type_names[] = { - { 1, "REG_SZ" }, - { 2, "REG_EXPAND_SZ" }, - { 3, "REG_BIN" }, - { 4, "REG_DWORD" }, - { 7, "REG_MULTI_SZ" }, - { 0, NULL }, -}; - -const char *val_to_str(unsigned int val, const VAL_STR *val_array) -{ - int i = 0; - - if (!val_array) return NULL; - - while (val_array[i].val && val_array[i].str) { - - if (val_array[i].val == val) return val_array[i].str; - i++; - - } - - return NULL; - -} - -/* - * Convert from UniCode to Ascii ... Does not take into account other lang - * Restrict by ascii_max if > 0 - */ -int uni_to_ascii(unsigned char *uni, unsigned char *ascii, int ascii_max, - int uni_max) -{ - int i = 0; - - while (i < ascii_max && !(!uni[i*2] && !uni[i*2+1])) { - if (uni_max > 0 && (i*2) >= uni_max) break; - ascii[i] = uni[i*2]; - i++; - - } - - ascii[i] = '\0'; - - return i; -} - -/* - * Convert a data value to a string for display - */ -int data_to_ascii(unsigned char *datap, int len, int type, char *ascii, int ascii_max) -{ - unsigned char *asciip; - int i; - - switch (type) { - case REG_TYPE_REGSZ: - fprintf(stderr, "Len: %d\n", len); - return uni_to_ascii(datap, ascii, len, ascii_max); - break; - - case REG_TYPE_EXPANDSZ: - return uni_to_ascii(datap, ascii, len, ascii_max); - break; - - case REG_TYPE_BIN: - asciip = ascii; - for (i=0; (i<len)&&(i+1)*3<ascii_max; i++) { - int str_rem = ascii_max - ((int)asciip - (int)ascii); - asciip += snprintf(asciip, str_rem, "%02x", *(unsigned char *)(datap+i)); - if (i < len && str_rem > 0) - *asciip = ' '; asciip++; - } - *asciip = '\0'; - return ((int)asciip - (int)ascii); - break; - - case REG_TYPE_DWORD: - if (*(int *)datap == 0) - return snprintf(ascii, ascii_max, "0"); - else - return snprintf(ascii, ascii_max, "0x%x", *(int *)datap); - break; - - case REG_TYPE_MULTISZ: - - break; - - default: - return 0; - break; - } - - return len; - -} - -REG_KEY *nt_get_key_tree(REGF *regf, NK_HDR *nk_hdr, int size); - -int nt_set_regf_input_file(REGF *regf, char *filename) -{ - return ((regf->regfile_name = strdup(filename)) != NULL); -} - -int nt_set_regf_output_file(REGF *regf, char *filename) -{ - return ((regf->outfile_name = strdup(filename)) != NULL); -} - -/* Create a regf structure and init it */ - -REGF *nt_create_regf(void) -{ - REGF *tmp = (REGF *)malloc(sizeof(REGF)); - if (!tmp) return tmp; - bzero(tmp, sizeof(REGF)); - return tmp; -} - -/* Free all the bits and pieces ... Assumes regf was malloc'd */ -/* If you add stuff to REGF, add the relevant free bits here */ -int nt_free_regf(REGF *regf) -{ - if (!regf) return 0; - - if (regf->regfile_name) free(regf->regfile_name); - if (regf->outfile_name) free(regf->outfile_name); - - /* Free the mmap'd area */ - - if (regf->base) munmap(regf->base, regf->sbuf.st_size); - regf->base = NULL; - close(regf->fd); /* Ignore the error :-) */ - - nt_delete_reg_key(regf->root); /* Free the tree */ - free(regf->sk_map); - regf->sk_count = regf->sk_map_size = 0; - - free(regf); - - return 1; -} - -/* Get the header of the registry. Return a pointer to the structure - * If the mmap'd area has not been allocated, then mmap the input file - */ -REGF_HDR *nt_get_regf_hdr(REGF *regf) -{ - if (!regf) - return NULL; /* What about errors */ - - if (!regf->regfile_name) - return NULL; /* What about errors */ - - if (!regf->base) { /* Try to mmap etc the file */ - - if ((regf->fd = open(regf->regfile_name, O_RDONLY, 0000)) <0) { - return NULL; /* What about errors? */ - } - - if (fstat(regf->fd, ®f->sbuf) < 0) { - return NULL; - } - - regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0); - - if ((int)regf->base == 1) { - fprintf(stderr, "Could not mmap file: %s, %s\n", regf->regfile_name, - strerror(errno)); - return NULL; - } - } - - /* - * At this point, regf->base != NULL, and we should be able to read the - * header - */ - - assert(regf->base != NULL); - - return (REGF_HDR *)regf->base; -} - -/* - * Validate a regf header - * For now, do nothing, but we should check the checksum - */ -int valid_regf_hdr(REGF_HDR *regf_hdr) -{ - if (!regf_hdr) return 0; - - return 1; -} - -/* - * Process an SK header ... - * Every time we see a new one, add it to the map. Otherwise, just look it up. - * We will do a simple linear search for the moment, since many KEYs have the - * same security descriptor. - * We allocate the map in increments of 10 entries. - */ - -/* - * Create a new entry in the map, and increase the size of the map if needed - */ - -SK_MAP *alloc_sk_map_entry(REGF *regf, KEY_SEC_DESC *tmp, int sk_off) -{ - if (!regf->sk_map) { /* Allocate a block of 10 */ - regf->sk_map = (SK_MAP *)malloc(sizeof(SK_MAP) * 10); - if (!regf->sk_map) { - free(tmp); - return NULL; - } - regf->sk_map_size = 10; - regf->sk_count = 1; - (regf->sk_map)[0].sk_off = sk_off; - (regf->sk_map)[0].key_sec_desc = tmp; - } - else { /* Simply allocate a new slot, unless we have to expand the list */ - int ndx = regf->sk_count; - if (regf->sk_count >= regf->sk_map_size) { - regf->sk_map = (SK_MAP *)realloc(regf->sk_map, - (regf->sk_map_size + 10)*sizeof(SK_MAP)); - if (!regf->sk_map) { - free(tmp); - return NULL; - } - /* - * ndx already points at the first entry of the new block - */ - regf->sk_map_size += 10; - } - (regf->sk_map)[ndx].sk_off = sk_off; - (regf->sk_map)[ndx].key_sec_desc = tmp; - regf->sk_count++; - } - return regf->sk_map; -} - -/* - * Search for a KEY_SEC_DESC in the sk_map, but dont create one if not - * found - */ - -KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off) -{ - int i; - - if (!sk_map) return NULL; - - for (i = 0; i < count; i++) { - - if (sk_map[i].sk_off == sk_off) - return sk_map[i].key_sec_desc; - - } - - return NULL; - -} - -/* - * Allocate a KEY_SEC_DESC if we can't find one in the map - */ - -KEY_SEC_DESC *lookup_create_sec_key(REGF *regf, SK_MAP *sk_map, int sk_off) -{ - KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off); - - if (tmp) { - return tmp; - } - else { /* Allocate a new one */ - tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC)); - if (!tmp) { - return NULL; - } - tmp->state = SEC_DESC_RES; - if (!alloc_sk_map_entry(regf, tmp, sk_off)) { - return NULL; - } - return tmp; - } -} - -/* - * Allocate storage and duplicate a SID - * We could allocate the SID to be only the size needed, but I am too lazy. - */ -DOM_SID *dup_sid(DOM_SID *sid) -{ - DOM_SID *tmp = (DOM_SID *)malloc(sizeof(DOM_SID)); - int i; - - if (!tmp) return NULL; - tmp->ver = sid->ver; - tmp->auths = sid->auths; - for (i=0; i<6; i++) { - tmp->auth[i] = sid->auth[i]; - } - for (i=0; i<tmp->auths&&i<MAXSUBAUTHS; i++) { - tmp->sub_auths[i] = sid->sub_auths[i]; - } - return tmp; -} - -/* - * Allocate space for an ACE and duplicate the registry encoded one passed in - */ -ACE *dup_ace(REG_ACE *ace) -{ - ACE *tmp = NULL; - - tmp = (ACE *)malloc(sizeof(ACE)); - - if (!tmp) return NULL; - - tmp->type = CVAL(&ace->type); - tmp->flags = CVAL(&ace->flags); - tmp->perms = IVAL(&ace->perms); - tmp->trustee = dup_sid(&ace->trustee); - return tmp; -} - -/* - * Allocate space for an ACL and duplicate the registry encoded one passed in - */ -ACL *dup_acl(REG_ACL *acl) -{ - ACL *tmp = NULL; - REG_ACE* ace; - int i, num_aces; - - num_aces = IVAL(&acl->num_aces); - - tmp = (ACL *)malloc(sizeof(ACL) + (num_aces - 1)*sizeof(ACE *)); - if (!tmp) return NULL; - - tmp->num_aces = num_aces; - tmp->refcnt = 1; - tmp->rev = SVAL(&acl->rev); - ace = (REG_ACE *)&acl->aces; - for (i=0; i<num_aces; i++) { - tmp->aces[i] = dup_ace(ace); - ace = (REG_ACE *)((char *)ace + SVAL(&ace->length)); - /* XXX: FIXME, should handle malloc errors */ - } - - return tmp; -} - -SEC_DESC *process_sec_desc(REGF *regf, REG_SEC_DESC *sec_desc) -{ - SEC_DESC *tmp = NULL; - - tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC)); - - if (!tmp) { - return NULL; - } - - tmp->rev = SVAL(&sec_desc->rev); - tmp->type = SVAL(&sec_desc->type); - tmp->owner = dup_sid((DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->owner_off))); - if (!tmp->owner) { - free(tmp); - return NULL; - } - tmp->group = dup_sid((DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->group_off))); - if (!tmp->group) { - free(tmp); - return NULL; - } - - /* Now pick up the SACL and DACL */ - - if (sec_desc->sacl_off) - tmp->sacl = dup_acl((REG_ACL *)((char *)sec_desc + IVAL(&sec_desc->sacl_off))); - else - tmp->sacl = NULL; - - if (sec_desc->dacl_off) - tmp->dacl = dup_acl((REG_ACL *)((char *)sec_desc + IVAL(&sec_desc->dacl_off))); - else - tmp->dacl = NULL; - - return tmp; -} - -KEY_SEC_DESC *process_sk(REGF *regf, SK_HDR *sk_hdr, int sk_off, int size) -{ - KEY_SEC_DESC *tmp = NULL; - int sk_next_off, sk_prev_off, sk_size; - REG_SEC_DESC *sec_desc; - - if (!sk_hdr) return NULL; - - if (SVAL(&sk_hdr->SK_ID) != REG_SK_ID) { - fprintf(stderr, "Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr, - regf->regfile_name); - return NULL; - } - - if (-size < (sk_size = IVAL(&sk_hdr->rec_size))) { - fprintf(stderr, "Incorrect SK record size: %d vs %d. %s\n", - -size, sk_size, regf->regfile_name); - return NULL; - } - - /* - * Now, we need to look up the SK Record in the map, and return it - * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can - * use that - */ - - if (regf->sk_map && - ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL) - && (tmp->state == SEC_DESC_OCU)) { - tmp->ref_cnt++; - return tmp; - } - - /* Here, we have an item in the map that has been reserved, or tmp==NULL. */ - - assert(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON)); - - /* - * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the - * new KEY_SEC_DESC to the mapping structure, since the offset supplied is - * the actual offset of structure. The same offset will be used by all - * all future references to this structure - * We chould put all this unpleasantness in a function. - */ - - if (!tmp) { - tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC)); - if (!tmp) return NULL; - bzero(tmp, sizeof(KEY_SEC_DESC)); - - /* - * Allocate an entry in the SK_MAP ... - * We don't need to free tmp, because that is done for us if the - * sm_map entry can't be expanded when we need more space in the map. - */ - - if (!alloc_sk_map_entry(regf, tmp, sk_off)) { - return NULL; - } - } - - tmp->ref_cnt++; - tmp->state = SEC_DESC_OCU; - - /* - * Now, process the actual sec desc and plug the values in - */ - - sec_desc = (REG_SEC_DESC *)&sk_hdr->sec_desc[0]; - tmp->sec_desc = process_sec_desc(regf, sec_desc); - - /* - * Now forward and back links. Here we allocate an entry in the sk_map - * if it does not exist, and mark it reserved - */ - - sk_prev_off = IVAL(&sk_hdr->prev_off); - tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off); - assert(tmp->prev != NULL); - sk_next_off = IVAL(&sk_hdr->next_off); - tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off); - assert(tmp->next != NULL); - - return tmp; -} - -/* - * Process a VK header and return a value - */ -VAL_KEY *process_vk(REGF *regf, VK_HDR *vk_hdr, int size) -{ - char val_name[1024]; - int nam_len, dat_len, flag, dat_type, dat_off, vk_id; - const char *val_type; - VAL_KEY *tmp = NULL; - - if (!vk_hdr) return NULL; - - if ((vk_id = SVAL(&vk_hdr->VK_ID)) != REG_VK_ID) { - fprintf(stderr, "Unrecognized VK header ID: %0X, block: %0X, %s\n", - vk_id, (int)vk_hdr, regf->regfile_name); - return NULL; - } - - nam_len = SVAL(&vk_hdr->nam_len); - val_name[nam_len] = '\0'; - flag = SVAL(&vk_hdr->flag); - dat_type = IVAL(&vk_hdr->dat_type); - dat_len = IVAL(&vk_hdr->dat_len); /* If top bit, offset contains data */ - dat_off = IVAL(&vk_hdr->dat_off); - - tmp = (VAL_KEY *)malloc(sizeof(VAL_KEY)); - if (!tmp) { - goto error; - } - bzero(tmp, sizeof(VAL_KEY)); - tmp->has_name = flag; - tmp->data_type = dat_type; - - if (flag & 0x01) { - strncpy(val_name, vk_hdr->dat_name, nam_len); - tmp->name = strdup(val_name); - if (!tmp->name) { - goto error; - } - } - else - strncpy(val_name, "<No Name>", 10); - - /* - * Allocate space and copy the data as a BLOB - */ - - if (dat_len) { - - char *dtmp = (char *)malloc(dat_len&0x7FFFFFFF); - - if (!dtmp) { - goto error; - } - - tmp->data_blk = dtmp; - - if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */ - char *dat_ptr = LOCN(regf->base, dat_off); - bcopy(dat_ptr, dtmp, dat_len); - } - else { /* The data is in the offset */ - dat_len = dat_len & 0x7FFFFFFF; - bcopy(&dat_off, dtmp, dat_len); - } - - tmp->data_len = dat_len; - } - - val_type = val_to_str(dat_type, reg_type_names); - - /* - * We need to save the data area as well - */ - - if (verbose) fprintf(stdout, " %s : %s : \n", val_name, val_type); - - return tmp; - - error: - /* XXX: FIXME, free the partially allocated struct */ - return NULL; - -} - -/* - * Process a VL Header and return a list of values - */ -VAL_LIST *process_vl(REGF *regf, VL_TYPE vl, int count, int size) -{ - int i, vk_off; - VK_HDR *vk_hdr; - VAL_LIST *tmp = NULL; - - if (!vl) return NULL; - - if (-size < (count+1)*sizeof(int)){ - fprintf(stderr, "Error in VL header format. Size less than space required. %d\n", -size); - return NULL; - } - - tmp = (VAL_LIST *)malloc(sizeof(VAL_LIST) + (count - 1) * sizeof(VAL_KEY *)); - if (!tmp) { - goto error; - } - - for (i=0; i<count; i++) { - vk_off = IVAL(&vl[i]); - vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off); - tmp->vals[i] = process_vk(regf, vk_hdr, BLK_SIZE(vk_hdr)); - if (!tmp->vals[i]){ - goto error; - } - } - - tmp->val_count = count; - - return tmp; - - error: - /* XXX: FIXME, free the partially allocated structure */ - return NULL; -} - -/* - * Process an LF Header and return a list of sub-keys - */ -KEY_LIST *process_lf(REGF *regf, LF_HDR *lf_hdr, int size) -{ - int count, i, nk_off; - unsigned int lf_id; - KEY_LIST *tmp; - - if (!lf_hdr) return NULL; - - if ((lf_id = SVAL(&lf_hdr->LF_ID)) != REG_LF_ID) { - fprintf(stderr, "Unrecognized LF Header format: %0X, Block: %0X, %s.\n", - lf_id, (int)lf_hdr, regf->regfile_name); - return NULL; - } - - assert(size < 0); - - count = SVAL(&lf_hdr->key_count); - - if (count <= 0) return NULL; - - /* Now, we should allocate a KEY_LIST struct and fill it in ... */ - - tmp = (KEY_LIST *)malloc(sizeof(KEY_LIST) + (count - 1) * sizeof(REG_KEY *)); - if (!tmp) { - goto error; - } - - tmp->key_count = count; - - for (i=0; i<count; i++) { - NK_HDR *nk_hdr; - - nk_off = IVAL(&lf_hdr->hr[i].nk_off); - nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off); - tmp->keys[i] = nt_get_key_tree(regf, nk_hdr, BLK_SIZE(nk_hdr)); - if (!tmp->keys[i]) { - goto error; - } - } - - return tmp; - - error: - /* XXX: FIXME, free the partially allocated structure */ - return NULL; -} - -/* - * This routine is passed a NK_HDR pointer and retrieves the entire tree - * from there down. It return a REG_KEY *. - */ -REG_KEY *nt_get_key_tree(REGF *regf, NK_HDR *nk_hdr, int size) -{ - REG_KEY *tmp = NULL; - int name_len, clsname_len, lf_off, val_off, val_count, sk_off; - unsigned int nk_id; - LF_HDR *lf_hdr; - VL_TYPE *vl; - SK_HDR *sk_hdr; - char key_name[1024], cls_name[1024]; - - if (!nk_hdr) return NULL; - - if ((nk_id = SVAL(&nk_hdr->NK_ID)) != REG_NK_ID) { - fprintf(stderr, "Unrecognized NK Header format: %08X, Block: %0X. %s\n", - nk_id, (int)nk_hdr, regf->regfile_name); - return NULL; - } - - assert(size < 0); - - name_len = SVAL(&nk_hdr->nam_len); - clsname_len = SVAL(&nk_hdr->clsnam_len); - - /* - * The value of -size should be ge - * (sizeof(NK_HDR) - 1 + name_len) - * The -1 accounts for the fact that we included the first byte of - * the name in the structure. clsname_len is the length of the thing - * pointed to by clsnam_off - */ - - if (-size < (sizeof(NK_HDR) - 1 + name_len)) { - fprintf(stderr, "Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr); - fprintf(stderr, "Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n", - sizeof(NK_HDR), name_len, clsname_len); - /*return NULL;*/ - } - - if (verbose) fprintf(stdout, "NK HDR: Name len: %d, class name len: %d\n", - name_len, clsname_len); - - /* Fish out the key name and process the LF list */ - - assert(name_len < sizeof(key_name)); - - /* Allocate the key struct now */ - tmp = (REG_KEY *)malloc(sizeof(REG_KEY)); - if (!tmp) return tmp; - bzero(tmp, sizeof(REG_KEY)); - - tmp->type = (SVAL(&nk_hdr->type)==0x2C?REG_ROOT_KEY:REG_SUB_KEY); - - strncpy(key_name, nk_hdr->key_nam, name_len); - key_name[name_len] = '\0'; - - if (verbose) fprintf(stdout, "Key name: %s\n", key_name); - - tmp->name = strdup(key_name); - if (!tmp->name) { - goto error; - } - - /* - * Fish out the class name, it is in UNICODE, while the key name is - * ASCII :-) - */ - - if (clsname_len) { /* Just print in Ascii for now */ - char *clsnamep; - int clsnam_off; - - clsnam_off = IVAL(&nk_hdr->clsnam_off); - clsnamep = LOCN(regf->base, clsnam_off); - - bzero(cls_name, clsname_len); - uni_to_ascii(clsnamep, cls_name, sizeof(cls_name), clsname_len); - - /* - * I am keeping class name as an ascii string for the moment. - * That means it needs to be converted on output. - * XXX: FIXME - */ - - tmp->class_name = strdup(cls_name); - if (!tmp->class_name) { - goto error; - } - - if (verbose) fprintf(stdout, " Class Name: %s\n", cls_name); - - } - - /* - * If there are any values, process them here - */ - - val_count = IVAL(&nk_hdr->val_cnt); - - if (val_count) { - - val_off = IVAL(&nk_hdr->val_off); - vl = (VL_TYPE *)LOCN(regf->base, val_off); - - tmp->values = process_vl(regf, *vl, val_count, BLK_SIZE(vl)); - if (!tmp->values) { - goto error; - } - - } - - /* - * Also handle the SK header ... - */ - - sk_off = IVAL(&nk_hdr->sk_off); - sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off); - - if (sk_off != -1) { - - tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr)); - - } - - lf_off = IVAL(&nk_hdr->lf_off); - - /* - * No more subkeys if lf_off == -1 - */ - - if (lf_off != -1) { - - lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); - - tmp->sub_keys = process_lf(regf, lf_hdr, BLK_SIZE(lf_hdr)); - if (!tmp->sub_keys){ - goto error; - } - - } - - return tmp; - - error: - if (tmp) nt_delete_reg_key(tmp); - return NULL; -} - -int nt_load_registry(REGF *regf) -{ - REGF_HDR *regf_hdr; - unsigned int regf_id, hbin_id; - HBIN_HDR *hbin_hdr; - NK_HDR *first_key; - - /* Get the header */ - - if ((regf_hdr = nt_get_regf_hdr(regf)) == NULL) { - return -1; - } - - /* Now process that header and start to read the rest in */ - - if ((regf_id = IVAL(®f_hdr->REGF_ID)) != REG_REGF_ID) { - fprintf(stderr, "Unrecognized NT registry header id: %0X, %s\n", - regf_id, regf->regfile_name); - return -1; - } - - /* - * Validate the header ... - */ - if (!valid_regf_hdr(regf_hdr)) { - fprintf(stderr, "Registry file header does not validate: %s\n", - regf->regfile_name); - return -1; - } - - /* Update the last mod date, and then go get the first NK record and on */ - - TTTONTTIME(regf, IVAL(®f_hdr->tim1), IVAL(®f_hdr->tim2)); - - /* - * The hbin hdr seems to be just uninteresting garbage. Check that - * it is there, but that is all. - */ - - hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ); - - if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID)) != REG_HBIN_ID) { - fprintf(stderr, "Unrecognized registry hbin hdr ID: %0X, %s\n", - hbin_id, regf->regfile_name); - return -1; - } - - /* - * Get a pointer to the first key from the hreg_hdr - */ - - first_key = (NK_HDR *)LOCN(regf->base, IVAL(®f_hdr->first_key)); - - /* - * Now, get the registry tree by processing that NK recursively - */ - - regf->root = nt_get_key_tree(regf, first_key, BLK_SIZE(first_key)); - - assert(regf->root != NULL); - - return 1; -} - -/* - * Routines to parse a REGEDIT4 file - * - * The file consists of: - * - * REGEDIT4 - * \[[-]key-path\]\n - * <value-spec>* - * - * There can be more than one key-path and value-spec. - * - * Since we want to support more than one type of file format, we - * construct a command-file structure that keeps info about the command file - */ - -#define FMT_UNREC -1 -#define FMT_REGEDIT4 0 -#define FMT_EDITREG1_1 1 - -typedef struct command_s { - int cmd; - char *key; - void *val_spec_list; -} CMD; - -/* - * We seek to offset 0, read in the required number of bytes, - * and compare to the correct value. - * We then seek back to the original location - */ -int regedit4_file_type(int fd) -{ - int cur_ofs = 0; - - cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */ - if (cur_ofs < 0) { - fprintf(stderr, "Unable to get current offset: %s\n", strerror(errno)); - exit(1); - } - - if (cur_ofs) { - lseek(fd, 0, SEEK_SET); - } - - return FMT_UNREC; -} - -CMD *regedit4_get_cmd(int fd) -{ - return NULL; -} - -int regedit4_exec_cmd(CMD *cmd) -{ - - return 0; -} - -int editreg_1_1_file_type(int fd) -{ - - return FMT_UNREC; -} - -CMD *editreg_1_1_get_cmd(int fd) -{ - return NULL; -} - -int editreg_1_1_exec_cmd(CMD *cmd) -{ - - return -1; -} - -typedef struct command_ops_s { - int type; - int (*file_type)(int fd); - CMD *(*get_cmd)(int fd); - int (*exec_cmd)(CMD *cmd); -} CMD_OPS; - -CMD_OPS default_cmd_ops[] = { - {0, regedit4_file_type, regedit4_get_cmd, regedit4_exec_cmd}, - {1, editreg_1_1_file_type, editreg_1_1_get_cmd, editreg_1_1_exec_cmd}, - {-1, NULL, NULL, NULL} -}; - -typedef struct command_file_s { - char *name; - int type, fd; - CMD_OPS cmd_ops; -} CMD_FILE; - -/* - * Create a new command file structure - */ - -CMD_FILE *cmd_file_create(char *file) -{ - CMD_FILE *tmp; - struct stat sbuf; - int i = 0; - - /* - * Let's check if the file exists ... - * No use creating the cmd_file structure if the file does not exist - */ - - if (stat(file, &sbuf) < 0) { /* Not able to access file */ - - return NULL; - } - - tmp = (CMD_FILE *)malloc(sizeof(CMD_FILE)); - if (!tmp) { - return NULL; - } - - /* - * Let's fill in some of the fields; - */ - - tmp->name = strdup(file); - - if ((tmp->fd = open(file, O_RDONLY, 666)) < 0) { - free(tmp); - return NULL; - } - - /* - * Now, try to find the format by indexing through the table - */ - while (default_cmd_ops[i].type != -1) { - if ((tmp->type = default_cmd_ops[i].file_type(tmp->fd)) >= 0) { - tmp->cmd_ops = default_cmd_ops[i]; - return tmp; - } - i++; - } - - /* - * If we got here, return NULL, as we could not figure out the type - * of command file. - * - * What about errors? - */ - - free(tmp); - return NULL; -} - -/* - * Extract commands from the command file, and execute them. - * We pass a table of command callbacks for that - */ - -/* - * Main code from here on ... - */ - -/* - * key print function here ... - */ - -int print_key(const char *path, char *name, char *class_name, int root, - int terminal, int vals) -{ - - if (terminal) fprintf(stdout, "%s\\%s\n", path, name); - - return 1; -} - -/* - * Sec Desc print functions - */ - -void print_sid(DOM_SID *sid) -{ - int i, comps = sid->auths; - fprintf(stdout, "S-%u-%u", sid->ver, sid->auth[5]); - - for (i = 0; i < comps; i++) { - - fprintf(stdout, "-%u", sid->sub_auths[i]); - - } - fprintf(stdout, "\n"); -} - -int print_sec(SEC_DESC *sec_desc) -{ - - fprintf(stdout, " SECURITY\n"); - fprintf(stdout, " Owner: "); - print_sid(sec_desc->owner); - fprintf(stdout, " Group: "); - print_sid(sec_desc->group); - return 1; -} - -/* - * Value print function here ... - */ -int print_val(const char *path, char *val_name, int val_type, int data_len, - void *data_blk, int terminal, int first, int last) -{ - char data_asc[1024]; - - bzero(data_asc, sizeof(data_asc)); - if (!terminal && first) - fprintf(stdout, "%s\n", path); - data_to_ascii((unsigned char *)data_blk, data_len, val_type, data_asc, - sizeof(data_asc) - 1); - fprintf(stdout, " %s : %s : %s\n", (val_name?val_name:"<No Name>"), - val_to_str(val_type, reg_type_names), data_asc); - return 1; -} - -int main(int argc, char *argv[]) -{ - REGF *regf; - int opt; - static char *cmd_file = NULL; - poptContext pc; - struct poptOption long_options[] = { - POPT_AUTOHELP - { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Sets verbose mode" }, - { "command-file", 'c', POPT_ARG_STRING, &cmd_file, 'c', "Specifies a command file" }, - { 0, 0, 0, 0 } - }; - - pc = poptGetContext("editreg", argc, (const char **)argv, long_options, - POPT_CONTEXT_KEEP_FIRST); - - poptSetOtherOptionHelp(pc, "<registry-file>"); - - while((opt = poptGetNextOpt(pc)) != -1) - switch(opt) { - case 'v': - verbose++; - break; - } - - poptGetArg(pc); /* For argv[0] */ - - if (!poptPeekArg(pc)) { - poptPrintUsage(pc, stderr, 0); - exit(1); - } - - if ((regf = nt_create_regf()) == NULL) { - fprintf(stderr, "Could not create registry object: %s\n", strerror(errno)); - exit(2); - } - - if (!nt_set_regf_input_file(regf, poptPeekArg(pc))) { - fprintf(stderr, "Could not set name of registry file: %s, %s\n", - poptPeekArg(pc), strerror(errno)); - exit(3); - } - - /* Now, open it, and bring it into memory :-) */ - - if (nt_load_registry(regf) < 0) { - fprintf(stderr, "Could not load registry: %s\n", poptPeekArg(pc)); - exit(4); - } - - /* - * At this point, we should have a registry in memory and should be able - * to iterate over it. - */ - - nt_key_iterator(regf, regf->root, 0, "", print_key, print_sec, print_val); - poptFreeContext(pc); - return 0; -} diff --git a/source3/utils/net.c b/source3/utils/net.c index 3ab34e7aa9..7588771fbc 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -78,6 +78,8 @@ static int opt_machine_pass = 0; BOOL opt_have_ip = False; struct in_addr opt_dest_ip; +extern BOOL AllowDebugChange; + /* run a function from a function table. If not found then call the specified usage function @@ -511,14 +513,18 @@ static struct functable net_func[] = { int argc_new = 0; const char ** argv_new; poptContext pc; + static char *servicesf = dyn_CONFIGFILE; + static char *debuglevel = NULL; struct poptOption long_options[] = { {"help", 'h', POPT_ARG_NONE, 0, 'h'}, {"workgroup", 'w', POPT_ARG_STRING, &opt_target_workgroup}, + {"myworkgroup", 'W', POPT_ARG_STRING, &opt_workgroup}, {"user", 'U', POPT_ARG_STRING, &opt_user_name, 'U'}, {"ipaddress", 'I', POPT_ARG_STRING, 0,'I'}, {"port", 'p', POPT_ARG_INT, &opt_port}, {"myname", 'n', POPT_ARG_STRING, &opt_requester_name}, + {"conf", 's', POPT_ARG_STRING, &servicesf}, {"server", 'S', POPT_ARG_STRING, &opt_host}, {"container", 'c', POPT_ARG_STRING, &opt_container}, {"comment", 'C', POPT_ARG_STRING, &opt_comment}, @@ -530,8 +536,8 @@ static struct functable net_func[] = { {"force", 'f', POPT_ARG_NONE, &opt_force}, {"timeout", 't', POPT_ARG_INT, &opt_timeout}, {"machine-pass",'P', POPT_ARG_NONE, &opt_machine_pass}, - {"myworkgroup", 'W', POPT_ARG_STRING, &opt_workgroup}, - POPT_COMMON_SAMBA + {"debuglevel", 'd', POPT_ARG_STRING, &debuglevel}, + {NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version}, { 0, 0, 0, 0} }; @@ -571,8 +577,13 @@ static struct functable net_func[] = { exit(1); } } - - lp_load(dyn_CONFIGFILE,True,False,False); + + if (debuglevel) { + debug_parse_levels(debuglevel); + AllowDebugChange = False; + } + + lp_load(servicesf,True,False,False); argv_new = (const char **)poptGetArgs(pc); @@ -625,10 +636,6 @@ static struct functable net_func[] = { exit(1); } } - - if (!opt_password) { - opt_password = getenv("PASSWD"); - } rc = net_run_function(argc_new-1, argv_new+1, net_func, net_help); diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 0f2d673b4b..b4697d73dd 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -124,7 +124,6 @@ static ADS_STRUCT *ads_startup(void) ADS_STATUS status; BOOL need_password = False; BOOL second_time = False; - char *realm; ads = ads_init(NULL, NULL, opt_host); @@ -151,16 +150,6 @@ retry: ads->auth.user_name = strdup(opt_user_name); - /* - * If the username is of the form "name@realm", - * extract the realm and convert to upper case. - */ - if ((realm = strchr(ads->auth.user_name, '@'))) { - *realm++ = '\0'; - ads->auth.realm = strdup(realm); - strupper(ads->auth.realm); - } - status = ads_connect(ads); if (!ADS_ERR_OK(status)) { if (!need_password && !second_time) { diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c index 07409aec22..4000a248ff 100644 --- a/source3/utils/net_help.c +++ b/source3/utils/net_help.c @@ -42,12 +42,11 @@ int net_common_flags_usage(int argc, const char **argv) d_printf("Valid miscellaneous options are:\n"); /* misc options */ d_printf("\t-p or --port=<port>\t\tconnection port on target\n"); d_printf("\t-W or --myworkgroup=<wg>\tclient workgroup\n"); - d_printf("\t-d or --debuglevel=<level>\t\tdebug level (0-10)\n"); + d_printf("\t-d or --debug=<level>\t\tdebug level (0-10)\n"); d_printf("\t-n or --myname=<name>\t\tclient name\n"); d_printf("\t-U or --user=<name>\t\tuser name\n"); - d_printf("\t-s or --configfile=<path>\t\tpathname of smb.conf file\n"); + d_printf("\t-s or --conf=<path>\t\tpathname of smb.conf file\n"); d_printf("\t-l or --long\t\t\tDisplay full information\n"); - d_printf("\t-V or --version\t\tPrint samba version information\n"); d_printf("\t-P or --machine-pass\t\tAuthenticate as machine account\n"); return -1; } diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index 69cf28f995..922fc027e6 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -1880,7 +1880,7 @@ static int rpc_trustdom_list(int argc, const char **argv) int num_domains, i, pad_len, col_len = 20; DOM_SID *domain_sids; char **trusted_dom_names; - fstring pdc_name, dummy; + fstring pdc_name; /* trusting domains listing variables */ POLICY_HND domain_hnd; @@ -1927,10 +1927,8 @@ static int rpc_trustdom_list(int argc, const char **argv) }; /* query info level 5 to obtain sid of a domain being queried */ - nt_status = cli_lsa_query_info_policy( - cli, mem_ctx, &connect_hnd, 5 /* info level */, - dummy, &queried_dom_sid); - + nt_status = cli_lsa_query_info_policy(cli, mem_ctx, &connect_hnd, + 5 /* info level */, domain_name, &queried_dom_sid); if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("LSA Query Info failed. Returned error was %s\n", nt_errstr(nt_status))); diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c index 0b78cd54ce..f811d76f68 100644 --- a/source3/utils/net_rpc_samsync.c +++ b/source3/utils/net_rpc_samsync.c @@ -362,7 +362,7 @@ sam_account_from_delta(SAM_ACCOUNT *account, SAM_ACCOUNT_INFO *delta) } #if 0 -/* No kickoff time in the delta? */ + /* No kickoff time in the delta? */ if (!nt_time_is_zero(&delta->kickoff_time)) { unix_time = nt_time_to_unix(&delta->kickoff_time); stored_time = pdb_get_kickoff_time(account); diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c index d2c5cbc00e..7e0ed4a203 100644 --- a/source3/utils/nmblookup.c +++ b/source3/utils/nmblookup.c @@ -2,7 +2,6 @@ Unix SMB/CIFS implementation. NBT client - used to lookup netbios names Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) Jelmer Vernooij 2003 (Conversion to popt) 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 @@ -55,6 +54,31 @@ static BOOL open_sockets(void) return True; } + +/**************************************************************************** +usage on the program +****************************************************************************/ +static void usage(void) +{ + d_printf("Usage: nmblookup [options] name\n"); + d_printf("Version %s\n",VERSION); + d_printf("\t-d debuglevel set the debuglevel\n"); + d_printf("\t-B broadcast address the address to use for broadcasts\n"); + d_printf("\t-f list the NMB flags returned\n"); + d_printf("\t-U unicast address the address to use for unicast\n"); + d_printf("\t-M searches for a master browser\n"); + d_printf("\t-R set recursion desired in packet\n"); + d_printf("\t-S lookup node status as well\n"); + d_printf("\t-T translate IP addresses into names\n"); + d_printf("\t-r Use root port 137 (Win95 only replies to this)\n"); + d_printf("\t-A Do a node status on <name> as an IP Address\n"); + d_printf("\t-i NetBIOS scope Use the given NetBIOS scope for name queries\n"); + d_printf("\t-s smb.conf file Use the given path to the smb.conf file\n"); + d_printf("\t-h Print this help message.\n"); + d_printf("\n If you specify -M and name is \"-\", nmblookup looks up __MSBROWSE__<01>\n"); + d_printf("\n"); +} + /**************************************************************************** turn a node status flags field into a string ****************************************************************************/ @@ -187,106 +211,130 @@ int main(int argc,char *argv[]) int opt; unsigned int lookup_type = 0x0; fstring lookup; - static BOOL find_master=False; - static BOOL lookup_by_ip = False; - poptContext pc; - - struct poptOption long_options[] = { - POPT_AUTOHELP - { "broadcast", 'B', POPT_ARG_STRING, NULL, 'B', "Specify address to use for broadcasts", "BROADCAST-ADDRESS" }, - { "flags", 'f', POPT_ARG_VAL, &give_flags, True, "List the NMB flags returned" }, - { "unicast", 'U', POPT_ARG_STRING, NULL, 'U', "Specify address to use for unicast" }, - { "master-browser", 'M', POPT_ARG_VAL, &find_master, True, "Search for a master browser" }, - { "recursion", 'R', POPT_ARG_VAL, &recursion_desired, True, "Set recursion desired in package" }, - { "status", 'S', POPT_ARG_VAL, &find_status, True, "Lookup node status as well" }, - { "translate", 'T', POPT_ARG_NONE, NULL, 'T', "Translate IP addresses into names" }, - { "root-port", 'r', POPT_ARG_VAL, &RootPort, True, "Use root port 137 (Win95 only replies to this)" }, - { "lookup-by-ip", 'A', POPT_ARG_VAL, &lookup_by_ip, True, "Do a node status on <name> as an IP Address" }, - POPT_COMMON_SAMBA - POPT_COMMON_CONNECTION - { 0, 0, 0, 0 } - }; - - *lookup = 0; + extern int optind; + extern char *optarg; + BOOL find_master=False; + int i; + BOOL lookup_by_ip = False; + int commandline_debuglevel = -2; - setup_logging(argv[0],True); + DEBUGLEVEL = 1; + /* Prevent smb.conf setting from overridding */ + AllowDebugChange = False; - pc = poptGetContext("nmblookup", argc, (const char **)argv, long_options, - POPT_CONTEXT_KEEP_FIRST); - - poptSetOtherOptionHelp(pc, "<NODE> ..."); - - while ((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - case 'B': - bcast_addr = *interpret_addr2(poptGetOptArg(pc)); - got_bcast = True; - use_bcast = True; - break; - case 'U': - bcast_addr = *interpret_addr2(poptGetOptArg(pc)); - got_bcast = True; - use_bcast = False; - break; - case 'T': - translate_addresses = !translate_addresses; - break; - } - } + *lookup = 0; - poptGetArg(pc); /* Remove argv[0] */ + setup_logging(argv[0],True); - if(!poptPeekArg(pc)) { - poptPrintUsage(pc, stderr, 0); - exit(1); + while ((opt = getopt(argc, argv, "d:fB:U:i:s:SMrhART")) != EOF) + switch (opt) + { + case 'B': + bcast_addr = *interpret_addr2(optarg); + got_bcast = True; + use_bcast = True; + break; + case 'f': + give_flags = True; + break; + case 'U': + bcast_addr = *interpret_addr2(optarg); + got_bcast = True; + use_bcast = False; + break; + case 'T': + translate_addresses = !translate_addresses; + break; + case 'i': + set_global_scope(optarg); + break; + case 'M': + find_master = True; + break; + case 'S': + find_status = True; + break; + case 'R': + recursion_desired = True; + break; + case 'd': + commandline_debuglevel = DEBUGLEVEL = atoi(optarg); + break; + case 's': + pstrcpy(dyn_CONFIGFILE, optarg); + break; + case 'r': + RootPort = True; + break; + case 'h': + usage(); + exit(0); + break; + case 'A': + lookup_by_ip = True; + break; + default: + usage(); + exit(1); + } + + if (argc < 2) { + usage(); + exit(1); } if (!lp_load(dyn_CONFIGFILE,True,False,False)) { - fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); + fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); } + /* + * Ensure we reset DEBUGLEVEL if someone specified it + * on the command line. + */ + + if(commandline_debuglevel != -2) + DEBUGLEVEL = commandline_debuglevel; + load_interfaces(); if (!open_sockets()) return(1); - while(poptPeekArg(pc)) + for (i=optind;i<argc;i++) { - char *p; - struct in_addr ip; - - fstrcpy(lookup,poptGetArg(pc)); - - if(lookup_by_ip) - { - ip = *interpret_addr2(lookup); - fstrcpy(lookup,"*"); - do_node_status(ServerFD, lookup, lookup_type, ip); - continue; - } - - if (find_master) { - if (*lookup == '-') { - fstrcpy(lookup,"\01\02__MSBROWSE__\02"); - lookup_type = 1; - } else { - lookup_type = 0x1d; - } - } - - p = strchr_m(lookup,'#'); - if (p) { - *p = '\0'; - sscanf(++p,"%x",&lookup_type); - } - - if (!query_one(lookup, lookup_type)) { - d_printf( "name_query failed to find name %s", lookup ); - if( 0 != lookup_type ) - d_printf( "#%02x", lookup_type ); - d_printf( "\n" ); - } + char *p; + struct in_addr ip; + + fstrcpy(lookup,argv[i]); + + if(lookup_by_ip) + { + fstrcpy(lookup,"*"); + ip = *interpret_addr2(argv[i]); + do_node_status(ServerFD, lookup, lookup_type, ip); + continue; + } + + if (find_master) { + if (*lookup == '-') { + fstrcpy(lookup,"\01\02__MSBROWSE__\02"); + lookup_type = 1; + } else { + lookup_type = 0x1d; + } + } + + p = strchr_m(lookup,'#'); + if (p) { + *p = '\0'; + sscanf(++p,"%x",&lookup_type); + } + + if (!query_one(lookup, lookup_type)) { + d_printf( "name_query failed to find name %s", lookup ); + if( 0 != lookup_type ) + d_printf( "#%02x", lookup_type ); + d_printf( "\n" ); + } } - - poptFreeContext(pc); - + return(0); } diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 88913c8051..0bead042fd 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -735,8 +735,7 @@ enum { { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retreive LM session key"}, { "request-nt-key", 0, POPT_ARG_NONE, &request_nt_key, OPT_NT_KEY, "Retreive NT session key"}, { "diagnostics", 0, POPT_ARG_NONE, &diagnostics, OPT_DIAGNOSTICS, "Perform diagnostics on the authentictaion chain"}, - POPT_COMMON_SAMBA - POPT_TABLEEND + { NULL, 0, 0, NULL, 0, NULL} }; /* Samba client initialisation */ diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index bf42fb805f..99d3e01fd2 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -516,7 +516,7 @@ int main (int argc, char **argv) poptContext pc; struct poptOption long_options[] = { POPT_AUTOHELP - {"list", 'L', POPT_ARG_NONE, &list_users, 0, "list all users", NULL}, + {"list", 'l', POPT_ARG_NONE, &list_users, 0, "list all users", NULL}, {"verbose", 'v', POPT_ARG_NONE, &verbose, 0, "be verbose", NULL }, {"smbpasswd-style", 'w',POPT_ARG_NONE, &spstyle, 0, "give output in smbpasswd style", NULL}, {"user", 'u', POPT_ARG_STRING, &user_name, 0, "use username", "USER" }, @@ -534,10 +534,11 @@ int main (int argc, char **argv) {"export", 'e', POPT_ARG_STRING, &backend_out, 0, "export user accounts to this backend", NULL}, {"group", 'g', POPT_ARG_NONE, &transfer_groups, 0, "use -i and -e for groups", NULL}, {"account-policy", 'P', POPT_ARG_STRING, &account_policy, 0,"value of an account policy (like maximum password age)",NULL}, - {"value", 'C', POPT_ARG_LONG, &account_policy_value, 'C',"set the account policy to this value", NULL}, + {"value", 'V', POPT_ARG_LONG, &account_policy_value, 'V',"set the account policy to this value", NULL}, {"account-control", 'c', POPT_ARG_STRING, &account_control, 0, "Values of account control", NULL}, - POPT_COMMON_SAMBA - POPT_TABLEEND + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug }, + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile }, + {0,0,0,0} }; setup_logging("pdbedit", True); diff --git a/source3/utils/profiles.c b/source3/utils/profiles.c index 7c2d820c81..2ed102b677 100644 --- a/source3/utils/profiles.c +++ b/source3/utils/profiles.c @@ -1,7 +1,6 @@ /* Samba Unix/Linux SMB client utility profiles.c Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com - Copyright (C) 2003 Jelmer Vernooij (conversion to popt) 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 @@ -35,7 +34,7 @@ times... the "regf"-Block ================ -"regf" is obviously the abbreviation for "Registry file". "regf" is the +"regf" is obviosly the abbreviation for "Registry file". "regf" is the signature of the header-block which is always 4kb in size, although only the first 64 bytes seem to be used and a checksum is calculated over the first 0x200 bytes only! @@ -392,14 +391,14 @@ typedef struct acl_struct { #define OFF(f) (0x1000 + (f) + 4) -static void print_sid(DOM_SID *sid); +void print_sid(DOM_SID *sid); int verbose = 1; DOM_SID old_sid, new_sid; int change = 0, new = 0; /* Compare two SIDs for equality */ -static int my_sid_equal(DOM_SID *s1, DOM_SID *s2) +int my_sid_equal(DOM_SID *s1, DOM_SID *s2) { int sa1, sa2; @@ -418,7 +417,7 @@ static int my_sid_equal(DOM_SID *s1, DOM_SID *s2) * Quick and dirty to read a SID in S-1-5-21-x-y-z-rid format and * construct a DOM_SID */ -static int get_sid(DOM_SID *sid, char *sid_str) +int get_sid(DOM_SID *sid, char *sid_str) { int i = 0, auth; char *lstr; @@ -461,7 +460,7 @@ static int get_sid(DOM_SID *sid, char *sid_str) * This routine does not need to deal with endianism as * long as the incoming SIDs are both in the same (LE) format. */ -static void change_sid(DOM_SID *s1, DOM_SID *s2) +void change_sid(DOM_SID *s1, DOM_SID *s2) { int i; @@ -470,7 +469,7 @@ static void change_sid(DOM_SID *s1, DOM_SID *s2) } } -static void print_sid(DOM_SID *sid) +void print_sid(DOM_SID *sid) { int i, comps = sid->num_auths; fprintf(stdout, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]); @@ -483,7 +482,7 @@ static void print_sid(DOM_SID *sid) fprintf(stdout, "\n"); } -static void process_sid(DOM_SID *sid, DOM_SID *o_sid, DOM_SID *n_sid) +void process_sid(DOM_SID *sid, DOM_SID *o_sid, DOM_SID *n_sid) { int i; if (my_sid_equal(sid, o_sid)) { @@ -497,7 +496,7 @@ static void process_sid(DOM_SID *sid, DOM_SID *o_sid, DOM_SID *n_sid) } -static void process_acl(ACL *acl, const char *prefix) +void process_acl(ACL *acl, const char *prefix) { int ace_cnt, i; ACE *ace; @@ -515,8 +514,21 @@ static void process_acl(ACL *acl, const char *prefix) } } +void usage(void) +{ + fprintf(stderr, "usage: profiles [-c <OLD-SID> -n <NEW-SID>] <profilefile>\n"); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "\n\t-v\t sets verbose mode"); + fprintf(stderr, "\n\t-c S-1-5-21-z-y-x-oldrid - provides SID to change"); + fprintf(stderr, "\n\t-n S-1-5-21-a-b-c-newrid - provides SID to change to"); + fprintf(stderr, "\n\t\tBoth must be present if the other is."); + fprintf(stderr, "\n\t\tIf neither present, just report the SIDs found\n"); +} + int main(int argc, char *argv[]) { + extern char *optarg; + extern int optind; int opt; int fd, start = 0; char *base; @@ -528,75 +540,63 @@ int main(int argc, char *argv[]) DWORD first_sk_off, sk_off; MY_SEC_DESC *sec_desc; int *ptr; - struct poptOption long_options[] = { - POPT_AUTOHELP - { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Sets verbose mode" }, - { "change-sid", 'c', POPT_ARG_STRING, NULL, 'c', "Provides SID to change" }, - { "new-sid", 'n', POPT_ARG_STRING, NULL, 'n', "Provides SID to change to" }, - { 0, 0, 0, 0 } - }; - - poptContext pc; - pc = poptGetContext("profiles", argc, (const char **)argv, long_options, - POPT_CONTEXT_KEEP_FIRST); - - poptSetOtherOptionHelp(pc, "<profilefile>"); + if (argc < 2) { + usage(); + exit(1); + } /* * Now, process the arguments */ - while ((opt = poptGetNextOpt(pc)) != -1) { + while ((opt = getopt(argc, argv, "c:n:v")) != EOF) { switch (opt) { - case 'c': - change = 1; - if (!get_sid(&old_sid, poptGetOptArg(pc))) { - fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n"); - poptPrintUsage(pc, stderr, 0); - exit(254); - } - break; - - case 'n': - new = 1; - if (!get_sid(&new_sid, poptGetOptArg(pc))) { - fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n"); - poptPrintUsage(pc, stderr, 0); - exit(253); - } - - break; - - case 'v': - verbose++; - break; - } - } + case 'c': + change = 1; + if (!get_sid(&old_sid, optarg)) { + fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n"); + usage(); + exit(254); + } + break; + + case 'n': + new = 1; + if (!get_sid(&new_sid, optarg)) { + fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n"); + usage(); + exit(253); + } + + break; + + case 'v': + verbose++; + break; - if (!poptPeekArg(pc)) { - poptPrintUsage(pc, stderr, 0); - exit(1); + default: + usage(); + exit(255); + } } if ((!change & new) || (change & !new)) { - fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n"); - poptPrintUsage(pc, stderr, 0); - exit(252); + fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n"); + usage(); + exit(252); } - poptGetArg(pc); /* To get argv[0] */ - - fd = open(poptPeekArg(pc), O_RDWR, 0000); + fd = open(argv[optind], O_RDWR, 0000); if (fd < 0) { - fprintf(stderr, "Could not open %s: %s\n", poptPeekArg(pc), + fprintf(stderr, "Could not open %s: %s\n", argv[optind], strerror(errno)); exit(2); } if (fstat(fd, &sbuf) < 0) { - fprintf(stderr, "Could not stat file %s, %s\n", poptPeekArg(pc), + fprintf(stderr, "Could not stat file %s, %s\n", argv[optind], strerror(errno)); exit(3); } @@ -609,7 +609,7 @@ int main(int argc, char *argv[]) base = mmap(&start, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((int)base == -1) { - fprintf(stderr, "Could not mmap file: %s, %s\n", poptPeekArg(pc), + fprintf(stderr, "Could not mmap file: %s, %s\n", argv[optind], strerror(errno)); exit(4); } @@ -640,7 +640,7 @@ int main(int argc, char *argv[]) if (verbose) fprintf(stdout, "Registry file size: %u\n", (unsigned int)sbuf.st_size); if (IVAL(®f_hdr->REGF_ID, 0) != REG_REGF_ID) { - fprintf(stderr, "Incorrect Registry file (doesn't have header ID): %s\n", poptPeekArg(pc)); + fprintf(stderr, "Incorrect Registry file (doesn't have header ID): %s\n", argv[optind]); exit(5); } @@ -655,7 +655,7 @@ int main(int argc, char *argv[]) */ if (IVAL(&hbin_hdr->HBIN_ID, 0) != REG_HBIN_ID) { - fprintf(stderr, "Incorrect hbin hdr: %s\n", poptPeekArg(pc)); + fprintf(stderr, "Incorrect hbin hdr: %s\n", argv[optind]); exit(6); } @@ -666,7 +666,7 @@ int main(int argc, char *argv[]) nk_hdr = (NK_HDR *)(base + 0x1000 + IVAL(®f_hdr->first_key, 0) + 4); if (SVAL(&nk_hdr->NK_ID, 0) != REG_NK_ID) { - fprintf(stderr, "Incorrect NK Header: %s\n", poptPeekArg(pc)); + fprintf(stderr, "Incorrect NK Header: %s\n", argv[optind]); exit(7); } @@ -724,8 +724,6 @@ int main(int argc, char *argv[]) munmap(base, sbuf.st_size); - poptFreeContext(pc); - close(fd); return 0; } diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index 9d8a657726..069ac56c67 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -5,7 +5,6 @@ Copyright (C) Andrew Tridgell 2000 Copyright (C) Tim Potter 2000 Copyright (C) Jeremy Allison 2000 - Copyright (C) Jelmer Vernooij 2003 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 @@ -24,9 +23,12 @@ #include "includes.h" +static fstring password; +static pstring username; static pstring owner_username; static fstring server; -static int test_args = False; +static int got_pass; +static int test_args; static TALLOC_CTX *ctx; #define CREATE_ACCESS_READ READ_CONTROL_ACCESS @@ -34,7 +36,7 @@ static TALLOC_CTX *ctx; /* numeric is set when the user wants numeric SIDs and ACEs rather than going via LSA calls to resolve them */ -static BOOL numeric = False; +static int numeric; enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD }; enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP}; @@ -713,19 +715,19 @@ static struct cli_state *connect_one(const char *share) NTSTATUS nt_status; zero_ip(&ip); - if (!cmdline_auth_info.got_pass) { + if (!got_pass) { char *pass = getpass("Password: "); if (pass) { - pstrcpy(cmdline_auth_info.password, pass); - cmdline_auth_info.got_pass = True; + fstrcpy(password, pass); + got_pass = True; } } if (NT_STATUS_IS_OK(nt_status = cli_full_connection(&c, global_myname(), server, &ip, 0, share, "?????", - cmdline_auth_info.username, lp_workgroup(), - cmdline_auth_info.password, 0, NULL))) { + username, lp_workgroup(), + password, 0, NULL))) { return c; } else { DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); @@ -733,34 +735,45 @@ static struct cli_state *connect_one(const char *share) } } + +static void usage(void) +{ + printf( +"Usage: smbcacls //server1/share1 filename [options]\n\ +\n\ +\t-D <acls> delete an acl\n\ +\t-M <acls> modify an acl\n\ +\t-A <acls> add an acl\n\ +\t-S <acls> set acls\n\ +\t-C username change ownership of a file\n\ +\t-G username change group ownership of a file\n\ +\t-n don't resolve sids or masks to names\n\ +\t-h print help\n\ +\t-d debuglevel set debug output level\n\ +\t-U username user to autheticate as\n\ +\n\ +The username can be of the form username%%password or\n\ +workgroup\\username%%password.\n\n\ +An acl is of the form ACL:<SID>:type/flags/mask\n\ +You can string acls together with spaces, commas or newlines\n\ +"); +} + /**************************************************************************** main program ****************************************************************************/ - int main(int argc, const char *argv[]) + int main(int argc,char *argv[]) { char *share; + pstring filename; + extern char *optarg; + extern int optind; int opt; + char *p; enum acl_mode mode = SMB_ACL_SET; - static char *the_acl = NULL; + char *the_acl = NULL; enum chown_mode change_mode = REQUEST_NONE; int result; - fstring path; - pstring filename; - poptContext pc; - struct poptOption long_options[] = { - POPT_AUTOHELP - { "delete", 'D', POPT_ARG_STRING, NULL, 'D', "Delete an acl", "ACL" }, - { "modify", 'M', POPT_ARG_STRING, NULL, 'M', "Modify an acl", "ACL" }, - { "add", 'A', POPT_ARG_STRING, NULL, 'A', "Add an acl", "ACL" }, - { "set", 'S', POPT_ARG_STRING, NULL, 'S', "Set acls", "ACLS" }, - { "chown", 'C', POPT_ARG_STRING, NULL, 'C', "Change ownership of a file", "USERNAME" }, - { "chgrp", 'G', POPT_ARG_STRING, NULL, 'G', "Change group ownership of a file", "GROUPNAME" }, - { "numeric", 0, POPT_ARG_NONE, &numeric, True, "Don't resolve sids or masks to names" }, - { "test-args", 't', POPT_ARG_NONE, &test_args, True, "Test arguments"}, - POPT_COMMON_SAMBA - POPT_COMMON_CREDENTIALS - { NULL } - }; struct cli_state *cli; @@ -770,72 +783,118 @@ static struct cli_state *connect_one(const char *share) dbf = x_stderr; + if (argc < 3 || argv[1][0] == '-') { + usage(); + talloc_destroy(ctx); + exit(EXIT_PARSE_ERROR); + } + setup_logging(argv[0],True); + share = argv[1]; + pstrcpy(filename, argv[2]); + all_string_sub(share,"/","\\",0); + + argc -= 2; + argv += 2; + lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); - pc = poptGetContext("smbcacls", argc, argv, long_options, 0); - - poptSetOtherOptionHelp(pc, "//server1/share1 filename"); + if (getenv("USER")) { + pstrcpy(username,getenv("USER")); - while ((opt = poptGetNextOpt(pc)) != -1) { + if ((p=strchr_m(username,'%'))) { + *p = 0; + fstrcpy(password,p+1); + got_pass = True; + memset(strchr_m(getenv("USER"), '%') + 1, 'X', + strlen(password)); + } + } + + while ((opt = getopt(argc, argv, "U:nhS:D:A:M:C:G:td:")) != EOF) { switch (opt) { + case 'U': + pstrcpy(username,optarg); + p = strchr_m(username,'%'); + if (p) { + *p = 0; + fstrcpy(password, p+1); + got_pass = 1; + } + break; + case 'S': - the_acl = smb_xstrdup(poptGetOptArg(pc)); + the_acl = optarg; mode = SMB_ACL_SET; break; case 'D': - the_acl = smb_xstrdup(poptGetOptArg(pc)); + the_acl = optarg; mode = SMB_ACL_DELETE; break; case 'M': - the_acl = smb_xstrdup(poptGetOptArg(pc)); + the_acl = optarg; mode = SMB_ACL_MODIFY; break; case 'A': - the_acl = smb_xstrdup(poptGetOptArg(pc)); + the_acl = optarg; mode = SMB_ACL_ADD; break; case 'C': - pstrcpy(owner_username,poptGetOptArg(pc)); + pstrcpy(owner_username,optarg); change_mode = REQUEST_CHOWN; break; case 'G': - pstrcpy(owner_username,poptGetOptArg(pc)); + pstrcpy(owner_username,optarg); change_mode = REQUEST_CHGRP; break; + + case 'n': + numeric = 1; + break; + + case 't': + test_args = 1; + break; + + case 'h': + usage(); + talloc_destroy(ctx); + exit(EXIT_PARSE_ERROR); + + case 'd': + DEBUGLEVEL = atoi(optarg); + break; + + default: + printf("Unknown option %c (%d)\n", (char)opt, opt); + talloc_destroy(ctx); + exit(EXIT_PARSE_ERROR); } } - /* Make connection to server */ - if(!poptPeekArg(pc)) { - poptPrintUsage(pc, stderr, 0); - return -1; - } - - fstrcpy(path, poptGetArg(pc)); - - if(!poptPeekArg(pc)) { - poptPrintUsage(pc, stderr, 0); - return -1; + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + talloc_destroy(ctx); + exit(EXIT_PARSE_ERROR); } - - pstrcpy(filename, poptGetArg(pc)); - all_string_sub(path,"/","\\",0); + /* Make connection to server */ - fstrcpy(server,path+2); + fstrcpy(server,share+2); share = strchr_m(server,'\\'); if (!share) { share = strchr_m(server,'/'); if (!share) { - printf("Invalid argument: %s\n", share); return -1; } } @@ -875,3 +934,4 @@ static struct cli_state *connect_one(const char *share) return result; } + diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index 8b984d9bd1..ec4f41cad6 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -1,11 +1,8 @@ /* Unix SMB/CIFS implementation. - - Send messages to other Samba daemons - - Copyright (C) Tim Potter 2003 + program to send control messages to Samba processes Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) Martin Pool 2001-2002 + Copyright (C) 2001, 2002 by Martin Pool Copyright (C) Simo Sorce 2002 This program is free software; you can redistribute it and/or modify @@ -25,718 +22,698 @@ #include "includes.h" -/* Default timeout value when waiting for replies (in seconds) */ - -#define DEFAULT_TIMEOUT 10 - -static int timeout = DEFAULT_TIMEOUT; -static int num_replies; /* Used by message callback fns */ +extern BOOL AllowDebugChange; -/* Send a message to a destination pid. Zero means broadcast smbd. */ - -static BOOL send_message(pid_t pid, int msg_type, void *buf, int len, - BOOL duplicates) -{ - TDB_CONTEXT *tdb; - BOOL ret; - int n_sent = 0; - - if (!message_init()) - return False; - - if (pid != 0) - return message_send_pid(pid, msg_type, buf, len, duplicates); - - tdb = tdb_open_log(lock_path("connections.tdb"), 0, - TDB_DEFAULT, O_RDWR, 0); - if (!tdb) { - fprintf(stderr,"Failed to open connections database" - ": %s\n", strerror(errno)); - return False; - } - - ret = message_send_all(tdb,msg_type, buf, len, duplicates, - &n_sent); - DEBUG(10,("smbcontrol/send_message: broadcast message to " - "%d processes\n", n_sent)); - - tdb_close(tdb); - - return ret; -} - -/* Wait for one or more reply messages */ - -static void wait_replies(BOOL multiple_replies) -{ - time_t start_time = time(NULL); +static const struct { + const char *name; + int value; +} msg_types[] = { + {"debug", MSG_DEBUG}, + {"force-election", MSG_FORCE_ELECTION}, + {"ping", MSG_PING}, + {"profile", MSG_PROFILE}, + {"profilelevel", MSG_REQ_PROFILELEVEL}, + {"debuglevel", MSG_REQ_DEBUGLEVEL}, + {"printnotify", MSG_PRINTER_NOTIFY2 }, + {"close-share", MSG_SMB_FORCE_TDIS}, + {"samsync", MSG_SMB_SAM_SYNC}, + {"samrepl", MSG_SMB_SAM_REPL}, + {"pool-usage", MSG_REQ_POOL_USAGE }, + {"dmalloc-mark", MSG_REQ_DMALLOC_MARK }, + {"dmalloc-log-changed", MSG_REQ_DMALLOC_LOG_CHANGED }, + {"shutdown", MSG_SHUTDOWN }, + {"drvupgrade", MSG_PRINTER_DRVUPGRADE}, + {"tallocdump", MSG_REQ_TALLOC_USAGE}, + {NULL, -1} +}; - /* Wait around a bit. This is pretty disgusting - we have to - busy-wait here as there is no nicer way to do it. */ +time_t timeout_start; - do { - message_dispatch(); - if (num_replies > 0 && !multiple_replies) - break; - sleep(1); - } while (timeout - (time(NULL) - start_time) > 0); -} +#define MAX_WAIT 10 -/* Message handler callback that displays a string on stdout */ +/* we need these because we link to printing*.o */ -static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len) -{ - printf("%.*s", (int)len, (const char *)buf); - num_replies++; -} +void become_root(void) {} +void unbecome_root(void) {} -/* Send no message. Useful for testing. */ -static BOOL do_noop(const pid_t pid, const int argc, char **argv) +static void usage(BOOL doexit) { - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> noop\n"); - return False; + int i; + if (doexit) { + printf("Usage: smbcontrol -i -s configfile\n"); + printf(" smbcontrol <destination> <message-type> <parameters>\n\n"); + } else { + printf("<destination> <message-type> <parameters>\n\n"); } - - /* Move along, nothing to see here */ - - return True; + printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n"); + printf("\t<message-type> is one of:\n"); + for (i=0; msg_types[i].name; i++) + printf("\t\t%s\n", msg_types[i].name); + printf("\n"); + if (doexit) exit(1); } -/* Send a debug string */ - -static BOOL do_debug(const pid_t pid, const int argc, char **argv) +static int pong_count; +static BOOL got_level; +static BOOL got_pool; +static BOOL pong_registered = False; +static BOOL debuglevel_registered = False; +static BOOL poolusage_registered = False; +static BOOL profilelevel_registered = False; + + +/** + * Wait for replies for up to @p *max_secs seconds, or until @p + * max_replies are received. max_replies may be NULL in which case it + * is ignored. + * + * @note This is a pretty lame timeout; all it means is that after + * max_secs we won't look for any more messages. + **/ +static void wait_for_replies(int max_secs, int *max_replies) { - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> debug " - "<debug-string>\n"); - return False; - } + time_t timeout_end = time(NULL) + max_secs; - return send_message( - pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); -} - -/* Force a browser election */ - -static BOOL do_election(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> force-election\n"); - return False; + while ((!max_replies || (*max_replies)-- > 0) + && (time(NULL) < timeout_end)) { + message_dispatch(); } - - return send_message( - pid, MSG_FORCE_ELECTION, NULL, 0, False); } -/* Ping a samba daemon process */ -static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len) +/**************************************************************************** +a useful function for testing the message system +****************************************************************************/ +void pong_function(int msg_type, pid_t src, void *buf, size_t len) { - printf("PONG from pid %u\n", (unsigned int)pid); - num_replies++; + pong_count++; + printf("PONG from PID %u\n",(unsigned int)src); } -static BOOL do_ping(const pid_t pid, const int argc, char **argv) +/**************************************************************************** + Prints out the current talloc list. +****************************************************************************/ +void tallocdump_function(int msg_type, pid_t src, void *buf, size_t len) { - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> ping\n"); - return False; - } - - /* Send a message and register our interest in a reply */ - - if (!send_message(pid, MSG_PING, NULL, 0, False)) - return False; - - message_register(MSG_PONG, pong_cb); - - wait_replies(pid == 0); - - /* No replies were received within the timeout period */ - - if (num_replies == 0) - printf("No replies received\n"); - - message_deregister(MSG_PONG); - - return num_replies; + char *info = (char *)buf; + + printf("Current talloc contexts for process %u\n", (unsigned int)src ); + if (len == 0) + printf("None returned\n"); + else + printf(info); + printf("\n"); + got_pool = True; } -/* Set profiling options */ - -static BOOL do_profile(const pid_t pid, const int argc, char **argv) +/**************************************************************************** +Prints out the current Debug level returned by MSG_DEBUGLEVEL +****************************************************************************/ +void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len) { - int v; - - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> profile " - "<off|count|on|flush>\n"); - return False; - } - - if (strcmp(argv[1], "off") == 0) { - v = 0; - } else if (strcmp(argv[1], "count") == 0) { - v = 1; - } else if (strcmp(argv[1], "on") == 0) { - v = 2; - } else if (strcmp(argv[1], "flush") == 0) { - v = 3; - } else { - fprintf(stderr, "Unknown profile command '%s'\n", argv[1]); - return False; - } + const char *levels = (char *)buf; - return send_message(pid, MSG_PROFILE, &v, sizeof(int), False); + printf("Current debug levels of PID %u are:\n",(unsigned int)src); + printf("%s\n", levels); + + got_level = True; } -/* Return the profiling level */ - -static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len) +/**************************************************************************** +Prints out the current Profile level returned by MSG_PROFILELEVEL +****************************************************************************/ +void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len) { - int level; - const char *s; + int level; + const char *s=NULL; + memcpy(&level, buf, sizeof(int)); - num_replies++; - - if (len != sizeof(int)) { - fprintf(stderr, "invalid message length %d returned\n", len); - return; - } - - memcpy(&level, buf, sizeof(int)); - - switch (level) { - case 0: - s = "not enabled"; - break; - case 1: + if (level) { + switch (level) { + case 1: s = "off"; break; - case 3: + case 3: s = "count only"; break; - case 7: + case 7: s = "count and time"; break; - default: - s = "BOGUS"; - break; + default: + s = "BOGUS"; + break; + } + printf("Profiling %s on PID %u\n",s,(unsigned int)src); + } else { + printf("Profiling not available on PID %u\n",(unsigned int)src); } - - printf("Profiling %s on pid %u\n",s,(unsigned int)pid); + got_level = True; } -static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len) +/** + * Handle reply from POOL_USAGE. + **/ +static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len) { - int v = 0; - - /* Send back a dummy reply */ - - send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False); + printf("Got POOL_USAGE reply from pid%u:\n%.*s", + (unsigned int) src_pid, (int) len, (const char *) buf); } -static BOOL do_profilelevel(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n"); - return False; - } - - /* Send a message and register our interest in a reply */ - - if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False)) - return False; - - message_register(MSG_PROFILELEVEL, profilelevel_cb); - message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst); - wait_replies(pid == 0); - - /* No replies were received within the timeout period */ - - if (num_replies == 0) - printf("No replies received\n"); +/** + * Send a message to a named destination + * + * @return False if an error occurred. + **/ +static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates) +{ + pid_t pid; + /* "smbd" is the only broadcast operation */ + if (strequal(dest,"smbd")) { + TDB_CONTEXT *tdb; + BOOL ret; + int n_sent = 0; + + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0); + if (!tdb) { + fprintf(stderr,"Failed to open connections database in send_message.\n"); + return False; + } - message_deregister(MSG_PROFILE); + ret = message_send_all(tdb,msg_type, buf, len, duplicates, + &n_sent); + DEBUG(10,("smbcontrol/send_message: broadcast message to " + "%d processes\n", n_sent)); + tdb_close(tdb); + + return ret; + } else if (strequal(dest,"nmbd")) { + pid = pidfile_pid(dest); + if (pid == 0) { + fprintf(stderr,"Can't find pid for nmbd\n"); + return False; + } + } else if (strequal(dest,"self")) { + pid = sys_getpid(); + } else { + pid = atoi(dest); + if (pid == 0) { + fprintf(stderr,"Not a valid pid\n"); + return False; + } + } - return num_replies; + DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid)); + return message_send_pid(pid, msg_type, buf, len, duplicates); } -/* Display debug level settings */ - -static BOOL do_debuglevel(const pid_t pid, const int argc, char **argv) +/**************************************************************************** +evaluate a message type string +****************************************************************************/ +static int parse_type(char *mtype) { - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n"); - return False; + int i; + for (i=0;msg_types[i].name;i++) { + if (strequal(mtype, msg_types[i].name)) return msg_types[i].value; } + return -1; +} - /* Send a message and register our interest in a reply */ - if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False)) - return False; +static void register_all(void) +{ + message_register(MSG_POOL_USAGE, pool_usage_cb); +} - message_register(MSG_DEBUGLEVEL, print_string_cb); +/* This guy is here so we can link printing/notify.c to the smbcontrol + binary without having to pull in tons of other crap. */ - wait_replies(pid == 0); +TDB_CONTEXT *conn_tdb_ctx(void) +{ + static TDB_CONTEXT *tdb; - /* No replies were received within the timeout period */ + if (tdb) + return tdb; - if (num_replies == 0) - printf("No replies received\n"); + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0); - message_deregister(MSG_DEBUGLEVEL); + if (!tdb) + DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n")); - return num_replies; + return tdb; } -/* Send a print notify message */ - -static BOOL do_printnotify(const pid_t pid, const int argc, char **argv) +/**************************************************************************** +do command +****************************************************************************/ +static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) { - char *cmd; - - /* Check for subcommand */ - - if (argc == 1) { - fprintf(stderr, "Must specify subcommand:\n"); - fprintf(stderr, "\tqueuepause <printername>\n"); - fprintf(stderr, "\tqueueresume <printername>\n"); - fprintf(stderr, "\tjobpause <printername> <unix jobid>\n"); - fprintf(stderr, "\tjobresume <printername> <unix jobid>\n"); - fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n"); - fprintf(stderr, "\tprinter <printername> <comment|port|" - "driver> <value>\n"); - - return False; + int i, n, v; + int mtype; + BOOL retval=False; + BOOL check_notify_msgs = False; + + mtype = parse_type(msg_name); + if (mtype == -1) { + fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name); + return(False); } - cmd = argv[1]; + switch (mtype) { + case MSG_DEBUG: { + char *buf, *b; + char **p; + int dim = 0; - if (strcmp(cmd, "queuepause") == 0) { - - if (argc != 3) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " queuepause <printername>\n"); - return False; + if (!params || !params[0]) { + fprintf(stderr,"MSG_DEBUG needs a parameter\n"); + return(False); } - - notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED); - goto send; - - } else if (strcmp(cmd, "queueresume") == 0) { - - if (argc != 3) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " queuereume <printername>\n"); - return False; + /* first pass retrieve total lenght */ + for (p = params; p && *p ; p++) + dim += (strnlen(*p, 1024) +1); /* lenght + space */ + b = buf = malloc(dim); + if (!buf) { + fprintf(stderr, "Out of memory!"); + return(False); } - - notify_printer_status_byname(argv[2], PRINTER_STATUS_OK); - - goto send; - - } else if (strcmp(cmd, "jobpause") == 0) { - int jobid; - - if (argc != 4) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " jobpause <printername> <unix-jobid>\n"); - return False; + /* now build a single string with all parameters */ + for(p = params; p && *p; p++) { + int l = strnlen(*p, 1024); + strncpy(b, *p, l); + b[l] = ' '; + b = b + l + 1; } + b[-1] = '\0'; - jobid = atoi(argv[3]); + send_message(dest, MSG_DEBUG, buf, dim, False); - notify_job_status_byname( - argv[2], jobid, JOB_STATUS_PAUSED, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - - goto send; - - } else if (strcmp(cmd, "jobresume") == 0) { - int jobid; + free(buf); + + break; + } - if (argc != 4) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " jobpause <printername> <unix-jobid>\n"); - return False; + case MSG_PROFILE: + if (!params || !params[0]) { + fprintf(stderr,"MSG_PROFILE needs a parameter\n"); + return(False); } - - jobid = atoi(argv[3]); - - notify_job_status_byname( - argv[2], jobid, JOB_STATUS_QUEUED, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - - goto send; - - } else if (strcmp(cmd, "jobdelete") == 0) { - int jobid; - - if (argc != 4) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " jobpause <printername> <unix-jobid>\n"); - return False; + if (strequal(params[0], "off")) { + v = 0; + } else if (strequal(params[0], "count")) { + v = 1; + } else if (strequal(params[0], "on")) { + v = 2; + } else if (strequal(params[0], "flush")) { + v = 3; + } else { + fprintf(stderr, + "MSG_PROFILE parameter must be off, count, on, or flush\n"); + return(False); } + send_message(dest, MSG_PROFILE, &v, sizeof(int), False); + break; - jobid = atoi(argv[3]); - - notify_job_status_byname( - argv[2], jobid, JOB_STATUS_DELETING, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - - notify_job_status_byname( - argv[2], jobid, JOB_STATUS_DELETING| - JOB_STATUS_DELETED, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - - goto send; - - } else if (strcmp(cmd, "printer") == 0) { - uint32 attribute; - - if (argc != 5) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify " - "printer <printername> <comment|port|driver> " - "<value>\n"); - return False; + case MSG_FORCE_ELECTION: + if (!strequal(dest, "nmbd")) { + fprintf(stderr,"force-election can only be sent to nmbd\n"); + return(False); } + send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False); + break; - if (strcmp(argv[3], "comment") == 0) { - attribute = PRINTER_NOTIFY_COMMENT; - } else if (strcmp(argv[3], "port") == 0) { - attribute = PRINTER_NOTIFY_PORT_NAME; - } else if (strcmp(argv[3], "driver") == 0) { - attribute = PRINTER_NOTIFY_DRIVER_NAME; - } else { - fprintf(stderr, "Invalid printer command '%s'\n", - argv[3]); - return False; + case MSG_REQ_PROFILELEVEL: + if (!profilelevel_registered) { + message_register(MSG_PROFILELEVEL, profilelevel_function); + profilelevel_registered = True; } + got_level = False; + retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True); + if (retval) { + timeout_start = time(NULL); + while (!got_level) { + message_dispatch(); + if ((time(NULL) - timeout_start) > MAX_WAIT) { + fprintf(stderr,"profilelevel timeout\n"); + break; + } + } + } + break; - notify_printer_byname(argv[2], attribute, argv[4]); - - goto send; - } - - fprintf(stderr, "Invalid subcommand '%s'\n", cmd); - return False; - -send: - print_notify_send_messages(0); - return True; -} - -/* Close a share */ - -static BOOL do_closeshare(const pid_t pid, const int argc, char **argv) -{ - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> close-share " - "<sharename>\n"); - return False; - } - - return send_message( - pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False); -} - -/* Force a SAM synchronisation */ - -static BOOL do_samsync(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> samsync\n"); - return False; - } - - return send_message( - pid, MSG_SMB_SAM_SYNC, NULL, 0, False); -} - -/* Force a SAM replication */ - -static BOOL do_samrepl(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n"); - return False; - } - - return send_message( - pid, MSG_SMB_SAM_REPL, NULL, 0, False); -} - -/* Display talloc pool usage */ - -static BOOL do_poolusage(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n"); - return False; - } - - /* Send a message and register our interest in a reply */ - - if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False)) - return False; + case MSG_REQ_TALLOC_USAGE: + if (!poolusage_registered) { + message_register(MSG_TALLOC_USAGE, tallocdump_function); + poolusage_registered = True; + } + got_pool = False; + retval = send_message(dest, MSG_REQ_TALLOC_USAGE, NULL, 0, True); + if (retval) { + timeout_start = time(NULL); + while (!got_pool) { + message_dispatch(); + if ((time(NULL) - timeout_start) > MAX_WAIT) { + fprintf(stderr,"tallocdump timeout\n"); + break; + } + } + } + break; - message_register(MSG_POOL_USAGE, print_string_cb); + case MSG_REQ_DEBUGLEVEL: + if (!debuglevel_registered) { + message_register(MSG_DEBUGLEVEL, debuglevel_function); + debuglevel_registered = True; + } + got_level = False; + retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True); + if (retval) { + timeout_start = time(NULL); + while (!got_level) { + message_dispatch(); + if ((time(NULL) - timeout_start) > MAX_WAIT) { + fprintf(stderr,"debuglevel timeout\n"); + break; + } + } + } + break; - wait_replies(pid == 0); + /* Send a notification message to a printer */ - /* No replies were received within the timeout period */ + case MSG_PRINTER_NOTIFY2: { + char *cmd; - if (num_replies == 0) - printf("No replies received\n"); + /* Read subcommand */ - message_deregister(MSG_POOL_USAGE); + if (!params || !params[0]) { + fprintf(stderr, "Must specify subcommand:\n"); + fprintf(stderr, "\tqueuepause <printername>\n"); + fprintf(stderr, "\tqueueresume <printername>\n"); + fprintf(stderr, "\tjobpause <printername> <unix jobid>\n"); + fprintf(stderr, "\tjobresume <printername> <unix jobid>\n"); + fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n"); + fprintf(stderr, "\tprinter <printername> <comment|port|driver> <new value>\n"); + return False; + } - return num_replies; -} + cmd = params[0]; -/* Perform a dmalloc mark */ + check_notify_msgs = True; -static BOOL do_dmalloc_mark(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n"); - return False; - } + /* Pause a print queue */ - return send_message( - pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False); -} + if (strequal(cmd, "queuepause")) { -/* Perform a dmalloc changed */ + if (!params[1]) { + fprintf(stderr, "queuepause command requires a printer name\n"); + return False; + } -static BOOL do_dmalloc_changed(const pid_t pid, const int argc, - char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> " - "dmalloc-log-changed\n"); - return False; - } + notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED); + break; + } - return send_message( - pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False); -} + /* Resume a print queue */ -/* Shutdown a server process */ + if (strequal(cmd, "queueresume")) { -static BOOL do_shutdown(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n"); - return False; - } + if (!params[1]) { + fprintf(stderr, "queueresume command requires a printer name\n"); + return False; + } - return send_message(pid, MSG_SHUTDOWN, NULL, 0, False); -} + notify_printer_status_byname(params[1], PRINTER_STATUS_OK); + break; + } -/* Notify a driver upgrade */ + /* Pause a print job */ -static BOOL do_drvupgrade(const pid_t pid, const int argc, char **argv) -{ - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade " - "<driver-name>\n"); - return False; - } + if (strequal(cmd, "jobpause")) { + int jobid; - return send_message( - pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); -} + if (!params[1] || !params[2]) { + fprintf(stderr, "jobpause command requires a printer name and a jobid\n"); + return False; + } -/* A list of message type supported */ + jobid = atoi(params[2]); -static const struct { - const char *name; /* Option name */ - BOOL (*fn)(const pid_t pid, const int argc, char **argv); - const char *help; /* Short help text */ -} msg_types[] = { - { "debug", do_debug, "Set debuglevel" }, - { "force-election", do_election, - "Force a browse election" }, - { "ping", do_ping, "Elicit a response" }, - { "profile", do_profile, "" }, - { "profilelevel", do_profilelevel, "" }, - { "debuglevel", do_debuglevel, "Display current debuglevels" }, - { "printnotify", do_printnotify, "Send a print notify message" }, - { "close-share", do_closeshare, "Forcibly disconnect a share" }, - { "samsync", do_samsync, "Initiate SAM synchronisation" }, - { "samrepl", do_samrepl, "Initiate SAM replication" }, - { "pool-usage", do_poolusage, "Display talloc memory usage" }, - { "dmalloc-mark", do_dmalloc_mark, "" }, - { "dmalloc-log-changed", do_dmalloc_changed, "" }, - { "shutdown", do_shutdown, "Shut down daemon" }, - { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" }, - { "noop", do_noop, "Do nothing" }, - { NULL } -}; + notify_job_status_byname( + params[1], jobid, JOB_STATUS_PAUSED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + break; + } -/* Yuck - we need these because we link to printing*.o even though - they aren't used. */ + /* Resume a print job */ -void become_root(void) {} -void unbecome_root(void) {} + if (strequal(cmd, "jobresume")) { + int jobid; -/* Display usage information */ + if (!params[1] || !params[2]) { + fprintf(stderr, "jobresume command requires a printer name and a jobid\n"); + return False; + } -static void usage(poptContext *pc) -{ - int i; + jobid = atoi(params[2]); - poptPrintHelp(*pc, stderr, 0); + notify_job_status_byname( + params[1], jobid, JOB_STATUS_QUEUED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + break; + } - fprintf(stderr, "\n"); - fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a " - "process ID\n"); + /* Delete a print job */ - fprintf(stderr, "\n"); - fprintf(stderr, "<message-type> is one of:\n"); + if (strequal(cmd, "jobdelete")) { + int jobid; - for (i = 0; msg_types[i].name; i++) - fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, - msg_types[i].help); + if (!params[1] || !params[2]) { + fprintf(stderr, "jobdelete command requires a printer name and a jobid\n"); + return False; + } - fprintf(stderr, "\n"); + jobid = atoi(params[2]); - exit(1); -} + notify_job_status_byname( + params[1], jobid, JOB_STATUS_DELETING, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); -/* Return the pid number for a string destination */ + notify_job_status_byname( + params[1], jobid, JOB_STATUS_DELETING| + JOB_STATUS_DELETED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + } + + /* printer change notify */ + + if (strequal(cmd, "printer")) { + int attribute = -1; + + if (!params[1] || !params[2] || !params[3]) { + fprintf(stderr, "printer command requires an and attribute name and value!\n"); + fprintf(stderr, "supported attributes:\n"); + fprintf(stderr, "\tcomment:\n"); + fprintf(stderr, "\tport:\n"); + fprintf(stderr, "\tdriver:\n"); + return False; + } + if ( strequal(params[2], "comment") ) + attribute = PRINTER_NOTIFY_COMMENT; + else if ( strequal(params[2], "port") ) + attribute = PRINTER_NOTIFY_PORT_NAME; + else if ( strequal(params[2], "driver") ) + attribute = PRINTER_NOTIFY_DRIVER_NAME; + + if ( attribute == -1 ) { + fprintf(stderr, "bad attribute!\n"); + return False; + } + + notify_printer_byname( params[1], attribute, params[3]); + + break; + } + + break; + } -static pid_t parse_dest(char *dest) -{ - pid_t pid; - /* Zero is a special return value for broadcast smbd */ + case MSG_SMB_FORCE_TDIS: + if (!strequal(dest, "smbd")) { + fprintf(stderr,"close-share can only be sent to smbd\n"); + return(False); + } + if (!params || !params[0]) { + fprintf(stderr, "close-share needs a share name or '*'\n"); + return (False); + } + retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0], + strlen(params[0]) + 1, False); + break; - if (strequal(dest, "smbd")) - return 0; + case MSG_SMB_SAM_SYNC: + if (!strequal(dest, "smbd")) { + fprintf(stderr, "samsync can only be sent to smbd\n"); + return False; + } - /* Try self - useful for testing */ + if (params) { + fprintf(stderr, "samsync does not take any parameters\n"); + return False; + } - if (strequal(dest, "self")) - return sys_getpid(); + retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False); - /* Check for numeric pid number */ + break; - if ((pid = atoi(dest)) != 0) - return pid; + case MSG_SMB_SAM_REPL: { + uint32 seqnum; - /* Look up other destinations in pidfile directory */ + if (!strequal(dest, "smbd")) { + fprintf(stderr, "sam repl can only be sent to smbd\n"); + return False; + } - if ((pid = pidfile_pid(dest)) != 0) - return pid; + if (!params || !params[0]) { + fprintf(stderr, "SAM_REPL needs a parameter\n"); + return False; + } - fprintf(stderr,"Can't find pid for destination '%s'\n", dest); + seqnum = atoi(params[0]); - return -1; -} + retval = send_message(dest, MSG_SMB_SAM_SYNC, + (char *)&seqnum, sizeof(uint32), False); -/* Execute smbcontrol command */ + break; + } -static BOOL do_command(int argc, char **argv) -{ - char *dest = argv[0], *command = argv[1]; - pid_t pid; - int i; + case MSG_PING: + if (!pong_registered) { + message_register(MSG_PONG, pong_function); + pong_registered = True; + } + if (!params || !params[0]) { + fprintf(stderr,"MSG_PING needs a parameter\n"); + return(False); + } + n = atoi(params[0]); + pong_count = 0; + for (i=0;i<n;i++) { + if (iparams > 1) + retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True); + else + retval = send_message(dest, MSG_PING, NULL, 0, True); + if (retval == False) + return False; + } + wait_for_replies(MAX_WAIT, &n); + if (n > 0) { + fprintf(stderr,"PING timeout\n"); + } + break; - /* Check destination */ + case MSG_REQ_POOL_USAGE: + if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True)) + return False; + wait_for_replies(MAX_WAIT, NULL); + + break; - if ((pid = parse_dest(dest)) == -1) - return False; + case MSG_REQ_DMALLOC_LOG_CHANGED: + case MSG_REQ_DMALLOC_MARK: + if (!send_message(dest, mtype, NULL, 0, False)) + return False; + break; - /* Check command */ + case MSG_SHUTDOWN: + if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False)) + return False; + break; + case MSG_PRINTER_DRVUPGRADE: + if (!params || !params[0]) { + fprintf(stderr,"drvupgrade needs a parameter\n"); + return(False); + } - for (i = 0; msg_types[i].name; i++) { - if (strequal(command, msg_types[i].name)) - return msg_types[i].fn(pid, argc - 1, argv + 1); + if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False)) + return False; + break; } - fprintf(stderr, "smbcontrol: unknown command '%s'\n", command); + /* check if we have any pending print notify messages */ - return False; + if ( check_notify_msgs ) + print_notify_send_messages(0); + + return (True); } -/* Main program */ - -int main(int argc, char **argv) + int main(int argc, char *argv[]) { - poptContext pc; int opt; + char temp[255]; + extern int optind; + BOOL interactive = False; - struct poptOption wbinfo_options[] = { - { "timeout", 't', POPT_ARG_INT, &timeout, 't', - "Set timeout value in seconds", "TIMEOUT" }, - - { "configfile", 's', POPT_ARG_STRING, NULL, 's', - "Use alternative configuration file", "CONFIGFILE" }, - - POPT_TABLEEND - }; - - struct poptOption options[] = { - { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, - "Options" }, - - POPT_AUTOHELP - POPT_COMMON_VERSION - POPT_TABLEEND - }; + AllowDebugChange = False; + DEBUGLEVEL = 0; setup_logging(argv[0],True); - /* Parse command line arguments using popt */ - - pc = poptGetContext( - "smbcontrol", argc, (const char **)argv, options, 0); - - poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> " - "<parameters>"); - - if (argc == 1) - usage(&pc); + if (argc < 2) usage(True); - while ((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - case 't': /* --timeout */ - argc -= 2; + while ((opt = getopt(argc, argv,"is:")) != EOF) { + switch (opt) { + case 'i': + interactive = True; break; - case 's': /* --configfile */ + case 's': pstrcpy(dyn_CONFIGFILE, optarg); - argc -= 2; break; default: - fprintf(stderr, "Invalid option\n"); - poptPrintHelp(pc, stderr, 0); - break; + printf("Unknown option %c (%d)\n", (char)opt, opt); + usage(True); } } - /* We should now have the remaining command line arguments in - argv. The argc parameter should have been decremented to the - correct value in the above switch statement. */ + lp_load(dyn_CONFIGFILE,False,False,False); - argv = (char **)poptGetArgs(pc); - argc--; /* Don't forget about argv[0] */ + if (!message_init()) exit(1); - if (argc == 1) - usage(&pc); + argc -= optind; + argv = &argv[optind]; - lp_load(dyn_CONFIGFILE,False,False,False); + register_all(); - /* Need to invert sense of return code -- samba - * routines mostly return True==1 for success, but - * shell needs 0. */ - - return !do_command(argc, argv); + if (!interactive) { + if (argc < 2) usage(True); + /* Need to invert sense of return code -- samba + * routines mostly return True==1 for success, but + * shell needs 0. */ + return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0); + } + + while (True) { + char *myargv[4]; + int myargc; + + printf("smbcontrol> "); + if (!fgets(temp, sizeof(temp)-1, stdin)) break; + myargc = 0; + while ((myargc < 4) && + (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) { + myargc++; + } + if (!myargc) break; + if (strequal(myargv[0],"q")) break; + if (myargc < 2) + usage(False); + else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0)) + usage(False); + } + return(0); } + diff --git a/source3/utils/smbtree.c b/source3/utils/smbtree.c index cbe1bd448f..940120d644 100644 --- a/source3/utils/smbtree.c +++ b/source3/utils/smbtree.c @@ -3,7 +3,6 @@ Network neighbourhood browser. Copyright (C) Tim Potter 2000 - Copyright (C) Jelmer Vernooij 2003 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 @@ -24,11 +23,34 @@ static BOOL use_bcast; +struct user_auth_info { + pstring username; + pstring password; + pstring workgroup; +}; + /* How low can we go? */ enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE}; static enum tree_level level = LEV_SHARE; +static void usage(void) +{ + printf( +"Usage: smbtree [options]\n\ +\n\ +\t-d debuglevel set debug output level\n\ +\t-U username user to autheticate as\n\ +\t-W workgroup workgroup of user to authenticate as\n\ +\t-D list only domains (workgroups) of tree\n\ +\t-S list domains and servers of tree\n\ +\t-b use bcast instead of using the master browser\n\ +\n\ +The username can be of the form username%%password or\n\ +workgroup\\username%%password.\n\n\ +"); +} + /* Holds a list of workgroups or servers */ struct name_list { @@ -65,6 +87,62 @@ static void add_name(const char *machine_name, uint32 server_type, DLIST_ADD(*name_list, new_name); } +/* Return a cli_state pointing at the IPC$ share for the given server */ + +static struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip, + struct user_auth_info *user_info) +{ + struct cli_state *cli; + pstring myname; + NTSTATUS nt_status; + + get_myname(myname); + + nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", + user_info->username, lp_workgroup(), user_info->password, + CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, NULL); + + if (NT_STATUS_IS_OK(nt_status)) { + return cli; + } else { + return NULL; + } +} + +/* Return the IP address and workgroup of a master browser on the + network. */ + +static BOOL find_master_ip_bcast(pstring workgroup, struct in_addr *server_ip) +{ + struct in_addr *ip_list; + int i, count; + + /* Go looking for workgroups by broadcasting on the local network */ + + if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { + return False; + } + + for (i = 0; i < count; i++) { + static fstring name; + + if (!name_status_find("*", 0, 0x1d, ip_list[i], name)) + continue; + + if (!find_master_ip(name, server_ip)) + continue; + + pstrcpy(workgroup, name); + + DEBUG(4, ("found master browser %s, %s\n", + name, inet_ntoa(ip_list[i]))); + + return True; + } + + return False; +} + /**************************************************************************** display tree of smb workgroups, servers and shares ****************************************************************************/ @@ -80,21 +158,19 @@ static BOOL get_workgroups(struct user_auth_info *user_info) pstrcpy(master_workgroup, lp_workgroup()); - if (!use_bcast && !find_master_ip(lp_workgroup(), &server_ip)) { - DEBUG(4, ("Unable to find master browser for workgroup %s, falling back to broadcast\n", + if (use_bcast || !find_master_ip(lp_workgroup(), &server_ip)) { + DEBUG(4, ("Unable to find master browser for workgroup %s\n", master_workgroup)); - use_bcast = True; - } else if(!use_bcast) { - if (!(cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info))) - return False; - } - - if (!(cli = get_ipc_connect_master_ip_bcast(master_workgroup, user_info))) { + if (!find_master_ip_bcast(master_workgroup, &server_ip)) { DEBUG(4, ("Unable to find master browser by " "broadcast\n")); return False; + } } + if (!(cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info))) + return False; + if (!cli_NetServerEnum(cli, master_workgroup, SV_TYPE_DOMAIN_ENUM, add_name, &workgroups)) return False; @@ -191,17 +267,13 @@ static BOOL print_tree(struct user_auth_info *user_info) ****************************************************************************/ int main(int argc,char *argv[]) { - struct poptOption long_options[] = { - POPT_AUTOHELP - { "broadcast", 'b', POPT_ARG_VAL, &use_bcast, True, "Use broadcast instead of using the master browser" }, - { "domains", 'D', POPT_ARG_VAL, &level, LEV_WORKGROUP, "List only domains (workgroups) of tree" }, - { "servers", 'S', POPT_ARG_VAL, &level, LEV_SERVER, "List domains(workgroups) and servers of tree" }, - POPT_COMMON_SAMBA - POPT_COMMON_CREDENTIALS - POPT_TABLEEND - }; - poptContext pc; - + extern char *optarg; + extern int optind; + int opt; + char *p; + struct user_auth_info user_info; + BOOL got_pass = False; + /* Initialise samba stuff */ setlinebuf(stdout); @@ -210,27 +282,86 @@ static BOOL print_tree(struct user_auth_info *user_info) setup_logging(argv[0],True); - pc = poptGetContext("smbtree", argc, (const char **)argv, long_options, - POPT_CONTEXT_KEEP_FIRST); - while(poptGetNextOpt(pc) != -1); - poptFreeContext(pc); - lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); + if (getenv("USER")) { + pstrcpy(user_info.username, getenv("USER")); + + if ((p=strchr(user_info.username, '%'))) { + *p = 0; + pstrcpy(user_info.password, p+1); + got_pass = True; + memset(strchr(getenv("USER"), '%') + 1, 'X', + strlen(user_info.password)); + } + } + + pstrcpy(user_info.workgroup, lp_workgroup()); + /* Parse command line args */ - if (!cmdline_auth_info.got_pass) { + while ((opt = getopt(argc, argv, "U:hd:W:DSb")) != EOF) { + switch (opt) { + case 'U': + pstrcpy(user_info.username,optarg); + p = strchr(user_info.username,'%'); + if (p) { + *p = 0; + pstrcpy(user_info.password, p+1); + got_pass = 1; + } + break; + + case 'b': + use_bcast = True; + break; + + case 'h': + usage(); + exit(1); + + case 'd': + DEBUGLEVEL = atoi(optarg); + break; + + case 'W': + pstrcpy(user_info.workgroup, optarg); + break; + + case 'D': + level = LEV_WORKGROUP; + break; + + case 'S': + level = LEV_SERVER; + break; + + default: + printf("Unknown option %c (%d)\n", (char)opt, opt); + exit(1); + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (!got_pass) { char *pass = getpass("Password: "); if (pass) { - pstrcpy(cmdline_auth_info.password, pass); + pstrcpy(user_info.password, pass); } - cmdline_auth_info.got_pass = True; + got_pass = True; } /* Now do our stuff */ - if (!print_tree(&cmdline_auth_info)) + if (!print_tree(&user_info)) return 1; return 0; diff --git a/source3/utils/status.c b/source3/utils/status.c index 7e87701752..8014b133d9 100644 --- a/source3/utils/status.c +++ b/source3/utils/status.c @@ -559,8 +559,10 @@ static int traverse_sessionid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, vo {"profile", 'P', POPT_ARG_NONE, &profile_only, 'P', "Do profiling" }, #endif /* WITH_PROFILE */ {"byterange", 'B', POPT_ARG_NONE, &show_brl, 'B', "Include byte range locks"}, - POPT_COMMON_SAMBA - POPT_TABLEEND + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug }, + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version}, + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile }, + { 0, 0, 0, 0} }; setup_logging(argv[0],True); diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index e3d6ce0274..ec58f906ed 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -177,21 +177,18 @@ via the %%o substitution. With encrypted passwords this is not possible.\n", lp_ printf("'algorithmic rid base' must be even.\n"); } -#ifndef HAVE_DLOPEN - if (lp_preload_modules()) { - printf("WARNING: 'preload modules = ' set while loading plugins not supported.\n"); - } -#endif - return ret; } - int main(int argc, const char *argv[]) +int main(int argc, const char *argv[]) { + extern char *optarg; + extern int optind; const char *config_file = dyn_CONFIGFILE; int s; static BOOL silent_mode = False; int ret = 0; + int opt; poptContext pc; static const char *term_code = ""; static char *new_local_machine = NULL; @@ -205,15 +202,15 @@ via the %%o substitution. With encrypted passwords this is not possible.\n", lp_ {"verbose", 'v', POPT_ARG_NONE, &show_defaults, 1, "Show default options too"}, {"server", 'L',POPT_ARG_STRING, &new_local_machine, 0, "Set %%L macro to servername\n"}, {"encoding", 't', POPT_ARG_STRING, &term_code, 0, "Print parameters with encoding"}, - POPT_COMMON_VERSION - POPT_TABLEEND + {NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version}, + {0,0,0,0} }; pc = poptGetContext(NULL, argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST); poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]"); - while(poptGetNextOpt(pc) != -1); + while((opt = poptGetNextOpt(pc)) != -1); setup_logging(poptGetArg(pc), True); |