diff options
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/debug2html.c | 253 | ||||
-rw-r--r-- | source3/utils/make_printerdef.c | 585 | ||||
-rw-r--r-- | source3/utils/net.c | 458 | ||||
-rw-r--r-- | source3/utils/net.h | 51 | ||||
-rw-r--r-- | source3/utils/net_ads.c | 787 | ||||
-rw-r--r-- | source3/utils/net_help.c | 126 | ||||
-rw-r--r-- | source3/utils/net_lookup.c | 61 | ||||
-rw-r--r-- | source3/utils/net_rap.c | 1084 | ||||
-rw-r--r-- | source3/utils/net_rpc.c | 1328 | ||||
-rw-r--r-- | source3/utils/net_rpc_join.c | 303 | ||||
-rw-r--r-- | source3/utils/net_time.c | 185 | ||||
-rw-r--r-- | source3/utils/nmblookup.c | 299 | ||||
-rw-r--r-- | source3/utils/pdbedit.c | 692 | ||||
-rw-r--r-- | source3/utils/rpccheck.c | 62 | ||||
-rw-r--r-- | source3/utils/smbcacls.c | 964 | ||||
-rw-r--r-- | source3/utils/smbcontrol.c | 509 | ||||
-rw-r--r-- | source3/utils/smbfilter.c | 246 | ||||
-rw-r--r-- | source3/utils/smbgroupedit.c | 397 | ||||
-rw-r--r-- | source3/utils/smbpasswd.c | 973 | ||||
-rw-r--r-- | source3/utils/smbtree.c | 423 | ||||
-rw-r--r-- | source3/utils/smbw_sample.c | 94 | ||||
-rw-r--r-- | source3/utils/status.c | 846 | ||||
-rw-r--r-- | source3/utils/testparm.c | 295 | ||||
-rw-r--r-- | source3/utils/testprns.c | 22 |
24 files changed, 10259 insertions, 784 deletions
diff --git a/source3/utils/debug2html.c b/source3/utils/debug2html.c new file mode 100644 index 0000000000..f9a1f43f46 --- /dev/null +++ b/source3/utils/debug2html.c @@ -0,0 +1,253 @@ +/* ========================================================================== ** + * debug2html.c + * + * Copyright (C) 1998 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * -------------------------------------------------------------------------- ** + * Parse Samba debug logs (2.0 & greater) and output the results as HTML. + * -------------------------------------------------------------------------- ** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- ** + * This program provides an example of the use of debugparse.c, and also + * does a decent job of converting Samba logs into HTML. + * -------------------------------------------------------------------------- ** + * + * Revision 1.4 1998/11/13 03:37:01 tridge + * fixes for OSF1 compilation + * + * Revision 1.3 1998/10/28 20:33:35 crh + * I've moved the debugparse module files into the ubiqx directory because I + * know that 'make proto' will ignore them there. The debugparse.h header + * file is included in includes.h, and includes.h is included in debugparse.c, + * so all of the pieces "see" each other. I've compiled and tested this, + * and it does seem to work. It's the same compromise model I used when + * adding the ubiqx modules into the system, which is why I put it all into + * the same directory. + * + * Chris -)----- + * + * Revision 1.1 1998/10/26 23:21:37 crh + * Here is the simple debug parser and the debug2html converter. Still to do: + * + * * Debug message filtering. + * * I need to add all this to Makefile.in + * (If it looks at all strange I'll ask for help.) + * + * If you want to compile debug2html, you'll need to do it by hand until I + * make the changes to Makefile.in. Sorry. + * + * Chris -)----- + * + * ========================================================================== ** + */ + +#include "debugparse.h" + +/* -------------------------------------------------------------------------- ** + * The size of the read buffer. + */ + +#define DBG_BSIZE 1024 + +/* -------------------------------------------------------------------------- ** + * Functions... + */ + +static dbg_Token modechange( dbg_Token new, dbg_Token mode ) + /* ------------------------------------------------------------------------ ** + * Handle a switch between header and message printing. + * + * Input: new - The token value of the current token. This indicates + * the lexical item currently being recognized. + * mode - The current mode. This is either dbg_null or + * dbg_message. It could really be any toggle + * (true/false, etc.) + * + * Output: The new mode. This will be the same as the input mode unless + * there was a transition in or out of message processing. + * + * Notes: The purpose of the mode value is to mark the beginning and end + * of the message text block. In order to show the text in its + * correct format, it must be included within a <PRE></PRE> block. + * + * ------------------------------------------------------------------------ ** + */ + { + switch( new ) + { + case dbg_null: + case dbg_ignore: + return( mode ); + case dbg_message: + if( dbg_message != mode ) + { + /* Switching to message mode. */ + (void)printf( "<PRE>\n" ); + return( dbg_message ); + } + break; + default: + if( dbg_message == mode ) + { + /* Switching out of message mode. */ + (void)printf( "</PRE>\n\n" ); + return( dbg_null ); + } + } + + return( mode ); + } /* modechange */ + +static void newblock( dbg_Token old, dbg_Token new ) + /* ------------------------------------------------------------------------ ** + * Handle the transition between tokens. + * + * Input: old - The previous token. + * new - The current token. + * + * Output: none. + * + * Notes: This is called whenever there is a transition from one token + * type to another. It first prints the markup tags that close + * the previous token, and then the markup tags for the new + * token. + * + * ------------------------------------------------------------------------ ** + */ + { + switch( old ) + { + case dbg_timestamp: + (void)printf( ",</B>" ); + break; + case dbg_level: + (void)printf( "</FONT>]</B>\n " ); + break; + case dbg_sourcefile: + (void)printf( ":" ); + break; + case dbg_lineno: + (void)printf( ")" ); + break; + } + + switch( new ) + { + case dbg_timestamp: + (void)printf( "<B>[" ); + break; + case dbg_level: + (void)printf( " <B><FONT COLOR=MAROON>" ); + break; + case dbg_lineno: + (void)printf( "(" ); + break; + } + } /* newblock */ + +static void charprint( dbg_Token tok, int c ) + /* ------------------------------------------------------------------------ ** + * Filter the input characters to determine what goes to output. + * + * Input: tok - The token value of the current character. + * c - The current character. + * + * Output: none. + * + * ------------------------------------------------------------------------ ** + */ + { + switch( tok ) + { + case dbg_ignore: + case dbg_header: + break; + case dbg_null: + case dbg_eof: + (void)putchar( '\n' ); + break; + default: + switch( c ) + { + case '<': + (void)printf( "<" ); + break; + case '>': + (void)printf( ">" ); + break; + case '&': + (void)printf( "&" ); + break; + case '\"': + (void)printf( """ ); + break; + default: + (void)putchar( c ); + break; + } + } + } /* charprint */ + +int main( int argc, char *argv[] ) + /* ------------------------------------------------------------------------ ** + * This simple program scans and parses Samba debug logs, and produces HTML + * output. + * + * Input: argc - Currently ignored. + * argv - Currently ignored. + * + * Output: Always zero. + * + * Notes: The HTML output is sent to stdout. + * + * ------------------------------------------------------------------------ ** + */ + { + int i; + int len; + char bufr[DBG_BSIZE]; + dbg_Token old = dbg_null, + new = dbg_null, + state = dbg_null, + mode = dbg_null; + + (void)printf( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n" ); + (void)printf( "<HTML>\n<HEAD>\n" ); + (void)printf( " <TITLE>Samba Debug Output</TITLE>\n</HEAD>\n\n<BODY>\n" ); + + while( (!feof( stdin )) + && ((len = fread( bufr, 1, DBG_BSIZE, stdin )) > 0) ) + { + for( i = 0; i < len; i++ ) + { + old = new; + new = dbg_char2token( &state, bufr[i] ); + if( new != old ) + { + mode = modechange( new, mode ); + newblock( old, new ); + } + charprint( new, bufr[i] ); + } + } + (void)modechange( dbg_eof, mode ); + + (void)printf( "</BODY>\n</HTML>\n" ); + return( 0 ); + } /* main */ diff --git a/source3/utils/make_printerdef.c b/source3/utils/make_printerdef.c new file mode 100644 index 0000000000..35ecd7f3e9 --- /dev/null +++ b/source3/utils/make_printerdef.c @@ -0,0 +1,585 @@ + /* + Unix SMB/CIFS implementation. + Create printer definition files. + + Copyright (C) Jean-Francois.Micouleau@utc.fr, 10/26/97 - 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* +#define DEBUGIT +*/ + +char *files_to_copy; +char *driverfile, *datafile, *helpfile, *languagemonitor, *datatype, *vendorsetup; +char buffer[50][sizeof(pstring)]; +char sbuffer[50][sizeof(pstring)]; +char sub_dir[50][2][sizeof(pstring)]; + +static void usage(char *name) +{ + fprintf(stderr,"%s: printer.def \"Printer Name\"\n", name); +} + +static char *myfgets(char *s, int n, FILE *stream) +{ + char *LString1; + char *LString2; + char *temp; + pstring String; + pstring NewString; + int i; + + fgets(s,n,stream); + while ((LString1 = strchr_m(s,'%')) != NULL) { + if (!(LString2 = strchr_m(LString1+1,'%'))) break; + *LString2 = '\0'; + pstrcpy(String,LString1+1); + i = 0; + while(*sbuffer[i]!='\0') { + if (strncmp(sbuffer[i],String,strlen(String))==0) + { + pstrcpy(String,sbuffer[i]); + if ((temp = strchr_m(String,'=')) != NULL) ++temp; + pstrcpy(String,temp); + break; + } + i++; + } + *LString1 = '\0'; + pstrcpy(NewString,s); + pstrcat(NewString,String); + pstrcat(NewString,LString2+1); + pstrcpy(s, NewString); + } + return(s); +} + +/* + This function split a line in two parts + on both side of the equal sign + "entry=value" +*/ +static char *scan(char *chaine,char **entry) +{ + char *value; + char *temp; + int i=0; + + *entry=(char *)malloc(sizeof(pstring)); + value=(char *)malloc(sizeof(pstring)); + + if(*entry == NULL || value == NULL) { + fprintf(stderr,"scan: malloc fail !\n"); + exit(1); + } + + pstrcpy(*entry,chaine); + temp=chaine; + while( temp[i]!='=' && temp[i]!='\0') { + i++; + } + (*entry)[i]='\0'; + if (temp[i]!='\0') { + i++; + } + while( temp[i]==' ' && temp[i]!='\0') { + i++; + } + pstrcpy(value,temp+i); + return (value); +} + +static void build_subdir(void) +{ + int i=0; + int j=0; + char *entry; + char *data; + + while (*buffer[i]!='\0') { + data=scan(buffer[i],&entry); +#ifdef DEBUGIT + fprintf(stderr,"\tentry=data %s:%s\n",entry,data); +#endif + j = strlen(entry); + while (j) { + if (entry[j-1] != ' ') break; + j--; + } + entry[j] = '\0'; + + if (strncmp(data,"11",2)==0) { + pstrcpy(sub_dir[i][0],entry); + pstrcpy(sub_dir[i][1],""); + } + if (strncmp(data,"23",2)==0) { + pstrcpy(sub_dir[i][0],entry); + pstrcpy(sub_dir[i][1],"color\\"); + } +#ifdef DEBUGIT + fprintf(stderr,"\tsubdir %s:%s\n",sub_dir[i][0],sub_dir[i][1]); +#endif + i++; + } +} + +/* + Lockup Strings entry in a file + Return all the lines between the entry and the next one or the end of file + An entry is something between braces. +*/ +static void lookup_strings(FILE *fichier) +{ + int found=0,pointeur=0,i=0; + char *temp,*temp2; + + temp=(char *)malloc(sizeof(pstring)); + temp2=(char *)malloc(sizeof(pstring)); + + if(temp == NULL || temp2 == NULL) { + SAFE_FREE(temp); + SAFE_FREE(temp2); + fprintf(stderr,"lookup_strings: malloc fail !\n"); + exit(1); + } + + *sbuffer[0]='\0'; + + pstrcpy(temp2,"[Strings]"); + + rewind(fichier); +#ifdef DEBUGIT + fprintf(stderr,"\tLooking for Strings\n"); +#endif + + while (!feof(fichier) && found==0) { + *temp='\0'; + fgets(temp,255,fichier); + if (strncmp(temp,temp2,strlen(temp2))==0) found=1; + } + + + while (!feof(fichier) && found==1) { + *temp='\0'; + fgets(temp,255,fichier); + if (*temp=='[') { + found=2; + *sbuffer[pointeur]='\0'; + } + else { + pstrcpy(sbuffer[pointeur],temp); + i=strlen(sbuffer[pointeur])-1; + while (sbuffer[pointeur][i]=='\r' || sbuffer[pointeur][i]=='\n') + sbuffer[pointeur][i--]='\0'; + pointeur++; + } + } + + /* CCMRCF Mod, seg fault or worse if not found */ + if (pointeur == 0) { + fprintf(stderr,"Printer not found\tNo [Strings] block in inf file\n"); + exit(2); + } + +#ifdef DEBUGIT + fprintf(stderr,"\t\tFound %d entries\n",pointeur-1); +#endif +} + + +/* + Lockup an entry in a file + Return all the lines between the entry and the next one or the end of file + An entry is something between braces. +*/ +static void lookup_entry(FILE *fichier,char *chaine) +{ + int found=0,pointeur=0,i=0; + char *temp,*temp2; + + temp=(char *)malloc(sizeof(pstring)); + temp2=(char *)malloc(sizeof(pstring)); + + if(temp == NULL || temp2 == NULL) { + SAFE_FREE(temp); + SAFE_FREE(temp2); + fprintf(stderr,"lookup_entry: malloc fail !\n"); + exit(1); + } + + *buffer[0]='\0'; + + pstrcpy(temp2,"["); + pstrcat(temp2,chaine); + pstrcat(temp2,"]"); + + rewind(fichier); +#ifdef DEBUGIT + fprintf(stderr,"\tLooking for %s\n",chaine); +#endif + + while (!feof(fichier) && found==0) { + *temp='\0'; + myfgets(temp,255,fichier); + if (strncmp(temp,temp2,strlen(temp2))==0) found=1; + } + + + while (!feof(fichier) && found==1) { + *temp='\0'; + myfgets(temp,255,fichier); + if (*temp=='[') { + found=2; + *buffer[pointeur]='\0'; + } + else { + pstrcpy(buffer[pointeur],temp); + i=strlen(buffer[pointeur])-1; + while (buffer[pointeur][i]=='\r' || buffer[pointeur][i]=='\n') + buffer[pointeur][i--]='\0'; + pointeur++; + } + } +#ifdef DEBUGIT + fprintf(stderr,"\t\tFound %d entries\n",pointeur-1); +#endif +} + +static char *find_desc(FILE *fichier,char *text) +{ + char *chaine; + char *long_desc; + char *short_desc; + char *crap = NULL; + char *p; + + int found=0; + + chaine=(char *)malloc(sizeof(pstring)); + long_desc=(char *)malloc(sizeof(pstring)); + short_desc=(char *)malloc(sizeof(pstring)); + if (!chaine || !long_desc || !short_desc) { + SAFE_FREE(chaine); + SAFE_FREE(long_desc); + SAFE_FREE(short_desc); + fprintf(stderr,"find_desc: Unable to malloc memory\n"); + exit(1); + } + + rewind(fichier); + while (!feof(fichier) && found==0) + { + myfgets(chaine,255,fichier); + + long_desc=strtok(chaine,"="); + crap=strtok(NULL,",\r"); + + p=long_desc; + while(*p!='"' && *p!='\0') + p++; + if (*p=='"' && *(p+1)!='\0') p++; + long_desc=p; + + if (*p!='\0') + { + p++; + while(*p!='\"') + p++; + *p='\0'; + } + if (!strcmp(text,long_desc)) + found=1; + } + SAFE_FREE(chaine); + if (!found || !crap) return(NULL); + while(*crap==' ') crap++; + pstrcpy(short_desc,crap); + return(short_desc); +} + +static void scan_copyfiles(FILE *fichier, char *chaine) +{ + char *part; + char *mpart; + int i; + pstring direc; +#ifdef DEBUGIT + fprintf(stderr,"In scan_copyfiles Lookup up of %s\n",chaine); +#endif + fprintf(stderr,"\nCopy the following files to your printer$ share location:\n"); + part=strtok(chaine,","); + do { + /* If the entry start with a @ then it's a file to copy + else it's an entry refering to files to copy + the main difference is when it's an entry + you can have a directory to append before the file name + */ + if (*part=='@') { + if (strlen(files_to_copy) != 0) + pstrcat(files_to_copy,","); + pstrcat(files_to_copy,&part[1]); + fprintf(stderr,"%s\n",&part[1]); + } else { + lookup_entry(fichier,part); + i=0; + pstrcpy(direc,""); + while (*sub_dir[i][0]!='\0') { +#ifdef DEBUGIT + fprintf(stderr,"\tsubdir %s:%s\n",sub_dir[i][0],sub_dir[i][1]); +#endif + if (strcmp(sub_dir[i][0],part)==0) + pstrcpy(direc,sub_dir[i][1]); + i++; + } + i=0; + while (*buffer[i]!='\0') { +/* + * HP inf files have strange entries that this attempts to address + * Entries in the Copy sections normally have only a single file name + * on each line. I have seen the following format in various HP inf files: + * + * pscript.hlp = pscript.hl_ + * hpdcmon.dll,hpdcmon.dl_ + * MSVCRT.DLL,MSVCRT.DL_,,32 + * ctl3dv2.dll,ctl3dv2.dl_,ctl3dv2.tmp + * + * In the first 2 cases you want the first file name - in the last case + * you only want the last file name (at least that is what a Win95 + * machine sent). In the third case you also want the first file name + * (detect by the last component being just a number ?). + * This may still be wrong but at least I get the same list + * of files as seen on a printer test page. + */ + part = strchr_m(buffer[i],'='); + if (part) { + /* + * Case (1) eg. pscript.hlp = pscript.hl_ - chop after the first name. + */ + + *part = '\0'; + + /* + * Now move back to the start and print that. + */ + + while (--part > buffer[i]) { + if ((*part == ' ') || (*part =='\t')) + *part = '\0'; + else + break; + } + } else { + part = strchr_m(buffer[i],','); + if (part) { + /* + * Cases (2-4) + */ + + if ((mpart = strrchr_m(part+1,','))!=NULL) { + /* + * Second ',' - case 3 or 4. + * Check if the last part is just a number, + * if so we need the first part. + */ + + char *endptr = NULL; + BOOL isnumber = False; + + mpart++; + (void)strtol(mpart, &endptr, 10); + + isnumber = ((endptr > mpart) && isdigit(*mpart)); + if(!isnumber) + pstrcpy(buffer[i],mpart+1); + else + *part = '\0'; + } else { + *part = '\0'; + } + while (--part > buffer[i]) + if ((*part == ' ') || (*part =='\t')) *part = '\0'; + else break; + } + } + if (*buffer[i] != ';') { + if (strlen(files_to_copy) != 0) + pstrcat(files_to_copy,","); + pstrcat(files_to_copy,direc); + pstrcat(files_to_copy,buffer[i]); + fprintf(stderr,"%s%s\n",direc,buffer[i]); + } + i++; + } /* end while */ + } + part=strtok(NULL,","); + if (part) { + while( *part ==' ' && *part != '\0') { + part++; + } + } + } while (part!=NULL); + fprintf(stderr,"\n"); +} + + +static void scan_short_desc(FILE *fichier, char *short_desc) +{ + int i=0; + char *temp; + char *copyfiles=0,*datasection=0; + + helpfile=0; + languagemonitor=0; + vendorsetup=0; + datatype="RAW"; + if((temp=(char *)malloc(sizeof(pstring))) == NULL) { + fprintf(stderr, "scan_short_desc: malloc fail !\n"); + exit(1); + } + + driverfile=short_desc; + datafile=short_desc; + + lookup_entry(fichier,short_desc); + + while(*buffer[i]!='\0') { +#ifdef DEBUGIT + fprintf(stderr,"\tLookup up of %s\n",buffer[i]); +#endif + if (strncasecmp(buffer[i],"CopyFiles",9)==0) + copyfiles=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DataSection",11)==0) + datasection=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DataFile",8)==0) + datafile=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DriverFile",10)==0) + driverfile=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"HelpFile",8)==0) + helpfile=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"LanguageMonitor",15)==0) + languagemonitor=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DefaultDataType",15)==0) + datatype=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"VendorSetup",11)==0) + vendorsetup=scan(buffer[i],&temp); + i++; + } + + if (datasection) { + lookup_entry(fichier,datasection); + + i = 0; + while(*buffer[i]!='\0') { +#ifdef DEBUGIT + fprintf(stderr,"\tLookup up of %s\n",buffer[i]); +#endif + if (strncasecmp(buffer[i],"CopyFiles",9)==0) + copyfiles=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DataSection",11)==0) + datasection=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DataFile",8)==0) + datafile=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DriverFile",10)==0) + driverfile=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"HelpFile",8)==0) + helpfile=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"LanguageMonitor",15)==0) + languagemonitor=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"DefaultDataType",15)==0) + datatype=scan(buffer[i],&temp); + else if (strncasecmp(buffer[i],"VendorSetup",11)==0) + vendorsetup=scan(buffer[i],&temp); + i++; + } + } + + if (languagemonitor) { + temp = strtok(languagemonitor,","); + if (*temp == '"') ++temp; + pstrcpy(languagemonitor,temp); + if ((temp = strchr_m(languagemonitor,'"'))!=NULL) *temp = '\0'; + } + + if (i) fprintf(stderr,"End of section found\n"); + + fprintf(stderr,"CopyFiles: %s\n", + copyfiles?copyfiles:"(null)"); + fprintf(stderr,"Datasection: %s\n", + datasection?datasection:"(null)"); + fprintf(stderr,"Datafile: %s\n", + datafile?datafile:"(null)"); + fprintf(stderr,"Driverfile: %s\n", + driverfile?driverfile:"(null)"); + fprintf(stderr,"Helpfile: %s\n", + helpfile?helpfile:"(null)"); + fprintf(stderr,"LanguageMonitor: %s\n", + languagemonitor?languagemonitor:"(null)"); + fprintf(stderr,"VendorSetup: %s\n", + vendorsetup?vendorsetup:"(null)"); + if (copyfiles) scan_copyfiles(fichier,copyfiles); +} + +int main(int argc, char *argv[]) +{ + char *short_desc; + FILE *inf_file; + + if (argc!=3) + { + usage(argv[0]); + return(-1); + } + + inf_file=sys_fopen(argv[1],"r"); + if (!inf_file) + { + fprintf(stderr,"Description file not found, bye\n"); + return(-1); + } + + lookup_strings(inf_file); + + short_desc=find_desc(inf_file,argv[2]); + if (short_desc==NULL) + { + fprintf(stderr,"Printer not found\n"); + return(-1); + } + else fprintf(stderr,"Found:%s\n",short_desc); + + lookup_entry(inf_file,"DestinationDirs"); + build_subdir(); + + if((files_to_copy=(char *)malloc(2048*sizeof(char))) == NULL) { + fprintf(stderr, "%s: malloc fail.\n", argv[0] ); + exit(1); + } + *files_to_copy='\0'; + scan_short_desc(inf_file,short_desc); + fprintf(stdout,"%s:%s:%s:", + argv[2],driverfile,datafile); + fprintf(stdout,"%s:", + helpfile?helpfile:""); + fprintf(stdout,"%s:", + languagemonitor?languagemonitor:""); + fprintf(stdout,"%s:",datatype); + fprintf(stdout,"%s\n",files_to_copy); + return 0; +} + diff --git a/source3/utils/net.c b/source3/utils/net.c new file mode 100644 index 0000000000..b81e37c0af --- /dev/null +++ b/source3/utils/net.c @@ -0,0 +1,458 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2001 Steve French (sfrench@us.ibm.com) + Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com) + Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) + Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) + + Originally written by Steve and Jim. Largely rewritten by tridge in + November 2001. + + Reworked again by abartlet in December 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*****************************************************/ +/* */ +/* Distributed SMB/CIFS Server Management Utility */ +/* */ +/* The intent was to make the syntax similar */ +/* to the NET utility (first developed in DOS */ +/* with additional interesting & useful functions */ +/* added in later SMB server network operating */ +/* systems). */ +/* */ +/*****************************************************/ + +#include "includes.h" +#include "../utils/net.h" + +/***********************************************************************/ +/* Beginning of internationalization section. Translatable constants */ +/* should be kept in this area and referenced in the rest of the code. */ +/* */ +/* No functions, outside of Samba or LSB (Linux Standards Base) should */ +/* be used (if possible). */ +/***********************************************************************/ + +#define YES_STRING "Yes" +#define NO_STRING "No" + +/************************************************************************************/ +/* end of internationalization section */ +/************************************************************************************/ + +/* Yes, these buggers are globals.... */ +char *opt_requester_name = NULL; +char *opt_host = NULL; +char *opt_password = NULL; +char *opt_user_name = NULL; +BOOL opt_user_specified = False; +char *opt_workgroup = NULL; +int opt_long_list_entries = 0; +int opt_reboot = 0; +int opt_force = 0; +int opt_port = 0; +int opt_maxusers = -1; +char *opt_comment = ""; +int opt_flags = -1; +int opt_jobid = 0; +int opt_timeout = 0; +char *opt_target_workgroup = NULL; + +BOOL opt_have_ip = False; +struct in_addr opt_dest_ip; + +extern pstring global_myname; + +/* + run a function from a function table. If not found then + call the specified usage function +*/ +int net_run_function(int argc, const char **argv, struct functable *table, + int (*usage_fn)(int argc, const char **argv)) +{ + int i; + + if (argc < 1) { + d_printf("\nUsage: \n"); + return usage_fn(argc, argv); + } + for (i=0; table[i].funcname; i++) { + if (StrCaseCmp(argv[0], table[i].funcname) == 0) + return table[i].fn(argc-1, argv+1); + } + d_printf("No command: %s\n", argv[0]); + return usage_fn(argc, argv); +} + + +/**************************************************************************** +connect to \\server\ipc$ +****************************************************************************/ +NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, + const char *server_name) +{ + NTSTATUS nt_status; + + if (!opt_password) { + char *pass = getpass("Password:"); + if (pass) { + opt_password = strdup(pass); + } + } + + nt_status = cli_full_connection(c, opt_requester_name, server_name, + server_ip, opt_port, + "IPC$", "IPC", + opt_user_name, opt_workgroup, + opt_password, strlen(opt_password)); + + if (NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } else { + DEBUG(1,("Cannot connect to server. Error was %s\n", + nt_errstr(nt_status))); + + /* Display a nicer message depending on the result */ + + if (NT_STATUS_V(nt_status) == + NT_STATUS_V(NT_STATUS_LOGON_FAILURE)) + d_printf("The username or password was not correct.\n"); + + return nt_status; + } +} + +/**************************************************************************** +connect to \\server\ipc$ anonymously +****************************************************************************/ +NTSTATUS connect_to_ipc_anonymous(struct cli_state **c, + struct in_addr *server_ip, const char *server_name) +{ + NTSTATUS nt_status; + + nt_status = cli_full_connection(c, opt_requester_name, server_name, + server_ip, opt_port, + "IPC$", "IPC", + "", "", + "", 0); + + if (NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } else { + DEBUG(1,("Cannot connect to server (anonymously). Error was %s\n", nt_errstr(nt_status))); + return nt_status; + } +} + +BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name) +{ + + if (opt_host) { + *server_name = strdup(opt_host); + } + + if (opt_have_ip) { + *server_ip = opt_dest_ip; + if (!*server_name) { + *server_name = strdup(inet_ntoa(opt_dest_ip)); + } + } else if (*server_name) { + /* resolve the IP address */ + if (!resolve_name(*server_name, server_ip, 0x20)) { + DEBUG(1,("Unable to resolve server name\n")); + return False; + } + } else if (flags & NET_FLAGS_PDC) { + struct in_addr *ip_list; + int addr_count; + if (get_dc_list(True /* PDC only*/, opt_target_workgroup, &ip_list, &addr_count)) { + fstring dc_name; + if (addr_count < 1) { + return False; + } + + *server_ip = *ip_list; + + if (is_zero_ip(*server_ip)) + return False; + + if (!lookup_dc_name(global_myname, opt_target_workgroup, server_ip, dc_name)) + return False; + + *server_name = strdup(dc_name); + } + + } else if (flags & NET_FLAGS_DMB) { + struct in_addr msbrow_ip; + /* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */ + if (!resolve_name(opt_target_workgroup, &msbrow_ip, 0x1B)) { + DEBUG(1,("Unable to resolve domain browser via name lookup\n")); + return False; + } else { + *server_ip = msbrow_ip; + } + *server_name = strdup(inet_ntoa(opt_dest_ip)); + } else if (flags & NET_FLAGS_MASTER) { + struct in_addr brow_ips; + if (!resolve_name(opt_target_workgroup, &brow_ips, 0x1D)) { + /* go looking for workgroups */ + DEBUG(1,("Unable to resolve master browser via name lookup\n")); + return False; + } else { + *server_ip = brow_ips; + } + *server_name = strdup(inet_ntoa(opt_dest_ip)); + } else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) { + extern struct in_addr loopback_ip; + *server_ip = loopback_ip; + *server_name = strdup("127.0.0.1"); + } + + if (!server_name || !*server_name) { + DEBUG(1,("no server to connect to\n")); + return False; + } + + return True; +} + + +BOOL net_find_dc(struct in_addr *server_ip, fstring server_name, char *domain_name) +{ + struct in_addr *ip_list; + int addr_count; + + if (get_dc_list(True /* PDC only*/, domain_name, &ip_list, &addr_count)) { + fstring dc_name; + if (addr_count < 1) { + return False; + } + + *server_ip = *ip_list; + + if (is_zero_ip(*server_ip)) + return False; + + if (!lookup_dc_name(global_myname, domain_name, server_ip, dc_name)) + return False; + + safe_strcpy(server_name, dc_name, FSTRING_LEN); + return True; + } else + return False; +} + + +struct cli_state *net_make_ipc_connection(unsigned flags) +{ + char *server_name = NULL; + struct in_addr server_ip; + struct cli_state *cli = NULL; + NTSTATUS nt_status; + + if (!net_find_server(flags, &server_ip, &server_name)) { + d_printf("\nUnable to find a suitable server\n"); + return NULL; + } + + if (flags & NET_FLAGS_ANONYMOUS) { + nt_status = connect_to_ipc_anonymous(&cli, &server_ip, server_name); + } else { + nt_status = connect_to_ipc(&cli, &server_ip, server_name); + } + SAFE_FREE(server_name); + return cli; +} + + + +static int net_user(int argc, const char **argv) +{ + if (net_ads_check() == 0) + return net_ads_user(argc, argv); + + /* if server is not specified, default to PDC? */ + if (net_rpc_check(NET_FLAGS_PDC)) + return net_rpc_user(argc, argv); + + return net_rap_user(argc, argv); +} + + +static int net_join(int argc, const char **argv) +{ + if (net_ads_check() == 0) { + if (net_ads_join(argc, argv) == 0) + return 0; + else + d_printf("ADS join did not work, trying RPC...\n"); + } + return net_rpc_join(argc, argv); +} + +/* main function table */ +static struct functable net_func[] = { + {"RPC", net_rpc}, + {"RAP", net_rap}, + {"ADS", net_ads}, + + /* eventually these should auto-choose the transport ... */ + {"FILE", net_rap_file}, + {"SHARE", net_rap_share}, + {"SESSION", net_rap_session}, + {"SERVER", net_rap_server}, + {"DOMAIN", net_rap_domain}, + {"PRINTQ", net_rap_printq}, + {"USER", net_user}, + {"GROUP", net_rap_group}, + {"VALIDATE", net_rap_validate}, + {"GROUPMEMBER", net_rap_groupmember}, + {"ADMIN", net_rap_admin}, + {"SERVICE", net_rap_service}, + {"PASSWORD", net_rap_password}, + {"TIME", net_time}, + {"LOOKUP", net_lookup}, + {"JOIN", net_join}, + + {"HELP", net_help}, + {NULL, NULL} +}; + + +/**************************************************************************** + main program +****************************************************************************/ + int main(int argc, const char **argv) +{ + int opt,i; + char *p; + int rc = 0; + int argc_new = 0; + const char ** argv_new; + poptContext pc; + static char *servicesf = dyn_CONFIGFILE; + static int debuglevel = 0; + + 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}, + {"debug", 'd', POPT_ARG_INT, &debuglevel}, + {"debuglevel", 'd', POPT_ARG_INT, &debuglevel}, + {"server", 'S', POPT_ARG_STRING, &opt_host}, + {"comment", 'C', POPT_ARG_STRING, &opt_comment}, + {"maxusers", 'M', POPT_ARG_INT, &opt_maxusers}, + {"flags", 'F', POPT_ARG_INT, &opt_flags}, + {"jobid", 'j', POPT_ARG_INT, &opt_jobid}, + {"long", 'l', POPT_ARG_NONE, &opt_long_list_entries}, + {"reboot", 'r', POPT_ARG_NONE, &opt_reboot}, + {"force", 'f', POPT_ARG_NONE, &opt_force}, + {"timeout", 't', POPT_ARG_INT, &opt_timeout}, + { 0, 0, 0, 0} + }; + + zero_ip(&opt_dest_ip); + + dbf = x_stderr; + + pc = poptGetContext(NULL, argc, (const char **) argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case 'h': + net_help(argc, argv); + exit(0); + break; + case 'I': + opt_dest_ip = *interpret_addr2(poptGetOptArg(pc)); + if (is_zero_ip(opt_dest_ip)) + d_printf("\nInvalid ip address specified\n"); + else + opt_have_ip = True; + break; + case 'U': + opt_user_specified = True; + opt_user_name = strdup(opt_user_name); + p = strchr(opt_user_name,'%'); + if (p) { + *p = 0; + opt_password = p+1; + } + break; + default: + d_printf("\nInvalid option %c (%d)\n", (char)opt, opt); + net_help(argc, argv); + } + } + + lp_load(servicesf,True,False,False); + + DEBUGLEVEL = debuglevel; + + argv_new = (const char **)poptGetArgs(pc); + + argc_new = argc; + for (i=0; i<argc; i++) { + if (argv_new[i] == NULL) { + argc_new = i; + break; + } + } + + if (!opt_requester_name) { + static fstring myname; + get_myname(myname); + opt_requester_name = myname; + } + + if (!opt_user_name && getenv("LOGNAME")) { + opt_user_name = getenv("LOGNAME"); + } + + if (!opt_workgroup) { + opt_workgroup = lp_workgroup(); + } + + if (!opt_target_workgroup) { + opt_target_workgroup = lp_workgroup(); + } + + if (!*global_myname) { + char *p2; + + fstrcpy(global_myname, myhostname()); + p2 = strchr_m(global_myname, '.'); + if (p2) + *p2 = 0; + } + + strupper(global_myname); + + load_interfaces(); + + rc = net_run_function(argc_new-1, argv_new+1, net_func, net_help); + + DEBUG(2,("return code = %d\n", rc)); + return rc; +} diff --git a/source3/utils/net.h b/source3/utils/net.h new file mode 100644 index 0000000000..af6f153f7b --- /dev/null +++ b/source3/utils/net.h @@ -0,0 +1,51 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define NET_FLAGS_MASTER 1 +#define NET_FLAGS_DMB 2 + +/* Would it be insane to set 'localhost' as the default + remote host for this operation? + + For example, localhost is insane for a 'join' operation. +*/ +#define NET_FLAGS_LOCALHOST_DEFAULT_INSANE 4 + +/* We want to find the PDC only */ +#define NET_FLAGS_PDC 8 + +/* We want an anonymous connection */ +#define NET_FLAGS_ANONYMOUS 16 + + +extern int opt_maxusers; +extern char *opt_comment; +extern int opt_flags; + +extern char *opt_comment; + +extern char *opt_target_workgroup; +extern int opt_long_list_entries; +extern int opt_reboot; +extern int opt_force; +extern int opt_timeout; +extern char *opt_host; +extern char *opt_user_name; +extern char *opt_password; +extern BOOL opt_user_specified; diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c new file mode 100644 index 0000000000..68fa89ea35 --- /dev/null +++ b/source3/utils/net_ads.c @@ -0,0 +1,787 @@ +/* + Samba Unix/Linux SMB client library + net ads commands + Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) + Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com) + Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "../utils/net.h" + +#ifdef HAVE_ADS + +int net_ads_usage(int argc, const char **argv) +{ + d_printf( +"\nnet ads join <org_unit>"\ +"\n\tjoins the local machine to a ADS realm\n"\ +"\nnet ads leave"\ +"\n\tremoves the local machine from a ADS realm\n"\ +"\nnet ads user"\ +"\n\tlist users in the realm\n"\ +"\nnet ads group"\ +"\n\tlist groups in the realm\n"\ +"\nnet ads info"\ +"\n\tshows some info on the server\n"\ +"\nnet ads status"\ +"\n\tdump the machine account details to stdout\n" +"\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\ +"\n\tchange a user's password using an admin account" +"\n\t(note: use realm in UPPERCASE)\n" +"\nnet ads chostpass" +"\n\tchange the trust account password of this machine in the AD tree\n" +"\nnet ads printer [info | publish | remove] <printername> <servername>" +"\n\t lookup, add, or remove directory entry for a printer\n" + ); + return -1; +} + + +static int net_ads_info(int argc, const char **argv) +{ + ADS_STRUCT *ads; + + ads = ads_init(NULL, opt_host, NULL, NULL); + ads_connect(ads); + + if (!ads) { + d_printf("Didn't find the ldap server!\n"); + return -1; + } + + d_printf("LDAP server: %s\n", ads->ldap_server); + d_printf("LDAP server name: %s\n", ads->ldap_server_name); + d_printf("Realm: %s\n", ads->realm); + d_printf("Bind Path: %s\n", ads->bind_path); + d_printf("LDAP port: %d\n", ads->ldap_port); + + return 0; +} + + +static ADS_STRUCT *ads_startup(void) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + BOOL need_password = False; + BOOL second_time = False; + + ads = ads_init(NULL, opt_host, NULL, NULL); + + if (!opt_user_name) { + opt_user_name = "administrator"; + } + + if (opt_user_specified) + need_password = True; + +retry: + if (!opt_password && need_password) { + char *prompt; + asprintf(&prompt,"%s password: ", opt_user_name); + opt_password = getpass(prompt); + free(prompt); + } + + if (opt_password) + ads->password = strdup(opt_password); + + ads->user_name = strdup(opt_user_name); + + status = ads_connect(ads); + if (!ADS_ERR_OK(status)) { + if (!need_password && !second_time) { + need_password = True; + second_time = True; + goto retry; + } else { + DEBUG(1,("ads_connect: %s\n", ads_errstr(status))); + return NULL; + } + } + return ads; +} + + +/* + Check to see if connection can be made via ads. + ads_startup() stores the password in opt_password if it needs to so + that rpc or rap can use it without re-prompting. +*/ +int net_ads_check(void) +{ + ADS_STRUCT *ads; + + ads = ads_startup(); + if (!ads) + return -1; + ads_destroy(&ads); + return 0; +} + + +static void usergrp_display(char *field, void **values, void *data_area) +{ + char **disp_fields = (char **) data_area; + + if (!field) { /* must be end of record */ + if (!strchr_m(disp_fields[0], '$')) { + if (disp_fields[1]) + printf("%-21.21s %-50.50s\n", + disp_fields[0], disp_fields[1]); + else + printf("%-21.21s\n", disp_fields[0]); + } + SAFE_FREE(disp_fields[0]); + SAFE_FREE(disp_fields[1]); + return; + } + if (StrCaseCmp(field, "sAMAccountName") == 0) { + disp_fields[0] = strdup(((struct berval *) values[0])->bv_val); + } + if (StrCaseCmp(field, "description") == 0) + disp_fields[1] = strdup(((struct berval *) values[0])->bv_val); +} + +static int net_ads_user_usage(int argc, const char **argv) +{ + return net_help_user(argc, argv); +} + +static int ads_user_add(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + void *res=NULL; + int rc = -1; + + if (argc < 1) return net_ads_user_usage(argc, argv); + + if (!(ads = ads_startup())) return -1; + + status = ads_find_user_acct(ads, &res, argv[0]); + + if (!ADS_ERR_OK(status)) { + d_printf("ads_user_add: %s\n", ads_errstr(status)); + goto done; + } + + if (ads_count_replies(ads, res)) { + d_printf("ads_user_add: User %s already exists\n", argv[0]); + ads_msgfree(ads, res); + goto done; + } + + status = ads_add_user_acct(ads, argv[0], opt_comment); + + if (ADS_ERR_OK(status)) { + d_printf("User %s added\n", argv[0]); + rc = 0; + } else { + d_printf("Could not add user %s: %s\n", argv[0], + ads_errstr(status)); + } + + done: + if (res) + ads_msgfree(ads, res); + ads_destroy(&ads); + return rc; +} + +static int ads_user_info(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + void *res; + const char *attrs[] = {"memberOf", NULL}; + char *searchstring=NULL; + char **grouplist; + + if (argc < 1) return net_ads_user_usage(argc, argv); + + if (!(ads = ads_startup())) return -1; + + asprintf(&searchstring, "(sAMAccountName=%s)", argv[0]); + rc = ads_search(ads, &res, searchstring, attrs); + safe_free(searchstring); + + if (!ADS_ERR_OK(rc)) { + d_printf("ads_search: %s\n", ads_errstr(rc)); + return -1; + } + + grouplist = ldap_get_values(ads->ld, res, "memberOf"); + + if (grouplist) { + int i; + char **groupname; + for (i=0;grouplist[i];i++) { + groupname = ldap_explode_dn(grouplist[i], 1); + printf("%s\n", groupname[0]); + ldap_value_free(groupname); + } + ldap_value_free(grouplist); + } + + ads_msgfree(ads, res); + + ads_destroy(&ads); + return 0; +} + +static int ads_user_delete(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + void *res; + char *userdn; + + if (argc < 1) return net_ads_user_usage(argc, argv); + + if (!(ads = ads_startup())) return -1; + + rc = ads_find_user_acct(ads, &res, argv[0]); + if (!ADS_ERR_OK(rc)) { + DEBUG(0, ("User %s does not exist\n", argv[0])); + return -1; + } + userdn = ads_get_dn(ads, res); + ads_msgfree(ads, res); + rc = ads_del_dn(ads, userdn); + ads_memfree(ads, userdn); + if (!ADS_ERR_OK(rc)) { + d_printf("User %s deleted\n", argv[0]); + return 0; + } + d_printf("Error deleting user %s: %s\n", argv[0], + ads_errstr(rc)); + return -1; +} + +int net_ads_user(int argc, const char **argv) +{ + struct functable func[] = { + {"ADD", ads_user_add}, + {"INFO", ads_user_info}, + {"DELETE", ads_user_delete}, + {NULL, NULL} + }; + ADS_STRUCT *ads; + ADS_STATUS rc; + const char *shortattrs[] = {"sAMAccountName", NULL}; + const char *longattrs[] = {"sAMAccountName", "description", NULL}; + char *disp_fields[2] = {NULL, NULL}; + + if (argc == 0) { + if (!(ads = ads_startup())) return -1; + + if (opt_long_list_entries) + d_printf("\nUser name Comment"\ + "\n-----------------------------\n"); + + rc = ads_do_search_all_fn(ads, ads->bind_path, + LDAP_SCOPE_SUBTREE, + "(objectclass=user)", + opt_long_list_entries ? longattrs : + shortattrs, usergrp_display, + disp_fields); + ads_destroy(&ads); + return 0; + } + + return net_run_function(argc, argv, func, net_ads_user_usage); +} + +static int net_ads_group(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + const char *shortattrs[] = {"sAMAccountName", NULL}; + const char *longattrs[] = {"sAMAccountName", "description", NULL}; + char *disp_fields[2] = {NULL, NULL}; + + if (!(ads = ads_startup())) return -1; + + if (opt_long_list_entries) + d_printf("\nGroup name Comment"\ + "\n-----------------------------\n"); + rc = ads_do_search_all_fn(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, + "(objectclass=group)", opt_long_list_entries + ? longattrs : shortattrs, usergrp_display, + disp_fields); + + ads_destroy(&ads); + return 0; +} + +static int net_ads_status(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + extern pstring global_myname; + void *res; + + if (!(ads = ads_startup())) return -1; + + rc = ads_find_machine_acct(ads, &res, global_myname); + if (!ADS_ERR_OK(rc)) { + d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc)); + return -1; + } + + if (ads_count_replies(ads, res) == 0) { + d_printf("No machine account for '%s' found\n", global_myname); + return -1; + } + + ads_dump(ads, res); + + return 0; +} + +static int net_ads_leave(int argc, const char **argv) +{ + ADS_STRUCT *ads = NULL; + ADS_STATUS rc; + extern pstring global_myname; + + if (!secrets_init()) { + DEBUG(1,("Failed to initialise secrets database\n")); + return -1; + } + + if (!opt_password) { + asprintf(&opt_user_name, "%s$", global_myname); + opt_password = secrets_fetch_machine_password(); + } + + if (!(ads = ads_startup())) { + return -1; + } + + rc = ads_leave_realm(ads, global_myname); + if (!ADS_ERR_OK(rc)) { + d_printf("Failed to delete host '%s' from the '%s' realm.\n", + global_myname, ads->realm); + return -1; + } + + d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->realm); + + return 0; +} + +int net_ads_join(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + char *password; + char *tmp_password; + extern pstring global_myname; + const char *org_unit = "Computers"; + char *dn; + void *res; + DOM_SID dom_sid; + char *ou_str; + + if (argc > 0) org_unit = argv[0]; + + if (!secrets_init()) { + DEBUG(1,("Failed to initialise secrets database\n")); + return -1; + } + + tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); + password = strdup(tmp_password); + + if (!(ads = ads_startup())) return -1; + + ou_str = ads_ou_string(org_unit); + asprintf(&dn, "%s,%s", ou_str, ads->bind_path); + free(ou_str); + + rc = ads_search_dn(ads, &res, dn, NULL); + ads_msgfree(ads, res); + + if (rc.error_type == ADS_ERROR_LDAP && rc.rc == LDAP_NO_SUCH_OBJECT) { + d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", + org_unit, dn); + return -1; + } + free(dn); + + if (!ADS_ERR_OK(rc)) { + d_printf("ads_join_realm: %s\n", ads_errstr(rc)); + return -1; + } + + rc = ads_join_realm(ads, global_myname, org_unit); + if (!ADS_ERR_OK(rc)) { + d_printf("ads_join_realm: %s\n", ads_errstr(rc)); + return -1; + } + + rc = ads_set_machine_password(ads, global_myname, password); + if (!ADS_ERR_OK(rc)) { + d_printf("ads_set_machine_password: %s\n", ads_errstr(rc)); + return -1; + } + + rc = ads_domain_sid(ads, &dom_sid); + if (!ADS_ERR_OK(rc)) { + d_printf("ads_domain_sid: %s\n", ads_errstr(rc)); + return -1; + } + + if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) { + DEBUG(1,("Failed to save domain sid\n")); + return -1; + } + + if (!secrets_store_machine_password(password)) { + DEBUG(1,("Failed to save machine password\n")); + return -1; + } + + d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->realm); + + free(password); + + return 0; +} + +int net_ads_printer_usage(int argc, const char **argv) +{ + d_printf( +"\nnet ads printer info <printer> <server>" +"\n\tlookup info in directory for printer on server" +"\n\t(note: printer defaults to \"*\", server defaults to local)\n" +"\nnet ads printer publish <printername>" +"\n\tpublish printer in directory" +"\n\t(note: printer name is required)\n" +"\nnet ads printer remove <printername>" +"\n\tremove printer from directory" +"\n\t(note: printer name is required)\n"); + return -1; +} + +static int net_ads_printer_info(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + char *servername, *printername; + extern pstring global_myname; + void *res = NULL; + + if (!(ads = ads_startup())) return -1; + + if (argc > 0) + printername = argv[0]; + else + printername = "*"; + + if (argc > 1) + servername = argv[1]; + else + servername = global_myname; + + rc = ads_find_printer_on_server(ads, &res, printername, servername); + + if (!ADS_ERR_OK(rc)) { + d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc)); + ads_msgfree(ads, res); + return -1; + } + + if (ads_count_replies(ads, res) == 0) { + d_printf("Printer '%s' not found\n", printername); + ads_msgfree(ads, res); + return -1; + } + + ads_dump(ads, res); + ads_msgfree(ads, res); + + return 0; +} + +static int net_ads_printer_publish(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + char *uncname, *servername; + ADS_PRINTER_ENTRY prt; + extern pstring global_myname; + + /* + these const strings are only here as an example. The attributes + they represent are not implemented yet + */ + const char *bins[] = {"Tray 21", NULL}; + const char *media[] = {"Letter", NULL}; + const char *orients[] = {"PORTRAIT", NULL}; + const char *ports[] = {"Samba", NULL}; + + if (!(ads = ads_startup())) return -1; + + if (argc < 1) + return net_ads_printer_usage(argc, argv); + + memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY)); + + prt.printerName = argv[0]; + asprintf(&servername, "%s.%s", global_myname, ads->realm); + prt.serverName = servername; + prt.shortServerName = global_myname; + prt.versionNumber = "4"; + asprintf(&uncname, "\\\\%s\\%s", global_myname, argv[0]); + prt.uNCName=uncname; + prt.printBinNames = (char **) bins; + prt.printMediaSupported = (char **) media; + prt.printOrientationsSupported = (char **) orients; + prt.portName = (char **) ports; + prt.printSpooling = "PrintAfterSpooled"; + + rc = ads_add_printer(ads, &prt); + if (!ADS_ERR_OK(rc)) { + d_printf("ads_publish_printer: %s\n", ads_errstr(rc)); + return -1; + } + + d_printf("published printer\n"); + + return 0; +} + +static int net_ads_printer_remove(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + char *servername, *prt_dn; + extern pstring global_myname; + void *res = NULL; + + if (!(ads = ads_startup())) return -1; + + if (argc < 1) + return net_ads_printer_usage(argc, argv); + + if (argc > 1) + servername = argv[1]; + else + servername = global_myname; + + rc = ads_find_printer_on_server(ads, &res, argv[0], servername); + + if (!ADS_ERR_OK(rc)) { + d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc)); + ads_msgfree(ads, res); + return -1; + } + + if (ads_count_replies(ads, res) == 0) { + d_printf("Printer '%s' not found\n", argv[1]); + ads_msgfree(ads, res); + return -1; + } + + prt_dn = ads_get_dn(ads, res); + ads_msgfree(ads, res); + rc = ads_del_dn(ads, prt_dn); + ads_memfree(ads, prt_dn); + + if (!ADS_ERR_OK(rc)) { + d_printf("ads_del_dn: %s\n", ads_errstr(rc)); + return -1; + } + + return 0; +} + +static int net_ads_printer(int argc, const char **argv) +{ + struct functable func[] = { + {"INFO", net_ads_printer_info}, + {"PUBLISH", net_ads_printer_publish}, + {"REMOVE", net_ads_printer_remove}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_ads_printer_usage); +} + + +static int net_ads_password(int argc, const char **argv) +{ + ADS_STRUCT *ads; + char *auth_principal = opt_user_name; + char *auth_password = opt_password; + char *realm = NULL; + char *new_password = NULL; + char *c; + char *prompt; + ADS_STATUS ret; + + + if ((argc != 1) || (opt_user_name == NULL) || + (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) || + (strchr(argv[0], '@') == NULL)) { + return net_ads_usage(argc, argv); + } + + c = strchr(auth_principal, '@'); + realm = ++c; + + /* use the realm so we can eventually change passwords for users + in realms other than default */ + if (!(ads = ads_init(realm, NULL, NULL, NULL))) return -1; + + asprintf(&prompt, "Enter new password for %s:", argv[0]); + + new_password = getpass(prompt); + + ret = kerberos_set_password(ads->kdc_server, auth_principal, + auth_password, argv[0], new_password); + if (!ADS_ERR_OK(ret)) { + d_printf("Password change failed :-( ...\n"); + ads_destroy(&ads); + free(prompt); + return -1; + } + + d_printf("Password change for %s completed.\n", argv[0]); + ads_destroy(&ads); + free(prompt); + + return 0; +} + + +static int net_ads_change_localhost_pass(int argc, const char **argv) +{ + ADS_STRUCT *ads; + extern pstring global_myname; + char *host_principal; + char *hostname; + ADS_STATUS ret; + + + if (!(ads = ads_init(NULL, NULL, NULL, NULL))) return -1; + + hostname = strdup(global_myname); + strlower(hostname); + asprintf(&host_principal, "%s@%s", hostname, ads->realm); + SAFE_FREE(hostname); + d_printf("Changing password for principal: HOST/%s\n", host_principal); + + ret = ads_change_trust_account_password(ads, host_principal); + + if (!ADS_ERR_OK(ret)) { + d_printf("Password change failed :-( ...\n"); + ads_destroy(&ads); + SAFE_FREE(host_principal); + return -1; + } + + d_printf("Password change for principal HOST/%s succeeded.\n", host_principal); + ads_destroy(&ads); + SAFE_FREE(host_principal); + + return 0; +} + +int net_ads_help(int argc, const char **argv) +{ + struct functable func[] = { + {"USER", net_ads_user_usage}, +#if 0 + {"INFO", net_ads_info}, + {"JOIN", net_ads_join}, + {"LEAVE", net_ads_leave}, + {"STATUS", net_ads_status}, + {"GROUP", net_ads_group}, + {"PASSWORD", net_ads_password}, + {"CHOSTPASS", net_ads_change_localhost_pass}, + {"PRINTER", net_ads_printer}, +#endif + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_ads_usage); +} + +int net_ads(int argc, const char **argv) +{ + struct functable func[] = { + {"INFO", net_ads_info}, + {"JOIN", net_ads_join}, + {"LEAVE", net_ads_leave}, + {"STATUS", net_ads_status}, + {"USER", net_ads_user}, + {"GROUP", net_ads_group}, + {"PASSWORD", net_ads_password}, + {"CHOSTPASS", net_ads_change_localhost_pass}, + {"PRINTER", net_ads_printer}, + {"HELP", net_ads_help}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_ads_usage); +} + +#else + +static int net_ads_noads(void) +{ + d_printf("ADS support not compiled in\n"); + return -1; +} + +int net_ads_usage(int argc, const char **argv) +{ + return net_ads_noads(); +} + +int net_ads_help(int argc, const char **argv) +{ + return net_ads_noads(); +} + +int net_ads_join(int argc, const char **argv) +{ + return net_ads_noads(); +} + +int net_ads_user(int argc, const char **argv) +{ + return net_ads_noads(); +} + +/* this one shouldn't display a message */ +int net_ads_check(void) +{ + return -1; +} + +int net_ads(int argc, const char **argv) +{ + return net_ads_usage(argc, argv); +} + +#endif diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c new file mode 100644 index 0000000000..21af8a4fd9 --- /dev/null +++ b/source3/utils/net_help.c @@ -0,0 +1,126 @@ +/* + Samba Unix/Linux SMB client library + net help commands + Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +int net_common_methods_usage(int argc, const char**argv) +{ + d_printf("Valid methods: (auto-detected if not specified)\n"); + d_printf("\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n"); + d_printf("\trpc\t\t\t\tDCE-RPC\n"); + d_printf("\trap\t\t\t\tRAP (older systems)\n"); + d_printf("\n"); + return 0; +} + +int net_common_flags_usage(int argc, const char **argv) +{ + d_printf("Valid targets: choose one (none defaults to localhost)\n"); + d_printf("\t-S or --server=<server>\t\tserver name\n"); + d_printf("\t-I or --ipaddress=<ipaddr>\taddress of target server\n"); + d_printf("\t-w or --workgroup=<wg>\t\ttarget workgroup or domain\n"); + + d_printf("\n"); + 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 --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 --conf=<path>\t\tpathname of smb.conf file\n"); + d_printf("\t-l or --long\t\t\tDisplay full information\n"); + return -1; +} + +static int help_usage(int argc, const char **argv) +{ + d_printf( +"\n"\ +"Usage: net help <function>\n"\ +"\n"\ +"Valid functions are:\n"\ +" RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\ +" GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP\n"); + return -1; +} + +int net_help_user(int argc, const char **argv) +{ + d_printf("\nnet [method] user [misc. options] [targets]\n\tList users\n"); + d_printf("\nnet [method] user DELETE <name> [misc. options] [targets]"\ + "\n\tDelete specified user\n"); + d_printf("\nnet [method] user INFO <name> [misc. options] [targets]"\ + "\n\tList the domain groups of the specified user\n"); + d_printf("\nnet [method] user ADD <name> [-F user flags] [misc. options]"\ + " [targets]\n\tAdd specified user\n"); + + net_common_methods_usage(argc, argv); + net_common_flags_usage(argc, argv); + d_printf( + "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n"); + return -1; +} + +static int net_usage(int argc, const char **argv) +{ + d_printf(" net time\t\tto view or set time information\n"\ + " net lookup\t\tto lookup host name or ip address\n"\ + " net user\t\tto manage users\n"\ + " net join\t\tto join a domain\n"\ + "\n"\ + " net ads [command]\tto run ADS commands\n"\ + " net rap [command]\tto run RAP (pre-RPC) commands\n"\ + " net rpc [command]\tto run RPC commands\n"\ + "\n"\ + "Type \"net help <option>\" to get more information on that option\n"); + return -1; +} + +/* + handle "net help *" subcommands +*/ +int net_help(int argc, const char **argv) +{ + struct functable func[] = { + {"ADS", net_ads_help}, + {"RAP", net_rap_help}, + {"RPC", net_rpc_help}, + + {"FILE", net_rap_file_usage}, + {"SHARE", net_rap_share_usage}, + {"SESSION", net_rap_session_usage}, + {"SERVER", net_rap_server_usage}, + {"DOMAIN", net_rap_domain_usage}, + {"PRINTQ", net_rap_printq_usage}, + {"USER", net_help_user}, + {"GROUP", net_rap_group_usage}, + {"VALIDATE", net_rap_validate_usage}, + {"GROUPMEMBER", net_rap_groupmember_usage}, + {"ADMIN", net_rap_admin_usage}, + {"SERVICE", net_rap_service_usage}, + {"PASSWORD", net_rap_password_usage}, + {"TIME", net_time_usage}, + {"LOOKUP", net_lookup_usage}, + + {"HELP", help_usage}, + {NULL, NULL}}; + + return net_run_function(argc, argv, func, net_usage); +} diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c new file mode 100644 index 0000000000..0cc1ff579f --- /dev/null +++ b/source3/utils/net_lookup.c @@ -0,0 +1,61 @@ +/* + Samba Unix/Linux SMB client library + net lookup command + Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "../utils/net.h" + +int net_lookup_usage(int argc, const char **argv) +{ + d_printf( +" net lookup host HOSTNAME <type>\n\tgives IP for a hostname\n\n"\ +"\n"); + return -1; +} + +/* lookup a hostname giving an IP */ +static int net_lookup_host(int argc, const char **argv) +{ + struct in_addr ip; + int name_type = 0x20; + + if (argc == 0) return net_lookup_usage(argc, argv); + if (argc > 1) name_type = strtol(argv[1], NULL, 0); + + if (!resolve_name(argv[0], &ip, name_type)) { + /* we deliberately use DEBUG() here to send it to stderr + so scripts aren't mucked up */ + DEBUG(0,("Didn't find %s#%02x\n", argv[0], name_type)); + return -1; + } + + d_printf("%s\n", inet_ntoa(ip)); + return 0; +} + + +/* lookup hosts or IP addresses using internal samba lookup fns */ +int net_lookup(int argc, const char **argv) +{ + struct functable func[] = { + {"HOST", net_lookup_host}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_lookup_usage); +} diff --git a/source3/utils/net_rap.c b/source3/utils/net_rap.c new file mode 100644 index 0000000000..a6b199fd88 --- /dev/null +++ b/source3/utils/net_rap.c @@ -0,0 +1,1084 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2001 Steve French (sfrench@us.ibm.com) + Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com) + Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) + Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) + + Originally written by Steve and Jim. Largely rewritten by tridge in + November 2001. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "../utils/net.h" + +/* The following messages were for error checking that is not properly + reported at the moment. Which should be reinstated? */ +#define ERRMSG_TARGET_WG_NOT_VALID "\nTarget workgroup option not valid "\ + "except on net rap server command, ignored" +#define ERRMSG_INVALID_HELP_OPTION "\nInvalid help option\n" + +#define ERRMSG_BOTH_SERVER_IPADDRESS "\nTarget server and IP address both "\ + "specified. Do not set both at the same time. The target IP address was used\n" + +static const char *share_type[] = { + "Disk", + "Print", + "Dev", + "IPC" +}; + +static int errmsg_not_implemented(void) +{ + d_printf("\nNot implemented\n"); + return 0; +} + +int net_rap_file_usage(int argc, const char **argv) +{ + d_printf("net rap file [misc. options] [targets]\n"\ + "\tlists all open files on file server\n\n"); + d_printf("net rap file USER <username> [misc. options] [targets]\n"\ + "\tlists all files opened by username on file server\n\n"); + d_printf("net rap file CLOSE <id> [misc. options] [targets]\n"\ + "\tcloses specified file on target server\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +/*************************************************************************** + list info on an open file +***************************************************************************/ +static void file_fn(const char * pPath, const char * pUser, uint16 perms, + uint16 locks, uint32 id) +{ + d_printf("\t%-7.1d %-20.20s 0x%-4.2x %-6.1d %s\n", + id, pUser, perms, locks, pPath); +} + +static void one_file_fn(const char *pPath, const char *pUser, uint16 perms, + uint16 locks, uint32 id) +{ + d_printf("File ID %d\n"\ + "User name %s\n"\ + "Locks 0x%-4.2x\n"\ + "Path %s\n"\ + "Permissions 0x%x\n", + id, pUser, locks, pPath, perms); +} + + +static int rap_file_close(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc == 0) { + d_printf("\nMissing fileid of file to close\n\n"); + return net_rap_file_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetFileClose(cli, atoi(argv[0])); + cli_shutdown(cli); + return ret; +} + +static int rap_file_info(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc == 0) + return net_rap_file_usage(argc, argv); + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetFileGetInfo(cli, atoi(argv[0]), one_file_fn); + cli_shutdown(cli); + return ret; +} + +static int rap_file_user(int argc, const char **argv) +{ + if (argc == 0) + return net_rap_file_usage(argc, argv); + + d_printf("net rap file user not implemented yet\n"); + return -1; +} + +int net_rap_file(int argc, const char **argv) +{ + struct functable func[] = { + {"CLOSE", rap_file_close}, + {"USER", rap_file_user}, + {"INFO", rap_file_info}, + {NULL, NULL} + }; + + if (argc == 0) { + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + /* list open files */ + d_printf( + "\nEnumerating open files on remote server:\n\n"\ + "\n\tFileId Opened by Perms Locks Path \n"\ + "\t------ --------- ----- ----- ---- \n"); + ret = cli_NetFileEnum(cli, NULL, NULL, file_fn); + cli_shutdown(cli); + return ret; + } + + return net_run_function(argc, argv, func, net_rap_file_usage); +} + +int net_rap_share_usage(int argc, const char **argv) +{ + d_printf( + "\nnet [rap] share [misc. options] [targets] \n"\ + "\tenumerates all exported resources (network shares) "\ + "on target server\n"); + d_printf( + "\nnet rap share ADD <name=serverpath> [misc. options] [targets]"\ + "\n\tAdds a share from a server (makes the export active)\n"); + d_printf( + "\nnet rap share DELETE <sharename> [misc. options] [targets]\n"\ + "\tor"\ + "\nnet rap share CLOSE <sharename> [misc. options] [targets]"\ + "\n\tDeletes a share from a server (makes the export inactive)\n"); + net_common_flags_usage(argc, argv); + d_printf( + "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n"); + d_printf("\t-M or --maxusers=<num>\t\tmax users allowed for share\n"); + return -1; +} + +static void long_share_fn(const char *share_name, uint32 type, + const char *comment, void *state) +{ + d_printf("%-12.12s %-8.8s %-50.50s\n", + share_name, share_type[type], comment); +} + +static void share_fn(const char *share_name, uint32 type, + const char *comment, void *state) +{ + d_printf("%-12.12s\n", share_name); +} + +static int rap_share_delete(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (argc == 0) { + d_printf("\n\nShare name not specified\n"); + return net_rap_share_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetShareDelete(cli, argv[0]); + cli_shutdown(cli); + return ret; +} + +static int rap_share_add(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + RAP_SHARE_INFO_2 sinfo; + char *p; + char *sharename; + + if (argc == 0) { + d_printf("\n\nShare name not specified\n"); + return net_rap_share_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + sharename = strdup(argv[0]); + p = strchr(sharename, '='); + *p = 0; + strlcpy(sinfo.share_name, sharename, sizeof(sinfo.share_name)); + sinfo.reserved1 = '\0'; + sinfo.share_type = 0; + sinfo.comment = opt_comment; + sinfo.perms = 0; + sinfo.maximum_users = opt_maxusers; + sinfo.active_users = 0; + sinfo.path = p+1; + memset(sinfo.password, '\0', sizeof(sinfo.password)); + sinfo.reserved2 = '\0'; + + ret = cli_NetShareAdd(cli, &sinfo); + cli_shutdown(cli); + return ret; +} + + +int net_rap_share(int argc, const char **argv) +{ + struct functable func[] = { + {"DELETE", rap_share_delete}, + {"CLOSE", rap_share_delete}, + {"ADD", rap_share_add}, + {NULL, NULL} + }; + + if (argc == 0) { + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + if (opt_long_list_entries) { + d_printf( + "\nEnumerating shared resources (exports) on remote server:\n\n"\ + "\nShare name Type Description\n"\ + "---------- ---- -----------\n"); + ret = cli_RNetShareEnum(cli, long_share_fn, NULL); + } + ret = cli_RNetShareEnum(cli, share_fn, NULL); + cli_shutdown(cli); + return ret; + } + + return net_run_function(argc, argv, func, net_rap_share_usage); +} + + +int net_rap_session_usage(int argc, const char **argv) +{ + d_printf( + "\nnet rap session [misc. options] [targets]"\ + "\n\tenumerates all active SMB/CIFS sessions on target server\n"); + d_printf( + "\nnet rap session DELETE <client_name> [misc. options] [targets] \n"\ + "\tor"\ + "\nnet rap session CLOSE <client_name> [misc. options] [targets]"\ + "\n\tDeletes (closes) a session from specified client to server\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +static void list_sessions_func(char *wsname, char *username, uint16 conns, + uint16 opens, uint16 users, uint32 sess_time, + uint32 idle_time, uint32 user_flags, char *clitype) +{ + int hrs = idle_time / 3600; + int min = (idle_time / 60) % 60; + int sec = idle_time % 60; + + d_printf("\\\\%-18.18s %-20.20s %-18.18s %5d %2.2d:%2.2d:%2.2d\n", + wsname, username, clitype, opens, hrs, min, sec); +} + +static void display_session_func(const char *wsname, const char *username, + uint16 conns, uint16 opens, uint16 users, + uint32 sess_time, uint32 idle_time, + uint32 user_flags, const char *clitype) +{ + int ihrs = idle_time / 3600; + int imin = (idle_time / 60) % 60; + int isec = idle_time % 60; + int shrs = sess_time / 3600; + int smin = (sess_time / 60) % 60; + int ssec = sess_time % 60; + d_printf("User name %-20.20s\n"\ + "Computer %-20.20s\n"\ + "Guest logon %-20.20s\n"\ + "Client Type %-40.40s\n"\ + "Sess time %2.2d:%2.2d:%2.2d\n"\ + "Idle time %2.2d:%2.2d:%2.2d\n", + username, wsname, + (user_flags&0x0)?"yes":"no", clitype, + shrs, smin, ssec, ihrs, imin, isec); +} + +static void display_conns_func(uint16 conn_id, uint16 conn_type, uint16 opens, + uint16 users, uint32 conn_time, + const char *username, const char *netname) +{ + d_printf("%-14.14s %-8.8s %5d\n", + netname, share_type[conn_type], opens); +} + +static int rap_session_info(int argc, const char **argv) +{ + const char *sessname; + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + if (argc == 0) + return net_rap_session_usage(argc, argv); + + sessname = argv[0]; + + ret = cli_NetSessionGetInfo(cli, sessname, display_session_func); + if (ret < 0) { + cli_shutdown(cli); + return ret; + } + + d_printf("Share name Type # Opens\n-------------------------"\ + "-----------------------------------------------------\n"); + ret = cli_NetConnectionEnum(cli, sessname, display_conns_func); + cli_shutdown(cli); + return ret; +} + +static int rap_session_delete(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + if (argc == 0) + return net_rap_session_usage(argc, argv); + + ret = cli_NetSessionDel(cli, argv[0]); + cli_shutdown(cli); + return ret; +} + +int net_rap_session(int argc, const char **argv) +{ + struct functable func[] = { + {"INFO", rap_session_info}, + {"DELETE", rap_session_delete}, + {"CLOSE", rap_session_delete}, + {NULL, NULL} + }; + + if (argc == 0) { + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + d_printf("Computer User name "\ + "Client Type Opens Idle time\n"\ + "------------------------------------------"\ + "------------------------------------\n"); + ret = cli_NetSessionEnum(cli, list_sessions_func); + + cli_shutdown(cli); + return ret; + } + + return net_run_function(argc, argv, func, net_rap_session_usage); +} + +/**************************************************************************** +list a server name +****************************************************************************/ +static void display_server_func(const char *name, uint32 m, + const char *comment, void * reserved) +{ + d_printf("\t%-16.16s %s\n", name, comment); +} + + +int net_rap_server_usage(int argc, const char **argv) +{ + d_printf("net rap server [misc. options] [target]\n\t"\ + "lists the servers in the specified domain or workgroup.\n"); + d_printf("\n\tIf domain is not specified, it uses the current"\ + " domain or workgroup as\n\tthe default.\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +int net_rap_server(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + d_printf("\nEnumerating servers in this domain or workgroup: \n\n"\ + "\tServer name Server description\n"\ + "\t------------- ----------------------------\n"); + + ret = cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, + display_server_func,NULL); + cli_shutdown(cli); + return ret; +} + +int net_rap_domain_usage(int argc, const char **argv) +{ + d_printf("net rap domain [misc. options] [target]\n\tlists the"\ + " domains or workgroups visible on the current network\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + + +int net_rap_domain(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + d_printf("\nEnumerating domains:\n\n"\ + "\tDomain name Server name of Browse Master\n"\ + "\t------------- ----------------------------\n"); + + ret = cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM, + display_server_func,NULL); + cli_shutdown(cli); + return ret; +} + +int net_rap_printq_usage(int argc, const char **argv) +{ + d_printf( + "net rap printq [misc. options] [targets]\n"\ + "\tor\n"\ + "net rap printq list [<queue_name>] [misc. options] [targets]\n"\ + "\tlists the specified queue and jobs on the target server.\n"\ + "\tIf the queue name is not specified, all queues are listed.\n\n"); + d_printf( + "net rap printq delete [<queue name>] [misc. options] [targets]\n"\ + "\tdeletes the specified job number on the target server, or the\n"\ + "\tprinter queue if no job number is specified\n"); + + net_common_flags_usage(argc, argv); + d_printf("\t-j or --jobid=<job id>\t\tjob id\n"); + + return -1; +} + +static void enum_queue(const char *queuename, uint16 pri, uint16 start, + uint16 until, const char *sep, const char *pproc, + const char *dest, const char *qparms, + const char *qcomment, uint16 status, uint16 jobcount) +{ + d_printf("%-17.17s Queue %5d jobs ", + queuename, jobcount); + + switch (status) { + case 0: + d_printf("*Printer Active*\n"); + break; + case 1: + d_printf("*Printer Paused*\n"); + break; + case 2: + d_printf("*Printer error*\n"); + break; + case 3: + d_printf("*Delete Pending*\n"); + break; + default: + d_printf("**UNKNOWN STATUS**\n"); + } +} + +static void enum_jobs(uint16 jobid, const char *ownername, + const char *notifyname, const char *datatype, + const char *jparms, uint16 pos, uint16 status, + const char *jstatus, uint submitted, uint jobsize, + const char *comment) +{ + d_printf(" %-23.23s %5d %9d ", + ownername, jobid, jobsize); + switch (status) { + case 0: + d_printf("Waiting\n"); + break; + case 1: + d_printf("Held in queue\n"); + break; + case 2: + d_printf("Spooling\n"); + break; + case 3: + d_printf("Printing\n"); + break; + default: + d_printf("**UNKNOWN STATUS**\n"); + } +} + +#define PRINTQ_ENUM_DISPLAY \ + "Print queues at \\\\%s\n\n"\ + "Name Job # Size Status\n\n"\ + "------------------------------------------------------------------"\ + "-------------\n" + +static int rap_printq_info(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (argc == 0) + return net_rap_printq_usage(argc, argv); + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + d_printf(PRINTQ_ENUM_DISPLAY, cli->desthost); /* list header */ + ret = cli_NetPrintQGetInfo(cli, argv[0], enum_queue, enum_jobs); + cli_shutdown(cli); + return ret; +} + +static int rap_printq_delete(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (argc == 0) + return net_rap_printq_usage(argc, argv); + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_printjob_del(cli, atoi(argv[0])); + cli_shutdown(cli); + return ret; +} + +int net_rap_printq(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + struct functable func[] = { + {"INFO", rap_printq_info}, + {"DELETE", rap_printq_delete}, + {NULL, NULL} + }; + + if (argc == 0) { + if (!(cli = net_make_ipc_connection(0))) + return -1; + + d_printf(PRINTQ_ENUM_DISPLAY, cli->desthost); /* list header */ + ret = cli_NetPrintQEnum(cli, enum_queue, enum_jobs); + cli_shutdown(cli); + return ret; + } + + return net_run_function(argc, argv, func, net_rap_printq_usage); +} + + +static int net_rap_user_usage(int argc, const char **argv) +{ + return net_help_user(argc, argv); +} + +static void user_fn(const char *user_name, const char *comment, + const char * home_dir, const char * logon_script, + void *state) +{ + d_printf("%-21.21s\n", user_name); +} + +static void long_user_fn(const char *user_name, const char *comment, + const char * home_dir, const char * logon_script, + void *state) +{ + d_printf("%-21.21s %-50.50s\n", + user_name, comment); +} + +static void group_member_fn(const char *user_name, void *state) +{ + d_printf("%-21.21s\n", user_name); +} + +static int rap_user_delete(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (argc == 0) { + d_printf("\n\nUser name not specified\n"); + return net_rap_user_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetUserDelete(cli, argv[0]); + cli_shutdown(cli); + return ret; +} + +static int rap_user_add(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + RAP_USER_INFO_1 userinfo; + + if (argc == 0) { + d_printf("\n\nUser name not specified\n"); + return net_rap_user_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + safe_strcpy(userinfo.user_name, argv[0], sizeof(userinfo.user_name)); + if (opt_flags == -1) + opt_flags = 0x21; + + userinfo.userflags = opt_flags; + userinfo.reserved1 = '\0'; + userinfo.comment = opt_comment; + userinfo.priv = 1; + userinfo.home_dir = NULL; + userinfo.logon_script = NULL; + + ret = cli_NetUserAdd(cli, &userinfo); + cli_shutdown(cli); + return ret; +} + +static int rap_user_info(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc == 0) { + d_printf("\n\nUser name not specified\n"); + return net_rap_user_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetUserGetGroups(cli, argv[0], group_member_fn, NULL); + cli_shutdown(cli); + return ret; +} + +int net_rap_user(int argc, const char **argv) +{ + int ret = -1; + struct functable func[] = { + {"ADD", rap_user_add}, + {"INFO", rap_user_info}, + {"DELETE", rap_user_delete}, + {NULL, NULL} + }; + + if (argc == 0) { + struct cli_state *cli; + if (!(cli = net_make_ipc_connection(0))) + goto done; + if (opt_long_list_entries) { + d_printf("\nUser name Comment"\ + "\n-----------------------------\n"); + ret = cli_RNetUserEnum(cli, long_user_fn, NULL); + cli_shutdown(cli); + goto done; + } + ret = cli_RNetUserEnum(cli, user_fn, NULL); + cli_shutdown(cli); + goto done; + } + + ret = net_run_function(argc, argv, func, net_rap_user_usage); + done: + if (ret != 0) { + DEBUG(1, ("Net user returned: %d\n", ret)); + } + return ret; +} + + +int net_rap_group_usage(int argc, const char **argv) +{ + d_printf("net rap group [misc. options] [targets]"\ + "\n\tList user groups\n"); + d_printf("\nnet rap group DELETE <name> [misc. options] [targets]"\ + "\n\tDelete specified group\n"); + d_printf("\nnet rap group ADD <name> [-C comment] [misc. options]"\ + " [targets]\n\tCreate specified group\n"); + + net_common_flags_usage(argc, argv); + d_printf( + "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n"); + return -1; +} + +static void long_group_fn(const char *group_name, const char *comment, + void *state) +{ + d_printf("%-21.21s %-50.50s\n", group_name, comment); +} + +static void group_fn(const char *group_name, const char *comment, void *state) +{ + d_printf("%-21.21s\n", group_name); +} + +static int rap_group_delete(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc == 0) { + d_printf("\n\nGroup name not specified\n"); + return net_rap_group_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetGroupDelete(cli, argv[0]); + cli_shutdown(cli); + return ret; +} + +static int rap_group_add(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + RAP_GROUP_INFO_1 grinfo; + + if (argc == 0) { + d_printf("\n\nGroup name not specified\n"); + return net_rap_group_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + /* BB check for length 21 or smaller explicitly ? BB */ + safe_strcpy(grinfo.group_name, argv[0], sizeof(grinfo.group_name)); + grinfo.reserved1 = '\0'; + grinfo.comment = opt_comment; + + ret = cli_NetGroupAdd(cli, &grinfo); + cli_shutdown(cli); + return ret; +} + +int net_rap_group(int argc, const char **argv) +{ + struct functable func[] = { + {"ADD", rap_group_add}, + {"DELETE", rap_group_delete}, + {NULL, NULL} + }; + + if (argc == 0) { + struct cli_state *cli; + int ret; + if (!(cli = net_make_ipc_connection(0))) + return -1; + if (opt_long_list_entries) { + d_printf("Group name Comment\n"); + d_printf("-----------------------------\n"); + ret = cli_RNetGroupEnum(cli, long_group_fn, NULL); + cli_shutdown(cli); + return ret; + } + ret = cli_RNetGroupEnum(cli, group_fn, NULL); + cli_shutdown(cli); + return ret; + } + + return net_run_function(argc, argv, func, net_rap_group_usage); +} + +int net_rap_groupmember_usage(int argc, const char **argv) +{ + d_printf( + "net rap groupmember LIST <group> [misc. options] [targets]"\ + "\n\t Enumerate users in a group\n"\ + "\nnet rap groupmember DELETE <group> <user> [misc. options] "\ + "[targets]\n\t Delete sepcified user from specified group\n"\ + "\nnet rap groupmember ADD <group> <user> [misc. options] [targets]"\ + "\n\t Add specified user to specified group\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + + +static int rap_groupmember_add(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc != 2) { + d_printf("\n\nGroup or user name not specified\n"); + return net_rap_groupmember_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetGroupAddUser(cli, argv[0], argv[1]); + cli_shutdown(cli); + return ret; +} + +static int rap_groupmember_delete(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc != 2) { + d_printf("\n\nGroup or user name not specified\n"); + return net_rap_groupmember_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetGroupDelUser(cli, argv[0], argv[1]); + cli_shutdown(cli); + return ret; +} + +static int rap_groupmember_list(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + if (argc == 0) { + d_printf("\n\nGroup name not specified\n"); + return net_rap_groupmember_usage(argc, argv); + } + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + ret = cli_NetGroupGetUsers(cli, argv[0], group_member_fn, NULL ); + cli_shutdown(cli); + return ret; +} + +int net_rap_groupmember(int argc, const char **argv) +{ + struct functable func[] = { + {"ADD", rap_groupmember_add}, + {"LIST", rap_groupmember_list}, + {"DELETE", rap_groupmember_delete}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_rap_groupmember_usage); +} + +int net_rap_validate_usage(int argc, const char **argv) +{ + d_printf("net rap validate <username> [password]\n"\ + "\tValidate user and password to check whether they"\ + " can access target server or domain\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +int net_rap_validate(int argc, const char **argv) +{ + return errmsg_not_implemented(); +} + +int net_rap_service_usage(int argc, const char **argv) +{ + d_printf("net rap service [misc. options] [targets] \n"\ + "\tlists all running service daemons on target server\n"); + d_printf("\nnet rap service START <name> [service startup arguments]"\ + " [misc. options] [targets]"\ + "\n\tStart named service on remote server\n"); + d_printf("\nnet rap service STOP <name> [misc. options] [targets]\n"\ + "\n\tStop named service on remote server\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +static int rap_service_start(int argc, const char **argv) +{ + return errmsg_not_implemented(); +} + +static int rap_service_stop(int argc, const char **argv) +{ + return errmsg_not_implemented(); +} + +int net_rap_service(int argc, const char **argv) +{ + struct functable func[] = { + {"START", rap_service_start}, + {"STOP", rap_service_stop}, + {NULL, NULL} + }; + + if (argc == 0) { + struct cli_state *cli; + int ret; + if (!(cli = net_make_ipc_connection(0))) + return -1; + + if (opt_long_list_entries) { + d_printf("Service name Comment\n"); + d_printf("-----------------------------\n"); + ret = cli_RNetServiceEnum(cli, long_group_fn, NULL); + } + ret = cli_RNetServiceEnum(cli, group_fn, NULL); + cli_shutdown(cli); + return ret; + } + + return net_run_function(argc, argv, func, net_rap_service_usage); +} + +int net_rap_password_usage(int argc, const char **argv) +{ + d_printf( + "net rap password <user> <oldpwo> <newpw> [misc. options] [target]\n"\ + "\tchanges the password for the specified user at target\n"); + + return -1; +} + + +int net_rap_password(int argc, const char **argv) +{ + struct cli_state *cli; + int ret; + + if (argc < 3) + return net_rap_password_usage(argc, argv); + + if (!(cli = net_make_ipc_connection(0))) + return -1; + + /* BB Add check for password lengths? */ + ret = cli_oem_change_password(cli, argv[0], argv[2], argv[1]); + cli_shutdown(cli); + return ret; +} + +int net_rap_admin_usage(int argc, const char **argv) +{ + d_printf( + "net rap admin <remote command> [cmd args [env]] [misc. options] [targets]"\ + "\n\texecutes a remote command on an os/2 target server\n"); + + return -1; +} + + +int net_rap_admin(int argc, const char **argv) +{ + return errmsg_not_implemented(); +} + +/* The help subsystem for the RAP subcommand */ + +int net_rap_usage(int argc, const char **argv) +{ + d_printf(" net rap domain \tto list domains \n"\ + " net rap file \t\tto list open files on a server \n"\ + " net rap group \tto list user groups \n"\ + " net rap groupmember \tto list users in a group \n"\ + " net rap password \tto change the password of a user\n"\ + " net rap printq \tto list the print queues on a server\n"\ + " net rap server \tto list servers in a domain\n"\ + " net rap session \tto list clients with open sessions to a server\n"\ + " net rap share \tto list shares exported by a server\n"\ + " net rap user \t\tto list users\n"\ + " net rap validate \tto check whether a user and the corresponding password are valid\n"\ + " net rap help\n"\ + "\nType \"net help <option>\" to get more information on that option\n\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +/* + handle "net rap help *" subcommands +*/ +int net_rap_help(int argc, const char **argv) +{ + struct functable func[] = { + {"FILE", net_rap_file_usage}, + {"SHARE", net_rap_share_usage}, + {"SESSION", net_rap_session_usage}, + {"SERVER", net_rap_server_usage}, + {"DOMAIN", net_rap_domain_usage}, + {"PRINTQ", net_rap_printq_usage}, + {"USER", net_rap_user_usage}, + {"GROUP", net_rap_group_usage}, + {"VALIDATE", net_rap_validate_usage}, + {"GROUPMEMBER", net_rap_groupmember_usage}, + {"ADMIN", net_rap_admin_usage}, + {"SERVICE", net_rap_service_usage}, + {"PASSWORD", net_rap_password_usage}, + {NULL, NULL}}; + + return net_run_function(argc, argv, func, net_rap_usage); +} + +/* Entry-point for all the RAP functions. */ + +int net_rap(int argc, const char **argv) +{ + struct functable func[] = { + {"FILE", net_rap_file}, + {"SHARE", net_rap_share}, + {"SESSION", net_rap_session}, + {"SERVER", net_rap_server}, + {"DOMAIN", net_rap_domain}, + {"PRINTQ", net_rap_printq}, + {"USER", net_rap_user}, + {"GROUP", net_rap_group}, + {"VALIDATE", net_rap_validate}, + {"GROUPMEMBER", net_rap_groupmember}, + {"ADMIN", net_rap_admin}, + {"SERVICE", net_rap_service}, + {"PASSWORD", net_rap_password}, + {"HELP", net_rap_help}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_rap_usage); +} + diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c new file mode 100644 index 0000000000..19e2c63ecc --- /dev/null +++ b/source3/utils/net_rpc.c @@ -0,0 +1,1328 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "../utils/net.h" + +extern pstring global_myname; + +/** + * @file net_rpc.c + * + * @brief RPC based subcommands for the 'net' utility. + * + * This file should contain much of the functionality that used to + * be found in rpcclient, execpt that the commands should change + * less often, and the fucntionality should be sane (the user is not + * expected to know a rid/sid before they conduct an operation etc.) + * + * @todo Perhaps eventually these should be split out into a number + * of files, as this could get quite big. + **/ + + +/* A function of this type is passed to the 'run_rpc_command' wrapper */ +typedef NTSTATUS (*rpc_command_fn)(const DOM_SID *, struct cli_state *, TALLOC_CTX *, int, const char **); + +/** + * Many of the RPC functions need the domain sid. This function gets + * it at the start of every run + * + * @param cli A cli_state already connected to the remote machine + * + * @return The Domain SID of the remote machine. + **/ + +static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli) +{ + DOM_SID *domain_sid; + POLICY_HND pol; + NTSTATUS result = NT_STATUS_OK; + uint32 info_class = 5; + fstring domain_name; + TALLOC_CTX *mem_ctx; + + if (!(domain_sid = malloc(sizeof(DOM_SID)))){ + DEBUG(0,("fetch_domain_sid: malloc returned NULL!\n")); + goto error; + } + + if (!(mem_ctx=talloc_init())) + { + DEBUG(0,("fetch_domain_sid: talloc_init returned NULL!\n")); + goto error; + } + + + if (!cli_nt_session_open (cli, PIPE_LSARPC)) { + fprintf(stderr, "could not initialise lsa pipe\n"); + goto error; + } + + result = cli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + if (!NT_STATUS_IS_OK(result)) { + goto error; + } + + result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, + domain_name, domain_sid); + if (!NT_STATUS_IS_OK(result)) { + goto error; + } + + cli_lsa_close(cli, mem_ctx, &pol); + cli_nt_session_close(cli); + talloc_destroy(mem_ctx); + + return domain_sid; + + error: + fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); + + if (!NT_STATUS_IS_OK(result)) { + fprintf(stderr, "error: %s\n", nt_errstr(result)); + } + + exit(1); +} + +/** + * Run a single RPC command, from start to finish. + * + * @param pipe_name the pipe to connect to (usually a PIPE_ constant) + * @param conn_flag a NET_FLAG_ combination. Passed to + * net_make_ipc_connection. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * @return A shell status integer (0 for success) + */ + +static int run_rpc_command(const char *pipe_name, int conn_flags, + rpc_command_fn fn, + int argc, const char **argv) +{ + struct cli_state *cli = net_make_ipc_connection(conn_flags); + TALLOC_CTX *mem_ctx; + NTSTATUS nt_status; + DOM_SID *domain_sid; + + if (!cli) { + return -1; + } + + domain_sid = net_get_remote_domain_sid(cli); + + /* Create mem_ctx */ + + if (!(mem_ctx = talloc_init())) { + DEBUG(0, ("talloc_init() failed\n")); + cli_shutdown(cli); + return -1; + } + + if (!cli_nt_session_open(cli, pipe_name)) { + DEBUG(0, ("Could not initialise samr pipe\n")); + } + + nt_status = fn(domain_sid, cli, mem_ctx, argc, argv); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("rpc command function failed! (%s)\n", nt_errstr(nt_status))); + } else { + DEBUG(5, ("rpc command function succedded\n")); + } + + + if (cli->nt_pipe_fnum) + cli_nt_session_close(cli); + + talloc_destroy(mem_ctx); + + return (!NT_STATUS_IS_OK(nt_status)); +} + + +/****************************************************************************/ + + +/** + * Force a change of the trust acccount password. + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS rpc_changetrustpw_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) { + + return trust_pw_find_change_and_store_it(cli, mem_ctx, opt_target_workgroup); +} + +/** + * Force a change of the trust acccount password. + * + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int rpc_changetrustpw(int argc, const char **argv) +{ + return run_rpc_command(PIPE_NETLOGON, NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC, rpc_changetrustpw_internals, + argc, argv); +} + + +/****************************************************************************/ + + +/** + * Join a domain, the old way. + * + * This uses 'machinename' as the inital password, and changes it. + * + * The password should be created with 'server manager' or eqiv first. + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS rpc_join_oldstyle_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) { + + extern pstring global_myname; + fstring trust_passwd; + unsigned char orig_trust_passwd_hash[16]; + + fstrcpy(trust_passwd, global_myname); + strlower(trust_passwd); + E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash); + + return trust_pw_change_and_store_it(cli, mem_ctx, orig_trust_passwd_hash); +} + +/** + * Join a domain, the old way. + * + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int net_rpc_join_oldstyle(int argc, const char **argv) +{ + return run_rpc_command(PIPE_NETLOGON, NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC, rpc_join_oldstyle_internals, + argc, argv); +} + +/** + * Basic usage function for 'net rpc join' + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + **/ + +static int rpc_join_usage(int argc, const char **argv) +{ + d_printf("net rpc join -U <username>[%%password] [options]\n"\ + "\t to join a domain with admin username & password\n"\ + "\t\t password will be prompted if none is specified\n"); + d_printf("net rpc join [options except -U]\n"\ + "\t to join a domain created in server manager\n\n\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +/** + * 'net rpc join' entrypoint. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * Main 'net_rpc_join()' (where the admain username/password is used) is + * in net_rpc_join.c + * Assume if a -U is specified, it's the new style, otherwise it's the + * old style + **/ + +int net_rpc_join(int argc, const char **argv) +{ + if ((net_rpc_join_oldstyle(argc, argv) == 0)) + return 0; + + return net_rpc_join_newstyle(argc, argv); +} + + +/****************************************************************************/ + +/** + * Basic usage function for 'net rpc user' + * @param argc Standard main() style argc. + * @param argv Standard main() style argv. Initial components are already + * stripped. + **/ + +static int rpc_user_usage(int argc, const char **argv) +{ + return net_help_user(argc, argv); +} + +/** + * Add a new user to a remote RPC server + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid acquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS rpc_user_add_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) { + + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + const char *acct_name; + uint16 acb_info; + uint32 unknown, user_rid; + + if (argc != 1) { + d_printf("User must be specified\n"); + rpc_user_usage(argc, argv); + return NT_STATUS_OK; + } + + acct_name = argv[0]; + + /* Get sam policy handle */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Get domain policy handle */ + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Create domain user */ + + acb_info = ACB_NORMAL; + unknown = 0xe005000b; /* No idea what this is - a permission mask? */ + + result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol, + acct_name, acb_info, unknown, + &user_pol, &user_rid); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + done: + if (!NT_STATUS_IS_OK(result)) { + d_printf("Failed to add user %s - %s\n", acct_name, + nt_errstr(result)); + } else { + d_printf("Added user %s\n", acct_name); + } + return result; +} + +/** + * Add a new user to a remote RPC server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int rpc_user_add(int argc, const char **argv) +{ + return run_rpc_command(PIPE_SAMR, 0, rpc_user_add_internals, + argc, argv); +} + +/** + * Delete a user from a remote RPC server + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid acquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS rpc_user_del_internals(const DOM_SID *domain_sid, + struct cli_state *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND connect_pol, domain_pol, user_pol; + + if (argc < 1) { + d_printf("User must be specified\n"); + rpc_user_usage(argc, argv); + return NT_STATUS_OK; + } + /* Get sam policy and domain handles */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Get handle on user */ + + { + uint32 *user_rids, num_rids, *name_types; + uint32 flags = 0x000003e8; /* Unknown */ + + result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol, + flags, 1, (char **) &argv[0], + &num_rids, &user_rids, + &name_types); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = cli_samr_open_user(cli, mem_ctx, &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + user_rids[0], &user_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + } + + /* Delete user */ + + result = cli_samr_delete_dom_user(cli, mem_ctx, &user_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Display results */ + + done: + return result; + +} + +/** + * Delete a user from a remote RPC server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int rpc_user_delete(int argc, const char **argv) +{ + return run_rpc_command(PIPE_SAMR, 0, rpc_user_del_internals, + argc, argv); +} + +/** + * List user's groups on a remote RPC server + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid acquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS +rpc_user_info_internals(const DOM_SID *domain_sid, struct cli_state *cli, + TALLOC_CTX *mem_ctx, int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 *rids, num_rids, *name_types, num_names; + uint32 flags = 0x000003e8; /* Unknown */ + int i; + char **names; + DOM_GID *user_gids; + + if (argc < 1) { + d_printf("User must be specified\n"); + rpc_user_usage(argc, argv); + return NT_STATUS_OK; + } + /* Get sam policy handle */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + /* Get domain policy handle */ + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + /* Get handle on user */ + + result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol, + flags, 1, (char **) &argv[0], + &num_rids, &rids, &name_types); + + if (!NT_STATUS_IS_OK(result)) goto done; + + result = cli_samr_open_user(cli, mem_ctx, &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + rids[0], &user_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = cli_samr_query_usergroups(cli, mem_ctx, &user_pol, + &num_rids, &user_gids); + + /* Look up rids */ + + rids = (uint32 *)talloc(mem_ctx, sizeof(uint32) * num_rids); + + for (i = 0; i < num_rids; i++) + rids[i] = user_gids[i].g_rid; + + result = cli_samr_lookup_rids(cli, mem_ctx, &domain_pol, + flags, num_rids, rids, + &num_names, &names, &name_types); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Display results */ + + for (i = 0; i < num_names; i++) + printf("%s\n", names[i]); + + done: + return result; +} + +/** + * List a user's groups from a remote RPC server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int rpc_user_info(int argc, const char **argv) +{ + return run_rpc_command(PIPE_SAMR, 0, rpc_user_info_internals, + argc, argv); +} + +/** + * List users on a remote RPC server + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid acquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS +rpc_user_list_internals(const DOM_SID *domain_sid, struct cli_state *cli, + TALLOC_CTX *mem_ctx, int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 start_idx=0, max_entries=250, num_entries, i; + SAM_DISPINFO_CTR ctr; + SAM_DISPINFO_1 info1; + + /* Get sam policy handle */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Get domain policy handle */ + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Query domain users */ + ZERO_STRUCT(ctr); + ZERO_STRUCT(info1); + ctr.sam.info1 = &info1; + if (opt_long_list_entries) + d_printf("\nUser name Comment"\ + "\n-----------------------------\n"); + do { + fstring user, desc; + result = cli_samr_query_dispinfo(cli, mem_ctx, &domain_pol, + &start_idx, 1, &num_entries, + max_entries, &ctr); + for (i = 0; i < num_entries; i++) { + unistr2_to_ascii(user, &(&ctr.sam.info1->str[i])->uni_acct_name, sizeof(user)-1); + if (opt_long_list_entries) + unistr2_to_ascii(desc, &(&ctr.sam.info1->str[i])->uni_acct_desc, sizeof(desc)-1); + + if (opt_long_list_entries) + printf("%-21.21s %-50.50s\n", user, desc); + else + printf("%-21.21s\n", user); + } + } while (!NT_STATUS_IS_OK(result)); + + done: + return result; +} + +/** + * 'net rpc user' entrypoint. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + **/ + +int net_rpc_user(int argc, const char **argv) +{ + struct functable func[] = { + {"add", rpc_user_add}, + {"info", rpc_user_info}, + {"delete", rpc_user_delete}, + {NULL, NULL} + }; + + if (argc == 0) { + if (opt_long_list_entries) { + } else { + } + return run_rpc_command(PIPE_SAMR, 0, + rpc_user_list_internals, + argc, argv); + } + + return net_run_function(argc, argv, func, rpc_user_usage); +} + + +/****************************************************************************/ + + + +/** + * ABORT the shutdown of a remote RPC Server + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS rpc_shutdown_abort_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + result = cli_reg_abort_shutdown(cli, mem_ctx); + + if (NT_STATUS_IS_OK(result)) + DEBUG(5,("cmd_reg_abort_shutdown: query succeeded\n")); + else + DEBUG(5,("cmd_reg_abort_shutdown: query failed\n")); + + return result; +} + + +/** + * ABORT the Shut down of a remote RPC server + * + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int rpc_shutdown_abort(int argc, const char **argv) +{ + return run_rpc_command(PIPE_WINREG, 0, rpc_shutdown_abort_internals, + argc, argv); +} + +/** + * Shut down a remote RPC Server + * + * All paramaters are provided by the run_rpc_command funcion, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ + +static NTSTATUS rpc_shutdown_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + char *msg = "This machine will be shutdown shortly"; + uint32 timeout = 20; + uint16 flgs = 0; + BOOL reboot = opt_reboot; + BOOL force = opt_force; +#if 0 + poptContext pc; + int rc; + + struct poptOption long_options[] = { + {"message", 'm', POPT_ARG_STRING, &msg}, + {"timeout", 't', POPT_ARG_INT, &timeout}, + {"reboot", 'r', POPT_ARG_NONE, &reboot}, + {"force", 'f', POPT_ARG_NONE, &force}, + { 0, 0, 0, 0} + }; + + pc = poptGetContext(NULL, argc, (const char **) argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + rc = poptGetNextOpt(pc); + + if (rc < -1) { + /* an error occurred during option processing */ + DEBUG(0, ("%s: %s\n", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(rc))); + return NT_STATUS_INVALID_PARAMETER; + } +#endif + if (reboot) { + flgs |= REG_REBOOT_ON_SHUTDOWN; + } + if (force) { + flgs |= REG_FORCE_SHUTDOWN; + } + if (opt_comment) { + msg = opt_comment; + } + if (opt_timeout) { + timeout = opt_timeout; + } + + /* create an entry */ + result = cli_reg_shutdown(cli, mem_ctx, msg, timeout, flgs); + + if (NT_STATUS_IS_OK(result)) + DEBUG(5,("Shutdown of remote machine succeeded\n")); + else + DEBUG(0,("Shutdown of remote machine failed!\n")); + + return result; +} + +/** + * Shut down a remote RPC server + * + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ + +static int rpc_shutdown(int argc, const char **argv) +{ + return run_rpc_command(PIPE_WINREG, 0, rpc_shutdown_internals, + argc, argv); +} + +/*************************************************************************** + NT Domain trusts code (i.e. 'net rpc trustdom' functionality) + + ***************************************************************************/ + +/** + * Add interdomain trust account to the RPC server. + * All parameters (except for argc and argv) are passed by run_rpc_command + * function. + * + * @param domain_sid The domain sid acquired from the server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return normal NTSTATUS return code + */ + +static NTSTATUS rpc_trustdom_add_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) { + + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + char *acct_name; + uint16 acb_info; + uint32 unknown, user_rid; + + if (argc != 1) { + d_printf("Usage: net rpc trustdom add <domain_name>\n"); + return NT_STATUS_OK; + } + + /* + * Make valid trusting domain account (ie. uppercased and with '$' appended) + */ + + if (asprintf(&acct_name, "%s$", argv[0]) < 0) { + return NT_STATUS_NO_MEMORY; + } + + strupper(acct_name); + + /* Get sam policy handle */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Get domain policy handle */ + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Create trusting domain's account */ + + acb_info = ACB_DOMTRUST; + unknown = 0xe005000b; /* No idea what this is - a permission mask? + Is it needed for interdomain account also ? */ + + result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol, + acct_name, acb_info, unknown, + &user_pol, &user_rid); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + done: + SAFE_FREE(acct_name); + return result; +} + +/** + * Create interdomain trust account for a remote domain. + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +static int rpc_trustdom_add(int argc, const char **argv) +{ + return run_rpc_command(PIPE_SAMR, 0, rpc_trustdom_add_internals, + argc, argv); +} + + +/** + * Delete interdomain trust account for a remote domain. + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +static int rpc_trustdom_del(int argc, const char **argv) +{ + d_printf("Sorry, not yet implemented.\n"); + return -1; +} + + +/** + * Establish trust relationship to a trusting domain. + * Interdomain account must already be created on remote PDC. + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +extern char *opt_user_name; +extern char *opt_password; + +static int rpc_trustdom_establish(int argc, const char **argv) { + + struct cli_state *cli; + struct in_addr server_ip; + POLICY_HND connect_hnd; + TALLOC_CTX *mem_ctx; + NTSTATUS nt_status; + DOM_SID domain_sid; + WKS_INFO_100 wks_info; + + char* domain_name; + char* acct_name; + fstring pdc_name; + + /* + * Connect to \\server\ipc$ as 'our domain' account with password + */ + + domain_name = smb_xstrdup(argv[0]); + strupper(domain_name); + + asprintf(&acct_name, "%s$", lp_workgroup()); + strupper(acct_name); + + opt_user_name = (char*)malloc(strlen(acct_name) + 1); + safe_strcpy(opt_user_name, acct_name, strlen(acct_name) + 1); + + /* find the domain controller */ + if (!net_find_dc(&server_ip, pdc_name, domain_name)) { + DEBUG(0, ("Coulnd find domain controller for domain %s\n", domain_name)); + return -1; + } + + /* connect to ipc$ as username/password */ + nt_status = connect_to_ipc(&cli, &server_ip, pdc_name); + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) { + + /* Is it trusting domain account for sure ? */ + DEBUG(0, ("Couldn't verify trusting domain account. Error was %s\n", + nt_errstr(nt_status))); + return -1; + } + + /* + * Connect to \\server\ipc$ again (this time anonymously) + */ + + nt_status = connect_to_ipc_anonymous(&cli, &server_ip, (char*)pdc_name); + + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("Couldn't connect to domain %s controller. Error was %s.\n", + domain_name, nt_errstr(nt_status))); + } + + /* + * Use NetServerEnum2 to make sure we're talking to a proper server + */ + + if (!cli_get_pdc_name(cli, domain_name, (char*)pdc_name)) { + DEBUG(0, ("NetServerEnum2 error: Couldn't find primary domain controller\ + for domain %s\n", domain_name)); + } + + /* + * Call WksQueryInfo to check remote server's capabilities + * FIXME:Is really necessary ? nt serv does this, but from samba's + * point of view it doesn't seem to make the difference + * IDEA: It may be used to get info about type of pdc we're talking to + * (e.g. WinNT or Win2k) + */ + + if (!cli_nt_session_open(cli, PIPE_WKSSVC)) { + DEBUG(0, ("Couldn't not initialise wkssvc pipe\n")); + return -1; + } + + /* TODO: convert this call from rpc_client/cli_wkssvc.c + to cli_wks_query_info() in libsmb/cli_wkssvc.c + UPDATE: already done :) + */ + + if (!(mem_ctx = talloc_init())) { + DEBUG(0, ("talloc_init() failed\n")); + cli_shutdown(cli); + return -1; + } + + nt_status = cli_wks_query_info(cli, mem_ctx, &wks_info); + + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("WksQueryInfo call failed.\n")); + return -1; + } + + if (cli->nt_pipe_fnum) { + cli_nt_session_close(cli); + talloc_destroy(mem_ctx); + } + + + /* + * Call LsaOpenPolicy and LsaQueryInfo + */ + + if (!(mem_ctx = talloc_init())) { + DEBUG(0, ("talloc_init() failed\n")); + cli_shutdown(cli); + return -1; + } + + if (!cli_nt_session_open(cli, PIPE_LSARPC)) { + DEBUG(0, ("Could not initialise lsa pipe\n")); + } + + nt_status = cli_lsa_open_policy2(cli, mem_ctx, True, SEC_RIGHTS_QUERY_VALUE, + &connect_hnd); + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("Couldn't open policy handle. Error was %s\n", + nt_errstr(nt_status))); + return -1; + } + + /* Querying info level 5 */ + + nt_status = cli_lsa_query_info_policy(cli, mem_ctx, &connect_hnd, + 5 /* info level */, domain_name, &domain_sid); + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("LSA Query Info failed. Returned error was %s\n", + nt_errstr(nt_status))); + return -1; + } + + + /* There should be actually query info level 3 (following nt serv behaviour), + but I still don't know if it's _really_ necessary */ + + /* + * Close the pipes and clean up + */ + + nt_status = cli_lsa_close(cli, mem_ctx, &connect_hnd); + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("Couldn't close LSA pipe. Error was %s\n", + nt_errstr(nt_status))); + return -1; + } + + if (cli->nt_pipe_fnum) + cli_nt_session_close(cli); + + talloc_destroy(mem_ctx); + + + /* + * Store the password in secrets db + */ + + if (!secrets_store_trusted_domain_password(domain_name, opt_password, + domain_sid)) { + DEBUG(0, ("Storing password for trusted domain failed.\n")); + return -1; + } + + DEBUG(0, ("Success!\n")); + return 0; +} + +/** + * Revoke trust relationship to the remote domain + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +static int rpc_trustdom_revoke(int argc, const char **argv) { + + char* domain_name; + + if (argc < 1) return -1; + + /* generate upper cased domain name */ + domain_name = smb_xstrdup(argv[0]); + strupper(domain_name); + + /* delete password of the trust */ + if (!trusted_domain_password_delete(domain_name)) { + DEBUG(0, ("Failed to revoke relationship to the trusted domain %s\n", + domain_name)); + return -1; + }; + + return 0; +} + +/** + * Usage for 'net rpc trustdom' command + * + * @param argc standard argc + * @param argv standard argv without inital components + * + * @return Integer status returned to shell + **/ + +static int rpc_trustdom_usage(int argc, const char **argv) { + d_printf(" net rpc trustdom add \t\t add trusting domain's account\n"); + d_printf(" net rpc trustdom del \t\t delete trusting domain's account\n"); + d_printf(" net rpc trustdom establish \t establish relationship to trusted domain\n"); + d_printf(" net rpc trustdom revoke \t abandon relationship to trusted domain\n"); + d_printf(" net rpc trustdom list \t show current interdomain trust relationships\n"); + return -1; +} + + +/** + * Entrypoint for 'net rpc trustdom' code + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + */ + +static int rpc_trustdom(int argc, const char **argv) +{ + struct functable func[] = { + {"add", rpc_trustdom_add}, + {"del", rpc_trustdom_del}, + {"establish", rpc_trustdom_establish}, + {"revoke", rpc_trustdom_revoke}, + {"help", rpc_trustdom_usage}, + {NULL, NULL} + }; + + if (argc == 0) { + rpc_trustdom_usage(argc, argv); + return -1; + } + + return (net_run_function(argc, argv, func, rpc_user_usage)); +} + +/** + * Check if a server will take rpc commands + * @param flags Type of server to connect to (PDC, DMB, localhost) + * if the host is not explicitly specified + * @return BOOL (true means rpc supported) + */ +BOOL net_rpc_check(unsigned flags) +{ + struct cli_state cli; + BOOL ret = False; + struct in_addr server_ip; + char *server_name = NULL; + + /* flags (i.e. server type) may depend on command */ + if (!net_find_server(flags, &server_ip, &server_name)) + goto done; + + ZERO_STRUCT(cli); + if (cli_initialise(&cli) == False) + return False; + + if (!cli_connect(&cli, server_name, &server_ip)) + goto done; + if (!attempt_netbios_session_request(&cli, global_myname, + server_name, &server_ip)) + goto done; + if (!cli_negprot(&cli)) + goto done; + if (cli.protocol < PROTOCOL_NT1) + goto done; + + ret = True; + done: + cli_shutdown(&cli); + return ret; +} + + +/****************************************************************************/ + + +/** + * Basic usage function for 'net rpc' + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ + +int net_rpc_usage(int argc, const char **argv) +{ + d_printf(" net rpc join \t\t\tto join a domain \n"); + d_printf(" net rpc user \t\t\tto add, delete and list users\n"); + d_printf(" net rpc changetrustpw \tto change the trust account password\n"); + d_printf(" net rpc trustdom \t\tto create trusting domain's account or establish trust\n"); + d_printf(" net rpc abortshutdown \tto to abort the shutdown of a remote server\n"); + d_printf(" net rpc shutdown \t\tto to shutdown a remote server\n"); + d_printf("\n"); + d_printf("'net rpc shutdown' also accepts the following miscellaneous options:\n"); /* misc options */ + d_printf("\t-r or --reboot\trequest remote server reboot on shutdown\n"); + d_printf("\t-f or --force\trequest the remote server force its shutdown\n"); + d_printf("\t-t or --timeout=<timeout>\tnumber of seconds before shutdown\n"); + d_printf("\t-c or --comment=<message>\ttext message to display on impending shutdown\n"); + return -1; +} + + +/** + * Help function for 'net rpc'. Calls command specific help if requested + * or displays usage of net rpc + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ + +int net_rpc_help(int argc, const char **argv) +{ + struct functable func[] = { + {"join", rpc_join_usage}, + {"user", net_help_user}, + /*{"changetrustpw", rpc_changetrustpw_usage}, */ + {"trustdom", rpc_trustdom_usage}, + /*{"abortshutdown", rpc_shutdown_abort_usage},*/ + /*{"shutdown", rpc_shutdown_usage}, */ + {NULL, NULL} + }; + + if (argc == 0) { + net_rpc_usage(argc, argv); + return -1; + } + + return (net_run_function(argc, argv, func, rpc_user_usage)); +} + + +/** + * 'net rpc' entrypoint. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ + +int net_rpc(int argc, const char **argv) +{ + struct functable func[] = { + {"join", net_rpc_join}, + {"user", net_rpc_user}, + {"changetrustpw", rpc_changetrustpw}, + {"trustdom", rpc_trustdom}, + {"abortshutdown", rpc_shutdown_abort}, + {"shutdown", rpc_shutdown}, + {"help", net_rpc_help}, + {NULL, NULL} + }; + return net_run_function(argc, argv, func, net_rpc_usage); +} diff --git a/source3/utils/net_rpc_join.c b/source3/utils/net_rpc_join.c new file mode 100644 index 0000000000..c4558ea10b --- /dev/null +++ b/source3/utils/net_rpc_join.c @@ -0,0 +1,303 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) + Copyright (C) Tim Potter 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "../utils/net.h" + +/* Macro for checking RPC error codes to make things more readable */ + +#define CHECK_RPC_ERR(rpc, msg) \ + if (!NT_STATUS_IS_OK(result = rpc)) { \ + DEBUG(0, (msg ": %s\n", nt_errstr(result))); \ + goto done; \ + } + +#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \ + if (!NT_STATUS_IS_OK(result = rpc)) { \ + DEBUG(0, debug_args); \ + goto done; \ + } + +/** + * Join a domain using the administrator username and password + * + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped. Currently not used. + * @return A shell status integer (0 for success) + * + **/ + +int net_rpc_join_newstyle(int argc, const char **argv) +{ + + extern pstring global_myname; + + /* libsmb variables */ + + struct cli_state *cli; + fstring acct_name; + TALLOC_CTX *mem_ctx; + uint32 acb_info; + + /* rpc variables */ + + POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol; + DOM_SID domain_sid; + uint32 user_rid; + + /* Password stuff */ + + char *clear_trust_password = NULL; + fstring ucs2_trust_password; + int ucs2_pw_len; + uchar stored_md4_trust_password[16]; + uchar pwbuf[516], sess_key[16]; + SAM_USERINFO_CTR ctr; + SAM_USER_INFO_24 p24; + SAM_USER_INFO_10 p10; + + /* Misc */ + + NTSTATUS result; + int retval = 1; + fstring domain; + uint32 num_rids, *name_types, *user_rids; + uint32 flags = 0x3e8; + char *names; + + /* Connect to remote machine */ + + if (!(cli = net_make_ipc_connection(NET_FLAGS_PDC))) + return 1; + + if (!(mem_ctx = talloc_init())) { + DEBUG(0, ("Could not initialise talloc context\n")); + goto done; + } + + /* Fetch domain sid */ + + if (!cli_nt_session_open(cli, PIPE_LSARPC)) { + DEBUG(0, ("Error connecting to SAM pipe\n")); + goto done; + } + + + CHECK_RPC_ERR(cli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &lsa_pol), + "error opening lsa policy handle"); + + CHECK_RPC_ERR(cli_lsa_query_info_policy(cli, mem_ctx, &lsa_pol, + 5, domain, &domain_sid), + "error querying info policy"); + + cli_lsa_close(cli, mem_ctx, &lsa_pol); + + cli_nt_session_close(cli); /* Done with this pipe */ + + /* Create domain user */ + if (!cli_nt_session_open(cli, PIPE_SAMR)) { + DEBUG(0, ("Error connecting to SAM pipe\n")); + goto done; + } + + CHECK_RPC_ERR(cli_samr_connect(cli, mem_ctx, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &sam_pol), + "could not connect to SAM database"); + + + CHECK_RPC_ERR(cli_samr_open_domain(cli, mem_ctx, &sam_pol, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &domain_sid, &domain_pol), + "could not open domain"); + + /* Create domain user */ + fstrcpy(acct_name, global_myname); + fstrcat(acct_name, "$"); + strlower(acct_name); + + acb_info = ((lp_server_role() == ROLE_DOMAIN_BDC) || lp_server_role() == ROLE_DOMAIN_PDC) ? ACB_SVRTRUST : ACB_WSTRUST; + + result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol, + acct_name, acb_info, + 0xe005000b, &user_pol, + &user_rid); + + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) { + d_printf("Create of workstation account failed\n"); + + /* If NT_STATUS_ACCESS_DENIED then we have a valid + username/password combo but the user does not have + administrator access. */ + + if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) + d_printf("User specified does not have administrator privileges\n"); + + goto done; + } + + /* We *must* do this.... don't ask... */ + + if (NT_STATUS_IS_OK(result)) + cli_samr_close(cli, mem_ctx, &user_pol); + + names = (char *)&acct_name[0]; + + CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli, mem_ctx, + &domain_pol, flags, + 1, &names, &num_rids, + &user_rids, &name_types), + ("error looking up rid for user %s: %s\n", + acct_name, nt_errstr(result))); + + if (name_types[0] != SID_NAME_USER) { + DEBUG(0, ("%s is not a user account\n", acct_name)); + goto done; + } + + user_rid = user_rids[0]; + + /* Open handle on user */ + + CHECK_RPC_ERR_DEBUG( + cli_samr_open_user(cli, mem_ctx, &domain_pol, + SEC_RIGHTS_MAXIMUM_ALLOWED, + user_rid, &user_pol), + ("could not re-open existing user %s: %s\n", + acct_name, nt_errstr(result))); + + /* Create a random machine account password */ + + { + char *str; + str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); + clear_trust_password = strdup(str); + } + + ucs2_pw_len = push_ucs2(NULL, ucs2_trust_password, + clear_trust_password, + sizeof(ucs2_trust_password), 0); + + encode_pw_buffer((char *)pwbuf, ucs2_trust_password, + ucs2_pw_len); + + /* Set password on machine account */ + + ZERO_STRUCT(ctr); + ZERO_STRUCT(p24); + + init_sam_user_info24(&p24, (char *)pwbuf,24); + + ctr.switch_value = 24; + ctr.info.id24 = &p24; + + /* I don't think this is quite the right place for this + calculation. It should be moved somewhere where the credentials + are calculated. )-: */ + + mdfour(sess_key, cli->pwd.smb_nt_pwd, 16); + + CHECK_RPC_ERR(cli_samr_set_userinfo(cli, mem_ctx, &user_pol, 24, + sess_key, &ctr), + "error setting trust account password"); + + /* Why do we have to try to (re-)set the ACB to be the same as what + we passed in the samr_create_dom_user() call? When a NT + workstation is joined to a domain by an administrator the + acb_info is set to 0x80. For a normal user with "Add + workstations to the domain" rights the acb_info is 0x84. I'm + not sure whether it is supposed to make a difference or not. NT + seems to cope with either value so don't bomb out if the set + userinfo2 level 0x10 fails. -tpot */ + + ZERO_STRUCT(ctr); + ctr.switch_value = 0x10; + ctr.info.id10 = &p10; + + init_sam_user_info10(&p10, acb_info); + + /* Ignoring the return value is necessary for joining a domain + as a normal user with "Add workstation to domain" privilege. */ + + result = cli_samr_set_userinfo2(cli, mem_ctx, &user_pol, 0x10, + sess_key, &ctr); + + /* Now store the secret in the secrets database */ + + strupper(domain); + + if (!secrets_store_domain_sid(domain, &domain_sid)) { + DEBUG(0, ("error storing domain sid for %s\n", domain)); + goto done; + } + + if (!secrets_store_machine_password(clear_trust_password)) { + DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain)); + } + + /* Now check the whole process from top-to-bottom */ + + cli_samr_close(cli, mem_ctx, &user_pol); + + cli_nt_session_close(cli); /* Done with this pipe */ + + if (!cli_nt_session_open(cli, PIPE_NETLOGON)) { + DEBUG(0, ("Error connecting to NETLOGON pipe\n")); + goto done; + } + + if (!secrets_fetch_trust_account_password(domain, + stored_md4_trust_password, NULL)) { + DEBUG(0, ("Could not reterive secrets we just stored!")); + goto done; + } + + CHECK_RPC_ERR(new_cli_nt_setup_creds(cli, + (acb_info & ACB_SVRTRUST) ? SEC_CHAN_BDC : SEC_CHAN_WKSTA, + stored_md4_trust_password), + "error in domain join verification"); + + retval = 0; /* Success! */ + +done: + /* Close down pipe - this will clean up open policy handles */ + + if (cli->nt_pipe_fnum) + cli_nt_session_close(cli); + + /* Display success or failure */ + + if (retval != 0) { + trust_password_delete(domain); + fprintf(stderr,"Unable to join domain %s.\n",domain); + } else { + printf("Joined domain %s.\n",domain); + } + + cli_shutdown(cli); + + SAFE_FREE(clear_trust_password); + + return retval; +} diff --git a/source3/utils/net_time.c b/source3/utils/net_time.c new file mode 100644 index 0000000000..3f5532109c --- /dev/null +++ b/source3/utils/net_time.c @@ -0,0 +1,185 @@ +/* + Samba Unix/Linux SMB client library + net time command + Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "../utils/net.h" + + +/* + return the time on a server. This does not require any authentication +*/ +static time_t cli_servertime(const char *host, struct in_addr *ip, int *zone) +{ + struct nmb_name calling, called; + time_t ret = 0; + extern pstring global_myname; + struct cli_state *cli = NULL; + + cli = cli_initialise(NULL); + if (!cli) goto done; + + if (!cli_connect(cli, host, ip)) { + fprintf(stderr,"Can't contact server\n"); + goto done; + } + + make_nmb_name(&calling, global_myname, 0x0); + if (host) { + make_nmb_name(&called, host, 0x20); + } else { + make_nmb_name(&called, "*SMBSERVER", 0x20); + } + + if (!cli_session_request(cli, &calling, &called)) { + fprintf(stderr,"Session request failed\n"); + goto done; + } + if (!cli_negprot(cli)) { + fprintf(stderr,"Protocol negotiation failed\n"); + goto done; + } + + ret = cli->servertime; + if (zone) *zone = cli->serverzone; + +done: + if (cli) cli_shutdown(cli); + return ret; +} + +/* find the servers time on the opt_host host */ +static time_t nettime(int *zone) +{ + extern BOOL opt_have_ip; + extern struct in_addr opt_dest_ip; + extern char *opt_host; + return cli_servertime(opt_host, opt_have_ip? &opt_dest_ip : NULL, zone); +} + +/* return a time as a string ready to be passed to /bin/date */ +static char *systime(time_t t) +{ + static char s[100]; + struct tm *tm; + + tm = localtime(&t); + + snprintf(s, sizeof(s), "%02d%02d%02d%02d%04d.%02d", + tm->tm_mon+1, tm->tm_mday, tm->tm_hour, + tm->tm_min, tm->tm_year + 1900, tm->tm_sec); + return s; +} + +int net_time_usage(int argc, const char **argv) +{ + d_printf( +"net time\n\tdisplays time on a server\n\n"\ +"net time system\n\tdisplays time on a server in a format ready for /bin/date\n\n"\ +"net time set\n\truns /bin/date with the time from the server\n\n"\ +"net time zone\n\tdisplays the timezone in hours from GMT on the remote computer\n\n"\ +"\n"); + net_common_flags_usage(argc, argv); + return -1; +} + +/* try to set the system clock using /bin/date */ +static int net_time_set(int argc, const char **argv) +{ + time_t t = nettime(NULL); + char *cmd; + + if (t == 0) return -1; + + /* yes, I know this is cheesy. Use "net time system" if you want to + roll your own. I'm putting this in as it works on a large number + of systems and the user has a choice in whether its used or not */ + asprintf(&cmd, "/bin/date %s", systime(t)); + system(cmd); + free(cmd); + + return 0; +} + +/* display the time on a remote box in a format ready for /bin/date */ +static int net_time_system(int argc, const char **argv) +{ + time_t t = nettime(NULL); + + if (t == 0) return -1; + + printf("%s\n", systime(t)); + + return 0; +} + +/* display the time on a remote box in a format ready for /bin/date */ +static int net_time_zone(int argc, const char **argv) +{ + int zone = 0; + int hours, mins; + char zsign; + time_t t; + + t = nettime(&zone); + + if (t == 0) return -1; + + zsign = (zone > 0) ? '-' : '+'; + if (zone < 0) zone = -zone; + + zone /= 60; + hours = zone / 60; + mins = zone % 60; + + printf("%c%02d%02d\n", zsign, hours, mins); + + return 0; +} + +/* display or set the time on a host */ +int net_time(int argc, const char **argv) +{ + time_t t; + extern BOOL opt_have_ip; + extern struct in_addr opt_dest_ip; + extern char *opt_host; + struct functable func[] = { + {"SYSTEM", net_time_system}, + {"SET", net_time_set}, + {"ZONE", net_time_zone}, + {NULL, NULL} + }; + + if (!opt_host && !opt_have_ip) { + d_printf("You must specify a hostname or IP\n"); + net_time_usage(argc,argv); + return -1; + } + + if (argc != 0) { + return net_run_function(argc, argv, func, net_time_usage); + } + + /* default - print the time */ + t = cli_servertime(opt_host, opt_have_ip? &opt_dest_ip : NULL, NULL); + if (t == 0) return -1; + + d_printf("%s", ctime(&t)); + return 0; +} diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c index aa43173332..9549d16d04 100644 --- a/source3/utils/nmblookup.c +++ b/source3/utils/nmblookup.c @@ -1,8 +1,7 @@ /* - Unix SMB/Netbios implementation. - Version 1.9. + Unix SMB/CIFS implementation. NBT client - used to lookup netbios names - Copyright (C) Andrew Tridgell 1994-1995 + Copyright (C) Andrew Tridgell 1994-1998 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 @@ -20,44 +19,35 @@ */ -#ifdef SYSLOG -#undef SYSLOG -#endif +#define NO_SYSLOG #include "includes.h" -#include "nameserv.h" -extern int DEBUGLEVEL; - -extern pstring scope; - -extern struct in_addr bcast_ip; -extern pstring myhostname; +extern BOOL AllowDebugChange; +static BOOL use_bcast = True; static BOOL got_bcast = False; - -int ServerFD= -1; +static struct in_addr bcast_addr; +static BOOL recursion_desired = False; +static BOOL translate_addresses = False; +static int ServerFD= -1; +static int RootPort = False; +static BOOL find_status=False; /**************************************************************************** open the socket communication **************************************************************************/ static BOOL open_sockets(void) { - struct hostent *hp; - - /* get host info */ - if ((hp = Get_Hostbyname(myhostname)) == 0) - { - DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname)); - return False; - } - - ServerFD = open_socket_in(SOCK_DGRAM, 0,3); + ServerFD = open_socket_in( SOCK_DGRAM, + (RootPort ? 137 : 0), + (RootPort ? 0 : 3), + interpret_addr(lp_socket_address()), True ); if (ServerFD == -1) return(False); - set_socket_options(ServerFD,"SO_BROADCAST"); + set_socket_options( ServerFD, "SO_BROADCAST" ); DEBUG(3, ("Socket opened.\n")); return True; @@ -65,43 +55,128 @@ static BOOL open_sockets(void) /**************************************************************************** - initialise connect, service and file structs +usage on the program ****************************************************************************/ -static BOOL init_structs(void ) +static void usage(void) { - struct in_addr myip; - - if (!get_myname(myhostname,&myip)) - return(False); - - /* Read the broadcast address from the interface */ - { - struct in_addr ip0,ip2; - - ip0 = myip; - - if (!got_bcast) { - get_broadcast(&ip0,&bcast_ip,&ip2); + d_printf("Usage: nmblookup [-M] [-B bcast address] [-d debuglevel] 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-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"); +} - DEBUG(2,("Using broadcast %s\n",inet_ntoa(bcast_ip))); - } - } +/**************************************************************************** +turn a node status flags field into a string +****************************************************************************/ +static char *node_status_flags(unsigned char flags) +{ + static fstring ret; + fstrcpy(ret,""); + + fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " "); + if ((flags & 0x60) == 0x00) fstrcat(ret,"B "); + if ((flags & 0x60) == 0x20) fstrcat(ret,"P "); + if ((flags & 0x60) == 0x40) fstrcat(ret,"M "); + if ((flags & 0x60) == 0x60) fstrcat(ret,"H "); + if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> "); + if (flags & 0x08) fstrcat(ret,"<CONFLICT> "); + if (flags & 0x04) fstrcat(ret,"<ACTIVE> "); + if (flags & 0x02) fstrcat(ret,"<PERMANENT> "); + + return ret; +} - return True; +/**************************************************************************** +do a node status query +****************************************************************************/ +static void do_node_status(int fd, char *name, int type, struct in_addr ip) +{ + struct nmb_name nname; + int count, i, j; + struct node_status *status; + fstring cleanname; + + d_printf("Looking up status of %s\n",inet_ntoa(ip)); + make_nmb_name(&nname, name, type); + status = node_status_query(fd,&nname,ip, &count); + if (status) { + for (i=0;i<count;i++) { + fstrcpy(cleanname, status[i].name); + for (j=0;cleanname[j];j++) { + if (!isprint((int)cleanname[j])) cleanname[j] = '.'; + } + d_printf("\t%-15s <%02x> - %s\n", + cleanname,status[i].type, + node_status_flags(status[i].flags)); + } + SAFE_FREE(status); + } + d_printf("\n"); } + /**************************************************************************** -usage on the program +send out one query ****************************************************************************/ -static void usage(void) +static BOOL query_one(char *lookup, unsigned int lookup_type) { - printf("Usage: nmblookup [-M] [-B bcast address] [-d debuglevel] name\n"); - printf("Version %s\n",VERSION); - printf("\t-d debuglevel set the debuglevel\n"); - printf("\t-B broadcast address the address to use for broadcasts\n"); - printf("\t-M searches for a master browser\n"); - printf("\t-S lookup node status as well\n"); - printf("\n"); + int j, count; + struct in_addr *ip_list=NULL; + + if (got_bcast) { + d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr)); + ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast, + use_bcast?True:recursion_desired, + bcast_addr,&count); + } else { + struct in_addr *bcast; + for (j=iface_count() - 1; + !ip_list && j >= 0; + j--) { + bcast = iface_n_bcast(j); + d_printf("querying %s on %s\n", + lookup, inet_ntoa(*bcast)); + ip_list = name_query(ServerFD,lookup,lookup_type, + use_bcast, + use_bcast?True:recursion_desired, + *bcast,&count); + } + } + + if (!ip_list) return False; + + for (j=0;j<count;j++) { + if (translate_addresses) { + struct hostent *host = gethostbyaddr((char *)&ip_list[j], sizeof(ip_list[j]), AF_INET); + if (host) { + d_printf("%s, ", host -> h_name); + } + } + d_printf("%s %s<%02x>\n",inet_ntoa(ip_list[j]),lookup, lookup_type); + } + + /* We can only do find_status if the ip address returned + was valid - ie. name_query returned true. + */ + if (find_status) { + do_node_status(ServerFD, lookup, lookup_type, ip_list[0]); + } + + safe_free(ip_list); + + return (ip_list != NULL); } @@ -111,50 +186,71 @@ static void usage(void) int main(int argc,char *argv[]) { int opt; - unsigned int lookup_type = 0x20; + unsigned int lookup_type = 0x0; pstring lookup; extern int optind; extern char *optarg; BOOL find_master=False; - BOOL find_status=False; int i; - + BOOL lookup_by_ip = False; + int commandline_debuglevel = -2; + DEBUGLEVEL = 1; - *lookup = 0; + /* Prevent smb.conf setting from overridding */ + AllowDebugChange = False; - TimeInit(); + *lookup = 0; setup_logging(argv[0],True); - charset_initialise(); - - while ((opt = getopt(argc, argv, "p:d:B:i:SMh")) != EOF) + while ((opt = getopt(argc, argv, "d:B:U:i:s:SMrhART")) != EOF) switch (opt) { case 'B': - { - unsigned long a = interpret_addr(optarg); - putip((char *)&bcast_ip,(char *)&a); - got_bcast = True; - } + bcast_addr = *interpret_addr2(optarg); + got_bcast = True; + use_bcast = True; break; - case 'i': - strcpy(scope,optarg); - strupper(scope); + case 'U': + bcast_addr = *interpret_addr2(optarg); + got_bcast = True; + use_bcast = False; + break; + case 'T': + translate_addresses = !translate_addresses; break; + case 'i': + { + extern pstring global_scope; + pstrcpy(global_scope,optarg); + strupper(global_scope); + } + break; case 'M': find_master = True; break; case 'S': find_status = True; break; + case 'R': + recursion_desired = True; + break; case 'd': - DEBUGLEVEL = atoi(optarg); + 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); @@ -165,53 +261,58 @@ int main(int argc,char *argv[]) exit(1); } - init_structs(); - if (!open_sockets()) return(1); + if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); + } - DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_ip))); + /* + * 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); for (i=optind;i<argc;i++) - { - BOOL bcast = True; - int retries = 2; + { char *p; struct in_addr ip; - strcpy(lookup,argv[i]); + 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 == '-') { - strcpy(lookup,"\01\02__MSBROWSE__\02"); + fstrcpy(lookup,"\01\02__MSBROWSE__\02"); lookup_type = 1; } else { lookup_type = 0x1d; } } - p = strchr(lookup,'#'); - + p = strchr_m(lookup,'#'); if (p) { - *p = 0; - sscanf(p+1,"%x",&lookup_type); - bcast = False; - retries = 1; + *p = '\0'; + sscanf(++p,"%x",&lookup_type); } - if (name_query(ServerFD,lookup,lookup_type,bcast,True, - bcast_ip,&ip,NULL)) - { - printf("%s %s\n",inet_ntoa(ip),lookup); - if (find_status) - { - printf("Looking up status of %s\n",inet_ntoa(ip)); - name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL); - printf("\n"); - } - } else { - printf("couldn't find name %s\n",lookup); + 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" ); } - } - + } + return(0); } diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c new file mode 100644 index 0000000000..1fb1f2355b --- /dev/null +++ b/source3/utils/pdbedit.c @@ -0,0 +1,692 @@ +/* + Unix SMB/CIFS implementation. + passdb editing frontend + + Copyright (C) Simo Sorce 2000 + Copyright (C) Andrew Bartlett 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern pstring global_myname; +extern BOOL AllowDebugChange; + +/* + * Next two lines needed for SunOS and don't + * hurt anything else... + */ +extern char *optarg; +extern int optind; + +/********************************************************* + Print command usage on stderr and die. +**********************************************************/ +static void usage(void) +{ + if (getuid() == 0) { + printf("pdbedit options\n"); + } else { + printf("You need to be root to use this tool!\n"); + } + printf("(actually to add a user you need to use smbpasswd)\n"); + printf("options:\n"); + printf(" -l list usernames\n"); + printf(" -v verbose output\n"); + printf(" -w smbpasswd file style\n"); + printf(" -u username print user's info\n"); + printf(" -f fullname set Full Name\n"); + printf(" -h homedir set home directory\n"); + printf(" -d drive set home dir drive\n"); + printf(" -s script set logon script\n"); + printf(" -p profile set profile path\n"); + printf(" -a create new account\n"); + printf(" -m it is a machine trust\n"); + printf(" -x delete this user\n"); + printf(" -i file import account from file (smbpasswd style)\n"); + printf(" -D debuglevel set DEBUGELEVEL (default = 1)\n"); + exit(1); +} + +/********************************************************* + Print info from sam structure +**********************************************************/ + +static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdstyle) +{ + uid_t uid; + gid_t gid; + + /* TODO: chaeck if entry is a user or a workstation */ + if (!sam_pwent) return -1; + + if (verbosity) { + printf ("username: %s\n", pdb_get_username(sam_pwent)); + if (IS_SAM_UNIX_USER(sam_pwent)) { + uid = pdb_get_uid(sam_pwent); + gid = pdb_get_gid(sam_pwent); + printf ("user ID/Group: %d/%d\n", uid, gid); + } + printf ("user RID/GRID: %u/%u\n", (unsigned int)pdb_get_user_rid(sam_pwent), + (unsigned int)pdb_get_group_rid(sam_pwent)); + printf ("Full Name: %s\n", pdb_get_fullname(sam_pwent)); + printf ("Home Directory: %s\n", pdb_get_homedir(sam_pwent)); + printf ("HomeDir Drive: %s\n", pdb_get_dirdrive(sam_pwent)); + printf ("Logon Script: %s\n", pdb_get_logon_script(sam_pwent)); + printf ("Profile Path: %s\n", pdb_get_profile_path(sam_pwent)); + } else if (smbpwdstyle) { + if (IS_SAM_UNIX_USER(sam_pwent)) { + char lm_passwd[33]; + char nt_passwd[33]; + + uid = pdb_get_uid(sam_pwent); + pdb_sethexpwd(lm_passwd, + pdb_get_lanman_passwd(sam_pwent), + pdb_get_acct_ctrl(sam_pwent)); + pdb_sethexpwd(nt_passwd, + pdb_get_nt_passwd(sam_pwent), + pdb_get_acct_ctrl(sam_pwent)); + + printf("%s:%d:%s:%s:%s:LCT-%08X:\n", + pdb_get_username(sam_pwent), + uid, + lm_passwd, + nt_passwd, + pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN), + (uint32)pdb_get_pass_last_set_time(sam_pwent)); + } else { + fprintf(stderr, "Can't output in smbpasswd format, no uid on this record.\n"); + } + } else { + if (IS_SAM_UNIX_USER(sam_pwent)) { + printf ("%s:%d:%s\n", pdb_get_username(sam_pwent), pdb_get_uid(sam_pwent), + pdb_get_fullname(sam_pwent)); + } else { + printf ("%s:(null):%s\n", pdb_get_username(sam_pwent), pdb_get_fullname(sam_pwent)); + } + } + + return 0; +} + +/********************************************************* + Get an Print User Info +**********************************************************/ + +static int print_user_info (char *username, BOOL verbosity, BOOL smbpwdstyle) +{ + SAM_ACCOUNT *sam_pwent=NULL; + BOOL ret; + + if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) { + return -1; + } + + ret = pdb_getsampwnam (sam_pwent, username); + + if (ret==False) { + fprintf (stderr, "Username not found!\n"); + pdb_free_sam(&sam_pwent); + return -1; + } + + ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle); + pdb_free_sam(&sam_pwent); + + return ret; +} + +/********************************************************* + List Users +**********************************************************/ +static int print_users_list (BOOL verbosity, BOOL smbpwdstyle) +{ + SAM_ACCOUNT *sam_pwent=NULL; + BOOL check, ret; + + errno = 0; /* testing --simo */ + check = pdb_setsampwent(False); + if (check && errno == ENOENT) { + fprintf (stderr,"Password database not found!\n"); + exit(1); + } + + check = True; + if (!(NT_STATUS_IS_OK(pdb_init_sam(&sam_pwent)))) return 1; + + while (check && (ret = pdb_getsampwent (sam_pwent))) { + if (verbosity) + printf ("---------------\n"); + print_sam_info (sam_pwent, verbosity, smbpwdstyle); + pdb_free_sam(&sam_pwent); + check = NT_STATUS_IS_OK(pdb_init_sam(&sam_pwent)); + } + if (check) pdb_free_sam(&sam_pwent); + + pdb_endsampwent(); + return 0; +} + +/********************************************************* + Set User Info +**********************************************************/ + +static int set_user_info (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile) +{ + SAM_ACCOUNT *sam_pwent=NULL; + BOOL ret; + + pdb_init_sam(&sam_pwent); + + ret = pdb_getsampwnam (sam_pwent, username); + if (ret==False) { + fprintf (stderr, "Username not found!\n"); + pdb_free_sam(&sam_pwent); + return -1; + } + + if (fullname) + pdb_set_fullname(sam_pwent, fullname); + if (homedir) + pdb_set_homedir(sam_pwent, homedir, True); + if (drive) + pdb_set_dir_drive(sam_pwent,drive, True); + if (script) + pdb_set_logon_script(sam_pwent, script, True); + if (profile) + pdb_set_profile_path (sam_pwent, profile, True); + + if (pdb_update_sam_account (sam_pwent)) + print_user_info (username, True, False); + else { + fprintf (stderr, "Unable to modify entry!\n"); + pdb_free_sam(&sam_pwent); + return -1; + } + pdb_free_sam(&sam_pwent); + return 0; +} + +/********************************************************* + Add New User +**********************************************************/ +static int new_user (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile) +{ + SAM_ACCOUNT *sam_pwent=NULL; + struct passwd *pwd = NULL; + char *password1, *password2; + + ZERO_STRUCT(sam_pwent); + + if ((pwd = getpwnam_alloc(username))) { + pdb_init_sam_pw (&sam_pwent, pwd); + passwd_free(&pwd); + } else { + fprintf (stderr, "WARNING: user %s does not exist in system passwd\n", username); + pdb_init_sam(&sam_pwent); + if (!pdb_set_username(sam_pwent, username)) { + return False; + } + } + + password1 = getpass("new password:"); + password2 = getpass("retype new password:"); + if (strcmp (password1, password2)) { + fprintf (stderr, "Passwords does not match!\n"); + pdb_free_sam (&sam_pwent); + return -1; + } + + pdb_set_plaintext_passwd(sam_pwent, password1); + + if (fullname) + pdb_set_fullname(sam_pwent, fullname); + if (homedir) + pdb_set_homedir (sam_pwent, homedir, True); + if (drive) + pdb_set_dir_drive (sam_pwent, drive, True); + if (script) + pdb_set_logon_script(sam_pwent, script, True); + if (profile) + pdb_set_profile_path (sam_pwent, profile, True); + + pdb_set_acct_ctrl (sam_pwent, ACB_NORMAL); + + if (pdb_add_sam_account (sam_pwent)) { + print_user_info (username, True, False); + } else { + fprintf (stderr, "Unable to add user! (does it alredy exist?)\n"); + pdb_free_sam (&sam_pwent); + return -1; + } + pdb_free_sam (&sam_pwent); + return 0; +} + +/********************************************************* + Add New Machine +**********************************************************/ + +static int new_machine (char *machinename) +{ + SAM_ACCOUNT *sam_pwent=NULL; + char name[16]; + char *password = NULL; + + if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) { + return -1; + } + + if (machinename[strlen (machinename) -1] == '$') + machinename[strlen (machinename) -1] = '\0'; + + safe_strcpy (name, machinename, 16); + safe_strcat (name, "$", 16); + + string_set (&password, machinename); + strlower_m(password); + + pdb_set_plaintext_passwd (sam_pwent, password); + + pdb_set_username (sam_pwent, name); + + pdb_set_acct_ctrl (sam_pwent, ACB_WSTRUST); + + pdb_set_group_rid(sam_pwent, DOMAIN_GROUP_RID_COMPUTERS); + + if (pdb_add_sam_account (sam_pwent)) { + print_user_info (name, True, False); + } else { + fprintf (stderr, "Unable to add machine! (does it already exist?)\n"); + pdb_free_sam (&sam_pwent); + return -1; + } + pdb_free_sam (&sam_pwent); + return 0; +} + +/********************************************************* + Delete user entry +**********************************************************/ + +static int delete_user_entry (char *username) +{ + SAM_ACCOUNT *samaccount = NULL; + + if (!NT_STATUS_IS_OK(pdb_init_sam (&samaccount))) { + return -1; + } + + if (!pdb_getsampwnam(samaccount, username)) { + fprintf (stderr, "user %s does not exist in the passdb\n", username); + return -1; + } + + return pdb_delete_sam_account (samaccount); +} + +/********************************************************* + Delete machine entry +**********************************************************/ + +static int delete_machine_entry (char *machinename) +{ + char name[16]; + SAM_ACCOUNT *samaccount = NULL; + + safe_strcpy (name, machinename, 16); + if (name[strlen(name)] != '$') + safe_strcat (name, "$", 16); + + if (!NT_STATUS_IS_OK(pdb_init_sam (&samaccount))) { + return -1; + } + + if (!pdb_getsampwnam(samaccount, name)) { + fprintf (stderr, "user %s does not exist in the passdb\n", name); + return -1; + } + + return pdb_delete_sam_account (samaccount); +} + +/********************************************************* + Import smbpasswd style file +**********************************************************/ + +static int import_users (char *filename) +{ + FILE *fp = NULL; + SAM_ACCOUNT *sam_pwent = NULL; + static pstring user_name; + static unsigned char smbpwd[16]; + static unsigned char smbntpwd[16]; + char linebuf[256]; + size_t linebuf_len; + unsigned char c; + unsigned char *p; + long uidval; + int line = 0; + int good = 0; + struct passwd *pwd; + + if((fp = sys_fopen(filename, "rb")) == NULL) { + fprintf (stderr, "%s\n", strerror (ferror (fp))); + return -1; + } + + while (!feof(fp)) { + /*Get a new line*/ + linebuf[0] = '\0'; + fgets(linebuf, 256, fp); + if (ferror(fp)) { + fprintf (stderr, "%s\n", strerror (ferror (fp))); + return -1; + } + if ((linebuf_len = strlen(linebuf)) == 0) { + line++; + continue; + } + if (linebuf[linebuf_len - 1] != '\n') { + c = '\0'; + while (!ferror(fp) && !feof(fp)) { + c = fgetc(fp); + if (c == '\n') break; + } + } else + linebuf[linebuf_len - 1] = '\0'; + linebuf[linebuf_len] = '\0'; + if ((linebuf[0] == 0) && feof(fp)) { + /*end of file!!*/ + return 0; + } + line++; + if (linebuf[0] == '#' || linebuf[0] == '\0') + continue; + + /* Get user name */ + p = (unsigned char *) strchr_m(linebuf, ':'); + if (p == NULL) { + fprintf (stderr, "Error: malformed password entry at line %d !!\n", line); + continue; + } + strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); + user_name[PTR_DIFF(p, linebuf)] = '\0'; + + /* Get smb uid. */ + p++; + if(*p == '-') { + fprintf (stderr, "Error: negative uid at line %d\n", line); + continue; + } + if (!isdigit(*p)) { + fprintf (stderr, "Error: malformed password entry at line %d (uid not number)\n", line); + continue; + } + uidval = atoi((char *) p); + while (*p && isdigit(*p)) p++; + if (*p != ':') { + fprintf (stderr, "Error: malformed password entry at line %d (no : after uid)\n", line); + continue; + } + if(!(pwd = sys_getpwnam(user_name))) { + fprintf(stderr, "User %s does not \ +exist in system password file (usually /etc/passwd). Cannot add \ +account without a valid local system user.\n", user_name); + return False; + } + + if (!NT_STATUS_IS_OK(pdb_init_sam_pw(&sam_pwent, pwd))) { + fprintf(stderr, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name); + return False; + } + + /* Get passwords */ + p++; + if (*p == '*' || *p == 'X') { + /* Password deliberately invalid */ + fprintf (stderr, "Warning: entry invalidated for user %s\n", user_name); + pdb_set_lanman_passwd(sam_pwent, NULL); + pdb_set_nt_passwd(sam_pwent,NULL); + pdb_set_acct_ctrl(sam_pwent, pdb_get_acct_ctrl(sam_pwent) | ACB_DISABLED); + } else { + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + fprintf (stderr, "Error: malformed password entry at line %d (password too short)\n",line); + pdb_free_sam (&sam_pwent); + continue; + } + if (p[32] != ':') { + fprintf (stderr, "Error: malformed password entry at line %d (no terminating :)\n",line); + pdb_free_sam (&sam_pwent); + continue; + } + if (!strncasecmp((char *) p, "NO PASSWORD", 11)) { + pdb_set_lanman_passwd(sam_pwent, NULL); + pdb_set_acct_ctrl(sam_pwent, pdb_get_acct_ctrl(sam_pwent) | ACB_PWNOTREQ); + } else { + if (!pdb_gethexpwd((char *)p, smbpwd)) { + fprintf (stderr, "Error: malformed Lanman password entry at line %d (non hex chars)\n", line); + pdb_free_sam (&sam_pwent); + continue; + } + pdb_set_lanman_passwd(sam_pwent, smbpwd); + } + /* NT password */ + p += 33; + if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { + if (*p != '*' && *p != 'X') { + if (pdb_gethexpwd((char *)p,smbntpwd)) { + pdb_set_nt_passwd(sam_pwent, smbntpwd); + } + } + p += 33; + } + } + + /* Get ACCT_CTRL field if any */ + if (*p == '[') { + uint16 acct_ctrl; + unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']'); + + acct_ctrl = pdb_decode_acct_ctrl((char*)p); + if (acct_ctrl) + acct_ctrl = ACB_NORMAL; + + pdb_set_acct_ctrl(sam_pwent, acct_ctrl); + + /* Get last change time */ + if(end_p) + p = end_p + 1; + if(*p == ':') { + p++; + if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) { + int i; + + p += 4; + for(i = 0; i < 8; i++) { + if(p[i] == '\0' || !isxdigit(p[i])) break; + } + if(i == 8) { + pdb_set_pass_last_set_time (sam_pwent, (time_t)strtol((char *)p, NULL, 16)); + } + } + } + } + + /* Now ADD the entry */ + if (!(pdb_add_sam_account (sam_pwent))) { + fprintf (stderr, "Unable to add user entry!\n"); + pdb_free_sam (&sam_pwent); + continue; + } + printf ("%s imported!\n", user_name); + good++; + pdb_free_sam (&sam_pwent); + } + printf ("%d lines read.\n%d entryes imported\n", line, good); + return 0; +} + +/********************************************************* + Start here. +**********************************************************/ + +int main (int argc, char **argv) +{ + int ch; + BOOL list_users = False; + BOOL verbose = False; + BOOL spstyle = False; + BOOL setparms = False; + BOOL machine = False; + BOOL add_user = False; + BOOL delete_user = False; + BOOL import = False; + char *user_name = NULL; + char *full_name = NULL; + char *home_dir = NULL; + char *home_drive = NULL; + char *logon_script = NULL; + char *profile_path = NULL; + char *smbpasswd = NULL; + + setup_logging("pdbedit", True); + + if (argc < 2) { + usage(); + return 0; + } + + DEBUGLEVEL = 1; + AllowDebugChange = False; + + if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", + dyn_CONFIGFILE); + exit(1); + } + + if(!initialize_password_db(True)) { + fprintf(stderr, "Can't setup password database vectors.\n"); + exit(1); + } + + while ((ch = getopt(argc, argv, "ad:f:h:i:lmp:s:u:vwxD:")) != EOF) { + switch(ch) { + case 'a': + add_user = True; + break; + case 'm': + machine = True; + break; + case 'l': + list_users = True; + break; + case 'v': + verbose = True; + break; + case 'w': + spstyle = True; + break; + case 'u': + user_name = optarg; + break; + case 'f': + setparms = True; + full_name = optarg; + break; + case 'h': + setparms = True; + home_dir = optarg; + break; + case 'd': + setparms = True; + home_drive = optarg; + break; + case 's': + setparms = True; + logon_script = optarg; + break; + case 'p': + setparms = True; + profile_path = optarg; + break; + case 'x': + delete_user = True; + break; + case 'i': + import = True; + smbpasswd = optarg; + break; + case 'D': + DEBUGLEVEL = atoi(optarg); + break; + default: + usage(); + } + } + if (((add_user?1:0) + (delete_user?1:0) + (list_users?1:0) + (import?1:0) + (setparms?1:0)) > 1) { + fprintf (stderr, "Incompatible options on command line!\n"); + usage(); + exit(1); + } + + if (add_user) { + if (!user_name) { + fprintf (stderr, "Username not specified! (use -u option)\n"); + return -1; + } + if (machine) + return new_machine (user_name); + else + return new_user (user_name, full_name, home_dir, home_drive, logon_script, profile_path); + } + + if (delete_user) { + if (!user_name) { + fprintf (stderr, "Username not specified! (use -u option)\n"); + return -1; + } + if (machine) + return delete_machine_entry (user_name); + else + return delete_user_entry (user_name); + } + + if (user_name) { + if (setparms) + set_user_info ( user_name, full_name, + home_dir, + home_drive, + logon_script, + profile_path); + else + return print_user_info (user_name, verbose, spstyle); + + return 0; + } + + + if (list_users) + return print_users_list (verbose, spstyle); + + if (import) + return import_users (smbpasswd); + + usage(); + + return 0; +} diff --git a/source3/utils/rpccheck.c b/source3/utils/rpccheck.c new file mode 100644 index 0000000000..ab7286f8be --- /dev/null +++ b/source3/utils/rpccheck.c @@ -0,0 +1,62 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Jean François Micouleau 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +main() +{ + char filter[]="0123456789ABCDEF"; + + char s[128]; + char d=0; + int x=0; + prs_struct ps; + TALLOC_CTX *ctx; + + /* change that struct */ + SAMR_R_QUERY_USERINFO rpc_stub; + + ZERO_STRUCT(rpc_stub); + + setup_logging("", True); + DEBUGLEVEL=10; + + ctx=talloc_init(); + if (!ctx) exit(1); + + prs_init(&ps, 1600, 4, ctx, MARSHALL); + + while (scanf("%s", s)!=-1) { + if (strlen(s)==2 && strchr_m(filter, *s)!=NULL && strchr_m(filter, *(s+1))!=NULL) { + d=strtol(s, NULL, 16); + if(!prs_append_data(&ps, &d, 1)) + printf("error while reading data\n"); + } + } + + prs_switch_type(&ps, UNMARSHALL); + prs_set_offset(&ps, 0); + + /* change that call */ + if(!samr_io_r_query_userinfo("", &rpc_stub, &ps, 0)) + printf("error while UNMARSHALLING the data\n"); + + printf("\n"); +} diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c new file mode 100644 index 0000000000..8c0b2a4a72 --- /dev/null +++ b/source3/utils/smbcacls.c @@ -0,0 +1,964 @@ +/* + Unix SMB/CIFS implementation. + ACL get/set utility + + Copyright (C) Andrew Tridgell 2000 + Copyright (C) Tim Potter 2000 + Copyright (C) Jeremy Allison 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static fstring password; +static pstring username; +static pstring owner_username; +static fstring server; +static int got_pass; +static int test_args; +TALLOC_CTX *ctx; + +#define CREATE_ACCESS_READ READ_CONTROL_ACCESS +#define CREATE_ACCESS_WRITE (WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS) + +/* numeric is set when the user wants numeric SIDs and ACEs rather + than going via LSA calls to resolve them */ +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}; +enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR}; + +struct perm_value { + char *perm; + uint32 mask; +}; + +/* These values discovered by inspection */ + +static struct perm_value special_values[] = { + { "R", 0x00120089 }, + { "W", 0x00120116 }, + { "X", 0x001200a0 }, + { "D", 0x00010000 }, + { "P", 0x00040000 }, + { "O", 0x00080000 }, + { NULL, 0 }, +}; + +static struct perm_value standard_values[] = { + { "READ", 0x001200a9 }, + { "CHANGE", 0x001301bf }, + { "FULL", 0x001f01ff }, + { NULL, 0 }, +}; + +struct cli_state lsa_cli; +POLICY_HND pol; +struct ntuser_creds creds; +BOOL got_policy_hnd; + +/* Open cli connection and policy handle */ + +static BOOL cacls_open_policy_hnd(void) +{ + creds.pwd.null_pwd = 1; + + /* Initialise cli LSA connection */ + + if (!lsa_cli.initialised && + !cli_lsa_initialise(&lsa_cli, server, &creds)) { + return False; + } + + /* Open policy handle */ + + if (!got_policy_hnd) { + + /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED, + but NT sends 0x2000000 so we might as well do it too. */ + + if (!NT_STATUS_IS_OK(cli_lsa_open_policy(&lsa_cli, lsa_cli.mem_ctx, True, + GENERIC_EXECUTE_ACCESS, &pol))) { + return False; + } + + got_policy_hnd = True; + } + + return True; +} + +/* convert a SID to a string, either numeric or username/group */ +static void SidToString(fstring str, DOM_SID *sid) +{ + char **domains = NULL; + char **names = NULL; + uint32 *types = NULL; + int num_names; + + sid_to_string(str, sid); + + if (numeric) return; + + /* Ask LSA to convert the sid to a name */ + + if (!cacls_open_policy_hnd() || + !NT_STATUS_IS_OK(cli_lsa_lookup_sids(&lsa_cli, lsa_cli.mem_ctx, + &pol, 1, sid, &domains, &names, + &types, &num_names)) || + !domains || !domains[0] || !names || !names[0]) { + return; + } + + /* Converted OK */ + + slprintf(str, sizeof(fstring) - 1, "%s%s%s", + domains[0], lp_winbind_separator(), + names[0]); + +} + +/* convert a string to a SID, either numeric or username/group */ +static BOOL StringToSid(DOM_SID *sid, const char *str) +{ + uint32 *types = NULL; + DOM_SID *sids = NULL; + int num_sids; + BOOL result = True; + + if (strncmp(str, "S-", 2) == 0) { + return string_to_sid(sid, str); + } + + if (!cacls_open_policy_hnd() || + !NT_STATUS_IS_OK(cli_lsa_lookup_names(&lsa_cli, lsa_cli.mem_ctx, &pol, 1, + &str, + &sids, &types, &num_sids))) { + result = False; + goto done; + } + + sid_copy(sid, &sids[0]); + + done: + + return result; +} + + +/* print an ACE on a FILE, using either numeric or ascii representation */ +static void print_ace(FILE *f, SEC_ACE *ace) +{ + struct perm_value *v; + fstring sidstr; + int do_print = 0; + uint32 got_mask; + + SidToString(sidstr, &ace->trustee); + + fprintf(f, "%s:", sidstr); + + if (numeric) { + fprintf(f, "%d/%d/0x%08x", + ace->type, ace->flags, ace->info.mask); + return; + } + + /* Ace type */ + + if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) { + fprintf(f, "ALLOWED"); + } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) { + fprintf(f, "DENIED"); + } else { + fprintf(f, "%d", ace->type); + } + + /* Not sure what flags can be set in a file ACL */ + + fprintf(f, "/%d/", ace->flags); + + /* Standard permissions */ + + for (v = standard_values; v->perm; v++) { + if (ace->info.mask == v->mask) { + fprintf(f, "%s", v->perm); + return; + } + } + + /* Special permissions. Print out a hex value if we have + leftover bits in the mask. */ + + got_mask = ace->info.mask; + + again: + for (v = special_values; v->perm; v++) { + if ((ace->info.mask & v->mask) == v->mask) { + if (do_print) { + fprintf(f, "%s", v->perm); + } + got_mask &= ~v->mask; + } + } + + if (!do_print) { + if (got_mask != 0) { + fprintf(f, "0x%08x", ace->info.mask); + } else { + do_print = 1; + goto again; + } + } +} + + +/* parse an ACE in the same format as print_ace() */ +static BOOL parse_ace(SEC_ACE *ace, char *str) +{ + char *p; + fstring tok; + unsigned atype, aflags, amask; + DOM_SID sid; + SEC_ACCESS mask; + struct perm_value *v; + + ZERO_STRUCTP(ace); + p = strchr_m(str,':'); + if (!p) return False; + *p = '\0'; + p++; + + /* Try to parse numeric form */ + + if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && + StringToSid(&sid, str)) { + goto done; + } + + /* Try to parse text form */ + + if (!StringToSid(&sid, str)) { + return False; + } + + if (!next_token(&p, tok, "/", sizeof(fstring))) { + return False; + } + + if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { + atype = SEC_ACE_TYPE_ACCESS_ALLOWED; + } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) { + atype = SEC_ACE_TYPE_ACCESS_DENIED; + } else { + return False; + } + + /* Only numeric form accepted for flags at present */ + + if (!(next_token(&p, tok, "/", sizeof(fstring)) && + sscanf(tok, "%i", &aflags))) { + return False; + } + + if (!next_token(&p, tok, "/", sizeof(fstring))) { + return False; + } + + if (strncmp(tok, "0x", 2) == 0) { + if (sscanf(tok, "%i", &amask) != 1) { + return False; + } + goto done; + } + + for (v = standard_values; v->perm; v++) { + if (strcmp(tok, v->perm) == 0) { + amask = v->mask; + goto done; + } + } + + p = tok; + + while(*p) { + BOOL found = False; + + for (v = special_values; v->perm; v++) { + if (v->perm[0] == *p) { + amask |= v->mask; + found = True; + } + } + + if (!found) return False; + p++; + } + + if (*p) { + return False; + } + + done: + mask.mask = amask; + init_sec_ace(ace, &sid, atype, mask, aflags); + return True; +} + +/* add an ACE to a list of ACEs in a SEC_ACL */ +static BOOL add_ace(SEC_ACL **the_acl, SEC_ACE *ace) +{ + SEC_ACL *new; + SEC_ACE *aces; + if (! *the_acl) { + (*the_acl) = make_sec_acl(ctx, 3, 1, ace); + return True; + } + + aces = calloc(1+(*the_acl)->num_aces,sizeof(SEC_ACE)); + memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE)); + memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE)); + new = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces); + SAFE_FREE(aces); + (*the_acl) = new; + return True; +} + +/* parse a ascii version of a security descriptor */ +static SEC_DESC *sec_desc_parse(char *str) +{ + char *p = str; + fstring tok; + SEC_DESC *ret; + size_t sd_size; + DOM_SID *grp_sid=NULL, *owner_sid=NULL; + SEC_ACL *dacl=NULL; + int revision=1; + + while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { + + if (strncmp(tok,"REVISION:", 9) == 0) { + revision = strtol(tok+9, NULL, 16); + continue; + } + + if (strncmp(tok,"OWNER:", 6) == 0) { + owner_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID)); + if (!owner_sid || + !StringToSid(owner_sid, tok+6)) { + printf("Failed to parse owner sid\n"); + return NULL; + } + continue; + } + + if (strncmp(tok,"GROUP:", 6) == 0) { + grp_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID)); + if (!grp_sid || + !StringToSid(grp_sid, tok+6)) { + printf("Failed to parse group sid\n"); + return NULL; + } + continue; + } + + if (strncmp(tok,"ACL:", 4) == 0) { + SEC_ACE ace; + if (!parse_ace(&ace, tok+4)) { + printf("Failed to parse ACL %s\n", tok); + return NULL; + } + if(!add_ace(&dacl, &ace)) { + printf("Failed to add ACL %s\n", tok); + return NULL; + } + continue; + } + + printf("Failed to parse security descriptor\n"); + return NULL; + } + + ret = make_sec_desc(ctx,revision, owner_sid, grp_sid, + NULL, dacl, &sd_size); + + SAFE_FREE(grp_sid); + SAFE_FREE(owner_sid); + + return ret; +} + + +/* print a ascii version of a security descriptor on a FILE handle */ +static void sec_desc_print(FILE *f, SEC_DESC *sd) +{ + fstring sidstr; + uint32 i; + + printf("REVISION:%d\n", sd->revision); + + /* Print owner and group sid */ + + if (sd->owner_sid) { + SidToString(sidstr, sd->owner_sid); + } else { + fstrcpy(sidstr, ""); + } + + printf("OWNER:%s\n", sidstr); + + if (sd->grp_sid) { + SidToString(sidstr, sd->grp_sid); + } else { + fstrcpy(sidstr, ""); + } + + fprintf(f, "GROUP:%s\n", sidstr); + + /* Print aces */ + for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { + SEC_ACE *ace = &sd->dacl->ace[i]; + fprintf(f, "ACL:"); + print_ace(f, ace); + fprintf(f, "\n"); + } + +} + +/***************************************************** +dump the acls for a file +*******************************************************/ +static int cacl_dump(struct cli_state *cli, char *filename) +{ + int fnum; + SEC_DESC *sd; + + if (test_args) return EXIT_OK; + + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); + if (fnum == -1) { + printf("Failed to open %s: %s\n", filename, cli_errstr(cli)); + return EXIT_FAILED; + } + + sd = cli_query_secdesc(cli, fnum, ctx); + + if (!sd) { + printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli)); + return EXIT_FAILED; + } + + sec_desc_print(stdout, sd); + + cli_close(cli, fnum); + + return EXIT_OK; +} + +/***************************************************** +Change the ownership or group ownership of a file. Just +because the NT docs say this can't be done :-). JRA. +*******************************************************/ + +static int owner_set(struct cli_state *cli, enum chown_mode change_mode, + char *filename, char *new_username) +{ + int fnum; + DOM_SID sid; + SEC_DESC *sd, *old; + size_t sd_size; + + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); + + if (fnum == -1) { + printf("Failed to open %s: %s\n", filename, cli_errstr(cli)); + return EXIT_FAILED; + } + + if (!StringToSid(&sid, new_username)) + return EXIT_PARSE_ERROR; + + old = cli_query_secdesc(cli, fnum, ctx); + + cli_close(cli, fnum); + + if (!old) { + printf("owner_set: Failed to query old descriptor\n"); + return EXIT_FAILED; + } + + sd = make_sec_desc(ctx,old->revision, + (change_mode == REQUEST_CHOWN) ? &sid : old->owner_sid, + (change_mode == REQUEST_CHGRP) ? &sid : old->grp_sid, + NULL, old->dacl, &sd_size); + + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE); + + if (fnum == -1) { + printf("Failed to open %s: %s\n", filename, cli_errstr(cli)); + return EXIT_FAILED; + } + + if (!cli_set_secdesc(cli, fnum, sd)) { + printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli)); + } + + cli_close(cli, fnum); + + return EXIT_OK; +} + + +/* The MSDN is contradictory over the ordering of ACE entries in an ACL. + However NT4 gives a "The information may have been modified by a + computer running Windows NT 5.0" if denied ACEs do not appear before + allowed ACEs. */ + +static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2) +{ + if (sec_ace_equal(ace1, ace2)) + return 0; + + if (ace1->type != ace2->type) + return ace2->type - ace1->type; + + if (sid_compare(&ace1->trustee, &ace2->trustee)) + return sid_compare(&ace1->trustee, &ace2->trustee); + + if (ace1->flags != ace2->flags) + return ace1->flags - ace2->flags; + + if (ace1->info.mask != ace2->info.mask) + return ace1->info.mask - ace2->info.mask; + + if (ace1->size != ace2->size) + return ace1->size - ace2->size; + + return memcmp(ace1, ace2, sizeof(SEC_ACE)); +} + +static void sort_acl(SEC_ACL *the_acl) +{ + uint32 i; + if (!the_acl) return; + + qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]), QSORT_CAST ace_compare); + + for (i=1;i<the_acl->num_aces;) { + if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) { + int j; + for (j=i; j<the_acl->num_aces-1; j++) { + the_acl->ace[j] = the_acl->ace[j+1]; + } + the_acl->num_aces--; + } else { + i++; + } + } +} + +/***************************************************** +set the ACLs on a file given an ascii description +*******************************************************/ +static int cacl_set(struct cli_state *cli, char *filename, + char *the_acl, enum acl_mode mode) +{ + int fnum; + SEC_DESC *sd, *old; + uint32 i, j; + size_t sd_size; + int result = EXIT_OK; + + sd = sec_desc_parse(the_acl); + + if (!sd) return EXIT_PARSE_ERROR; + if (test_args) return EXIT_OK; + + /* The desired access below is the only one I could find that works + with NT4, W2KP and Samba */ + + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); + + if (fnum == -1) { + printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli)); + return EXIT_FAILED; + } + + old = cli_query_secdesc(cli, fnum, ctx); + + if (!old) { + printf("calc_set: Failed to query old descriptor\n"); + return EXIT_FAILED; + } + + cli_close(cli, fnum); + + /* the logic here is rather more complex than I would like */ + switch (mode) { + case SMB_ACL_DELETE: + for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { + BOOL found = False; + + for (j=0;old->dacl && j<old->dacl->num_aces;j++) { + if (sec_ace_equal(&sd->dacl->ace[i], + &old->dacl->ace[j])) { + uint32 k; + for (k=j; k<old->dacl->num_aces-1;k++) { + old->dacl->ace[k] = old->dacl->ace[k+1]; + } + old->dacl->num_aces--; + if (old->dacl->num_aces == 0) { + SAFE_FREE(old->dacl->ace); + SAFE_FREE(old->dacl); + old->off_dacl = 0; + } + found = True; + break; + } + } + + if (!found) { + printf("ACL for ACE:"); + print_ace(stdout, &sd->dacl->ace[i]); + printf(" not found\n"); + } + } + break; + + case SMB_ACL_MODIFY: + for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { + BOOL found = False; + + for (j=0;old->dacl && j<old->dacl->num_aces;j++) { + if (sid_equal(&sd->dacl->ace[i].trustee, + &old->dacl->ace[j].trustee)) { + old->dacl->ace[j] = sd->dacl->ace[i]; + found = True; + } + } + + if (!found) { + fstring str; + + SidToString(str, &sd->dacl->ace[i].trustee); + printf("ACL for SID %s not found\n", str); + } + } + + break; + + case SMB_ACL_ADD: + for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { + add_ace(&old->dacl, &sd->dacl->ace[i]); + } + break; + + case SMB_ACL_SET: + old = sd; + break; + } + + /* Denied ACE entries must come before allowed ones */ + sort_acl(old->dacl); + + /* Create new security descriptor and set it */ + sd = make_sec_desc(ctx,old->revision, old->owner_sid, old->grp_sid, + NULL, old->dacl, &sd_size); + + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE); + + if (fnum == -1) { + printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli)); + return EXIT_FAILED; + } + + if (!cli_set_secdesc(cli, fnum, sd)) { + printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli)); + result = EXIT_FAILED; + } + + /* Clean up */ + + cli_close(cli, fnum); + + return result; +} + + +/***************************************************** +return a connection to a server +*******************************************************/ +struct cli_state *connect_one(char *share) +{ + struct cli_state *c; + struct nmb_name called, calling; + struct in_addr ip; + extern pstring global_myname; + + fstrcpy(server,share+2); + share = strchr_m(server,'\\'); + if (!share) return NULL; + *share = 0; + share++; + + zero_ip(&ip); + + make_nmb_name(&calling, global_myname, 0x0); + make_nmb_name(&called , server, 0x20); + + again: + zero_ip(&ip); + + /* have to open a new connection */ + if (!(c=cli_initialise(NULL)) || !cli_connect(c, server, &ip)) { + DEBUG(0,("Connection to %s failed\n", server)); + cli_shutdown(c); + return NULL; + } + + if (!cli_session_request(c, &calling, &called)) { + DEBUG(0,("session request to %s failed\n", called.name)); + cli_shutdown(c); + if (strcmp(called.name, "*SMBSERVER")) { + make_nmb_name(&called , "*SMBSERVER", 0x20); + goto again; + } + return NULL; + } + + DEBUG(4,(" session request ok\n")); + + if (!cli_negprot(c)) { + DEBUG(0,("protocol negotiation failed\n")); + cli_shutdown(c); + return NULL; + } + + if (!got_pass) { + char *pass = getpass("Password: "); + if (pass) { + pstrcpy(password, pass); + } + } + + if (!cli_session_setup(c, username, + password, strlen(password), + password, strlen(password), + lp_workgroup())) { + DEBUG(0,("session setup failed: %s\n", cli_errstr(c))); + cli_shutdown(c); + return NULL; + } + + DEBUG(4,(" session setup ok\n")); + + if (!cli_send_tconX(c, share, "?????", + password, strlen(password)+1)) { + DEBUG(0,("tree connect failed: %s\n", cli_errstr(c))); + cli_shutdown(c); + return NULL; + } + + DEBUG(4,(" tconx ok\n")); + + return c; +} + + +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,char *argv[]) +{ + char *share; + pstring filename; + extern char *optarg; + extern int optind; + int opt; + char *p; + struct cli_state *cli=NULL; + enum acl_mode mode = SMB_ACL_SET; + char *the_acl = NULL; + enum chown_mode change_mode = REQUEST_NONE; + int result; + + ctx=talloc_init(); + + setlinebuf(stdout); + + 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(); + + if (getenv("USER")) { + pstrcpy(username,getenv("USER")); + + if ((p=strchr_m(username,'%'))) { + *p = 0; + pstrcpy(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; + pstrcpy(password, p+1); + got_pass = 1; + } + break; + + case 'S': + the_acl = optarg; + mode = SMB_ACL_SET; + break; + + case 'D': + the_acl = optarg; + mode = SMB_ACL_DELETE; + break; + + case 'M': + the_acl = optarg; + mode = SMB_ACL_MODIFY; + break; + + case 'A': + the_acl = optarg; + mode = SMB_ACL_ADD; + break; + + case 'C': + pstrcpy(owner_username,optarg); + change_mode = REQUEST_CHOWN; + break; + + case 'G': + 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); + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + talloc_destroy(ctx); + exit(EXIT_PARSE_ERROR); + } + + /* Make connection to server */ + + if (!test_args) { + cli = connect_one(share); + if (!cli) { + talloc_destroy(ctx); + exit(EXIT_FAILED); + } + } + + all_string_sub(filename, "/", "\\", 0); + if (filename[0] != '\\') { + pstring s; + s[0] = '\\'; + safe_strcpy(&s[1], filename, sizeof(pstring)-1); + pstrcpy(filename, s); + } + + /* Perform requested action */ + + if (change_mode != REQUEST_NONE) { + result = owner_set(cli, change_mode, filename, owner_username); + } else if (the_acl) { + result = cacl_set(cli, filename, the_acl, mode); + } else { + result = cacl_dump(cli, filename); + } + + talloc_destroy(ctx); + + return result; +} diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c new file mode 100644 index 0000000000..d680fa4489 --- /dev/null +++ b/source3/utils/smbcontrol.c @@ -0,0 +1,509 @@ +/* + Unix SMB/CIFS implementation. + program to send control messages to Samba processes + Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) 2001, 2002 by Martin Pool + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern BOOL AllowDebugChange; + +static struct { + 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}, + {"printer-notify", MSG_PRINTER_NOTIFY}, + {"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 }, + {NULL, -1} +}; + +time_t timeout_start; + +#define MAX_WAIT 10 + +static void usage(BOOL doexit) +{ + 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"); + } + printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n"); + printf("\t<message-type> is one of: "); + for (i=0; msg_types[i].name; i++) + printf("%s%s", i?", ":"",msg_types[i].name); + printf("\n"); + if (doexit) exit(1); +} + +static int pong_count; +static BOOL got_level; +static BOOL pong_registered = False; +static BOOL debuglevel_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) +{ + time_t timeout_end = time(NULL) + max_secs; + + while ((!max_replies || (*max_replies)-- > 0) + && (time(NULL) < timeout_end)) { + message_dispatch(); + } +} + + +/**************************************************************************** +a useful function for testing the message system +****************************************************************************/ +void pong_function(int msg_type, pid_t src, void *buf, size_t len) +{ + pong_count++; + printf("PONG from PID %u\n",(unsigned int)src); +} + +/**************************************************************************** +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 i; + int debuglevel_class[DBGC_LAST]; + + memcpy(debuglevel_class, buf, len); + + printf("Current debug level of PID %u is %d ",(unsigned int)src, debuglevel_class[0]); + for (i=1;i<DBGC_LAST;i++) + if (debuglevel_class[i]) + printf("%s:%d ", debug_classname_from_index(i), debuglevel_class[i]); + printf("\n"); + + got_level = True; +} + +/**************************************************************************** +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; + char *s=NULL; + memcpy(&level, buf, sizeof(int)); + + if (level) { + switch (level) { + case 1: + s = "off"; + break; + case 3: + s = "count only"; + break; + case 7: + s = "count and time"; + 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); + } + got_level = True; +} + +/** + * Handle reply from POOL_USAGE. + **/ +static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len) +{ + printf("Got POOL_USAGE reply from pid%u:\n%.*s", + (unsigned int) src_pid, (int) len, (const char *) buf); +} + + +/** + * 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; + } + + 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; + } + } + + DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid)); + return message_send_pid(pid, msg_type, buf, len, duplicates); +} + +/**************************************************************************** +evaluate a message type string +****************************************************************************/ +static int parse_type(char *mtype) +{ + int i; + for (i=0;msg_types[i].name;i++) { + if (strequal(mtype, msg_types[i].name)) return msg_types[i].value; + } + return -1; +} + + +static void register_all(void) +{ + message_register(MSG_POOL_USAGE, pool_usage_cb); +} + + +/**************************************************************************** +do command +****************************************************************************/ +static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) +{ + int i, n, v; + int mtype; + BOOL retval=False; + + mtype = parse_type(msg_name); + if (mtype == -1) { + fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name); + return(False); + } + + switch (mtype) { + case MSG_DEBUG: { + struct debuglevel_message dm; + + if (!params || !params[0]) { + fprintf(stderr,"MSG_DEBUG needs a parameter\n"); + return(False); + } + + ZERO_STRUCT(dm); + if (!debug_parse_params(params, dm.debuglevel_class, dm.debuglevel_class_isset)) { + fprintf(stderr, "MSG_DEBUG error. Expected <class name>:level\n"); + return(False); + } else + send_message(dest, MSG_DEBUG, &dm, sizeof(dm), False); + break; + } + + case MSG_PROFILE: + if (!params || !params[0]) { + fprintf(stderr,"MSG_PROFILE needs a parameter\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; + + 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; + + 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; + + 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; + + case MSG_PRINTER_NOTIFY: + if (!strequal(dest, "smbd")) { + fprintf(stderr,"printer-notify can only be sent to smbd\n"); + return(False); + } + if (!params || !params[0]) { + fprintf(stderr, "printer-notify needs a printer name\n"); + return (False); + } + { + char msg[8 + sizeof(fstring)]; + SIVAL(msg,0,PRINTER_CHANGE_ALL); + SIVAL(msg,4,0); + fstrcpy(&msg[8], params[0]); + + retval = send_message(dest, MSG_PRINTER_NOTIFY, msg, 8 + strlen(params[0]) + 1, False); + } + break; + + 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; + + case MSG_SMB_SAM_SYNC: + if (!strequal(dest, "smbd")) { + fprintf(stderr, "samsync can only be sent to smbd\n"); + return False; + } + + if (params) { + fprintf(stderr, "samsync does not take any parameters\n"); + return False; + } + + retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False); + + break; + + case MSG_SMB_SAM_REPL: { + uint32 seqnum; + + if (!strequal(dest, "smbd")) { + fprintf(stderr, "sam repl can only be sent to smbd\n"); + return False; + } + + if (!params || !params[0]) { + fprintf(stderr, "SAM_REPL needs a parameter\n"); + return False; + } + + seqnum = atoi(params[0]); + + retval = send_message(dest, MSG_SMB_SAM_SYNC, + (char *)&seqnum, sizeof(uint32), False); + + break; + } + + 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; + + 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; + + case MSG_REQ_DMALLOC_LOG_CHANGED: + case MSG_REQ_DMALLOC_MARK: + if (!send_message(dest, mtype, NULL, 0, False)) + return False; + break; + + case MSG_SHUTDOWN: + if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False)) + return False; + break; + } + + return (True); +} + + int main(int argc, char *argv[]) +{ + int opt; + char temp[255]; + extern int optind; + BOOL interactive = False; + + AllowDebugChange = False; + DEBUGLEVEL = 0; + + setup_logging(argv[0],True); + + if (argc < 2) usage(True); + + while ((opt = getopt(argc, argv,"is:")) != EOF) { + switch (opt) { + case 'i': + interactive = True; + break; + case 's': + pstrcpy(dyn_CONFIGFILE, optarg); + break; + default: + printf("Unknown option %c (%d)\n", (char)opt, opt); + usage(True); + } + } + + lp_load(dyn_CONFIGFILE,False,False,False); + + if (!message_init()) exit(1); + + argc -= optind; + argv = &argv[optind]; + + register_all(); + + 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/smbfilter.c b/source3/utils/smbfilter.c new file mode 100644 index 0000000000..5a2d394706 --- /dev/null +++ b/source3/utils/smbfilter.c @@ -0,0 +1,246 @@ +/* + Unix SMB/CIFS implementation. + SMB filter/socket plugin + Copyright (C) Andrew Tridgell 1999 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "smb.h" + +#define SECURITY_MASK 0 +#define SECURITY_SET 0 + +/* this forces non-unicode */ +#define CAPABILITY_MASK 0 +#define CAPABILITY_SET 0 + +/* and non-unicode for the client too */ +#define CLI_CAPABILITY_MASK 0 +#define CLI_CAPABILITY_SET 0 + +static char *netbiosname; +static char packet[BUFFER_SIZE]; + +static void save_file(const char *fname, void *packet, size_t length) +{ + int fd; + fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd == -1) { + perror(fname); + return; + } + if (write(fd, packet, length) != length) { + fprintf(stderr,"Failed to write %s\n", fname); + return; + } + close(fd); + printf("Wrote %d bytes to %s\n", length, fname); +} + +static void filter_reply(char *buf) +{ + int msg_type = CVAL(buf,0); + int type = CVAL(buf,smb_com); + unsigned x; + + if (msg_type) return; + + switch (type) { + + case SMBnegprot: + /* force the security bits */ + x = CVAL(buf, smb_vwv1); + x = (x | SECURITY_SET) & ~SECURITY_MASK; + SCVAL(buf, smb_vwv1, x); + + /* force the capabilities */ + x = IVAL(buf,smb_vwv9+1); + x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK; + SIVAL(buf, smb_vwv9+1, x); + break; + + } +} + +static void filter_request(char *buf) +{ + int msg_type = CVAL(buf,0); + int type = CVAL(buf,smb_com); + pstring name1,name2; + unsigned x; + + if (msg_type) { + /* it's a netbios special */ + switch (msg_type) { + case 0x81: + /* session request */ + name_extract(buf,4,name1); + name_extract(buf,4 + name_len(buf + 4),name2); + d_printf("sesion_request: %s -> %s\n", + name1, name2); + if (netbiosname) { + /* replace the destination netbios name */ + name_mangle(netbiosname, buf+4, 0x20); + } + } + return; + } + + /* it's an ordinary SMB request */ + switch (type) { + case SMBsesssetupX: + /* force the client capabilities */ + x = IVAL(buf,smb_vwv11); + d_printf("SMBsesssetupX cap=0x%08x\n", x); + d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8)); + system("mv sessionsetup.dat sessionsetup1.dat"); + save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7)); + x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK; + SIVAL(buf, smb_vwv11, x); + break; + } + +} + + +static void filter_child(int c, struct in_addr dest_ip) +{ + int s; + + /* we have a connection from a new client, now connect to the server */ + s = open_socket_out(SOCK_STREAM, &dest_ip, 445, LONG_CONNECT_TIMEOUT); + + if (s == -1) { + d_printf("Unable to connect to %s\n", inet_ntoa(dest_ip)); + exit(1); + } + + while (c != -1 || s != -1) { + fd_set fds; + int num; + + FD_ZERO(&fds); + if (s != -1) FD_SET(s, &fds); + if (c != -1) FD_SET(c, &fds); + + num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL); + if (num <= 0) continue; + + if (c != -1 && FD_ISSET(c, &fds)) { + if (!receive_smb(c, packet, 0)) { + d_printf("client closed connection\n"); + exit(0); + } + filter_request(packet); + if (!send_smb(s, packet)) { + d_printf("server is dead\n"); + exit(1); + } + } + if (s != -1 && FD_ISSET(s, &fds)) { + if (!receive_smb(s, packet, 0)) { + d_printf("server closed connection\n"); + exit(0); + } + filter_reply(packet); + if (!send_smb(c, packet)) { + d_printf("client is dead\n"); + exit(1); + } + } + } + d_printf("Connection closed\n"); + exit(0); +} + + +static void start_filter(char *desthost) +{ + int s, c; + struct in_addr dest_ip; + + CatchChild(); + + /* start listening on port 445 locally */ + s = open_socket_in(SOCK_STREAM, 445, 0, 0, True); + + if (s == -1) { + d_printf("bind failed\n"); + exit(1); + } + + if (listen(s, 5) == -1) { + d_printf("listen failed\n"); + } + + if (!resolve_name(desthost, &dest_ip, 0x20)) { + d_printf("Unable to resolve host %s\n", desthost); + exit(1); + } + + while (1) { + fd_set fds; + int num; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + + FD_ZERO(&fds); + FD_SET(s, &fds); + + num = sys_select_intr(s+1,&fds,NULL,NULL,NULL); + if (num > 0) { + c = accept(s, &addr, &in_addrlen); + if (c != -1) { + if (fork() == 0) { + close(s); + filter_child(c, dest_ip); + exit(0); + } else { + close(c); + } + } + } + } +} + + +int main(int argc, char *argv[]) +{ + char *desthost; + pstring configfile; + + setup_logging(argv[0],True); + + pstrcpy(configfile,dyn_CONFIGFILE); + + if (argc < 2) { + fprintf(stderr,"smbfilter <desthost> <netbiosname>\n"); + exit(1); + } + + desthost = argv[1]; + if (argc > 2) { + netbiosname = argv[2]; + } + + if (!lp_load(configfile,True,False,False)) { + d_printf("Unable to load config file\n"); + } + + start_filter(desthost); + return 0; +} diff --git a/source3/utils/smbgroupedit.c b/source3/utils/smbgroupedit.c new file mode 100644 index 0000000000..cfa0dd8af9 --- /dev/null +++ b/source3/utils/smbgroupedit.c @@ -0,0 +1,397 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-2000, + * Copyright (C) Jean François Micouleau 1998-2001. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +extern pstring global_myname; +extern DOM_SID global_sam_sid; + +/* + * Next two lines needed for SunOS and don't + * hurt anything else... + */ +extern char *optarg; +extern int optind; + +/********************************************************* + Print command usage on stderr and die. +**********************************************************/ +static void usage(void) +{ + if (getuid() == 0) { + printf("smbgroupedit options\n"); + } else { + printf("You need to be root to use this tool!\n"); + } + printf("options:\n"); + printf(" -a group create new group\n"); + printf(" -n group NT group name\n"); + printf(" -p privilege only local\n"); + printf(" -v list groups\n"); + printf(" -l long list (include details)\n"); + printf(" -s short list (default)\n"); + printf(" -c SID change group\n"); + printf(" -u unix group\n"); + printf(" -x group delete this group\n"); + printf("\n"); + printf(" -t[b|d|l] type: builtin, domain, local \n"); + exit(1); +} + +/********************************************************* + Figure out if the input was an NT group or a SID string. + Return the SID. +**********************************************************/ +static BOOL get_sid_from_input(DOM_SID *sid, char *input) +{ + GROUP_MAP map; + + if (StrnCaseCmp( input, "S-", 2)) { + /* Perhaps its the NT group name? */ + if (!get_group_map_from_ntname(input, &map, MAPPING_WITHOUT_PRIV)) { + printf("NT Group %s doesn't exist in mapping DB\n", input); + return False; + } else { + *sid = map.sid; + } + } else { + if (!string_to_sid(sid, input)) { + printf("converting sid %s from a string failed!\n", input); + return False; + } + } + return True; +} + +/********************************************************* + add a group. +**********************************************************/ +static int addgroup(char *group, enum SID_NAME_USE sid_type, char *ntgroup, char *ntcomment, char *privilege) +{ + PRIVILEGE_SET se_priv; + gid_t gid; + DOM_SID sid; + fstring string_sid; + fstring name, comment; + + gid=nametogid(group); + if (gid==-1) { + printf("unix group %s doesn't exist!\n", group); + return -1; + } + + local_gid_to_sid(&sid, gid); + + sid_to_string(string_sid, &sid); + + if (ntgroup==NULL) + fstrcpy(name, group); + else + fstrcpy(name, ntgroup); + + if (ntcomment==NULL) + fstrcpy(comment, "Local Unix group"); + else + fstrcpy(comment, ntcomment); + + init_privilege(&se_priv); + if (privilege!=NULL) + convert_priv_from_text(&se_priv, privilege); + + if(!add_initial_entry(gid, string_sid, sid_type, name, comment, se_priv, PR_ACCESS_FROM_NETWORK)) { + printf("adding entry for group %s failed!\n", group); + free_privilege(&se_priv); + return -1; + } + + free_privilege(&se_priv); + return 0; +} + +/********************************************************* + Change a group. +**********************************************************/ +static int changegroup(char *sid_string, char *group, enum SID_NAME_USE sid_type, char *ntgroup, char *groupdesc, char *privilege) +{ + DOM_SID sid; + GROUP_MAP map; + gid_t gid; + + if (!get_sid_from_input(&sid, sid_string)) { + return -1; + } + + /* Get the current mapping from the database */ + if(!get_group_map_from_sid(sid, &map, MAPPING_WITH_PRIV)) { + printf("This SID does not exist in the database\n"); + return -1; + } + + /* If a new Unix group is specified, check and change */ + if (group!=NULL) { + gid=nametogid(group); + if (gid==-1) { + printf("The UNIX group does not exist\n"); + return -1; + } else + map.gid=gid; + } + + /* + * Allow changing of group type only between domain and local + * We disallow changing Builtin groups !!! (SID problem) + */ + if (sid_type==SID_NAME_ALIAS + || sid_type==SID_NAME_DOM_GRP + || sid_type==SID_NAME_UNKNOWN) { + if (map.sid_name_use==SID_NAME_ALIAS + || map.sid_name_use==SID_NAME_DOM_GRP + || map.sid_name_use==SID_NAME_UNKNOWN) { + map.sid_name_use=sid_type; + } else { + printf("cannot change group type to builtin\n"); + }; + } else { + printf("cannot change group type from builtin\n"); + } + + if (ntgroup!=NULL) + fstrcpy(map.nt_name, ntgroup); + + /* Change comment if new one */ + if (groupdesc!=NULL) + fstrcpy(map.comment, groupdesc); + + /* Change the privilege if new one */ + if (privilege!=NULL) + convert_priv_from_text(&map.priv_set, privilege); + + if (!add_mapping_entry(&map, TDB_REPLACE)) { + printf("Count not update group database\n"); + free_privilege(&map.priv_set); + return -1; + } + + free_privilege(&map.priv_set); + return 0; +} + +/********************************************************* + Delete the group. +**********************************************************/ +static int deletegroup(char *group) +{ + DOM_SID sid; + + if (!get_sid_from_input(&sid, group)) { + return -1; + } + + if(!group_map_remove(sid)) { + printf("removing group %s from the mapping db failed!\n", group); + return -1; + } + + return 0; +} + +/********************************************************* + List the groups. +**********************************************************/ +static int listgroup(enum SID_NAME_USE sid_type, BOOL long_list) +{ + int entries,i; + GROUP_MAP *map=NULL; + fstring string_sid; + fstring group_type; + fstring priv_text; + + if (!long_list) + printf("NT group (SID) -> Unix group\n"); + + if (!enum_group_mapping(sid_type, &map, &entries, ENUM_ALL_MAPPED, MAPPING_WITH_PRIV)) + return -1; + + for (i=0; i<entries; i++) { + decode_sid_name_use(group_type, (map[i]).sid_name_use); + sid_to_string(string_sid, &map[i].sid); + convert_priv_to_text(&(map[i].priv_set), priv_text); + free_privilege(&(map[i].priv_set)); + + if (!long_list) + printf("%s (%s) -> %s\n", map[i].nt_name, string_sid, gidtoname(map[i].gid)); + else { + printf("%s\n", map[i].nt_name); + printf("\tSID : %s\n", string_sid); + printf("\tUnix group: %s\n", gidtoname(map[i].gid)); + printf("\tGroup type: %s\n", group_type); + printf("\tComment : %s\n", map[i].comment); + printf("\tPrivilege : %s\n\n", priv_text); + } + } + + return 0; +} + +/********************************************************* + Start here. +**********************************************************/ +int main (int argc, char **argv) +{ + int ch; + BOOL add_group = False; + BOOL view_group = False; + BOOL change_group = False; + BOOL delete_group = False; + BOOL nt_group = False; + BOOL priv = False; + BOOL group_type = False; + BOOL long_list = False; + + char *group = NULL; + char *sid = NULL; + char *ntgroup = NULL; + char *privilege = NULL; + char *groupt = NULL; + char *group_desc = NULL; + + enum SID_NAME_USE sid_type; + + setup_logging("groupedit", True); + + if (argc < 2) { + usage(); + return 0; + } + + if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", + dyn_CONFIGFILE); + exit(1); + } + + if(!initialize_password_db(True)) { + fprintf(stderr, "Can't setup password database vectors.\n"); + exit(1); + } + + if(pdb_generate_sam_sid()==False) { + printf("Can not read machine SID\n"); + return 0; + } + + while ((ch = getopt(argc, argv, "a:c:d:ln:p:st:u:vx:")) != EOF) { + switch(ch) { + case 'a': + add_group = True; + group=optarg; + break; + case 'c': + change_group = True; + sid=optarg; + break; + case 'd': + group_desc=optarg; + break; + case 'l': + long_list = True; + break; + case 'n': + nt_group = True; + ntgroup=optarg; + break; + case 'p': + priv = True; + privilege=optarg; + break; + case 's': + long_list = False; + break; + case 't': + group_type = True; + groupt=optarg; + break; + case 'u': + group=optarg; + break; + case 'v': + view_group = True; + break; + case 'x': + delete_group = True; + group=optarg; + break; + /*default: + usage();*/ + } + } + + + if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) > 1) { + fprintf (stderr, "Incompatible options on command line!\n"); + usage(); + exit(1); + } + + /* no option on command line -> list groups */ + if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) == 0) + view_group = True; + + + if (group_type==False) + sid_type=SID_NAME_UNKNOWN; + else { + switch (groupt[0]) { + case 'l': + case 'L': + sid_type=SID_NAME_ALIAS; + break; + case 'd': + case 'D': + sid_type=SID_NAME_DOM_GRP; + break; + case 'b': + case 'B': + sid_type=SID_NAME_WKN_GRP; + break; + default: + sid_type=SID_NAME_UNKNOWN; + break; + } + } + + if (add_group) + return addgroup(group, sid_type, ntgroup, group_desc, privilege); + + if (view_group) + return listgroup(sid_type, long_list); + + if (delete_group) + return deletegroup(group); + + if (change_group) { + return changegroup(sid, group, sid_type, ntgroup, group_desc, privilege); + } + + usage(); + + return 0; +} diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c index 167eb2ed5f..a96fad0cdb 100644 --- a/source3/utils/smbpasswd.c +++ b/source3/utils/smbpasswd.c @@ -1,13 +1,12 @@ -#ifdef SMB_PASSWD - /* - * Unix SMB/Netbios implementation. Version 1.9. smbpasswd module. Copyright - * (C) Jeremy Allison 1995. + * Unix SMB/CIFS implementation. + * Copyright (C) Jeremy Allison 1995-1998 + * Copyright (C) Tim Potter 2001 * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is 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 @@ -16,441 +15,603 @@ * * 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. - */ + * Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" -#include "des.h" -/* Static buffers we will return. */ -static struct smb_passwd pw_buf; -static pstring user_name; -static unsigned char smbpwd[16]; -static unsigned char smbntpwd[16]; +extern pstring global_myname; +extern BOOL AllowDebugChange; + +/* + * Next two lines needed for SunOS and don't + * hurt anything else... + */ +extern char *optarg; +extern int optind; + +/* forced running in root-mode */ +static BOOL local_mode; +static BOOL got_pass = False, got_username = False; +static int local_flags = 0; +static BOOL stdin_passwd_get = False; +static fstring user_name, user_password; +static char *new_domain = NULL; +static char *new_passwd = NULL; +static char *old_passwd = NULL; +static char *remote_machine = NULL; +static pstring configfile; + +#ifdef WITH_LDAP_SAM +static fstring ldap_secret; +#endif + +/********************************************************* + Print command usage on stderr and die. +**********************************************************/ +static void usage(void) +{ + printf("When run by root:\n"); + printf(" smbpasswd [options] [username] [password]\n"); + printf("otherwise:\n"); + printf(" smbpasswd [options] [password]\n\n"); + + printf("options:\n"); + printf(" -L local mode (must be first option)\n"); + printf(" -h print this usage message\n"); + printf(" -s use stdin for password prompt\n"); + printf(" -c smb.conf file Use the given path to the smb.conf file\n"); + printf(" -D LEVEL debug level\n"); + printf(" -r MACHINE remote machine\n"); + printf(" -U USER remote username\n"); + + printf("extra options when run by root or in local mode:\n"); + printf(" -a add user\n"); + printf(" -d disable user\n"); + printf(" -e enable user\n"); + printf(" -i interdomain trust account\n"); + printf(" -m machine trust account\n"); + printf(" -n set no password\n"); +#ifdef WITH_LDAP_SAM + printf(" -w ldap admin password\n"); +#endif + printf(" -x delete user\n"); + printf(" -R ORDER name resolve order\n"); + + exit(1); +} + +static void set_line_buffering(FILE *f) +{ + setvbuf(f, NULL, _IOLBF, 0); +} -static int gethexpwd(char *p, char *pwd) +/******************************************************************* + Process command line options + ******************************************************************/ +static void process_options(int argc, char **argv, BOOL amroot) { - int i; - unsigned char lonybble, hinybble; - char *hexchars = "0123456789ABCDEF"; - char *p1, *p2; - for (i = 0; i < 32; i += 2) { - hinybble = toupper(p[i]); - lonybble = toupper(p[i + 1]); - - p1 = strchr(hexchars, hinybble); - p2 = strchr(hexchars, lonybble); - if (!p1 || !p2) - return (False); - - hinybble = PTR_DIFF(p1, hexchars); - lonybble = PTR_DIFF(p2, hexchars); - - pwd[i / 2] = (hinybble << 4) | lonybble; + int ch; + + if (amroot) + local_flags = LOCAL_SET_PASSWORD; + + ZERO_STRUCT(user_name); + ZERO_STRUCT(user_password); + + user_name[0] = '\0'; + + while ((ch = getopt(argc, argv, "c:axdehmnj:r:sw:R:D:U:L")) != EOF) { + switch(ch) { + case 'L': + local_mode = amroot = True; + local_flags = LOCAL_SET_PASSWORD; + break; + case 'c': + pstrcpy(configfile,optarg); + break; + case 'a': + if (!amroot) goto bad_args; + local_flags |= LOCAL_ADD_USER; + break; + case 'x': + if (!amroot) goto bad_args; + local_flags |= LOCAL_DELETE_USER; + local_flags &= ~LOCAL_SET_PASSWORD; + break; + case 'd': + if (!amroot) goto bad_args; + local_flags |= LOCAL_DISABLE_USER; + local_flags &= ~LOCAL_SET_PASSWORD; + break; + case 'e': + if (!amroot) goto bad_args; + local_flags |= LOCAL_ENABLE_USER; + local_flags &= ~LOCAL_SET_PASSWORD; + break; + case 'm': + if (!amroot) goto bad_args; + local_flags |= LOCAL_TRUST_ACCOUNT; + break; + case 'i': + if (!amroot) goto bad_args; + local_flags |= LOCAL_INTERDOM_ACCOUNT; + break; + case 'j': + if (!amroot) goto bad_args; + d_printf("See 'net rpc join' for this functionality\n"); + exit(1); + break; + case 'n': + if (!amroot) goto bad_args; + local_flags |= LOCAL_SET_NO_PASSWORD; + new_passwd = smb_xstrdup("NO PASSWORD"); + break; + case 'r': + remote_machine = optarg; + break; + case 's': + set_line_buffering(stdin); + set_line_buffering(stdout); + set_line_buffering(stderr); + stdin_passwd_get = True; + break; + case 'w': + if (!amroot) goto bad_args; +#ifdef WITH_LDAP_SAM + local_flags |= LOCAL_SET_LDAP_ADMIN_PW; + fstrcpy(ldap_secret, optarg); + break; +#else + printf("-w not available unless configured --with-ldap\n"); + goto bad_args; +#endif + case 'R': + if (!amroot) goto bad_args; + lp_set_name_resolve_order(optarg); + break; + case 'D': + DEBUGLEVEL = atoi(optarg); + break; + case 'U': { + char *lp; + + got_username = True; + fstrcpy(user_name, optarg); + + if ((lp = strchr(user_name, '%'))) { + *lp = 0; + fstrcpy(user_password, lp + 1); + got_pass = True; + memset(strchr_m(optarg, '%') + 1, 'X', + strlen(user_password)); + } + + break; + } + case 'h': + default: +bad_args: + usage(); + } + } + + argc -= optind; + argv += optind; + + switch(argc) { + case 0: + if (!got_username) + fstrcpy(user_name, ""); + break; + case 1: + if (!amroot) { + new_passwd = argv[0]; + break; + } + if (got_username) + usage(); + fstrcpy(user_name, argv[0]); + break; + case 2: + if (!amroot || got_username || got_pass) + usage(); + fstrcpy(user_name, argv[0]); + new_passwd = smb_xstrdup(argv[1]); + break; + default: + usage(); } - return (True); + } -struct smb_passwd * -_my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd, - BOOL *got_valid_nt_entry, long *pwd_seekpos) +/************************************************************* + Utility function to prompt for passwords from stdin. Each + password entered must end with a newline. +*************************************************************/ +static char *stdin_new_passwd(void) { - char linebuf[256]; - unsigned char c; - unsigned char *p; - long uidval; - long linebuf_len; + static fstring new_passwd; + size_t len; + + ZERO_ARRAY(new_passwd); /* - * Scan the file, a line at a time and check if the name matches. + * if no error is reported from fgets() and string at least contains + * the newline that ends the password, then replace the newline with + * a null terminator. */ - while (!feof(fp)) { - linebuf[0] = '\0'; - *pwd_seekpos = ftell(fp); + if ( fgets(new_passwd, sizeof(new_passwd), stdin) != NULL) { + if ((len = strlen(new_passwd)) > 0) { + if(new_passwd[len-1] == '\n') + new_passwd[len - 1] = 0; + } + } + return(new_passwd); +} - fgets(linebuf, 256, fp); - if (ferror(fp)) - return NULL; - /* - * Check if the string is terminated with a newline - if not - * then we must keep reading and discard until we get one. - */ - linebuf_len = strlen(linebuf); - if (linebuf[linebuf_len - 1] != '\n') { - c = '\0'; - while (!ferror(fp) && !feof(fp)) { - c = fgetc(fp); - if (c == '\n') - break; - } - } else - linebuf[linebuf_len - 1] = '\0'; +/************************************************************* + Utility function to get passwords via tty or stdin + Used if the '-s' option is set to silently get passwords + to enable scripting. +*************************************************************/ +static char *get_pass( char *prompt, BOOL stdin_get) +{ + char *p; + if (stdin_get) { + p = stdin_new_passwd(); + } else { + p = getpass(prompt); + } + return smb_xstrdup(p); +} - if ((linebuf[0] == 0) && feof(fp)) - break; - /* - * The line we have should be of the form :- - * - * username:uid:[32hex bytes]:....other flags presently - * ignored.... - * - * or, - * - * username:uid:[32hex bytes]:[32hex bytes]:....ignored.... - * - * if Windows NT compatible passwords are also present. - */ +/************************************************************* + Utility function to prompt for new password. +*************************************************************/ +static char *prompt_for_new_password(BOOL stdin_get) +{ + char *p; + fstring new_passwd; - if (linebuf[0] == '#' || linebuf[0] == '\0') - continue; - p = (unsigned char *) strchr(linebuf, ':'); - if (p == NULL) - continue; - /* - * As 256 is shorter than a pstring we don't need to check - * length here - if this ever changes.... - */ - strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); - user_name[PTR_DIFF(p, linebuf)] = '\0'; - if (!strequal(user_name, name)) - continue; + ZERO_ARRAY(new_passwd); + + p = get_pass("New SMB password:", stdin_get); + + fstrcpy(new_passwd, p); + SAFE_FREE(p); + + p = get_pass("Retype new SMB password:", stdin_get); + + if (strcmp(p, new_passwd)) { + fprintf(stderr, "Mismatch - password unchanged.\n"); + ZERO_ARRAY(new_passwd); + SAFE_FREE(p); + return NULL; + } + + return p; +} + + +/************************************************************* + Change a password either locally or remotely. +*************************************************************/ - /* User name matches - get uid and password */ - p++; /* Go past ':' */ - if (!isdigit(*p)) - return (False); +static BOOL password_change(const char *remote_machine, char *user_name, + char *old_passwd, char *new_passwd, int local_flags) +{ + BOOL ret; + pstring err_str; + pstring msg_str; - uidval = atoi((char *) p); - while (*p && isdigit(*p)) - p++; + if (remote_machine != NULL) { + if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER| + LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) { + /* these things can't be done remotely yet */ + return False; + } + ret = remote_password_change(remote_machine, user_name, + old_passwd, new_passwd, err_str, sizeof(err_str)); + if(*err_str) + fprintf(stderr, err_str); + return ret; + } + + ret = local_password_change(user_name, local_flags, new_passwd, + err_str, sizeof(err_str), msg_str, sizeof(msg_str)); - if (*p != ':') - return (False); + if(*msg_str) + printf(msg_str); + if(*err_str) + fprintf(stderr, err_str); + + return ret; +} + +#ifdef WITH_LDAP_SAM +/******************************************************************* + Store the LDAP admin password in secrets.tdb + ******************************************************************/ +static BOOL store_ldap_admin_pw (char* pw) +{ + if (!pw) + return False; + + if (!secrets_init()) + return False; + + return secrets_store_ldap_pw(lp_ldap_admin_dn(), pw); +} +#endif + + +/************************************************************* + Handle password changing for root. +*************************************************************/ + +static int process_root(void) +{ + struct passwd *pwd; + int result = 0; + +#ifdef WITH_LDAP_SAM + if (local_flags & LOCAL_SET_LDAP_ADMIN_PW) + { + printf("Setting stored password for \"%s\" in secrets.tdb\n", + lp_ldap_admin_dn()); + if (!store_ldap_admin_pw(ldap_secret)) + DEBUG(0,("ERROR: Failed to store the ldap admin password!\n")); + goto done; + } +#endif + + /* + * Ensure both add/delete user are not set + * Ensure add/delete user and either remote machine or join domain are + * not both set. + */ + if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) || + ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && + (remote_machine != NULL))) { + usage(); + } + + /* Only load interfaces if we are doing network operations. */ + + if (remote_machine) { + load_interfaces(); + } + + if (!user_name[0] && (pwd = sys_getpwuid(geteuid()))) { + fstrcpy(user_name, pwd->pw_name); + } + + if (!user_name[0]) { + fprintf(stderr,"You must specify a username\n"); + exit(1); + } + + if (local_flags & LOCAL_TRUST_ACCOUNT) { + /* add the $ automatically */ + static fstring buf; /* - * Now get the password value - this should be 32 hex digits - * which are the ascii representations of a 16 byte string. - * Get two at a time and put them into the password. + * Remove any trailing '$' before we + * generate the initial machine password. */ - p++; - *pwd_seekpos += PTR_DIFF(p, linebuf); /* Save exact position - * of passwd in file - - * this is used by - * smbpasswd.c */ - if (*p == '*' || *p == 'X') { - /* Password deliberately invalid - end here. */ - *valid_old_pwd = False; - *got_valid_nt_entry = False; - pw_buf.smb_nt_passwd = NULL; /* No NT password (yet)*/ - - /* Now check if the NT compatible password is - available. */ - p += 33; /* Move to the first character of the line after - the lanman password. */ - if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { - /* NT Entry was valid - even if 'X' or '*', can be overwritten */ - *got_valid_nt_entry = True; - if (*p != '*' && *p != 'X') { - if(gethexpwd(p,smbntpwd)) - pw_buf.smb_nt_passwd = smbntpwd; - } - } - pw_buf.smb_name = user_name; - pw_buf.smb_userid = uidval; - pw_buf.smb_passwd = NULL; /* No password */ - return (&pw_buf); + + if (user_name[strlen(user_name)-1] == '$') { + user_name[strlen(user_name)-1] = 0; } - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) - return (False); - if (p[32] != ':') - return (False); + if (local_flags & LOCAL_ADD_USER) { + SAFE_FREE(new_passwd); + new_passwd = smb_xstrdup(user_name); + strlower(new_passwd); + } - if (!strncasecmp(p, "NO PASSWORD", 11)) { - pw_buf.smb_passwd = NULL; /* No password */ - } else { - if(!gethexpwd(p,smbpwd)) - return False; - pw_buf.smb_passwd = smbpwd; + /* + * Now ensure the username ends in '$' for + * the machine add. + */ + + slprintf(buf, sizeof(buf)-1, "%s$", user_name); + fstrcpy(user_name, buf); + } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) { + static fstring buf; + + if (local_flags & LOCAL_ADD_USER) { + /* + * Prompt for trusting domain's account password + */ + new_passwd = prompt_for_new_password(stdin_passwd_get); + if(!new_passwd) { + fprintf(stderr, "Unable to get newpassword.\n"); + exit(1); + } } + slprintf(buf, sizeof(buf) - 1, "%s$", user_name); + fstrcpy(user_name, buf); - pw_buf.smb_name = user_name; - pw_buf.smb_userid = uidval; - pw_buf.smb_nt_passwd = NULL; - *got_valid_nt_entry = False; - *valid_old_pwd = True; - - /* Now check if the NT compatible password is - available. */ - p += 33; /* Move to the first character of the line after - the lanman password. */ - if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { - /* NT Entry was valid - even if 'X' or '*', can be overwritten */ - *got_valid_nt_entry = True; - if (*p != '*' && *p != 'X') { - if(gethexpwd(p,smbntpwd)) - pw_buf.smb_nt_passwd = smbntpwd; + } else { + + if (remote_machine != NULL) { + old_passwd = get_pass("Old SMB password:",stdin_passwd_get); + } + + if (!(local_flags & LOCAL_SET_PASSWORD)) { + + /* + * If we are trying to enable a user, first we need to find out + * if they are using a modern version of the smbpasswd file that + * disables a user by just writing a flag into the file. If so + * then we can re-enable a user without prompting for a new + * password. If not (ie. they have a no stored password in the + * smbpasswd file) then we need to prompt for a new password. + */ + + if(local_flags & LOCAL_ENABLE_USER) { + SAM_ACCOUNT *sampass = NULL; + BOOL ret; + + pdb_init_sam(&sampass); + ret = pdb_getsampwnam(sampass, user_name); + if((sampass != False) && (pdb_get_lanman_passwd(sampass) == NULL)) { + local_flags |= LOCAL_SET_PASSWORD; + } + pdb_free_sam(&sampass); } } - return &pw_buf; + + if(local_flags & LOCAL_SET_PASSWORD) { + new_passwd = prompt_for_new_password(stdin_passwd_get); + + if(!new_passwd) { + fprintf(stderr, "Unable to get new password.\n"); + exit(1); + } + } + } + + if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) { + fprintf(stderr,"Failed to modify password entry for user %s\n", user_name); + result = 1; + goto done; + } + + if(remote_machine) { + printf("Password changed for user %s on %s.\n", user_name, remote_machine ); + } else if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) { + SAM_ACCOUNT *sampass = NULL; + BOOL ret; + + pdb_init_sam(&sampass); + ret = pdb_getsampwnam(sampass, user_name); + + printf("Password changed for user %s.", user_name ); + if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) ) + printf(" User has disabled flag set."); + if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) ) + printf(" User has no password flag set."); + printf("\n"); + pdb_free_sam(&sampass); } - return NULL; + + done: + SAFE_FREE(new_passwd); + return result; } -/* - * Print command usage on stderr and die. - */ -void -usage(char *name) + +/************************************************************* + Handle password changing for non-root. +*************************************************************/ + +static int process_nonroot(void) { - fprintf(stderr, "Usage is : %s [username]\n", name); - exit(1); + struct passwd *pwd = NULL; + int result = 0; + + if (!user_name[0]) { + pwd = sys_getpwuid(getuid()); + if (pwd) { + fstrcpy(user_name,pwd->pw_name); + } else { + fprintf(stderr, "smbpasswd: you don't exist - go away\n"); + exit(1); + } + } + + /* + * A non-root user is always setting a password + * via a remote machine (even if that machine is + * localhost). + */ + + load_interfaces(); /* Delayed from main() */ + + if (remote_machine == NULL) { + remote_machine = "127.0.0.1"; + } + + if (remote_machine != NULL) { + old_passwd = get_pass("Old SMB password:",stdin_passwd_get); + } + + if (!new_passwd) { + new_passwd = prompt_for_new_password(stdin_passwd_get); + } + + if (!new_passwd) { + fprintf(stderr, "Unable to get new password.\n"); + exit(1); + } + + if (!password_change(remote_machine, user_name, old_passwd, new_passwd, 0)) { + fprintf(stderr,"Failed to change password for %s\n", user_name); + result = 1; + goto done; + } + + printf("Password changed for user %s\n", user_name); + + done: + SAFE_FREE(old_passwd); + SAFE_FREE(new_passwd); + + return result; } + + +/********************************************************* + Start here. +**********************************************************/ int main(int argc, char **argv) -{ - int real_uid; - struct passwd *pwd; - fstring old_passwd; - uchar old_p16[16]; - uchar old_nt_p16[16]; - fstring new_passwd; - uchar new_p16[16]; - uchar new_nt_p16[16]; - char *p; - struct smb_passwd *smb_pwent; - FILE *fp; - BOOL valid_old_pwd = False; - BOOL got_valid_nt_entry = False; - long seekpos; - int pwfd; - char ascii_p16[66]; - char c; - int ret, i, err, writelen; - int lockfd = -1; - char *pfile = SMB_PASSWD_FILE; - char readbuf[16 * 1024]; - - setup_logging(argv[0],True); - - charset_initialise(); - -#ifndef DEBUG_PASSWORD - /* Check the effective uid */ - if (geteuid() != 0) { - fprintf(stderr, "%s: Must be setuid root.\n", argv[0]); - exit(1); - } -#endif - - /* Get the real uid */ - real_uid = getuid(); - - /* Deal with usage problems */ - if (real_uid == 0) { - /* As root we can change anothers password. */ - if (argc != 1 && argc != 2) - usage(argv[0]); - } else if (argc != 1) - usage(argv[0]); - - - if (real_uid == 0 && argc == 2) { - /* If we are root we can change anothers password. */ - strncpy(user_name, argv[1], sizeof(user_name) - 1); - user_name[sizeof(user_name) - 1] = '\0'; - pwd = getpwnam(user_name); - } else { - pwd = getpwuid(real_uid); - } - - if (pwd == 0) { - fprintf(stderr, "%s: Unable to get UNIX password entry for user.\n", argv[0]); - exit(1); - } - /* If we are root we don't ask for the old password. */ - old_passwd[0] = '\0'; - if (real_uid != 0) { - p = getpass("Old SMB password:"); - strncpy(old_passwd, p, sizeof(fstring)); - old_passwd[sizeof(fstring)-1] = '\0'; - } - new_passwd[0] = '\0'; - p = getpass("New SMB password:"); - strncpy(new_passwd, p, sizeof(fstring)); - new_passwd[sizeof(fstring)-1] = '\0'; - p = getpass("Retype new SMB password:"); - if (strcmp(p, new_passwd)) { - fprintf(stderr, "%s: Mismatch - password unchanged.\n", argv[0]); - exit(1); - } - - if (new_passwd[0] == '\0') { - printf("Password not set\n"); - exit(0); - } - - /* Calculate the MD4 hash (NT compatible) of the old and new passwords */ - memset(old_nt_p16, '\0', 16); - E_md4hash((uchar *)old_passwd, old_nt_p16); - - memset(new_nt_p16, '\0', 16); - E_md4hash((uchar *) new_passwd, new_nt_p16); - - /* Mangle the passwords into Lanman format */ - old_passwd[14] = '\0'; - strupper(old_passwd); - new_passwd[14] = '\0'; - strupper(new_passwd); - - /* - * Calculate the SMB (lanman) hash functions of both old and new passwords. - */ - - memset(old_p16, '\0', 16); - E_P16((uchar *) old_passwd, old_p16); - - memset(new_p16, '\0', 16); - E_P16((uchar *) new_passwd, new_p16); - - /* - * Open the smbpaswd file XXXX - we need to parse smb.conf to get the - * filename - */ - if ((fp = fopen(pfile, "r+")) == NULL) { - err = errno; - fprintf(stderr, "%s: Failed to open password file %s.\n", - argv[0], pfile); - errno = err; - perror(argv[0]); - exit(err); - } - /* Set read buffer to 16k for effiecient reads */ - setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); - - /* make sure it is only rw by the owner */ - chmod(pfile, 0600); - - /* Lock the smbpasswd file for write. */ - if ((lockfd = pw_file_lock(pfile, F_WRLCK, 5)) < 0) { - err = errno; - fprintf(stderr, "%s: Failed to lock password file %s.\n", - argv[0], pfile); - fclose(fp); - errno = err; - perror(argv[0]); - exit(err); - } - /* Get the smb passwd entry for this user */ - smb_pwent = _my_get_smbpwnam(fp, pwd->pw_name, &valid_old_pwd, - &got_valid_nt_entry, &seekpos); - if (smb_pwent == NULL) { - fprintf(stderr, "%s: Failed to find entry for user %s in file %s.\n", - argv[0], pwd->pw_name, pfile); - fclose(fp); - pw_file_unlock(lockfd); - exit(1); - } - /* If we are root we don't need to check the old password. */ - if (real_uid != 0) { - if ((valid_old_pwd == False) || (smb_pwent->smb_passwd == NULL)) { - fprintf(stderr, "%s: User %s is disabled, plase contact your administrator to enable it.\n", argv[0], pwd->pw_name); - fclose(fp); - pw_file_unlock(lockfd); - exit(1); - } - /* Check the old Lanman password */ - if (memcmp(old_p16, smb_pwent->smb_passwd, 16)) { - fprintf(stderr, "%s: Couldn't change password.\n", argv[0]); - fclose(fp); - pw_file_unlock(lockfd); - exit(1); - } - /* Check the NT password if it exists */ - if (smb_pwent->smb_nt_passwd != NULL) { - if (memcmp(old_nt_p16, smb_pwent->smb_nt_passwd, 16)) { - fprintf(stderr, "%s: Couldn't change password.\n", argv[0]); - fclose(fp); - pw_file_unlock(lockfd); - exit(1); - } - } - } - /* - * If we get here either we were root or the old password checked out - * ok. - */ - /* Create the 32 byte representation of the new p16 */ - for (i = 0; i < 16; i++) { - sprintf(&ascii_p16[i * 2], "%02X", (uchar) new_p16[i]); - } - if(got_valid_nt_entry) { - /* Add on the NT md4 hash */ - ascii_p16[32] = ':'; - for (i = 0; i < 16; i++) { - sprintf(&ascii_p16[(i * 2)+33], "%02X", (uchar) new_nt_p16[i]); - } - } - /* - * Do an atomic write into the file at the position defined by - * seekpos. - */ - pwfd = fileno(fp); - ret = lseek(pwfd, seekpos - 1, SEEK_SET); - if (ret != seekpos - 1) { - err = errno; - fprintf(stderr, "%s: seek fail on file %s.\n", - argv[0], pfile); - fclose(fp); - errno = err; - perror(argv[0]); - pw_file_unlock(lockfd); - exit(1); - } - /* Sanity check - ensure the character is a ':' */ - if (read(pwfd, &c, 1) != 1) { - err = errno; - fprintf(stderr, "%s: read fail on file %s.\n", - argv[0], pfile); - fclose(fp); - errno = err; - perror(argv[0]); - pw_file_unlock(lockfd); - exit(1); - } - if (c != ':') { - fprintf(stderr, "%s: sanity check on passwd file %s failed.\n", - argv[0], pfile); - fclose(fp); - pw_file_unlock(lockfd); - exit(1); - } - writelen = (got_valid_nt_entry) ? 65 : 32; - if (write(pwfd, ascii_p16, writelen) != writelen) { - err = errno; - fprintf(stderr, "%s: write fail in file %s.\n", - argv[0], pfile); - fclose(fp); - errno = err; - perror(argv[0]); - pw_file_unlock(lockfd); - exit(err); - } - fclose(fp); - pw_file_unlock(lockfd); - printf("Password changed\n"); - return 0; -} +{ + BOOL amroot = getuid() == 0; -#else + pstrcpy(configfile, dyn_CONFIGFILE); + AllowDebugChange = False; -#include "includes.h" +#if defined(HAVE_SET_AUTH_PARAMETERS) + set_auth_parameters(argc, argv); +#endif /* HAVE_SET_AUTH_PARAMETERS */ -int -main(int argc, char **argv) -{ - printf("smb password encryption not selected in Makefile\n"); - return 0; + process_options(argc, argv, amroot); + + setup_logging("smbpasswd", True); + + if (!lp_load(configfile,True,False,False)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", + dyn_CONFIGFILE); + exit(1); + } + + /* + * Set the machine NETBIOS name if not already + * set from the config file. + */ + + if (!*global_myname) { + char *p; + fstrcpy(global_myname, myhostname()); + p = strchr_m(global_myname, '.' ); + if (p) *p = 0; + } + strupper(global_myname); + + /* Check the effective uid - make sure we are not setuid */ + if (is_setuid_root()) { + fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n"); + exit(1); + } + + if (local_mode || amroot) { + secrets_init(); + return process_root(); + } + + return process_nonroot(); } -#endif diff --git a/source3/utils/smbtree.c b/source3/utils/smbtree.c new file mode 100644 index 0000000000..b80a27eb37 --- /dev/null +++ b/source3/utils/smbtree.c @@ -0,0 +1,423 @@ +/* + Unix SMB/CIFS implementation. + Network neighbourhood browser. + + Copyright (C) Tim Potter 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static BOOL 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}; +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 { + struct name_list *prev, *next; + pstring name, comment; + uint32 server_type; +}; + +static struct name_list *workgroups, *servers, *shares; + +static void free_name_list(struct name_list *list) +{ + while(list) + DLIST_REMOVE(list, list); +} + +static void add_name(const char *machine_name, uint32 server_type, + const char *comment, void *state) +{ + struct name_list **name_list = (struct name_list **)state; + struct name_list *new_name; + + new_name = (struct name_list *)malloc(sizeof(struct name_list)); + + if (!new_name) + return; + + ZERO_STRUCTP(new_name); + + pstrcpy(new_name->name, machine_name); + pstrcpy(new_name->comment, comment); + new_name->server_type = server_type; + + DLIST_ADD(*name_list, new_name); +} + +/* Return a cli_state pointing at the IPC$ share for the given workgroup */ + +static struct cli_state *get_ipc_connect(char *server, + struct user_auth_info *user_info) +{ + struct nmb_name calling, called; + struct in_addr server_ip; + struct cli_state *cli; + pstring myname; + + zero_ip(&server_ip); + + get_myname(myname); + + make_nmb_name(&called, myname, 0x0); + make_nmb_name(&calling, server, 0x20); + + if (is_ipaddress(server)) + if (!resolve_name(server, &server_ip, 0x20)) + return False; + + again: + if (!(cli = cli_initialise(NULL))) { + DEBUG(4, ("Unable to initialise cli structure\n")); + goto error; + } + + if (!cli_connect(cli, server, &server_ip)) { + DEBUG(4, ("Unable to connect to %s\n", server)); + goto error; + } + + if (!cli_session_request(cli, &calling, &called)) { + cli_shutdown(cli); + if (!strequal(called.name, "*SMBSERVER")) { + make_nmb_name(&called , "*SMBSERVER", 0x20); + goto again; + } + DEBUG(4, ("Session request failed to %s\n", called.name)); + goto error; + } + + if (!cli_negprot(cli)) { + DEBUG(4, ("Negprot failed\n")); + goto error; + } + + if (!cli_session_setup(cli, user_info->username, user_info->password, + strlen(user_info->password), + user_info->password, + strlen(user_info->password), server) && + /* try an anonymous login if it failed */ + !cli_session_setup(cli, "", "", 1,"", 0, server)) { + DEBUG(4, ("Session setup failed\n")); + goto error; + } + + DEBUG(4,(" session setup ok\n")); + + if (!cli_send_tconX(cli, "IPC$", "?????", + user_info->password, + strlen(user_info->password)+1)) { + DEBUG(4, ("Tconx failed\n")); + goto error; + } + + return cli; + + /* Clean up after error */ + + error: + if (cli && cli->initialised) + cli_shutdown(cli); + + 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 +****************************************************************************/ +static BOOL get_workgroups(struct user_auth_info *user_info) +{ + struct cli_state *cli; + struct in_addr server_ip; + pstring master_workgroup; + + /* Try to connect to a #1d name of our current workgroup. If that + doesn't work broadcast for a master browser and then jump off + that workgroup. */ + + 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\n", + master_workgroup)); + 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), user_info))) + return False; + + if (!cli_NetServerEnum(cli, master_workgroup, + SV_TYPE_DOMAIN_ENUM, add_name, &workgroups)) + return False; + + return True; +} + +/* Retrieve the list of servers for a given workgroup */ + +static BOOL get_servers(char *workgroup, struct user_auth_info *user_info) +{ + struct cli_state *cli; + struct in_addr server_ip; + + /* Open an IPC$ connection to the master browser for the workgroup */ + + if (!find_master_ip(workgroup, &server_ip)) { + DEBUG(4, ("Cannot find master browser for workgroup %s\n", + workgroup)); + return False; + } + + if (!(cli = get_ipc_connect(inet_ntoa(server_ip), user_info))) + return False; + + if (!cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, add_name, + &servers)) + return False; + + return True; +} + +static BOOL get_shares(char *server_name, struct user_auth_info *user_info) +{ + struct cli_state *cli; + + if (!(cli = get_ipc_connect(server_name, user_info))) + return False; + + if (!cli_RNetShareEnum(cli, add_name, &shares)) + return False; + + return True; +} + +static BOOL print_tree(struct user_auth_info *user_info) +{ + struct name_list *wg, *sv, *sh; + + /* List workgroups */ + + if (!get_workgroups(user_info)) + return False; + + for (wg = workgroups; wg; wg = wg->next) { + + printf("%s\n", wg->name); + + /* List servers */ + + free_name_list(servers); + servers = NULL; + + if (level == LEV_WORKGROUP || + !get_servers(wg->name, user_info)) + continue; + + for (sv = servers; sv; sv = sv->next) { + + printf("\t\\\\%-15s\t\t%s\n", + sv->name, sv->comment); + + /* List shares */ + + free_name_list(shares); + shares = NULL; + + if (level == LEV_SERVER || + !get_shares(sv->name, user_info)) + continue; + + for (sh = shares; sh; sh = sh->next) { + printf("\t\t\\\\%s\\%-15s\t%s\n", + sv->name, sh->name, sh->comment); + } + } + } + + return True; +} + +/**************************************************************************** + main program +****************************************************************************/ + int main(int argc,char *argv[]) +{ + 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); + + dbf = x_stderr; + + setup_logging(argv[0],True); + + 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 */ + + 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(user_info.password, pass); + } + got_pass = True; + } + + /* Now do our stuff */ + + if (!print_tree(&user_info)) + return 1; + + return 0; +} diff --git a/source3/utils/smbw_sample.c b/source3/utils/smbw_sample.c new file mode 100644 index 0000000000..5cd792df7a --- /dev/null +++ b/source3/utils/smbw_sample.c @@ -0,0 +1,94 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <dirent.h> +#include <sys/stat.h> + +static void usage(void) +{ + printf(" +smbw_sample - a sample program that uses smbw + +smbw_sample <options> path + + options: + -W workgroup + -l logfile + -P prefix + -d debuglevel + -U username%%password + -R resolve order + +note that path must start with /smb/ +"); +} + +int main(int argc, char *argv[]) +{ + DIR *dir; + struct dirent *dent; + int opt; + char *p; + extern char *optarg; + extern int optind; + char *path; + + lp_load(dyn_CONFIGFILE,1,0,0); + smbw_setup_shared(); + + while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) { + switch (opt) { + case 'W': + smbw_setshared("WORKGROUP", optarg); + break; + case 'l': + smbw_setshared("LOGFILE", optarg); + break; + case 'P': + smbw_setshared("PREFIX", optarg); + break; + case 'd': + smbw_setshared("DEBUG", optarg); + break; + case 'U': + p = strchr_m(optarg,'%'); + if (p) { + *p=0; + smbw_setshared("PASSWORD",p+1); + } + smbw_setshared("USER", optarg); + break; + case 'R': + smbw_setshared("RESOLVE_ORDER",optarg); + break; + case 'h': + default: + usage(); + exit(1); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + exit(1); + } + + path = argv[0]; + + smbw_init(); + + dir = smbw_opendir(path); + if (!dir) { + printf("failed to open %s\n", path); + exit(1); + } + + while ((dent = smbw_readdir(dir))) { + printf("%s\n", dent->d_name); + } + smbw_closedir(dir); + return 0; +} diff --git a/source3/utils/status.c b/source3/utils/status.c index ed0ae53211..6f4b9eb28c 100644 --- a/source3/utils/status.c +++ b/source3/utils/status.c @@ -1,8 +1,7 @@ /* - Unix SMB/Netbios implementation. - Version 1.9. + Unix SMB/CIFS implementation. status reporting - Copyright (C) Andrew Tridgell 1994-1995 + Copyright (C) Andrew Tridgell 1994-1998 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 @@ -17,242 +16,659 @@ 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. + + Revision History: + + 12 aug 96: Erik.Devriendt@te6.siemens.be + added support for shared memory implementation of share mode locking + + 21-Jul-1998: rsharpe@ns.aus.com (Richard Sharpe) + Added -L (locks only) -S (shares only) flags and code + */ /* * This program reports current SMB connections */ -#ifdef SYSLOG -#undef SYSLOG -#endif +#define NO_SYSLOG #include "includes.h" -#include "loadparm.h" -struct connect_record crec; -extern int DEBUGLEVEL; -extern FILE *dbf; +extern BOOL AllowDebugChange; + +struct session_record{ + pid_t pid; + uid_t uid; + char machine[31]; + time_t start; + struct session_record *next; +} *srecs; static pstring Ucrit_username = ""; /* added by OH */ -int Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */ -int Ucrit_MaxPid=0; /* added by OH */ -unsigned int Ucrit_IsActive = 0; /* added by OH */ -void Ucrit_addUsername(pstring username); /* added by OH */ -unsigned int Ucrit_checkUsername(pstring username); /* added by OH */ -void Ucrit_addPid(int pid); /* added by OH */ -unsigned int Ucrit_checkPid(int pid); /* added by OH */ - -int main(int argc, char *argv[]) +static pid_t Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */ +static int Ucrit_MaxPid=0; /* added by OH */ +static unsigned int Ucrit_IsActive = 0; /* added by OH */ +static int verbose, brief; +static int shares_only = 0; /* Added by RJS */ +static int locks_only = 0; /* Added by RJS */ +static BOOL processes_only=False; +static int show_brl; + +/* we need these because we link to locking*.o */ + void become_root(void) {} + void unbecome_root(void) {} + + +/* added by OH */ +static void Ucrit_addUsername(char *username) +{ + pstrcpy(Ucrit_username, username); + if(strlen(Ucrit_username) > 0) + Ucrit_IsActive = 1; +} + +static unsigned int Ucrit_checkUsername(char *username) +{ + if ( !Ucrit_IsActive) return 1; + if (strcmp(Ucrit_username,username) ==0) return 1; + return 0; +} + +static unsigned int Ucrit_checkPid(pid_t pid) { - FILE *f; - pstring fname; - int uid, c, n; - static pstring servicesf = CONFIGFILE; - extern char *optarg; - int verbose = 0; - void *dir; - char *s; - BOOL firstopen=True; - BOOL processes_only=False; - int last_pid=0; - - setup_logging(argv[0],True); - - charset_initialise(); - - DEBUGLEVEL = 0; - dbf = fopen("/dev/null","w"); - - if (getuid() != geteuid()) { - printf("smbstatus should not be run setuid\n"); - return(1); - } - - while ((c = getopt(argc, argv, "pdsu:")) != EOF) { - switch (c) { - case 'd': - verbose = 1; - break; - case 'p': - processes_only = 1; - break; - case 's': - strcpy(servicesf, optarg); - break; - case 'u': /* added by OH */ - Ucrit_addUsername(optarg); /* added by OH */ - break; - default: - fprintf(stderr, "Usage: %s [-d] [-p] [-s configfile] [-u username]\n", *argv); /* changed by OH */ - return (-1); - } - } - - - - if (!lp_load(servicesf,False)) { - fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf); - return (-1); - } - - if (verbose) { - printf("using configfile = %s\n", servicesf); - printf("lockdir = %s\n", *lp_lockdir() ? lp_lockdir() : "NULL"); - } - - strcpy(fname,lp_lockdir()); - standard_sub_basic(fname); - trim_string(fname,"","/"); - strcat(fname,"/STATUS..LCK"); - - f = fopen(fname,"r"); - if (!f) { - printf("Couldn't open status file %s\n",fname); - if (!lp_status(-1)) - printf("You need to have status=yes in your smb config file\n"); - return(0); - } - - uid = getuid(); - - if (!processes_only) { - printf("\nSamba version %s\n",VERSION); - - printf("Service uid gid pid machine\n"); - printf("----------------------------------------------\n"); - } - - while (!feof(f)) - { - if (fread(&crec,sizeof(crec),1,f) != 1) - break; - if ( crec.magic == 0x280267 && process_exists(crec.pid) - && Ucrit_checkUsername(uidtoname(crec.uid)) /* added by OH */ - ) - { - Ucrit_addPid(crec.pid); /* added by OH */ - if (processes_only) { - if (last_pid != crec.pid) - printf("%d\n",crec.pid); - last_pid = crec.pid; /* XXXX we can still get repeats, have to - add a sort at some time */ + int i; + if ( !Ucrit_IsActive) return 1; + for (i=0;i<Ucrit_MaxPid;i++) + if( pid == Ucrit_pid[i] ) return 1; + return 0; +} + + +static void print_share_mode(share_mode_entry *e, char *fname) +{ + static int count; + if (count==0) { + d_printf("Locked files:\n"); + d_printf("Pid DenyMode Access R/W Oplock Name\n"); + d_printf("--------------------------------------------------------------\n"); + } + count++; + + if (Ucrit_checkPid(e->pid)) { + d_printf("%-5d ",(int)e->pid); + switch (GET_DENY_MODE(e->share_mode)) { + case DENY_NONE: d_printf("DENY_NONE "); break; + case DENY_ALL: d_printf("DENY_ALL "); break; + case DENY_DOS: d_printf("DENY_DOS "); break; + case DENY_READ: d_printf("DENY_READ "); break; + case DENY_WRITE:printf("DENY_WRITE "); break; + case DENY_FCB: d_printf("DENY_FCB "); break; + } + d_printf("0x%-8x ",(unsigned int)e->desired_access); + switch (e->share_mode&0xF) { + case 0: d_printf("RDONLY "); break; + case 1: d_printf("WRONLY "); break; + case 2: d_printf("RDWR "); break; + } + + if((e->op_type & + (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == + (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) + d_printf("EXCLUSIVE+BATCH "); + else if (e->op_type & EXCLUSIVE_OPLOCK) + d_printf("EXCLUSIVE "); + else if (e->op_type & BATCH_OPLOCK) + d_printf("BATCH "); + else if (e->op_type & LEVEL_II_OPLOCK) + d_printf("LEVEL_II "); + else + d_printf("NONE "); + + d_printf(" %s %s",fname, + asctime(LocalTime((time_t *)&e->time.tv_sec))); } - else - printf("%-10.10s %-8s %-8s %5d %-8s (%s) %s", - crec.name,uidtoname(crec.uid),gidtoname(crec.gid),crec.pid, - crec.machine,crec.addr, - asctime(LocalTime(&crec.start,GMT_TO_LOCAL))); - } - } - fclose(f); - - if (processes_only) exit(0); - - printf("\n"); - - dir = opendir(lp_lockdir()); - if (!dir) return(0); - while ((s=readdirname(dir))) { - char buf[16]; - int pid,mode; - time_t t; - int fd; - pstring lname; - int dev,inode; - - if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue; - - strcpy(lname,lp_lockdir()); - trim_string(lname,NULL,"/"); - strcat(lname,"/"); - strcat(lname,s); - - fd = open(lname,O_RDONLY,0); - if (fd < 0) continue; - if (read(fd,buf,16) != 16) continue; - n = read(fd,fname,sizeof(fname)); - fname[MAX(n,0)]=0; - close(fd); - - t = IVAL(buf,0); - mode = IVAL(buf,4); - pid = IVAL(buf,8); - - if ( !Ucrit_checkPid(pid) ) /* added by OH */ - continue; - - if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) { - if (unlink(lname)==0) - printf("Deleted stale share file %s\n",s); - continue; - } - - fname[sizeof(fname)-1] = 0; - - if (firstopen) { - firstopen=False; - printf("Locked files:\n"); - printf("Pid DenyMode R/W Name\n"); - printf("------------------------------\n"); - } - - - printf("%-5d ",pid); - switch ((mode>>4)&0xF) - { - case DENY_NONE: printf("DENY_NONE "); break; - case DENY_ALL: printf("DENY_ALL "); break; - case DENY_DOS: printf("DENY_DOS "); break; - case DENY_READ: printf("DENY_READ "); break; - case DENY_WRITE:printf("DENY_WRITE "); break; - } - switch (mode&0xF) - { - case 0: printf("RDONLY "); break; - case 1: printf("WRONLY "); break; - case 2: printf("RDWR "); break; - } - printf(" %s %s",fname,asctime(LocalTime(&t,GMT_TO_LOCAL))); - } - closedir(dir); - - if (firstopen) - printf("No locked files\n"); - - return (0); } -/* added by OH */ -void Ucrit_addUsername(pstring username) +static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid, + enum brl_type lock_type, + br_off start, br_off size) { - strcpy(Ucrit_username, username); - if(strlen(Ucrit_username) > 0) - Ucrit_IsActive = 1; + static int count; + if (count==0) { + d_printf("Byte range locks:\n"); + d_printf(" Pid dev:inode R/W start size\n"); + d_printf("------------------------------------------------\n"); + } + count++; + + d_printf("%6d %05x:%05x %s %9.0f %9.0f\n", + (int)pid, (int)dev, (int)ino, + lock_type==READ_LOCK?"R":"W", + (double)start, (double)size); } -unsigned int Ucrit_checkUsername(pstring username) + +/******************************************************************* + dump the elements of the profile structure + ******************************************************************/ +static int profile_dump(void) { - if ( !Ucrit_IsActive) return 1; - if (strcmp(Ucrit_username,username) ==0) return 1; - return 0; + if (!profile_setup(True)) { + fprintf(stderr,"Failed to initialise profile memory\n"); + return -1; + } + + d_printf("smb_count: %u\n", profile_p->smb_count); + d_printf("uid_changes: %u\n", profile_p->uid_changes); + d_printf("************************ System Calls ****************************\n"); + d_printf("opendir_count: %u\n", profile_p->syscall_opendir_count); + d_printf("opendir_time: %u\n", profile_p->syscall_opendir_time); + d_printf("readdir_count: %u\n", profile_p->syscall_readdir_count); + d_printf("readdir_time: %u\n", profile_p->syscall_readdir_time); + d_printf("mkdir_count: %u\n", profile_p->syscall_mkdir_count); + d_printf("mkdir_time: %u\n", profile_p->syscall_mkdir_time); + d_printf("rmdir_count: %u\n", profile_p->syscall_rmdir_count); + d_printf("rmdir_time: %u\n", profile_p->syscall_rmdir_time); + d_printf("closedir_count: %u\n", profile_p->syscall_closedir_count); + d_printf("closedir_time: %u\n", profile_p->syscall_closedir_time); + d_printf("open_count: %u\n", profile_p->syscall_open_count); + d_printf("open_time: %u\n", profile_p->syscall_open_time); + d_printf("close_count: %u\n", profile_p->syscall_close_count); + d_printf("close_time: %u\n", profile_p->syscall_close_time); + d_printf("read_count: %u\n", profile_p->syscall_read_count); + d_printf("read_time: %u\n", profile_p->syscall_read_time); + d_printf("read_bytes: %u\n", profile_p->syscall_read_bytes); + d_printf("write_count: %u\n", profile_p->syscall_write_count); + d_printf("write_time: %u\n", profile_p->syscall_write_time); + d_printf("write_bytes: %u\n", profile_p->syscall_write_bytes); + d_printf("lseek_count: %u\n", profile_p->syscall_lseek_count); + d_printf("lseek_time: %u\n", profile_p->syscall_lseek_time); + d_printf("rename_count: %u\n", profile_p->syscall_rename_count); + d_printf("rename_time: %u\n", profile_p->syscall_rename_time); + d_printf("fsync_count: %u\n", profile_p->syscall_fsync_count); + d_printf("fsync_time: %u\n", profile_p->syscall_fsync_time); + d_printf("stat_count: %u\n", profile_p->syscall_stat_count); + d_printf("stat_time: %u\n", profile_p->syscall_stat_time); + d_printf("fstat_count: %u\n", profile_p->syscall_fstat_count); + d_printf("fstat_time: %u\n", profile_p->syscall_fstat_time); + d_printf("lstat_count: %u\n", profile_p->syscall_lstat_count); + d_printf("lstat_time: %u\n", profile_p->syscall_lstat_time); + d_printf("unlink_count: %u\n", profile_p->syscall_unlink_count); + d_printf("unlink_time: %u\n", profile_p->syscall_unlink_time); + d_printf("chmod_count: %u\n", profile_p->syscall_chmod_count); + d_printf("chmod_time: %u\n", profile_p->syscall_chmod_time); + d_printf("fchmod_count: %u\n", profile_p->syscall_fchmod_count); + d_printf("fchmod_time: %u\n", profile_p->syscall_fchmod_time); + d_printf("chown_count: %u\n", profile_p->syscall_chown_count); + d_printf("chown_time: %u\n", profile_p->syscall_chown_time); + d_printf("fchown_count: %u\n", profile_p->syscall_fchown_count); + d_printf("fchown_time: %u\n", profile_p->syscall_fchown_time); + d_printf("chdir_count: %u\n", profile_p->syscall_chdir_count); + d_printf("chdir_time: %u\n", profile_p->syscall_chdir_time); + d_printf("getwd_count: %u\n", profile_p->syscall_getwd_count); + d_printf("getwd_time: %u\n", profile_p->syscall_getwd_time); + d_printf("utime_count: %u\n", profile_p->syscall_utime_count); + d_printf("utime_time: %u\n", profile_p->syscall_utime_time); + d_printf("ftruncate_count: %u\n", profile_p->syscall_ftruncate_count); + d_printf("ftruncate_time: %u\n", profile_p->syscall_ftruncate_time); + d_printf("fcntl_lock_count: %u\n", profile_p->syscall_fcntl_lock_count); + d_printf("fcntl_lock_time: %u\n", profile_p->syscall_fcntl_lock_time); + d_printf("readlink_count: %u\n", profile_p->syscall_readlink_count); + d_printf("readlink_time: %u\n", profile_p->syscall_readlink_time); + d_printf("symlink_count: %u\n", profile_p->syscall_symlink_count); + d_printf("symlink_time: %u\n", profile_p->syscall_symlink_time); + d_printf("************************ Statcache *******************************\n"); + d_printf("lookups: %u\n", profile_p->statcache_lookups); + d_printf("misses: %u\n", profile_p->statcache_misses); + d_printf("hits: %u\n", profile_p->statcache_hits); + d_printf("************************ Writecache ******************************\n"); + d_printf("read_hits: %u\n", profile_p->writecache_read_hits); + d_printf("abutted_writes: %u\n", profile_p->writecache_abutted_writes); + d_printf("total_writes: %u\n", profile_p->writecache_total_writes); + d_printf("non_oplock_writes: %u\n", profile_p->writecache_non_oplock_writes); + d_printf("direct_writes: %u\n", profile_p->writecache_direct_writes); + d_printf("init_writes: %u\n", profile_p->writecache_init_writes); + d_printf("flushed_writes[SEEK]: %u\n", profile_p->writecache_flushed_writes[SEEK_FLUSH]); + d_printf("flushed_writes[READ]: %u\n", profile_p->writecache_flushed_writes[READ_FLUSH]); + d_printf("flushed_writes[WRITE]: %u\n", profile_p->writecache_flushed_writes[WRITE_FLUSH]); + d_printf("flushed_writes[READRAW]: %u\n", profile_p->writecache_flushed_writes[READRAW_FLUSH]); + d_printf("flushed_writes[OPLOCK_RELEASE]: %u\n", profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH]); + d_printf("flushed_writes[CLOSE]: %u\n", profile_p->writecache_flushed_writes[CLOSE_FLUSH]); + d_printf("flushed_writes[SYNC]: %u\n", profile_p->writecache_flushed_writes[SYNC_FLUSH]); + d_printf("flushed_writes[SIZECHANGE]: %u\n", profile_p->writecache_flushed_writes[SIZECHANGE_FLUSH]); + d_printf("num_perfect_writes: %u\n", profile_p->writecache_num_perfect_writes); + d_printf("num_write_caches: %u\n", profile_p->writecache_num_write_caches); + d_printf("allocated_write_caches: %u\n", profile_p->writecache_allocated_write_caches); + d_printf("************************ SMB Calls *******************************\n"); + d_printf("mkdir_count: %u\n", profile_p->SMBmkdir_count); + d_printf("mkdir_time: %u\n", profile_p->SMBmkdir_time); + d_printf("rmdir_count: %u\n", profile_p->SMBrmdir_count); + d_printf("rmdir_time: %u\n", profile_p->SMBrmdir_time); + d_printf("open_count: %u\n", profile_p->SMBopen_count); + d_printf("open_time: %u\n", profile_p->SMBopen_time); + d_printf("create_count: %u\n", profile_p->SMBcreate_count); + d_printf("create_time: %u\n", profile_p->SMBcreate_time); + d_printf("close_count: %u\n", profile_p->SMBclose_count); + d_printf("close_time: %u\n", profile_p->SMBclose_time); + d_printf("flush_count: %u\n", profile_p->SMBflush_count); + d_printf("flush_time: %u\n", profile_p->SMBflush_time); + d_printf("unlink_count: %u\n", profile_p->SMBunlink_count); + d_printf("unlink_time: %u\n", profile_p->SMBunlink_time); + d_printf("mv_count: %u\n", profile_p->SMBmv_count); + d_printf("mv_time: %u\n", profile_p->SMBmv_time); + d_printf("getatr_count: %u\n", profile_p->SMBgetatr_count); + d_printf("getatr_time: %u\n", profile_p->SMBgetatr_time); + d_printf("setatr_count: %u\n", profile_p->SMBsetatr_count); + d_printf("setatr_time: %u\n", profile_p->SMBsetatr_time); + d_printf("read_count: %u\n", profile_p->SMBread_count); + d_printf("read_time: %u\n", profile_p->SMBread_time); + d_printf("write_count: %u\n", profile_p->SMBwrite_count); + d_printf("write_time: %u\n", profile_p->SMBwrite_time); + d_printf("lock_count: %u\n", profile_p->SMBlock_count); + d_printf("lock_time: %u\n", profile_p->SMBlock_time); + d_printf("unlock_count: %u\n", profile_p->SMBunlock_count); + d_printf("unlock_time: %u\n", profile_p->SMBunlock_time); + d_printf("ctemp_count: %u\n", profile_p->SMBctemp_count); + d_printf("ctemp_time: %u\n", profile_p->SMBctemp_time); + d_printf("mknew_count: %u\n", profile_p->SMBmknew_count); + d_printf("mknew_time: %u\n", profile_p->SMBmknew_time); + d_printf("chkpth_count: %u\n", profile_p->SMBchkpth_count); + d_printf("chkpth_time: %u\n", profile_p->SMBchkpth_time); + d_printf("exit_count: %u\n", profile_p->SMBexit_count); + d_printf("exit_time: %u\n", profile_p->SMBexit_time); + d_printf("lseek_count: %u\n", profile_p->SMBlseek_count); + d_printf("lseek_time: %u\n", profile_p->SMBlseek_time); + d_printf("lockread_count: %u\n", profile_p->SMBlockread_count); + d_printf("lockread_time: %u\n", profile_p->SMBlockread_time); + d_printf("writeunlock_count: %u\n", profile_p->SMBwriteunlock_count); + d_printf("writeunlock_time: %u\n", profile_p->SMBwriteunlock_time); + d_printf("readbraw_count: %u\n", profile_p->SMBreadbraw_count); + d_printf("readbraw_time: %u\n", profile_p->SMBreadbraw_time); + d_printf("readBmpx_count: %u\n", profile_p->SMBreadBmpx_count); + d_printf("readBmpx_time: %u\n", profile_p->SMBreadBmpx_time); + d_printf("readBs_count: %u\n", profile_p->SMBreadBs_count); + d_printf("readBs_time: %u\n", profile_p->SMBreadBs_time); + d_printf("writebraw_count: %u\n", profile_p->SMBwritebraw_count); + d_printf("writebraw_time: %u\n", profile_p->SMBwritebraw_time); + d_printf("writeBmpx_count: %u\n", profile_p->SMBwriteBmpx_count); + d_printf("writeBmpx_time: %u\n", profile_p->SMBwriteBmpx_time); + d_printf("writeBs_count: %u\n", profile_p->SMBwriteBs_count); + d_printf("writeBs_time: %u\n", profile_p->SMBwriteBs_time); + d_printf("writec_count: %u\n", profile_p->SMBwritec_count); + d_printf("writec_time: %u\n", profile_p->SMBwritec_time); + d_printf("setattrE_count: %u\n", profile_p->SMBsetattrE_count); + d_printf("setattrE_time: %u\n", profile_p->SMBsetattrE_time); + d_printf("getattrE_count: %u\n", profile_p->SMBgetattrE_count); + d_printf("getattrE_time: %u\n", profile_p->SMBgetattrE_time); + d_printf("lockingX_count: %u\n", profile_p->SMBlockingX_count); + d_printf("lockingX_time: %u\n", profile_p->SMBlockingX_time); + d_printf("trans_count: %u\n", profile_p->SMBtrans_count); + d_printf("trans_time: %u\n", profile_p->SMBtrans_time); + d_printf("transs_count: %u\n", profile_p->SMBtranss_count); + d_printf("transs_time: %u\n", profile_p->SMBtranss_time); + d_printf("ioctl_count: %u\n", profile_p->SMBioctl_count); + d_printf("ioctl_time: %u\n", profile_p->SMBioctl_time); + d_printf("ioctls_count: %u\n", profile_p->SMBioctls_count); + d_printf("ioctls_time: %u\n", profile_p->SMBioctls_time); + d_printf("copy_count: %u\n", profile_p->SMBcopy_count); + d_printf("copy_time: %u\n", profile_p->SMBcopy_time); + d_printf("move_count: %u\n", profile_p->SMBmove_count); + d_printf("move_time: %u\n", profile_p->SMBmove_time); + d_printf("echo_count: %u\n", profile_p->SMBecho_count); + d_printf("echo_time: %u\n", profile_p->SMBecho_time); + d_printf("writeclose_count: %u\n", profile_p->SMBwriteclose_count); + d_printf("writeclose_time: %u\n", profile_p->SMBwriteclose_time); + d_printf("openX_count: %u\n", profile_p->SMBopenX_count); + d_printf("openX_time: %u\n", profile_p->SMBopenX_time); + d_printf("readX_count: %u\n", profile_p->SMBreadX_count); + d_printf("readX_time: %u\n", profile_p->SMBreadX_time); + d_printf("writeX_count: %u\n", profile_p->SMBwriteX_count); + d_printf("writeX_time: %u\n", profile_p->SMBwriteX_time); + d_printf("trans2_count: %u\n", profile_p->SMBtrans2_count); + d_printf("trans2_time: %u\n", profile_p->SMBtrans2_time); + d_printf("transs2_count: %u\n", profile_p->SMBtranss2_count); + d_printf("transs2_time: %u\n", profile_p->SMBtranss2_time); + d_printf("findclose_count: %u\n", profile_p->SMBfindclose_count); + d_printf("findclose_time: %u\n", profile_p->SMBfindclose_time); + d_printf("findnclose_count: %u\n", profile_p->SMBfindnclose_count); + d_printf("findnclose_time: %u\n", profile_p->SMBfindnclose_time); + d_printf("tcon_count: %u\n", profile_p->SMBtcon_count); + d_printf("tcon_time: %u\n", profile_p->SMBtcon_time); + d_printf("tdis_count: %u\n", profile_p->SMBtdis_count); + d_printf("tdis_time: %u\n", profile_p->SMBtdis_time); + d_printf("negprot_count: %u\n", profile_p->SMBnegprot_count); + d_printf("negprot_time: %u\n", profile_p->SMBnegprot_time); + d_printf("sesssetupX_count: %u\n", profile_p->SMBsesssetupX_count); + d_printf("sesssetupX_time: %u\n", profile_p->SMBsesssetupX_time); + d_printf("ulogoffX_count: %u\n", profile_p->SMBulogoffX_count); + d_printf("ulogoffX_time: %u\n", profile_p->SMBulogoffX_time); + d_printf("tconX_count: %u\n", profile_p->SMBtconX_count); + d_printf("tconX_time: %u\n", profile_p->SMBtconX_time); + d_printf("dskattr_count: %u\n", profile_p->SMBdskattr_count); + d_printf("dskattr_time: %u\n", profile_p->SMBdskattr_time); + d_printf("search_count: %u\n", profile_p->SMBsearch_count); + d_printf("search_time: %u\n", profile_p->SMBsearch_time); + d_printf("ffirst_count: %u\n", profile_p->SMBffirst_count); + d_printf("ffirst_time: %u\n", profile_p->SMBffirst_time); + d_printf("funique_count: %u\n", profile_p->SMBfunique_count); + d_printf("funique_time: %u\n", profile_p->SMBfunique_time); + d_printf("fclose_count: %u\n", profile_p->SMBfclose_count); + d_printf("fclose_time: %u\n", profile_p->SMBfclose_time); + d_printf("nttrans_count: %u\n", profile_p->SMBnttrans_count); + d_printf("nttrans_time: %u\n", profile_p->SMBnttrans_time); + d_printf("nttranss_count: %u\n", profile_p->SMBnttranss_count); + d_printf("nttranss_time: %u\n", profile_p->SMBnttranss_time); + d_printf("ntcreateX_count: %u\n", profile_p->SMBntcreateX_count); + d_printf("ntcreateX_time: %u\n", profile_p->SMBntcreateX_time); + d_printf("ntcancel_count: %u\n", profile_p->SMBntcancel_count); + d_printf("ntcancel_time: %u\n", profile_p->SMBntcancel_time); + d_printf("splopen_count: %u\n", profile_p->SMBsplopen_count); + d_printf("splopen_time: %u\n", profile_p->SMBsplopen_time); + d_printf("splwr_count: %u\n", profile_p->SMBsplwr_count); + d_printf("splwr_time: %u\n", profile_p->SMBsplwr_time); + d_printf("splclose_count: %u\n", profile_p->SMBsplclose_count); + d_printf("splclose_time: %u\n", profile_p->SMBsplclose_time); + d_printf("splretq_count: %u\n", profile_p->SMBsplretq_count); + d_printf("splretq_time: %u\n", profile_p->SMBsplretq_time); + d_printf("sends_count: %u\n", profile_p->SMBsends_count); + d_printf("sends_time: %u\n", profile_p->SMBsends_time); + d_printf("sendb_count: %u\n", profile_p->SMBsendb_count); + d_printf("sendb_time: %u\n", profile_p->SMBsendb_time); + d_printf("fwdname_count: %u\n", profile_p->SMBfwdname_count); + d_printf("fwdname_time: %u\n", profile_p->SMBfwdname_time); + d_printf("cancelf_count: %u\n", profile_p->SMBcancelf_count); + d_printf("cancelf_time: %u\n", profile_p->SMBcancelf_time); + d_printf("getmac_count: %u\n", profile_p->SMBgetmac_count); + d_printf("getmac_time: %u\n", profile_p->SMBgetmac_time); + d_printf("sendstrt_count: %u\n", profile_p->SMBsendstrt_count); + d_printf("sendstrt_time: %u\n", profile_p->SMBsendstrt_time); + d_printf("sendend_count: %u\n", profile_p->SMBsendend_count); + d_printf("sendend_time: %u\n", profile_p->SMBsendend_time); + d_printf("sendtxt_count: %u\n", profile_p->SMBsendtxt_count); + d_printf("sendtxt_time: %u\n", profile_p->SMBsendtxt_time); + d_printf("invalid_count: %u\n", profile_p->SMBinvalid_count); + d_printf("invalid_time: %u\n", profile_p->SMBinvalid_time); + d_printf("************************ Pathworks Calls *************************\n"); + d_printf("setdir_count: %u\n", profile_p->pathworks_setdir_count); + d_printf("setdir_time: %u\n", profile_p->pathworks_setdir_time); + d_printf("************************ Trans2 Calls ****************************\n"); + d_printf("open_count: %u\n", profile_p->Trans2_open_count); + d_printf("open_time: %u\n", profile_p->Trans2_open_time); + d_printf("findfirst_count: %u\n", profile_p->Trans2_findfirst_count); + d_printf("findfirst_time: %u\n", profile_p->Trans2_findfirst_time); + d_printf("findnext_count: %u\n", profile_p->Trans2_findnext_count); + d_printf("findnext_time: %u\n", profile_p->Trans2_findnext_time); + d_printf("qfsinfo_count: %u\n", profile_p->Trans2_qfsinfo_count); + d_printf("qfsinfo_time: %u\n", profile_p->Trans2_qfsinfo_time); + d_printf("setfsinfo_count: %u\n", profile_p->Trans2_setfsinfo_count); + d_printf("setfsinfo_time: %u\n", profile_p->Trans2_setfsinfo_time); + d_printf("qpathinfo_count: %u\n", profile_p->Trans2_qpathinfo_count); + d_printf("qpathinfo_time: %u\n", profile_p->Trans2_qpathinfo_time); + d_printf("setpathinfo_count: %u\n", profile_p->Trans2_setpathinfo_count); + d_printf("setpathinfo_time: %u\n", profile_p->Trans2_setpathinfo_time); + d_printf("qfileinfo_count: %u\n", profile_p->Trans2_qfileinfo_count); + d_printf("qfileinfo_time: %u\n", profile_p->Trans2_qfileinfo_time); + d_printf("setfileinfo_count: %u\n", profile_p->Trans2_setfileinfo_count); + d_printf("setfileinfo_time: %u\n", profile_p->Trans2_setfileinfo_time); + d_printf("fsctl_count: %u\n", profile_p->Trans2_fsctl_count); + d_printf("fsctl_time: %u\n", profile_p->Trans2_fsctl_time); + d_printf("ioctl_count: %u\n", profile_p->Trans2_ioctl_count); + d_printf("ioctl_time: %u\n", profile_p->Trans2_ioctl_time); + d_printf("findnotifyfirst_count: %u\n", profile_p->Trans2_findnotifyfirst_count); + d_printf("findnotifyfirst_time: %u\n", profile_p->Trans2_findnotifyfirst_time); + d_printf("findnotifynext_count: %u\n", profile_p->Trans2_findnotifynext_count); + d_printf("findnotifynext_time: %u\n", profile_p->Trans2_findnotifynext_time); + d_printf("mkdir_count: %u\n", profile_p->Trans2_mkdir_count); + d_printf("mkdir_time: %u\n", profile_p->Trans2_mkdir_time); + d_printf("session_setup_count: %u\n", profile_p->Trans2_session_setup_count); + d_printf("session_setup_time: %u\n", profile_p->Trans2_session_setup_time); + d_printf("get_dfs_referral_count: %u\n", profile_p->Trans2_get_dfs_referral_count); + d_printf("get_dfs_referral_time: %u\n", profile_p->Trans2_get_dfs_referral_time); + d_printf("report_dfs_inconsistancy_count: %u\n", profile_p->Trans2_report_dfs_inconsistancy_count); + d_printf("report_dfs_inconsistancy_time: %u\n", profile_p->Trans2_report_dfs_inconsistancy_time); + d_printf("************************ NT Transact Calls ***********************\n"); + d_printf("create_count: %u\n", profile_p->NT_transact_create_count); + d_printf("create_time: %u\n", profile_p->NT_transact_create_time); + d_printf("ioctl_count: %u\n", profile_p->NT_transact_ioctl_count); + d_printf("ioctl_time: %u\n", profile_p->NT_transact_ioctl_time); + d_printf("set_security_desc_count: %u\n", profile_p->NT_transact_set_security_desc_count); + d_printf("set_security_desc_time: %u\n", profile_p->NT_transact_set_security_desc_time); + d_printf("notify_change_count: %u\n", profile_p->NT_transact_notify_change_count); + d_printf("notify_change_time: %u\n", profile_p->NT_transact_notify_change_time); + d_printf("rename_count: %u\n", profile_p->NT_transact_rename_count); + d_printf("rename_time: %u\n", profile_p->NT_transact_rename_time); + d_printf("query_security_desc_count: %u\n", profile_p->NT_transact_query_security_desc_count); + d_printf("query_security_desc_time: %u\n", profile_p->NT_transact_query_security_desc_time); + d_printf("************************ ACL Calls *******************************\n"); + d_printf("get_nt_acl_count: %u\n", profile_p->get_nt_acl_count); + d_printf("get_nt_acl_time: %u\n", profile_p->get_nt_acl_time); + d_printf("fget_nt_acl_count: %u\n", profile_p->fget_nt_acl_count); + d_printf("fget_nt_acl_time: %u\n", profile_p->fget_nt_acl_time); + d_printf("set_nt_acl_count: %u\n", profile_p->set_nt_acl_count); + d_printf("set_nt_acl_time: %u\n", profile_p->set_nt_acl_time); + d_printf("fset_nt_acl_count: %u\n", profile_p->fset_nt_acl_count); + d_printf("fset_nt_acl_time: %u\n", profile_p->fset_nt_acl_time); + d_printf("chmod_acl_count: %u\n", profile_p->chmod_acl_count); + d_printf("chmod_acl_time: %u\n", profile_p->chmod_acl_time); + d_printf("fchmod_acl_count: %u\n", profile_p->fchmod_acl_count); + d_printf("fchmod_acl_time: %u\n", profile_p->fchmod_acl_time); + d_printf("************************ NMBD Calls ****************************\n"); + d_printf("name_release_count: %u\n", profile_p->name_release_count); + d_printf("name_release_time: %u\n", profile_p->name_release_time); + d_printf("name_refresh_count: %u\n", profile_p->name_refresh_count); + d_printf("name_refresh_time: %u\n", profile_p->name_refresh_time); + d_printf("name_registration_count: %u\n", profile_p->name_registration_count); + d_printf("name_registration_time: %u\n", profile_p->name_registration_time); + d_printf("node_status_count: %u\n", profile_p->node_status_count); + d_printf("node_status_time: %u\n", profile_p->node_status_time); + d_printf("name_query_count: %u\n", profile_p->name_query_count); + d_printf("name_query_time: %u\n", profile_p->name_query_time); + d_printf("host_announce_count: %u\n", profile_p->host_announce_count); + d_printf("host_announce_time: %u\n", profile_p->host_announce_time); + d_printf("workgroup_announce_count: %u\n", profile_p->workgroup_announce_count); + d_printf("workgroup_announce_time: %u\n", profile_p->workgroup_announce_time); + d_printf("local_master_announce_count: %u\n", profile_p->local_master_announce_count); + d_printf("local_master_announce_time: %u\n", profile_p->local_master_announce_time); + d_printf("master_browser_announce_count: %u\n", profile_p->master_browser_announce_count); + d_printf("master_browser_announce_time: %u\n", profile_p->master_browser_announce_time); + d_printf("lm_host_announce_count: %u\n", profile_p->lm_host_announce_count); + d_printf("lm_host_announce_time: %u\n", profile_p->lm_host_announce_time); + d_printf("get_backup_list_count: %u\n", profile_p->get_backup_list_count); + d_printf("get_backup_list_time: %u\n", profile_p->get_backup_list_time); + d_printf("reset_browser_count: %u\n", profile_p->reset_browser_count); + d_printf("reset_browser_time: %u\n", profile_p->reset_browser_time); + d_printf("announce_request_count: %u\n", profile_p->announce_request_count); + d_printf("announce_request_time: %u\n", profile_p->announce_request_time); + d_printf("lm_announce_request_count: %u\n", profile_p->lm_announce_request_count); + d_printf("lm_announce_request_time: %u\n", profile_p->lm_announce_request_time); + d_printf("domain_logon_count: %u\n", profile_p->domain_logon_count); + d_printf("domain_logon_time: %u\n", profile_p->domain_logon_time); + d_printf("sync_browse_lists_count: %u\n", profile_p->sync_browse_lists_count); + d_printf("sync_browse_lists_time: %u\n", profile_p->sync_browse_lists_time); + d_printf("run_elections_count: %u\n", profile_p->run_elections_count); + d_printf("run_elections_time: %u\n", profile_p->run_elections_time); + d_printf("election_count: %u\n", profile_p->election_count); + d_printf("election_time: %u\n", profile_p->election_time); + + return 0; } -void Ucrit_addPid(int pid) + +static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) { - int i; - if ( !Ucrit_IsActive) return; - for (i=0;i<Ucrit_MaxPid;i++) - if( pid == Ucrit_pid[i] ) return; - Ucrit_pid[Ucrit_MaxPid++] = pid; + struct connections_data crec; + + if (dbuf.dsize != sizeof(crec)) + return 0; + + memcpy(&crec, dbuf.dptr, sizeof(crec)); + + if (crec.cnum == -1) + return 0; + + if (!process_exists(crec.pid) || !Ucrit_checkUsername(uidtoname(crec.uid))) { + return 0; + } + + d_printf("%-10.10s %5d %-12s %s", + crec.name,(int)crec.pid, + crec.machine, + asctime(LocalTime(&crec.start))); + + return 0; } -unsigned int Ucrit_checkPid(int pid) +static int traverse_sessionid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) { - int i; - if ( !Ucrit_IsActive) return 1; - for (i=0;i<Ucrit_MaxPid;i++) - if( pid == Ucrit_pid[i] ) return 1; - return 0; + struct sessionid sessionid; + + if (dbuf.dsize != sizeof(sessionid)) + return 0; + + memcpy(&sessionid, dbuf.dptr, sizeof(sessionid)); + + if (!process_exists(sessionid.pid) || !Ucrit_checkUsername(uidtoname(sessionid.uid))) { + return 0; + } + + d_printf("%5d %-12s %-12s %-12s (%s)\n", + (int)sessionid.pid, uidtoname(sessionid.uid), gidtoname(sessionid.gid), + sessionid.remote_machine, sessionid.hostname); + + return 0; } + + + + int main(int argc, char *argv[]) +{ + pstring fname; + int c; + static int profile_only = 0; + static int new_debuglevel = -1; + TDB_CONTEXT *tdb; + poptContext pc; + struct poptOption long_options[] = { + {"processes", 'p', POPT_ARG_NONE, &processes_only}, + {"verbose", 'v', POPT_ARG_NONE, &verbose}, + {"locks", 'L', POPT_ARG_NONE, &locks_only}, + {"shares", 'S', POPT_ARG_NONE, &shares_only}, + {"conf", 's', POPT_ARG_STRING, 0, 's'}, + {"user", 'u', POPT_ARG_STRING, 0, 'u'}, + {"brief", 'b', POPT_ARG_NONE, &brief}, + {"profile", 'P', POPT_ARG_NONE, &profile_only}, + {"byterange", 'B', POPT_ARG_NONE, &show_brl}, + {"debug", 'd', POPT_ARG_INT, &new_debuglevel}, + { 0, 0, 0, 0} + }; + + + setup_logging(argv[0],True); + + AllowDebugChange = False; + DEBUGLEVEL = 0; + dbf = x_stderr; + + if (getuid() != geteuid()) { + d_printf("smbstatus should not be run setuid\n"); + return(1); + } + + pc = poptGetContext(NULL, argc, (const char **) argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + while ((c = poptGetNextOpt(pc)) != EOF) { + switch (c) { + case 's': + pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc)); + break; + case 'u': + Ucrit_addUsername(poptGetOptArg(pc)); + break; + default: + fprintf(stderr, "Usage: %s [-P] [-v] [-L] [-p] [-S] [-s configfile] [-u username] [-d debuglevel]\n", *argv); + return (-1); + } + } + + if (!lp_load(dyn_CONFIGFILE,False,False,False)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); + return (-1); + } + + if (new_debuglevel != -1) { + DEBUGLEVEL = new_debuglevel; + } + + if (verbose) { + d_printf("using configfile = %s\n", dyn_CONFIGFILE); + } + + if (profile_only) { + return profile_dump(); + } + + tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0); + if (!tdb) { + d_printf("sessionid.tdb not initialised\n"); + } else { + if (locks_only) goto locks; + + d_printf("\nSamba version %s\n",VERSION); + d_printf("PID Username Group Machine \n"); + d_printf("-------------------------------------------------------------------\n"); + + tdb_traverse(tdb, traverse_sessionid, NULL); + tdb_close(tdb); + } + + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0); + if (!tdb) { + d_printf("connections.tdb not initialised\n"); + } else { + if (verbose) { + d_printf("Opened status file %s\n", fname); + } + + if (brief) + exit(0); + + d_printf("\nService pid machine Connected at\n"); + d_printf("-------------------------------------------------------\n"); + + tdb_traverse(tdb, traverse_fn1, NULL); + tdb_close(tdb); + } + + locks: + if (processes_only) exit(0); + + if (!shares_only) { + int ret; + + if (!locking_init(1)) { + d_printf("Can't initialise locking module - exiting\n"); + exit(1); + } + + ret = share_mode_forall(print_share_mode); + + if (ret == 0) { + d_printf("No locked files\n"); + } else if (ret == -1) { + d_printf("locked file list truncated\n"); + } + + d_printf("\n"); + + if (show_brl) { + brl_forall(print_brl); + } + + locking_end(); + } + + return (0); +} diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index e1f070a4b8..defde6cb2c 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -1,8 +1,7 @@ /* - Unix SMB/Netbios implementation. - Version 1.9. + Unix SMB/CIFS implementation. Test validity of smb.conf - Copyright (C) Karl Auer 1993, 1994 + Copyright (C) Karl Auer 1993, 1994-1998 Extensively modified by Andrew Tridgell, 1995 @@ -34,80 +33,280 @@ #include "includes.h" #include "smb.h" -#include "params.h" -#include "loadparm.h" -/* these live in util.c */ -extern FILE *dbf; -extern int DEBUGLEVEL; +extern BOOL AllowDebugChange; + +/*********************************************** + Here we do a set of 'hard coded' checks for bad + configuration settings. +************************************************/ + +static int do_global_checks(void) +{ + int ret = 0; + SMB_STRUCT_STAT st; + + if (lp_security() >= SEC_DOMAIN && !lp_encrypted_passwords()) { + printf("ERROR: in 'security=domain' mode the 'encrypt passwords' parameter must also be set to 'true'.\n"); + ret = 1; + } + + if (lp_wins_support() && wins_srv_count()) { + printf("ERROR: both 'wins support = true' and 'wins server = <server>' \ +cannot be set in the smb.conf file. nmbd will abort with this setting.\n"); + ret = 1; + } + + if (!directory_exist(lp_lockdir(), &st)) { + printf("ERROR: lock directory %s does not exist\n", + lp_lockdir()); + ret = 1; + } else if ((st.st_mode & 0777) != 0755) { + printf("WARNING: lock directory %s should have permissions 0755 for browsing to work\n", + lp_lockdir()); + ret = 1; + } + + /* + * Password server sanity checks. + */ + + if((lp_security() == SEC_SERVER || lp_security() >= SEC_DOMAIN) && !lp_passwordserver()) { + pstring sec_setting; + if(lp_security() == SEC_SERVER) + pstrcpy(sec_setting, "server"); + else if(lp_security() == SEC_DOMAIN) + pstrcpy(sec_setting, "domain"); + + printf("ERROR: The setting 'security=%s' requires the 'password server' parameter be set \ +to a valid password server.\n", sec_setting ); + ret = 1; + } + + + /* + * Check 'hosts equiv' and 'use rhosts' compatibility with 'hostname lookup' value. + */ + + if(*lp_hosts_equiv() && !lp_hostname_lookups()) { + printf("ERROR: The setting 'hosts equiv = %s' requires that 'hostname lookups = yes'.\n", lp_hosts_equiv()); + ret = 1; + } + + /* + * Password chat sanity checks. + */ + + if(lp_security() == SEC_USER && lp_unix_password_sync()) { + + /* + * Check that we have a valid lp_passwd_program() if not using pam. + */ + +#ifdef WITH_PAM + if (!lp_pam_password_change()) { +#endif + + if(lp_passwd_program() == NULL) { + printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd program' \ +parameter.\n" ); + ret = 1; + } else { + pstring passwd_prog; + pstring truncated_prog; + char *p; + + pstrcpy( passwd_prog, lp_passwd_program()); + p = passwd_prog; + *truncated_prog = '\0'; + next_token(&p, truncated_prog, NULL, sizeof(pstring)); + + if(access(truncated_prog, F_OK) == -1) { + printf("ERROR: the 'unix password sync' parameter is set and the 'passwd program' (%s) \ +cannot be executed (error was %s).\n", truncated_prog, strerror(errno) ); + ret = 1; + } + } + +#ifdef WITH_PAM + } +#endif + + if(lp_passwd_chat() == NULL) { + printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd chat' \ +parameter.\n"); + ret = 1; + } + + /* + * Check that we have a valid script and that it hasn't + * been written to expect the old password. + */ + + if(lp_encrypted_passwords()) { + if(strstr( lp_passwd_chat(), "%o")!=NULL) { + printf("ERROR: the 'passwd chat' script [%s] expects to use the old plaintext password \ +via the %%o substitution. With encrypted passwords this is not possible.\n", lp_passwd_chat() ); + ret = 1; + } + } + } + + return ret; +} + +static void usage(char *pname) +{ + printf("Usage: %s [-sh] [-L servername] [configfilename] [hostname hostIP]\n", pname); + printf("\t-s Suppress prompt for enter\n"); + printf("\t-h Print usage\n"); + printf("\t-L servername Set %%L macro to servername\n"); + printf("\t-t encoding Print parameters with encoding\n"); + printf("\tconfigfilename Configuration file to test\n"); + printf("\thostname hostIP. Hostname and Host IP address to test\n"); + printf("\t against \"host allow\" and \"host deny\"\n"); + printf("\n"); +} + int main(int argc, char *argv[]) { + extern char *optarg; + extern int optind; + extern fstring local_machine; pstring configfile; + int opt; int s; + BOOL silent_mode = False; + int ret = 0; + pstring term_code; + + *term_code = 0; setup_logging(argv[0],True); - charset_initialise(); + while ((opt = getopt(argc, argv,"shL:t:")) != EOF) { + switch (opt) { + case 's': + silent_mode = True; + break; + case 'L': + fstrcpy(local_machine,optarg); + break; + case 'h': + usage(argv[0]); + exit(0); + break; + case 't': + pstrcpy(term_code,optarg); + break; + default: + printf("Incorrect program usage\n"); + usage(argv[0]); + exit(1); + break; + } + } + + argc += (1 - optind); - if (argc < 2) - strcpy(configfile,CONFIGFILE); - else - strcpy(configfile,argv[1]); + if ((argc == 1) || (argc == 3)) + pstrcpy(configfile, dyn_CONFIGFILE); + else if ((argc == 2) || (argc == 4)) + pstrcpy(configfile,argv[optind]); - dbf = stdout; + dbf = x_stdout; DEBUGLEVEL = 2; + AllowDebugChange = False; printf("Load smb config files from %s\n",configfile); - if (!lp_load(configfile,False)) - { + if (!lp_load(configfile,False,True,False)) { printf("Error loading services.\n"); return(1); - } - + } printf("Loaded services file OK.\n"); - for (s=0;s<1000;s++) + ret = do_global_checks(); + + for (s=0;s<1000;s++) { if (VALID_SNUM(s)) if (strlen(lp_servicename(s)) > 8) { - printf("WARNING: You have some share names that are longer than 8 chars\n"); - printf("These may give errors while browsing or may not be accessible\nto some older clients\n"); - break; + printf("WARNING: You have some share names that are longer than 8 chars\n"); + printf("These may give errors while browsing or may not be accessible\nto some older clients\n"); + break; + } + } + + for (s=0;s<1000;s++) { + if (VALID_SNUM(s)) { + char **deny_list = lp_hostsdeny(s); + char **allow_list = lp_hostsallow(s); + int i; + if(deny_list) { + for (i=0; deny_list[i]; i++) { + char *hasstar = strchr_m(deny_list[i], '*'); + char *hasquery = strchr_m(deny_list[i], '?'); + if(hasstar || hasquery) { + printf("Invalid character %c in hosts deny list (%s) for service %s.\n", + hasstar ? *hasstar : *hasquery, deny_list[i], lp_servicename(s) ); + } + } } - if (argc < 4) - { + if(allow_list) { + for (i=0; allow_list[i]; i++) { + char *hasstar = strchr_m(allow_list[i], '*'); + char *hasquery = strchr_m(allow_list[i], '?'); + if(hasstar || hasquery) { + printf("Invalid character %c in hosts allow list (%s) for service %s.\n", + hasstar ? *hasstar : *hasquery, allow_list[i], lp_servicename(s) ); + } + } + } + + if(lp_level2_oplocks(s) && !lp_oplocks(s)) { + printf("Invalid combination of parameters for service %s. \ +Level II oplocks can only be set if oplocks are also set.\n", + lp_servicename(s) ); + } + } + } + + if (argc < 3) { + if (!silent_mode) { printf("Press enter to see a dump of your service definitions\n"); fflush(stdout); getc(stdin); - lp_dump(); } + lp_dump(stdout,True, lp_numservices()); + } - if (argc == 4) - { - struct from_host f; - f.name = argv[2]; - f.addr = argv[3]; + if (argc >= 3) { + char *cname; + char *caddr; - /* this is totally ugly, a real `quick' hack */ - for (s=0;s<1000;s++) - if (VALID_SNUM(s)) - { - if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),&f)) - { - printf("Allow connection from %s (%s) to %s\n", - f.name,f.addr,lp_servicename(s)); - } - else - { - printf("Deny connection from %s (%s) to %s\n", - f.name,f.addr,lp_servicename(s)); - } - } + if (argc == 3) { + cname = argv[optind]; + caddr = argv[optind+1]; + } else { + cname = argv[optind+1]; + caddr = argv[optind+2]; } - return(0); -} - + /* this is totally ugly, a real `quick' hack */ + for (s=0;s<1000;s++) { + if (VALID_SNUM(s)) { + if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),cname,caddr)) { + printf("Allow connection from %s (%s) to %s\n", + cname,caddr,lp_servicename(s)); + } else { + printf("Deny connection from %s (%s) to %s\n", + cname,caddr,lp_servicename(s)); + } + } + } + } + return(ret); +} diff --git a/source3/utils/testprns.c b/source3/utils/testprns.c index 89c615898d..66c8e9bfd6 100644 --- a/source3/utils/testprns.c +++ b/source3/utils/testprns.c @@ -1,8 +1,7 @@ /* - Unix SMB/Netbios implementation. - Version 1.9. + Unix SMB/CIFS implementation. test printer setup - Copyright (C) Karl Auer 1993, 1994 + Copyright (C) Karl Auer 1993, 1994-1998 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 @@ -33,11 +32,6 @@ #include "includes.h" #include "smb.h" -#include "pcap.h" - -/* these live in util.c */ -extern FILE *dbf; -extern int DEBUGLEVEL; int main(int argc, char *argv[]) { @@ -45,17 +39,14 @@ int main(int argc, char *argv[]) setup_logging(argv[0],True); - charset_initialise(); - if (argc < 2 || argc > 3) printf("Usage: testprns printername [printcapfile]\n"); else { - dbf = fopen("test.log", "w"); - if (dbf == NULL) + dbf = x_fopen("test.log", O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (dbf == NULL) { printf("Unable to open logfile.\n"); - else - { + } else { DEBUGLEVEL = 3; pszTemp = (argc < 3) ? PRINTCAP_NAME : argv[2]; printf("Looking for printer %s in printcap file %s\n", @@ -64,9 +55,8 @@ int main(int argc, char *argv[]) printf("Printer name %s is not valid.\n", argv[1]); else printf("Printer name %s is valid.\n", argv[1]); - fclose(dbf); + x_fclose(dbf); } } return (0); } - |