2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
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 3 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, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
30 extern struct current_user current_user;
37 #define NERR_Success 0
38 #define NERR_badpass 86
39 #define NERR_notsupported 50
41 #define NERR_BASE (2100)
42 #define NERR_BufTooSmall (NERR_BASE+23)
43 #define NERR_JobNotFound (NERR_BASE+51)
44 #define NERR_DestNotFound (NERR_BASE+52)
46 #define ACCESS_READ 0x01
47 #define ACCESS_WRITE 0x02
48 #define ACCESS_CREATE 0x04
50 #define SHPWLEN 8 /* share password length */
52 /* Limit size of ipc replies */
54 static char *smb_realloc_limit(void *ptr, size_t size)
58 size = MAX((size),4*1024);
59 val = (char *)SMB_REALLOC(ptr,size);
61 memset(val,'\0',size);
66 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
67 char *param, int tpscnt,
68 char *data, int tdscnt,
69 int mdrcnt, int mprcnt,
70 char **rdata, char **rparam,
71 int *rdata_len, int *rparam_len);
73 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
74 int mdrcnt, int mprcnt,
75 char **rdata, char **rparam,
76 int *rdata_len, int *rparam_len);
79 static int CopyExpanded(connection_struct *conn,
80 int snum, char **dst, char *src, int *p_space_remaining)
82 TALLOC_CTX *ctx = talloc_tos();
86 if (!src || !dst || !p_space_remaining || !(*dst) ||
87 *p_space_remaining <= 0) {
91 buf = talloc_strdup(ctx, src);
93 *p_space_remaining = 0;
96 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
98 *p_space_remaining = 0;
101 buf = talloc_sub_advanced(ctx,
102 lp_servicename(SNUM(conn)),
103 conn->server_info->unix_name,
105 conn->server_info->utok.gid,
106 conn->server_info->sanitized_username,
107 pdb_get_domain(conn->server_info->sam_account),
110 *p_space_remaining = 0;
113 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
118 (*p_space_remaining) -= l;
122 static int CopyAndAdvance(char **dst, char *src, int *n)
125 if (!src || !dst || !n || !(*dst)) {
128 l = push_ascii(*dst,src,*n, STR_TERMINATE);
137 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
139 TALLOC_CTX *ctx = talloc_tos();
144 buf = talloc_strdup(ctx,s);
148 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
152 buf = talloc_sub_advanced(ctx,
153 lp_servicename(SNUM(conn)),
154 conn->server_info->unix_name,
156 conn->server_info->utok.gid,
157 conn->server_info->sanitized_username,
158 pdb_get_domain(conn->server_info->sam_account),
163 return strlen(buf) + 1;
166 static char *Expand(connection_struct *conn, int snum, char *s)
168 TALLOC_CTX *ctx = talloc_tos();
174 buf = talloc_strdup(ctx,s);
178 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
182 return talloc_sub_advanced(ctx,
183 lp_servicename(SNUM(conn)),
184 conn->server_info->unix_name,
186 conn->server_info->utok.gid,
187 conn->server_info->sanitized_username,
188 pdb_get_domain(conn->server_info->sam_account),
192 /*******************************************************************
193 Check a API string for validity when we only need to check the prefix.
194 ******************************************************************/
196 static bool prefix_ok(const char *str, const char *prefix)
198 return(strncmp(str,prefix,strlen(prefix)) == 0);
202 const char *format; /* formatstring for structure */
203 const char *subformat; /* subformat for structure */
204 char *base; /* baseaddress of buffer */
205 int buflen; /* remaining size for fixed part; on init: length of base */
206 int subcount; /* count of substructures */
207 char *structbuf; /* pointer into buffer for remaining fixed part */
208 int stringlen; /* remaining size for variable part */
209 char *stringbuf; /* pointer into buffer for remaining variable part */
210 int neededlen; /* total needed size */
211 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
212 const char *curpos; /* current position; pointer into format or subformat */
216 static int get_counter(const char **p)
222 if (!isdigit((int)**p)) {
228 n = 10 * n + (i - '0');
236 static int getlen(const char *p)
245 case 'W': /* word (2 byte) */
248 case 'K': /* status word? (2 byte) */
251 case 'N': /* count of substructures (word) at end */
254 case 'D': /* double word (4 byte) */
255 case 'z': /* offset to zero terminated string (4 byte) */
256 case 'l': /* offset to user data (4 byte) */
259 case 'b': /* offset to data (with counter) (4 byte) */
263 case 'B': /* byte (with optional counter) */
264 n += get_counter(&p);
271 static bool init_package(struct pack_desc *p, int count, int subcount)
276 if (!p->format || !p->base) {
280 i = count * getlen(p->format);
282 i += subcount * getlen(p->subformat);
284 p->structbuf = p->base;
288 p->curpos = p->format;
294 * This is the old error code we used. Aparently
295 * WinNT/2k systems return ERRbuftoosmall (2123) and
296 * OS/2 needs this. I'm leaving this here so we can revert
299 p->errcode = ERRmoredata;
301 p->errcode = ERRbuftoosmall;
304 p->errcode = NERR_Success;
308 p->stringbuf = p->base + i;
310 return (p->errcode == NERR_Success);
313 static int package(struct pack_desc *p, ...)
316 int needed=0, stringneeded;
317 const char *str=NULL;
318 int is_string=0, stringused;
325 p->curpos = p->format;
327 p->curpos = p->subformat;
332 str = va_arg(args,char*);
333 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
342 switch( *p->curpos++ ) {
343 case 'W': /* word (2 byte) */
345 temp = va_arg(args,int);
346 if (p->buflen >= needed) {
347 SSVAL(p->structbuf,0,temp);
350 case 'K': /* status word? (2 byte) */
352 temp = va_arg(args,int);
353 if (p->buflen >= needed) {
354 SSVAL(p->structbuf,0,temp);
357 case 'N': /* count of substructures (word) at end */
359 p->subcount = va_arg(args,int);
360 if (p->buflen >= needed) {
361 SSVAL(p->structbuf,0,p->subcount);
364 case 'D': /* double word (4 byte) */
366 temp = va_arg(args,int);
367 if (p->buflen >= needed) {
368 SIVAL(p->structbuf,0,temp);
371 case 'B': /* byte (with optional counter) */
372 needed = get_counter(&p->curpos);
374 char *s = va_arg(args,char*);
375 if (p->buflen >= needed) {
376 StrnCpy(p->structbuf,s?s:"",needed-1);
380 case 'z': /* offset to zero terminated string (4 byte) */
381 str = va_arg(args,char*);
382 stringneeded = (str ? strlen(str)+1 : 0);
385 case 'l': /* offset to user data (4 byte) */
386 str = va_arg(args,char*);
387 stringneeded = va_arg(args,int);
390 case 'b': /* offset to data (with counter) (4 byte) */
391 str = va_arg(args,char*);
392 stringneeded = get_counter(&p->curpos);
398 if (stringneeded >= 0) {
400 if (p->buflen >= needed) {
401 stringused = stringneeded;
402 if (stringused > p->stringlen) {
403 stringused = (is_string ? p->stringlen : 0);
404 if (p->errcode == NERR_Success) {
405 p->errcode = ERRmoredata;
409 SIVAL(p->structbuf,0,0);
411 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
412 memcpy(p->stringbuf,str?str:"",stringused);
414 p->stringbuf[stringused-1] = '\0';
416 p->stringbuf += stringused;
417 p->stringlen -= stringused;
418 p->usedlen += stringused;
421 p->neededlen += stringneeded;
424 p->neededlen += needed;
425 if (p->buflen >= needed) {
426 p->structbuf += needed;
428 p->usedlen += needed;
430 if (p->errcode == NERR_Success) {
431 p->errcode = ERRmoredata;
438 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
439 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
441 #define PACK(desc,t,v) package(desc,v)
442 #define PACKl(desc,t,v,l) package(desc,v,l)
445 static void PACKI(struct pack_desc* desc, const char *t,int v)
450 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
455 /****************************************************************************
457 ****************************************************************************/
459 static void PackDriverData(struct pack_desc* desc)
461 char drivdata[4+4+32];
462 SIVAL(drivdata,0,sizeof drivdata); /* cb */
463 SIVAL(drivdata,4,1000); /* lVersion */
464 memset(drivdata+8,0,32); /* szDeviceName */
465 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
466 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
469 static int check_printq_info(struct pack_desc* desc,
470 unsigned int uLevel, char *id1, char *id2)
472 desc->subformat = NULL;
475 desc->format = "B13";
478 desc->format = "B13BWWWzzzzzWW";
481 desc->format = "B13BWWWzzzzzWN";
482 desc->subformat = "WB21BB16B10zWWzDDz";
485 desc->format = "zWWWWzzzzWWzzl";
488 desc->format = "zWWWWzzzzWNzzl";
489 desc->subformat = "WWzWWDDzz";
498 desc->format = "WzzzzzzzzN";
499 desc->subformat = "z";
502 DEBUG(0,("check_printq_info: invalid level %d\n",
506 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
507 DEBUG(0,("check_printq_info: invalid format %s\n",
508 id1 ? id1 : "<NULL>" ));
511 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
512 DEBUG(0,("check_printq_info: invalid subformat %s\n",
513 id2 ? id2 : "<NULL>" ));
520 #define RAP_JOB_STATUS_QUEUED 0
521 #define RAP_JOB_STATUS_PAUSED 1
522 #define RAP_JOB_STATUS_SPOOLING 2
523 #define RAP_JOB_STATUS_PRINTING 3
524 #define RAP_JOB_STATUS_PRINTED 4
526 #define RAP_QUEUE_STATUS_PAUSED 1
527 #define RAP_QUEUE_STATUS_ERROR 2
529 /* turn a print job status into a on the wire status
531 static int printj_status(int v)
535 return RAP_JOB_STATUS_QUEUED;
537 return RAP_JOB_STATUS_PAUSED;
539 return RAP_JOB_STATUS_SPOOLING;
541 return RAP_JOB_STATUS_PRINTING;
546 /* turn a print queue status into a on the wire status
548 static int printq_status(int v)
554 return RAP_QUEUE_STATUS_PAUSED;
556 return RAP_QUEUE_STATUS_ERROR;
559 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
560 struct pack_desc *desc,
561 print_queue_struct *queue, int n)
563 time_t t = queue->time;
565 /* the client expects localtime */
566 t -= get_time_zone(t);
568 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
570 PACKS(desc,"B21",queue->fs_user); /* szUserName */
571 PACKS(desc,"B",""); /* pad */
572 PACKS(desc,"B16",""); /* szNotifyName */
573 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
574 PACKS(desc,"z",""); /* pszParms */
575 PACKI(desc,"W",n+1); /* uPosition */
576 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
577 PACKS(desc,"z",""); /* pszStatus */
578 PACKI(desc,"D",t); /* ulSubmitted */
579 PACKI(desc,"D",queue->size); /* ulSize */
580 PACKS(desc,"z",queue->fs_file); /* pszComment */
582 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
583 PACKI(desc,"W",queue->priority); /* uPriority */
584 PACKS(desc,"z",queue->fs_user); /* pszUserName */
585 PACKI(desc,"W",n+1); /* uPosition */
586 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
587 PACKI(desc,"D",t); /* ulSubmitted */
588 PACKI(desc,"D",queue->size); /* ulSize */
589 PACKS(desc,"z","Samba"); /* pszComment */
590 PACKS(desc,"z",queue->fs_file); /* pszDocument */
592 PACKS(desc,"z",""); /* pszNotifyName */
593 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
594 PACKS(desc,"z",""); /* pszParms */
595 PACKS(desc,"z",""); /* pszStatus */
596 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
597 PACKS(desc,"z","lpd"); /* pszQProcName */
598 PACKS(desc,"z",""); /* pszQProcParms */
599 PACKS(desc,"z","NULL"); /* pszDriverName */
600 PackDriverData(desc); /* pDriverData */
601 PACKS(desc,"z",""); /* pszPrinterName */
602 } else if (uLevel == 4) { /* OS2 */
603 PACKS(desc,"z",""); /* pszSpoolFileName */
604 PACKS(desc,"z",""); /* pszPortName */
605 PACKS(desc,"z",""); /* pszStatus */
606 PACKI(desc,"D",0); /* ulPagesSpooled */
607 PACKI(desc,"D",0); /* ulPagesSent */
608 PACKI(desc,"D",0); /* ulPagesPrinted */
609 PACKI(desc,"D",0); /* ulTimePrinted */
610 PACKI(desc,"D",0); /* ulExtendJobStatus */
611 PACKI(desc,"D",0); /* ulStartPage */
612 PACKI(desc,"D",0); /* ulEndPage */
617 /********************************************************************
618 Return a driver name given an snum.
619 Returns True if from tdb, False otherwise.
620 ********************************************************************/
622 static bool get_driver_name(int snum, char **pp_drivername)
624 NT_PRINTER_INFO_LEVEL *info = NULL;
627 get_a_printer (NULL, &info, 2, lp_servicename(snum));
629 *pp_drivername = talloc_strdup(talloc_tos(),
630 info->info_2->drivername);
632 free_a_printer(&info, 2);
633 if (!*pp_drivername) {
641 /********************************************************************
642 Respond to the DosPrintQInfo command with a level of 52
643 This is used to get printer driver information for Win9x clients
644 ********************************************************************/
645 static void fill_printq_info_52(connection_struct *conn, int snum,
646 struct pack_desc* desc, int count )
650 NT_PRINTER_DRIVER_INFO_LEVEL driver;
651 NT_PRINTER_INFO_LEVEL *printer = NULL;
655 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
656 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
657 lp_servicename(snum)));
661 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
664 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
665 printer->info_2->drivername));
669 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
670 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
671 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
673 PACKI(desc, "W", 0x0400); /* don't know */
674 PACKS(desc, "z", driver.info_3->name); /* long printer name */
675 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
676 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
677 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
679 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
680 standard_sub_basic( "", "", location, sizeof(location)-1 );
681 PACKS(desc,"z", location); /* share to retrieve files */
683 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
684 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
685 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
687 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
688 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
689 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
690 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
691 DEBUG(3,("Driver Location: %s:\n",location));
692 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
693 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
694 PACKI(desc,"N",count); /* number of files to copy */
696 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
698 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
699 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
700 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
705 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
708 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
710 desc->errcode=NERR_Success;
714 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
715 desc->errcode=NERR_notsupported;
719 free_a_printer( &printer, 2 );
722 free_a_printer_driver( driver, 3 );
726 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
727 struct pack_desc* desc,
728 int count, print_queue_struct* queue,
729 print_status_struct* status)
734 PACKS(desc,"B13",SERVICE(snum));
739 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
742 PACKI(desc,"K",printq_status(status->status));
746 if (uLevel == 1 || uLevel == 2) {
747 PACKS(desc,"B",""); /* alignment */
748 PACKI(desc,"W",5); /* priority */
749 PACKI(desc,"W",0); /* start time */
750 PACKI(desc,"W",0); /* until time */
751 PACKS(desc,"z",""); /* pSepFile */
752 PACKS(desc,"z","lpd"); /* pPrProc */
753 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
754 PACKS(desc,"z",""); /* pParms */
756 PACKS(desc,"z","UNKNOWN PRINTER");
757 PACKI(desc,"W",LPSTAT_ERROR);
759 else if (!status || !status->message[0]) {
760 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
761 PACKI(desc,"W",LPSTAT_OK); /* status */
763 PACKS(desc,"z",status->message);
764 PACKI(desc,"W",printq_status(status->status)); /* status */
766 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
769 if (uLevel == 3 || uLevel == 4) {
770 char *drivername = NULL;
772 PACKI(desc,"W",5); /* uPriority */
773 PACKI(desc,"W",0); /* uStarttime */
774 PACKI(desc,"W",0); /* uUntiltime */
775 PACKI(desc,"W",5); /* pad1 */
776 PACKS(desc,"z",""); /* pszSepFile */
777 PACKS(desc,"z","WinPrint"); /* pszPrProc */
778 PACKS(desc,"z",NULL); /* pszParms */
779 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
780 /* "don't ask" that it's done this way to fix corrupted
781 Win9X/ME printer comments. */
783 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
785 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
787 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
788 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
789 get_driver_name(snum,&drivername);
793 PACKS(desc,"z",drivername); /* pszDriverName */
794 PackDriverData(desc); /* pDriverData */
797 if (uLevel == 2 || uLevel == 4) {
799 for (i=0;i<count;i++)
800 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
804 fill_printq_info_52( conn, snum, desc, count );
807 /* This function returns the number of files for a given driver */
808 static int get_printerdrivernumber(int snum)
811 NT_PRINTER_DRIVER_INFO_LEVEL driver;
812 NT_PRINTER_INFO_LEVEL *printer = NULL;
816 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
817 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
818 lp_servicename(snum)));
822 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
825 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
826 printer->info_2->drivername));
830 /* count the number of files */
831 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
836 free_a_printer( &printer, 2 );
839 free_a_printer_driver( driver, 3 );
844 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
845 char *param, int tpscnt,
846 char *data, int tdscnt,
847 int mdrcnt,int mprcnt,
848 char **rdata,char **rparam,
849 int *rdata_len,int *rparam_len)
851 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
852 char *str2 = skip_string(param,tpscnt,str1);
853 char *p = skip_string(param,tpscnt,str2);
859 struct pack_desc desc;
860 print_queue_struct *queue=NULL;
861 print_status_struct status;
864 if (!str1 || !str2 || !p) {
867 memset((char *)&status,'\0',sizeof(status));
868 memset((char *)&desc,'\0',sizeof(desc));
870 p = skip_string(param,tpscnt,p);
874 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
875 str3 = get_safe_str_ptr(param,tpscnt,p,4);
876 /* str3 may be null here and is checked in check_printq_info(). */
878 /* remove any trailing username */
879 if ((p = strchr_m(QueueName,'%')))
882 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
884 /* check it's a supported varient */
885 if (!prefix_ok(str1,"zWrLh"))
887 if (!check_printq_info(&desc,uLevel,str2,str3)) {
889 * Patch from Scott Moomaw <scott@bridgewater.edu>
890 * to return the 'invalid info level' error if an
891 * unknown level was requested.
895 *rparam = smb_realloc_limit(*rparam,*rparam_len);
899 SSVALS(*rparam,0,ERRunknownlevel);
905 snum = find_service(QueueName);
906 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
910 count = get_printerdrivernumber(snum);
911 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
913 count = print_queue_status(snum, &queue,&status);
917 *rdata = smb_realloc_limit(*rdata,mdrcnt);
923 desc.buflen = mdrcnt;
926 * Don't return data but need to get correct length
927 * init_package will return wrong size if buflen=0
929 desc.buflen = getlen(desc.format);
930 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
933 if (init_package(&desc,1,count)) {
934 desc.subcount = count;
935 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
938 *rdata_len = desc.usedlen;
941 * We must set the return code to ERRbuftoosmall
942 * in order to support lanman style printing with Win NT/2k
945 if (!mdrcnt && lp_disable_spoolss())
946 desc.errcode = ERRbuftoosmall;
948 *rdata_len = desc.usedlen;
950 *rparam = smb_realloc_limit(*rparam,*rparam_len);
956 SSVALS(*rparam,0,desc.errcode);
958 SSVAL(*rparam,4,desc.neededlen);
960 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
968 /****************************************************************************
969 View list of all print jobs on all queues.
970 ****************************************************************************/
972 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
973 char *param, int tpscnt,
974 char *data, int tdscnt,
975 int mdrcnt, int mprcnt,
976 char **rdata, char** rparam,
977 int *rdata_len, int *rparam_len)
979 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
980 char *output_format1 = skip_string(param,tpscnt,param_format);
981 char *p = skip_string(param,tpscnt,output_format1);
982 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
983 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
984 int services = lp_numservices();
986 struct pack_desc desc;
987 print_queue_struct **queue = NULL;
988 print_status_struct *status = NULL;
989 int *subcntarr = NULL;
990 int queuecnt = 0, subcnt = 0, succnt = 0;
992 if (!param_format || !output_format1 || !p) {
996 memset((char *)&desc,'\0',sizeof(desc));
998 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1000 if (!prefix_ok(param_format,"WrLeh")) {
1003 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1005 * Patch from Scott Moomaw <scott@bridgewater.edu>
1006 * to return the 'invalid info level' error if an
1007 * unknown level was requested.
1011 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1015 SSVALS(*rparam,0,ERRunknownlevel);
1021 for (i = 0; i < services; i++) {
1022 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1027 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1028 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1031 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1032 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1033 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1036 memset(status,0,queuecnt*sizeof(print_status_struct));
1037 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1038 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1044 for (i = 0; i < services; i++) {
1045 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1046 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1047 subcnt += subcntarr[n];
1053 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1059 desc.buflen = mdrcnt;
1061 if (init_package(&desc,queuecnt,subcnt)) {
1064 for (i = 0; i < services; i++) {
1065 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1066 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1068 if (desc.errcode == NERR_Success) {
1075 SAFE_FREE(subcntarr);
1077 *rdata_len = desc.usedlen;
1079 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1083 SSVALS(*rparam,0,desc.errcode);
1085 SSVAL(*rparam,4,succnt);
1086 SSVAL(*rparam,6,queuecnt);
1088 for (i = 0; i < queuecnt; i++) {
1090 SAFE_FREE(queue[i]);
1101 SAFE_FREE(subcntarr);
1102 for (i = 0; i < queuecnt; i++) {
1104 SAFE_FREE(queue[i]);
1113 /****************************************************************************
1114 Get info level for a server list query.
1115 ****************************************************************************/
1117 static bool check_server_info(int uLevel, char* id)
1121 if (strcmp(id,"B16") != 0) {
1126 if (strcmp(id,"B16BBDz") != 0) {
1136 struct srv_info_struct {
1144 /*******************************************************************
1145 Get server info lists from the files saved by nmbd. Return the
1147 ******************************************************************/
1149 static int get_server_info(uint32 servertype,
1150 struct srv_info_struct **servers,
1156 bool local_list_only;
1159 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1161 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1165 /* request for everything is code for request all servers */
1166 if (servertype == SV_TYPE_ALL) {
1167 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1170 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1172 DEBUG(4,("Servertype search: %8x\n",servertype));
1174 for (i=0;lines[i];i++) {
1176 struct srv_info_struct *s;
1177 const char *ptr = lines[i];
1179 TALLOC_CTX *frame = NULL;
1186 if (count == alloced) {
1188 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1190 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1191 file_lines_free(lines);
1194 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1196 s = &(*servers)[count];
1198 frame = talloc_stackframe();
1200 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1204 fstrcpy(s->name, p);
1207 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1213 s->comment[0] = '\0';
1214 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1218 fstrcpy(s->comment, p);
1220 s->domain[0] = '\0';
1221 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1222 /* this allows us to cope with an old nmbd */
1223 fstrcpy(s->domain,lp_workgroup());
1225 fstrcpy(s->domain, p);
1229 if (sscanf(stype,"%X",&s->type) != 1) {
1230 DEBUG(4,("r:host file "));
1234 /* Filter the servers/domains we return based on what was asked for. */
1236 /* Check to see if we are being asked for a local list only. */
1237 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1238 DEBUG(4,("r: local list only"));
1242 /* doesn't match up: don't want it */
1243 if (!(servertype & s->type)) {
1244 DEBUG(4,("r:serv type "));
1248 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1249 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1250 DEBUG(4,("s: dom mismatch "));
1254 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1258 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1259 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1262 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1263 s->name, s->type, s->comment, s->domain));
1264 s->server_added = True;
1267 DEBUG(4,("%20s %8x %25s %15s\n",
1268 s->name, s->type, s->comment, s->domain));
1272 file_lines_free(lines);
1276 /*******************************************************************
1277 Fill in a server info structure.
1278 ******************************************************************/
1280 static int fill_srv_info(struct srv_info_struct *service,
1281 int uLevel, char **buf, int *buflen,
1282 char **stringbuf, int *stringspace, char *baseaddr)
1305 len = strlen(service->comment)+1;
1309 *buflen = struct_len;
1311 return struct_len + len;
1316 if (*buflen < struct_len) {
1323 p2 = p + struct_len;
1324 l2 = *buflen - struct_len;
1332 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1336 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1337 SIVAL(p,18,service->type);
1338 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1339 len += CopyAndAdvance(&p2,service->comment,&l2);
1344 *buf = p + struct_len;
1345 *buflen -= struct_len;
1356 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1358 return(strcmp(s1->name,s2->name));
1361 /****************************************************************************
1362 View list of servers available (or possibly domains). The info is
1363 extracted from lists saved by nmbd on the local host.
1364 ****************************************************************************/
1366 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1367 char *param, int tpscnt,
1368 char *data, int tdscnt,
1369 int mdrcnt, int mprcnt, char **rdata,
1370 char **rparam, int *rdata_len, int *rparam_len)
1372 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1373 char *str2 = skip_string(param,tpscnt,str1);
1374 char *p = skip_string(param,tpscnt,str2);
1375 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1376 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1377 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1379 int data_len, fixed_len, string_len;
1380 int f_len = 0, s_len = 0;
1381 struct srv_info_struct *servers=NULL;
1382 int counted=0,total=0;
1385 bool domain_request;
1388 if (!str1 || !str2 || !p) {
1392 /* If someone sets all the bits they don't really mean to set
1393 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1396 if (servertype == SV_TYPE_ALL) {
1397 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1400 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1401 any other bit (they may just set this bit on its own) they
1402 want all the locally seen servers. However this bit can be
1403 set on its own so set the requested servers to be
1404 ALL - DOMAIN_ENUM. */
1406 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1407 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1410 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1411 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1415 if (!prefix_ok(str1,"WrLehD")) {
1418 if (!check_server_info(uLevel,str2)) {
1422 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1423 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1424 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1426 if (strcmp(str1, "WrLehDz") == 0) {
1427 if (skip_string(param,tpscnt,p) == NULL) {
1430 pull_ascii_fstring(domain, p);
1432 fstrcpy(domain, lp_workgroup());
1435 if (lp_browse_list()) {
1436 total = get_server_info(servertype,&servers,domain);
1439 data_len = fixed_len = string_len = 0;
1443 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1447 char *lastname=NULL;
1449 for (i=0;i<total;i++) {
1450 struct srv_info_struct *s = &servers[i];
1452 if (lastname && strequal(lastname,s->name)) {
1456 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1457 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1458 s->name, s->type, s->comment, s->domain));
1460 if (data_len <= buf_len) {
1463 string_len += s_len;
1470 *rdata_len = fixed_len + string_len;
1471 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1476 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1482 char *lastname=NULL;
1483 int count2 = counted;
1485 for (i = 0; i < total && count2;i++) {
1486 struct srv_info_struct *s = &servers[i];
1488 if (lastname && strequal(lastname,s->name)) {
1492 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1493 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1494 s->name, s->type, s->comment, s->domain));
1500 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1504 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1506 SSVAL(*rparam,4,counted);
1507 SSVAL(*rparam,6,counted+missed);
1511 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1512 domain,uLevel,counted,counted+missed));
1517 /****************************************************************************
1518 command 0x34 - suspected of being a "Lookup Names" stub api
1519 ****************************************************************************/
1521 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1522 char *param, int tpscnt,
1523 char *data, int tdscnt,
1524 int mdrcnt, int mprcnt, char **rdata,
1525 char **rparam, int *rdata_len, int *rparam_len)
1527 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1528 char *str2 = skip_string(param,tpscnt,str1);
1529 char *p = skip_string(param,tpscnt,str2);
1530 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1531 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1535 if (!str1 || !str2 || !p) {
1539 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1540 str1, str2, p, uLevel, buf_len));
1542 if (!prefix_ok(str1,"zWrLeh")) {
1549 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1554 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1556 SSVAL(*rparam,4,counted);
1557 SSVAL(*rparam,6,counted+missed);
1562 /****************************************************************************
1563 get info about a share
1564 ****************************************************************************/
1566 static bool check_share_info(int uLevel, char* id)
1570 if (strcmp(id,"B13") != 0) {
1575 if (strcmp(id,"B13BWz") != 0) {
1580 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1585 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1595 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1596 char** buf, int* buflen,
1597 char** stringbuf, int* stringspace, char* baseaddr)
1627 len += StrlenExpanded(conn,snum,lp_comment(snum));
1630 len += strlen(lp_pathname(snum)) + 1;
1633 *buflen = struct_len;
1638 return struct_len + len;
1643 if ((*buflen) < struct_len) {
1651 p2 = p + struct_len;
1652 l2 = (*buflen) - struct_len;
1659 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1665 type = STYPE_DISKTREE;
1666 if (lp_print_ok(snum)) {
1667 type = STYPE_PRINTQ;
1669 if (strequal("IPC",lp_fstype(snum))) {
1672 SSVAL(p,14,type); /* device type */
1673 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1674 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1678 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1679 SSVALS(p,22,-1); /* max uses */
1680 SSVAL(p,24,1); /* current uses */
1681 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1682 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1683 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1687 memset(p+40,0,SHPWLEN+2);
1698 (*buf) = p + struct_len;
1699 (*buflen) -= struct_len;
1701 (*stringspace) = l2;
1710 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1711 char *param, int tpscnt,
1712 char *data, int tdscnt,
1713 int mdrcnt,int mprcnt,
1714 char **rdata,char **rparam,
1715 int *rdata_len,int *rparam_len)
1717 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1718 char *str2 = skip_string(param,tpscnt,str1);
1719 char *netname = skip_string(param,tpscnt,str2);
1720 char *p = skip_string(param,tpscnt,netname);
1721 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1724 if (!str1 || !str2 || !netname || !p) {
1728 snum = find_service(netname);
1733 /* check it's a supported varient */
1734 if (!prefix_ok(str1,"zWrLh")) {
1737 if (!check_share_info(uLevel,str2)) {
1741 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1746 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1747 if (*rdata_len < 0) {
1752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1756 SSVAL(*rparam,0,NERR_Success);
1757 SSVAL(*rparam,2,0); /* converter word */
1758 SSVAL(*rparam,4,*rdata_len);
1763 /****************************************************************************
1764 View the list of available shares.
1766 This function is the server side of the NetShareEnum() RAP call.
1767 It fills the return buffer with share names and share comments.
1768 Note that the return buffer normally (in all known cases) allows only
1769 twelve byte strings for share names (plus one for a nul terminator).
1770 Share names longer than 12 bytes must be skipped.
1771 ****************************************************************************/
1773 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1774 char *param, int tpscnt,
1775 char *data, int tdscnt,
1783 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1784 char *str2 = skip_string(param,tpscnt,str1);
1785 char *p = skip_string(param,tpscnt,str2);
1786 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1787 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1790 int total=0,counted=0;
1791 bool missed = False;
1793 int data_len, fixed_len, string_len;
1794 int f_len = 0, s_len = 0;
1796 if (!str1 || !str2 || !p) {
1800 if (!prefix_ok(str1,"WrLeh")) {
1803 if (!check_share_info(uLevel,str2)) {
1807 /* Ensure all the usershares are loaded. */
1809 load_registry_shares();
1810 count = load_usershare_shares();
1813 data_len = fixed_len = string_len = 0;
1814 for (i=0;i<count;i++) {
1815 fstring servicename_dos;
1816 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1819 push_ascii_fstring(servicename_dos, lp_servicename(i));
1820 /* Maximum name length = 13. */
1821 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1823 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1824 if (data_len <= buf_len) {
1827 string_len += s_len;
1834 *rdata_len = fixed_len + string_len;
1835 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1840 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1845 for( i = 0; i < count; i++ ) {
1846 fstring servicename_dos;
1847 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1851 push_ascii_fstring(servicename_dos, lp_servicename(i));
1852 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1853 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1860 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1864 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1866 SSVAL(*rparam,4,counted);
1867 SSVAL(*rparam,6,total);
1869 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1870 counted,total,uLevel,
1871 buf_len,*rdata_len,mdrcnt));
1876 /****************************************************************************
1878 ****************************************************************************/
1880 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1881 char *param, int tpscnt,
1882 char *data, int tdscnt,
1883 int mdrcnt,int mprcnt,
1884 char **rdata,char **rparam,
1885 int *rdata_len,int *rparam_len)
1887 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1888 char *str2 = skip_string(param,tpscnt,str1);
1889 char *p = skip_string(param,tpscnt,str2);
1890 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1893 char *pathname = NULL;
1894 char *command, *cmdname;
1895 unsigned int offset;
1898 size_t converted_size;
1900 if (!str1 || !str2 || !p) {
1904 /* check it's a supported varient */
1905 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1908 if (!check_share_info(uLevel,str2)) {
1915 /* Do we have a string ? */
1916 if (skip_string(data,mdrcnt,data) == NULL) {
1919 pull_ascii_fstring(sharename,data);
1920 snum = find_service(sharename);
1921 if (snum >= 0) { /* already exists */
1930 /* only support disk share adds */
1931 if (SVAL(data,14)!=STYPE_DISKTREE) {
1935 offset = IVAL(data, 16);
1936 if (offset >= mdrcnt) {
1937 res = ERRinvalidparam;
1941 /* Do we have a string ? */
1942 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1945 pull_ascii_fstring(comment, offset? (data+offset) : "");
1947 offset = IVAL(data, 26);
1949 if (offset >= mdrcnt) {
1950 res = ERRinvalidparam;
1954 /* Do we have a string ? */
1955 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1959 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1960 offset ? (data+offset) : "", &converted_size))
1962 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1970 string_replace(sharename, '"', ' ');
1971 string_replace(pathname, '"', ' ');
1972 string_replace(comment, '"', ' ');
1974 cmdname = lp_add_share_cmd();
1976 if (!cmdname || *cmdname == '\0') {
1980 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1981 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1982 pathname, comment) == -1) {
1986 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1988 if ((res = smbrun(command, NULL)) != 0) {
1989 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1996 message_send_all(smbd_messaging_context(),
1997 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2001 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2005 SSVAL(*rparam,0,NERR_Success);
2006 SSVAL(*rparam,2,0); /* converter word */
2007 SSVAL(*rparam,4,*rdata_len);
2015 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2020 SSVAL(*rparam,0,res);
2025 /****************************************************************************
2026 view list of groups available
2027 ****************************************************************************/
2029 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2030 char *param, int tpscnt,
2031 char *data, int tdscnt,
2032 int mdrcnt,int mprcnt,
2033 char **rdata,char **rparam,
2034 int *rdata_len,int *rparam_len)
2038 int resume_context, cli_buf_size;
2039 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2040 char *str2 = skip_string(param,tpscnt,str1);
2041 char *p = skip_string(param,tpscnt,str2);
2043 struct pdb_search *search;
2044 struct samr_displayentry *entries;
2048 if (!str1 || !str2 || !p) {
2052 if (strcmp(str1,"WrLeh") != 0) {
2057 * W-> resume context (number of users to skip)
2058 * r -> return parameter pointer to receive buffer
2059 * L -> length of receive buffer
2060 * e -> return parameter number of entries
2061 * h -> return parameter total number of users
2064 if (strcmp("B21",str2) != 0) {
2068 /* get list of domain groups SID_DOMAIN_GRP=2 */
2070 search = pdb_search_groups();
2073 if (search == NULL) {
2074 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2078 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2079 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2080 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2081 "%d\n", resume_context, cli_buf_size));
2084 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2088 *rdata_len = cli_buf_size;
2089 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2096 for(i=0; i<num_entries; i++) {
2098 fstrcpy(name, entries[i].account_name);
2099 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2100 /* truncate the name at 21 chars. */
2101 memcpy(p, name, 21);
2102 DEBUG(10,("adding entry %d group %s\n", i, p));
2104 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2107 /* set overflow error */
2108 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2114 pdb_search_destroy(search);
2116 *rdata_len = PTR_DIFF(p,*rdata);
2119 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2123 SSVAL(*rparam, 0, errflags);
2124 SSVAL(*rparam, 2, 0); /* converter word */
2125 SSVAL(*rparam, 4, i); /* is this right?? */
2126 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2131 /*******************************************************************
2132 Get groups that a user is a member of.
2133 ******************************************************************/
2135 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2136 char *param, int tpscnt,
2137 char *data, int tdscnt,
2138 int mdrcnt,int mprcnt,
2139 char **rdata,char **rparam,
2140 int *rdata_len,int *rparam_len)
2142 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2143 char *str2 = skip_string(param,tpscnt,str1);
2144 char *UserName = skip_string(param,tpscnt,str2);
2145 char *p = skip_string(param,tpscnt,UserName);
2146 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2147 const char *level_string;
2149 struct samu *sampw = NULL;
2157 enum lsa_SidType type;
2159 TALLOC_CTX *mem_ctx;
2161 if (!str1 || !str2 || !UserName || !p) {
2166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2171 /* check it's a supported varient */
2173 if ( strcmp(str1,"zWrLeh") != 0 )
2178 level_string = "B21";
2184 if (strcmp(level_string,str2) != 0)
2187 *rdata_len = mdrcnt + 1024;
2188 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2193 SSVAL(*rparam,0,NERR_Success);
2194 SSVAL(*rparam,2,0); /* converter word */
2197 endp = *rdata + *rdata_len;
2199 mem_ctx = talloc_new(NULL);
2200 if (mem_ctx == NULL) {
2201 DEBUG(0, ("talloc_new failed\n"));
2205 if ( !(sampw = samu_new(mem_ctx)) ) {
2206 DEBUG(0, ("samu_new() failed!\n"));
2207 TALLOC_FREE(mem_ctx);
2211 /* Lookup the user information; This should only be one of
2212 our accounts (not remote domains) */
2214 become_root(); /* ROOT BLOCK */
2216 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2217 NULL, NULL, &user_sid, &type)) {
2218 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2222 if (type != SID_NAME_USER) {
2223 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2224 sid_type_lookup(type)));
2228 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2229 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2230 sid_string_dbg(&user_sid), UserName));
2238 result = pdb_enum_group_memberships(mem_ctx, sampw,
2239 &sids, &gids, &num_groups);
2241 if (!NT_STATUS_IS_OK(result)) {
2242 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2247 for (i=0; i<num_groups; i++) {
2248 const char *grp_name;
2250 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2251 strlcpy(p, grp_name, PTR_DIFF(endp,p));
2257 *rdata_len = PTR_DIFF(p,*rdata);
2259 SSVAL(*rparam,4,count); /* is this right?? */
2260 SSVAL(*rparam,6,count); /* is this right?? */
2265 unbecome_root(); /* END ROOT BLOCK */
2267 TALLOC_FREE(mem_ctx);
2272 /*******************************************************************
2274 ******************************************************************/
2276 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2277 char *param, int tpscnt,
2278 char *data, int tdscnt,
2279 int mdrcnt,int mprcnt,
2280 char **rdata,char **rparam,
2281 int *rdata_len,int *rparam_len)
2286 int i, resume_context, cli_buf_size;
2287 struct pdb_search *search;
2288 struct samr_displayentry *users;
2290 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2291 char *str2 = skip_string(param,tpscnt,str1);
2292 char *p = skip_string(param,tpscnt,str2);
2295 if (!str1 || !str2 || !p) {
2299 if (strcmp(str1,"WrLeh") != 0)
2302 * W-> resume context (number of users to skip)
2303 * r -> return parameter pointer to receive buffer
2304 * L -> length of receive buffer
2305 * e -> return parameter number of entries
2306 * h -> return parameter total number of users
2309 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2310 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2311 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2312 resume_context, cli_buf_size));
2315 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2320 /* check it's a supported varient */
2321 if (strcmp("B21",str2) != 0)
2324 *rdata_len = cli_buf_size;
2325 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2331 endp = *rdata + *rdata_len;
2334 search = pdb_search_users(ACB_NORMAL);
2336 if (search == NULL) {
2337 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2342 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2346 errflags=NERR_Success;
2348 for (i=0; i<num_users; i++) {
2349 const char *name = users[i].account_name;
2351 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2352 strlcpy(p,name,PTR_DIFF(endp,p));
2353 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2354 "%s\n",count_sent,p));
2358 /* set overflow error */
2359 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2360 "username %s\n",count_sent,name));
2366 pdb_search_destroy(search);
2368 *rdata_len = PTR_DIFF(p,*rdata);
2370 SSVAL(*rparam,0,errflags);
2371 SSVAL(*rparam,2,0); /* converter word */
2372 SSVAL(*rparam,4,count_sent); /* is this right?? */
2373 SSVAL(*rparam,6,num_users); /* is this right?? */
2378 /****************************************************************************
2379 Get the time of day info.
2380 ****************************************************************************/
2382 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2383 char *param, int tpscnt,
2384 char *data, int tdscnt,
2385 int mdrcnt,int mprcnt,
2386 char **rdata,char **rparam,
2387 int *rdata_len,int *rparam_len)
2390 time_t unixdate = time(NULL);
2394 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2400 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2405 SSVAL(*rparam,0,NERR_Success);
2406 SSVAL(*rparam,2,0); /* converter word */
2410 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2411 by NT in a "net time" operation,
2412 it seems to ignore the one below */
2414 /* the client expects to get localtime, not GMT, in this bit
2415 (I think, this needs testing) */
2416 t = localtime(&unixdate);
2421 SIVAL(p,4,0); /* msecs ? */
2422 SCVAL(p,8,t->tm_hour);
2423 SCVAL(p,9,t->tm_min);
2424 SCVAL(p,10,t->tm_sec);
2425 SCVAL(p,11,0); /* hundredths of seconds */
2426 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2427 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2428 SCVAL(p,16,t->tm_mday);
2429 SCVAL(p,17,t->tm_mon + 1);
2430 SSVAL(p,18,1900+t->tm_year);
2431 SCVAL(p,20,t->tm_wday);
2436 /****************************************************************************
2437 Set the user password.
2438 *****************************************************************************/
2440 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2441 char *param, int tpscnt,
2442 char *data, int tdscnt,
2443 int mdrcnt,int mprcnt,
2444 char **rdata,char **rparam,
2445 int *rdata_len,int *rparam_len)
2447 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2450 fstring pass1,pass2;
2452 /* Skip 2 strings. */
2453 p = skip_string(param,tpscnt,np);
2454 p = skip_string(param,tpscnt,p);
2460 /* Do we have a string ? */
2461 if (skip_string(param,tpscnt,p) == NULL) {
2464 pull_ascii_fstring(user,p);
2466 p = skip_string(param,tpscnt,p);
2471 memset(pass1,'\0',sizeof(pass1));
2472 memset(pass2,'\0',sizeof(pass2));
2474 * We use 31 here not 32 as we're checking
2475 * the last byte we want to access is safe.
2477 if (!is_offset_safe(param,tpscnt,p,31)) {
2481 memcpy(pass2,p+16,16);
2484 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2491 SSVAL(*rparam,0,NERR_badpass);
2492 SSVAL(*rparam,2,0); /* converter word */
2494 DEBUG(3,("Set password for <%s>\n",user));
2497 * Attempt to verify the old password against smbpasswd entries
2498 * Win98 clients send old and new password in plaintext for this call.
2502 auth_serversupplied_info *server_info = NULL;
2503 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2505 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2508 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2509 SSVAL(*rparam,0,NERR_Success);
2513 TALLOC_FREE(server_info);
2515 data_blob_clear_free(&password);
2519 * If the plaintext change failed, attempt
2520 * the old encrypted method. NT will generate this
2521 * after trying the samr method. Note that this
2522 * method is done as a last resort as this
2523 * password change method loses the NT password hash
2524 * and cannot change the UNIX password as no plaintext
2528 if(SVAL(*rparam,0) != NERR_Success) {
2529 struct samu *hnd = NULL;
2531 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2533 if (change_lanman_password(hnd,(uchar *)pass2)) {
2534 SSVAL(*rparam,0,NERR_Success);
2541 memset((char *)pass1,'\0',sizeof(fstring));
2542 memset((char *)pass2,'\0',sizeof(fstring));
2547 /****************************************************************************
2548 Set the user password (SamOEM version - gets plaintext).
2549 ****************************************************************************/
2551 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2552 char *param, int tpscnt,
2553 char *data, int tdscnt,
2554 int mdrcnt,int mprcnt,
2555 char **rdata,char **rparam,
2556 int *rdata_len,int *rparam_len)
2559 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2571 SSVAL(*rparam,0,NERR_badpass);
2574 * Check the parameter definition is correct.
2577 /* Do we have a string ? */
2578 if (skip_string(param,tpscnt,p) == 0) {
2581 if(!strequal(p, "zsT")) {
2582 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2585 p = skip_string(param, tpscnt, p);
2590 /* Do we have a string ? */
2591 if (skip_string(param,tpscnt,p) == 0) {
2594 if(!strequal(p, "B516B16")) {
2595 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2598 p = skip_string(param,tpscnt,p);
2602 /* Do we have a string ? */
2603 if (skip_string(param,tpscnt,p) == 0) {
2606 p += pull_ascii_fstring(user,p);
2608 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2611 * Pass the user through the NT -> unix user mapping
2615 (void)map_username(user);
2617 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2618 SSVAL(*rparam,0,NERR_Success);
2624 /****************************************************************************
2627 ****************************************************************************/
2629 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2630 char *param, int tpscnt,
2631 char *data, int tdscnt,
2632 int mdrcnt,int mprcnt,
2633 char **rdata,char **rparam,
2634 int *rdata_len,int *rparam_len)
2636 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2637 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2638 char *str2 = skip_string(param,tpscnt,str1);
2639 char *p = skip_string(param,tpscnt,str2);
2644 WERROR werr = WERR_OK;
2646 if (!str1 || !str2 || !p) {
2650 * We use 1 here not 2 as we're checking
2651 * the last byte we want to access is safe.
2653 if (!is_offset_safe(param,tpscnt,p,1)) {
2656 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2659 /* check it's a supported varient */
2660 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2664 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2670 if (!print_job_exists(sharename, jobid)) {
2671 errcode = NERR_JobNotFound;
2675 snum = lp_servicenumber( sharename);
2677 errcode = NERR_DestNotFound;
2681 errcode = NERR_notsupported;
2684 case 81: /* delete */
2685 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2686 errcode = NERR_Success;
2688 case 82: /* pause */
2689 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2690 errcode = NERR_Success;
2692 case 83: /* resume */
2693 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2694 errcode = NERR_Success;
2698 if (!W_ERROR_IS_OK(werr))
2699 errcode = W_ERROR_V(werr);
2702 SSVAL(*rparam,0,errcode);
2703 SSVAL(*rparam,2,0); /* converter word */
2708 /****************************************************************************
2709 Purge a print queue - or pause or resume it.
2710 ****************************************************************************/
2712 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2713 char *param, int tpscnt,
2714 char *data, int tdscnt,
2715 int mdrcnt,int mprcnt,
2716 char **rdata,char **rparam,
2717 int *rdata_len,int *rparam_len)
2719 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2720 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2721 char *str2 = skip_string(param,tpscnt,str1);
2722 char *QueueName = skip_string(param,tpscnt,str2);
2723 int errcode = NERR_notsupported;
2725 WERROR werr = WERR_OK;
2727 if (!str1 || !str2 || !QueueName) {
2731 /* check it's a supported varient */
2732 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2736 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2742 if (skip_string(param,tpscnt,QueueName) == NULL) {
2745 snum = print_queue_snum(QueueName);
2748 errcode = NERR_JobNotFound;
2753 case 74: /* Pause queue */
2754 if (print_queue_pause(conn->server_info, snum, &werr)) {
2755 errcode = NERR_Success;
2758 case 75: /* Resume queue */
2759 if (print_queue_resume(conn->server_info, snum, &werr)) {
2760 errcode = NERR_Success;
2763 case 103: /* Purge */
2764 if (print_queue_purge(conn->server_info, snum, &werr)) {
2765 errcode = NERR_Success;
2770 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2773 SSVAL(*rparam,0,errcode);
2774 SSVAL(*rparam,2,0); /* converter word */
2779 /****************************************************************************
2780 set the property of a print job (undocumented?)
2781 ? function = 0xb -> set name of print job
2782 ? function = 0x6 -> move print job up/down
2783 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2784 or <WWsTP> <WB21BB16B10zWWzDDz>
2785 ****************************************************************************/
2787 static int check_printjob_info(struct pack_desc* desc,
2788 int uLevel, char* id)
2790 desc->subformat = NULL;
2792 case 0: desc->format = "W"; break;
2793 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2794 case 2: desc->format = "WWzWWDDzz"; break;
2795 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2796 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2798 DEBUG(0,("check_printjob_info: invalid level %d\n",
2802 if (id == NULL || strcmp(desc->format,id) != 0) {
2803 DEBUG(0,("check_printjob_info: invalid format %s\n",
2804 id ? id : "<NULL>" ));
2810 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2811 char *param, int tpscnt,
2812 char *data, int tdscnt,
2813 int mdrcnt,int mprcnt,
2814 char **rdata,char **rparam,
2815 int *rdata_len,int *rparam_len)
2817 struct pack_desc desc;
2818 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2819 char *str2 = skip_string(param,tpscnt,str1);
2820 char *p = skip_string(param,tpscnt,str2);
2823 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2824 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2827 if (!str1 || !str2 || !p) {
2831 * We use 1 here not 2 as we're checking
2832 * the last byte we want to access is safe.
2834 if (!is_offset_safe(param,tpscnt,p,1)) {
2837 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2840 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2845 if (!share_defined(sharename)) {
2846 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2853 /* check it's a supported varient */
2854 if ((strcmp(str1,"WWsTP")) ||
2855 (!check_printjob_info(&desc,uLevel,str2)))
2858 if (!print_job_exists(sharename, jobid)) {
2859 errcode=NERR_JobNotFound;
2863 errcode = NERR_notsupported;
2867 /* change job place in the queue,
2868 data gives the new place */
2869 place = SVAL(data,0);
2870 if (print_job_set_place(sharename, jobid, place)) {
2871 errcode=NERR_Success;
2876 /* change print job name, data gives the name */
2877 if (print_job_set_name(sharename, jobid, data)) {
2878 errcode=NERR_Success;
2887 SSVALS(*rparam,0,errcode);
2888 SSVAL(*rparam,2,0); /* converter word */
2894 /****************************************************************************
2895 Get info about the server.
2896 ****************************************************************************/
2898 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2899 char *param, int tpscnt,
2900 char *data, int tdscnt,
2901 int mdrcnt,int mprcnt,
2902 char **rdata,char **rparam,
2903 int *rdata_len,int *rparam_len)
2905 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2906 char *str2 = skip_string(param,tpscnt,str1);
2907 char *p = skip_string(param,tpscnt,str2);
2908 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2912 if (!str1 || !str2 || !p) {
2916 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2918 /* check it's a supported varient */
2919 if (!prefix_ok(str1,"WrLh")) {
2925 if (strcmp(str2,"B16") != 0) {
2931 if (strcmp(str2,"B16BBDz") != 0) {
2937 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2943 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2949 if (strcmp(str2,"DN") != 0) {
2955 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2964 *rdata_len = mdrcnt;
2965 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2971 p2 = p + struct_len;
2973 srvstr_push(NULL, 0, p,global_myname(),16,
2974 STR_ASCII|STR_UPPER|STR_TERMINATE);
2978 struct srv_info_struct *servers=NULL;
2980 char *comment = NULL;
2981 TALLOC_CTX *ctx = talloc_tos();
2982 uint32 servertype= lp_default_server_announce();
2984 comment = talloc_strdup(ctx,lp_serverstring());
2989 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2990 for (i=0;i<count;i++) {
2991 if (strequal(servers[i].name,global_myname())) {
2992 servertype = servers[i].type;
2993 TALLOC_FREE(comment);
2994 comment = talloc_strdup(ctx,
2995 servers[i].comment);
3005 SCVAL(p,0,lp_major_announce_version());
3006 SCVAL(p,1,lp_minor_announce_version());
3007 SIVAL(p,2,servertype);
3009 if (mdrcnt == struct_len) {
3012 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3013 comment = talloc_sub_advanced(
3015 lp_servicename(SNUM(conn)),
3016 conn->server_info->unix_name,
3018 conn->server_info->utok.gid,
3019 conn->server_info->sanitized_username,
3020 pdb_get_domain(conn->server_info->sam_account),
3025 if (mdrcnt - struct_len <= 0) {
3030 MIN(mdrcnt - struct_len,
3031 MAX_SERVER_STRING_LENGTH),
3033 p2 = skip_string(*rdata,*rdata_len,p2);
3041 return False; /* not yet implemented */
3044 *rdata_len = PTR_DIFF(p2,*rdata);
3047 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3051 SSVAL(*rparam,0,NERR_Success);
3052 SSVAL(*rparam,2,0); /* converter word */
3053 SSVAL(*rparam,4,*rdata_len);
3058 /****************************************************************************
3059 Get info about the server.
3060 ****************************************************************************/
3062 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3063 char *param, int tpscnt,
3064 char *data, int tdscnt,
3065 int mdrcnt,int mprcnt,
3066 char **rdata,char **rparam,
3067 int *rdata_len,int *rparam_len)
3069 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3070 char *str2 = skip_string(param,tpscnt,str1);
3071 char *p = skip_string(param,tpscnt,str2);
3074 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3076 if (!str1 || !str2 || !p) {
3080 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3083 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3088 /* check it's a supported varient */
3089 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3093 *rdata_len = mdrcnt + 1024;
3094 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3099 SSVAL(*rparam,0,NERR_Success);
3100 SSVAL(*rparam,2,0); /* converter word */
3103 endp = *rdata + *rdata_len;
3105 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3110 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3111 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3113 p2 = skip_string(*rdata,*rdata_len,p2);
3119 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3120 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3121 p2 = skip_string(*rdata,*rdata_len,p2);
3127 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3128 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3130 p2 = skip_string(*rdata,*rdata_len,p2);
3136 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3137 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3140 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3141 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3142 p2 = skip_string(*rdata,*rdata_len,p2);
3148 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3149 strlcpy(p2,"",PTR_DIFF(endp,p2));
3150 p2 = skip_string(*rdata,*rdata_len,p2);
3156 *rdata_len = PTR_DIFF(p2,*rdata);
3158 SSVAL(*rparam,4,*rdata_len);
3163 /****************************************************************************
3164 get info about a user
3166 struct user_info_11 {
3167 char usri11_name[21]; 0-20
3169 char *usri11_comment; 22-25
3170 char *usri11_usr_comment; 26-29
3171 unsigned short usri11_priv; 30-31
3172 unsigned long usri11_auth_flags; 32-35
3173 long usri11_password_age; 36-39
3174 char *usri11_homedir; 40-43
3175 char *usri11_parms; 44-47
3176 long usri11_last_logon; 48-51
3177 long usri11_last_logoff; 52-55
3178 unsigned short usri11_bad_pw_count; 56-57
3179 unsigned short usri11_num_logons; 58-59
3180 char *usri11_logon_server; 60-63
3181 unsigned short usri11_country_code; 64-65
3182 char *usri11_workstations; 66-69
3183 unsigned long usri11_max_storage; 70-73
3184 unsigned short usri11_units_per_week; 74-75
3185 unsigned char *usri11_logon_hours; 76-79
3186 unsigned short usri11_code_page; 80-81
3191 usri11_name specifies the user name for which information is retrieved
3193 usri11_pad aligns the next data structure element to a word boundary
3195 usri11_comment is a null terminated ASCII comment
3197 usri11_user_comment is a null terminated ASCII comment about the user
3199 usri11_priv specifies the level of the privilege assigned to the user.
3200 The possible values are:
3202 Name Value Description
3203 USER_PRIV_GUEST 0 Guest privilege
3204 USER_PRIV_USER 1 User privilege
3205 USER_PRV_ADMIN 2 Administrator privilege
3207 usri11_auth_flags specifies the account operator privileges. The
3208 possible values are:
3210 Name Value Description
3211 AF_OP_PRINT 0 Print operator
3214 Leach, Naik [Page 28]
3218 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3221 AF_OP_COMM 1 Communications operator
3222 AF_OP_SERVER 2 Server operator
3223 AF_OP_ACCOUNTS 3 Accounts operator
3226 usri11_password_age specifies how many seconds have elapsed since the
3227 password was last changed.
3229 usri11_home_dir points to a null terminated ASCII string that contains
3230 the path name of the user's home directory.
3232 usri11_parms points to a null terminated ASCII string that is set
3233 aside for use by applications.
3235 usri11_last_logon specifies the time when the user last logged on.
3236 This value is stored as the number of seconds elapsed since
3237 00:00:00, January 1, 1970.
3239 usri11_last_logoff specifies the time when the user last logged off.
3240 This value is stored as the number of seconds elapsed since
3241 00:00:00, January 1, 1970. A value of 0 means the last logoff
3244 usri11_bad_pw_count specifies the number of incorrect passwords
3245 entered since the last successful logon.
3247 usri11_log1_num_logons specifies the number of times this user has
3248 logged on. A value of -1 means the number of logons is unknown.
3250 usri11_logon_server points to a null terminated ASCII string that
3251 contains the name of the server to which logon requests are sent.
3252 A null string indicates logon requests should be sent to the
3255 usri11_country_code specifies the country code for the user's language
3258 usri11_workstations points to a null terminated ASCII string that
3259 contains the names of workstations the user may log on from.
3260 There may be up to 8 workstations, with the names separated by
3261 commas. A null strings indicates there are no restrictions.
3263 usri11_max_storage specifies the maximum amount of disk space the user
3264 can occupy. A value of 0xffffffff indicates there are no
3267 usri11_units_per_week specifies the equal number of time units into
3268 which a week is divided. This value must be equal to 168.
3270 usri11_logon_hours points to a 21 byte (168 bits) string that
3271 specifies the time during which the user can log on. Each bit
3272 represents one unique hour in a week. The first bit (bit 0, word
3273 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3277 Leach, Naik [Page 29]
3281 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3284 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3285 are no restrictions.
3287 usri11_code_page specifies the code page for the user's language of
3290 All of the pointers in this data structure need to be treated
3291 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3292 to be ignored. The converter word returned in the parameters section
3293 needs to be subtracted from the lower 16 bits to calculate an offset
3294 into the return buffer where this ASCII string resides.
3296 There is no auxiliary data in the response.
3298 ****************************************************************************/
3300 #define usri11_name 0
3301 #define usri11_pad 21
3302 #define usri11_comment 22
3303 #define usri11_usr_comment 26
3304 #define usri11_full_name 30
3305 #define usri11_priv 34
3306 #define usri11_auth_flags 36
3307 #define usri11_password_age 40
3308 #define usri11_homedir 44
3309 #define usri11_parms 48
3310 #define usri11_last_logon 52
3311 #define usri11_last_logoff 56
3312 #define usri11_bad_pw_count 60
3313 #define usri11_num_logons 62
3314 #define usri11_logon_server 64
3315 #define usri11_country_code 68
3316 #define usri11_workstations 70
3317 #define usri11_max_storage 74
3318 #define usri11_units_per_week 78
3319 #define usri11_logon_hours 80
3320 #define usri11_code_page 84
3321 #define usri11_end 86
3323 #define USER_PRIV_GUEST 0
3324 #define USER_PRIV_USER 1
3325 #define USER_PRIV_ADMIN 2
3327 #define AF_OP_PRINT 0
3328 #define AF_OP_COMM 1
3329 #define AF_OP_SERVER 2
3330 #define AF_OP_ACCOUNTS 3
3333 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3334 char *param, int tpscnt,
3335 char *data, int tdscnt,
3336 int mdrcnt,int mprcnt,
3337 char **rdata,char **rparam,
3338 int *rdata_len,int *rparam_len)
3340 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3341 char *str2 = skip_string(param,tpscnt,str1);
3342 char *UserName = skip_string(param,tpscnt,str2);
3343 char *p = skip_string(param,tpscnt,UserName);
3344 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3347 const char *level_string;
3349 /* get NIS home of a previously validated user - simeon */
3350 /* With share level security vuid will always be zero.
3351 Don't depend on vuser being non-null !!. JRA */
3352 user_struct *vuser = get_valid_user_struct(vuid);
3354 DEBUG(3,(" Username of UID %d is %s\n",
3355 (int)vuser->server_info->utok.uid,
3356 vuser->server_info->unix_name));
3359 if (!str1 || !str2 || !UserName || !p) {
3364 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3369 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3371 /* check it's a supported variant */
3372 if (strcmp(str1,"zWrLh") != 0) {
3376 case 0: level_string = "B21"; break;
3377 case 1: level_string = "B21BB16DWzzWz"; break;
3378 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3379 case 10: level_string = "B21Bzzz"; break;
3380 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3381 default: return False;
3384 if (strcmp(level_string,str2) != 0) {
3388 *rdata_len = mdrcnt + 1024;
3389 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3394 SSVAL(*rparam,0,NERR_Success);
3395 SSVAL(*rparam,2,0); /* converter word */
3398 endp = *rdata + *rdata_len;
3399 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3405 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3408 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3413 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3414 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3415 p2 = skip_string(*rdata,*rdata_len,p2);
3420 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3421 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3422 p2 = skip_string(*rdata,*rdata_len,p2);
3427 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3428 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3429 strlcpy(p2,((vuser != NULL)
3430 ? pdb_get_fullname(vuser->server_info->sam_account)
3431 : UserName),PTR_DIFF(endp,p2));
3432 p2 = skip_string(*rdata,*rdata_len,p2);
3439 const char *homedir = "";
3440 if (vuser != NULL) {
3441 homedir = pdb_get_homedir(
3442 vuser->server_info->sam_account);
3444 /* modelled after NTAS 3.51 reply */
3445 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3446 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3447 SIVALS(p,usri11_password_age,-1); /* password age */
3448 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3449 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3450 p2 = skip_string(*rdata,*rdata_len,p2);
3454 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3455 strlcpy(p2,"",PTR_DIFF(endp,p2));
3456 p2 = skip_string(*rdata,*rdata_len,p2);
3460 SIVAL(p,usri11_last_logon,0); /* last logon */
3461 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3462 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3463 SSVALS(p,usri11_num_logons,-1); /* num logons */
3464 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3465 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3466 p2 = skip_string(*rdata,*rdata_len,p2);
3470 SSVAL(p,usri11_country_code,0); /* country code */
3472 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3473 strlcpy(p2,"",PTR_DIFF(endp,p2));
3474 p2 = skip_string(*rdata,*rdata_len,p2);
3479 SIVALS(p,usri11_max_storage,-1); /* max storage */
3480 SSVAL(p,usri11_units_per_week,168); /* units per week */
3481 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3483 /* a simple way to get logon hours at all times. */
3485 SCVAL(p2,21,0); /* fix zero termination */
3486 p2 = skip_string(*rdata,*rdata_len,p2);
3491 SSVAL(p,usri11_code_page,0); /* code page */
3494 if (uLevel == 1 || uLevel == 2) {
3495 memset(p+22,' ',16); /* password */
3496 SIVALS(p,38,-1); /* password age */
3498 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3499 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3500 strlcpy(p2, vuser ? pdb_get_homedir(
3501 vuser->server_info->sam_account) : "",
3503 p2 = skip_string(*rdata,*rdata_len,p2);
3507 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3509 SSVAL(p,52,0); /* flags */
3510 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3511 strlcpy(p2, vuser ? pdb_get_logon_script(
3512 vuser->server_info->sam_account) : "",
3514 p2 = skip_string(*rdata,*rdata_len,p2);
3519 SIVAL(p,60,0); /* auth_flags */
3520 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3521 strlcpy(p2,((vuser != NULL)
3522 ? pdb_get_fullname(vuser->server_info->sam_account)
3523 : UserName),PTR_DIFF(endp,p2));
3524 p2 = skip_string(*rdata,*rdata_len,p2);
3528 SIVAL(p,68,0); /* urs_comment */
3529 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3530 strlcpy(p2,"",PTR_DIFF(endp,p2));
3531 p2 = skip_string(*rdata,*rdata_len,p2);
3535 SIVAL(p,76,0); /* workstations */
3536 SIVAL(p,80,0); /* last_logon */
3537 SIVAL(p,84,0); /* last_logoff */
3538 SIVALS(p,88,-1); /* acct_expires */
3539 SIVALS(p,92,-1); /* max_storage */
3540 SSVAL(p,96,168); /* units_per_week */
3541 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3544 SSVALS(p,102,-1); /* bad_pw_count */
3545 SSVALS(p,104,-1); /* num_logons */
3546 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3548 TALLOC_CTX *ctx = talloc_tos();
3549 int space_rem = *rdata_len - (p2 - *rdata);
3552 if (space_rem <= 0) {
3555 tmp = talloc_strdup(ctx, "\\\\%L");
3559 tmp = talloc_sub_basic(ctx,
3572 p2 = skip_string(*rdata,*rdata_len,p2);
3576 SSVAL(p,110,49); /* country_code */
3577 SSVAL(p,112,860); /* code page */
3581 *rdata_len = PTR_DIFF(p2,*rdata);
3583 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3588 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3589 char *param, int tpscnt,
3590 char *data, int tdscnt,
3591 int mdrcnt,int mprcnt,
3592 char **rdata,char **rparam,
3593 int *rdata_len,int *rparam_len)
3595 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3596 char *str2 = skip_string(param,tpscnt,str1);
3597 char *p = skip_string(param,tpscnt,str2);
3599 struct pack_desc desc;
3601 /* With share level security vuid will always be zero.
3602 Don't depend on vuser being non-null !!. JRA */
3603 user_struct *vuser = get_valid_user_struct(vuid);
3605 if (!str1 || !str2 || !p) {
3610 DEBUG(3,(" Username of UID %d is %s\n",
3611 (int)vuser->server_info->utok.uid,
3612 vuser->server_info->unix_name));
3615 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3616 name = get_safe_str_ptr(param,tpscnt,p,2);
3621 memset((char *)&desc,'\0',sizeof(desc));
3623 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3625 /* check it's a supported varient */
3626 if (strcmp(str1,"OOWb54WrLh") != 0) {
3629 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3633 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3640 desc.buflen = mdrcnt;
3641 desc.subformat = NULL;
3644 if (init_package(&desc,1,0)) {
3645 PACKI(&desc,"W",0); /* code */
3646 PACKS(&desc,"B21",name); /* eff. name */
3647 PACKS(&desc,"B",""); /* pad */
3648 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3649 PACKI(&desc,"D",0); /* auth flags XXX */
3650 PACKI(&desc,"W",0); /* num logons */
3651 PACKI(&desc,"W",0); /* bad pw count */
3652 PACKI(&desc,"D",0); /* last logon */
3653 PACKI(&desc,"D",-1); /* last logoff */
3654 PACKI(&desc,"D",-1); /* logoff time */
3655 PACKI(&desc,"D",-1); /* kickoff time */
3656 PACKI(&desc,"D",0); /* password age */
3657 PACKI(&desc,"D",0); /* password can change */
3658 PACKI(&desc,"D",-1); /* password must change */
3662 fstrcpy(mypath,"\\\\");
3663 fstrcat(mypath,get_local_machine_name());
3665 PACKS(&desc,"z",mypath); /* computer */
3668 PACKS(&desc,"z",lp_workgroup());/* domain */
3669 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3670 vuser->server_info->sam_account) : ""); /* script path */
3671 PACKI(&desc,"D",0x00000000); /* reserved */
3674 *rdata_len = desc.usedlen;
3676 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3680 SSVALS(*rparam,0,desc.errcode);
3682 SSVAL(*rparam,4,desc.neededlen);
3684 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3689 /****************************************************************************
3690 api_WAccessGetUserPerms
3691 ****************************************************************************/
3693 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3694 char *param, int tpscnt,
3695 char *data, int tdscnt,
3696 int mdrcnt,int mprcnt,
3697 char **rdata,char **rparam,
3698 int *rdata_len,int *rparam_len)
3700 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3701 char *str2 = skip_string(param,tpscnt,str1);
3702 char *user = skip_string(param,tpscnt,str2);
3703 char *resource = skip_string(param,tpscnt,user);
3705 if (!str1 || !str2 || !user || !resource) {
3709 if (skip_string(param,tpscnt,resource) == NULL) {
3712 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3714 /* check it's a supported varient */
3715 if (strcmp(str1,"zzh") != 0) {
3718 if (strcmp(str2,"") != 0) {
3723 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3727 SSVALS(*rparam,0,0); /* errorcode */
3728 SSVAL(*rparam,2,0); /* converter word */
3729 SSVAL(*rparam,4,0x7f); /* permission flags */
3734 /****************************************************************************
3735 api_WPrintJobEnumerate
3736 ****************************************************************************/
3738 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3739 char *param, int tpscnt,
3740 char *data, int tdscnt,
3741 int mdrcnt,int mprcnt,
3742 char **rdata,char **rparam,
3743 int *rdata_len,int *rparam_len)
3745 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3746 char *str2 = skip_string(param,tpscnt,str1);
3747 char *p = skip_string(param,tpscnt,str2);
3754 struct pack_desc desc;
3755 print_queue_struct *queue=NULL;
3756 print_status_struct status;
3759 if (!str1 || !str2 || !p) {
3763 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3765 memset((char *)&desc,'\0',sizeof(desc));
3766 memset((char *)&status,'\0',sizeof(status));
3768 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3770 /* check it's a supported varient */
3771 if (strcmp(str1,"WWrLh") != 0) {
3774 if (!check_printjob_info(&desc,uLevel,str2)) {
3778 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3782 snum = lp_servicenumber( sharename);
3783 if (snum < 0 || !VALID_SNUM(snum)) {
3787 count = print_queue_status(snum,&queue,&status);
3788 for (i = 0; i < count; i++) {
3789 if (queue[i].job == jobid) {
3795 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3800 desc.buflen = mdrcnt;
3803 * Don't return data but need to get correct length
3804 * init_package will return wrong size if buflen=0
3806 desc.buflen = getlen(desc.format);
3807 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3810 if (init_package(&desc,1,0)) {
3812 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3813 *rdata_len = desc.usedlen;
3815 desc.errcode = NERR_JobNotFound;
3821 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3825 SSVALS(*rparam,0,desc.errcode);
3827 SSVAL(*rparam,4,desc.neededlen);
3832 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3837 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3838 char *param, int tpscnt,
3839 char *data, int tdscnt,
3840 int mdrcnt,int mprcnt,
3841 char **rdata,char **rparam,
3842 int *rdata_len,int *rparam_len)
3844 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3845 char *str2 = skip_string(param,tpscnt,str1);
3846 char *p = skip_string(param,tpscnt,str2);
3852 struct pack_desc desc;
3853 print_queue_struct *queue=NULL;
3854 print_status_struct status;
3856 if (!str1 || !str2 || !p) {
3860 memset((char *)&desc,'\0',sizeof(desc));
3861 memset((char *)&status,'\0',sizeof(status));
3863 p = skip_string(param,tpscnt,p);
3867 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3869 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3871 /* check it's a supported variant */
3872 if (strcmp(str1,"zWrLeh") != 0) {
3877 return False; /* defined only for uLevel 0,1,2 */
3880 if (!check_printjob_info(&desc,uLevel,str2)) {
3884 snum = find_service(name);
3885 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3889 count = print_queue_status(snum,&queue,&status);
3891 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3897 desc.buflen = mdrcnt;
3899 if (init_package(&desc,count,0)) {
3901 for (i = 0; i < count; i++) {
3902 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3903 if (desc.errcode == NERR_Success) {
3909 *rdata_len = desc.usedlen;
3912 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3916 SSVALS(*rparam,0,desc.errcode);
3918 SSVAL(*rparam,4,succnt);
3919 SSVAL(*rparam,6,count);
3923 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3928 static int check_printdest_info(struct pack_desc* desc,
3929 int uLevel, char* id)
3931 desc->subformat = NULL;
3934 desc->format = "B9";
3937 desc->format = "B9B21WWzW";
3943 desc->format = "zzzWWzzzWW";
3946 DEBUG(0,("check_printdest_info: invalid level %d\n",
3950 if (id == NULL || strcmp(desc->format,id) != 0) {
3951 DEBUG(0,("check_printdest_info: invalid string %s\n",
3952 id ? id : "<NULL>" ));
3958 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3959 struct pack_desc* desc)
3963 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3964 buf[sizeof(buf)-1] = 0;
3968 PACKS(desc,"B9",buf); /* szName */
3970 PACKS(desc,"B21",""); /* szUserName */
3971 PACKI(desc,"W",0); /* uJobId */
3972 PACKI(desc,"W",0); /* fsStatus */
3973 PACKS(desc,"z",""); /* pszStatus */
3974 PACKI(desc,"W",0); /* time */
3978 if (uLevel == 2 || uLevel == 3) {
3979 PACKS(desc,"z",buf); /* pszPrinterName */
3981 PACKS(desc,"z",""); /* pszUserName */
3982 PACKS(desc,"z",""); /* pszLogAddr */
3983 PACKI(desc,"W",0); /* uJobId */
3984 PACKI(desc,"W",0); /* fsStatus */
3985 PACKS(desc,"z",""); /* pszStatus */
3986 PACKS(desc,"z",""); /* pszComment */
3987 PACKS(desc,"z","NULL"); /* pszDrivers */
3988 PACKI(desc,"W",0); /* time */
3989 PACKI(desc,"W",0); /* pad1 */
3994 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3995 char *param, int tpscnt,
3996 char *data, int tdscnt,
3997 int mdrcnt,int mprcnt,
3998 char **rdata,char **rparam,
3999 int *rdata_len,int *rparam_len)
4001 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4002 char *str2 = skip_string(param,tpscnt,str1);
4003 char *p = skip_string(param,tpscnt,str2);
4004 char* PrinterName = p;
4006 struct pack_desc desc;
4010 if (!str1 || !str2 || !p) {
4014 memset((char *)&desc,'\0',sizeof(desc));
4016 p = skip_string(param,tpscnt,p);
4020 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4022 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4024 /* check it's a supported varient */
4025 if (strcmp(str1,"zWrLh") != 0) {
4028 if (!check_printdest_info(&desc,uLevel,str2)) {
4032 snum = find_service(PrinterName);
4033 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4035 desc.errcode = NERR_DestNotFound;
4039 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4044 desc.buflen = mdrcnt;
4047 * Don't return data but need to get correct length
4048 * init_package will return wrong size if buflen=0
4050 desc.buflen = getlen(desc.format);
4051 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4053 if (init_package(&desc,1,0)) {
4054 fill_printdest_info(conn,snum,uLevel,&desc);
4056 *rdata_len = desc.usedlen;
4060 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4064 SSVALS(*rparam,0,desc.errcode);
4066 SSVAL(*rparam,4,desc.neededlen);
4068 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4074 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4075 char *param, int tpscnt,
4076 char *data, int tdscnt,
4077 int mdrcnt,int mprcnt,
4078 char **rdata,char **rparam,
4079 int *rdata_len,int *rparam_len)
4081 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4082 char *str2 = skip_string(param,tpscnt,str1);
4083 char *p = skip_string(param,tpscnt,str2);
4087 struct pack_desc desc;
4088 int services = lp_numservices();
4090 if (!str1 || !str2 || !p) {
4094 memset((char *)&desc,'\0',sizeof(desc));
4096 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4098 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4100 /* check it's a supported varient */
4101 if (strcmp(str1,"WrLeh") != 0) {
4104 if (!check_printdest_info(&desc,uLevel,str2)) {
4109 for (i = 0; i < services; i++) {
4110 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4116 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4123 desc.buflen = mdrcnt;
4124 if (init_package(&desc,queuecnt,0)) {
4127 for (i = 0; i < services; i++) {
4128 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4129 fill_printdest_info(conn,i,uLevel,&desc);
4131 if (desc.errcode == NERR_Success) {
4138 *rdata_len = desc.usedlen;
4141 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4145 SSVALS(*rparam,0,desc.errcode);
4147 SSVAL(*rparam,4,succnt);
4148 SSVAL(*rparam,6,queuecnt);
4150 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4155 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4156 char *param, int tpscnt,
4157 char *data, int tdscnt,
4158 int mdrcnt,int mprcnt,
4159 char **rdata,char **rparam,
4160 int *rdata_len,int *rparam_len)
4162 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4163 char *str2 = skip_string(param,tpscnt,str1);
4164 char *p = skip_string(param,tpscnt,str2);
4167 struct pack_desc desc;
4169 if (!str1 || !str2 || !p) {
4173 memset((char *)&desc,'\0',sizeof(desc));
4175 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4177 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4179 /* check it's a supported varient */
4180 if (strcmp(str1,"WrLeh") != 0) {
4183 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4188 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4194 desc.buflen = mdrcnt;
4195 if (init_package(&desc,1,0)) {
4196 PACKS(&desc,"B41","NULL");
4199 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4201 *rdata_len = desc.usedlen;
4204 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4208 SSVALS(*rparam,0,desc.errcode);
4210 SSVAL(*rparam,4,succnt);
4213 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4218 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4219 char *param, int tpscnt,
4220 char *data, int tdscnt,
4221 int mdrcnt,int mprcnt,
4222 char **rdata,char **rparam,
4223 int *rdata_len,int *rparam_len)
4225 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4226 char *str2 = skip_string(param,tpscnt,str1);
4227 char *p = skip_string(param,tpscnt,str2);
4230 struct pack_desc desc;
4232 if (!str1 || !str2 || !p) {
4235 memset((char *)&desc,'\0',sizeof(desc));
4237 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4239 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4241 /* check it's a supported varient */
4242 if (strcmp(str1,"WrLeh") != 0) {
4245 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4250 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4256 desc.buflen = mdrcnt;
4258 if (init_package(&desc,1,0)) {
4259 PACKS(&desc,"B13","lpd");
4262 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4264 *rdata_len = desc.usedlen;
4267 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4271 SSVALS(*rparam,0,desc.errcode);
4273 SSVAL(*rparam,4,succnt);
4276 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4281 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4282 char *param, int tpscnt,
4283 char *data, int tdscnt,
4284 int mdrcnt,int mprcnt,
4285 char **rdata,char **rparam,
4286 int *rdata_len,int *rparam_len)
4288 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4289 char *str2 = skip_string(param,tpscnt,str1);
4290 char *p = skip_string(param,tpscnt,str2);
4293 struct pack_desc desc;
4295 if (!str1 || !str2 || !p) {
4299 memset((char *)&desc,'\0',sizeof(desc));
4301 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4303 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4305 /* check it's a supported varient */
4306 if (strcmp(str1,"WrLeh") != 0) {
4309 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4314 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4319 memset((char *)&desc,'\0',sizeof(desc));
4321 desc.buflen = mdrcnt;
4323 if (init_package(&desc,1,0)) {
4324 PACKS(&desc,"B13","lp0");
4327 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4329 *rdata_len = desc.usedlen;
4332 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4336 SSVALS(*rparam,0,desc.errcode);
4338 SSVAL(*rparam,4,succnt);
4341 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4346 /****************************************************************************
4348 ****************************************************************************/
4350 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4351 char *param, int tpscnt,
4352 char *data, int tdscnt,
4353 int mdrcnt,int mprcnt,
4354 char **rdata,char **rparam,
4355 int *rdata_len,int *rparam_len)
4358 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4359 char *str2 = skip_string(param,tpscnt,str1);
4360 char *p = skip_string(param,tpscnt,str2);
4362 struct pack_desc desc;
4363 struct sessionid *session_list;
4364 int i, num_sessions;
4366 if (!str1 || !str2 || !p) {
4370 memset((char *)&desc,'\0',sizeof(desc));
4372 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4374 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4375 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4376 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4378 /* check it's a supported varient */
4379 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4382 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4386 num_sessions = list_sessions(talloc_tos(), &session_list);
4389 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4394 memset((char *)&desc,'\0',sizeof(desc));
4396 desc.buflen = mdrcnt;
4398 if (!init_package(&desc,num_sessions,0)) {
4402 for(i=0; i<num_sessions; i++) {
4403 PACKS(&desc, "z", session_list[i].remote_machine);
4404 PACKS(&desc, "z", session_list[i].username);
4405 PACKI(&desc, "W", 1); /* num conns */
4406 PACKI(&desc, "W", 0); /* num opens */
4407 PACKI(&desc, "W", 1); /* num users */
4408 PACKI(&desc, "D", 0); /* session time */
4409 PACKI(&desc, "D", 0); /* idle time */
4410 PACKI(&desc, "D", 0); /* flags */
4411 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4414 *rdata_len = desc.usedlen;
4417 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4421 SSVALS(*rparam,0,desc.errcode);
4422 SSVAL(*rparam,2,0); /* converter */
4423 SSVAL(*rparam,4,num_sessions); /* count */
4425 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4431 /****************************************************************************
4432 The buffer was too small.
4433 ****************************************************************************/
4435 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4436 int mdrcnt, int mprcnt,
4437 char **rdata, char **rparam,
4438 int *rdata_len, int *rparam_len)
4440 *rparam_len = MIN(*rparam_len,mprcnt);
4441 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4448 SSVAL(*rparam,0,NERR_BufTooSmall);
4450 DEBUG(3,("Supplied buffer too small in API command\n"));
4455 /****************************************************************************
4456 The request is not supported.
4457 ****************************************************************************/
4459 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4460 char *param, int tpscnt,
4461 char *data, int tdscnt,
4462 int mdrcnt, int mprcnt,
4463 char **rdata, char **rparam,
4464 int *rdata_len, int *rparam_len)
4467 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4474 SSVAL(*rparam,0,NERR_notsupported);
4475 SSVAL(*rparam,2,0); /* converter word */
4477 DEBUG(3,("Unsupported API command\n"));
4482 static const struct {
4485 bool (*fn)(connection_struct *, uint16,
4488 int,int,char **,char **,int *,int *);
4489 bool auth_user; /* Deny anonymous access? */
4490 } api_commands[] = {
4491 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4492 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4493 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4494 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4495 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4496 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4497 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4498 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4499 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4500 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4501 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4502 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4503 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4504 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4505 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4506 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4507 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4508 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4509 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4510 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4511 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4512 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4513 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4514 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4515 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4516 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4517 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4518 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4519 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4520 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4521 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4522 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4523 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4524 {NULL, -1, api_Unsupported}
4525 /* The following RAP calls are not implemented by Samba:
4527 RAP_WFileEnum2 - anon not OK
4532 /****************************************************************************
4533 Handle remote api calls.
4534 ****************************************************************************/
4536 void api_reply(connection_struct *conn, uint16 vuid,
4537 struct smb_request *req,
4538 char *data, char *params,
4539 int tdscnt, int tpscnt,
4540 int mdrcnt, int mprcnt)
4544 char *rparam = NULL;
4545 const char *name1 = NULL;
4546 const char *name2 = NULL;
4553 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4554 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4559 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4562 api_command = SVAL(params,0);
4563 /* Is there a string at position params+2 ? */
4564 if (skip_string(params,tpscnt,params+2)) {
4569 name2 = skip_string(params,tpscnt,params+2);
4574 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4578 tdscnt,tpscnt,mdrcnt,mprcnt));
4580 for (i=0;api_commands[i].name;i++) {
4581 if (api_commands[i].id == api_command && api_commands[i].fn) {
4582 DEBUG(3,("Doing %s\n",api_commands[i].name));
4587 /* Check whether this api call can be done anonymously */
4589 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4590 user_struct *user = get_valid_user_struct(vuid);
4592 if (!user || user->server_info->guest) {
4593 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4598 rdata = (char *)SMB_MALLOC(1024);
4600 memset(rdata,'\0',1024);
4603 rparam = (char *)SMB_MALLOC(1024);
4605 memset(rparam,'\0',1024);
4608 if(!rdata || !rparam) {
4609 DEBUG(0,("api_reply: malloc fail !\n"));
4612 reply_nterror(req, NT_STATUS_NO_MEMORY);
4616 reply = api_commands[i].fn(conn,
4618 params,tpscnt, /* params + length */
4619 data,tdscnt, /* data + length */
4621 &rdata,&rparam,&rdata_len,&rparam_len);
4624 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4625 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4626 &rdata,&rparam,&rdata_len,&rparam_len);
4629 /* if we get False back then it's actually unsupported */
4631 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4632 &rdata,&rparam,&rdata_len,&rparam_len);
4635 /* If api_Unsupported returns false we can't return anything. */
4637 send_trans_reply(conn, req, rparam, rparam_len,
4638 rdata, rdata_len, False);