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 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
31 extern struct current_user current_user;
32 extern userdom_struct current_user_info;
39 #define NERR_Success 0
40 #define NERR_badpass 86
41 #define NERR_notsupported 50
43 #define NERR_BASE (2100)
44 #define NERR_BufTooSmall (NERR_BASE+23)
45 #define NERR_JobNotFound (NERR_BASE+51)
46 #define NERR_DestNotFound (NERR_BASE+52)
48 #define ACCESS_READ 0x01
49 #define ACCESS_WRITE 0x02
50 #define ACCESS_CREATE 0x04
52 #define SHPWLEN 8 /* share password length */
54 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
55 char *param, int tpscnt,
56 char *data, int tdscnt,
57 int mdrcnt, int mprcnt,
58 char **rdata, char **rparam,
59 int *rdata_len, int *rparam_len);
61 static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
62 int mdrcnt, int mprcnt,
63 char **rdata, char **rparam,
64 int *rdata_len, int *rparam_len);
67 static int CopyExpanded(connection_struct *conn,
68 int snum, char **dst, char *src, int *n)
73 if (!src || !dst || !n || !(*dst)) {
77 StrnCpy(buf,src,sizeof(buf)/2);
78 pstring_sub(buf,"%S",lp_servicename(snum));
79 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
80 conn->connectpath, conn->gid,
81 get_current_username(),
82 current_user_info.domain,
84 l = push_ascii(*dst,buf,*n, STR_TERMINATE);
90 static int CopyAndAdvance(char **dst, char *src, int *n)
93 if (!src || !dst || !n || !(*dst)) {
96 l = push_ascii(*dst,src,*n, STR_TERMINATE);
102 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
108 StrnCpy(buf,s,sizeof(buf)/2);
109 pstring_sub(buf,"%S",lp_servicename(snum));
110 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
111 conn->connectpath, conn->gid,
112 get_current_username(),
113 current_user_info.domain,
115 return strlen(buf) + 1;
118 static char *Expand(connection_struct *conn, int snum, char *s)
124 StrnCpy(buf,s,sizeof(buf)/2);
125 pstring_sub(buf,"%S",lp_servicename(snum));
126 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
127 conn->connectpath, conn->gid,
128 get_current_username(),
129 current_user_info.domain,
134 /*******************************************************************
135 Check a API string for validity when we only need to check the prefix.
136 ******************************************************************/
138 static BOOL prefix_ok(const char *str, const char *prefix)
140 return(strncmp(str,prefix,strlen(prefix)) == 0);
144 const char *format; /* formatstring for structure */
145 const char *subformat; /* subformat for structure */
146 char *base; /* baseaddress of buffer */
147 int buflen; /* remaining size for fixed part; on init: length of base */
148 int subcount; /* count of substructures */
149 char *structbuf; /* pointer into buffer for remaining fixed part */
150 int stringlen; /* remaining size for variable part */
151 char *stringbuf; /* pointer into buffer for remaining variable part */
152 int neededlen; /* total needed size */
153 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
154 const char *curpos; /* current position; pointer into format or subformat */
158 static int get_counter(const char **p)
164 if (!isdigit((int)**p)) {
170 n = 10 * n + (i - '0');
178 static int getlen(const char *p)
187 case 'W': /* word (2 byte) */
190 case 'K': /* status word? (2 byte) */
193 case 'N': /* count of substructures (word) at end */
196 case 'D': /* double word (4 byte) */
197 case 'z': /* offset to zero terminated string (4 byte) */
198 case 'l': /* offset to user data (4 byte) */
201 case 'b': /* offset to data (with counter) (4 byte) */
205 case 'B': /* byte (with optional counter) */
206 n += get_counter(&p);
213 static BOOL init_package(struct pack_desc *p, int count, int subcount)
218 if (!p->format || !p->base) {
222 i = count * getlen(p->format);
224 i += subcount * getlen(p->subformat);
226 p->structbuf = p->base;
230 p->curpos = p->format;
236 * This is the old error code we used. Aparently
237 * WinNT/2k systems return ERRbuftoosmall (2123) and
238 * OS/2 needs this. I'm leaving this here so we can revert
241 p->errcode = ERRmoredata;
243 p->errcode = ERRbuftoosmall;
246 p->errcode = NERR_Success;
250 p->stringbuf = p->base + i;
252 return (p->errcode == NERR_Success);
255 static int package(struct pack_desc *p, ...)
258 int needed=0, stringneeded;
259 const char *str=NULL;
260 int is_string=0, stringused;
267 p->curpos = p->format;
269 p->curpos = p->subformat;
274 str = va_arg(args,char*);
275 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
284 switch( *p->curpos++ ) {
285 case 'W': /* word (2 byte) */
287 temp = va_arg(args,int);
288 if (p->buflen >= needed) {
289 SSVAL(p->structbuf,0,temp);
292 case 'K': /* status word? (2 byte) */
294 temp = va_arg(args,int);
295 if (p->buflen >= needed) {
296 SSVAL(p->structbuf,0,temp);
299 case 'N': /* count of substructures (word) at end */
301 p->subcount = va_arg(args,int);
302 if (p->buflen >= needed) {
303 SSVAL(p->structbuf,0,p->subcount);
306 case 'D': /* double word (4 byte) */
308 temp = va_arg(args,int);
309 if (p->buflen >= needed) {
310 SIVAL(p->structbuf,0,temp);
313 case 'B': /* byte (with optional counter) */
314 needed = get_counter(&p->curpos);
316 char *s = va_arg(args,char*);
317 if (p->buflen >= needed) {
318 StrnCpy(p->structbuf,s?s:"",needed-1);
322 case 'z': /* offset to zero terminated string (4 byte) */
323 str = va_arg(args,char*);
324 stringneeded = (str ? strlen(str)+1 : 0);
327 case 'l': /* offset to user data (4 byte) */
328 str = va_arg(args,char*);
329 stringneeded = va_arg(args,int);
332 case 'b': /* offset to data (with counter) (4 byte) */
333 str = va_arg(args,char*);
334 stringneeded = get_counter(&p->curpos);
340 if (stringneeded >= 0) {
342 if (p->buflen >= needed) {
343 stringused = stringneeded;
344 if (stringused > p->stringlen) {
345 stringused = (is_string ? p->stringlen : 0);
346 if (p->errcode == NERR_Success) {
347 p->errcode = ERRmoredata;
351 SIVAL(p->structbuf,0,0);
353 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
354 memcpy(p->stringbuf,str?str:"",stringused);
356 p->stringbuf[stringused-1] = '\0';
358 p->stringbuf += stringused;
359 p->stringlen -= stringused;
360 p->usedlen += stringused;
363 p->neededlen += stringneeded;
366 p->neededlen += needed;
367 if (p->buflen >= needed) {
368 p->structbuf += needed;
370 p->usedlen += needed;
372 if (p->errcode == NERR_Success) {
373 p->errcode = ERRmoredata;
380 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
381 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
383 #define PACK(desc,t,v) package(desc,v)
384 #define PACKl(desc,t,v,l) package(desc,v,l)
387 static void PACKI(struct pack_desc* desc, const char *t,int v)
392 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
397 /****************************************************************************
399 ****************************************************************************/
401 static void PackDriverData(struct pack_desc* desc)
403 char drivdata[4+4+32];
404 SIVAL(drivdata,0,sizeof drivdata); /* cb */
405 SIVAL(drivdata,4,1000); /* lVersion */
406 memset(drivdata+8,0,32); /* szDeviceName */
407 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
408 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
411 static int check_printq_info(struct pack_desc* desc,
412 unsigned int uLevel, char *id1, char *id2)
414 desc->subformat = NULL;
417 desc->format = "B13";
420 desc->format = "B13BWWWzzzzzWW";
423 desc->format = "B13BWWWzzzzzWN";
424 desc->subformat = "WB21BB16B10zWWzDDz";
427 desc->format = "zWWWWzzzzWWzzl";
430 desc->format = "zWWWWzzzzWNzzl";
431 desc->subformat = "WWzWWDDzz";
440 desc->format = "WzzzzzzzzN";
441 desc->subformat = "z";
446 if (strcmp(desc->format,id1) != 0) {
449 if (desc->subformat && strcmp(desc->subformat,id2) != 0) {
456 #define RAP_JOB_STATUS_QUEUED 0
457 #define RAP_JOB_STATUS_PAUSED 1
458 #define RAP_JOB_STATUS_SPOOLING 2
459 #define RAP_JOB_STATUS_PRINTING 3
460 #define RAP_JOB_STATUS_PRINTED 4
462 #define RAP_QUEUE_STATUS_PAUSED 1
463 #define RAP_QUEUE_STATUS_ERROR 2
465 /* turn a print job status into a on the wire status
467 static int printj_status(int v)
471 return RAP_JOB_STATUS_QUEUED;
473 return RAP_JOB_STATUS_PAUSED;
475 return RAP_JOB_STATUS_SPOOLING;
477 return RAP_JOB_STATUS_PRINTING;
482 /* turn a print queue status into a on the wire status
484 static int printq_status(int v)
490 return RAP_QUEUE_STATUS_PAUSED;
492 return RAP_QUEUE_STATUS_ERROR;
495 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
496 struct pack_desc *desc,
497 print_queue_struct *queue, int n)
499 time_t t = queue->time;
501 /* the client expects localtime */
502 t -= get_time_zone(t);
504 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
506 PACKS(desc,"B21",queue->fs_user); /* szUserName */
507 PACKS(desc,"B",""); /* pad */
508 PACKS(desc,"B16",""); /* szNotifyName */
509 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
510 PACKS(desc,"z",""); /* pszParms */
511 PACKI(desc,"W",n+1); /* uPosition */
512 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
513 PACKS(desc,"z",""); /* pszStatus */
514 PACKI(desc,"D",t); /* ulSubmitted */
515 PACKI(desc,"D",queue->size); /* ulSize */
516 PACKS(desc,"z",queue->fs_file); /* pszComment */
518 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
519 PACKI(desc,"W",queue->priority); /* uPriority */
520 PACKS(desc,"z",queue->fs_user); /* pszUserName */
521 PACKI(desc,"W",n+1); /* uPosition */
522 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
523 PACKI(desc,"D",t); /* ulSubmitted */
524 PACKI(desc,"D",queue->size); /* ulSize */
525 PACKS(desc,"z","Samba"); /* pszComment */
526 PACKS(desc,"z",queue->fs_file); /* pszDocument */
528 PACKS(desc,"z",""); /* pszNotifyName */
529 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
530 PACKS(desc,"z",""); /* pszParms */
531 PACKS(desc,"z",""); /* pszStatus */
532 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
533 PACKS(desc,"z","lpd"); /* pszQProcName */
534 PACKS(desc,"z",""); /* pszQProcParms */
535 PACKS(desc,"z","NULL"); /* pszDriverName */
536 PackDriverData(desc); /* pDriverData */
537 PACKS(desc,"z",""); /* pszPrinterName */
538 } else if (uLevel == 4) { /* OS2 */
539 PACKS(desc,"z",""); /* pszSpoolFileName */
540 PACKS(desc,"z",""); /* pszPortName */
541 PACKS(desc,"z",""); /* pszStatus */
542 PACKI(desc,"D",0); /* ulPagesSpooled */
543 PACKI(desc,"D",0); /* ulPagesSent */
544 PACKI(desc,"D",0); /* ulPagesPrinted */
545 PACKI(desc,"D",0); /* ulTimePrinted */
546 PACKI(desc,"D",0); /* ulExtendJobStatus */
547 PACKI(desc,"D",0); /* ulStartPage */
548 PACKI(desc,"D",0); /* ulEndPage */
553 /********************************************************************
554 Return a driver name given an snum.
555 Returns True if from tdb, False otherwise.
556 ********************************************************************/
558 static BOOL get_driver_name(int snum, pstring drivername)
560 NT_PRINTER_INFO_LEVEL *info = NULL;
563 get_a_printer (NULL, &info, 2, lp_servicename(snum));
565 pstrcpy( drivername, info->info_2->drivername);
567 free_a_printer(&info, 2);
573 /********************************************************************
574 Respond to the DosPrintQInfo command with a level of 52
575 This is used to get printer driver information for Win9x clients
576 ********************************************************************/
577 static void fill_printq_info_52(connection_struct *conn, int snum,
578 struct pack_desc* desc, int count )
582 NT_PRINTER_DRIVER_INFO_LEVEL driver;
583 NT_PRINTER_INFO_LEVEL *printer = NULL;
587 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
588 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
589 lp_servicename(snum)));
593 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
596 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
597 printer->info_2->drivername));
601 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
602 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
603 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
605 PACKI(desc, "W", 0x0400); /* don't know */
606 PACKS(desc, "z", driver.info_3->name); /* long printer name */
607 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
608 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
609 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
611 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
612 standard_sub_basic( "", "", location, sizeof(location)-1 );
613 PACKS(desc,"z", location); /* share to retrieve files */
615 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
616 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
617 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
619 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
620 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
621 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
622 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
623 DEBUG(3,("Driver Location: %s:\n",location));
624 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
625 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
626 PACKI(desc,"N",count); /* number of files to copy */
628 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
630 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
631 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
632 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
637 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
640 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
642 desc->errcode=NERR_Success;
646 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
647 desc->errcode=NERR_notsupported;
651 free_a_printer( &printer, 2 );
654 free_a_printer_driver( driver, 3 );
658 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
659 struct pack_desc* desc,
660 int count, print_queue_struct* queue,
661 print_status_struct* status)
666 PACKS(desc,"B13",SERVICE(snum));
671 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
674 PACKI(desc,"K",printq_status(status->status));
678 if (uLevel == 1 || uLevel == 2) {
679 PACKS(desc,"B",""); /* alignment */
680 PACKI(desc,"W",5); /* priority */
681 PACKI(desc,"W",0); /* start time */
682 PACKI(desc,"W",0); /* until time */
683 PACKS(desc,"z",""); /* pSepFile */
684 PACKS(desc,"z","lpd"); /* pPrProc */
685 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
686 PACKS(desc,"z",""); /* pParms */
688 PACKS(desc,"z","UNKNOWN PRINTER");
689 PACKI(desc,"W",LPSTAT_ERROR);
691 else if (!status || !status->message[0]) {
692 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
693 PACKI(desc,"W",LPSTAT_OK); /* status */
695 PACKS(desc,"z",status->message);
696 PACKI(desc,"W",printq_status(status->status)); /* status */
698 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
701 if (uLevel == 3 || uLevel == 4) {
704 PACKI(desc,"W",5); /* uPriority */
705 PACKI(desc,"W",0); /* uStarttime */
706 PACKI(desc,"W",0); /* uUntiltime */
707 PACKI(desc,"W",5); /* pad1 */
708 PACKS(desc,"z",""); /* pszSepFile */
709 PACKS(desc,"z","WinPrint"); /* pszPrProc */
710 PACKS(desc,"z",NULL); /* pszParms */
711 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
712 /* "don't ask" that it's done this way to fix corrupted
713 Win9X/ME printer comments. */
715 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
717 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
719 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
720 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
721 get_driver_name(snum,drivername);
722 PACKS(desc,"z",drivername); /* pszDriverName */
723 PackDriverData(desc); /* pDriverData */
726 if (uLevel == 2 || uLevel == 4) {
728 for (i=0;i<count;i++)
729 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
733 fill_printq_info_52( conn, snum, desc, count );
736 /* This function returns the number of files for a given driver */
737 static int get_printerdrivernumber(int snum)
740 NT_PRINTER_DRIVER_INFO_LEVEL driver;
741 NT_PRINTER_INFO_LEVEL *printer = NULL;
745 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
746 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
747 lp_servicename(snum)));
751 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
754 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
755 printer->info_2->drivername));
759 /* count the number of files */
760 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
765 free_a_printer( &printer, 2 );
768 free_a_printer_driver( driver, 3 );
773 static BOOL api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
774 char *param, int tpscnt,
775 char *data, int tdscnt,
776 int mdrcnt,int mprcnt,
777 char **rdata,char **rparam,
778 int *rdata_len,int *rparam_len)
780 char *str1 = get_safe_offset(param,tpscnt,param,2);
781 char *str2 = skip_string(param,tpscnt,str1,1);
782 char *p = skip_string(param,tpscnt,str2,1);
788 struct pack_desc desc;
789 print_queue_struct *queue=NULL;
790 print_status_struct status;
793 if (!str1 || !str2 || !p) {
796 memset((char *)&status,'\0',sizeof(status));
797 memset((char *)&desc,'\0',sizeof(desc));
799 p = skip_string(param,tpscnt,p,1);
803 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
804 str3 = get_safe_offset(param,tpscnt,p,4) ? p + 4 : 0;
805 /* Check if string exists. */
806 if (skip_string(param,tpscnt,str3,1) == NULL) {
810 /* remove any trailing username */
811 if ((p = strchr_m(QueueName,'%')))
814 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
816 /* check it's a supported varient */
817 if (!prefix_ok(str1,"zWrLh"))
819 if (!check_printq_info(&desc,uLevel,str2,str3)) {
821 * Patch from Scott Moomaw <scott@bridgewater.edu>
822 * to return the 'invalid info level' error if an
823 * unknown level was requested.
827 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
831 SSVALS(*rparam,0,ERRunknownlevel);
837 snum = find_service(QueueName);
838 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
842 count = get_printerdrivernumber(snum);
843 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
845 count = print_queue_status(snum, &queue,&status);
849 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
854 desc.buflen = mdrcnt;
857 * Don't return data but need to get correct length
858 * init_package will return wrong size if buflen=0
860 desc.buflen = getlen(desc.format);
861 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
864 if (init_package(&desc,1,count)) {
865 desc.subcount = count;
866 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
869 *rdata_len = desc.usedlen;
872 * We must set the return code to ERRbuftoosmall
873 * in order to support lanman style printing with Win NT/2k
876 if (!mdrcnt && lp_disable_spoolss())
877 desc.errcode = ERRbuftoosmall;
879 *rdata_len = desc.usedlen;
881 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
885 SSVALS(*rparam,0,desc.errcode);
887 SSVAL(*rparam,4,desc.neededlen);
889 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
897 /****************************************************************************
898 View list of all print jobs on all queues.
899 ****************************************************************************/
901 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
902 char *param, int tpscnt,
903 char *data, int tdscnt,
904 int mdrcnt, int mprcnt,
905 char **rdata, char** rparam,
906 int *rdata_len, int *rparam_len)
908 char *param_format = get_safe_offset(param,tpscnt,param,2);
909 char *output_format1 = skip_string(param,tpscnt,param_format,1);
910 char *p = skip_string(param,tpscnt,output_format1,1);
911 unsigned int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
912 char *output_format2 = get_safe_offset(param,tpscnt,p,4);
913 int services = lp_numservices();
915 struct pack_desc desc;
916 print_queue_struct **queue = NULL;
917 print_status_struct *status = NULL;
918 int *subcntarr = NULL;
919 int queuecnt = 0, subcnt = 0, succnt = 0;
921 if (!param_format || !output_format1 || !p || !output_format2) {
926 output_format2 = p + 4;
928 memset((char *)&desc,'\0',sizeof(desc));
930 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
932 if (!prefix_ok(param_format,"WrLeh")) {
935 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
937 * Patch from Scott Moomaw <scott@bridgewater.edu>
938 * to return the 'invalid info level' error if an
939 * unknown level was requested.
943 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
947 SSVALS(*rparam,0,ERRunknownlevel);
953 for (i = 0; i < services; i++) {
954 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
959 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
960 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
963 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
964 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
965 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
968 memset(status,0,queuecnt*sizeof(print_status_struct));
969 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
970 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
976 for (i = 0; i < services; i++) {
977 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
978 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
979 subcnt += subcntarr[n];
985 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
991 desc.buflen = mdrcnt;
993 if (init_package(&desc,queuecnt,subcnt)) {
996 for (i = 0; i < services; i++) {
997 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
998 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1000 if (desc.errcode == NERR_Success) {
1007 SAFE_FREE(subcntarr);
1009 *rdata_len = desc.usedlen;
1011 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1015 SSVALS(*rparam,0,desc.errcode);
1017 SSVAL(*rparam,4,succnt);
1018 SSVAL(*rparam,6,queuecnt);
1020 for (i = 0; i < queuecnt; i++) {
1022 SAFE_FREE(queue[i]);
1033 SAFE_FREE(subcntarr);
1034 for (i = 0; i < queuecnt; i++) {
1036 SAFE_FREE(queue[i]);
1045 /****************************************************************************
1046 Get info level for a server list query.
1047 ****************************************************************************/
1049 static BOOL check_server_info(int uLevel, char* id)
1053 if (strcmp(id,"B16") != 0) {
1058 if (strcmp(id,"B16BBDz") != 0) {
1068 struct srv_info_struct {
1076 /*******************************************************************
1077 Get server info lists from the files saved by nmbd. Return the
1079 ******************************************************************/
1081 static int get_server_info(uint32 servertype,
1082 struct srv_info_struct **servers,
1088 BOOL local_list_only;
1091 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1093 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1097 /* request for everything is code for request all servers */
1098 if (servertype == SV_TYPE_ALL) {
1099 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1102 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1104 DEBUG(4,("Servertype search: %8x\n",servertype));
1106 for (i=0;lines[i];i++) {
1108 struct srv_info_struct *s;
1109 const char *ptr = lines[i];
1116 if (count == alloced) {
1118 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1120 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1121 file_lines_free(lines);
1124 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1126 s = &(*servers)[count];
1128 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1131 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1134 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1137 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1138 /* this allows us to cope with an old nmbd */
1139 fstrcpy(s->domain,lp_workgroup());
1142 if (sscanf(stype,"%X",&s->type) != 1) {
1143 DEBUG(4,("r:host file "));
1147 /* Filter the servers/domains we return based on what was asked for. */
1149 /* Check to see if we are being asked for a local list only. */
1150 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1151 DEBUG(4,("r: local list only"));
1155 /* doesn't match up: don't want it */
1156 if (!(servertype & s->type)) {
1157 DEBUG(4,("r:serv type "));
1161 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1162 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1163 DEBUG(4,("s: dom mismatch "));
1167 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1171 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1172 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1175 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1176 s->name, s->type, s->comment, s->domain));
1177 s->server_added = True;
1180 DEBUG(4,("%20s %8x %25s %15s\n",
1181 s->name, s->type, s->comment, s->domain));
1185 file_lines_free(lines);
1189 /*******************************************************************
1190 Fill in a server info structure.
1191 ******************************************************************/
1193 static int fill_srv_info(struct srv_info_struct *service,
1194 int uLevel, char **buf, int *buflen,
1195 char **stringbuf, int *stringspace, char *baseaddr)
1218 len = strlen(service->comment)+1;
1222 *buflen = struct_len;
1224 return struct_len + len;
1229 if (*buflen < struct_len) {
1236 p2 = p + struct_len;
1237 l2 = *buflen - struct_len;
1245 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1249 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1250 SIVAL(p,18,service->type);
1251 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1252 len += CopyAndAdvance(&p2,service->comment,&l2);
1257 *buf = p + struct_len;
1258 *buflen -= struct_len;
1269 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1271 return(strcmp(s1->name,s2->name));
1274 /****************************************************************************
1275 View list of servers available (or possibly domains). The info is
1276 extracted from lists saved by nmbd on the local host.
1277 ****************************************************************************/
1279 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1280 char *param, int tpscnt,
1281 char *data, int tdscnt,
1282 int mdrcnt, int mprcnt, char **rdata,
1283 char **rparam, int *rdata_len, int *rparam_len)
1285 char *str1 = get_safe_offset(param, tpscnt, param, 2);
1286 char *str2 = skip_string(param,tpscnt,str1,1);
1287 char *p = skip_string(param,tpscnt,str2,1);
1288 int uLevel = get_safe_offset(param, tpscnt, p, 2) ? SVAL(p,0) : -1;
1289 int buf_len = get_safe_offset(param,tpscnt, p, 4) ? SVAL(p,2) : 0;
1290 uint32 servertype = get_safe_offset(param,tpscnt,p,8) ? IVAL(p,4) : 0;
1292 int data_len, fixed_len, string_len;
1293 int f_len = 0, s_len = 0;
1294 struct srv_info_struct *servers=NULL;
1295 int counted=0,total=0;
1298 BOOL domain_request;
1301 if (!str1 || !str2 || !p) {
1305 /* If someone sets all the bits they don't really mean to set
1306 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1309 if (servertype == SV_TYPE_ALL) {
1310 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1313 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1314 any other bit (they may just set this bit on it's own) they
1315 want all the locally seen servers. However this bit can be
1316 set on its own so set the requested servers to be
1317 ALL - DOMAIN_ENUM. */
1319 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1320 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1323 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1324 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1328 if (!prefix_ok(str1,"WrLehD")) {
1331 if (!check_server_info(uLevel,str2)) {
1335 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1336 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1337 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1339 if (strcmp(str1, "WrLehDz") == 0) {
1340 if (skip_string(param,tpscnt,p,1) == NULL) {
1343 pull_ascii_fstring(domain, p);
1345 fstrcpy(domain, lp_workgroup());
1348 if (lp_browse_list()) {
1349 total = get_server_info(servertype,&servers,domain);
1352 data_len = fixed_len = string_len = 0;
1356 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1360 char *lastname=NULL;
1362 for (i=0;i<total;i++) {
1363 struct srv_info_struct *s = &servers[i];
1365 if (lastname && strequal(lastname,s->name)) {
1369 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1370 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1371 s->name, s->type, s->comment, s->domain));
1373 if (data_len <= buf_len) {
1376 string_len += s_len;
1383 *rdata_len = fixed_len + string_len;
1384 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1388 memset(*rdata,'\0',*rdata_len);
1390 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1396 char *lastname=NULL;
1397 int count2 = counted;
1399 for (i = 0; i < total && count2;i++) {
1400 struct srv_info_struct *s = &servers[i];
1402 if (lastname && strequal(lastname,s->name)) {
1406 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1407 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1408 s->name, s->type, s->comment, s->domain));
1414 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1418 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1420 SSVAL(*rparam,4,counted);
1421 SSVAL(*rparam,6,counted+missed);
1425 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1426 domain,uLevel,counted,counted+missed));
1431 /****************************************************************************
1432 command 0x34 - suspected of being a "Lookup Names" stub api
1433 ****************************************************************************/
1435 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1436 char *param, int tpscnt,
1437 char *data, int tdscnt,
1438 int mdrcnt, int mprcnt, char **rdata,
1439 char **rparam, int *rdata_len, int *rparam_len)
1441 char *str1 = get_safe_offset(param,tpscnt,param,2);
1442 char *str2 = skip_string(param,tpscnt,str1,1);
1443 char *p = skip_string(param,tpscnt,str2,1);
1444 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
1445 int buf_len = get_safe_offset(param,tpscnt,p,4) ? SVAL(p,2) : 0;
1449 if (!str1 || !str2 || !p) {
1453 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1454 str1, str2, p, uLevel, buf_len));
1456 if (!prefix_ok(str1,"zWrLeh")) {
1463 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1468 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1470 SSVAL(*rparam,4,counted);
1471 SSVAL(*rparam,6,counted+missed);
1476 /****************************************************************************
1477 get info about a share
1478 ****************************************************************************/
1480 static BOOL check_share_info(int uLevel, char* id)
1484 if (strcmp(id,"B13") != 0) {
1489 if (strcmp(id,"B13BWz") != 0) {
1494 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1499 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1509 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1510 char** buf, int* buflen,
1511 char** stringbuf, int* stringspace, char* baseaddr)
1541 len += StrlenExpanded(conn,snum,lp_comment(snum));
1544 len += strlen(lp_pathname(snum)) + 1;
1547 *buflen = struct_len;
1552 return struct_len + len;
1557 if ((*buflen) < struct_len) {
1565 p2 = p + struct_len;
1566 l2 = (*buflen) - struct_len;
1573 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1579 type = STYPE_DISKTREE;
1580 if (lp_print_ok(snum)) {
1581 type = STYPE_PRINTQ;
1583 if (strequal("IPC",lp_fstype(snum))) {
1586 SSVAL(p,14,type); /* device type */
1587 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1588 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1592 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1593 SSVALS(p,22,-1); /* max uses */
1594 SSVAL(p,24,1); /* current uses */
1595 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1596 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1597 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1601 memset(p+40,0,SHPWLEN+2);
1612 (*buf) = p + struct_len;
1613 (*buflen) -= struct_len;
1615 (*stringspace) = l2;
1624 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1625 char *param, int tpscnt,
1626 char *data, int tdscnt,
1627 int mdrcnt,int mprcnt,
1628 char **rdata,char **rparam,
1629 int *rdata_len,int *rparam_len)
1631 char *str1 = get_safe_offset(param,tpscnt,param,2);
1632 char *str2 = skip_string(param,tpscnt,str1,1);
1633 char *netname = skip_string(param,tpscnt,str2,1);
1634 char *p = skip_string(param,tpscnt,netname,1);
1635 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
1638 if (!str1 || !str2 || !netname || !p) {
1642 snum = find_service(netname);
1647 /* check it's a supported varient */
1648 if (!prefix_ok(str1,"zWrLh")) {
1651 if (!check_share_info(uLevel,str2)) {
1655 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1660 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1661 if (*rdata_len < 0) {
1666 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1670 SSVAL(*rparam,0,NERR_Success);
1671 SSVAL(*rparam,2,0); /* converter word */
1672 SSVAL(*rparam,4,*rdata_len);
1677 /****************************************************************************
1678 View the list of available shares.
1680 This function is the server side of the NetShareEnum() RAP call.
1681 It fills the return buffer with share names and share comments.
1682 Note that the return buffer normally (in all known cases) allows only
1683 twelve byte strings for share names (plus one for a nul terminator).
1684 Share names longer than 12 bytes must be skipped.
1685 ****************************************************************************/
1687 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1688 char *param, int tpscnt,
1689 char *data, int tdscnt,
1697 char *str1 = get_safe_offset(param,tpscnt,param,2);
1698 char *str2 = skip_string(param,tpscnt,str1,1);
1699 char *p = skip_string(param,tpscnt,str2,1);
1700 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
1701 int buf_len = get_safe_offset(param,tpscnt,p,4) ? SVAL(p,2) : 0;
1704 int total=0,counted=0;
1705 BOOL missed = False;
1707 int data_len, fixed_len, string_len;
1708 int f_len = 0, s_len = 0;
1710 if (!str1 || !str2 || !p) {
1714 if (!prefix_ok(str1,"WrLeh")) {
1717 if (!check_share_info(uLevel,str2)) {
1721 /* Ensure all the usershares are loaded. */
1723 load_registry_shares();
1724 count = load_usershare_shares();
1727 data_len = fixed_len = string_len = 0;
1728 for (i=0;i<count;i++) {
1729 fstring servicename_dos;
1730 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1733 push_ascii_fstring(servicename_dos, lp_servicename(i));
1734 /* Maximum name length = 13. */
1735 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1737 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1738 if (data_len <= buf_len) {
1741 string_len += s_len;
1748 *rdata_len = fixed_len + string_len;
1749 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1753 memset(*rdata,0,*rdata_len);
1755 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1760 for( i = 0; i < count; i++ ) {
1761 fstring servicename_dos;
1762 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1766 push_ascii_fstring(servicename_dos, lp_servicename(i));
1767 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1768 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1775 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1779 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1781 SSVAL(*rparam,4,counted);
1782 SSVAL(*rparam,6,total);
1784 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1785 counted,total,uLevel,
1786 buf_len,*rdata_len,mdrcnt));
1791 /****************************************************************************
1793 ****************************************************************************/
1795 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1796 char *param, int tpscnt,
1797 char *data, int tdscnt,
1798 int mdrcnt,int mprcnt,
1799 char **rdata,char **rparam,
1800 int *rdata_len,int *rparam_len)
1802 char *str1 = get_safe_offset(param,tpscnt,param,2);
1803 char *str2 = skip_string(param,tpscnt,str1,1);
1804 char *p = skip_string(param,tpscnt,str2,1);
1805 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
1809 char *command, *cmdname;
1810 unsigned int offset;
1814 if (!str1 || !str2 || !p) {
1818 /* check it's a supported varient */
1819 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1822 if (!check_share_info(uLevel,str2)) {
1829 /* Do we have a string ? */
1830 if (skip_string(data,mdrcnt,data,1) == NULL) {
1833 pull_ascii_fstring(sharename,data);
1834 snum = find_service(sharename);
1835 if (snum >= 0) { /* already exists */
1844 /* only support disk share adds */
1845 if (SVAL(data,14)!=STYPE_DISKTREE) {
1849 offset = IVAL(data, 16);
1850 if (offset >= mdrcnt) {
1851 res = ERRinvalidparam;
1855 /* Do we have a string ? */
1856 if (skip_string(data,mdrcnt,data+offset,1) == NULL) {
1859 pull_ascii_fstring(comment, offset? (data+offset) : "");
1861 offset = IVAL(data, 26);
1863 if (offset >= mdrcnt) {
1864 res = ERRinvalidparam;
1868 /* Do we have a string ? */
1869 if (skip_string(data,mdrcnt,data+offset,1) == NULL) {
1872 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1874 string_replace(sharename, '"', ' ');
1875 string_replace(pathname, '"', ' ');
1876 string_replace(comment, '"', ' ');
1878 cmdname = lp_add_share_cmd();
1880 if (!cmdname || *cmdname == '\0') {
1884 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1885 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1888 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1890 if ((res = smbrun(command, NULL)) != 0) {
1891 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1897 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1904 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1908 SSVAL(*rparam,0,NERR_Success);
1909 SSVAL(*rparam,2,0); /* converter word */
1910 SSVAL(*rparam,4,*rdata_len);
1918 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1923 SSVAL(*rparam,0,res);
1928 /****************************************************************************
1929 view list of groups available
1930 ****************************************************************************/
1932 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1933 char *param, int tpscnt,
1934 char *data, int tdscnt,
1935 int mdrcnt,int mprcnt,
1936 char **rdata,char **rparam,
1937 int *rdata_len,int *rparam_len)
1941 int resume_context, cli_buf_size;
1942 char *str1 = get_safe_offset(param,tpscnt,param,2);
1943 char *str2 = skip_string(param,tpscnt,str1,1);
1944 char *p = skip_string(param,tpscnt,str2,1);
1946 struct pdb_search *search;
1947 struct samr_displayentry *entries;
1951 if (!str1 || !str2 || !p) {
1955 if (strcmp(str1,"WrLeh") != 0) {
1960 * W-> resume context (number of users to skip)
1961 * r -> return parameter pointer to receive buffer
1962 * L -> length of receive buffer
1963 * e -> return parameter number of entries
1964 * h -> return parameter total number of users
1967 if (strcmp("B21",str2) != 0) {
1971 /* get list of domain groups SID_DOMAIN_GRP=2 */
1973 search = pdb_search_groups();
1976 if (search == NULL) {
1977 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1981 resume_context = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
1982 cli_buf_size= get_safe_offset(param,tpscnt,p,4) ? SVAL(p+2,0) : 0;
1983 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1984 "%d\n", resume_context, cli_buf_size));
1987 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1991 *rdata_len = cli_buf_size;
1992 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1999 for(i=0; i<num_entries; i++) {
2001 fstrcpy(name, entries[i].account_name);
2002 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2003 /* truncate the name at 21 chars. */
2004 memcpy(p, name, 21);
2005 DEBUG(10,("adding entry %d group %s\n", i, p));
2007 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2010 /* set overflow error */
2011 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2017 pdb_search_destroy(search);
2019 *rdata_len = PTR_DIFF(p,*rdata);
2022 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2026 SSVAL(*rparam, 0, errflags);
2027 SSVAL(*rparam, 2, 0); /* converter word */
2028 SSVAL(*rparam, 4, i); /* is this right?? */
2029 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2034 /*******************************************************************
2035 Get groups that a user is a member of.
2036 ******************************************************************/
2038 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2039 char *param, int tpscnt,
2040 char *data, int tdscnt,
2041 int mdrcnt,int mprcnt,
2042 char **rdata,char **rparam,
2043 int *rdata_len,int *rparam_len)
2045 char *str1 = get_safe_offset(param,tpscnt,param,2);
2046 char *str2 = skip_string(param,tpscnt,str1,1);
2047 char *UserName = skip_string(param,tpscnt,str2,1);
2048 char *p = skip_string(param,tpscnt,UserName,1);
2049 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
2050 const char *level_string;
2052 struct samu *sampw = NULL;
2060 enum lsa_SidType type;
2061 TALLOC_CTX *mem_ctx;
2063 if (!str1 || !str2 || !UserName || !p) {
2068 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2073 /* check it's a supported varient */
2075 if ( strcmp(str1,"zWrLeh") != 0 )
2080 level_string = "B21";
2086 if (strcmp(level_string,str2) != 0)
2089 *rdata_len = mdrcnt + 1024;
2090 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2094 SSVAL(*rparam,0,NERR_Success);
2095 SSVAL(*rparam,2,0); /* converter word */
2099 mem_ctx = talloc_new(NULL);
2100 if (mem_ctx == NULL) {
2101 DEBUG(0, ("talloc_new failed\n"));
2105 if ( !(sampw = samu_new(mem_ctx)) ) {
2106 DEBUG(0, ("samu_new() failed!\n"));
2107 TALLOC_FREE(mem_ctx);
2111 /* Lookup the user information; This should only be one of
2112 our accounts (not remote domains) */
2114 become_root(); /* ROOT BLOCK */
2116 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2117 NULL, NULL, &user_sid, &type)) {
2118 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2122 if (type != SID_NAME_USER) {
2123 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2124 sid_type_lookup(type)));
2128 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2129 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2130 sid_string_static(&user_sid), UserName));
2138 result = pdb_enum_group_memberships(mem_ctx, sampw,
2139 &sids, &gids, &num_groups);
2141 if (!NT_STATUS_IS_OK(result)) {
2142 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2147 for (i=0; i<num_groups; i++) {
2149 const char *grp_name;
2151 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2152 pstrcpy(p, grp_name);
2158 *rdata_len = PTR_DIFF(p,*rdata);
2160 SSVAL(*rparam,4,count); /* is this right?? */
2161 SSVAL(*rparam,6,count); /* is this right?? */
2166 unbecome_root(); /* END ROOT BLOCK */
2168 TALLOC_FREE(mem_ctx);
2173 /*******************************************************************
2175 ******************************************************************/
2177 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2178 char *param, int tpscnt,
2179 char *data, int tdscnt,
2180 int mdrcnt,int mprcnt,
2181 char **rdata,char **rparam,
2182 int *rdata_len,int *rparam_len)
2187 int i, resume_context, cli_buf_size;
2188 struct pdb_search *search;
2189 struct samr_displayentry *users;
2191 char *str1 = get_safe_offset(param,tpscnt,param,2);
2192 char *str2 = skip_string(param,tpscnt,str1,1);
2193 char *p = skip_string(param,tpscnt,str2,1);
2195 if (!str1 || !str2 || !p) {
2199 if (strcmp(str1,"WrLeh") != 0)
2202 * W-> resume context (number of users to skip)
2203 * r -> return parameter pointer to receive buffer
2204 * L -> length of receive buffer
2205 * e -> return parameter number of entries
2206 * h -> return parameter total number of users
2209 resume_context = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
2210 cli_buf_size= get_safe_offset(param,tpscnt,p,4) ? SVAL(p+2,0) : 0;
2211 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2212 resume_context, cli_buf_size));
2215 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2220 /* check it's a supported varient */
2221 if (strcmp("B21",str2) != 0)
2224 *rdata_len = cli_buf_size;
2225 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2233 search = pdb_search_users(ACB_NORMAL);
2235 if (search == NULL) {
2236 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2241 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2245 errflags=NERR_Success;
2247 for (i=0; i<num_users; i++) {
2248 const char *name = users[i].account_name;
2250 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2252 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2253 "%s\n",count_sent,p));
2257 /* set overflow error */
2258 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2259 "username %s\n",count_sent,name));
2265 pdb_search_destroy(search);
2267 *rdata_len = PTR_DIFF(p,*rdata);
2269 SSVAL(*rparam,0,errflags);
2270 SSVAL(*rparam,2,0); /* converter word */
2271 SSVAL(*rparam,4,count_sent); /* is this right?? */
2272 SSVAL(*rparam,6,num_users); /* is this right?? */
2277 /****************************************************************************
2278 Get the time of day info.
2279 ****************************************************************************/
2281 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2282 char *param, int tpscnt,
2283 char *data, int tdscnt,
2284 int mdrcnt,int mprcnt,
2285 char **rdata,char **rparam,
2286 int *rdata_len,int *rparam_len)
2289 time_t unixdate = time(NULL);
2293 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2299 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2304 SSVAL(*rparam,0,NERR_Success);
2305 SSVAL(*rparam,2,0); /* converter word */
2309 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2310 by NT in a "net time" operation,
2311 it seems to ignore the one below */
2313 /* the client expects to get localtime, not GMT, in this bit
2314 (I think, this needs testing) */
2315 t = localtime(&unixdate);
2320 SIVAL(p,4,0); /* msecs ? */
2321 SCVAL(p,8,t->tm_hour);
2322 SCVAL(p,9,t->tm_min);
2323 SCVAL(p,10,t->tm_sec);
2324 SCVAL(p,11,0); /* hundredths of seconds */
2325 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2326 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2327 SCVAL(p,16,t->tm_mday);
2328 SCVAL(p,17,t->tm_mon + 1);
2329 SSVAL(p,18,1900+t->tm_year);
2330 SCVAL(p,20,t->tm_wday);
2335 /****************************************************************************
2336 Set the user password.
2337 *****************************************************************************/
2339 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2340 char *param, int tpscnt,
2341 char *data, int tdscnt,
2342 int mdrcnt,int mprcnt,
2343 char **rdata,char **rparam,
2344 int *rdata_len,int *rparam_len)
2346 char *np = get_safe_offset(param,tpscnt,param,2);
2347 char *p = skip_string(param,tpscnt,np,2);
2349 fstring pass1,pass2;
2355 /* Do we have a string ? */
2356 if (skip_string(param,tpscnt,p,1) == NULL) {
2359 pull_ascii_fstring(user,p);
2361 p = skip_string(param,tpscnt,p,1);
2366 memset(pass1,'\0',sizeof(pass1));
2367 memset(pass2,'\0',sizeof(pass2));
2368 if (get_safe_offset(param,tpscnt,p,32) == NULL) {
2372 memcpy(pass2,p+16,16);
2375 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2382 SSVAL(*rparam,0,NERR_badpass);
2383 SSVAL(*rparam,2,0); /* converter word */
2385 DEBUG(3,("Set password for <%s>\n",user));
2388 * Attempt to verify the old password against smbpasswd entries
2389 * Win98 clients send old and new password in plaintext for this call.
2393 auth_serversupplied_info *server_info = NULL;
2394 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2396 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2399 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2400 SSVAL(*rparam,0,NERR_Success);
2404 TALLOC_FREE(server_info);
2406 data_blob_clear_free(&password);
2410 * If the plaintext change failed, attempt
2411 * the old encrypted method. NT will generate this
2412 * after trying the samr method. Note that this
2413 * method is done as a last resort as this
2414 * password change method loses the NT password hash
2415 * and cannot change the UNIX password as no plaintext
2419 if(SVAL(*rparam,0) != NERR_Success) {
2420 struct samu *hnd = NULL;
2422 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2424 if (change_lanman_password(hnd,(uchar *)pass2)) {
2425 SSVAL(*rparam,0,NERR_Success);
2432 memset((char *)pass1,'\0',sizeof(fstring));
2433 memset((char *)pass2,'\0',sizeof(fstring));
2438 /****************************************************************************
2439 Set the user password (SamOEM version - gets plaintext).
2440 ****************************************************************************/
2442 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2443 char *param, int tpscnt,
2444 char *data, int tdscnt,
2445 int mdrcnt,int mprcnt,
2446 char **rdata,char **rparam,
2447 int *rdata_len,int *rparam_len)
2450 char *p = get_safe_offset(param,tpscnt,param,2);
2452 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2462 SSVAL(*rparam,0,NERR_badpass);
2465 * Check the parameter definition is correct.
2468 /* Do we have a string ? */
2469 if (skip_string(param,tpscnt,p,1) == 0) {
2472 if(!strequal(p, "zsT")) {
2473 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2476 p = skip_string(param, tpscnt, p, 1);
2481 /* Do we have a string ? */
2482 if (skip_string(param,tpscnt,p,1) == 0) {
2485 if(!strequal(p, "B516B16")) {
2486 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2489 p = skip_string(param,tpscnt,p,1);
2493 /* Do we have a string ? */
2494 if (skip_string(param,tpscnt,p,1) == 0) {
2497 p += pull_ascii_fstring(user,p);
2499 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2502 * Pass the user through the NT -> unix user mapping
2506 (void)map_username(user);
2508 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2509 SSVAL(*rparam,0,NERR_Success);
2515 /****************************************************************************
2518 ****************************************************************************/
2520 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2521 char *param, int tpscnt,
2522 char *data, int tdscnt,
2523 int mdrcnt,int mprcnt,
2524 char **rdata,char **rparam,
2525 int *rdata_len,int *rparam_len)
2527 int function = get_safe_offset(param,tpscnt,param,2) ? SVAL(param,0) : 0;
2528 char *str1 = get_safe_offset(param,tpscnt,param,2);
2529 char *str2 = skip_string(param,tpscnt,str1,1);
2530 char *p = skip_string(param,tpscnt,str2,1);
2535 WERROR werr = WERR_OK;
2537 if (!str1 || !str2 || !p) {
2540 if (get_safe_offset(param,tpscnt,p,2) == NULL) {
2543 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2546 /* check it's a supported varient */
2547 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2551 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2557 if (!print_job_exists(sharename, jobid)) {
2558 errcode = NERR_JobNotFound;
2562 snum = lp_servicenumber( sharename);
2564 errcode = NERR_DestNotFound;
2568 errcode = NERR_notsupported;
2571 case 81: /* delete */
2572 if (print_job_delete(¤t_user, snum, jobid, &werr))
2573 errcode = NERR_Success;
2575 case 82: /* pause */
2576 if (print_job_pause(¤t_user, snum, jobid, &werr))
2577 errcode = NERR_Success;
2579 case 83: /* resume */
2580 if (print_job_resume(¤t_user, snum, jobid, &werr))
2581 errcode = NERR_Success;
2585 if (!W_ERROR_IS_OK(werr))
2586 errcode = W_ERROR_V(werr);
2589 SSVAL(*rparam,0,errcode);
2590 SSVAL(*rparam,2,0); /* converter word */
2595 /****************************************************************************
2596 Purge a print queue - or pause or resume it.
2597 ****************************************************************************/
2599 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2600 char *param, int tpscnt,
2601 char *data, int tdscnt,
2602 int mdrcnt,int mprcnt,
2603 char **rdata,char **rparam,
2604 int *rdata_len,int *rparam_len)
2606 int function = get_safe_offset(param,tpscnt,param,2) ? SVAL(param,0) : 0;
2607 char *str1 = get_safe_offset(param,tpscnt,param,2);
2608 char *str2 = skip_string(param,tpscnt,str1,1);
2609 char *QueueName = skip_string(param,tpscnt,str2,1);
2610 int errcode = NERR_notsupported;
2612 WERROR werr = WERR_OK;
2614 if (!str1 || !str2 || !QueueName) {
2618 /* check it's a supported varient */
2619 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2623 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2629 snum = print_queue_snum(QueueName);
2632 errcode = NERR_JobNotFound;
2637 case 74: /* Pause queue */
2638 if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success;
2640 case 75: /* Resume queue */
2641 if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success;
2643 case 103: /* Purge */
2644 if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success;
2648 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2651 SSVAL(*rparam,0,errcode);
2652 SSVAL(*rparam,2,0); /* converter word */
2657 /****************************************************************************
2658 set the property of a print job (undocumented?)
2659 ? function = 0xb -> set name of print job
2660 ? function = 0x6 -> move print job up/down
2661 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2662 or <WWsTP> <WB21BB16B10zWWzDDz>
2663 ****************************************************************************/
2665 static int check_printjob_info(struct pack_desc* desc,
2666 int uLevel, char* id)
2668 desc->subformat = NULL;
2670 case 0: desc->format = "W"; break;
2671 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2672 case 2: desc->format = "WWzWWDDzz"; break;
2673 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2674 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2675 default: return False;
2677 if (strcmp(desc->format,id) != 0) return False;
2681 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2682 char *param, int tpscnt,
2683 char *data, int tdscnt,
2684 int mdrcnt,int mprcnt,
2685 char **rdata,char **rparam,
2686 int *rdata_len,int *rparam_len)
2688 struct pack_desc desc;
2689 char *str1 = get_safe_offset(param,tpscnt,param,2);
2690 char *str2 = skip_string(param,tpscnt,str1,1);
2691 char *p = skip_string(param,tpscnt,str2,1);
2694 int uLevel = get_safe_offset(param,tpscnt,p,4) ? SVAL(p,2) : -1;
2695 int function = get_safe_offset(param,tpscnt,p,6) ? SVAL(p,4) : -1;
2698 if (!str1 || !str2 || !p) {
2701 if (get_safe_offset(param,tpscnt,p,2) == NULL) {
2704 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2707 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2712 if (!share_defined(sharename)) {
2713 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2720 /* check it's a supported varient */
2721 if ((strcmp(str1,"WWsTP")) ||
2722 (!check_printjob_info(&desc,uLevel,str2)))
2725 if (!print_job_exists(sharename, jobid)) {
2726 errcode=NERR_JobNotFound;
2730 errcode = NERR_notsupported;
2734 /* change job place in the queue,
2735 data gives the new place */
2736 place = SVAL(data,0);
2737 if (print_job_set_place(sharename, jobid, place)) {
2738 errcode=NERR_Success;
2743 /* change print job name, data gives the name */
2744 if (print_job_set_name(sharename, jobid, data)) {
2745 errcode=NERR_Success;
2754 SSVALS(*rparam,0,errcode);
2755 SSVAL(*rparam,2,0); /* converter word */
2761 /****************************************************************************
2762 Get info about the server.
2763 ****************************************************************************/
2765 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2766 char *param, int tpscnt,
2767 char *data, int tdscnt,
2768 int mdrcnt,int mprcnt,
2769 char **rdata,char **rparam,
2770 int *rdata_len,int *rparam_len)
2772 char *str1 = get_safe_offset(param,tpscnt,param,2);
2773 char *str2 = skip_string(param,tpscnt,str1,1);
2774 char *p = skip_string(param,tpscnt,str2,1);
2775 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
2779 if (!str1 || !str2 || !p) {
2783 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2785 /* check it's a supported varient */
2786 if (!prefix_ok(str1,"WrLh")) {
2792 if (strcmp(str2,"B16") != 0) {
2798 if (strcmp(str2,"B16BBDz") != 0) {
2804 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2810 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2816 if (strcmp(str2,"DN") != 0) {
2822 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2831 *rdata_len = mdrcnt;
2832 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2838 p2 = p + struct_len;
2840 srvstr_push(NULL, p,global_myname(),16,
2841 STR_ASCII|STR_UPPER|STR_TERMINATE);
2845 struct srv_info_struct *servers=NULL;
2848 uint32 servertype= lp_default_server_announce();
2850 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2852 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2853 for (i=0;i<count;i++) {
2854 if (strequal(servers[i].name,global_myname())) {
2855 servertype = servers[i].type;
2856 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2863 SCVAL(p,0,lp_major_announce_version());
2864 SCVAL(p,1,lp_minor_announce_version());
2865 SIVAL(p,2,servertype);
2867 if (mdrcnt == struct_len) {
2870 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2871 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2872 conn->connectpath, conn->gid,
2873 get_current_username(),
2874 current_user_info.domain,
2875 comment, sizeof(comment));
2876 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2877 p2 = skip_string(*rdata,*rdata_len,p2,1);
2885 return False; /* not yet implemented */
2888 *rdata_len = PTR_DIFF(p2,*rdata);
2891 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2895 SSVAL(*rparam,0,NERR_Success);
2896 SSVAL(*rparam,2,0); /* converter word */
2897 SSVAL(*rparam,4,*rdata_len);
2902 /****************************************************************************
2903 Get info about the server.
2904 ****************************************************************************/
2906 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2907 char *param, int tpscnt,
2908 char *data, int tdscnt,
2909 int mdrcnt,int mprcnt,
2910 char **rdata,char **rparam,
2911 int *rdata_len,int *rparam_len)
2913 char *str1 = get_safe_offset(param,tpscnt,param,2);
2914 char *str2 = skip_string(param,tpscnt,str1,1);
2915 char *p = skip_string(param,tpscnt,str2,1);
2917 int level = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
2919 if (!str1 || !str2 || !p) {
2923 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2926 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2931 /* check it's a supported varient */
2932 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2936 *rdata_len = mdrcnt + 1024;
2937 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2942 SSVAL(*rparam,0,NERR_Success);
2943 SSVAL(*rparam,2,0); /* converter word */
2946 p2 = get_safe_offset(*rdata,*rdata_len,p,22);
2951 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2952 pstrcpy(p2,get_local_machine_name());
2954 p2 = skip_string(*rdata,*rdata_len,p2,1);
2960 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2961 pstrcpy(p2,current_user_info.smb_name);
2962 p2 = skip_string(*rdata,*rdata_len,p2,1);
2968 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2969 pstrcpy(p2,lp_workgroup());
2971 p2 = skip_string(*rdata,*rdata_len,p2,1);
2977 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2978 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2981 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2982 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
2983 p2 = skip_string(*rdata,*rdata_len,p2,1);
2989 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2991 p2 = skip_string(*rdata,*rdata_len,p2,1);
2997 *rdata_len = PTR_DIFF(p2,*rdata);
2999 SSVAL(*rparam,4,*rdata_len);
3004 /****************************************************************************
3005 get info about a user
3007 struct user_info_11 {
3008 char usri11_name[21]; 0-20
3010 char *usri11_comment; 22-25
3011 char *usri11_usr_comment; 26-29
3012 unsigned short usri11_priv; 30-31
3013 unsigned long usri11_auth_flags; 32-35
3014 long usri11_password_age; 36-39
3015 char *usri11_homedir; 40-43
3016 char *usri11_parms; 44-47
3017 long usri11_last_logon; 48-51
3018 long usri11_last_logoff; 52-55
3019 unsigned short usri11_bad_pw_count; 56-57
3020 unsigned short usri11_num_logons; 58-59
3021 char *usri11_logon_server; 60-63
3022 unsigned short usri11_country_code; 64-65
3023 char *usri11_workstations; 66-69
3024 unsigned long usri11_max_storage; 70-73
3025 unsigned short usri11_units_per_week; 74-75
3026 unsigned char *usri11_logon_hours; 76-79
3027 unsigned short usri11_code_page; 80-81
3032 usri11_name specifies the user name for which information is retireved
3034 usri11_pad aligns the next data structure element to a word boundary
3036 usri11_comment is a null terminated ASCII comment
3038 usri11_user_comment is a null terminated ASCII comment about the user
3040 usri11_priv specifies the level of the privilege assigned to the user.
3041 The possible values are:
3043 Name Value Description
3044 USER_PRIV_GUEST 0 Guest privilege
3045 USER_PRIV_USER 1 User privilege
3046 USER_PRV_ADMIN 2 Administrator privilege
3048 usri11_auth_flags specifies the account operator privileges. The
3049 possible values are:
3051 Name Value Description
3052 AF_OP_PRINT 0 Print operator
3055 Leach, Naik [Page 28]
3059 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3062 AF_OP_COMM 1 Communications operator
3063 AF_OP_SERVER 2 Server operator
3064 AF_OP_ACCOUNTS 3 Accounts operator
3067 usri11_password_age specifies how many seconds have elapsed since the
3068 password was last changed.
3070 usri11_home_dir points to a null terminated ASCII string that contains
3071 the path name of the user's home directory.
3073 usri11_parms points to a null terminated ASCII string that is set
3074 aside for use by applications.
3076 usri11_last_logon specifies the time when the user last logged on.
3077 This value is stored as the number of seconds elapsed since
3078 00:00:00, January 1, 1970.
3080 usri11_last_logoff specifies the time when the user last logged off.
3081 This value is stored as the number of seconds elapsed since
3082 00:00:00, January 1, 1970. A value of 0 means the last logoff
3085 usri11_bad_pw_count specifies the number of incorrect passwords
3086 entered since the last successful logon.
3088 usri11_log1_num_logons specifies the number of times this user has
3089 logged on. A value of -1 means the number of logons is unknown.
3091 usri11_logon_server points to a null terminated ASCII string that
3092 contains the name of the server to which logon requests are sent.
3093 A null string indicates logon requests should be sent to the
3096 usri11_country_code specifies the country code for the user's language
3099 usri11_workstations points to a null terminated ASCII string that
3100 contains the names of workstations the user may log on from.
3101 There may be up to 8 workstations, with the names separated by
3102 commas. A null strings indicates there are no restrictions.
3104 usri11_max_storage specifies the maximum amount of disk space the user
3105 can occupy. A value of 0xffffffff indicates there are no
3108 usri11_units_per_week specifies the equal number of time units into
3109 which a week is divided. This value must be equal to 168.
3111 usri11_logon_hours points to a 21 byte (168 bits) string that
3112 specifies the time during which the user can log on. Each bit
3113 represents one unique hour in a week. The first bit (bit 0, word
3114 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3118 Leach, Naik [Page 29]
3122 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3125 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3126 are no restrictions.
3128 usri11_code_page specifies the code page for the user's language of
3131 All of the pointers in this data structure need to be treated
3132 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3133 to be ignored. The converter word returned in the parameters section
3134 needs to be subtracted from the lower 16 bits to calculate an offset
3135 into the return buffer where this ASCII string resides.
3137 There is no auxiliary data in the response.
3139 ****************************************************************************/
3141 #define usri11_name 0
3142 #define usri11_pad 21
3143 #define usri11_comment 22
3144 #define usri11_usr_comment 26
3145 #define usri11_full_name 30
3146 #define usri11_priv 34
3147 #define usri11_auth_flags 36
3148 #define usri11_password_age 40
3149 #define usri11_homedir 44
3150 #define usri11_parms 48
3151 #define usri11_last_logon 52
3152 #define usri11_last_logoff 56
3153 #define usri11_bad_pw_count 60
3154 #define usri11_num_logons 62
3155 #define usri11_logon_server 64
3156 #define usri11_country_code 68
3157 #define usri11_workstations 70
3158 #define usri11_max_storage 74
3159 #define usri11_units_per_week 78
3160 #define usri11_logon_hours 80
3161 #define usri11_code_page 84
3162 #define usri11_end 86
3164 #define USER_PRIV_GUEST 0
3165 #define USER_PRIV_USER 1
3166 #define USER_PRIV_ADMIN 2
3168 #define AF_OP_PRINT 0
3169 #define AF_OP_COMM 1
3170 #define AF_OP_SERVER 2
3171 #define AF_OP_ACCOUNTS 3
3174 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3175 char *param, int tpscnt,
3176 char *data, int tdscnt,
3177 int mdrcnt,int mprcnt,
3178 char **rdata,char **rparam,
3179 int *rdata_len,int *rparam_len)
3181 char *str1 = get_safe_offset(param,tpscnt,param,2);
3182 char *str2 = skip_string(param,tpscnt,str1,1);
3183 char *UserName = skip_string(param,tpscnt,str2,1);
3184 char *p = skip_string(param,tpscnt,UserName,1);
3185 int uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
3187 const char *level_string;
3189 /* get NIS home of a previously validated user - simeon */
3190 /* With share level security vuid will always be zero.
3191 Don't depend on vuser being non-null !!. JRA */
3192 user_struct *vuser = get_valid_user_struct(vuid);
3194 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3195 vuser->user.unix_name));
3198 if (!str1 || !str2 || !UserName || !p) {
3203 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3208 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3210 /* check it's a supported variant */
3211 if (strcmp(str1,"zWrLh") != 0) {
3215 case 0: level_string = "B21"; break;
3216 case 1: level_string = "B21BB16DWzzWz"; break;
3217 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3218 case 10: level_string = "B21Bzzz"; break;
3219 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3220 default: return False;
3223 if (strcmp(level_string,str2) != 0) {
3227 *rdata_len = mdrcnt + 1024;
3228 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3233 SSVAL(*rparam,0,NERR_Success);
3234 SSVAL(*rparam,2,0); /* converter word */
3237 p2 = get_safe_offset(*rdata,*rdata_len,p,usri11_end);
3243 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3246 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3251 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3252 pstrcpy(p2,"Comment");
3253 p2 = skip_string(*rdata,*rdata_len,p2,1);
3258 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3259 pstrcpy(p2,"UserComment");
3260 p2 = skip_string(*rdata,*rdata_len,p2,1);
3265 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3266 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3267 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3268 p2 = skip_string(*rdata,*rdata_len,p2,1);
3275 /* modelled after NTAS 3.51 reply */
3276 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3277 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3278 SIVALS(p,usri11_password_age,-1); /* password age */
3279 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3280 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3281 p2 = skip_string(*rdata,*rdata_len,p2,1);
3285 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3287 p2 = skip_string(*rdata,*rdata_len,p2,1);
3291 SIVAL(p,usri11_last_logon,0); /* last logon */
3292 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3293 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3294 SSVALS(p,usri11_num_logons,-1); /* num logons */
3295 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3296 pstrcpy(p2,"\\\\*");
3297 p2 = skip_string(*rdata,*rdata_len,p2,1);
3301 SSVAL(p,usri11_country_code,0); /* country code */
3303 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3305 p2 = skip_string(*rdata,*rdata_len,p2,1);
3310 SIVALS(p,usri11_max_storage,-1); /* max storage */
3311 SSVAL(p,usri11_units_per_week,168); /* units per week */
3312 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3314 /* a simple way to get logon hours at all times. */
3316 SCVAL(p2,21,0); /* fix zero termination */
3317 p2 = skip_string(*rdata,*rdata_len,p2,1);
3322 SSVAL(p,usri11_code_page,0); /* code page */
3325 if (uLevel == 1 || uLevel == 2) {
3326 memset(p+22,' ',16); /* password */
3327 SIVALS(p,38,-1); /* password age */
3329 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3330 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3331 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3332 p2 = skip_string(*rdata,*rdata_len,p2,1);
3336 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3338 SSVAL(p,52,0); /* flags */
3339 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3340 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3341 p2 = skip_string(*rdata,*rdata_len,p2,1);
3346 SIVAL(p,60,0); /* auth_flags */
3347 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3348 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3349 p2 = skip_string(*rdata,*rdata_len,p2,1);
3353 SIVAL(p,68,0); /* urs_comment */
3354 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3356 p2 = skip_string(*rdata,*rdata_len,p2,1);
3360 SIVAL(p,76,0); /* workstations */
3361 SIVAL(p,80,0); /* last_logon */
3362 SIVAL(p,84,0); /* last_logoff */
3363 SIVALS(p,88,-1); /* acct_expires */
3364 SIVALS(p,92,-1); /* max_storage */
3365 SSVAL(p,96,168); /* units_per_week */
3366 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3369 SSVALS(p,102,-1); /* bad_pw_count */
3370 SSVALS(p,104,-1); /* num_logons */
3371 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3374 pstrcpy(tmp, "\\\\%L");
3375 standard_sub_basic("", "", tmp, sizeof(tmp));
3378 p2 = skip_string(*rdata,*rdata_len,p2,1);
3382 SSVAL(p,110,49); /* country_code */
3383 SSVAL(p,112,860); /* code page */
3387 *rdata_len = PTR_DIFF(p2,*rdata);
3389 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3394 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3395 char *param, int tpscnt,
3396 char *data, int tdscnt,
3397 int mdrcnt,int mprcnt,
3398 char **rdata,char **rparam,
3399 int *rdata_len,int *rparam_len)
3401 char *str1 = get_safe_offset(param,tpscnt,param,2);
3402 char *str2 = skip_string(param,tpscnt,str1,1);
3403 char *p = skip_string(param,tpscnt,str2,1);
3405 struct pack_desc desc;
3407 /* With share level security vuid will always be zero.
3408 Don't depend on vuser being non-null !!. JRA */
3409 user_struct *vuser = get_valid_user_struct(vuid);
3411 if (!str1 || !str2 || !p) {
3416 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3417 vuser->user.unix_name));
3420 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
3421 if (skip_string(param,tpscnt,p+2,1) == NULL) {
3426 memset((char *)&desc,'\0',sizeof(desc));
3428 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3430 /* check it's a supported varient */
3431 if (strcmp(str1,"OOWb54WrLh") != 0) {
3434 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3438 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3445 desc.buflen = mdrcnt;
3446 desc.subformat = NULL;
3449 if (init_package(&desc,1,0)) {
3450 PACKI(&desc,"W",0); /* code */
3451 PACKS(&desc,"B21",name); /* eff. name */
3452 PACKS(&desc,"B",""); /* pad */
3453 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3454 PACKI(&desc,"D",0); /* auth flags XXX */
3455 PACKI(&desc,"W",0); /* num logons */
3456 PACKI(&desc,"W",0); /* bad pw count */
3457 PACKI(&desc,"D",0); /* last logon */
3458 PACKI(&desc,"D",-1); /* last logoff */
3459 PACKI(&desc,"D",-1); /* logoff time */
3460 PACKI(&desc,"D",-1); /* kickoff time */
3461 PACKI(&desc,"D",0); /* password age */
3462 PACKI(&desc,"D",0); /* password can change */
3463 PACKI(&desc,"D",-1); /* password must change */
3467 fstrcpy(mypath,"\\\\");
3468 fstrcat(mypath,get_local_machine_name());
3470 PACKS(&desc,"z",mypath); /* computer */
3473 PACKS(&desc,"z",lp_workgroup());/* domain */
3474 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3475 PACKI(&desc,"D",0x00000000); /* reserved */
3478 *rdata_len = desc.usedlen;
3480 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3484 SSVALS(*rparam,0,desc.errcode);
3486 SSVAL(*rparam,4,desc.neededlen);
3488 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3493 /****************************************************************************
3494 api_WAccessGetUserPerms
3495 ****************************************************************************/
3497 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3498 char *param, int tpscnt,
3499 char *data, int tdscnt,
3500 int mdrcnt,int mprcnt,
3501 char **rdata,char **rparam,
3502 int *rdata_len,int *rparam_len)
3504 char *str1 = get_safe_offset(param,tpscnt,param,2);
3505 char *str2 = skip_string(param,tpscnt,str1,1);
3506 char *user = skip_string(param,tpscnt,str2,1);
3507 char *resource = skip_string(param,tpscnt,user,1);
3509 if (!str1 || !str2 || !user || !resource) {
3513 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3515 /* check it's a supported varient */
3516 if (strcmp(str1,"zzh") != 0) {
3519 if (strcmp(str2,"") != 0) {
3524 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3528 SSVALS(*rparam,0,0); /* errorcode */
3529 SSVAL(*rparam,2,0); /* converter word */
3530 SSVAL(*rparam,4,0x7f); /* permission flags */
3535 /****************************************************************************
3536 api_WPrintJobEnumerate
3537 ****************************************************************************/
3539 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3540 char *param, int tpscnt,
3541 char *data, int tdscnt,
3542 int mdrcnt,int mprcnt,
3543 char **rdata,char **rparam,
3544 int *rdata_len,int *rparam_len)
3546 char *str1 = get_safe_offset(param,tpscnt,param,2);
3547 char *str2 = skip_string(param,tpscnt,str1,1);
3548 char *p = skip_string(param,tpscnt,str2,1);
3555 struct pack_desc desc;
3556 print_queue_struct *queue=NULL;
3557 print_status_struct status;
3560 if (!str1 || !str2 || !p) {
3564 uLevel = get_safe_offset(param,tpscnt,p,4) ? SVAL(p,2) : -1;
3566 memset((char *)&desc,'\0',sizeof(desc));
3567 memset((char *)&status,'\0',sizeof(status));
3569 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3571 /* check it's a supported varient */
3572 if (strcmp(str1,"WWrLh") != 0) {
3575 if (!check_printjob_info(&desc,uLevel,str2)) {
3579 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3583 snum = lp_servicenumber( sharename);
3584 if (snum < 0 || !VALID_SNUM(snum)) {
3588 count = print_queue_status(snum,&queue,&status);
3589 for (i = 0; i < count; i++) {
3590 if (queue[i].job == jobid) {
3596 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3601 desc.buflen = mdrcnt;
3604 * Don't return data but need to get correct length
3605 * init_package will return wrong size if buflen=0
3607 desc.buflen = getlen(desc.format);
3608 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3611 if (init_package(&desc,1,0)) {
3613 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3614 *rdata_len = desc.usedlen;
3616 desc.errcode = NERR_JobNotFound;
3622 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3626 SSVALS(*rparam,0,desc.errcode);
3628 SSVAL(*rparam,4,desc.neededlen);
3633 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3638 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3639 char *param, int tpscnt,
3640 char *data, int tdscnt,
3641 int mdrcnt,int mprcnt,
3642 char **rdata,char **rparam,
3643 int *rdata_len,int *rparam_len)
3645 char *str1 = get_safe_offset(param,tpscnt,param,2);
3646 char *str2 = skip_string(param,tpscnt,str1,1);
3647 char *p = skip_string(param,tpscnt,str2,1);
3653 struct pack_desc desc;
3654 print_queue_struct *queue=NULL;
3655 print_status_struct status;
3657 if (!str1 || !str2 || !p) {
3661 memset((char *)&desc,'\0',sizeof(desc));
3662 memset((char *)&status,'\0',sizeof(status));
3664 p = skip_string(param,tpscnt,p,1);
3668 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
3670 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3672 /* check it's a supported variant */
3673 if (strcmp(str1,"zWrLeh") != 0) {
3678 return False; /* defined only for uLevel 0,1,2 */
3681 if (!check_printjob_info(&desc,uLevel,str2)) {
3685 snum = find_service(name);
3686 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3690 count = print_queue_status(snum,&queue,&status);
3692 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3698 desc.buflen = mdrcnt;
3700 if (init_package(&desc,count,0)) {
3702 for (i = 0; i < count; i++) {
3703 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3704 if (desc.errcode == NERR_Success) {
3710 *rdata_len = desc.usedlen;
3713 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3717 SSVALS(*rparam,0,desc.errcode);
3719 SSVAL(*rparam,4,succnt);
3720 SSVAL(*rparam,6,count);
3724 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3729 static int check_printdest_info(struct pack_desc* desc,
3730 int uLevel, char* id)
3732 desc->subformat = NULL;
3735 desc->format = "B9";
3738 desc->format = "B9B21WWzW";
3744 desc->format = "zzzWWzzzWW";
3749 if (strcmp(desc->format,id) != 0) {
3755 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3756 struct pack_desc* desc)
3760 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3761 buf[sizeof(buf)-1] = 0;
3765 PACKS(desc,"B9",buf); /* szName */
3767 PACKS(desc,"B21",""); /* szUserName */
3768 PACKI(desc,"W",0); /* uJobId */
3769 PACKI(desc,"W",0); /* fsStatus */
3770 PACKS(desc,"z",""); /* pszStatus */
3771 PACKI(desc,"W",0); /* time */
3775 if (uLevel == 2 || uLevel == 3) {
3776 PACKS(desc,"z",buf); /* pszPrinterName */
3778 PACKS(desc,"z",""); /* pszUserName */
3779 PACKS(desc,"z",""); /* pszLogAddr */
3780 PACKI(desc,"W",0); /* uJobId */
3781 PACKI(desc,"W",0); /* fsStatus */
3782 PACKS(desc,"z",""); /* pszStatus */
3783 PACKS(desc,"z",""); /* pszComment */
3784 PACKS(desc,"z","NULL"); /* pszDrivers */
3785 PACKI(desc,"W",0); /* time */
3786 PACKI(desc,"W",0); /* pad1 */
3791 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3792 char *param, int tpscnt,
3793 char *data, int tdscnt,
3794 int mdrcnt,int mprcnt,
3795 char **rdata,char **rparam,
3796 int *rdata_len,int *rparam_len)
3798 char *str1 = get_safe_offset(param,tpscnt,param,2);
3799 char *str2 = skip_string(param,tpscnt,str1,1);
3800 char *p = skip_string(param,tpscnt,str2,1);
3801 char* PrinterName = p;
3803 struct pack_desc desc;
3807 if (!str1 || !str2 || !p) {
3811 memset((char *)&desc,'\0',sizeof(desc));
3813 p = skip_string(param,tpscnt,p,1);
3817 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
3819 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3821 /* check it's a supported varient */
3822 if (strcmp(str1,"zWrLh") != 0) {
3825 if (!check_printdest_info(&desc,uLevel,str2)) {
3829 snum = find_service(PrinterName);
3830 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3832 desc.errcode = NERR_DestNotFound;
3836 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3841 desc.buflen = mdrcnt;
3844 * Don't return data but need to get correct length
3845 * init_package will return wrong size if buflen=0
3847 desc.buflen = getlen(desc.format);
3848 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3850 if (init_package(&desc,1,0)) {
3851 fill_printdest_info(conn,snum,uLevel,&desc);
3853 *rdata_len = desc.usedlen;
3857 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3861 SSVALS(*rparam,0,desc.errcode);
3863 SSVAL(*rparam,4,desc.neededlen);
3865 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3871 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3872 char *param, int tpscnt,
3873 char *data, int tdscnt,
3874 int mdrcnt,int mprcnt,
3875 char **rdata,char **rparam,
3876 int *rdata_len,int *rparam_len)
3878 char *str1 = get_safe_offset(param,tpscnt,param,2);
3879 char *str2 = skip_string(param,tpscnt,str1,1);
3880 char *p = skip_string(param,tpscnt,str2,1);
3884 struct pack_desc desc;
3885 int services = lp_numservices();
3887 if (!str1 || !str2 || !p) {
3891 memset((char *)&desc,'\0',sizeof(desc));
3893 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
3895 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3897 /* check it's a supported varient */
3898 if (strcmp(str1,"WrLeh") != 0) {
3901 if (!check_printdest_info(&desc,uLevel,str2)) {
3906 for (i = 0; i < services; i++) {
3907 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3913 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3920 desc.buflen = mdrcnt;
3921 if (init_package(&desc,queuecnt,0)) {
3924 for (i = 0; i < services; i++) {
3925 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3926 fill_printdest_info(conn,i,uLevel,&desc);
3928 if (desc.errcode == NERR_Success) {
3935 *rdata_len = desc.usedlen;
3938 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3942 SSVALS(*rparam,0,desc.errcode);
3944 SSVAL(*rparam,4,succnt);
3945 SSVAL(*rparam,6,queuecnt);
3947 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3952 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3953 char *param, int tpscnt,
3954 char *data, int tdscnt,
3955 int mdrcnt,int mprcnt,
3956 char **rdata,char **rparam,
3957 int *rdata_len,int *rparam_len)
3959 char *str1 = get_safe_offset(param,tpscnt,param,2);
3960 char *str2 = skip_string(param,tpscnt,str1,1);
3961 char *p = skip_string(param,tpscnt,str2,1);
3964 struct pack_desc desc;
3966 if (!str1 || !str2 || !p) {
3970 memset((char *)&desc,'\0',sizeof(desc));
3972 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : 0;
3974 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3976 /* check it's a supported varient */
3977 if (strcmp(str1,"WrLeh") != 0) {
3980 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
3985 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3991 desc.buflen = mdrcnt;
3992 if (init_package(&desc,1,0)) {
3993 PACKS(&desc,"B41","NULL");
3996 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3998 *rdata_len = desc.usedlen;
4001 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4005 SSVALS(*rparam,0,desc.errcode);
4007 SSVAL(*rparam,4,succnt);
4010 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4015 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4016 char *param, int tpscnt,
4017 char *data, int tdscnt,
4018 int mdrcnt,int mprcnt,
4019 char **rdata,char **rparam,
4020 int *rdata_len,int *rparam_len)
4022 char *str1 = get_safe_offset(param,tpscnt,param,2);
4023 char *str2 = skip_string(param,tpscnt,str1,1);
4024 char *p = skip_string(param,tpscnt,str2,1);
4027 struct pack_desc desc;
4029 if (!str1 || !str2 || !p) {
4032 memset((char *)&desc,'\0',sizeof(desc));
4034 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
4036 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4038 /* check it's a supported varient */
4039 if (strcmp(str1,"WrLeh") != 0) {
4042 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4047 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4053 desc.buflen = mdrcnt;
4055 if (init_package(&desc,1,0)) {
4056 PACKS(&desc,"B13","lpd");
4059 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4061 *rdata_len = desc.usedlen;
4064 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4068 SSVALS(*rparam,0,desc.errcode);
4070 SSVAL(*rparam,4,succnt);
4073 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4078 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4079 char *param, int tpscnt,
4080 char *data, int tdscnt,
4081 int mdrcnt,int mprcnt,
4082 char **rdata,char **rparam,
4083 int *rdata_len,int *rparam_len)
4085 char *str1 = get_safe_offset(param,tpscnt,param,2);
4086 char *str2 = skip_string(param,tpscnt,str1,1);
4087 char *p = skip_string(param,tpscnt,str2,1);
4090 struct pack_desc desc;
4092 if (!str1 || !str2 || !p) {
4096 memset((char *)&desc,'\0',sizeof(desc));
4098 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
4100 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4102 /* check it's a supported varient */
4103 if (strcmp(str1,"WrLeh") != 0) {
4106 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4111 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4116 memset((char *)&desc,'\0',sizeof(desc));
4118 desc.buflen = mdrcnt;
4120 if (init_package(&desc,1,0)) {
4121 PACKS(&desc,"B13","lp0");
4124 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4126 *rdata_len = desc.usedlen;
4129 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4133 SSVALS(*rparam,0,desc.errcode);
4135 SSVAL(*rparam,4,succnt);
4138 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4143 /****************************************************************************
4145 ****************************************************************************/
4147 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4148 char *param, int tpscnt,
4149 char *data, int tdscnt,
4150 int mdrcnt,int mprcnt,
4151 char **rdata,char **rparam,
4152 int *rdata_len,int *rparam_len)
4155 char *str1 = get_safe_offset(param,tpscnt,param,2);
4156 char *str2 = skip_string(param,tpscnt,str1,1);
4157 char *p = skip_string(param,tpscnt,str2,1);
4159 struct pack_desc desc;
4160 struct sessionid *session_list;
4161 int i, num_sessions;
4163 if (!str1 || !str2 || !p) {
4167 memset((char *)&desc,'\0',sizeof(desc));
4169 uLevel = get_safe_offset(param,tpscnt,p,2) ? SVAL(p,0) : -1;
4171 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4172 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4173 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4175 /* check it's a supported varient */
4176 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4179 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4183 num_sessions = list_sessions(&session_list);
4186 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4191 memset((char *)&desc,'\0',sizeof(desc));
4193 desc.buflen = mdrcnt;
4195 if (!init_package(&desc,num_sessions,0)) {
4199 for(i=0; i<num_sessions; i++) {
4200 PACKS(&desc, "z", session_list[i].remote_machine);
4201 PACKS(&desc, "z", session_list[i].username);
4202 PACKI(&desc, "W", 1); /* num conns */
4203 PACKI(&desc, "W", 0); /* num opens */
4204 PACKI(&desc, "W", 1); /* num users */
4205 PACKI(&desc, "D", 0); /* session time */
4206 PACKI(&desc, "D", 0); /* idle time */
4207 PACKI(&desc, "D", 0); /* flags */
4208 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4211 *rdata_len = desc.usedlen;
4214 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4218 SSVALS(*rparam,0,desc.errcode);
4219 SSVAL(*rparam,2,0); /* converter */
4220 SSVAL(*rparam,4,num_sessions); /* count */
4222 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4228 /****************************************************************************
4229 The buffer was too small.
4230 ****************************************************************************/
4232 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4233 int mdrcnt, int mprcnt,
4234 char **rdata, char **rparam,
4235 int *rdata_len, int *rparam_len)
4237 *rparam_len = MIN(*rparam_len,mprcnt);
4238 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4245 SSVAL(*rparam,0,NERR_BufTooSmall);
4247 DEBUG(3,("Supplied buffer too small in API command\n"));
4252 /****************************************************************************
4253 The request is not supported.
4254 ****************************************************************************/
4256 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4257 char *param, int tpscnt,
4258 char *data, int tdscnt,
4259 int mdrcnt, int mprcnt,
4260 char **rdata, char **rparam,
4261 int *rdata_len, int *rparam_len)
4264 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4271 SSVAL(*rparam,0,NERR_notsupported);
4272 SSVAL(*rparam,2,0); /* converter word */
4274 DEBUG(3,("Unsupported API command\n"));
4279 static const struct {
4282 BOOL (*fn)(connection_struct *, uint16,
4285 int,int,char **,char **,int *,int *);
4286 BOOL auth_user; /* Deny anonymous access? */
4287 } api_commands[] = {
4288 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4289 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4290 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4291 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4292 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4293 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4294 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4295 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4296 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4297 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4298 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4299 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4300 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4301 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4302 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4303 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4304 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4305 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4306 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4307 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4308 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4309 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4310 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4311 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4312 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4313 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4314 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4315 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4316 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4317 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4318 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4319 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4320 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4321 {NULL, -1, api_Unsupported}
4322 /* The following RAP calls are not implemented by Samba:
4324 RAP_WFileEnum2 - anon not OK
4329 /****************************************************************************
4330 Handle remote api calls
4331 ****************************************************************************/
4333 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4334 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
4338 char *rparam = NULL;
4339 const char *name1 = NULL;
4340 const char *name2 = NULL;
4347 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4354 api_command = SVAL(params,0);
4355 /* Is there a string at position params+2 ? */
4356 if (skip_string(params,tpscnt,params+2,1)) {
4361 name2 = skip_string(params,tpscnt,params+2,1);
4366 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4370 tdscnt,tpscnt,mdrcnt,mprcnt));
4372 for (i=0;api_commands[i].name;i++) {
4373 if (api_commands[i].id == api_command && api_commands[i].fn) {
4374 DEBUG(3,("Doing %s\n",api_commands[i].name));
4379 /* Check whether this api call can be done anonymously */
4381 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4382 user_struct *user = get_valid_user_struct(vuid);
4384 if (!user || user->guest) {
4385 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4389 rdata = (char *)SMB_MALLOC(1024);
4391 memset(rdata,'\0',1024);
4394 rparam = (char *)SMB_MALLOC(1024);
4396 memset(rparam,'\0',1024);
4399 if(!rdata || !rparam) {
4400 DEBUG(0,("api_reply: malloc fail !\n"));
4406 reply = api_commands[i].fn(conn,
4408 params,tpscnt, /* params + length */
4409 data,tdscnt, /* data + length */
4411 &rdata,&rparam,&rdata_len,&rparam_len);
4414 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4415 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4416 &rdata,&rparam,&rdata_len,&rparam_len);
4419 /* if we get False back then it's actually unsupported */
4421 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4422 &rdata,&rparam,&rdata_len,&rparam_len);
4425 /* If api_Unsupported returns false we can't return anything. */
4427 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);