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;
31 extern userdom_struct current_user_info;
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
51 #define SHPWLEN 8 /* share password length */
53 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
54 char *param, int tpscnt,
55 char *data, int tdscnt,
56 int mdrcnt, int mprcnt,
57 char **rdata, char **rparam,
58 int *rdata_len, int *rparam_len);
60 static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
61 int mdrcnt, int mprcnt,
62 char **rdata, char **rparam,
63 int *rdata_len, int *rparam_len);
66 static int CopyExpanded(connection_struct *conn,
67 int snum, char **dst, char *src, int *n)
72 if (!src || !dst || !n || !(*dst)) {
76 StrnCpy(buf,src,sizeof(buf)/2);
77 pstring_sub(buf,"%S",lp_servicename(snum));
78 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
79 conn->connectpath, conn->gid,
80 get_current_username(),
81 current_user_info.domain,
83 l = push_ascii(*dst,buf,*n, STR_TERMINATE);
89 static int CopyAndAdvance(char **dst, char *src, int *n)
92 if (!src || !dst || !n || !(*dst)) {
95 l = push_ascii(*dst,src,*n, STR_TERMINATE);
101 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
107 StrnCpy(buf,s,sizeof(buf)/2);
108 pstring_sub(buf,"%S",lp_servicename(snum));
109 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
110 conn->connectpath, conn->gid,
111 get_current_username(),
112 current_user_info.domain,
114 return strlen(buf) + 1;
117 static char *Expand(connection_struct *conn, int snum, char *s)
123 StrnCpy(buf,s,sizeof(buf)/2);
124 pstring_sub(buf,"%S",lp_servicename(snum));
125 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
126 conn->connectpath, conn->gid,
127 get_current_username(),
128 current_user_info.domain,
133 /*******************************************************************
134 Check a API string for validity when we only need to check the prefix.
135 ******************************************************************/
137 static BOOL prefix_ok(const char *str, const char *prefix)
139 return(strncmp(str,prefix,strlen(prefix)) == 0);
143 const char *format; /* formatstring for structure */
144 const char *subformat; /* subformat for structure */
145 char *base; /* baseaddress of buffer */
146 int buflen; /* remaining size for fixed part; on init: length of base */
147 int subcount; /* count of substructures */
148 char *structbuf; /* pointer into buffer for remaining fixed part */
149 int stringlen; /* remaining size for variable part */
150 char *stringbuf; /* pointer into buffer for remaining variable part */
151 int neededlen; /* total needed size */
152 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
153 const char *curpos; /* current position; pointer into format or subformat */
157 static int get_counter(const char **p)
163 if (!isdigit((int)**p)) {
169 n = 10 * n + (i - '0');
177 static int getlen(const char *p)
186 case 'W': /* word (2 byte) */
189 case 'K': /* status word? (2 byte) */
192 case 'N': /* count of substructures (word) at end */
195 case 'D': /* double word (4 byte) */
196 case 'z': /* offset to zero terminated string (4 byte) */
197 case 'l': /* offset to user data (4 byte) */
200 case 'b': /* offset to data (with counter) (4 byte) */
204 case 'B': /* byte (with optional counter) */
205 n += get_counter(&p);
212 static BOOL init_package(struct pack_desc *p, int count, int subcount)
217 if (!p->format || !p->base) {
221 i = count * getlen(p->format);
223 i += subcount * getlen(p->subformat);
225 p->structbuf = p->base;
229 p->curpos = p->format;
235 * This is the old error code we used. Aparently
236 * WinNT/2k systems return ERRbuftoosmall (2123) and
237 * OS/2 needs this. I'm leaving this here so we can revert
240 p->errcode = ERRmoredata;
242 p->errcode = ERRbuftoosmall;
245 p->errcode = NERR_Success;
249 p->stringbuf = p->base + i;
251 return (p->errcode == NERR_Success);
254 static int package(struct pack_desc *p, ...)
257 int needed=0, stringneeded;
258 const char *str=NULL;
259 int is_string=0, stringused;
266 p->curpos = p->format;
268 p->curpos = p->subformat;
273 str = va_arg(args,char*);
274 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
283 switch( *p->curpos++ ) {
284 case 'W': /* word (2 byte) */
286 temp = va_arg(args,int);
287 if (p->buflen >= needed) {
288 SSVAL(p->structbuf,0,temp);
291 case 'K': /* status word? (2 byte) */
293 temp = va_arg(args,int);
294 if (p->buflen >= needed) {
295 SSVAL(p->structbuf,0,temp);
298 case 'N': /* count of substructures (word) at end */
300 p->subcount = va_arg(args,int);
301 if (p->buflen >= needed) {
302 SSVAL(p->structbuf,0,p->subcount);
305 case 'D': /* double word (4 byte) */
307 temp = va_arg(args,int);
308 if (p->buflen >= needed) {
309 SIVAL(p->structbuf,0,temp);
312 case 'B': /* byte (with optional counter) */
313 needed = get_counter(&p->curpos);
315 char *s = va_arg(args,char*);
316 if (p->buflen >= needed) {
317 StrnCpy(p->structbuf,s?s:"",needed-1);
321 case 'z': /* offset to zero terminated string (4 byte) */
322 str = va_arg(args,char*);
323 stringneeded = (str ? strlen(str)+1 : 0);
326 case 'l': /* offset to user data (4 byte) */
327 str = va_arg(args,char*);
328 stringneeded = va_arg(args,int);
331 case 'b': /* offset to data (with counter) (4 byte) */
332 str = va_arg(args,char*);
333 stringneeded = get_counter(&p->curpos);
339 if (stringneeded >= 0) {
341 if (p->buflen >= needed) {
342 stringused = stringneeded;
343 if (stringused > p->stringlen) {
344 stringused = (is_string ? p->stringlen : 0);
345 if (p->errcode == NERR_Success) {
346 p->errcode = ERRmoredata;
350 SIVAL(p->structbuf,0,0);
352 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
353 memcpy(p->stringbuf,str?str:"",stringused);
355 p->stringbuf[stringused-1] = '\0';
357 p->stringbuf += stringused;
358 p->stringlen -= stringused;
359 p->usedlen += stringused;
362 p->neededlen += stringneeded;
365 p->neededlen += needed;
366 if (p->buflen >= needed) {
367 p->structbuf += needed;
369 p->usedlen += needed;
371 if (p->errcode == NERR_Success) {
372 p->errcode = ERRmoredata;
379 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
380 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
382 #define PACK(desc,t,v) package(desc,v)
383 #define PACKl(desc,t,v,l) package(desc,v,l)
386 static void PACKI(struct pack_desc* desc, const char *t,int v)
391 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
396 /****************************************************************************
398 ****************************************************************************/
400 static void PackDriverData(struct pack_desc* desc)
402 char drivdata[4+4+32];
403 SIVAL(drivdata,0,sizeof drivdata); /* cb */
404 SIVAL(drivdata,4,1000); /* lVersion */
405 memset(drivdata+8,0,32); /* szDeviceName */
406 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
407 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
410 static int check_printq_info(struct pack_desc* desc,
411 unsigned int uLevel, char *id1, char *id2)
413 desc->subformat = NULL;
416 desc->format = "B13";
419 desc->format = "B13BWWWzzzzzWW";
422 desc->format = "B13BWWWzzzzzWN";
423 desc->subformat = "WB21BB16B10zWWzDDz";
426 desc->format = "zWWWWzzzzWWzzl";
429 desc->format = "zWWWWzzzzWNzzl";
430 desc->subformat = "WWzWWDDzz";
439 desc->format = "WzzzzzzzzN";
440 desc->subformat = "z";
443 DEBUG(0,("check_printq_info: invalid level %d\n",
447 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
448 DEBUG(0,("check_printq_info: invalid format %s\n",
449 id1 ? id1 : "<NULL>" ));
452 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
453 DEBUG(0,("check_printq_info: invalid subformat %s\n",
454 id2 ? id2 : "<NULL>" ));
461 #define RAP_JOB_STATUS_QUEUED 0
462 #define RAP_JOB_STATUS_PAUSED 1
463 #define RAP_JOB_STATUS_SPOOLING 2
464 #define RAP_JOB_STATUS_PRINTING 3
465 #define RAP_JOB_STATUS_PRINTED 4
467 #define RAP_QUEUE_STATUS_PAUSED 1
468 #define RAP_QUEUE_STATUS_ERROR 2
470 /* turn a print job status into a on the wire status
472 static int printj_status(int v)
476 return RAP_JOB_STATUS_QUEUED;
478 return RAP_JOB_STATUS_PAUSED;
480 return RAP_JOB_STATUS_SPOOLING;
482 return RAP_JOB_STATUS_PRINTING;
487 /* turn a print queue status into a on the wire status
489 static int printq_status(int v)
495 return RAP_QUEUE_STATUS_PAUSED;
497 return RAP_QUEUE_STATUS_ERROR;
500 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
501 struct pack_desc *desc,
502 print_queue_struct *queue, int n)
504 time_t t = queue->time;
506 /* the client expects localtime */
507 t -= get_time_zone(t);
509 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
511 PACKS(desc,"B21",queue->fs_user); /* szUserName */
512 PACKS(desc,"B",""); /* pad */
513 PACKS(desc,"B16",""); /* szNotifyName */
514 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
515 PACKS(desc,"z",""); /* pszParms */
516 PACKI(desc,"W",n+1); /* uPosition */
517 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
518 PACKS(desc,"z",""); /* pszStatus */
519 PACKI(desc,"D",t); /* ulSubmitted */
520 PACKI(desc,"D",queue->size); /* ulSize */
521 PACKS(desc,"z",queue->fs_file); /* pszComment */
523 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
524 PACKI(desc,"W",queue->priority); /* uPriority */
525 PACKS(desc,"z",queue->fs_user); /* pszUserName */
526 PACKI(desc,"W",n+1); /* uPosition */
527 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
528 PACKI(desc,"D",t); /* ulSubmitted */
529 PACKI(desc,"D",queue->size); /* ulSize */
530 PACKS(desc,"z","Samba"); /* pszComment */
531 PACKS(desc,"z",queue->fs_file); /* pszDocument */
533 PACKS(desc,"z",""); /* pszNotifyName */
534 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
535 PACKS(desc,"z",""); /* pszParms */
536 PACKS(desc,"z",""); /* pszStatus */
537 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
538 PACKS(desc,"z","lpd"); /* pszQProcName */
539 PACKS(desc,"z",""); /* pszQProcParms */
540 PACKS(desc,"z","NULL"); /* pszDriverName */
541 PackDriverData(desc); /* pDriverData */
542 PACKS(desc,"z",""); /* pszPrinterName */
543 } else if (uLevel == 4) { /* OS2 */
544 PACKS(desc,"z",""); /* pszSpoolFileName */
545 PACKS(desc,"z",""); /* pszPortName */
546 PACKS(desc,"z",""); /* pszStatus */
547 PACKI(desc,"D",0); /* ulPagesSpooled */
548 PACKI(desc,"D",0); /* ulPagesSent */
549 PACKI(desc,"D",0); /* ulPagesPrinted */
550 PACKI(desc,"D",0); /* ulTimePrinted */
551 PACKI(desc,"D",0); /* ulExtendJobStatus */
552 PACKI(desc,"D",0); /* ulStartPage */
553 PACKI(desc,"D",0); /* ulEndPage */
558 /********************************************************************
559 Return a driver name given an snum.
560 Returns True if from tdb, False otherwise.
561 ********************************************************************/
563 static BOOL get_driver_name(int snum, pstring drivername)
565 NT_PRINTER_INFO_LEVEL *info = NULL;
568 get_a_printer (NULL, &info, 2, lp_servicename(snum));
570 pstrcpy( drivername, info->info_2->drivername);
572 free_a_printer(&info, 2);
578 /********************************************************************
579 Respond to the DosPrintQInfo command with a level of 52
580 This is used to get printer driver information for Win9x clients
581 ********************************************************************/
582 static void fill_printq_info_52(connection_struct *conn, int snum,
583 struct pack_desc* desc, int count )
587 NT_PRINTER_DRIVER_INFO_LEVEL driver;
588 NT_PRINTER_INFO_LEVEL *printer = NULL;
592 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
593 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
594 lp_servicename(snum)));
598 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
601 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
602 printer->info_2->drivername));
606 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
607 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
608 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
610 PACKI(desc, "W", 0x0400); /* don't know */
611 PACKS(desc, "z", driver.info_3->name); /* long printer name */
612 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
613 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
614 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
616 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
617 standard_sub_basic( "", "", location, sizeof(location)-1 );
618 PACKS(desc,"z", location); /* share to retrieve files */
620 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
621 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
622 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
624 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
625 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
626 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
627 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
628 DEBUG(3,("Driver Location: %s:\n",location));
629 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
630 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
631 PACKI(desc,"N",count); /* number of files to copy */
633 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
635 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
636 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
637 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
642 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
645 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
647 desc->errcode=NERR_Success;
651 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
652 desc->errcode=NERR_notsupported;
656 free_a_printer( &printer, 2 );
659 free_a_printer_driver( driver, 3 );
663 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
664 struct pack_desc* desc,
665 int count, print_queue_struct* queue,
666 print_status_struct* status)
671 PACKS(desc,"B13",SERVICE(snum));
676 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
679 PACKI(desc,"K",printq_status(status->status));
683 if (uLevel == 1 || uLevel == 2) {
684 PACKS(desc,"B",""); /* alignment */
685 PACKI(desc,"W",5); /* priority */
686 PACKI(desc,"W",0); /* start time */
687 PACKI(desc,"W",0); /* until time */
688 PACKS(desc,"z",""); /* pSepFile */
689 PACKS(desc,"z","lpd"); /* pPrProc */
690 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
691 PACKS(desc,"z",""); /* pParms */
693 PACKS(desc,"z","UNKNOWN PRINTER");
694 PACKI(desc,"W",LPSTAT_ERROR);
696 else if (!status || !status->message[0]) {
697 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
698 PACKI(desc,"W",LPSTAT_OK); /* status */
700 PACKS(desc,"z",status->message);
701 PACKI(desc,"W",printq_status(status->status)); /* status */
703 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
706 if (uLevel == 3 || uLevel == 4) {
709 PACKI(desc,"W",5); /* uPriority */
710 PACKI(desc,"W",0); /* uStarttime */
711 PACKI(desc,"W",0); /* uUntiltime */
712 PACKI(desc,"W",5); /* pad1 */
713 PACKS(desc,"z",""); /* pszSepFile */
714 PACKS(desc,"z","WinPrint"); /* pszPrProc */
715 PACKS(desc,"z",NULL); /* pszParms */
716 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
717 /* "don't ask" that it's done this way to fix corrupted
718 Win9X/ME printer comments. */
720 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
722 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
724 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
725 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
726 get_driver_name(snum,drivername);
727 PACKS(desc,"z",drivername); /* pszDriverName */
728 PackDriverData(desc); /* pDriverData */
731 if (uLevel == 2 || uLevel == 4) {
733 for (i=0;i<count;i++)
734 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
738 fill_printq_info_52( conn, snum, desc, count );
741 /* This function returns the number of files for a given driver */
742 static int get_printerdrivernumber(int snum)
745 NT_PRINTER_DRIVER_INFO_LEVEL driver;
746 NT_PRINTER_INFO_LEVEL *printer = NULL;
750 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
751 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
752 lp_servicename(snum)));
756 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
759 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
760 printer->info_2->drivername));
764 /* count the number of files */
765 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
770 free_a_printer( &printer, 2 );
773 free_a_printer_driver( driver, 3 );
778 static BOOL api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
779 char *param, int tpscnt,
780 char *data, int tdscnt,
781 int mdrcnt,int mprcnt,
782 char **rdata,char **rparam,
783 int *rdata_len,int *rparam_len)
785 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
786 char *str2 = skip_string(param,tpscnt,str1);
787 char *p = skip_string(param,tpscnt,str2);
793 struct pack_desc desc;
794 print_queue_struct *queue=NULL;
795 print_status_struct status;
798 if (!str1 || !str2 || !p) {
801 memset((char *)&status,'\0',sizeof(status));
802 memset((char *)&desc,'\0',sizeof(desc));
804 p = skip_string(param,tpscnt,p);
808 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
809 str3 = get_safe_str_ptr(param,tpscnt,p,4);
810 /* str3 may be null here and is checked in check_printq_info(). */
812 /* remove any trailing username */
813 if ((p = strchr_m(QueueName,'%')))
816 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
818 /* check it's a supported varient */
819 if (!prefix_ok(str1,"zWrLh"))
821 if (!check_printq_info(&desc,uLevel,str2,str3)) {
823 * Patch from Scott Moomaw <scott@bridgewater.edu>
824 * to return the 'invalid info level' error if an
825 * unknown level was requested.
829 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
833 SSVALS(*rparam,0,ERRunknownlevel);
839 snum = find_service(QueueName);
840 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
844 count = get_printerdrivernumber(snum);
845 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
847 count = print_queue_status(snum, &queue,&status);
851 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
857 desc.buflen = mdrcnt;
860 * Don't return data but need to get correct length
861 * init_package will return wrong size if buflen=0
863 desc.buflen = getlen(desc.format);
864 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
867 if (init_package(&desc,1,count)) {
868 desc.subcount = count;
869 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
872 *rdata_len = desc.usedlen;
875 * We must set the return code to ERRbuftoosmall
876 * in order to support lanman style printing with Win NT/2k
879 if (!mdrcnt && lp_disable_spoolss())
880 desc.errcode = ERRbuftoosmall;
882 *rdata_len = desc.usedlen;
884 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
890 SSVALS(*rparam,0,desc.errcode);
892 SSVAL(*rparam,4,desc.neededlen);
894 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
902 /****************************************************************************
903 View list of all print jobs on all queues.
904 ****************************************************************************/
906 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
907 char *param, int tpscnt,
908 char *data, int tdscnt,
909 int mdrcnt, int mprcnt,
910 char **rdata, char** rparam,
911 int *rdata_len, int *rparam_len)
913 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
914 char *output_format1 = skip_string(param,tpscnt,param_format);
915 char *p = skip_string(param,tpscnt,output_format1);
916 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
917 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
918 int services = lp_numservices();
920 struct pack_desc desc;
921 print_queue_struct **queue = NULL;
922 print_status_struct *status = NULL;
923 int *subcntarr = NULL;
924 int queuecnt = 0, subcnt = 0, succnt = 0;
926 if (!param_format || !output_format1 || !p) {
930 memset((char *)&desc,'\0',sizeof(desc));
932 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
934 if (!prefix_ok(param_format,"WrLeh")) {
937 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
939 * Patch from Scott Moomaw <scott@bridgewater.edu>
940 * to return the 'invalid info level' error if an
941 * unknown level was requested.
945 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
949 SSVALS(*rparam,0,ERRunknownlevel);
955 for (i = 0; i < services; i++) {
956 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
961 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
962 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
965 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
966 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
967 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
970 memset(status,0,queuecnt*sizeof(print_status_struct));
971 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
972 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
978 for (i = 0; i < services; i++) {
979 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
980 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
981 subcnt += subcntarr[n];
987 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
993 desc.buflen = mdrcnt;
995 if (init_package(&desc,queuecnt,subcnt)) {
998 for (i = 0; i < services; i++) {
999 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1000 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1002 if (desc.errcode == NERR_Success) {
1009 SAFE_FREE(subcntarr);
1011 *rdata_len = desc.usedlen;
1013 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1017 SSVALS(*rparam,0,desc.errcode);
1019 SSVAL(*rparam,4,succnt);
1020 SSVAL(*rparam,6,queuecnt);
1022 for (i = 0; i < queuecnt; i++) {
1024 SAFE_FREE(queue[i]);
1035 SAFE_FREE(subcntarr);
1036 for (i = 0; i < queuecnt; i++) {
1038 SAFE_FREE(queue[i]);
1047 /****************************************************************************
1048 Get info level for a server list query.
1049 ****************************************************************************/
1051 static BOOL check_server_info(int uLevel, char* id)
1055 if (strcmp(id,"B16") != 0) {
1060 if (strcmp(id,"B16BBDz") != 0) {
1070 struct srv_info_struct {
1078 /*******************************************************************
1079 Get server info lists from the files saved by nmbd. Return the
1081 ******************************************************************/
1083 static int get_server_info(uint32 servertype,
1084 struct srv_info_struct **servers,
1090 BOOL local_list_only;
1093 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1095 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1099 /* request for everything is code for request all servers */
1100 if (servertype == SV_TYPE_ALL) {
1101 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1104 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1106 DEBUG(4,("Servertype search: %8x\n",servertype));
1108 for (i=0;lines[i];i++) {
1110 struct srv_info_struct *s;
1111 const char *ptr = lines[i];
1118 if (count == alloced) {
1120 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1122 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1123 file_lines_free(lines);
1126 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1128 s = &(*servers)[count];
1130 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1133 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1136 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1139 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1140 /* this allows us to cope with an old nmbd */
1141 fstrcpy(s->domain,lp_workgroup());
1144 if (sscanf(stype,"%X",&s->type) != 1) {
1145 DEBUG(4,("r:host file "));
1149 /* Filter the servers/domains we return based on what was asked for. */
1151 /* Check to see if we are being asked for a local list only. */
1152 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1153 DEBUG(4,("r: local list only"));
1157 /* doesn't match up: don't want it */
1158 if (!(servertype & s->type)) {
1159 DEBUG(4,("r:serv type "));
1163 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1164 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1165 DEBUG(4,("s: dom mismatch "));
1169 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1173 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1174 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1177 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1178 s->name, s->type, s->comment, s->domain));
1179 s->server_added = True;
1182 DEBUG(4,("%20s %8x %25s %15s\n",
1183 s->name, s->type, s->comment, s->domain));
1187 file_lines_free(lines);
1191 /*******************************************************************
1192 Fill in a server info structure.
1193 ******************************************************************/
1195 static int fill_srv_info(struct srv_info_struct *service,
1196 int uLevel, char **buf, int *buflen,
1197 char **stringbuf, int *stringspace, char *baseaddr)
1220 len = strlen(service->comment)+1;
1224 *buflen = struct_len;
1226 return struct_len + len;
1231 if (*buflen < struct_len) {
1238 p2 = p + struct_len;
1239 l2 = *buflen - struct_len;
1247 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1251 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1252 SIVAL(p,18,service->type);
1253 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1254 len += CopyAndAdvance(&p2,service->comment,&l2);
1259 *buf = p + struct_len;
1260 *buflen -= struct_len;
1271 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1273 return(strcmp(s1->name,s2->name));
1276 /****************************************************************************
1277 View list of servers available (or possibly domains). The info is
1278 extracted from lists saved by nmbd on the local host.
1279 ****************************************************************************/
1281 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1282 char *param, int tpscnt,
1283 char *data, int tdscnt,
1284 int mdrcnt, int mprcnt, char **rdata,
1285 char **rparam, int *rdata_len, int *rparam_len)
1287 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1288 char *str2 = skip_string(param,tpscnt,str1);
1289 char *p = skip_string(param,tpscnt,str2);
1290 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1291 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1292 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1294 int data_len, fixed_len, string_len;
1295 int f_len = 0, s_len = 0;
1296 struct srv_info_struct *servers=NULL;
1297 int counted=0,total=0;
1300 BOOL domain_request;
1303 if (!str1 || !str2 || !p) {
1307 /* If someone sets all the bits they don't really mean to set
1308 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1311 if (servertype == SV_TYPE_ALL) {
1312 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1315 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1316 any other bit (they may just set this bit on it's own) they
1317 want all the locally seen servers. However this bit can be
1318 set on its own so set the requested servers to be
1319 ALL - DOMAIN_ENUM. */
1321 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1322 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1325 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1326 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1330 if (!prefix_ok(str1,"WrLehD")) {
1333 if (!check_server_info(uLevel,str2)) {
1337 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1338 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1339 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1341 if (strcmp(str1, "WrLehDz") == 0) {
1342 if (skip_string(param,tpscnt,p) == NULL) {
1345 pull_ascii_fstring(domain, p);
1347 fstrcpy(domain, lp_workgroup());
1350 if (lp_browse_list()) {
1351 total = get_server_info(servertype,&servers,domain);
1354 data_len = fixed_len = string_len = 0;
1358 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1362 char *lastname=NULL;
1364 for (i=0;i<total;i++) {
1365 struct srv_info_struct *s = &servers[i];
1367 if (lastname && strequal(lastname,s->name)) {
1371 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1372 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1373 s->name, s->type, s->comment, s->domain));
1375 if (data_len <= buf_len) {
1378 string_len += s_len;
1385 *rdata_len = fixed_len + string_len;
1386 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1390 memset(*rdata,'\0',*rdata_len);
1392 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1398 char *lastname=NULL;
1399 int count2 = counted;
1401 for (i = 0; i < total && count2;i++) {
1402 struct srv_info_struct *s = &servers[i];
1404 if (lastname && strequal(lastname,s->name)) {
1408 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1409 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1410 s->name, s->type, s->comment, s->domain));
1416 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1420 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1422 SSVAL(*rparam,4,counted);
1423 SSVAL(*rparam,6,counted+missed);
1427 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1428 domain,uLevel,counted,counted+missed));
1433 /****************************************************************************
1434 command 0x34 - suspected of being a "Lookup Names" stub api
1435 ****************************************************************************/
1437 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1438 char *param, int tpscnt,
1439 char *data, int tdscnt,
1440 int mdrcnt, int mprcnt, char **rdata,
1441 char **rparam, int *rdata_len, int *rparam_len)
1443 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1444 char *str2 = skip_string(param,tpscnt,str1);
1445 char *p = skip_string(param,tpscnt,str2);
1446 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1447 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1451 if (!str1 || !str2 || !p) {
1455 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1456 str1, str2, p, uLevel, buf_len));
1458 if (!prefix_ok(str1,"zWrLeh")) {
1465 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1470 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1472 SSVAL(*rparam,4,counted);
1473 SSVAL(*rparam,6,counted+missed);
1478 /****************************************************************************
1479 get info about a share
1480 ****************************************************************************/
1482 static BOOL check_share_info(int uLevel, char* id)
1486 if (strcmp(id,"B13") != 0) {
1491 if (strcmp(id,"B13BWz") != 0) {
1496 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1501 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1511 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1512 char** buf, int* buflen,
1513 char** stringbuf, int* stringspace, char* baseaddr)
1543 len += StrlenExpanded(conn,snum,lp_comment(snum));
1546 len += strlen(lp_pathname(snum)) + 1;
1549 *buflen = struct_len;
1554 return struct_len + len;
1559 if ((*buflen) < struct_len) {
1567 p2 = p + struct_len;
1568 l2 = (*buflen) - struct_len;
1575 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1581 type = STYPE_DISKTREE;
1582 if (lp_print_ok(snum)) {
1583 type = STYPE_PRINTQ;
1585 if (strequal("IPC",lp_fstype(snum))) {
1588 SSVAL(p,14,type); /* device type */
1589 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1590 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1594 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1595 SSVALS(p,22,-1); /* max uses */
1596 SSVAL(p,24,1); /* current uses */
1597 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1598 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1599 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1603 memset(p+40,0,SHPWLEN+2);
1614 (*buf) = p + struct_len;
1615 (*buflen) -= struct_len;
1617 (*stringspace) = l2;
1626 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1627 char *param, int tpscnt,
1628 char *data, int tdscnt,
1629 int mdrcnt,int mprcnt,
1630 char **rdata,char **rparam,
1631 int *rdata_len,int *rparam_len)
1633 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1634 char *str2 = skip_string(param,tpscnt,str1);
1635 char *netname = skip_string(param,tpscnt,str2);
1636 char *p = skip_string(param,tpscnt,netname);
1637 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1640 if (!str1 || !str2 || !netname || !p) {
1644 snum = find_service(netname);
1649 /* check it's a supported varient */
1650 if (!prefix_ok(str1,"zWrLh")) {
1653 if (!check_share_info(uLevel,str2)) {
1657 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1662 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1663 if (*rdata_len < 0) {
1668 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1672 SSVAL(*rparam,0,NERR_Success);
1673 SSVAL(*rparam,2,0); /* converter word */
1674 SSVAL(*rparam,4,*rdata_len);
1679 /****************************************************************************
1680 View the list of available shares.
1682 This function is the server side of the NetShareEnum() RAP call.
1683 It fills the return buffer with share names and share comments.
1684 Note that the return buffer normally (in all known cases) allows only
1685 twelve byte strings for share names (plus one for a nul terminator).
1686 Share names longer than 12 bytes must be skipped.
1687 ****************************************************************************/
1689 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1690 char *param, int tpscnt,
1691 char *data, int tdscnt,
1699 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1700 char *str2 = skip_string(param,tpscnt,str1);
1701 char *p = skip_string(param,tpscnt,str2);
1702 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1703 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1706 int total=0,counted=0;
1707 BOOL missed = False;
1709 int data_len, fixed_len, string_len;
1710 int f_len = 0, s_len = 0;
1712 if (!str1 || !str2 || !p) {
1716 if (!prefix_ok(str1,"WrLeh")) {
1719 if (!check_share_info(uLevel,str2)) {
1723 /* Ensure all the usershares are loaded. */
1725 load_registry_shares();
1726 count = load_usershare_shares();
1729 data_len = fixed_len = string_len = 0;
1730 for (i=0;i<count;i++) {
1731 fstring servicename_dos;
1732 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1735 push_ascii_fstring(servicename_dos, lp_servicename(i));
1736 /* Maximum name length = 13. */
1737 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1739 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1740 if (data_len <= buf_len) {
1743 string_len += s_len;
1750 *rdata_len = fixed_len + string_len;
1751 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1755 memset(*rdata,0,*rdata_len);
1757 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1762 for( i = 0; i < count; i++ ) {
1763 fstring servicename_dos;
1764 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1768 push_ascii_fstring(servicename_dos, lp_servicename(i));
1769 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1770 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1777 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1781 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1783 SSVAL(*rparam,4,counted);
1784 SSVAL(*rparam,6,total);
1786 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1787 counted,total,uLevel,
1788 buf_len,*rdata_len,mdrcnt));
1793 /****************************************************************************
1795 ****************************************************************************/
1797 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1798 char *param, int tpscnt,
1799 char *data, int tdscnt,
1800 int mdrcnt,int mprcnt,
1801 char **rdata,char **rparam,
1802 int *rdata_len,int *rparam_len)
1804 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1805 char *str2 = skip_string(param,tpscnt,str1);
1806 char *p = skip_string(param,tpscnt,str2);
1807 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1811 char *command, *cmdname;
1812 unsigned int offset;
1816 if (!str1 || !str2 || !p) {
1820 /* check it's a supported varient */
1821 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1824 if (!check_share_info(uLevel,str2)) {
1831 /* Do we have a string ? */
1832 if (skip_string(data,mdrcnt,data) == NULL) {
1835 pull_ascii_fstring(sharename,data);
1836 snum = find_service(sharename);
1837 if (snum >= 0) { /* already exists */
1846 /* only support disk share adds */
1847 if (SVAL(data,14)!=STYPE_DISKTREE) {
1851 offset = IVAL(data, 16);
1852 if (offset >= mdrcnt) {
1853 res = ERRinvalidparam;
1857 /* Do we have a string ? */
1858 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1861 pull_ascii_fstring(comment, offset? (data+offset) : "");
1863 offset = IVAL(data, 26);
1865 if (offset >= mdrcnt) {
1866 res = ERRinvalidparam;
1870 /* Do we have a string ? */
1871 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1874 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1876 string_replace(sharename, '"', ' ');
1877 string_replace(pathname, '"', ' ');
1878 string_replace(comment, '"', ' ');
1880 cmdname = lp_add_share_cmd();
1882 if (!cmdname || *cmdname == '\0') {
1886 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1887 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1890 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1892 if ((res = smbrun(command, NULL)) != 0) {
1893 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1899 message_send_all(smbd_messaging_context(),
1900 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1907 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1911 SSVAL(*rparam,0,NERR_Success);
1912 SSVAL(*rparam,2,0); /* converter word */
1913 SSVAL(*rparam,4,*rdata_len);
1921 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1926 SSVAL(*rparam,0,res);
1931 /****************************************************************************
1932 view list of groups available
1933 ****************************************************************************/
1935 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1936 char *param, int tpscnt,
1937 char *data, int tdscnt,
1938 int mdrcnt,int mprcnt,
1939 char **rdata,char **rparam,
1940 int *rdata_len,int *rparam_len)
1944 int resume_context, cli_buf_size;
1945 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1946 char *str2 = skip_string(param,tpscnt,str1);
1947 char *p = skip_string(param,tpscnt,str2);
1949 struct pdb_search *search;
1950 struct samr_displayentry *entries;
1954 if (!str1 || !str2 || !p) {
1958 if (strcmp(str1,"WrLeh") != 0) {
1963 * W-> resume context (number of users to skip)
1964 * r -> return parameter pointer to receive buffer
1965 * L -> length of receive buffer
1966 * e -> return parameter number of entries
1967 * h -> return parameter total number of users
1970 if (strcmp("B21",str2) != 0) {
1974 /* get list of domain groups SID_DOMAIN_GRP=2 */
1976 search = pdb_search_groups();
1979 if (search == NULL) {
1980 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1984 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1985 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1986 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1987 "%d\n", resume_context, cli_buf_size));
1990 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1994 *rdata_len = cli_buf_size;
1995 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2002 for(i=0; i<num_entries; i++) {
2004 fstrcpy(name, entries[i].account_name);
2005 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2006 /* truncate the name at 21 chars. */
2007 memcpy(p, name, 21);
2008 DEBUG(10,("adding entry %d group %s\n", i, p));
2010 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2013 /* set overflow error */
2014 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2020 pdb_search_destroy(search);
2022 *rdata_len = PTR_DIFF(p,*rdata);
2025 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2029 SSVAL(*rparam, 0, errflags);
2030 SSVAL(*rparam, 2, 0); /* converter word */
2031 SSVAL(*rparam, 4, i); /* is this right?? */
2032 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2037 /*******************************************************************
2038 Get groups that a user is a member of.
2039 ******************************************************************/
2041 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2042 char *param, int tpscnt,
2043 char *data, int tdscnt,
2044 int mdrcnt,int mprcnt,
2045 char **rdata,char **rparam,
2046 int *rdata_len,int *rparam_len)
2048 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2049 char *str2 = skip_string(param,tpscnt,str1);
2050 char *UserName = skip_string(param,tpscnt,str2);
2051 char *p = skip_string(param,tpscnt,UserName);
2052 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2053 const char *level_string;
2055 struct samu *sampw = NULL;
2063 enum lsa_SidType type;
2064 TALLOC_CTX *mem_ctx;
2066 if (!str1 || !str2 || !UserName || !p) {
2071 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2076 /* check it's a supported varient */
2078 if ( strcmp(str1,"zWrLeh") != 0 )
2083 level_string = "B21";
2089 if (strcmp(level_string,str2) != 0)
2092 *rdata_len = mdrcnt + 1024;
2093 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2097 SSVAL(*rparam,0,NERR_Success);
2098 SSVAL(*rparam,2,0); /* converter word */
2102 mem_ctx = talloc_new(NULL);
2103 if (mem_ctx == NULL) {
2104 DEBUG(0, ("talloc_new failed\n"));
2108 if ( !(sampw = samu_new(mem_ctx)) ) {
2109 DEBUG(0, ("samu_new() failed!\n"));
2110 TALLOC_FREE(mem_ctx);
2114 /* Lookup the user information; This should only be one of
2115 our accounts (not remote domains) */
2117 become_root(); /* ROOT BLOCK */
2119 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2120 NULL, NULL, &user_sid, &type)) {
2121 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2125 if (type != SID_NAME_USER) {
2126 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2127 sid_type_lookup(type)));
2131 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2132 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2133 sid_string_static(&user_sid), UserName));
2141 result = pdb_enum_group_memberships(mem_ctx, sampw,
2142 &sids, &gids, &num_groups);
2144 if (!NT_STATUS_IS_OK(result)) {
2145 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2150 for (i=0; i<num_groups; i++) {
2152 const char *grp_name;
2154 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2155 pstrcpy(p, grp_name);
2161 *rdata_len = PTR_DIFF(p,*rdata);
2163 SSVAL(*rparam,4,count); /* is this right?? */
2164 SSVAL(*rparam,6,count); /* is this right?? */
2169 unbecome_root(); /* END ROOT BLOCK */
2171 TALLOC_FREE(mem_ctx);
2176 /*******************************************************************
2178 ******************************************************************/
2180 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2181 char *param, int tpscnt,
2182 char *data, int tdscnt,
2183 int mdrcnt,int mprcnt,
2184 char **rdata,char **rparam,
2185 int *rdata_len,int *rparam_len)
2190 int i, resume_context, cli_buf_size;
2191 struct pdb_search *search;
2192 struct samr_displayentry *users;
2194 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2195 char *str2 = skip_string(param,tpscnt,str1);
2196 char *p = skip_string(param,tpscnt,str2);
2198 if (!str1 || !str2 || !p) {
2202 if (strcmp(str1,"WrLeh") != 0)
2205 * W-> resume context (number of users to skip)
2206 * r -> return parameter pointer to receive buffer
2207 * L -> length of receive buffer
2208 * e -> return parameter number of entries
2209 * h -> return parameter total number of users
2212 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2213 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2214 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2215 resume_context, cli_buf_size));
2218 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2223 /* check it's a supported varient */
2224 if (strcmp("B21",str2) != 0)
2227 *rdata_len = cli_buf_size;
2228 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2236 search = pdb_search_users(ACB_NORMAL);
2238 if (search == NULL) {
2239 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2244 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2248 errflags=NERR_Success;
2250 for (i=0; i<num_users; i++) {
2251 const char *name = users[i].account_name;
2253 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2255 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2256 "%s\n",count_sent,p));
2260 /* set overflow error */
2261 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2262 "username %s\n",count_sent,name));
2268 pdb_search_destroy(search);
2270 *rdata_len = PTR_DIFF(p,*rdata);
2272 SSVAL(*rparam,0,errflags);
2273 SSVAL(*rparam,2,0); /* converter word */
2274 SSVAL(*rparam,4,count_sent); /* is this right?? */
2275 SSVAL(*rparam,6,num_users); /* is this right?? */
2280 /****************************************************************************
2281 Get the time of day info.
2282 ****************************************************************************/
2284 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2285 char *param, int tpscnt,
2286 char *data, int tdscnt,
2287 int mdrcnt,int mprcnt,
2288 char **rdata,char **rparam,
2289 int *rdata_len,int *rparam_len)
2292 time_t unixdate = time(NULL);
2296 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2302 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2307 SSVAL(*rparam,0,NERR_Success);
2308 SSVAL(*rparam,2,0); /* converter word */
2312 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2313 by NT in a "net time" operation,
2314 it seems to ignore the one below */
2316 /* the client expects to get localtime, not GMT, in this bit
2317 (I think, this needs testing) */
2318 t = localtime(&unixdate);
2323 SIVAL(p,4,0); /* msecs ? */
2324 SCVAL(p,8,t->tm_hour);
2325 SCVAL(p,9,t->tm_min);
2326 SCVAL(p,10,t->tm_sec);
2327 SCVAL(p,11,0); /* hundredths of seconds */
2328 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2329 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2330 SCVAL(p,16,t->tm_mday);
2331 SCVAL(p,17,t->tm_mon + 1);
2332 SSVAL(p,18,1900+t->tm_year);
2333 SCVAL(p,20,t->tm_wday);
2338 /****************************************************************************
2339 Set the user password.
2340 *****************************************************************************/
2342 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2343 char *param, int tpscnt,
2344 char *data, int tdscnt,
2345 int mdrcnt,int mprcnt,
2346 char **rdata,char **rparam,
2347 int *rdata_len,int *rparam_len)
2349 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2352 fstring pass1,pass2;
2354 /* Skip 2 strings. */
2355 p = skip_string(param,tpscnt,np);
2356 p = skip_string(param,tpscnt,p);
2362 /* Do we have a string ? */
2363 if (skip_string(param,tpscnt,p) == NULL) {
2366 pull_ascii_fstring(user,p);
2368 p = skip_string(param,tpscnt,p);
2373 memset(pass1,'\0',sizeof(pass1));
2374 memset(pass2,'\0',sizeof(pass2));
2376 * We use 31 here not 32 as we're checking
2377 * the last byte we want to access is safe.
2379 if (!is_offset_safe(param,tpscnt,p,31)) {
2383 memcpy(pass2,p+16,16);
2386 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2393 SSVAL(*rparam,0,NERR_badpass);
2394 SSVAL(*rparam,2,0); /* converter word */
2396 DEBUG(3,("Set password for <%s>\n",user));
2399 * Attempt to verify the old password against smbpasswd entries
2400 * Win98 clients send old and new password in plaintext for this call.
2404 auth_serversupplied_info *server_info = NULL;
2405 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2407 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2410 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2411 SSVAL(*rparam,0,NERR_Success);
2415 TALLOC_FREE(server_info);
2417 data_blob_clear_free(&password);
2421 * If the plaintext change failed, attempt
2422 * the old encrypted method. NT will generate this
2423 * after trying the samr method. Note that this
2424 * method is done as a last resort as this
2425 * password change method loses the NT password hash
2426 * and cannot change the UNIX password as no plaintext
2430 if(SVAL(*rparam,0) != NERR_Success) {
2431 struct samu *hnd = NULL;
2433 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2435 if (change_lanman_password(hnd,(uchar *)pass2)) {
2436 SSVAL(*rparam,0,NERR_Success);
2443 memset((char *)pass1,'\0',sizeof(fstring));
2444 memset((char *)pass2,'\0',sizeof(fstring));
2449 /****************************************************************************
2450 Set the user password (SamOEM version - gets plaintext).
2451 ****************************************************************************/
2453 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2454 char *param, int tpscnt,
2455 char *data, int tdscnt,
2456 int mdrcnt,int mprcnt,
2457 char **rdata,char **rparam,
2458 int *rdata_len,int *rparam_len)
2461 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2463 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2473 SSVAL(*rparam,0,NERR_badpass);
2476 * Check the parameter definition is correct.
2479 /* Do we have a string ? */
2480 if (skip_string(param,tpscnt,p) == 0) {
2483 if(!strequal(p, "zsT")) {
2484 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2487 p = skip_string(param, tpscnt, p);
2492 /* Do we have a string ? */
2493 if (skip_string(param,tpscnt,p) == 0) {
2496 if(!strequal(p, "B516B16")) {
2497 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2500 p = skip_string(param,tpscnt,p);
2504 /* Do we have a string ? */
2505 if (skip_string(param,tpscnt,p) == 0) {
2508 p += pull_ascii_fstring(user,p);
2510 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2513 * Pass the user through the NT -> unix user mapping
2517 (void)map_username(user);
2519 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2520 SSVAL(*rparam,0,NERR_Success);
2526 /****************************************************************************
2529 ****************************************************************************/
2531 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2532 char *param, int tpscnt,
2533 char *data, int tdscnt,
2534 int mdrcnt,int mprcnt,
2535 char **rdata,char **rparam,
2536 int *rdata_len,int *rparam_len)
2538 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2539 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2540 char *str2 = skip_string(param,tpscnt,str1);
2541 char *p = skip_string(param,tpscnt,str2);
2546 WERROR werr = WERR_OK;
2548 if (!str1 || !str2 || !p) {
2552 * We use 1 here not 2 as we're checking
2553 * the last byte we want to access is safe.
2555 if (!is_offset_safe(param,tpscnt,p,1)) {
2558 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2561 /* check it's a supported varient */
2562 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2566 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2572 if (!print_job_exists(sharename, jobid)) {
2573 errcode = NERR_JobNotFound;
2577 snum = lp_servicenumber( sharename);
2579 errcode = NERR_DestNotFound;
2583 errcode = NERR_notsupported;
2586 case 81: /* delete */
2587 if (print_job_delete(¤t_user, snum, jobid, &werr))
2588 errcode = NERR_Success;
2590 case 82: /* pause */
2591 if (print_job_pause(¤t_user, snum, jobid, &werr))
2592 errcode = NERR_Success;
2594 case 83: /* resume */
2595 if (print_job_resume(¤t_user, snum, jobid, &werr))
2596 errcode = NERR_Success;
2600 if (!W_ERROR_IS_OK(werr))
2601 errcode = W_ERROR_V(werr);
2604 SSVAL(*rparam,0,errcode);
2605 SSVAL(*rparam,2,0); /* converter word */
2610 /****************************************************************************
2611 Purge a print queue - or pause or resume it.
2612 ****************************************************************************/
2614 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2615 char *param, int tpscnt,
2616 char *data, int tdscnt,
2617 int mdrcnt,int mprcnt,
2618 char **rdata,char **rparam,
2619 int *rdata_len,int *rparam_len)
2621 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2622 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2623 char *str2 = skip_string(param,tpscnt,str1);
2624 char *QueueName = skip_string(param,tpscnt,str2);
2625 int errcode = NERR_notsupported;
2627 WERROR werr = WERR_OK;
2629 if (!str1 || !str2 || !QueueName) {
2633 /* check it's a supported varient */
2634 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2638 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2644 if (skip_string(param,tpscnt,QueueName) == NULL) {
2647 snum = print_queue_snum(QueueName);
2650 errcode = NERR_JobNotFound;
2655 case 74: /* Pause queue */
2656 if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success;
2658 case 75: /* Resume queue */
2659 if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success;
2661 case 103: /* Purge */
2662 if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success;
2666 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2669 SSVAL(*rparam,0,errcode);
2670 SSVAL(*rparam,2,0); /* converter word */
2675 /****************************************************************************
2676 set the property of a print job (undocumented?)
2677 ? function = 0xb -> set name of print job
2678 ? function = 0x6 -> move print job up/down
2679 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2680 or <WWsTP> <WB21BB16B10zWWzDDz>
2681 ****************************************************************************/
2683 static int check_printjob_info(struct pack_desc* desc,
2684 int uLevel, char* id)
2686 desc->subformat = NULL;
2688 case 0: desc->format = "W"; break;
2689 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2690 case 2: desc->format = "WWzWWDDzz"; break;
2691 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2692 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2694 DEBUG(0,("check_printjob_info: invalid level %d\n",
2698 if (id == NULL || strcmp(desc->format,id) != 0) {
2699 DEBUG(0,("check_printjob_info: invalid format %s\n",
2700 id ? id : "<NULL>" ));
2706 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2707 char *param, int tpscnt,
2708 char *data, int tdscnt,
2709 int mdrcnt,int mprcnt,
2710 char **rdata,char **rparam,
2711 int *rdata_len,int *rparam_len)
2713 struct pack_desc desc;
2714 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2715 char *str2 = skip_string(param,tpscnt,str1);
2716 char *p = skip_string(param,tpscnt,str2);
2719 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2720 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2723 if (!str1 || !str2 || !p) {
2727 * We use 1 here not 2 as we're checking
2728 * the last byte we want to access is safe.
2730 if (!is_offset_safe(param,tpscnt,p,1)) {
2733 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2736 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2741 if (!share_defined(sharename)) {
2742 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2749 /* check it's a supported varient */
2750 if ((strcmp(str1,"WWsTP")) ||
2751 (!check_printjob_info(&desc,uLevel,str2)))
2754 if (!print_job_exists(sharename, jobid)) {
2755 errcode=NERR_JobNotFound;
2759 errcode = NERR_notsupported;
2763 /* change job place in the queue,
2764 data gives the new place */
2765 place = SVAL(data,0);
2766 if (print_job_set_place(sharename, jobid, place)) {
2767 errcode=NERR_Success;
2772 /* change print job name, data gives the name */
2773 if (print_job_set_name(sharename, jobid, data)) {
2774 errcode=NERR_Success;
2783 SSVALS(*rparam,0,errcode);
2784 SSVAL(*rparam,2,0); /* converter word */
2790 /****************************************************************************
2791 Get info about the server.
2792 ****************************************************************************/
2794 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2795 char *param, int tpscnt,
2796 char *data, int tdscnt,
2797 int mdrcnt,int mprcnt,
2798 char **rdata,char **rparam,
2799 int *rdata_len,int *rparam_len)
2801 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2802 char *str2 = skip_string(param,tpscnt,str1);
2803 char *p = skip_string(param,tpscnt,str2);
2804 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2808 if (!str1 || !str2 || !p) {
2812 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2814 /* check it's a supported varient */
2815 if (!prefix_ok(str1,"WrLh")) {
2821 if (strcmp(str2,"B16") != 0) {
2827 if (strcmp(str2,"B16BBDz") != 0) {
2833 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2839 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2845 if (strcmp(str2,"DN") != 0) {
2851 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2860 *rdata_len = mdrcnt;
2861 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2867 p2 = p + struct_len;
2869 srvstr_push(NULL, 0, p,global_myname(),16,
2870 STR_ASCII|STR_UPPER|STR_TERMINATE);
2874 struct srv_info_struct *servers=NULL;
2877 uint32 servertype= lp_default_server_announce();
2879 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2881 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2882 for (i=0;i<count;i++) {
2883 if (strequal(servers[i].name,global_myname())) {
2884 servertype = servers[i].type;
2885 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2892 SCVAL(p,0,lp_major_announce_version());
2893 SCVAL(p,1,lp_minor_announce_version());
2894 SIVAL(p,2,servertype);
2896 if (mdrcnt == struct_len) {
2899 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2900 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2901 conn->connectpath, conn->gid,
2902 get_current_username(),
2903 current_user_info.domain,
2904 comment, sizeof(comment));
2905 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2906 p2 = skip_string(*rdata,*rdata_len,p2);
2914 return False; /* not yet implemented */
2917 *rdata_len = PTR_DIFF(p2,*rdata);
2920 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2924 SSVAL(*rparam,0,NERR_Success);
2925 SSVAL(*rparam,2,0); /* converter word */
2926 SSVAL(*rparam,4,*rdata_len);
2931 /****************************************************************************
2932 Get info about the server.
2933 ****************************************************************************/
2935 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2936 char *param, int tpscnt,
2937 char *data, int tdscnt,
2938 int mdrcnt,int mprcnt,
2939 char **rdata,char **rparam,
2940 int *rdata_len,int *rparam_len)
2942 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2943 char *str2 = skip_string(param,tpscnt,str1);
2944 char *p = skip_string(param,tpscnt,str2);
2946 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2948 if (!str1 || !str2 || !p) {
2952 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2955 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2960 /* check it's a supported varient */
2961 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2965 *rdata_len = mdrcnt + 1024;
2966 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2971 SSVAL(*rparam,0,NERR_Success);
2972 SSVAL(*rparam,2,0); /* converter word */
2975 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2980 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2981 pstrcpy(p2,get_local_machine_name());
2983 p2 = skip_string(*rdata,*rdata_len,p2);
2989 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2990 pstrcpy(p2,current_user_info.smb_name);
2991 p2 = skip_string(*rdata,*rdata_len,p2);
2997 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2998 pstrcpy(p2,lp_workgroup());
3000 p2 = skip_string(*rdata,*rdata_len,p2);
3006 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3007 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3010 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3011 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
3012 p2 = skip_string(*rdata,*rdata_len,p2);
3018 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3020 p2 = skip_string(*rdata,*rdata_len,p2);
3026 *rdata_len = PTR_DIFF(p2,*rdata);
3028 SSVAL(*rparam,4,*rdata_len);
3033 /****************************************************************************
3034 get info about a user
3036 struct user_info_11 {
3037 char usri11_name[21]; 0-20
3039 char *usri11_comment; 22-25
3040 char *usri11_usr_comment; 26-29
3041 unsigned short usri11_priv; 30-31
3042 unsigned long usri11_auth_flags; 32-35
3043 long usri11_password_age; 36-39
3044 char *usri11_homedir; 40-43
3045 char *usri11_parms; 44-47
3046 long usri11_last_logon; 48-51
3047 long usri11_last_logoff; 52-55
3048 unsigned short usri11_bad_pw_count; 56-57
3049 unsigned short usri11_num_logons; 58-59
3050 char *usri11_logon_server; 60-63
3051 unsigned short usri11_country_code; 64-65
3052 char *usri11_workstations; 66-69
3053 unsigned long usri11_max_storage; 70-73
3054 unsigned short usri11_units_per_week; 74-75
3055 unsigned char *usri11_logon_hours; 76-79
3056 unsigned short usri11_code_page; 80-81
3061 usri11_name specifies the user name for which information is retireved
3063 usri11_pad aligns the next data structure element to a word boundary
3065 usri11_comment is a null terminated ASCII comment
3067 usri11_user_comment is a null terminated ASCII comment about the user
3069 usri11_priv specifies the level of the privilege assigned to the user.
3070 The possible values are:
3072 Name Value Description
3073 USER_PRIV_GUEST 0 Guest privilege
3074 USER_PRIV_USER 1 User privilege
3075 USER_PRV_ADMIN 2 Administrator privilege
3077 usri11_auth_flags specifies the account operator privileges. The
3078 possible values are:
3080 Name Value Description
3081 AF_OP_PRINT 0 Print operator
3084 Leach, Naik [Page 28]
3088 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3091 AF_OP_COMM 1 Communications operator
3092 AF_OP_SERVER 2 Server operator
3093 AF_OP_ACCOUNTS 3 Accounts operator
3096 usri11_password_age specifies how many seconds have elapsed since the
3097 password was last changed.
3099 usri11_home_dir points to a null terminated ASCII string that contains
3100 the path name of the user's home directory.
3102 usri11_parms points to a null terminated ASCII string that is set
3103 aside for use by applications.
3105 usri11_last_logon specifies the time when the user last logged on.
3106 This value is stored as the number of seconds elapsed since
3107 00:00:00, January 1, 1970.
3109 usri11_last_logoff specifies the time when the user last logged off.
3110 This value is stored as the number of seconds elapsed since
3111 00:00:00, January 1, 1970. A value of 0 means the last logoff
3114 usri11_bad_pw_count specifies the number of incorrect passwords
3115 entered since the last successful logon.
3117 usri11_log1_num_logons specifies the number of times this user has
3118 logged on. A value of -1 means the number of logons is unknown.
3120 usri11_logon_server points to a null terminated ASCII string that
3121 contains the name of the server to which logon requests are sent.
3122 A null string indicates logon requests should be sent to the
3125 usri11_country_code specifies the country code for the user's language
3128 usri11_workstations points to a null terminated ASCII string that
3129 contains the names of workstations the user may log on from.
3130 There may be up to 8 workstations, with the names separated by
3131 commas. A null strings indicates there are no restrictions.
3133 usri11_max_storage specifies the maximum amount of disk space the user
3134 can occupy. A value of 0xffffffff indicates there are no
3137 usri11_units_per_week specifies the equal number of time units into
3138 which a week is divided. This value must be equal to 168.
3140 usri11_logon_hours points to a 21 byte (168 bits) string that
3141 specifies the time during which the user can log on. Each bit
3142 represents one unique hour in a week. The first bit (bit 0, word
3143 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3147 Leach, Naik [Page 29]
3151 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3154 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3155 are no restrictions.
3157 usri11_code_page specifies the code page for the user's language of
3160 All of the pointers in this data structure need to be treated
3161 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3162 to be ignored. The converter word returned in the parameters section
3163 needs to be subtracted from the lower 16 bits to calculate an offset
3164 into the return buffer where this ASCII string resides.
3166 There is no auxiliary data in the response.
3168 ****************************************************************************/
3170 #define usri11_name 0
3171 #define usri11_pad 21
3172 #define usri11_comment 22
3173 #define usri11_usr_comment 26
3174 #define usri11_full_name 30
3175 #define usri11_priv 34
3176 #define usri11_auth_flags 36
3177 #define usri11_password_age 40
3178 #define usri11_homedir 44
3179 #define usri11_parms 48
3180 #define usri11_last_logon 52
3181 #define usri11_last_logoff 56
3182 #define usri11_bad_pw_count 60
3183 #define usri11_num_logons 62
3184 #define usri11_logon_server 64
3185 #define usri11_country_code 68
3186 #define usri11_workstations 70
3187 #define usri11_max_storage 74
3188 #define usri11_units_per_week 78
3189 #define usri11_logon_hours 80
3190 #define usri11_code_page 84
3191 #define usri11_end 86
3193 #define USER_PRIV_GUEST 0
3194 #define USER_PRIV_USER 1
3195 #define USER_PRIV_ADMIN 2
3197 #define AF_OP_PRINT 0
3198 #define AF_OP_COMM 1
3199 #define AF_OP_SERVER 2
3200 #define AF_OP_ACCOUNTS 3
3203 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3204 char *param, int tpscnt,
3205 char *data, int tdscnt,
3206 int mdrcnt,int mprcnt,
3207 char **rdata,char **rparam,
3208 int *rdata_len,int *rparam_len)
3210 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3211 char *str2 = skip_string(param,tpscnt,str1);
3212 char *UserName = skip_string(param,tpscnt,str2);
3213 char *p = skip_string(param,tpscnt,UserName);
3214 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3216 const char *level_string;
3218 /* get NIS home of a previously validated user - simeon */
3219 /* With share level security vuid will always be zero.
3220 Don't depend on vuser being non-null !!. JRA */
3221 user_struct *vuser = get_valid_user_struct(vuid);
3223 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3224 vuser->user.unix_name));
3227 if (!str1 || !str2 || !UserName || !p) {
3232 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3237 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3239 /* check it's a supported variant */
3240 if (strcmp(str1,"zWrLh") != 0) {
3244 case 0: level_string = "B21"; break;
3245 case 1: level_string = "B21BB16DWzzWz"; break;
3246 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3247 case 10: level_string = "B21Bzzz"; break;
3248 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3249 default: return False;
3252 if (strcmp(level_string,str2) != 0) {
3256 *rdata_len = mdrcnt + 1024;
3257 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3262 SSVAL(*rparam,0,NERR_Success);
3263 SSVAL(*rparam,2,0); /* converter word */
3266 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3272 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3275 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3280 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3281 pstrcpy(p2,"Comment");
3282 p2 = skip_string(*rdata,*rdata_len,p2);
3287 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3288 pstrcpy(p2,"UserComment");
3289 p2 = skip_string(*rdata,*rdata_len,p2);
3294 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3295 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3296 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3297 p2 = skip_string(*rdata,*rdata_len,p2);
3304 /* modelled after NTAS 3.51 reply */
3305 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3306 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3307 SIVALS(p,usri11_password_age,-1); /* password age */
3308 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3309 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3310 p2 = skip_string(*rdata,*rdata_len,p2);
3314 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3316 p2 = skip_string(*rdata,*rdata_len,p2);
3320 SIVAL(p,usri11_last_logon,0); /* last logon */
3321 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3322 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3323 SSVALS(p,usri11_num_logons,-1); /* num logons */
3324 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3325 pstrcpy(p2,"\\\\*");
3326 p2 = skip_string(*rdata,*rdata_len,p2);
3330 SSVAL(p,usri11_country_code,0); /* country code */
3332 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3334 p2 = skip_string(*rdata,*rdata_len,p2);
3339 SIVALS(p,usri11_max_storage,-1); /* max storage */
3340 SSVAL(p,usri11_units_per_week,168); /* units per week */
3341 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3343 /* a simple way to get logon hours at all times. */
3345 SCVAL(p2,21,0); /* fix zero termination */
3346 p2 = skip_string(*rdata,*rdata_len,p2);
3351 SSVAL(p,usri11_code_page,0); /* code page */
3354 if (uLevel == 1 || uLevel == 2) {
3355 memset(p+22,' ',16); /* password */
3356 SIVALS(p,38,-1); /* password age */
3358 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3359 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3360 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3361 p2 = skip_string(*rdata,*rdata_len,p2);
3365 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3367 SSVAL(p,52,0); /* flags */
3368 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3369 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3370 p2 = skip_string(*rdata,*rdata_len,p2);
3375 SIVAL(p,60,0); /* auth_flags */
3376 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3377 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3378 p2 = skip_string(*rdata,*rdata_len,p2);
3382 SIVAL(p,68,0); /* urs_comment */
3383 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3385 p2 = skip_string(*rdata,*rdata_len,p2);
3389 SIVAL(p,76,0); /* workstations */
3390 SIVAL(p,80,0); /* last_logon */
3391 SIVAL(p,84,0); /* last_logoff */
3392 SIVALS(p,88,-1); /* acct_expires */
3393 SIVALS(p,92,-1); /* max_storage */
3394 SSVAL(p,96,168); /* units_per_week */
3395 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3398 SSVALS(p,102,-1); /* bad_pw_count */
3399 SSVALS(p,104,-1); /* num_logons */
3400 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3403 pstrcpy(tmp, "\\\\%L");
3404 standard_sub_basic("", "", tmp, sizeof(tmp));
3407 p2 = skip_string(*rdata,*rdata_len,p2);
3411 SSVAL(p,110,49); /* country_code */
3412 SSVAL(p,112,860); /* code page */
3416 *rdata_len = PTR_DIFF(p2,*rdata);
3418 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3423 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3424 char *param, int tpscnt,
3425 char *data, int tdscnt,
3426 int mdrcnt,int mprcnt,
3427 char **rdata,char **rparam,
3428 int *rdata_len,int *rparam_len)
3430 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3431 char *str2 = skip_string(param,tpscnt,str1);
3432 char *p = skip_string(param,tpscnt,str2);
3434 struct pack_desc desc;
3436 /* With share level security vuid will always be zero.
3437 Don't depend on vuser being non-null !!. JRA */
3438 user_struct *vuser = get_valid_user_struct(vuid);
3440 if (!str1 || !str2 || !p) {
3445 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3446 vuser->user.unix_name));
3449 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3450 name = get_safe_str_ptr(param,tpscnt,p,2);
3455 memset((char *)&desc,'\0',sizeof(desc));
3457 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3459 /* check it's a supported varient */
3460 if (strcmp(str1,"OOWb54WrLh") != 0) {
3463 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3467 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3474 desc.buflen = mdrcnt;
3475 desc.subformat = NULL;
3478 if (init_package(&desc,1,0)) {
3479 PACKI(&desc,"W",0); /* code */
3480 PACKS(&desc,"B21",name); /* eff. name */
3481 PACKS(&desc,"B",""); /* pad */
3482 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3483 PACKI(&desc,"D",0); /* auth flags XXX */
3484 PACKI(&desc,"W",0); /* num logons */
3485 PACKI(&desc,"W",0); /* bad pw count */
3486 PACKI(&desc,"D",0); /* last logon */
3487 PACKI(&desc,"D",-1); /* last logoff */
3488 PACKI(&desc,"D",-1); /* logoff time */
3489 PACKI(&desc,"D",-1); /* kickoff time */
3490 PACKI(&desc,"D",0); /* password age */
3491 PACKI(&desc,"D",0); /* password can change */
3492 PACKI(&desc,"D",-1); /* password must change */
3496 fstrcpy(mypath,"\\\\");
3497 fstrcat(mypath,get_local_machine_name());
3499 PACKS(&desc,"z",mypath); /* computer */
3502 PACKS(&desc,"z",lp_workgroup());/* domain */
3503 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3504 PACKI(&desc,"D",0x00000000); /* reserved */
3507 *rdata_len = desc.usedlen;
3509 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3513 SSVALS(*rparam,0,desc.errcode);
3515 SSVAL(*rparam,4,desc.neededlen);
3517 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3522 /****************************************************************************
3523 api_WAccessGetUserPerms
3524 ****************************************************************************/
3526 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3527 char *param, int tpscnt,
3528 char *data, int tdscnt,
3529 int mdrcnt,int mprcnt,
3530 char **rdata,char **rparam,
3531 int *rdata_len,int *rparam_len)
3533 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3534 char *str2 = skip_string(param,tpscnt,str1);
3535 char *user = skip_string(param,tpscnt,str2);
3536 char *resource = skip_string(param,tpscnt,user);
3538 if (!str1 || !str2 || !user || !resource) {
3542 if (skip_string(param,tpscnt,resource) == NULL) {
3545 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3547 /* check it's a supported varient */
3548 if (strcmp(str1,"zzh") != 0) {
3551 if (strcmp(str2,"") != 0) {
3556 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3560 SSVALS(*rparam,0,0); /* errorcode */
3561 SSVAL(*rparam,2,0); /* converter word */
3562 SSVAL(*rparam,4,0x7f); /* permission flags */
3567 /****************************************************************************
3568 api_WPrintJobEnumerate
3569 ****************************************************************************/
3571 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3572 char *param, int tpscnt,
3573 char *data, int tdscnt,
3574 int mdrcnt,int mprcnt,
3575 char **rdata,char **rparam,
3576 int *rdata_len,int *rparam_len)
3578 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3579 char *str2 = skip_string(param,tpscnt,str1);
3580 char *p = skip_string(param,tpscnt,str2);
3587 struct pack_desc desc;
3588 print_queue_struct *queue=NULL;
3589 print_status_struct status;
3592 if (!str1 || !str2 || !p) {
3596 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3598 memset((char *)&desc,'\0',sizeof(desc));
3599 memset((char *)&status,'\0',sizeof(status));
3601 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3603 /* check it's a supported varient */
3604 if (strcmp(str1,"WWrLh") != 0) {
3607 if (!check_printjob_info(&desc,uLevel,str2)) {
3611 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3615 snum = lp_servicenumber( sharename);
3616 if (snum < 0 || !VALID_SNUM(snum)) {
3620 count = print_queue_status(snum,&queue,&status);
3621 for (i = 0; i < count; i++) {
3622 if (queue[i].job == jobid) {
3628 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3633 desc.buflen = mdrcnt;
3636 * Don't return data but need to get correct length
3637 * init_package will return wrong size if buflen=0
3639 desc.buflen = getlen(desc.format);
3640 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3643 if (init_package(&desc,1,0)) {
3645 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3646 *rdata_len = desc.usedlen;
3648 desc.errcode = NERR_JobNotFound;
3654 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3658 SSVALS(*rparam,0,desc.errcode);
3660 SSVAL(*rparam,4,desc.neededlen);
3665 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3670 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3671 char *param, int tpscnt,
3672 char *data, int tdscnt,
3673 int mdrcnt,int mprcnt,
3674 char **rdata,char **rparam,
3675 int *rdata_len,int *rparam_len)
3677 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3678 char *str2 = skip_string(param,tpscnt,str1);
3679 char *p = skip_string(param,tpscnt,str2);
3685 struct pack_desc desc;
3686 print_queue_struct *queue=NULL;
3687 print_status_struct status;
3689 if (!str1 || !str2 || !p) {
3693 memset((char *)&desc,'\0',sizeof(desc));
3694 memset((char *)&status,'\0',sizeof(status));
3696 p = skip_string(param,tpscnt,p);
3700 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3702 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3704 /* check it's a supported variant */
3705 if (strcmp(str1,"zWrLeh") != 0) {
3710 return False; /* defined only for uLevel 0,1,2 */
3713 if (!check_printjob_info(&desc,uLevel,str2)) {
3717 snum = find_service(name);
3718 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3722 count = print_queue_status(snum,&queue,&status);
3724 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3730 desc.buflen = mdrcnt;
3732 if (init_package(&desc,count,0)) {
3734 for (i = 0; i < count; i++) {
3735 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3736 if (desc.errcode == NERR_Success) {
3742 *rdata_len = desc.usedlen;
3745 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3749 SSVALS(*rparam,0,desc.errcode);
3751 SSVAL(*rparam,4,succnt);
3752 SSVAL(*rparam,6,count);
3756 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3761 static int check_printdest_info(struct pack_desc* desc,
3762 int uLevel, char* id)
3764 desc->subformat = NULL;
3767 desc->format = "B9";
3770 desc->format = "B9B21WWzW";
3776 desc->format = "zzzWWzzzWW";
3779 DEBUG(0,("check_printdest_info: invalid level %d\n",
3783 if (id == NULL || strcmp(desc->format,id) != 0) {
3784 DEBUG(0,("check_printdest_info: invalid string %s\n",
3785 id ? id : "<NULL>" ));
3791 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3792 struct pack_desc* desc)
3796 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3797 buf[sizeof(buf)-1] = 0;
3801 PACKS(desc,"B9",buf); /* szName */
3803 PACKS(desc,"B21",""); /* szUserName */
3804 PACKI(desc,"W",0); /* uJobId */
3805 PACKI(desc,"W",0); /* fsStatus */
3806 PACKS(desc,"z",""); /* pszStatus */
3807 PACKI(desc,"W",0); /* time */
3811 if (uLevel == 2 || uLevel == 3) {
3812 PACKS(desc,"z",buf); /* pszPrinterName */
3814 PACKS(desc,"z",""); /* pszUserName */
3815 PACKS(desc,"z",""); /* pszLogAddr */
3816 PACKI(desc,"W",0); /* uJobId */
3817 PACKI(desc,"W",0); /* fsStatus */
3818 PACKS(desc,"z",""); /* pszStatus */
3819 PACKS(desc,"z",""); /* pszComment */
3820 PACKS(desc,"z","NULL"); /* pszDrivers */
3821 PACKI(desc,"W",0); /* time */
3822 PACKI(desc,"W",0); /* pad1 */
3827 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3828 char *param, int tpscnt,
3829 char *data, int tdscnt,
3830 int mdrcnt,int mprcnt,
3831 char **rdata,char **rparam,
3832 int *rdata_len,int *rparam_len)
3834 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3835 char *str2 = skip_string(param,tpscnt,str1);
3836 char *p = skip_string(param,tpscnt,str2);
3837 char* PrinterName = p;
3839 struct pack_desc desc;
3843 if (!str1 || !str2 || !p) {
3847 memset((char *)&desc,'\0',sizeof(desc));
3849 p = skip_string(param,tpscnt,p);
3853 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3855 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3857 /* check it's a supported varient */
3858 if (strcmp(str1,"zWrLh") != 0) {
3861 if (!check_printdest_info(&desc,uLevel,str2)) {
3865 snum = find_service(PrinterName);
3866 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3868 desc.errcode = NERR_DestNotFound;
3872 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3877 desc.buflen = mdrcnt;
3880 * Don't return data but need to get correct length
3881 * init_package will return wrong size if buflen=0
3883 desc.buflen = getlen(desc.format);
3884 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3886 if (init_package(&desc,1,0)) {
3887 fill_printdest_info(conn,snum,uLevel,&desc);
3889 *rdata_len = desc.usedlen;
3893 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3897 SSVALS(*rparam,0,desc.errcode);
3899 SSVAL(*rparam,4,desc.neededlen);
3901 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3907 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3908 char *param, int tpscnt,
3909 char *data, int tdscnt,
3910 int mdrcnt,int mprcnt,
3911 char **rdata,char **rparam,
3912 int *rdata_len,int *rparam_len)
3914 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3915 char *str2 = skip_string(param,tpscnt,str1);
3916 char *p = skip_string(param,tpscnt,str2);
3920 struct pack_desc desc;
3921 int services = lp_numservices();
3923 if (!str1 || !str2 || !p) {
3927 memset((char *)&desc,'\0',sizeof(desc));
3929 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3931 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3933 /* check it's a supported varient */
3934 if (strcmp(str1,"WrLeh") != 0) {
3937 if (!check_printdest_info(&desc,uLevel,str2)) {
3942 for (i = 0; i < services; i++) {
3943 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3949 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3956 desc.buflen = mdrcnt;
3957 if (init_package(&desc,queuecnt,0)) {
3960 for (i = 0; i < services; i++) {
3961 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3962 fill_printdest_info(conn,i,uLevel,&desc);
3964 if (desc.errcode == NERR_Success) {
3971 *rdata_len = desc.usedlen;
3974 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3978 SSVALS(*rparam,0,desc.errcode);
3980 SSVAL(*rparam,4,succnt);
3981 SSVAL(*rparam,6,queuecnt);
3983 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3988 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3989 char *param, int tpscnt,
3990 char *data, int tdscnt,
3991 int mdrcnt,int mprcnt,
3992 char **rdata,char **rparam,
3993 int *rdata_len,int *rparam_len)
3995 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3996 char *str2 = skip_string(param,tpscnt,str1);
3997 char *p = skip_string(param,tpscnt,str2);
4000 struct pack_desc desc;
4002 if (!str1 || !str2 || !p) {
4006 memset((char *)&desc,'\0',sizeof(desc));
4008 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4010 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4012 /* check it's a supported varient */
4013 if (strcmp(str1,"WrLeh") != 0) {
4016 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4021 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4027 desc.buflen = mdrcnt;
4028 if (init_package(&desc,1,0)) {
4029 PACKS(&desc,"B41","NULL");
4032 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4034 *rdata_len = desc.usedlen;
4037 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4041 SSVALS(*rparam,0,desc.errcode);
4043 SSVAL(*rparam,4,succnt);
4046 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4051 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4052 char *param, int tpscnt,
4053 char *data, int tdscnt,
4054 int mdrcnt,int mprcnt,
4055 char **rdata,char **rparam,
4056 int *rdata_len,int *rparam_len)
4058 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4059 char *str2 = skip_string(param,tpscnt,str1);
4060 char *p = skip_string(param,tpscnt,str2);
4063 struct pack_desc desc;
4065 if (!str1 || !str2 || !p) {
4068 memset((char *)&desc,'\0',sizeof(desc));
4070 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4072 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4074 /* check it's a supported varient */
4075 if (strcmp(str1,"WrLeh") != 0) {
4078 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4083 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4089 desc.buflen = mdrcnt;
4091 if (init_package(&desc,1,0)) {
4092 PACKS(&desc,"B13","lpd");
4095 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4097 *rdata_len = desc.usedlen;
4100 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4104 SSVALS(*rparam,0,desc.errcode);
4106 SSVAL(*rparam,4,succnt);
4109 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4114 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4115 char *param, int tpscnt,
4116 char *data, int tdscnt,
4117 int mdrcnt,int mprcnt,
4118 char **rdata,char **rparam,
4119 int *rdata_len,int *rparam_len)
4121 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4122 char *str2 = skip_string(param,tpscnt,str1);
4123 char *p = skip_string(param,tpscnt,str2);
4126 struct pack_desc desc;
4128 if (!str1 || !str2 || !p) {
4132 memset((char *)&desc,'\0',sizeof(desc));
4134 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4136 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4138 /* check it's a supported varient */
4139 if (strcmp(str1,"WrLeh") != 0) {
4142 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4147 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4152 memset((char *)&desc,'\0',sizeof(desc));
4154 desc.buflen = mdrcnt;
4156 if (init_package(&desc,1,0)) {
4157 PACKS(&desc,"B13","lp0");
4160 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4162 *rdata_len = desc.usedlen;
4165 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4169 SSVALS(*rparam,0,desc.errcode);
4171 SSVAL(*rparam,4,succnt);
4174 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4179 /****************************************************************************
4181 ****************************************************************************/
4183 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4184 char *param, int tpscnt,
4185 char *data, int tdscnt,
4186 int mdrcnt,int mprcnt,
4187 char **rdata,char **rparam,
4188 int *rdata_len,int *rparam_len)
4191 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4192 char *str2 = skip_string(param,tpscnt,str1);
4193 char *p = skip_string(param,tpscnt,str2);
4195 struct pack_desc desc;
4196 struct sessionid *session_list;
4197 int i, num_sessions;
4199 if (!str1 || !str2 || !p) {
4203 memset((char *)&desc,'\0',sizeof(desc));
4205 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4207 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4208 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4209 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4211 /* check it's a supported varient */
4212 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4215 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4219 num_sessions = list_sessions(talloc_tos(), &session_list);
4222 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4227 memset((char *)&desc,'\0',sizeof(desc));
4229 desc.buflen = mdrcnt;
4231 if (!init_package(&desc,num_sessions,0)) {
4235 for(i=0; i<num_sessions; i++) {
4236 PACKS(&desc, "z", session_list[i].remote_machine);
4237 PACKS(&desc, "z", session_list[i].username);
4238 PACKI(&desc, "W", 1); /* num conns */
4239 PACKI(&desc, "W", 0); /* num opens */
4240 PACKI(&desc, "W", 1); /* num users */
4241 PACKI(&desc, "D", 0); /* session time */
4242 PACKI(&desc, "D", 0); /* idle time */
4243 PACKI(&desc, "D", 0); /* flags */
4244 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4247 *rdata_len = desc.usedlen;
4250 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4254 SSVALS(*rparam,0,desc.errcode);
4255 SSVAL(*rparam,2,0); /* converter */
4256 SSVAL(*rparam,4,num_sessions); /* count */
4258 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4264 /****************************************************************************
4265 The buffer was too small.
4266 ****************************************************************************/
4268 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4269 int mdrcnt, int mprcnt,
4270 char **rdata, char **rparam,
4271 int *rdata_len, int *rparam_len)
4273 *rparam_len = MIN(*rparam_len,mprcnt);
4274 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4281 SSVAL(*rparam,0,NERR_BufTooSmall);
4283 DEBUG(3,("Supplied buffer too small in API command\n"));
4288 /****************************************************************************
4289 The request is not supported.
4290 ****************************************************************************/
4292 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4293 char *param, int tpscnt,
4294 char *data, int tdscnt,
4295 int mdrcnt, int mprcnt,
4296 char **rdata, char **rparam,
4297 int *rdata_len, int *rparam_len)
4300 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4307 SSVAL(*rparam,0,NERR_notsupported);
4308 SSVAL(*rparam,2,0); /* converter word */
4310 DEBUG(3,("Unsupported API command\n"));
4315 static const struct {
4318 BOOL (*fn)(connection_struct *, uint16,
4321 int,int,char **,char **,int *,int *);
4322 BOOL auth_user; /* Deny anonymous access? */
4323 } api_commands[] = {
4324 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4325 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4326 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4327 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4328 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4329 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4330 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4331 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4332 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4333 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4334 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4335 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4336 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4337 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4338 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4339 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4340 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4341 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4342 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4343 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4344 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4345 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4346 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4347 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4348 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4349 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4350 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4351 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4352 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4353 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4354 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4355 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4356 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4357 {NULL, -1, api_Unsupported}
4358 /* The following RAP calls are not implemented by Samba:
4360 RAP_WFileEnum2 - anon not OK
4365 /****************************************************************************
4366 Handle remote api calls.
4367 ****************************************************************************/
4369 void api_reply(connection_struct *conn, uint16 vuid,
4370 struct smb_request *req,
4371 char *data, char *params,
4372 int tdscnt, int tpscnt,
4373 int mdrcnt, int mprcnt)
4377 char *rparam = NULL;
4378 const char *name1 = NULL;
4379 const char *name2 = NULL;
4386 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4387 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4392 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4395 api_command = SVAL(params,0);
4396 /* Is there a string at position params+2 ? */
4397 if (skip_string(params,tpscnt,params+2)) {
4402 name2 = skip_string(params,tpscnt,params+2);
4407 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4411 tdscnt,tpscnt,mdrcnt,mprcnt));
4413 for (i=0;api_commands[i].name;i++) {
4414 if (api_commands[i].id == api_command && api_commands[i].fn) {
4415 DEBUG(3,("Doing %s\n",api_commands[i].name));
4420 /* Check whether this api call can be done anonymously */
4422 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4423 user_struct *user = get_valid_user_struct(vuid);
4425 if (!user || user->guest) {
4426 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4431 rdata = (char *)SMB_MALLOC(1024);
4433 memset(rdata,'\0',1024);
4436 rparam = (char *)SMB_MALLOC(1024);
4438 memset(rparam,'\0',1024);
4441 if(!rdata || !rparam) {
4442 DEBUG(0,("api_reply: malloc fail !\n"));
4445 reply_nterror(req, NT_STATUS_NO_MEMORY);
4449 reply = api_commands[i].fn(conn,
4451 params,tpscnt, /* params + length */
4452 data,tdscnt, /* data + length */
4454 &rdata,&rparam,&rdata_len,&rparam_len);
4457 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4458 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4459 &rdata,&rparam,&rdata_len,&rparam_len);
4462 /* if we get False back then it's actually unsupported */
4464 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4465 &rdata,&rparam,&rdata_len,&rparam_len);
4468 /* If api_Unsupported returns false we can't return anything. */
4470 send_trans_reply(req, rparam, rparam_len,
4471 rdata, rdata_len, False);