X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source%2Fsmbd%2Flanman.c;h=c53889a7a47fb0d66c574dffb5a2441d4cebf071;hb=68283407e0f366d8315f4be6caed67eb6fe84b85;hp=944a187ccc9a6a0622ced57574237cbbd6c08da3;hpb=18fa724a7969666dd5aa176af187054abc94bfd3;p=jra%2Fsamba%2F.git diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c index 944a187ccc9..c53889a7a47 100644 --- a/source/smbd/lanman.c +++ b/source/smbd/lanman.c @@ -1,7 +1,5 @@ -#define OLD_NTDOMAIN 1 /* - Unix SMB/Netbios implementation. - Version 1.9. + Unix SMB/CIFS implementation. Inter-process communication and named pipe handling Copyright (C) Andrew Tridgell 1992-1998 @@ -34,11 +32,7 @@ #endif #define CHECK_TYPES 0 -extern int DEBUGLEVEL; - extern fstring local_machine; -extern pstring global_myname; -extern fstring global_myworkgroup; #define NERR_Success 0 #define NERR_badpass 86 @@ -75,9 +69,8 @@ static int CopyExpanded(connection_struct *conn, StrnCpy(buf,src,sizeof(buf)/2); pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf); - StrnCpy(*dst,buf,*n); - l = strlen(*dst) + 1; + standard_sub_conn(conn,buf,sizeof(buf)); + l = push_ascii(*dst,buf,*n, STR_TERMINATE); (*dst) += l; (*n) -= l; return l; @@ -87,8 +80,7 @@ static int CopyAndAdvance(char** dst, char* src, int* n) { int l; if (!src || !dst || !n || !(*dst)) return(0); - StrnCpy(*dst,src,*n-1); - l = strlen(*dst) + 1; + l = push_ascii(*dst,src,*n, STR_TERMINATE); (*dst) += l; (*n) -= l; return l; @@ -100,7 +92,7 @@ static int StrlenExpanded(connection_struct *conn, int snum, char* s) if (!s) return(0); StrnCpy(buf,s,sizeof(buf)/2); pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf); + standard_sub_conn(conn,buf,sizeof(buf)); return strlen(buf) + 1; } @@ -110,21 +102,21 @@ static char* Expand(connection_struct *conn, int snum, char* s) if (!s) return(NULL); StrnCpy(buf,s,sizeof(buf)/2); pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf); + standard_sub_conn(conn,buf,sizeof(buf)); return &buf[0]; } /******************************************************************* check a API string for validity when we only need to check the prefix ******************************************************************/ -static BOOL prefix_ok(char *str,char *prefix) +static BOOL prefix_ok(const char *str, const char *prefix) { return(strncmp(str,prefix,strlen(prefix)) == 0); } struct pack_desc { - char* format; /* formatstring for structure */ - char* subformat; /* subformat for structure */ + const char* format; /* formatstring for structure */ + const char* subformat; /* subformat for structure */ char* base; /* baseaddress of buffer */ int buflen; /* remaining size for fixed part; on init: length of base */ int subcount; /* count of substructures */ @@ -133,11 +125,11 @@ struct pack_desc { char* stringbuf; /* pointer into buffer for remaining variable part */ int neededlen; /* total needed size */ int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */ - char* curpos; /* current position; pointer into format or subformat */ + const char* curpos; /* current position; pointer into format or subformat */ int errcode; }; -static int get_counter(char** p) +static int get_counter(const char** p) { int i, n; if (!p || !(*p)) return(1); @@ -152,7 +144,7 @@ static int get_counter(char** p) } } -static int getlen(char* p) +static int getlen(const char* p) { int n = 0; if (!p) return(0); @@ -201,7 +193,17 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount) if (i > n) { p->neededlen = i; i = n = 0; +#if 0 + /* + * This is the old error code we used. Aparently + * WinNT/2k systems return ERRbuftoosmall (2123) and + * OS/2 needs this. I'm leaving this here so we can revert + * if needed. JRA. + */ p->errcode = ERRmoredata; +#else + p->errcode = ERRbuftoosmall; +#endif } else p->errcode = NERR_Success; @@ -212,27 +214,15 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount) return(p->errcode == NERR_Success); } -#ifdef HAVE_STDARG_H static int package(struct pack_desc* p, ...) { -#else -static int package(va_alist) -va_dcl -{ - struct pack_desc* p; -#endif va_list args; int needed=0, stringneeded; - char* str=NULL; + const char* str=NULL; int is_string=0, stringused; int32 temp; -#ifdef HAVE_STDARG_H va_start(args,p); -#else - va_start(args); - p = va_arg(args,struct pack_desc *); -#endif if (!*p->curpos) { if (!p->subcount) @@ -339,12 +329,12 @@ va_dcl #define PACKl(desc,t,v,l) package(desc,v,l) #endif -static void PACKI(struct pack_desc* desc,char *t,int v) +static void PACKI(struct pack_desc* desc, const char *t,int v) { PACK(desc,t,v); } -static void PACKS(struct pack_desc* desc,char *t,char *v) +static void PACKS(struct pack_desc* desc,const char *t,const char *v) { PACK(desc,t,v); } @@ -359,7 +349,7 @@ static void PackDriverData(struct pack_desc* desc) SIVAL(drivdata,0,sizeof drivdata); /* cb */ SIVAL(drivdata,4,1000); /* lVersion */ memset(drivdata+8,0,32); /* szDeviceName */ - pstrcpy(drivdata+8,"NULL"); + push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE); PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */ } @@ -403,14 +393,14 @@ static int check_printq_info(struct pack_desc* desc, } -#define JOB_STATUS_QUEUED 0 -#define JOB_STATUS_PAUSED 1 -#define JOB_STATUS_SPOOLING 2 -#define JOB_STATUS_PRINTING 3 -#define JOB_STATUS_PRINTED 4 +#define RAP_JOB_STATUS_QUEUED 0 +#define RAP_JOB_STATUS_PAUSED 1 +#define RAP_JOB_STATUS_SPOOLING 2 +#define RAP_JOB_STATUS_PRINTING 3 +#define RAP_JOB_STATUS_PRINTED 4 -#define QUEUE_STATUS_PAUSED 1 -#define QUEUE_STATUS_ERROR 2 +#define RAP_QUEUE_STATUS_PAUSED 1 +#define RAP_QUEUE_STATUS_ERROR 2 /* turn a print job status into a on the wire status */ @@ -418,13 +408,13 @@ static int printj_status(int v) { switch (v) { case LPQ_QUEUED: - return JOB_STATUS_QUEUED; + return RAP_JOB_STATUS_QUEUED; case LPQ_PAUSED: - return JOB_STATUS_PAUSED; + return RAP_JOB_STATUS_PAUSED; case LPQ_SPOOLING: - return JOB_STATUS_SPOOLING; + return RAP_JOB_STATUS_SPOOLING; case LPQ_PRINTING: - return JOB_STATUS_PRINTING; + return RAP_JOB_STATUS_PRINTING; } return 0; } @@ -437,9 +427,9 @@ static int printq_status(int v) case LPQ_QUEUED: return 0; case LPQ_PAUSED: - return QUEUE_STATUS_PAUSED; + return RAP_QUEUE_STATUS_PAUSED; } - return QUEUE_STATUS_ERROR; + return RAP_QUEUE_STATUS_ERROR; } static void fill_printjob_info(connection_struct *conn, int snum, int uLevel, @@ -451,9 +441,9 @@ static void fill_printjob_info(connection_struct *conn, int snum, int uLevel, /* the client expects localtime */ t -= TimeDiff(t); - PACKI(desc,"W",queue->job); /* uJobId */ + PACKI(desc,"W",pjobid_to_rap(snum,queue->job)); /* uJobId */ if (uLevel == 1) { - PACKS(desc,"B21",queue->user); /* szUserName */ + PACKS(desc,"B21",queue->fs_user); /* szUserName */ PACKS(desc,"B",""); /* pad */ PACKS(desc,"B16",""); /* szNotifyName */ PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */ @@ -463,17 +453,17 @@ static void fill_printjob_info(connection_struct *conn, int snum, int uLevel, PACKS(desc,"z",""); /* pszStatus */ PACKI(desc,"D",t); /* ulSubmitted */ PACKI(desc,"D",queue->size); /* ulSize */ - PACKS(desc,"z",queue->file); /* pszComment */ + PACKS(desc,"z",queue->fs_file); /* pszComment */ } - if (uLevel == 2 || uLevel == 3) { + if (uLevel == 2 || uLevel == 3 || uLevel == 4) { PACKI(desc,"W",queue->priority); /* uPriority */ - PACKS(desc,"z",queue->user); /* pszUserName */ + PACKS(desc,"z",queue->fs_user); /* pszUserName */ PACKI(desc,"W",n+1); /* uPosition */ PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */ PACKI(desc,"D",t); /* ulSubmitted */ PACKI(desc,"D",queue->size); /* ulSize */ PACKS(desc,"z","Samba"); /* pszComment */ - PACKS(desc,"z",queue->file); /* pszDocument */ + PACKS(desc,"z",queue->fs_file); /* pszDocument */ if (uLevel == 3) { PACKS(desc,"z",""); /* pszNotifyName */ PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */ @@ -485,183 +475,124 @@ static void fill_printjob_info(connection_struct *conn, int snum, int uLevel, PACKS(desc,"z","NULL"); /* pszDriverName */ PackDriverData(desc); /* pDriverData */ PACKS(desc,"z",""); /* pszPrinterName */ + } else if (uLevel == 4) { /* OS2 */ + PACKS(desc,"z",""); /* pszSpoolFileName */ + PACKS(desc,"z",""); /* pszPortName */ + PACKS(desc,"z",""); /* pszStatus */ + PACKI(desc,"D",0); /* ulPagesSpooled */ + PACKI(desc,"D",0); /* ulPagesSent */ + PACKI(desc,"D",0); /* ulPagesPrinted */ + PACKI(desc,"D",0); /* ulTimePrinted */ + PACKI(desc,"D",0); /* ulExtendJobStatus */ + PACKI(desc,"D",0); /* ulStartPage */ + PACKI(desc,"D",0); /* ulEndPage */ } } } /******************************************************************** - Respond to the DosPrintQInfo command with a level of 52 - This is used to get printer driver information for Win9x clients + Return a driver name given an snum. + Returns True if from tdb, False otherwise. ********************************************************************/ -static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel, - struct pack_desc* desc, - int count, print_queue_struct* queue, - print_status_struct* status) + +static BOOL get_driver_name(int snum, pstring drivername) { - int i; - BOOL ok = False; - pstring tok,driver,datafile,langmon,helpfile,datatype; - char *p; - char **lines = NULL; - pstring gen_line; NT_PRINTER_INFO_LEVEL *info = NULL; BOOL in_tdb = False; - fstring location; - - /* - * Check in the tdb *first* before checking the legacy - * files. This allows an NT upload to take precedence over - * the existing fileset. JRA. - * - * we need to lookup the driver name prior to making the call - * to get_a_printer_driver_9x_compatible() and not rely on the - * 'print driver' parameter --jerry - */ - get_a_printer (&info, 2, lp_servicename(snum)); - if ((info != NULL) && - ((ok = get_a_printer_driver_9x_compatible(gen_line, info->info_2->drivername)) == True)) - { + get_a_printer (NULL, &info, 2, lp_servicename(snum)); + if (info != NULL) { + pstrcpy( drivername, info->info_2->drivername); in_tdb = True; - p = gen_line; - DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", - info->info_2->drivername, gen_line)); - } - else - { - /* didn't find driver in tdb */ - - DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n", - snum, lp_printerdriver(snum), lp_driverfile(snum))); - - lines = file_lines_load(lp_driverfile(snum),NULL); - if (!lines) - { - DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum), - strerror(errno))); - desc->errcode=NERR_notsupported; - goto done; - } - - /* lookup the long printer driver name in the file description */ - for (i=0;lines[i] && !ok;i++) - { - p = lines[i]; - if (next_token(&p,tok,":",sizeof(tok)) && - (strlen(lp_printerdriver(snum)) == strlen(tok)) && - (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum))))) - { - ok = True; - } - } + free_a_printer(&info, 2); } - if (ok) - { - /* driver file name */ - if (!next_token(&p,driver,":",sizeof(driver))) - goto err; + return in_tdb; +} - /* data file name */ - if (!next_token(&p,datafile,":",sizeof(datafile))) - goto err; +/******************************************************************** + Respond to the DosPrintQInfo command with a level of 52 + This is used to get printer driver information for Win9x clients + ********************************************************************/ +static void fill_printq_info_52(connection_struct *conn, int snum, + struct pack_desc* desc, int count ) +{ + int i; + fstring location; + NT_PRINTER_DRIVER_INFO_LEVEL driver; + NT_PRINTER_INFO_LEVEL *printer = NULL; - /* - * for the next tokens - which may be empty - I have - * to check for empty tokens first because the - * next_token function will skip all empty token - * fields */ + ZERO_STRUCT(driver); - /* help file */ - if (*p == ':') - { - *helpfile = '\0'; - p++; - } - else if (!next_token(&p,helpfile,":",sizeof(helpfile))) - goto err; + if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) { + DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", + lp_servicename(snum))); + goto err; + } + + if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, + "Windows 4.0", 0)) ) + { + DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", + printer->info_2->drivername)); + goto err; + } + + trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0); + trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0); + trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0); - /* language monitor */ - if (*p == ':') - { - *langmon = '\0'; - p++; - } - else if (!next_token(&p,langmon,":",sizeof(langmon))) - goto err; + PACKI(desc, "W", 0x0400); /* don't know */ + PACKS(desc, "z", driver.info_3->name); /* long printer name */ + PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */ + PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */ + PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */ - /* default data type */ - if (!next_token(&p,datatype,":",sizeof(datatype))) - goto err; + fstrcpy(location, "\\\\"); + fstrcat(location, get_called_name()); + fstrcat(location, "\\print$\\WIN40\\0"); + PACKS(desc,"z", location); /* share to retrieve files */ - PACKI(desc,"W",0x0400); /* don't know */ - if (in_tdb) - { - PACKS(desc,"z",info->info_2->drivername); /* long printer name */ - } - else - { - PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */ - } - PACKS(desc,"z",driver); /* Driverfile Name */ - PACKS(desc,"z",datafile); /* Datafile name */ - PACKS(desc,"z",langmon); /* language monitor */ - if (in_tdb) - { - fstrcpy(location, "\\\\"); - fstrcat(location, global_myname); - fstrcat(location, "\\print$\\WIN40\\0"); - PACKS(desc,"z",location); /* share to retrieve files */ - } - else - { - PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */ - } - PACKS(desc,"z",datatype); /* default data type */ - PACKS(desc,"z",helpfile); /* helpfile name */ - PACKS(desc,"z",driver); /* driver name */ - - if (in_tdb) - DEBUG(3,("lp_printerdriver:%s:\n",info->info_2->drivername)); - else - DEBUG(3,("lp_printerdriver:%s:\n",lp_printerdriver(snum))); - - DEBUG(3,("Driver:%s:\n",driver)); - DEBUG(3,("Data File:%s:\n",datafile)); - DEBUG(3,("Language Monitor:%s:\n",langmon)); - if (in_tdb) - DEBUG(3,("lp_driverlocation:%s:\n",location)); - else - DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum))); - DEBUG(3,("Data Type:%s:\n",datatype)); - DEBUG(3,("Help File:%s:\n",helpfile)); - PACKI(desc,"N",count); /* number of files to copy */ - - for (i=0;i gave %d entries\n", - SERVICE(snum),count)); - - desc->errcode=NERR_Success; - goto done; + PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */ + PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */ + PACKS(desc,"z", driver.info_3->driverpath); /* driver name */ + + DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name)); + DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath)); + DEBUG(3,("Data File: %s:\n",driver.info_3->datafile)); + DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname)); + DEBUG(3,("Driver Location: %s:\n",location)); + DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype)); + DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile)); + PACKI(desc,"N",count); /* number of files to copy */ + + for ( i=0; idependentfiles && *driver.info_3->dependentfiles[i]; i++) + { + trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0); + PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */ + DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i])); } + + /* sanity check */ + if ( i != count ) + DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n", + count, i)); + + DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i)); - err: + desc->errcode=NERR_Success; + goto done; +err: DEBUG(3,("fill_printq_info: Can't supply driver files\n")); desc->errcode=NERR_notsupported; - done: - safe_free(info); - file_lines_free(lines); +done: + if ( printer ) + free_a_printer( &printer, 2 ); + + if ( driver.info_3 ) + free_a_printer_driver( driver, 3 ); } @@ -709,23 +640,27 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel, } if (uLevel == 3 || uLevel == 4) { + pstring drivername; + PACKI(desc,"W",5); /* uPriority */ PACKI(desc,"W",0); /* uStarttime */ PACKI(desc,"W",0); /* uUntiltime */ PACKI(desc,"W",5); /* pad1 */ PACKS(desc,"z",""); /* pszSepFile */ PACKS(desc,"z","WinPrint"); /* pszPrProc */ - PACKS(desc,"z",""); /* pszParms */ - if (!status || !status->message[0]) { - PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */ + PACKS(desc,"z",NULL); /* pszParms */ + PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */ + /* "don't ask" that it's done this way to fix corrupted + Win9X/ME printer comments. */ + if (!status) { PACKI(desc,"W",LPSTAT_OK); /* fsStatus */ } else { - PACKS(desc,"z",status->message); /* pszComment */ PACKI(desc,"W",printq_status(status->status)); /* fsStatus */ } PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */ PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */ - PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */ + get_driver_name(snum,drivername); + PACKS(desc,"z",drivername); /* pszDriverName */ PackDriverData(desc); /* pDriverData */ } @@ -735,90 +670,44 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel, fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i); } - if (uLevel==52) { - fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status); - } + if (uLevel==52) + fill_printq_info_52( conn, snum, desc, count ); } /* This function returns the number of files for a given driver */ static int get_printerdrivernumber(int snum) { - int i, result = 0; - BOOL ok = False; - pstring tok; - char *p; - char **lines = NULL; - pstring gen_line; - NT_PRINTER_INFO_LEVEL *info = NULL; - - /* - * Check in the tdb *first* before checking the legacy - * files. This allows an NT upload to take precedence over - * the existing fileset. JRA. - * - * we need to lookup the driver name prior to making the call - * to get_a_printer_driver_9x_compatible() and not rely on the - * 'print driver' parameter --jerry - */ - - get_a_printer (&info, 2, lp_servicename(snum)); - if ((info != NULL) && - (ok = get_a_printer_driver_9x_compatible(gen_line, info->info_2->drivername) == True)) - { - p = gen_line; - DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", lp_printerdriver(snum), gen_line)); - } - else - { - /* didn't find driver in tdb */ - - DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n", - snum, lp_printerdriver(snum), lp_driverfile(snum))); - - lines = file_lines_load(lp_driverfile(snum), NULL); - if (!lines) - { - DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno))); - goto done; - } + int result = 0; + NT_PRINTER_DRIVER_INFO_LEVEL driver; + NT_PRINTER_INFO_LEVEL *printer = NULL; - /* lookup the long printer driver name in the file description */ - for (i=0;lines[i] && !ok;i++) - { - p = lines[i]; - if (next_token(&p,tok,":",sizeof(tok)) && - (strlen(lp_printerdriver(snum)) == strlen(tok)) && - (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum))))) - { - ok = True; - } - } + ZERO_STRUCT(driver); + + if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) { + DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n", + lp_servicename(snum))); + goto done; } - - if( ok ) - { - /* skip 5 fields */ - i = 5; - while (*p && i) { - if (*p++ == ':') i--; - } - if (!*p || i) { - DEBUG(3,("Can't determine number of printer driver files\n")); - goto done; - } - /* count the number of files */ - while (next_token(&p,tok,",",sizeof(tok))) - i++; - - result = i; + if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, + "Windows 4.0", 0)) ) + { + DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", + printer->info_2->drivername)); + goto done; } - + + /* count the number of files */ + while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] ) + result++; + \ done: - - safe_free(info); - file_lines_free(lines); - + if ( printer ) + free_a_printer( &printer, 2 ); + + if ( driver.info_3 ) + free_a_printer_driver( driver, 3 ); + return result; } @@ -828,108 +717,110 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char *QueueName = p; - int uLevel; - int count=0; - int snum; - char* str3; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - - memset((char *)&status,'\0',sizeof(status)); - memset((char *)&desc,'\0',sizeof(desc)); + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + char *QueueName = p; + int uLevel; + int count=0; + int snum; + char* str3; + struct pack_desc desc; + print_queue_struct *queue=NULL; + print_status_struct status; + char* tmpdata=NULL; + + memset((char *)&status,'\0',sizeof(status)); + memset((char *)&desc,'\0',sizeof(desc)); - p = skip_string(p,1); - uLevel = SVAL(p,0); - str3 = p + 4; + p = skip_string(p,1); + uLevel = SVAL(p,0); + str3 = p + 4; - /* remove any trailing username */ - if ((p = strchr(QueueName,'%'))) *p = 0; + /* remove any trailing username */ + if ((p = strchr_m(QueueName,'%'))) + *p = 0; - DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName)); + DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName)); - /* check it's a supported varient */ - if (!prefix_ok(str1,"zWrLh")) return False; - if (!check_printq_info(&desc,uLevel,str2,str3)) { - /* - * Patch from Scott Moomaw - * to return the 'invalid info level' error if an - * unknown level was requested. - */ - *rdata_len = 0; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,ERROR_INVALID_LEVEL); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,0); - return(True); - } + /* check it's a supported varient */ + if (!prefix_ok(str1,"zWrLh")) + return False; + if (!check_printq_info(&desc,uLevel,str2,str3)) { + /* + * Patch from Scott Moomaw + * to return the 'invalid info level' error if an + * unknown level was requested. + */ + *rdata_len = 0; + *rparam_len = 6; + *rparam = REALLOC(*rparam,*rparam_len); + SSVALS(*rparam,0,ERRunknownlevel); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,0); + return(True); + } - snum = lp_servicenumber(QueueName); - if (snum < 0 && pcap_printername_ok(QueueName,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(QueueName,pnum); - snum = lp_servicenumber(QueueName); - } - } + snum = lp_servicenumber(QueueName); + if (snum < 0 && pcap_printername_ok(QueueName,NULL)) { + int pnum = lp_servicenumber(PRINTERS_NAME); + if (pnum >= 0) { + lp_add_printer(QueueName,pnum); + snum = lp_servicenumber(QueueName); + } + } - if (snum < 0 || !VALID_SNUM(snum)) return(False); + if (snum < 0 || !VALID_SNUM(snum)) + return(False); - if (uLevel==52) { - count = get_printerdrivernumber(snum); - DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count)); - } else { - count = print_queue_status(snum, &queue,&status); - } + if (uLevel==52) { + count = get_printerdrivernumber(snum); + DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count)); + } else { + count = print_queue_status(snum, &queue,&status); + } - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,1,count)) { - desc.subcount = count; - fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status); - } else if(uLevel == 0) { -#if 0 - /* - * This is a *disgusting* hack. - * This is *so* bad that even I'm embarrassed (and I - * have no shame). Here's the deal : - * Until we get the correct SPOOLSS code into smbd - * then when we're running with NT SMB support then - * NT makes this call with a level of zero, and then - * immediately follows it with an open request to - * the \\SRVSVC pipe. If we allow that open to - * succeed then NT barfs when it cannot open the - * \\SPOOLSS pipe immediately after and continually - * whines saying "Printer name is invalid" forever - * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC - * to fail, then NT downgrades to using the downlevel code - * and everything works as well as before. I hate - * myself for adding this code.... JRA. - */ - - fail_next_srvsvc_open(); -#endif - } + if (mdrcnt > 0) { + *rdata = REALLOC(*rdata,mdrcnt); + desc.base = *rdata; + desc.buflen = mdrcnt; + } else { + /* + * Don't return data but need to get correct length + * init_package will return wrong size if buflen=0 + */ + desc.buflen = getlen(desc.format); + desc.base = tmpdata = (char *) malloc (desc.buflen); + } - *rdata_len = desc.usedlen; + if (init_package(&desc,1,count)) { + desc.subcount = count; + fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status); + } + + *rdata_len = desc.usedlen; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); + /* + * We must set the return code to ERRbuftoosmall + * in order to support lanman style printing with Win NT/2k + * clients --jerry + */ + if (!mdrcnt && lp_disable_spoolss()) + desc.errcode = ERRbuftoosmall; + + *rdata_len = desc.usedlen; + *rparam_len = 6; + *rparam = REALLOC(*rparam,*rparam_len); + SSVALS(*rparam,0,desc.errcode); + SSVAL(*rparam,2,0); + SSVAL(*rparam,4,desc.neededlen); - DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode)); + DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode)); - if (queue) free(queue); - - return(True); + SAFE_FREE(queue); + SAFE_FREE(tmpdata); + + return(True); } /**************************************************************************** @@ -968,7 +859,7 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, *rdata_len = 0; *rparam_len = 6; *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,ERROR_INVALID_LEVEL); + SSVALS(*rparam,0,ERRunknownlevel); SSVAL(*rparam,2,0); SSVAL(*rparam,4,0); return(True); @@ -1017,7 +908,7 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, } } - if (subcntarr) free(subcntarr); + SAFE_FREE(subcntarr); *rdata_len = desc.usedlen; *rparam_len = 8; @@ -1028,11 +919,11 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, SSVAL(*rparam,6,queuecnt); for (i = 0; i < queuecnt; i++) { - if (queue && queue[i]) free(queue[i]); + if (queue) SAFE_FREE(queue[i]); } - if (queue) free(queue); - if (status) free(status); + SAFE_FREE(queue); + SAFE_FREE(status); return True; } @@ -1071,7 +962,7 @@ struct srv_info_struct ******************************************************************/ static int get_server_info(uint32 servertype, struct srv_info_struct **servers, - char *domain) + const char *domain) { int count=0; int alloced=0; @@ -1096,16 +987,22 @@ static int get_server_info(uint32 servertype, for (i=0;lines[i];i++) { fstring stype; struct srv_info_struct *s; - char *ptr = lines[i]; + const char *ptr = lines[i]; BOOL ok = True; if (!*ptr) continue; if (count == alloced) { + struct srv_info_struct *ts; + alloced += 10; - (*servers) = (struct srv_info_struct *) + ts = (struct srv_info_struct *) Realloc(*servers,sizeof(**servers)*alloced); - if (!(*servers)) return(0); + if (!ts) { + DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n")); + return(0); + } + else *servers = ts; memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count)); } s = &(*servers)[count]; @@ -1115,7 +1012,7 @@ static int get_server_info(uint32 servertype, if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue; if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) { /* this allows us to cope with an old nmbd */ - pstrcpy(s->domain,global_myworkgroup); + fstrcpy(s->domain,lp_workgroup()); } if (sscanf(stype,"%X",&s->type) != 1) { @@ -1224,15 +1121,15 @@ static int fill_srv_info(struct srv_info_struct *service, switch (uLevel) { case 0: - StrnCpy(p,service->name,15); - break; + push_ascii(p,service->name, 15, STR_TERMINATE); + break; case 1: - StrnCpy(p,service->name,15); - SIVAL(p,18,service->type); - SIVAL(p,22,PTR_DIFF(p2,baseaddr)); - len += CopyAndAdvance(&p2,service->comment,&l2); - break; + push_ascii(p,service->name,15, STR_TERMINATE); + SIVAL(p,18,service->type); + SIVAL(p,22,PTR_DIFF(p2,baseaddr)); + len += CopyAndAdvance(&p2,service->comment,&l2); + break; } if (stringbuf) @@ -1309,9 +1206,9 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); if (strcmp(str1, "WrLehDz") == 0) { - StrnCpy(domain, p, sizeof(fstring)-1); + pull_ascii_fstring(domain, p); } else { - StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1); + fstrcpy(domain, lp_workgroup()); } if (lp_browse_list()) @@ -1320,7 +1217,8 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param data_len = fixed_len = string_len = 0; missed = 0; - qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); + if (total > 0) + qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); { char *lastname=NULL; @@ -1375,7 +1273,7 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param SSVAL(*rparam,4,counted); SSVAL(*rparam,6,counted+missed); - if (servers) free(servers); + SAFE_FREE(servers); DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", domain,uLevel,counted,counted+missed)); @@ -1483,15 +1381,15 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel, } if (!baseaddr) baseaddr = p; - StrnCpy(p,lp_servicename(snum),13); + push_ascii(p,lp_servicename(snum),13, STR_TERMINATE); if (uLevel > 0) { int type; - CVAL(p,13) = 0; + SCVAL(p,13,0); type = STYPE_DISKTREE; if (lp_print_ok(snum)) type = STYPE_PRINTQ; - if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC; + if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC; SSVAL(p,14,type); /* device type */ SIVAL(p,16,PTR_DIFF(p2,baseaddr)); len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2); @@ -1609,7 +1507,7 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c *rdata = REALLOC(*rdata,*rdata_len); memset(*rdata,0,*rdata_len); - p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */ + p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ p = *rdata; f_len = fixed_len; s_len = string_len; @@ -1625,10 +1523,379 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c SSVAL(*rparam,4,counted); SSVAL(*rparam,6,total); - DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", - counted,total,uLevel, - buf_len,*rdata_len,mdrcnt)); - return(True); + DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", + counted,total,uLevel, + buf_len,*rdata_len,mdrcnt)); + return(True); +} + +/**************************************************************************** + Add a share + ****************************************************************************/ +static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data, + int mdrcnt,int mprcnt, + char **rdata,char **rparam, + int *rdata_len,int *rparam_len) +{ + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel = SVAL(p,0); + fstring sharename; + fstring comment; + pstring pathname; + char *command, *cmdname; + unsigned int offset; + int snum; + int res = ERRunsup; + + /* check it's a supported varient */ + if (!prefix_ok(str1,RAP_WShareAdd_REQ)) return False; + if (!check_share_info(uLevel,str2)) return False; + if (uLevel != 2) return False; + + pull_ascii_fstring(sharename,data); + snum = find_service(sharename); + if (snum >= 0) { /* already exists */ + res = ERRfilexists; + goto error_exit; + } + + /* only support disk share adds */ + if (SVAL(data,14)!=STYPE_DISKTREE) return False; + + offset = IVAL(data, 16); + if (offset >= mdrcnt) { + res = ERRinvalidparam; + goto error_exit; + } + pull_ascii_fstring(comment, offset? (data+offset) : ""); + + offset = IVAL(data, 26); + if (offset >= mdrcnt) { + res = ERRinvalidparam; + goto error_exit; + } + pull_ascii_pstring(pathname, offset? (data+offset) : ""); + + string_replace(sharename, '"', ' '); + string_replace(pathname, '"', ' '); + string_replace(comment, '"', ' '); + + cmdname = lp_add_share_cmd(); + + if (!cmdname || *cmdname == '\0') return False; + + asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"", + lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment); + + if (command) { + DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command )); + if ((res = smbrun(command, NULL)) != 0) { + DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res )); + SAFE_FREE(command); + res = ERRnoaccess; + goto error_exit; + } else { + SAFE_FREE(command); + message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL); + } + } else return False; + + *rparam_len = 6; + *rparam = REALLOC(*rparam,*rparam_len); + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,*rdata_len); + *rdata_len = 0; + + return True; + + error_exit: + *rparam_len = 4; + *rparam = REALLOC(*rparam,*rparam_len); + *rdata_len = 0; + SSVAL(*rparam,0,res); + SSVAL(*rparam,2,0); + return True; + +} + +/**************************************************************************** + view list of groups available + ****************************************************************************/ +static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data, + int mdrcnt,int mprcnt, + char **rdata,char **rparam, + int *rdata_len,int *rparam_len) +{ + int i; + int errflags=0; + int resume_context, cli_buf_size; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + BOOL ret; + + GROUP_MAP *group_list; + int num_entries; + + if (strcmp(str1,"WrLeh") != 0) + return False; + + /* parameters + * W-> resume context (number of users to skip) + * r -> return parameter pointer to receive buffer + * L -> length of receive buffer + * e -> return parameter number of entries + * h -> return parameter total number of users + */ + if (strcmp("B21",str2) != 0) + return False; + + /* get list of domain groups SID_DOMAIN_GRP=2 */ + become_root(); + ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False); + unbecome_root(); + + if( !ret ) { + DEBUG(3,("api_RNetGroupEnum:failed to get group list")); + return False; + } + + resume_context = SVAL(p,0); + cli_buf_size=SVAL(p+2,0); + DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size)); + + *rdata_len = cli_buf_size; + *rdata = REALLOC(*rdata,*rdata_len); + + p = *rdata; + + for(i=resume_context; imem_ctx, &num_groups, &gids, sampw) ) { + DEBUG(1,("api_NetUserGetGroups: get_domain_user_groups() failed!\n")); + goto out; + } + + /* convert to names (we don't support universal groups so the domain + can only be ours) */ + + sid_copy( &dom_sid, get_global_sam_sid() ); + for (i=0; i resume context (number of users to skip) + * r -> return parameter pointer to receive buffer + * L -> length of receive buffer + * e -> return parameter number of entries + * h -> return parameter total number of users + */ + + resume_context = SVAL(p,0); + cli_buf_size=SVAL(p+2,0); + DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size)); + + *rparam_len = 8; + *rparam = REALLOC(*rparam,*rparam_len); + + /* check it's a supported varient */ + if (strcmp("B21",str2) != 0) + return False; + + *rdata_len = cli_buf_size; + *rdata = REALLOC(*rdata,*rdata_len); + + p = *rdata; + + /* to get user list enumerations for NetUserEnum in B21 format */ + pdb_init_sam(&pwd); + + /* Open the passgrp file - not for update. */ + become_root(); + if(!pdb_setsampwent(False)) { + DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n")); + unbecome_root(); + return False; + } + errflags=NERR_Success; + + while ( pdb_getsampwent(pwd) ) { + const char *name=pdb_get_username(pwd); + if ((name) && (*(name+strlen(name)-1)!='$')) { + count_total++; + if(count_total>=resume_context) { + if( ((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21) ) { + pstrcpy(p,name); + DEBUG(10,("api_RNetUserEnum:adding entry %d username %s\n",count_sent,p)); + p += 21; + count_sent++; + } else { + /* set overflow error */ + DEBUG(10,("api_RNetUserEnum:overflow on entry %d username %s\n",count_sent,name)); + errflags=234; + break; + } + } + } + } ; + + pdb_endsampwent(); + unbecome_root(); + + pdb_free_sam(&pwd); + + *rdata_len = PTR_DIFF(p,*rdata); + + SSVAL(*rparam,0,errflags); + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,count_sent); /* is this right?? */ + SSVAL(*rparam,6,count_total); /* is this right?? */ + + return True; } @@ -1666,16 +1933,16 @@ static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,ch t = LocalTime(&unixdate); SIVAL(p,4,0); /* msecs ? */ - CVAL(p,8) = t->tm_hour; - CVAL(p,9) = t->tm_min; - CVAL(p,10) = t->tm_sec; - CVAL(p,11) = 0; /* hundredths of seconds */ + SCVAL(p,8,t->tm_hour); + SCVAL(p,9,t->tm_min); + SCVAL(p,10,t->tm_sec); + SCVAL(p,11,0); /* hundredths of seconds */ SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */ SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */ - CVAL(p,16) = t->tm_mday; - CVAL(p,17) = t->tm_mon + 1; + SCVAL(p,16,t->tm_mday); + SCVAL(p,17,t->tm_mon + 1); SSVAL(p,18,1900+t->tm_year); - CVAL(p,20) = t->tm_wday; + SCVAL(p,20,t->tm_wday); } @@ -1691,112 +1958,78 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *p = skip_string(param+2,2); - fstring user; - fstring pass1,pass2; - - fstrcpy(user,p); - - p = skip_string(p,1); - - memset(pass1,'\0',sizeof(pass1)); - memset(pass2,'\0',sizeof(pass2)); - memcpy(pass1,p,16); - memcpy(pass2,p+16,16); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_badpass); - SSVAL(*rparam,2,0); /* converter word */ - - DEBUG(3,("Set password for <%s>\n",user)); + char *p = skip_string(param+2,2); + fstring user; + fstring pass1,pass2; - /* - * Pass the user through the NT -> unix user mapping - * function. - */ + pull_ascii_fstring(user,p); - (void)map_username(user); + p = skip_string(p,1); - /* - * Do any UNIX username case mangling. - */ - (void)Get_Pwnam( user, True); + memset(pass1,'\0',sizeof(pass1)); + memset(pass2,'\0',sizeof(pass2)); + memcpy(pass1,p,16); + memcpy(pass2,p+16,16); - /* - * Attempt to verify the old password against smbpasswd entries - * Win98 clients send old and new password in plaintext for this call. - */ + *rparam_len = 4; + *rparam = REALLOC(*rparam,*rparam_len); - { - fstring saved_pass2; - struct smb_passwd *smbpw = NULL; + *rdata_len = 0; - /* - * Save the new password as change_oem_password overwrites it - * with zeros. - */ + SSVAL(*rparam,0,NERR_badpass); + SSVAL(*rparam,2,0); /* converter word */ - fstrcpy(saved_pass2, pass2); + DEBUG(3,("Set password for <%s>\n",user)); - if (check_plaintext_password(user,pass1,strlen(pass1),&smbpw) && - change_oem_password(smbpw,pass2,False)) - { - SSVAL(*rparam,0,NERR_Success); + /* + * Attempt to verify the old password against smbpasswd entries + * Win98 clients send old and new password in plaintext for this call. + */ - /* - * If unix password sync was requested, attempt to change - * the /etc/passwd database also. Return failure if this cannot - * be done. - */ + { + auth_serversupplied_info *server_info = NULL; + DATA_BLOB password = data_blob(pass1, strlen(pass1)+1); - if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False)) - SSVAL(*rparam,0,NERR_badpass); - } - } + if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) { - /* - * If the above failed, attempt the plaintext password change. - * This tests against the /etc/passwd database only. - */ + become_root(); + if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False))) { + SSVAL(*rparam,0,NERR_Success); + } + unbecome_root(); - if(SVAL(*rparam,0) != NERR_Success) - { - if (password_ok(user, pass1,strlen(pass1),NULL) && - chgpasswd(user,pass1,pass2,False)) - { - SSVAL(*rparam,0,NERR_Success); - } - } + free_server_info(&server_info); + } + data_blob_clear_free(&password); + } - /* - * If the plaintext change failed, attempt - * the old encrypted method. NT will generate this - * after trying the samr method. Note that this - * method is done as a last resort as this - * password change method loses the NT password hash - * and cannot change the UNIX password as no plaintext - * is received. - */ + /* + * If the plaintext change failed, attempt + * the old encrypted method. NT will generate this + * after trying the samr method. Note that this + * method is done as a last resort as this + * password change method loses the NT password hash + * and cannot change the UNIX password as no plaintext + * is received. + */ - if(SVAL(*rparam,0) != NERR_Success) - { - struct smb_passwd *sampw = NULL; + if(SVAL(*rparam,0) != NERR_Success) { + SAM_ACCOUNT *hnd = NULL; - if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) && - change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2)) - { - SSVAL(*rparam,0,NERR_Success); - } - } + if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) { + become_root(); + if (change_lanman_password(hnd,(uchar *)pass2)) { + SSVAL(*rparam,0,NERR_Success); + } + unbecome_root(); + pdb_free_sam(&hnd); + } + } - memset((char *)pass1,'\0',sizeof(fstring)); - memset((char *)pass2,'\0',sizeof(fstring)); + memset((char *)pass1,'\0',sizeof(fstring)); + memset((char *)pass2,'\0',sizeof(fstring)); - return(True); + return(True); } /**************************************************************************** @@ -1808,53 +2041,46 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char * char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - fstring user; - char *p = param + 2; - *rparam_len = 2; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; + fstring user; + char *p = param + 2; + *rparam_len = 2; + *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_badpass); + *rdata_len = 0; - /* - * Check the parameter definition is correct. - */ - if(!strequal(param + 2, "zsT")) { - DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2)); - return False; - } - p = skip_string(p, 1); + SSVAL(*rparam,0,NERR_badpass); - if(!strequal(p, "B516B16")) { - DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p)); - return False; - } - p = skip_string(p,1); + /* + * Check the parameter definition is correct. + */ - fstrcpy(user,p); - p = skip_string(p,1); + if(!strequal(param + 2, "zsT")) { + DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2)); + return False; + } + p = skip_string(p, 1); - DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user)); + if(!strequal(p, "B516B16")) { + DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p)); + return False; + } + p = skip_string(p,1); + p += pull_ascii_fstring(user,p); - /* - * Pass the user through the NT -> unix user mapping - * function. - */ + DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user)); - (void)map_username(user); + /* + * Pass the user through the NT -> unix user mapping + * function. + */ - /* - * Do any UNIX username case mangling. - */ - (void)Get_Pwnam( user, True); + (void)map_username(user); - if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL)) - { - SSVAL(*rparam,0,NERR_Success); - } + if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))) { + SSVAL(*rparam,0,NERR_Success); + } - return(True); + return(True); } /**************************************************************************** @@ -1870,10 +2096,14 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param char *str1 = param+2; char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); - int jobid, errcode; + uint32 jobid; + int snum; + int errcode; extern struct current_user current_user; + WERROR werr = WERR_OK; - jobid = SVAL(p,0); + if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) + return False; /* check it's a supported varient */ if (!(strcsequal(str1,"W") && strcsequal(str2,""))) @@ -1883,7 +2113,7 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param *rparam = REALLOC(*rparam,*rparam_len); *rdata_len = 0; - if (!print_job_exists(jobid)) { + if (!print_job_exists(snum, jobid)) { errcode = NERR_JobNotFound; goto out; } @@ -1892,18 +2122,21 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param switch (function) { case 81: /* delete */ - if (print_job_delete(¤t_user, jobid, &errcode)) + if (print_job_delete(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; case 82: /* pause */ - if (print_job_pause(¤t_user, jobid, &errcode)) + if (print_job_pause(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; case 83: /* resume */ - if (print_job_resume(¤t_user, jobid, &errcode)) + if (print_job_resume(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; } + + if (!W_ERROR_IS_OK(werr)) + errcode = W_ERROR_V(werr); out: SSVAL(*rparam,0,errcode); @@ -1926,6 +2159,8 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param char *QueueName = skip_string(str2,1); int errcode = NERR_notsupported; int snum; + WERROR werr = WERR_OK; + extern struct current_user current_user; /* check it's a supported varient */ if (!(strcsequal(str1,"z") && strcsequal(str2,""))) @@ -1944,16 +2179,18 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param switch (function) { case 74: /* Pause queue */ - if (print_queue_pause(NULL, snum, &errcode)) errcode = NERR_Success; + if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success; break; case 75: /* Resume queue */ - if (print_queue_resume(NULL, snum, &errcode)) errcode = NERR_Success; + if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success; break; case 103: /* Purge */ - if (print_queue_purge(NULL, snum, &errcode)) errcode = NERR_Success; + if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success; break; } + if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr); + out: SSVAL(*rparam,0,errcode); SSVAL(*rparam,2,0); /* converter word */ @@ -1978,6 +2215,7 @@ static int check_printjob_info(struct pack_desc* desc, case 1: desc->format = "WB21BB16B10zWWzDDz"; break; case 2: desc->format = "WWzWWDDzz"; break; case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break; + case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break; default: return False; } if (strcmp(desc->format,id) != 0) return False; @@ -1993,12 +2231,14 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha char *str1 = param+2; char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); - int jobid; + uint32 jobid; + int snum; int uLevel = SVAL(p,2); int function = SVAL(p,4); int place, errcode; - jobid = SVAL(p,0); + if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) + return False; *rparam_len = 4; *rparam = REALLOC(*rparam,*rparam_len); @@ -2009,7 +2249,7 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha (!check_printjob_info(&desc,uLevel,str2))) return(False); - if (!print_job_exists(jobid)) { + if (!print_job_exists(snum, jobid)) { errcode=NERR_JobNotFound; goto out; } @@ -2021,14 +2261,14 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha /* change job place in the queue, data gives the new place */ place = SVAL(data,0); - if (print_job_set_place(jobid, place)) { + if (print_job_set_place(snum, jobid, place)) { errcode=NERR_Success; } break; case 0xb: /* change print job name, data gives the name */ - if (print_job_set_name(jobid, data)) { + if (print_job_set_name(snum, jobid, data)) { errcode=NERR_Success; } break; @@ -2100,8 +2340,8 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par p = *rdata; p2 = p + struct_len; if (uLevel != 20) { - StrnCpy(p,local_machine,16); - strupper(p); + srvstr_push(NULL, p,local_machine,16, + STR_ASCII|STR_UPPER|STR_TERMINATE); } p += 16; if (uLevel > 0) @@ -2111,17 +2351,17 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par pstring comment; uint32 servertype= lp_default_server_announce(); - pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH)); + push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE); - if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) { - for (i=0;i0) { + for (i=0;ihomedir ? vuser->homedir : ""); p2 = skip_string(p2,1); SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */ pstrcpy(p2,""); @@ -2510,15 +2750,13 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param SSVAL(p,42, conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ - pstrcpy(p2,lp_logon_home()); - standard_sub_conn(conn, p2); + pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : ""); p2 = skip_string(p2,1); SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ *p2++ = 0; SSVAL(p,52,0); /* flags */ SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */ - pstrcpy(p2,lp_logon_script()); - standard_sub_conn( conn, p2 ); + pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : ""); p2 = skip_string(p2,1); if (uLevel == 2) { @@ -2543,7 +2781,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param SSVALS(p,104,-1); /* num_logons */ SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */ pstrcpy(p2,"\\\\%L"); - standard_sub_conn(conn, p2); + standard_sub_conn(conn, p2,0); p2 = skip_string(p2,1); SSVAL(p,110,49); /* country_code */ SSVAL(p,112,860); /* code page */ @@ -2557,56 +2795,6 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param return(True); } -/******************************************************************* - get groups that a user is a member of - ******************************************************************/ -static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - char *p2; - int count=0; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLeh") != 0) return False; - switch( uLevel ) { - case 0: p2 = "B21"; break; - default: return False; - } - if (strcmp(p2,str2) != 0) return False; - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - - /* XXXX we need a real SAM database some day */ - pstrcpy(p,"Users"); p += 21; count++; - pstrcpy(p,"Domain Users"); p += 21; count++; - pstrcpy(p,"Guests"); p += 21; count++; - pstrcpy(p,"Domain Guests"); p += 21; count++; - - *rdata_len = PTR_DIFF(p,*rdata); - - SSVAL(*rparam,4,count); /* is this right?? */ - SSVAL(*rparam,6,count); /* is this right?? */ - - return(True); -} - - static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data, int mdrcnt,int mprcnt, char **rdata,char **rparam, @@ -2618,6 +2806,12 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param int uLevel; struct pack_desc desc; char* name; + /* With share level security vuid will always be zero. + Don't depend on vuser being non-null !!. JRA */ + user_struct *vuser = get_valid_user_struct(vuid); + if(vuser != NULL) + DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, + vuser->user.unix_name)); uLevel = SVAL(p,0); name = p + 2; @@ -2656,20 +2850,12 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param fstring mypath; fstrcpy(mypath,"\\\\"); fstrcat(mypath,local_machine); - strupper(mypath); + strupper_m(mypath); PACKS(&desc,"z",mypath); /* computer */ } - PACKS(&desc,"z",global_myworkgroup);/* domain */ + PACKS(&desc,"z",lp_workgroup());/* domain */ -/* JHT - By calling lp_logon_script() and standard_sub() we have */ -/* made sure all macros are fully substituted and available */ - { - pstring logon_script; - pstrcpy(logon_script,lp_logon_script()); - standard_sub_conn( conn, logon_script ); - PACKS(&desc,"z", logon_script); /* script path */ - } -/* End of JHT mods */ + PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */ PACKI(&desc,"D",0x00000000); /* reserved */ } @@ -2729,10 +2915,11 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para int count; int i; int snum; - int job; + uint32 jobid; struct pack_desc desc; print_queue_struct *queue=NULL; print_status_struct status; + char *tmpdata=NULL; uLevel = SVAL(p,2); @@ -2745,18 +2932,28 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para if (strcmp(str1,"WWrLh") != 0) return False; if (!check_printjob_info(&desc,uLevel,str2)) return False; - job = SVAL(p,0); - snum = print_job_snum(job); + if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) + return False; if (snum < 0 || !VALID_SNUM(snum)) return(False); count = print_queue_status(snum,&queue,&status); for (i = 0; i < count; i++) { - if (queue[i].job == job) break; + if (queue[i].job == jobid) break; + } + + if (mdrcnt > 0) { + *rdata = REALLOC(*rdata,mdrcnt); + desc.base = *rdata; + desc.buflen = mdrcnt; + } else { + /* + * Don't return data but need to get correct length + * init_package will return wrong size if buflen=0 + */ + desc.buflen = getlen(desc.format); + desc.base = tmpdata = (char *)malloc ( desc.buflen ); } - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; if (init_package(&desc,1,0)) { if (i < count) { @@ -2775,7 +2972,8 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para SSVAL(*rparam,2,0); SSVAL(*rparam,4,desc.neededlen); - if (queue) free(queue); + SAFE_FREE(queue); + SAFE_FREE(tmpdata); DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); return(True); @@ -2806,7 +3004,7 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); - /* check it's a supported varient */ + /* check it's a supported variant */ if (strcmp(str1,"zWrLeh") != 0) return False; if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */ if (!check_printjob_info(&desc,uLevel,str2)) return False; @@ -2844,7 +3042,7 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa SSVAL(*rparam,4,succnt); SSVAL(*rparam,6,count); - if (queue) free(queue); + SAFE_FREE(queue); DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); return(True); @@ -2871,7 +3069,7 @@ static void fill_printdest_info(connection_struct *conn, int snum, int uLevel, char buf[100]; strncpy(buf,SERVICE(snum),sizeof(buf)-1); buf[sizeof(buf)-1] = 0; - strupper(buf); + strupper_m(buf); if (uLevel <= 1) { PACKS(desc,"B9",buf); /* szName */ if (uLevel == 1) { @@ -2910,6 +3108,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par int uLevel; struct pack_desc desc; int snum; + char *tmpdata=NULL; memset((char *)&desc,'\0',sizeof(desc)); @@ -2937,9 +3136,18 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par desc.neededlen = 0; } else { - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; + if (mdrcnt > 0) { + *rdata = REALLOC(*rdata,mdrcnt); + desc.base = *rdata; + desc.buflen = mdrcnt; + } else { + /* + * Don't return data but need to get correct length + * init_package will return wrong size if buflen=0 + */ + desc.buflen = getlen(desc.format); + desc.base = tmpdata = (char *)malloc ( desc.buflen ); + } if (init_package(&desc,1,0)) { fill_printdest_info(conn,snum,uLevel,&desc); } @@ -2953,6 +3161,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par SSVAL(*rparam,4,desc.neededlen); DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); + SAFE_FREE(tmpdata); return(True); } @@ -3148,6 +3357,72 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param, return(True); } + +/**************************************************************************** + List open sessions + ****************************************************************************/ +static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data, + int mdrcnt,int mprcnt, + char **rdata,char **rparam, + int *rdata_len,int *rparam_len) + +{ + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + int uLevel; + struct pack_desc desc; + struct sessionid *session_list; + int i, num_sessions; + + memset((char *)&desc,'\0',sizeof(desc)); + + uLevel = SVAL(p,0); + + DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel)); + DEBUG(7,("RNetSessionEnum req string=%s\n",str1)); + DEBUG(7,("RNetSessionEnum ret string=%s\n",str2)); + + /* check it's a supported varient */ + if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False; + if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False; + + num_sessions = list_sessions(&session_list); + + if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); + memset((char *)&desc,'\0',sizeof(desc)); + desc.base = *rdata; + desc.buflen = mdrcnt; + desc.format = str2; + if (!init_package(&desc,num_sessions,0)) { + return False; + } + + for(i=0; iguest) + return ERROR_NT(NT_STATUS_ACCESS_DENIED); + } + rdata = (char *)malloc(1024); if (rdata) memset(rdata,'\0',1024); @@ -3300,13 +3592,8 @@ int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char * send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False); - if (rdata ) - free(rdata); - if (rparam) - free(rparam); + SAFE_FREE(rdata); + SAFE_FREE(rparam); return -1; } - - -#undef OLD_NTDOMAIN