2 Unix SMB/Netbios implementation.
4 Inter-process communication and named pipe handling
5 Copyright (C) Andrew Tridgell 1992-1998
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
36 extern int DEBUGLEVEL;
38 extern fstring local_machine;
39 extern pstring global_myname;
40 extern fstring global_myworkgroup;
42 #define NERR_Success 0
43 #define NERR_badpass 86
44 #define NERR_notsupported 50
46 #define NERR_BASE (2100)
47 #define NERR_BufTooSmall (NERR_BASE+23)
48 #define NERR_JobNotFound (NERR_BASE+51)
49 #define NERR_DestNotFound (NERR_BASE+52)
51 #define ACCESS_READ 0x01
52 #define ACCESS_WRITE 0x02
53 #define ACCESS_CREATE 0x04
55 #define SHPWLEN 8 /* share password length */
57 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
58 int mdrcnt,int mprcnt,
59 char **rdata,char **rparam,
60 int *rdata_len,int *rparam_len);
61 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
62 int mdrcnt,int mprcnt,
63 char **rdata,char **rparam,
64 int *rdata_len,int *rparam_len);
67 static int CopyExpanded(connection_struct *conn,
68 int snum, char** dst, char* src, int* n)
73 if (!src || !dst || !n || !(*dst)) return(0);
75 StrnCpy(buf,src,sizeof(buf)/2);
76 pstring_sub(buf,"%S",lp_servicename(snum));
77 standard_sub_conn(conn,buf);
78 l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
84 static int CopyAndAdvance(char** dst, char* src, int* n)
87 if (!src || !dst || !n || !(*dst)) return(0);
88 l = push_ascii(*dst,src,*n-1, STR_TERMINATE);
94 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
98 StrnCpy(buf,s,sizeof(buf)/2);
99 pstring_sub(buf,"%S",lp_servicename(snum));
100 standard_sub_conn(conn,buf);
101 return strlen(buf) + 1;
104 static char* Expand(connection_struct *conn, int snum, char* s)
107 if (!s) return(NULL);
108 StrnCpy(buf,s,sizeof(buf)/2);
109 pstring_sub(buf,"%S",lp_servicename(snum));
110 standard_sub_conn(conn,buf);
114 /*******************************************************************
115 check a API string for validity when we only need to check the prefix
116 ******************************************************************/
117 static BOOL prefix_ok(char *str,char *prefix)
119 return(strncmp(str,prefix,strlen(prefix)) == 0);
123 char* format; /* formatstring for structure */
124 char* subformat; /* subformat for structure */
125 char* base; /* baseaddress of buffer */
126 int buflen; /* remaining size for fixed part; on init: length of base */
127 int subcount; /* count of substructures */
128 char* structbuf; /* pointer into buffer for remaining fixed part */
129 int stringlen; /* remaining size for variable part */
130 char* stringbuf; /* pointer into buffer for remaining variable part */
131 int neededlen; /* total needed size */
132 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
133 char* curpos; /* current position; pointer into format or subformat */
137 static int get_counter(char** p)
140 if (!p || !(*p)) return(1);
141 if (!isdigit((int)**p)) return 1;
145 n = 10 * n + (i - '0');
152 static int getlen(char* p)
158 case 'W': /* word (2 byte) */
161 case 'K': /* status word? (2 byte) */
164 case 'N': /* count of substructures (word) at end */
167 case 'D': /* double word (4 byte) */
168 case 'z': /* offset to zero terminated string (4 byte) */
169 case 'l': /* offset to user data (4 byte) */
172 case 'b': /* offset to data (with counter) (4 byte) */
176 case 'B': /* byte (with optional counter) */
177 n += get_counter(&p);
184 static BOOL init_package(struct pack_desc* p, int count, int subcount)
189 if (!p->format || !p->base) return(False);
191 i = count * getlen(p->format);
192 if (p->subformat) i += subcount * getlen(p->subformat);
193 p->structbuf = p->base;
197 p->curpos = p->format;
203 * This is the old error code we used. Aparently
204 * WinNT/2k systems return ERRbuftoosmall (2123) and
205 * OS/2 needs this. I'm leaving this here so we can revert
208 p->errcode = ERRmoredata;
210 p->errcode = ERRbuftoosmall;
214 p->errcode = NERR_Success;
217 p->stringbuf = p->base + i;
219 return(p->errcode == NERR_Success);
222 static int package(struct pack_desc* p, ...)
225 int needed=0, stringneeded;
227 int is_string=0, stringused;
234 p->curpos = p->format;
236 p->curpos = p->subformat;
241 str = va_arg(args,char*);
242 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
251 switch( *p->curpos++ ) {
252 case 'W': /* word (2 byte) */
254 temp = va_arg(args,int);
255 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
257 case 'K': /* status word? (2 byte) */
259 temp = va_arg(args,int);
260 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
262 case 'N': /* count of substructures (word) at end */
264 p->subcount = va_arg(args,int);
265 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
267 case 'D': /* double word (4 byte) */
269 temp = va_arg(args,int);
270 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
272 case 'B': /* byte (with optional counter) */
273 needed = get_counter(&p->curpos);
275 char *s = va_arg(args,char*);
276 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
279 case 'z': /* offset to zero terminated string (4 byte) */
280 str = va_arg(args,char*);
281 stringneeded = (str ? strlen(str)+1 : 0);
284 case 'l': /* offset to user data (4 byte) */
285 str = va_arg(args,char*);
286 stringneeded = va_arg(args,int);
289 case 'b': /* offset to data (with counter) (4 byte) */
290 str = va_arg(args,char*);
291 stringneeded = get_counter(&p->curpos);
296 if (stringneeded >= 0) {
298 if (p->buflen >= needed) {
299 stringused = stringneeded;
300 if (stringused > p->stringlen) {
301 stringused = (is_string ? p->stringlen : 0);
302 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
305 SIVAL(p->structbuf,0,0);
307 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
308 memcpy(p->stringbuf,str?str:"",stringused);
309 if (is_string) p->stringbuf[stringused-1] = '\0';
310 p->stringbuf += stringused;
311 p->stringlen -= stringused;
312 p->usedlen += stringused;
315 p->neededlen += stringneeded;
317 p->neededlen += needed;
318 if (p->buflen >= needed) {
319 p->structbuf += needed;
321 p->usedlen += needed;
324 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
330 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
331 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
333 #define PACK(desc,t,v) package(desc,v)
334 #define PACKl(desc,t,v,l) package(desc,v,l)
337 static void PACKI(struct pack_desc* desc,char *t,int v)
342 static void PACKS(struct pack_desc* desc,char *t,char *v)
348 /****************************************************************************
350 ****************************************************************************/
351 static void PackDriverData(struct pack_desc* desc)
353 char drivdata[4+4+32];
354 SIVAL(drivdata,0,sizeof drivdata); /* cb */
355 SIVAL(drivdata,4,1000); /* lVersion */
356 memset(drivdata+8,0,32); /* szDeviceName */
357 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
358 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
361 static int check_printq_info(struct pack_desc* desc,
362 int uLevel, char *id1, char *id2)
364 desc->subformat = NULL;
367 desc->format = "B13";
370 desc->format = "B13BWWWzzzzzWW";
373 desc->format = "B13BWWWzzzzzWN";
374 desc->subformat = "WB21BB16B10zWWzDDz";
377 desc->format = "zWWWWzzzzWWzzl";
380 desc->format = "zWWWWzzzzWNzzl";
381 desc->subformat = "WWzWWDDzz";
390 desc->format = "WzzzzzzzzN";
391 desc->subformat = "z";
393 default: return False;
395 if (strcmp(desc->format,id1) != 0) return False;
396 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
401 #define RAP_JOB_STATUS_QUEUED 0
402 #define RAP_JOB_STATUS_PAUSED 1
403 #define RAP_JOB_STATUS_SPOOLING 2
404 #define RAP_JOB_STATUS_PRINTING 3
405 #define RAP_JOB_STATUS_PRINTED 4
407 #define RAP_QUEUE_STATUS_PAUSED 1
408 #define RAP_QUEUE_STATUS_ERROR 2
410 /* turn a print job status into a on the wire status
412 static int printj_status(int v)
416 return RAP_JOB_STATUS_QUEUED;
418 return RAP_JOB_STATUS_PAUSED;
420 return RAP_JOB_STATUS_SPOOLING;
422 return RAP_JOB_STATUS_PRINTING;
427 /* turn a print queue status into a on the wire status
429 static int printq_status(int v)
435 return RAP_QUEUE_STATUS_PAUSED;
437 return RAP_QUEUE_STATUS_ERROR;
440 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
441 struct pack_desc* desc,
442 print_queue_struct* queue, int n)
444 time_t t = queue->time;
446 /* the client expects localtime */
449 PACKI(desc,"W",queue->job); /* uJobId */
451 PACKS(desc,"B21",queue->user); /* szUserName */
452 PACKS(desc,"B",""); /* pad */
453 PACKS(desc,"B16",""); /* szNotifyName */
454 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
455 PACKS(desc,"z",""); /* pszParms */
456 PACKI(desc,"W",n+1); /* uPosition */
457 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
458 PACKS(desc,"z",""); /* pszStatus */
459 PACKI(desc,"D",t); /* ulSubmitted */
460 PACKI(desc,"D",queue->size); /* ulSize */
461 PACKS(desc,"z",queue->file); /* pszComment */
463 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
464 PACKI(desc,"W",queue->priority); /* uPriority */
465 PACKS(desc,"z",queue->user); /* pszUserName */
466 PACKI(desc,"W",n+1); /* uPosition */
467 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
468 PACKI(desc,"D",t); /* ulSubmitted */
469 PACKI(desc,"D",queue->size); /* ulSize */
470 PACKS(desc,"z","Samba"); /* pszComment */
471 PACKS(desc,"z",queue->file); /* pszDocument */
473 PACKS(desc,"z",""); /* pszNotifyName */
474 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
475 PACKS(desc,"z",""); /* pszParms */
476 PACKS(desc,"z",""); /* pszStatus */
477 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
478 PACKS(desc,"z","lpd"); /* pszQProcName */
479 PACKS(desc,"z",""); /* pszQProcParms */
480 PACKS(desc,"z","NULL"); /* pszDriverName */
481 PackDriverData(desc); /* pDriverData */
482 PACKS(desc,"z",""); /* pszPrinterName */
483 } else if (uLevel == 4) { /* OS2 */
484 PACKS(desc,"z",""); /* pszSpoolFileName */
485 PACKS(desc,"z",""); /* pszPortName */
486 PACKS(desc,"z",""); /* pszStatus */
487 PACKI(desc,"D",0); /* ulPagesSpooled */
488 PACKI(desc,"D",0); /* ulPagesSent */
489 PACKI(desc,"D",0); /* ulPagesPrinted */
490 PACKI(desc,"D",0); /* ulTimePrinted */
491 PACKI(desc,"D",0); /* ulExtendJobStatus */
492 PACKI(desc,"D",0); /* ulStartPage */
493 PACKI(desc,"D",0); /* ulEndPage */
498 /********************************************************************
499 Return a driver name given an snum.
500 Looks in a tdb first. Returns True if from tdb, False otherwise.
501 ********************************************************************/
503 static BOOL get_driver_name(int snum, pstring drivername)
505 NT_PRINTER_INFO_LEVEL *info = NULL;
508 get_a_printer (&info, 2, lp_servicename(snum));
510 pstrcpy( drivername, info->info_2->drivername);
512 free_a_printer(&info, 2);
514 pstrcpy( drivername, lp_printerdriver(snum));
520 /********************************************************************
521 Respond to the DosPrintQInfo command with a level of 52
522 This is used to get printer driver information for Win9x clients
523 ********************************************************************/
524 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
525 struct pack_desc* desc,
526 int count, print_queue_struct* queue,
527 print_status_struct* status)
531 pstring tok,driver,datafile,langmon,helpfile,datatype;
540 * Check in the tdb *first* before checking the legacy
541 * files. This allows an NT upload to take precedence over
542 * the existing fileset. JRA.
544 * we need to lookup the driver name prior to making the call
545 * to get_a_printer_driver_9x_compatible() and not rely on the
546 * 'print driver' parameter --jerry
550 if ((get_driver_name(snum,drivername)) &&
551 ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
555 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
559 /* didn't find driver in tdb */
561 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
562 snum, drivername, lp_driverfile(snum)));
564 lines = file_lines_load(lp_driverfile(snum),NULL);
567 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
569 desc->errcode=NERR_notsupported;
573 /* lookup the long printer driver name in the file description */
574 for (i=0;lines[i] && !ok;i++)
577 if (next_token(&p,tok,":",sizeof(tok)) &&
578 (strlen(drivername) == strlen(tok)) &&
579 (!strncmp(tok,drivername,strlen(drivername))))
588 /* driver file name */
589 if (!next_token(&p,driver,":",sizeof(driver)))
593 if (!next_token(&p,datafile,":",sizeof(datafile)))
597 * for the next tokens - which may be empty - I have
598 * to check for empty tokens first because the
599 * next_token function will skip all empty token
608 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
611 /* language monitor */
617 else if (!next_token(&p,langmon,":",sizeof(langmon)))
620 /* default data type */
621 if (!next_token(&p,datatype,":",sizeof(datatype)))
624 PACKI(desc,"W",0x0400); /* don't know */
625 PACKS(desc,"z",drivername); /* long printer name */
626 PACKS(desc,"z",driver); /* Driverfile Name */
627 PACKS(desc,"z",datafile); /* Datafile name */
628 PACKS(desc,"z",langmon); /* language monitor */
631 fstrcpy(location, "\\\\");
632 fstrcat(location, global_myname);
633 fstrcat(location, "\\print$\\WIN40\\0");
634 PACKS(desc,"z",location); /* share to retrieve files */
638 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
640 PACKS(desc,"z",datatype); /* default data type */
641 PACKS(desc,"z",helpfile); /* helpfile name */
642 PACKS(desc,"z",driver); /* driver name */
644 DEBUG(3,("printerdriver:%s:\n",drivername));
645 DEBUG(3,("Driver:%s:\n",driver));
646 DEBUG(3,("Data File:%s:\n",datafile));
647 DEBUG(3,("Language Monitor:%s:\n",langmon));
649 DEBUG(3,("lp_driverlocation:%s:\n",location));
651 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
652 DEBUG(3,("Data Type:%s:\n",datatype));
653 DEBUG(3,("Help File:%s:\n",helpfile));
654 PACKI(desc,"N",count); /* number of files to copy */
656 for (i=0;i<count;i++)
658 /* no need to check return value here
659 * - it was already tested in
660 * get_printerdrivernumber */
661 next_token(&p,tok,",",sizeof(tok));
662 PACKS(desc,"z",tok); /* driver files to copy */
663 DEBUG(3,("file:%s:\n",tok));
666 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
667 SERVICE(snum),count));
669 desc->errcode=NERR_Success;
675 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
676 desc->errcode=NERR_notsupported;
679 file_lines_free(lines);
683 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
684 struct pack_desc* desc,
685 int count, print_queue_struct* queue,
686 print_status_struct* status)
691 PACKS(desc,"B13",SERVICE(snum));
696 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
699 PACKI(desc,"K",printq_status(status->status));
703 if (uLevel == 1 || uLevel == 2) {
704 PACKS(desc,"B",""); /* alignment */
705 PACKI(desc,"W",5); /* priority */
706 PACKI(desc,"W",0); /* start time */
707 PACKI(desc,"W",0); /* until time */
708 PACKS(desc,"z",""); /* pSepFile */
709 PACKS(desc,"z","lpd"); /* pPrProc */
710 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
711 PACKS(desc,"z",""); /* pParms */
713 PACKS(desc,"z","UNKNOWN PRINTER");
714 PACKI(desc,"W",LPSTAT_ERROR);
716 else if (!status || !status->message[0]) {
717 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
718 PACKI(desc,"W",LPSTAT_OK); /* status */
720 PACKS(desc,"z",status->message);
721 PACKI(desc,"W",printq_status(status->status)); /* status */
723 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
726 if (uLevel == 3 || uLevel == 4) {
729 PACKI(desc,"W",5); /* uPriority */
730 PACKI(desc,"W",0); /* uStarttime */
731 PACKI(desc,"W",0); /* uUntiltime */
732 PACKI(desc,"W",5); /* pad1 */
733 PACKS(desc,"z",""); /* pszSepFile */
734 PACKS(desc,"z","WinPrint"); /* pszPrProc */
735 PACKS(desc,"z",NULL); /* pszParms */
736 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
737 /* "don't ask" that it's done this way to fix corrupted
738 Win9X/ME printer comments. */
740 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
742 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
744 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
745 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
746 get_driver_name(snum,drivername);
747 PACKS(desc,"z",drivername); /* pszDriverName */
748 PackDriverData(desc); /* pDriverData */
751 if (uLevel == 2 || uLevel == 4) {
753 for (i=0;i<count;i++)
754 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
758 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
762 /* This function returns the number of files for a given driver */
763 static int get_printerdrivernumber(int snum)
774 * Check in the tdb *first* before checking the legacy
775 * files. This allows an NT upload to take precedence over
776 * the existing fileset. JRA.
778 * we need to lookup the driver name prior to making the call
779 * to get_a_printer_driver_9x_compatible() and not rely on the
780 * 'print driver' parameter --jerry
783 if ((get_driver_name(snum,drivername)) &&
784 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
787 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
791 /* didn't find driver in tdb */
793 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
794 snum, drivername, lp_driverfile(snum)));
796 lines = file_lines_load(lp_driverfile(snum), NULL);
799 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
803 /* lookup the long printer driver name in the file description */
804 for (i=0;lines[i] && !ok;i++)
807 if (next_token(&p,tok,":",sizeof(tok)) &&
808 (strlen(drivername) == strlen(tok)) &&
809 (!strncmp(tok,drivername,strlen(drivername))))
821 if (*p++ == ':') i--;
824 DEBUG(3,("Can't determine number of printer driver files\n"));
828 /* count the number of files */
829 while (next_token(&p,tok,",",sizeof(tok)))
837 file_lines_free(lines);
842 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
843 uint16 vuid, char *param,char *data,
844 int mdrcnt,int mprcnt,
845 char **rdata,char **rparam,
846 int *rdata_len,int *rparam_len)
848 char *str1 = param+2;
849 char *str2 = skip_string(str1,1);
850 char *p = skip_string(str2,1);
856 struct pack_desc desc;
857 print_queue_struct *queue=NULL;
858 print_status_struct status;
861 memset((char *)&status,'\0',sizeof(status));
862 memset((char *)&desc,'\0',sizeof(desc));
864 p = skip_string(p,1);
868 /* remove any trailing username */
869 if ((p = strchr_m(QueueName,'%'))) *p = 0;
871 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
873 /* check it's a supported varient */
874 if (!prefix_ok(str1,"zWrLh")) return False;
875 if (!check_printq_info(&desc,uLevel,str2,str3)) {
877 * Patch from Scott Moomaw <scott@bridgewater.edu>
878 * to return the 'invalid info level' error if an
879 * unknown level was requested.
883 *rparam = REALLOC(*rparam,*rparam_len);
884 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
890 snum = lp_servicenumber(QueueName);
891 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
892 int pnum = lp_servicenumber(PRINTERS_NAME);
894 lp_add_printer(QueueName,pnum);
895 snum = lp_servicenumber(QueueName);
899 if (snum < 0 || !VALID_SNUM(snum)) return(False);
902 count = get_printerdrivernumber(snum);
903 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
905 count = print_queue_status(snum, &queue,&status);
909 *rdata = REALLOC(*rdata,mdrcnt);
911 desc.buflen = mdrcnt;
914 * Don't return data but need to get correct length
915 * init_package will return wrong size if buflen=0
917 desc.buflen = getlen(desc.format);
918 desc.base = tmpdata = (char *) malloc (desc.buflen);
921 if (init_package(&desc,1,count)) {
922 desc.subcount = count;
923 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
924 } else if(uLevel == 0) {
927 * This is a *disgusting* hack.
928 * This is *so* bad that even I'm embarrassed (and I
929 * have no shame). Here's the deal :
930 * Until we get the correct SPOOLSS code into smbd
931 * then when we're running with NT SMB support then
932 * NT makes this call with a level of zero, and then
933 * immediately follows it with an open request to
934 * the \\SRVSVC pipe. If we allow that open to
935 * succeed then NT barfs when it cannot open the
936 * \\SPOOLSS pipe immediately after and continually
937 * whines saying "Printer name is invalid" forever
938 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
939 * to fail, then NT downgrades to using the downlevel code
940 * and everything works as well as before. I hate
941 * myself for adding this code.... JRA.
944 fail_next_srvsvc_open();
948 *rdata_len = desc.usedlen;
951 *rparam = REALLOC(*rparam,*rparam_len);
952 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,4,desc.neededlen);
956 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
958 if (queue) free(queue);
959 if (tmpdata) free (tmpdata);
964 /****************************************************************************
965 View list of all print jobs on all queues.
966 ****************************************************************************/
968 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
969 int mdrcnt, int mprcnt,
970 char **rdata, char** rparam,
971 int *rdata_len, int *rparam_len)
973 char *param_format = param+2;
974 char *output_format1 = skip_string(param_format,1);
975 char *p = skip_string(output_format1,1);
976 int uLevel = SVAL(p,0);
977 char *output_format2 = p + 4;
978 int services = lp_numservices();
980 struct pack_desc desc;
981 print_queue_struct **queue = NULL;
982 print_status_struct *status = NULL;
983 int* subcntarr = NULL;
984 int queuecnt, subcnt=0, succnt=0;
986 memset((char *)&desc,'\0',sizeof(desc));
988 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
990 if (!prefix_ok(param_format,"WrLeh")) return False;
991 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
993 * Patch from Scott Moomaw <scott@bridgewater.edu>
994 * to return the 'invalid info level' error if an
995 * unknown level was requested.
999 *rparam = REALLOC(*rparam,*rparam_len);
1000 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
1007 for (i = 0; i < services; i++)
1008 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1011 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1012 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1015 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1016 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1017 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1020 memset(status,0,queuecnt*sizeof(print_status_struct));
1021 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1022 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1027 for (i = 0; i < services; i++)
1028 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1029 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1030 subcnt += subcntarr[n];
1034 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1036 desc.buflen = mdrcnt;
1038 if (init_package(&desc,queuecnt,subcnt)) {
1041 for (i = 0; i < services; i++)
1042 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1043 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1045 if (desc.errcode == NERR_Success) succnt = n;
1049 if (subcntarr) free(subcntarr);
1051 *rdata_len = desc.usedlen;
1053 *rparam = REALLOC(*rparam,*rparam_len);
1054 SSVALS(*rparam,0,desc.errcode);
1056 SSVAL(*rparam,4,succnt);
1057 SSVAL(*rparam,6,queuecnt);
1059 for (i = 0; i < queuecnt; i++) {
1060 if (queue && queue[i]) free(queue[i]);
1063 if (queue) free(queue);
1064 if (status) free(status);
1069 /****************************************************************************
1070 get info level for a server list query
1071 ****************************************************************************/
1072 static BOOL check_server_info(int uLevel, char* id)
1076 if (strcmp(id,"B16") != 0) return False;
1079 if (strcmp(id,"B16BBDz") != 0) return False;
1087 struct srv_info_struct
1097 /*******************************************************************
1098 get server info lists from the files saved by nmbd. Return the
1100 ******************************************************************/
1101 static int get_server_info(uint32 servertype,
1102 struct srv_info_struct **servers,
1108 BOOL local_list_only;
1111 lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1113 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1117 /* request for everything is code for request all servers */
1118 if (servertype == SV_TYPE_ALL)
1119 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1121 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1123 DEBUG(4,("Servertype search: %8x\n",servertype));
1125 for (i=0;lines[i];i++) {
1127 struct srv_info_struct *s;
1128 char *ptr = lines[i];
1131 if (!*ptr) continue;
1133 if (count == alloced) {
1135 (*servers) = (struct srv_info_struct *)
1136 Realloc(*servers,sizeof(**servers)*alloced);
1137 if (!(*servers)) return(0);
1138 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1140 s = &(*servers)[count];
1142 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1143 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1144 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1145 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1146 /* this allows us to cope with an old nmbd */
1147 pstrcpy(s->domain,global_myworkgroup);
1150 if (sscanf(stype,"%X",&s->type) != 1) {
1151 DEBUG(4,("r:host file "));
1155 /* Filter the servers/domains we return based on what was asked for. */
1157 /* Check to see if we are being asked for a local list only. */
1158 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1159 DEBUG(4,("r: local list only"));
1163 /* doesn't match up: don't want it */
1164 if (!(servertype & s->type)) {
1165 DEBUG(4,("r:serv type "));
1169 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1170 (s->type & SV_TYPE_DOMAIN_ENUM))
1172 DEBUG(4,("s: dom mismatch "));
1176 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1181 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1182 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1186 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1187 s->name, s->type, s->comment, s->domain));
1189 s->server_added = True;
1194 DEBUG(4,("%20s %8x %25s %15s\n",
1195 s->name, s->type, s->comment, s->domain));
1199 file_lines_free(lines);
1204 /*******************************************************************
1205 fill in a server info structure
1206 ******************************************************************/
1207 static int fill_srv_info(struct srv_info_struct *service,
1208 int uLevel, char **buf, int *buflen,
1209 char **stringbuf, int *stringspace, char *baseaddr)
1218 case 0: struct_len = 16; break;
1219 case 1: struct_len = 26; break;
1229 len = strlen(service->comment)+1;
1233 if (buflen) *buflen = struct_len;
1234 if (stringspace) *stringspace = len;
1235 return struct_len + len;
1240 if (*buflen < struct_len) return -1;
1248 p2 = p + struct_len;
1249 l2 = *buflen - struct_len;
1251 if (!baseaddr) baseaddr = p;
1256 push_ascii(p,service->name, 15, STR_TERMINATE);
1260 push_ascii(p,service->name,15, STR_TERMINATE);
1261 SIVAL(p,18,service->type);
1262 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1263 len += CopyAndAdvance(&p2,service->comment,&l2);
1269 *buf = p + struct_len;
1270 *buflen -= struct_len;
1283 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1285 return(strcmp(s1->name,s2->name));
1288 /****************************************************************************
1289 view list of servers available (or possibly domains). The info is
1290 extracted from lists saved by nmbd on the local host
1291 ****************************************************************************/
1292 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1293 int mdrcnt, int mprcnt, char **rdata,
1294 char **rparam, int *rdata_len, int *rparam_len)
1296 char *str1 = param+2;
1297 char *str2 = skip_string(str1,1);
1298 char *p = skip_string(str2,1);
1299 int uLevel = SVAL(p,0);
1300 int buf_len = SVAL(p,2);
1301 uint32 servertype = IVAL(p,4);
1303 int data_len, fixed_len, string_len;
1304 int f_len = 0, s_len = 0;
1305 struct srv_info_struct *servers=NULL;
1306 int counted=0,total=0;
1309 BOOL domain_request;
1312 /* If someone sets all the bits they don't really mean to set
1313 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1316 if (servertype == SV_TYPE_ALL)
1317 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1319 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1320 any other bit (they may just set this bit on it's own) they
1321 want all the locally seen servers. However this bit can be
1322 set on its own so set the requested servers to be
1323 ALL - DOMAIN_ENUM. */
1325 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1326 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1328 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1329 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1333 if (!prefix_ok(str1,"WrLehD")) return False;
1334 if (!check_server_info(uLevel,str2)) return False;
1336 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1337 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1338 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1340 if (strcmp(str1, "WrLehDz") == 0) {
1341 pull_ascii_fstring(domain, p);
1343 fstrcpy(domain, global_myworkgroup);
1346 if (lp_browse_list())
1347 total = get_server_info(servertype,&servers,domain);
1349 data_len = fixed_len = string_len = 0;
1353 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1356 char *lastname=NULL;
1358 for (i=0;i<total;i++)
1360 struct srv_info_struct *s = &servers[i];
1361 if (lastname && strequal(lastname,s->name)) continue;
1363 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1364 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1365 s->name, s->type, s->comment, s->domain));
1367 if (data_len <= buf_len) {
1370 string_len += s_len;
1377 *rdata_len = fixed_len + string_len;
1378 *rdata = REALLOC(*rdata,*rdata_len);
1379 memset(*rdata,'\0',*rdata_len);
1381 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1387 char *lastname=NULL;
1388 int count2 = counted;
1389 for (i = 0; i < total && count2;i++)
1391 struct srv_info_struct *s = &servers[i];
1392 if (lastname && strequal(lastname,s->name)) continue;
1394 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1395 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1396 s->name, s->type, s->comment, s->domain));
1402 *rparam = REALLOC(*rparam,*rparam_len);
1403 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1405 SSVAL(*rparam,4,counted);
1406 SSVAL(*rparam,6,counted+missed);
1408 if (servers) free(servers);
1410 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1411 domain,uLevel,counted,counted+missed));
1416 /****************************************************************************
1417 command 0x34 - suspected of being a "Lookup Names" stub api
1418 ****************************************************************************/
1419 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1420 int mdrcnt, int mprcnt, char **rdata,
1421 char **rparam, int *rdata_len, int *rparam_len)
1423 char *str1 = param+2;
1424 char *str2 = skip_string(str1,1);
1425 char *p = skip_string(str2,1);
1426 int uLevel = SVAL(p,0);
1427 int buf_len = SVAL(p,2);
1431 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1432 str1, str2, p, uLevel, buf_len));
1434 if (!prefix_ok(str1,"zWrLeh")) return False;
1439 *rparam = REALLOC(*rparam,*rparam_len);
1441 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1443 SSVAL(*rparam,4,counted);
1444 SSVAL(*rparam,6,counted+missed);
1449 /****************************************************************************
1450 get info about a share
1451 ****************************************************************************/
1452 static BOOL check_share_info(int uLevel, char* id)
1456 if (strcmp(id,"B13") != 0) return False;
1459 if (strcmp(id,"B13BWz") != 0) return False;
1462 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1465 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1467 default: return False;
1472 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1473 char** buf, int* buflen,
1474 char** stringbuf, int* stringspace, char* baseaddr)
1483 case 0: struct_len = 13; break;
1484 case 1: struct_len = 20; break;
1485 case 2: struct_len = 40; break;
1486 case 91: struct_len = 68; break;
1494 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1495 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1496 if (buflen) *buflen = struct_len;
1497 if (stringspace) *stringspace = len;
1498 return struct_len + len;
1503 if ((*buflen) < struct_len) return -1;
1511 p2 = p + struct_len;
1512 l2 = (*buflen) - struct_len;
1514 if (!baseaddr) baseaddr = p;
1516 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1522 type = STYPE_DISKTREE;
1523 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1524 if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
1525 SSVAL(p,14,type); /* device type */
1526 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1527 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1532 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1533 SSVALS(p,22,-1); /* max uses */
1534 SSVAL(p,24,1); /* current uses */
1535 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1536 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1537 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1542 memset(p+40,0,SHPWLEN+2);
1554 (*buf) = p + struct_len;
1555 (*buflen) -= struct_len;
1557 (*stringspace) = l2;
1567 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1568 int mdrcnt,int mprcnt,
1569 char **rdata,char **rparam,
1570 int *rdata_len,int *rparam_len)
1572 char *str1 = param+2;
1573 char *str2 = skip_string(str1,1);
1574 char *netname = skip_string(str2,1);
1575 char *p = skip_string(netname,1);
1576 int uLevel = SVAL(p,0);
1577 int snum = find_service(netname);
1579 if (snum < 0) return False;
1581 /* check it's a supported varient */
1582 if (!prefix_ok(str1,"zWrLh")) return False;
1583 if (!check_share_info(uLevel,str2)) return False;
1585 *rdata = REALLOC(*rdata,mdrcnt);
1587 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1588 if (*rdata_len < 0) return False;
1591 *rparam = REALLOC(*rparam,*rparam_len);
1592 SSVAL(*rparam,0,NERR_Success);
1593 SSVAL(*rparam,2,0); /* converter word */
1594 SSVAL(*rparam,4,*rdata_len);
1599 /****************************************************************************
1600 view list of shares available
1601 ****************************************************************************/
1602 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1603 int mdrcnt,int mprcnt,
1604 char **rdata,char **rparam,
1605 int *rdata_len,int *rparam_len)
1607 char *str1 = param+2;
1608 char *str2 = skip_string(str1,1);
1609 char *p = skip_string(str2,1);
1610 int uLevel = SVAL(p,0);
1611 int buf_len = SVAL(p,2);
1613 int count=lp_numservices();
1614 int total=0,counted=0;
1615 BOOL missed = False;
1617 int data_len, fixed_len, string_len;
1618 int f_len = 0, s_len = 0;
1620 if (!prefix_ok(str1,"WrLeh")) return False;
1621 if (!check_share_info(uLevel,str2)) return False;
1623 data_len = fixed_len = string_len = 0;
1624 for (i=0;i<count;i++)
1625 if (lp_browseable(i) && lp_snum_ok(i))
1628 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1629 if (data_len <= buf_len)
1633 string_len += s_len;
1638 *rdata_len = fixed_len + string_len;
1639 *rdata = REALLOC(*rdata,*rdata_len);
1640 memset(*rdata,0,*rdata_len);
1642 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1646 for (i = 0; i < count;i++)
1647 if (lp_browseable(i) && lp_snum_ok(i))
1648 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1652 *rparam = REALLOC(*rparam,*rparam_len);
1653 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1655 SSVAL(*rparam,4,counted);
1656 SSVAL(*rparam,6,total);
1658 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1659 counted,total,uLevel,
1660 buf_len,*rdata_len,mdrcnt));
1666 /****************************************************************************
1667 get the time of day info
1668 ****************************************************************************/
1669 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1670 int mdrcnt,int mprcnt,
1671 char **rdata,char **rparam,
1672 int *rdata_len,int *rparam_len)
1676 *rparam = REALLOC(*rparam,*rparam_len);
1679 *rdata = REALLOC(*rdata,*rdata_len);
1681 SSVAL(*rparam,0,NERR_Success);
1682 SSVAL(*rparam,2,0); /* converter word */
1688 time_t unixdate = time(NULL);
1690 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1691 by NT in a "net time" operation,
1692 it seems to ignore the one below */
1694 /* the client expects to get localtime, not GMT, in this bit
1695 (I think, this needs testing) */
1696 t = LocalTime(&unixdate);
1698 SIVAL(p,4,0); /* msecs ? */
1699 CVAL(p,8) = t->tm_hour;
1700 CVAL(p,9) = t->tm_min;
1701 CVAL(p,10) = t->tm_sec;
1702 CVAL(p,11) = 0; /* hundredths of seconds */
1703 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1704 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1705 CVAL(p,16) = t->tm_mday;
1706 CVAL(p,17) = t->tm_mon + 1;
1707 SSVAL(p,18,1900+t->tm_year);
1708 CVAL(p,20) = t->tm_wday;
1715 /****************************************************************************
1716 Set the user password.
1717 *****************************************************************************/
1719 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1720 int mdrcnt,int mprcnt,
1721 char **rdata,char **rparam,
1722 int *rdata_len,int *rparam_len)
1724 char *p = skip_string(param+2,2);
1726 fstring pass1,pass2;
1728 pull_ascii_fstring(user,p);
1730 p = skip_string(p,1);
1732 memset(pass1,'\0',sizeof(pass1));
1733 memset(pass2,'\0',sizeof(pass2));
1735 memcpy(pass2,p+16,16);
1738 *rparam = REALLOC(*rparam,*rparam_len);
1742 SSVAL(*rparam,0,NERR_badpass);
1743 SSVAL(*rparam,2,0); /* converter word */
1745 DEBUG(3,("Set password for <%s>\n",user));
1748 * Pass the user through the NT -> unix user mapping
1752 (void)map_username(user);
1755 * Do any UNIX username case mangling.
1757 (void)Get_Pwnam( user, True);
1760 * Attempt to verify the old password against smbpasswd entries
1761 * Win98 clients send old and new password in plaintext for this call.
1765 fstring saved_pass2;
1766 SAM_ACCOUNT *sampass=NULL;
1769 * Save the new password as change_oem_password overwrites it
1773 fstrcpy(saved_pass2, pass2);
1775 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1776 change_oem_password(sampass,pass2,False))
1778 SSVAL(*rparam,0,NERR_Success);
1781 * If unix password sync was requested, attempt to change
1782 * the /etc/passwd database also. Return failure if this cannot
1786 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1787 SSVAL(*rparam,0,NERR_badpass);
1789 pdb_free_sam(sampass);
1794 * If the above failed, attempt the plaintext password change.
1795 * This tests against the /etc/passwd database only.
1798 if(SVAL(*rparam,0) != NERR_Success)
1800 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1801 chgpasswd(user,pass1,pass2,False))
1803 SSVAL(*rparam,0,NERR_Success);
1808 * If the plaintext change failed, attempt
1809 * the old encrypted method. NT will generate this
1810 * after trying the samr method. Note that this
1811 * method is done as a last resort as this
1812 * password change method loses the NT password hash
1813 * and cannot change the UNIX password as no plaintext
1817 if(SVAL(*rparam,0) != NERR_Success)
1819 SAM_ACCOUNT *hnd = NULL;
1821 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
1822 change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1824 SSVAL(*rparam,0,NERR_Success);
1830 memset((char *)pass1,'\0',sizeof(fstring));
1831 memset((char *)pass2,'\0',sizeof(fstring));
1836 /****************************************************************************
1837 Set the user password (SamOEM version - gets plaintext).
1838 ****************************************************************************/
1840 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1841 int mdrcnt,int mprcnt,
1842 char **rdata,char **rparam,
1843 int *rdata_len,int *rparam_len)
1846 char *p = param + 2;
1848 *rparam = REALLOC(*rparam,*rparam_len);
1852 SSVAL(*rparam,0,NERR_badpass);
1855 * Check the parameter definition is correct.
1857 if(!strequal(param + 2, "zsT")) {
1858 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1861 p = skip_string(p, 1);
1863 if(!strequal(p, "B516B16")) {
1864 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1867 p = skip_string(p,1);
1869 p += pull_ascii_fstring(user,p);
1871 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1874 * Pass the user through the NT -> unix user mapping
1878 (void)map_username(user);
1881 * Do any UNIX username case mangling.
1883 (void)Get_Pwnam( user, True);
1885 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1887 SSVAL(*rparam,0,NERR_Success);
1893 /****************************************************************************
1896 ****************************************************************************/
1897 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1898 int mdrcnt,int mprcnt,
1899 char **rdata,char **rparam,
1900 int *rdata_len,int *rparam_len)
1902 int function = SVAL(param,0);
1903 char *str1 = param+2;
1904 char *str2 = skip_string(str1,1);
1905 char *p = skip_string(str2,1);
1907 extern struct current_user current_user;
1911 /* check it's a supported varient */
1912 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1916 *rparam = REALLOC(*rparam,*rparam_len);
1919 if (!print_job_exists(jobid)) {
1920 errcode = NERR_JobNotFound;
1924 errcode = NERR_notsupported;
1927 case 81: /* delete */
1928 if (print_job_delete(¤t_user, jobid, &errcode))
1929 errcode = NERR_Success;
1931 case 82: /* pause */
1932 if (print_job_pause(¤t_user, jobid, &errcode))
1933 errcode = NERR_Success;
1935 case 83: /* resume */
1936 if (print_job_resume(¤t_user, jobid, &errcode))
1937 errcode = NERR_Success;
1942 SSVAL(*rparam,0,errcode);
1943 SSVAL(*rparam,2,0); /* converter word */
1948 /****************************************************************************
1949 Purge a print queue - or pause or resume it.
1950 ****************************************************************************/
1951 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1952 int mdrcnt,int mprcnt,
1953 char **rdata,char **rparam,
1954 int *rdata_len,int *rparam_len)
1956 int function = SVAL(param,0);
1957 char *str1 = param+2;
1958 char *str2 = skip_string(str1,1);
1959 char *QueueName = skip_string(str2,1);
1960 int errcode = NERR_notsupported;
1962 extern struct current_user current_user;
1964 /* check it's a supported varient */
1965 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1969 *rparam = REALLOC(*rparam,*rparam_len);
1972 snum = print_queue_snum(QueueName);
1975 errcode = NERR_JobNotFound;
1980 case 74: /* Pause queue */
1981 if (print_queue_pause(¤t_user, snum, &errcode)) errcode = NERR_Success;
1983 case 75: /* Resume queue */
1984 if (print_queue_resume(¤t_user, snum, &errcode)) errcode = NERR_Success;
1986 case 103: /* Purge */
1987 if (print_queue_purge(¤t_user, snum, &errcode)) errcode = NERR_Success;
1992 SSVAL(*rparam,0,errcode);
1993 SSVAL(*rparam,2,0); /* converter word */
1999 /****************************************************************************
2000 set the property of a print job (undocumented?)
2001 ? function = 0xb -> set name of print job
2002 ? function = 0x6 -> move print job up/down
2003 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2004 or <WWsTP> <WB21BB16B10zWWzDDz>
2005 ****************************************************************************/
2006 static int check_printjob_info(struct pack_desc* desc,
2007 int uLevel, char* id)
2009 desc->subformat = NULL;
2011 case 0: desc->format = "W"; break;
2012 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2013 case 2: desc->format = "WWzWWDDzz"; break;
2014 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2015 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2016 default: return False;
2018 if (strcmp(desc->format,id) != 0) return False;
2022 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2023 int mdrcnt,int mprcnt,
2024 char **rdata,char **rparam,
2025 int *rdata_len,int *rparam_len)
2027 struct pack_desc desc;
2028 char *str1 = param+2;
2029 char *str2 = skip_string(str1,1);
2030 char *p = skip_string(str2,1);
2032 int uLevel = SVAL(p,2);
2033 int function = SVAL(p,4);
2038 *rparam = REALLOC(*rparam,*rparam_len);
2042 /* check it's a supported varient */
2043 if ((strcmp(str1,"WWsTP")) ||
2044 (!check_printjob_info(&desc,uLevel,str2)))
2047 if (!print_job_exists(jobid)) {
2048 errcode=NERR_JobNotFound;
2052 errcode = NERR_notsupported;
2056 /* change job place in the queue,
2057 data gives the new place */
2058 place = SVAL(data,0);
2059 if (print_job_set_place(jobid, place)) {
2060 errcode=NERR_Success;
2065 /* change print job name, data gives the name */
2066 if (print_job_set_name(jobid, data)) {
2067 errcode=NERR_Success;
2076 SSVALS(*rparam,0,errcode);
2077 SSVAL(*rparam,2,0); /* converter word */
2083 /****************************************************************************
2084 get info about the server
2085 ****************************************************************************/
2086 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2087 int mdrcnt,int mprcnt,
2088 char **rdata,char **rparam,
2089 int *rdata_len,int *rparam_len)
2091 char *str1 = param+2;
2092 char *str2 = skip_string(str1,1);
2093 char *p = skip_string(str2,1);
2094 int uLevel = SVAL(p,0);
2098 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2100 /* check it's a supported varient */
2101 if (!prefix_ok(str1,"WrLh")) return False;
2104 if (strcmp(str2,"B16") != 0) return False;
2108 if (strcmp(str2,"B16BBDz") != 0) return False;
2112 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2117 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2122 if (strcmp(str2,"DN") != 0) return False;
2126 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2129 default: return False;
2132 *rdata_len = mdrcnt;
2133 *rdata = REALLOC(*rdata,*rdata_len);
2136 p2 = p + struct_len;
2138 srvstr_push(NULL, p,local_machine,16,
2139 STR_ASCII|STR_UPPER|STR_TERMINATE);
2144 struct srv_info_struct *servers=NULL;
2147 uint32 servertype= lp_default_server_announce();
2149 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2151 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2152 for (i=0;i<count;i++)
2153 if (strequal(servers[i].name,local_machine))
2155 servertype = servers[i].type;
2156 pstrcpy(comment,servers[i].comment);
2159 if (servers) free(servers);
2161 SCVAL(p,0,lp_major_announce_version());
2162 SCVAL(p,1,lp_minor_announce_version());
2163 SIVAL(p,2,servertype);
2165 if (mdrcnt == struct_len) {
2168 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2169 standard_sub_conn(conn,comment);
2170 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2171 p2 = skip_string(p2,1);
2176 return False; /* not yet implemented */
2179 *rdata_len = PTR_DIFF(p2,*rdata);
2182 *rparam = REALLOC(*rparam,*rparam_len);
2183 SSVAL(*rparam,0,NERR_Success);
2184 SSVAL(*rparam,2,0); /* converter word */
2185 SSVAL(*rparam,4,*rdata_len);
2191 /****************************************************************************
2192 get info about the server
2193 ****************************************************************************/
2194 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2195 int mdrcnt,int mprcnt,
2196 char **rdata,char **rparam,
2197 int *rdata_len,int *rparam_len)
2199 char *str1 = param+2;
2200 char *str2 = skip_string(str1,1);
2201 char *p = skip_string(str2,1);
2203 extern userdom_struct current_user_info;
2204 int level = SVAL(p,0);
2206 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2209 *rparam = REALLOC(*rparam,*rparam_len);
2211 /* check it's a supported varient */
2212 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2215 *rdata_len = mdrcnt + 1024;
2216 *rdata = REALLOC(*rdata,*rdata_len);
2218 SSVAL(*rparam,0,NERR_Success);
2219 SSVAL(*rparam,2,0); /* converter word */
2225 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2226 pstrcpy(p2,local_machine);
2228 p2 = skip_string(p2,1);
2231 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2232 pstrcpy(p2,current_user_info.smb_name);
2233 p2 = skip_string(p2,1);
2236 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2237 pstrcpy(p2,global_myworkgroup);
2239 p2 = skip_string(p2,1);
2242 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2243 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2246 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2247 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2248 p2 = skip_string(p2,1);
2251 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2253 p2 = skip_string(p2,1);
2256 *rdata_len = PTR_DIFF(p2,*rdata);
2258 SSVAL(*rparam,4,*rdata_len);
2263 /****************************************************************************
2264 get info about a user
2266 struct user_info_11 {
2267 char usri11_name[21]; 0-20
2269 char *usri11_comment; 22-25
2270 char *usri11_usr_comment; 26-29
2271 unsigned short usri11_priv; 30-31
2272 unsigned long usri11_auth_flags; 32-35
2273 long usri11_password_age; 36-39
2274 char *usri11_homedir; 40-43
2275 char *usri11_parms; 44-47
2276 long usri11_last_logon; 48-51
2277 long usri11_last_logoff; 52-55
2278 unsigned short usri11_bad_pw_count; 56-57
2279 unsigned short usri11_num_logons; 58-59
2280 char *usri11_logon_server; 60-63
2281 unsigned short usri11_country_code; 64-65
2282 char *usri11_workstations; 66-69
2283 unsigned long usri11_max_storage; 70-73
2284 unsigned short usri11_units_per_week; 74-75
2285 unsigned char *usri11_logon_hours; 76-79
2286 unsigned short usri11_code_page; 80-81
2291 usri11_name specifies the user name for which information is retireved
2293 usri11_pad aligns the next data structure element to a word boundary
2295 usri11_comment is a null terminated ASCII comment
2297 usri11_user_comment is a null terminated ASCII comment about the user
2299 usri11_priv specifies the level of the privilege assigned to the user.
2300 The possible values are:
2302 Name Value Description
2303 USER_PRIV_GUEST 0 Guest privilege
2304 USER_PRIV_USER 1 User privilege
2305 USER_PRV_ADMIN 2 Administrator privilege
2307 usri11_auth_flags specifies the account operator privileges. The
2308 possible values are:
2310 Name Value Description
2311 AF_OP_PRINT 0 Print operator
2314 Leach, Naik [Page 28]
2318 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2321 AF_OP_COMM 1 Communications operator
2322 AF_OP_SERVER 2 Server operator
2323 AF_OP_ACCOUNTS 3 Accounts operator
2326 usri11_password_age specifies how many seconds have elapsed since the
2327 password was last changed.
2329 usri11_home_dir points to a null terminated ASCII string that contains
2330 the path name of the user's home directory.
2332 usri11_parms points to a null terminated ASCII string that is set
2333 aside for use by applications.
2335 usri11_last_logon specifies the time when the user last logged on.
2336 This value is stored as the number of seconds elapsed since
2337 00:00:00, January 1, 1970.
2339 usri11_last_logoff specifies the time when the user last logged off.
2340 This value is stored as the number of seconds elapsed since
2341 00:00:00, January 1, 1970. A value of 0 means the last logoff
2344 usri11_bad_pw_count specifies the number of incorrect passwords
2345 entered since the last successful logon.
2347 usri11_log1_num_logons specifies the number of times this user has
2348 logged on. A value of -1 means the number of logons is unknown.
2350 usri11_logon_server points to a null terminated ASCII string that
2351 contains the name of the server to which logon requests are sent.
2352 A null string indicates logon requests should be sent to the
2355 usri11_country_code specifies the country code for the user's language
2358 usri11_workstations points to a null terminated ASCII string that
2359 contains the names of workstations the user may log on from.
2360 There may be up to 8 workstations, with the names separated by
2361 commas. A null strings indicates there are no restrictions.
2363 usri11_max_storage specifies the maximum amount of disk space the user
2364 can occupy. A value of 0xffffffff indicates there are no
2367 usri11_units_per_week specifies the equal number of time units into
2368 which a week is divided. This value must be equal to 168.
2370 usri11_logon_hours points to a 21 byte (168 bits) string that
2371 specifies the time during which the user can log on. Each bit
2372 represents one unique hour in a week. The first bit (bit 0, word
2373 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2377 Leach, Naik [Page 29]
2381 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2384 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2385 are no restrictions.
2387 usri11_code_page specifies the code page for the user's language of
2390 All of the pointers in this data structure need to be treated
2391 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2392 to be ignored. The converter word returned in the parameters section
2393 needs to be subtracted from the lower 16 bits to calculate an offset
2394 into the return buffer where this ASCII string resides.
2396 There is no auxiliary data in the response.
2398 ****************************************************************************/
2400 #define usri11_name 0
2401 #define usri11_pad 21
2402 #define usri11_comment 22
2403 #define usri11_usr_comment 26
2404 #define usri11_full_name 30
2405 #define usri11_priv 34
2406 #define usri11_auth_flags 36
2407 #define usri11_password_age 40
2408 #define usri11_homedir 44
2409 #define usri11_parms 48
2410 #define usri11_last_logon 52
2411 #define usri11_last_logoff 56
2412 #define usri11_bad_pw_count 60
2413 #define usri11_num_logons 62
2414 #define usri11_logon_server 64
2415 #define usri11_country_code 68
2416 #define usri11_workstations 70
2417 #define usri11_max_storage 74
2418 #define usri11_units_per_week 78
2419 #define usri11_logon_hours 80
2420 #define usri11_code_page 84
2421 #define usri11_end 86
2423 #define USER_PRIV_GUEST 0
2424 #define USER_PRIV_USER 1
2425 #define USER_PRIV_ADMIN 2
2427 #define AF_OP_PRINT 0
2428 #define AF_OP_COMM 1
2429 #define AF_OP_SERVER 2
2430 #define AF_OP_ACCOUNTS 3
2433 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2434 int mdrcnt,int mprcnt,
2435 char **rdata,char **rparam,
2436 int *rdata_len,int *rparam_len)
2438 char *str1 = param+2;
2439 char *str2 = skip_string(str1,1);
2440 char *UserName = skip_string(str2,1);
2441 char *p = skip_string(UserName,1);
2442 int uLevel = SVAL(p,0);
2445 /* get NIS home of a previously validated user - simeon */
2446 /* With share level security vuid will always be zero.
2447 Don't depend on vuser being non-null !!. JRA */
2448 user_struct *vuser = get_valid_user_struct(vuid);
2450 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2451 vuser->user.unix_name));
2454 *rparam = REALLOC(*rparam,*rparam_len);
2456 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2458 /* check it's a supported variant */
2459 if (strcmp(str1,"zWrLh") != 0) return False;
2462 case 0: p2 = "B21"; break;
2463 case 1: p2 = "B21BB16DWzzWz"; break;
2464 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2465 case 10: p2 = "B21Bzzz"; break;
2466 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2467 default: return False;
2470 if (strcmp(p2,str2) != 0) return False;
2472 *rdata_len = mdrcnt + 1024;
2473 *rdata = REALLOC(*rdata,*rdata_len);
2475 SSVAL(*rparam,0,NERR_Success);
2476 SSVAL(*rparam,2,0); /* converter word */
2479 p2 = p + usri11_end;
2482 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2486 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2491 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2492 pstrcpy(p2,"Comment");
2493 p2 = skip_string(p2,1);
2495 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2496 pstrcpy(p2,"UserComment");
2497 p2 = skip_string(p2,1);
2499 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2500 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2501 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2502 p2 = skip_string(p2,1);
2505 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2507 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2508 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2509 SIVALS(p,usri11_password_age,-1); /* password age */
2510 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2511 pstrcpy(p2, lp_logon_home());
2512 standard_sub_conn(conn, p2);
2513 p2 = skip_string(p2,1);
2514 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2516 p2 = skip_string(p2,1);
2517 SIVAL(p,usri11_last_logon,0); /* last logon */
2518 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2519 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2520 SSVALS(p,usri11_num_logons,-1); /* num logons */
2521 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2522 pstrcpy(p2,"\\\\*");
2523 p2 = skip_string(p2,1);
2524 SSVAL(p,usri11_country_code,0); /* country code */
2526 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2528 p2 = skip_string(p2,1);
2530 SIVALS(p,usri11_max_storage,-1); /* max storage */
2531 SSVAL(p,usri11_units_per_week,168); /* units per week */
2532 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2534 /* a simple way to get logon hours at all times. */
2536 SCVAL(p2,21,0); /* fix zero termination */
2537 p2 = skip_string(p2,1);
2539 SSVAL(p,usri11_code_page,0); /* code page */
2541 if (uLevel == 1 || uLevel == 2)
2543 memset(p+22,' ',16); /* password */
2544 SIVALS(p,38,-1); /* password age */
2546 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2547 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2548 pstrcpy(p2,lp_logon_home());
2549 standard_sub_conn(conn, p2);
2550 p2 = skip_string(p2,1);
2551 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2553 SSVAL(p,52,0); /* flags */
2554 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2555 pstrcpy(p2,lp_logon_script());
2556 standard_sub_conn( conn, p2 );
2557 p2 = skip_string(p2,1);
2560 SIVAL(p,60,0); /* auth_flags */
2561 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2562 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2563 p2 = skip_string(p2,1);
2564 SIVAL(p,68,0); /* urs_comment */
2565 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2567 p2 = skip_string(p2,1);
2568 SIVAL(p,76,0); /* workstations */
2569 SIVAL(p,80,0); /* last_logon */
2570 SIVAL(p,84,0); /* last_logoff */
2571 SIVALS(p,88,-1); /* acct_expires */
2572 SIVALS(p,92,-1); /* max_storage */
2573 SSVAL(p,96,168); /* units_per_week */
2574 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2577 SSVALS(p,102,-1); /* bad_pw_count */
2578 SSVALS(p,104,-1); /* num_logons */
2579 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2580 pstrcpy(p2,"\\\\%L");
2581 standard_sub_conn(conn, p2);
2582 p2 = skip_string(p2,1);
2583 SSVAL(p,110,49); /* country_code */
2584 SSVAL(p,112,860); /* code page */
2588 *rdata_len = PTR_DIFF(p2,*rdata);
2590 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2595 /*******************************************************************
2596 get groups that a user is a member of
2597 ******************************************************************/
2598 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2599 int mdrcnt,int mprcnt,
2600 char **rdata,char **rparam,
2601 int *rdata_len,int *rparam_len)
2603 char *str1 = param+2;
2604 char *str2 = skip_string(str1,1);
2605 char *UserName = skip_string(str2,1);
2606 char *p = skip_string(UserName,1);
2607 int uLevel = SVAL(p,0);
2612 *rparam = REALLOC(*rparam,*rparam_len);
2614 /* check it's a supported varient */
2615 if (strcmp(str1,"zWrLeh") != 0) return False;
2617 case 0: p2 = "B21"; break;
2618 default: return False;
2620 if (strcmp(p2,str2) != 0) return False;
2622 *rdata_len = mdrcnt + 1024;
2623 *rdata = REALLOC(*rdata,*rdata_len);
2625 SSVAL(*rparam,0,NERR_Success);
2626 SSVAL(*rparam,2,0); /* converter word */
2630 /* XXXX we need a real SAM database some day */
2631 pstrcpy(p,"Users"); p += 21; count++;
2632 pstrcpy(p,"Domain Users"); p += 21; count++;
2633 pstrcpy(p,"Guests"); p += 21; count++;
2634 pstrcpy(p,"Domain Guests"); p += 21; count++;
2636 *rdata_len = PTR_DIFF(p,*rdata);
2638 SSVAL(*rparam,4,count); /* is this right?? */
2639 SSVAL(*rparam,6,count); /* is this right?? */
2645 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2646 int mdrcnt,int mprcnt,
2647 char **rdata,char **rparam,
2648 int *rdata_len,int *rparam_len)
2650 char *str1 = param+2;
2651 char *str2 = skip_string(str1,1);
2652 char *p = skip_string(str2,1);
2654 struct pack_desc desc;
2660 memset((char *)&desc,'\0',sizeof(desc));
2662 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2664 /* check it's a supported varient */
2665 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2666 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2667 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2669 desc.buflen = mdrcnt;
2670 desc.subformat = NULL;
2673 if (init_package(&desc,1,0))
2675 PACKI(&desc,"W",0); /* code */
2676 PACKS(&desc,"B21",name); /* eff. name */
2677 PACKS(&desc,"B",""); /* pad */
2679 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2680 PACKI(&desc,"D",0); /* auth flags XXX */
2681 PACKI(&desc,"W",0); /* num logons */
2682 PACKI(&desc,"W",0); /* bad pw count */
2683 PACKI(&desc,"D",0); /* last logon */
2684 PACKI(&desc,"D",-1); /* last logoff */
2685 PACKI(&desc,"D",-1); /* logoff time */
2686 PACKI(&desc,"D",-1); /* kickoff time */
2687 PACKI(&desc,"D",0); /* password age */
2688 PACKI(&desc,"D",0); /* password can change */
2689 PACKI(&desc,"D",-1); /* password must change */
2692 fstrcpy(mypath,"\\\\");
2693 fstrcat(mypath,local_machine);
2695 PACKS(&desc,"z",mypath); /* computer */
2697 PACKS(&desc,"z",global_myworkgroup);/* domain */
2699 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2700 /* made sure all macros are fully substituted and available */
2702 pstring logon_script;
2703 pstrcpy(logon_script,lp_logon_script());
2704 standard_sub_conn( conn, logon_script );
2705 PACKS(&desc,"z", logon_script); /* script path */
2707 /* End of JHT mods */
2709 PACKI(&desc,"D",0x00000000); /* reserved */
2712 *rdata_len = desc.usedlen;
2714 *rparam = REALLOC(*rparam,*rparam_len);
2715 SSVALS(*rparam,0,desc.errcode);
2717 SSVAL(*rparam,4,desc.neededlen);
2719 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2724 /****************************************************************************
2725 api_WAccessGetUserPerms
2726 ****************************************************************************/
2727 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2728 int mdrcnt,int mprcnt,
2729 char **rdata,char **rparam,
2730 int *rdata_len,int *rparam_len)
2732 char *str1 = param+2;
2733 char *str2 = skip_string(str1,1);
2734 char *user = skip_string(str2,1);
2735 char *resource = skip_string(user,1);
2737 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2739 /* check it's a supported varient */
2740 if (strcmp(str1,"zzh") != 0) return False;
2741 if (strcmp(str2,"") != 0) return False;
2744 *rparam = REALLOC(*rparam,*rparam_len);
2745 SSVALS(*rparam,0,0); /* errorcode */
2746 SSVAL(*rparam,2,0); /* converter word */
2747 SSVAL(*rparam,4,0x7f); /* permission flags */
2752 /****************************************************************************
2753 api_WPrintJobEnumerate
2754 ****************************************************************************/
2755 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2756 int mdrcnt,int mprcnt,
2757 char **rdata,char **rparam,
2758 int *rdata_len,int *rparam_len)
2760 char *str1 = param+2;
2761 char *str2 = skip_string(str1,1);
2762 char *p = skip_string(str2,1);
2768 struct pack_desc desc;
2769 print_queue_struct *queue=NULL;
2770 print_status_struct status;
2775 memset((char *)&desc,'\0',sizeof(desc));
2776 memset((char *)&status,'\0',sizeof(status));
2778 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2780 /* check it's a supported varient */
2781 if (strcmp(str1,"WWrLh") != 0) return False;
2782 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2785 snum = print_job_snum(job);
2787 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2789 count = print_queue_status(snum,&queue,&status);
2790 for (i = 0; i < count; i++) {
2791 if (queue[i].job == job) break;
2795 *rdata = REALLOC(*rdata,mdrcnt);
2797 desc.buflen = mdrcnt;
2800 * Don't return data but need to get correct length
2801 * init_package will return wrong size if buflen=0
2803 desc.buflen = getlen(desc.format);
2804 desc.base = tmpdata = (char *)malloc ( desc.buflen );
2807 if (init_package(&desc,1,0)) {
2809 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2810 *rdata_len = desc.usedlen;
2813 desc.errcode = NERR_JobNotFound;
2819 *rparam = REALLOC(*rparam,*rparam_len);
2820 SSVALS(*rparam,0,desc.errcode);
2822 SSVAL(*rparam,4,desc.neededlen);
2824 if (queue) free(queue);
2825 if (tmpdata) free(tmpdata);
2827 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2831 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2832 int mdrcnt,int mprcnt,
2833 char **rdata,char **rparam,
2834 int *rdata_len,int *rparam_len)
2836 char *str1 = param+2;
2837 char *str2 = skip_string(str1,1);
2838 char *p = skip_string(str2,1);
2844 struct pack_desc desc;
2845 print_queue_struct *queue=NULL;
2846 print_status_struct status;
2848 memset((char *)&desc,'\0',sizeof(desc));
2849 memset((char *)&status,'\0',sizeof(status));
2851 p = skip_string(p,1);
2854 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2856 /* check it's a supported varient */
2857 if (strcmp(str1,"zWrLeh") != 0) return False;
2858 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2859 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2861 snum = lp_servicenumber(name);
2862 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2863 int pnum = lp_servicenumber(PRINTERS_NAME);
2865 lp_add_printer(name,pnum);
2866 snum = lp_servicenumber(name);
2870 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2872 count = print_queue_status(snum,&queue,&status);
2873 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2875 desc.buflen = mdrcnt;
2877 if (init_package(&desc,count,0)) {
2879 for (i = 0; i < count; i++) {
2880 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2881 if (desc.errcode == NERR_Success) succnt = i+1;
2885 *rdata_len = desc.usedlen;
2888 *rparam = REALLOC(*rparam,*rparam_len);
2889 SSVALS(*rparam,0,desc.errcode);
2891 SSVAL(*rparam,4,succnt);
2892 SSVAL(*rparam,6,count);
2894 if (queue) free(queue);
2896 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2900 static int check_printdest_info(struct pack_desc* desc,
2901 int uLevel, char* id)
2903 desc->subformat = NULL;
2905 case 0: desc->format = "B9"; break;
2906 case 1: desc->format = "B9B21WWzW"; break;
2907 case 2: desc->format = "z"; break;
2908 case 3: desc->format = "zzzWWzzzWW"; break;
2909 default: return False;
2911 if (strcmp(desc->format,id) != 0) return False;
2915 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2916 struct pack_desc* desc)
2919 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2920 buf[sizeof(buf)-1] = 0;
2923 PACKS(desc,"B9",buf); /* szName */
2925 PACKS(desc,"B21",""); /* szUserName */
2926 PACKI(desc,"W",0); /* uJobId */
2927 PACKI(desc,"W",0); /* fsStatus */
2928 PACKS(desc,"z",""); /* pszStatus */
2929 PACKI(desc,"W",0); /* time */
2932 if (uLevel == 2 || uLevel == 3) {
2933 PACKS(desc,"z",buf); /* pszPrinterName */
2935 PACKS(desc,"z",""); /* pszUserName */
2936 PACKS(desc,"z",""); /* pszLogAddr */
2937 PACKI(desc,"W",0); /* uJobId */
2938 PACKI(desc,"W",0); /* fsStatus */
2939 PACKS(desc,"z",""); /* pszStatus */
2940 PACKS(desc,"z",""); /* pszComment */
2941 PACKS(desc,"z","NULL"); /* pszDrivers */
2942 PACKI(desc,"W",0); /* time */
2943 PACKI(desc,"W",0); /* pad1 */
2948 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2949 int mdrcnt,int mprcnt,
2950 char **rdata,char **rparam,
2951 int *rdata_len,int *rparam_len)
2953 char *str1 = param+2;
2954 char *str2 = skip_string(str1,1);
2955 char *p = skip_string(str2,1);
2956 char* PrinterName = p;
2958 struct pack_desc desc;
2962 memset((char *)&desc,'\0',sizeof(desc));
2964 p = skip_string(p,1);
2967 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2969 /* check it's a supported varient */
2970 if (strcmp(str1,"zWrLh") != 0) return False;
2971 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2973 snum = lp_servicenumber(PrinterName);
2974 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2975 int pnum = lp_servicenumber(PRINTERS_NAME);
2977 lp_add_printer(PrinterName,pnum);
2978 snum = lp_servicenumber(PrinterName);
2984 desc.errcode = NERR_DestNotFound;
2989 *rdata = REALLOC(*rdata,mdrcnt);
2991 desc.buflen = mdrcnt;
2994 * Don't return data but need to get correct length
2995 * init_package will return wrong size if buflen=0
2997 desc.buflen = getlen(desc.format);
2998 desc.base = tmpdata = (char *)malloc ( desc.buflen );
3000 if (init_package(&desc,1,0)) {
3001 fill_printdest_info(conn,snum,uLevel,&desc);
3003 *rdata_len = desc.usedlen;
3007 *rparam = REALLOC(*rparam,*rparam_len);
3008 SSVALS(*rparam,0,desc.errcode);
3010 SSVAL(*rparam,4,desc.neededlen);
3012 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3013 if (tmpdata) free (tmpdata);
3017 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3018 int mdrcnt,int mprcnt,
3019 char **rdata,char **rparam,
3020 int *rdata_len,int *rparam_len)
3022 char *str1 = param+2;
3023 char *str2 = skip_string(str1,1);
3024 char *p = skip_string(str2,1);
3028 struct pack_desc desc;
3029 int services = lp_numservices();
3031 memset((char *)&desc,'\0',sizeof(desc));
3035 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3037 /* check it's a supported varient */
3038 if (strcmp(str1,"WrLeh") != 0) return False;
3039 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3042 for (i = 0; i < services; i++)
3043 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3046 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3048 desc.buflen = mdrcnt;
3049 if (init_package(&desc,queuecnt,0)) {
3052 for (i = 0; i < services; i++) {
3053 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3054 fill_printdest_info(conn,i,uLevel,&desc);
3056 if (desc.errcode == NERR_Success) succnt = n;
3061 *rdata_len = desc.usedlen;
3064 *rparam = REALLOC(*rparam,*rparam_len);
3065 SSVALS(*rparam,0,desc.errcode);
3067 SSVAL(*rparam,4,succnt);
3068 SSVAL(*rparam,6,queuecnt);
3070 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3074 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3075 int mdrcnt,int mprcnt,
3076 char **rdata,char **rparam,
3077 int *rdata_len,int *rparam_len)
3079 char *str1 = param+2;
3080 char *str2 = skip_string(str1,1);
3081 char *p = skip_string(str2,1);
3084 struct pack_desc desc;
3086 memset((char *)&desc,'\0',sizeof(desc));
3090 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3092 /* check it's a supported varient */
3093 if (strcmp(str1,"WrLeh") != 0) return False;
3094 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3096 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3098 desc.buflen = mdrcnt;
3099 if (init_package(&desc,1,0)) {
3100 PACKS(&desc,"B41","NULL");
3103 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3105 *rdata_len = desc.usedlen;
3108 *rparam = REALLOC(*rparam,*rparam_len);
3109 SSVALS(*rparam,0,desc.errcode);
3111 SSVAL(*rparam,4,succnt);
3114 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3118 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3119 int mdrcnt,int mprcnt,
3120 char **rdata,char **rparam,
3121 int *rdata_len,int *rparam_len)
3123 char *str1 = param+2;
3124 char *str2 = skip_string(str1,1);
3125 char *p = skip_string(str2,1);
3128 struct pack_desc desc;
3130 memset((char *)&desc,'\0',sizeof(desc));
3134 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3136 /* check it's a supported varient */
3137 if (strcmp(str1,"WrLeh") != 0) return False;
3138 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3140 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3142 desc.buflen = mdrcnt;
3144 if (init_package(&desc,1,0)) {
3145 PACKS(&desc,"B13","lpd");
3148 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3150 *rdata_len = desc.usedlen;
3153 *rparam = REALLOC(*rparam,*rparam_len);
3154 SSVALS(*rparam,0,desc.errcode);
3156 SSVAL(*rparam,4,succnt);
3159 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3163 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3164 int mdrcnt,int mprcnt,
3165 char **rdata,char **rparam,
3166 int *rdata_len,int *rparam_len)
3168 char *str1 = param+2;
3169 char *str2 = skip_string(str1,1);
3170 char *p = skip_string(str2,1);
3173 struct pack_desc desc;
3175 memset((char *)&desc,'\0',sizeof(desc));
3179 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3181 /* check it's a supported varient */
3182 if (strcmp(str1,"WrLeh") != 0) return False;
3183 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3185 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3186 memset((char *)&desc,'\0',sizeof(desc));
3188 desc.buflen = mdrcnt;
3190 if (init_package(&desc,1,0)) {
3191 PACKS(&desc,"B13","lp0");
3194 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3196 *rdata_len = desc.usedlen;
3199 *rparam = REALLOC(*rparam,*rparam_len);
3200 SSVALS(*rparam,0,desc.errcode);
3202 SSVAL(*rparam,4,succnt);
3205 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3209 /****************************************************************************
3210 The buffer was too small
3211 ****************************************************************************/
3213 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3214 int mdrcnt,int mprcnt,
3215 char **rdata,char **rparam,
3216 int *rdata_len,int *rparam_len)
3218 *rparam_len = MIN(*rparam_len,mprcnt);
3219 *rparam = REALLOC(*rparam,*rparam_len);
3223 SSVAL(*rparam,0,NERR_BufTooSmall);
3225 DEBUG(3,("Supplied buffer too small in API command\n"));
3231 /****************************************************************************
3232 The request is not supported
3233 ****************************************************************************/
3235 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3236 int mdrcnt,int mprcnt,
3237 char **rdata,char **rparam,
3238 int *rdata_len,int *rparam_len)
3241 *rparam = REALLOC(*rparam,*rparam_len);
3245 SSVAL(*rparam,0,NERR_notsupported);
3246 SSVAL(*rparam,2,0); /* converter word */
3248 DEBUG(3,("Unsupported API command\n"));
3260 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3261 int,int,char **,char **,int *,int *);
3263 } api_commands[] = {
3264 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3265 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3266 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3267 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3268 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3269 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3270 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3271 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3272 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3273 {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0},
3274 {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3275 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3276 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3277 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3278 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3279 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3280 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3281 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3282 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3283 {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0},
3284 {"NetServerEnum", 104, api_RNetServerEnum,0},
3285 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3286 {"SetUserPassword", 115, api_SetUserPassword,0},
3287 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3288 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3289 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3290 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3291 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3292 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3293 {NULL, -1, api_Unsupported,0}};
3296 /****************************************************************************
3297 Handle remote api calls
3298 ****************************************************************************/
3300 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3301 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3305 char *rparam = NULL;
3312 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3316 api_command = SVAL(params,0);
3318 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3321 skip_string(params+2,1),
3322 tdscnt,tpscnt,mdrcnt,mprcnt));
3324 for (i=0;api_commands[i].name;i++) {
3325 if (api_commands[i].id == api_command && api_commands[i].fn) {
3326 DEBUG(3,("Doing %s\n",api_commands[i].name));
3331 rdata = (char *)malloc(1024);
3333 memset(rdata,'\0',1024);
3335 rparam = (char *)malloc(1024);
3337 memset(rparam,'\0',1024);
3339 if(!rdata || !rparam) {
3340 DEBUG(0,("api_reply: malloc fail !\n"));
3344 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3345 &rdata,&rparam,&rdata_len,&rparam_len);
3348 if (rdata_len > mdrcnt ||
3349 rparam_len > mprcnt) {
3350 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3351 &rdata,&rparam,&rdata_len,&rparam_len);
3354 /* if we get False back then it's actually unsupported */
3356 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3357 &rdata,&rparam,&rdata_len,&rparam_len);
3359 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);