2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
30 extern struct current_user current_user;
31 extern userdom_struct current_user_info;
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
51 #define SHPWLEN 8 /* share password length */
53 /* Limit size of ipc replies */
55 static char *smb_realloc_limit(void *ptr, size_t size)
59 size = MAX((size),4*1024);
60 val = (char *)SMB_REALLOC(ptr,size);
62 memset(val,'\0',size);
67 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
68 char *param, int tpscnt,
69 char *data, int tdscnt,
70 int mdrcnt, int mprcnt,
71 char **rdata, char **rparam,
72 int *rdata_len, int *rparam_len);
74 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
75 int mdrcnt, int mprcnt,
76 char **rdata, char **rparam,
77 int *rdata_len, int *rparam_len);
80 static int CopyExpanded(connection_struct *conn,
81 int snum, char **dst, char *src, int *p_space_remaining)
83 TALLOC_CTX *ctx = talloc_tos();
87 if (!src || !dst || !p_space_remaining || !(*dst) ||
88 *p_space_remaining <= 0) {
92 buf = talloc_strdup(ctx, src);
94 *p_space_remaining = 0;
97 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
99 *p_space_remaining = 0;
102 buf = talloc_sub_advanced(ctx,
103 lp_servicename(SNUM(conn)),
107 get_current_username(),
108 current_user_info.domain,
111 *p_space_remaining = 0;
114 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
116 (*p_space_remaining) -= l;
120 static int CopyAndAdvance(char **dst, char *src, int *n)
123 if (!src || !dst || !n || !(*dst)) {
126 l = push_ascii(*dst,src,*n, STR_TERMINATE);
132 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
134 TALLOC_CTX *ctx = talloc_tos();
139 buf = talloc_strdup(ctx,s);
143 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
147 buf = talloc_sub_advanced(ctx,
148 lp_servicename(SNUM(conn)),
152 get_current_username(),
153 current_user_info.domain,
158 return strlen(buf) + 1;
161 static char *Expand(connection_struct *conn, int snum, char *s)
163 TALLOC_CTX *ctx = talloc_tos();
169 buf = talloc_strdup(ctx,s);
173 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
177 return talloc_sub_advanced(ctx,
178 lp_servicename(SNUM(conn)),
182 get_current_username(),
183 current_user_info.domain,
187 /*******************************************************************
188 Check a API string for validity when we only need to check the prefix.
189 ******************************************************************/
191 static bool prefix_ok(const char *str, const char *prefix)
193 return(strncmp(str,prefix,strlen(prefix)) == 0);
197 const char *format; /* formatstring for structure */
198 const char *subformat; /* subformat for structure */
199 char *base; /* baseaddress of buffer */
200 int buflen; /* remaining size for fixed part; on init: length of base */
201 int subcount; /* count of substructures */
202 char *structbuf; /* pointer into buffer for remaining fixed part */
203 int stringlen; /* remaining size for variable part */
204 char *stringbuf; /* pointer into buffer for remaining variable part */
205 int neededlen; /* total needed size */
206 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
207 const char *curpos; /* current position; pointer into format or subformat */
211 static int get_counter(const char **p)
217 if (!isdigit((int)**p)) {
223 n = 10 * n + (i - '0');
231 static int getlen(const char *p)
240 case 'W': /* word (2 byte) */
243 case 'K': /* status word? (2 byte) */
246 case 'N': /* count of substructures (word) at end */
249 case 'D': /* double word (4 byte) */
250 case 'z': /* offset to zero terminated string (4 byte) */
251 case 'l': /* offset to user data (4 byte) */
254 case 'b': /* offset to data (with counter) (4 byte) */
258 case 'B': /* byte (with optional counter) */
259 n += get_counter(&p);
266 static bool init_package(struct pack_desc *p, int count, int subcount)
271 if (!p->format || !p->base) {
275 i = count * getlen(p->format);
277 i += subcount * getlen(p->subformat);
279 p->structbuf = p->base;
283 p->curpos = p->format;
289 * This is the old error code we used. Aparently
290 * WinNT/2k systems return ERRbuftoosmall (2123) and
291 * OS/2 needs this. I'm leaving this here so we can revert
294 p->errcode = ERRmoredata;
296 p->errcode = ERRbuftoosmall;
299 p->errcode = NERR_Success;
303 p->stringbuf = p->base + i;
305 return (p->errcode == NERR_Success);
308 static int package(struct pack_desc *p, ...)
311 int needed=0, stringneeded;
312 const char *str=NULL;
313 int is_string=0, stringused;
320 p->curpos = p->format;
322 p->curpos = p->subformat;
327 str = va_arg(args,char*);
328 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
337 switch( *p->curpos++ ) {
338 case 'W': /* word (2 byte) */
340 temp = va_arg(args,int);
341 if (p->buflen >= needed) {
342 SSVAL(p->structbuf,0,temp);
345 case 'K': /* status word? (2 byte) */
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SSVAL(p->structbuf,0,temp);
352 case 'N': /* count of substructures (word) at end */
354 p->subcount = va_arg(args,int);
355 if (p->buflen >= needed) {
356 SSVAL(p->structbuf,0,p->subcount);
359 case 'D': /* double word (4 byte) */
361 temp = va_arg(args,int);
362 if (p->buflen >= needed) {
363 SIVAL(p->structbuf,0,temp);
366 case 'B': /* byte (with optional counter) */
367 needed = get_counter(&p->curpos);
369 char *s = va_arg(args,char*);
370 if (p->buflen >= needed) {
371 StrnCpy(p->structbuf,s?s:"",needed-1);
375 case 'z': /* offset to zero terminated string (4 byte) */
376 str = va_arg(args,char*);
377 stringneeded = (str ? strlen(str)+1 : 0);
380 case 'l': /* offset to user data (4 byte) */
381 str = va_arg(args,char*);
382 stringneeded = va_arg(args,int);
385 case 'b': /* offset to data (with counter) (4 byte) */
386 str = va_arg(args,char*);
387 stringneeded = get_counter(&p->curpos);
393 if (stringneeded >= 0) {
395 if (p->buflen >= needed) {
396 stringused = stringneeded;
397 if (stringused > p->stringlen) {
398 stringused = (is_string ? p->stringlen : 0);
399 if (p->errcode == NERR_Success) {
400 p->errcode = ERRmoredata;
404 SIVAL(p->structbuf,0,0);
406 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
407 memcpy(p->stringbuf,str?str:"",stringused);
409 p->stringbuf[stringused-1] = '\0';
411 p->stringbuf += stringused;
412 p->stringlen -= stringused;
413 p->usedlen += stringused;
416 p->neededlen += stringneeded;
419 p->neededlen += needed;
420 if (p->buflen >= needed) {
421 p->structbuf += needed;
423 p->usedlen += needed;
425 if (p->errcode == NERR_Success) {
426 p->errcode = ERRmoredata;
433 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
434 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
436 #define PACK(desc,t,v) package(desc,v)
437 #define PACKl(desc,t,v,l) package(desc,v,l)
440 static void PACKI(struct pack_desc* desc, const char *t,int v)
445 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
450 /****************************************************************************
452 ****************************************************************************/
454 static void PackDriverData(struct pack_desc* desc)
456 char drivdata[4+4+32];
457 SIVAL(drivdata,0,sizeof drivdata); /* cb */
458 SIVAL(drivdata,4,1000); /* lVersion */
459 memset(drivdata+8,0,32); /* szDeviceName */
460 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
461 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
464 static int check_printq_info(struct pack_desc* desc,
465 unsigned int uLevel, char *id1, char *id2)
467 desc->subformat = NULL;
470 desc->format = "B13";
473 desc->format = "B13BWWWzzzzzWW";
476 desc->format = "B13BWWWzzzzzWN";
477 desc->subformat = "WB21BB16B10zWWzDDz";
480 desc->format = "zWWWWzzzzWWzzl";
483 desc->format = "zWWWWzzzzWNzzl";
484 desc->subformat = "WWzWWDDzz";
493 desc->format = "WzzzzzzzzN";
494 desc->subformat = "z";
497 DEBUG(0,("check_printq_info: invalid level %d\n",
501 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
502 DEBUG(0,("check_printq_info: invalid format %s\n",
503 id1 ? id1 : "<NULL>" ));
506 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
507 DEBUG(0,("check_printq_info: invalid subformat %s\n",
508 id2 ? id2 : "<NULL>" ));
515 #define RAP_JOB_STATUS_QUEUED 0
516 #define RAP_JOB_STATUS_PAUSED 1
517 #define RAP_JOB_STATUS_SPOOLING 2
518 #define RAP_JOB_STATUS_PRINTING 3
519 #define RAP_JOB_STATUS_PRINTED 4
521 #define RAP_QUEUE_STATUS_PAUSED 1
522 #define RAP_QUEUE_STATUS_ERROR 2
524 /* turn a print job status into a on the wire status
526 static int printj_status(int v)
530 return RAP_JOB_STATUS_QUEUED;
532 return RAP_JOB_STATUS_PAUSED;
534 return RAP_JOB_STATUS_SPOOLING;
536 return RAP_JOB_STATUS_PRINTING;
541 /* turn a print queue status into a on the wire status
543 static int printq_status(int v)
549 return RAP_QUEUE_STATUS_PAUSED;
551 return RAP_QUEUE_STATUS_ERROR;
554 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
555 struct pack_desc *desc,
556 print_queue_struct *queue, int n)
558 time_t t = queue->time;
560 /* the client expects localtime */
561 t -= get_time_zone(t);
563 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
565 PACKS(desc,"B21",queue->fs_user); /* szUserName */
566 PACKS(desc,"B",""); /* pad */
567 PACKS(desc,"B16",""); /* szNotifyName */
568 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
569 PACKS(desc,"z",""); /* pszParms */
570 PACKI(desc,"W",n+1); /* uPosition */
571 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
572 PACKS(desc,"z",""); /* pszStatus */
573 PACKI(desc,"D",t); /* ulSubmitted */
574 PACKI(desc,"D",queue->size); /* ulSize */
575 PACKS(desc,"z",queue->fs_file); /* pszComment */
577 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
578 PACKI(desc,"W",queue->priority); /* uPriority */
579 PACKS(desc,"z",queue->fs_user); /* pszUserName */
580 PACKI(desc,"W",n+1); /* uPosition */
581 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
582 PACKI(desc,"D",t); /* ulSubmitted */
583 PACKI(desc,"D",queue->size); /* ulSize */
584 PACKS(desc,"z","Samba"); /* pszComment */
585 PACKS(desc,"z",queue->fs_file); /* pszDocument */
587 PACKS(desc,"z",""); /* pszNotifyName */
588 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
589 PACKS(desc,"z",""); /* pszParms */
590 PACKS(desc,"z",""); /* pszStatus */
591 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
592 PACKS(desc,"z","lpd"); /* pszQProcName */
593 PACKS(desc,"z",""); /* pszQProcParms */
594 PACKS(desc,"z","NULL"); /* pszDriverName */
595 PackDriverData(desc); /* pDriverData */
596 PACKS(desc,"z",""); /* pszPrinterName */
597 } else if (uLevel == 4) { /* OS2 */
598 PACKS(desc,"z",""); /* pszSpoolFileName */
599 PACKS(desc,"z",""); /* pszPortName */
600 PACKS(desc,"z",""); /* pszStatus */
601 PACKI(desc,"D",0); /* ulPagesSpooled */
602 PACKI(desc,"D",0); /* ulPagesSent */
603 PACKI(desc,"D",0); /* ulPagesPrinted */
604 PACKI(desc,"D",0); /* ulTimePrinted */
605 PACKI(desc,"D",0); /* ulExtendJobStatus */
606 PACKI(desc,"D",0); /* ulStartPage */
607 PACKI(desc,"D",0); /* ulEndPage */
612 /********************************************************************
613 Return a driver name given an snum.
614 Returns True if from tdb, False otherwise.
615 ********************************************************************/
617 static bool get_driver_name(int snum, char **pp_drivername)
619 NT_PRINTER_INFO_LEVEL *info = NULL;
622 get_a_printer (NULL, &info, 2, lp_servicename(snum));
624 *pp_drivername = talloc_strdup(talloc_tos(),
625 info->info_2->drivername);
627 free_a_printer(&info, 2);
628 if (!*pp_drivername) {
636 /********************************************************************
637 Respond to the DosPrintQInfo command with a level of 52
638 This is used to get printer driver information for Win9x clients
639 ********************************************************************/
640 static void fill_printq_info_52(connection_struct *conn, int snum,
641 struct pack_desc* desc, int count )
645 NT_PRINTER_DRIVER_INFO_LEVEL driver;
646 NT_PRINTER_INFO_LEVEL *printer = NULL;
650 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
651 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
652 lp_servicename(snum)));
656 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
659 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
660 printer->info_2->drivername));
664 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
665 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
666 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
668 PACKI(desc, "W", 0x0400); /* don't know */
669 PACKS(desc, "z", driver.info_3->name); /* long printer name */
670 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
671 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
672 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
674 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
675 standard_sub_basic( "", "", location, sizeof(location)-1 );
676 PACKS(desc,"z", location); /* share to retrieve files */
678 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
679 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
680 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
682 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
683 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
684 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
685 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
686 DEBUG(3,("Driver Location: %s:\n",location));
687 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
688 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
689 PACKI(desc,"N",count); /* number of files to copy */
691 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
693 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
694 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
695 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
700 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
703 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
705 desc->errcode=NERR_Success;
709 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
710 desc->errcode=NERR_notsupported;
714 free_a_printer( &printer, 2 );
717 free_a_printer_driver( driver, 3 );
721 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
722 struct pack_desc* desc,
723 int count, print_queue_struct* queue,
724 print_status_struct* status)
729 PACKS(desc,"B13",SERVICE(snum));
734 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
737 PACKI(desc,"K",printq_status(status->status));
741 if (uLevel == 1 || uLevel == 2) {
742 PACKS(desc,"B",""); /* alignment */
743 PACKI(desc,"W",5); /* priority */
744 PACKI(desc,"W",0); /* start time */
745 PACKI(desc,"W",0); /* until time */
746 PACKS(desc,"z",""); /* pSepFile */
747 PACKS(desc,"z","lpd"); /* pPrProc */
748 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
749 PACKS(desc,"z",""); /* pParms */
751 PACKS(desc,"z","UNKNOWN PRINTER");
752 PACKI(desc,"W",LPSTAT_ERROR);
754 else if (!status || !status->message[0]) {
755 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
756 PACKI(desc,"W",LPSTAT_OK); /* status */
758 PACKS(desc,"z",status->message);
759 PACKI(desc,"W",printq_status(status->status)); /* status */
761 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
764 if (uLevel == 3 || uLevel == 4) {
765 char *drivername = NULL;
767 PACKI(desc,"W",5); /* uPriority */
768 PACKI(desc,"W",0); /* uStarttime */
769 PACKI(desc,"W",0); /* uUntiltime */
770 PACKI(desc,"W",5); /* pad1 */
771 PACKS(desc,"z",""); /* pszSepFile */
772 PACKS(desc,"z","WinPrint"); /* pszPrProc */
773 PACKS(desc,"z",NULL); /* pszParms */
774 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
775 /* "don't ask" that it's done this way to fix corrupted
776 Win9X/ME printer comments. */
778 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
780 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
782 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
783 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
784 get_driver_name(snum,&drivername);
788 PACKS(desc,"z",drivername); /* pszDriverName */
789 PackDriverData(desc); /* pDriverData */
792 if (uLevel == 2 || uLevel == 4) {
794 for (i=0;i<count;i++)
795 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
799 fill_printq_info_52( conn, snum, desc, count );
802 /* This function returns the number of files for a given driver */
803 static int get_printerdrivernumber(int snum)
806 NT_PRINTER_DRIVER_INFO_LEVEL driver;
807 NT_PRINTER_INFO_LEVEL *printer = NULL;
811 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
812 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
813 lp_servicename(snum)));
817 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
820 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
821 printer->info_2->drivername));
825 /* count the number of files */
826 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
831 free_a_printer( &printer, 2 );
834 free_a_printer_driver( driver, 3 );
839 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
840 char *param, int tpscnt,
841 char *data, int tdscnt,
842 int mdrcnt,int mprcnt,
843 char **rdata,char **rparam,
844 int *rdata_len,int *rparam_len)
846 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
847 char *str2 = skip_string(param,tpscnt,str1);
848 char *p = skip_string(param,tpscnt,str2);
854 struct pack_desc desc;
855 print_queue_struct *queue=NULL;
856 print_status_struct status;
859 if (!str1 || !str2 || !p) {
862 memset((char *)&status,'\0',sizeof(status));
863 memset((char *)&desc,'\0',sizeof(desc));
865 p = skip_string(param,tpscnt,p);
869 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
870 str3 = get_safe_str_ptr(param,tpscnt,p,4);
871 /* str3 may be null here and is checked in check_printq_info(). */
873 /* remove any trailing username */
874 if ((p = strchr_m(QueueName,'%')))
877 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
879 /* check it's a supported varient */
880 if (!prefix_ok(str1,"zWrLh"))
882 if (!check_printq_info(&desc,uLevel,str2,str3)) {
884 * Patch from Scott Moomaw <scott@bridgewater.edu>
885 * to return the 'invalid info level' error if an
886 * unknown level was requested.
890 *rparam = smb_realloc_limit(*rparam,*rparam_len);
894 SSVALS(*rparam,0,ERRunknownlevel);
900 snum = find_service(QueueName);
901 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
905 count = get_printerdrivernumber(snum);
906 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
908 count = print_queue_status(snum, &queue,&status);
912 *rdata = smb_realloc_limit(*rdata,mdrcnt);
918 desc.buflen = mdrcnt;
921 * Don't return data but need to get correct length
922 * init_package will return wrong size if buflen=0
924 desc.buflen = getlen(desc.format);
925 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
928 if (init_package(&desc,1,count)) {
929 desc.subcount = count;
930 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
933 *rdata_len = desc.usedlen;
936 * We must set the return code to ERRbuftoosmall
937 * in order to support lanman style printing with Win NT/2k
940 if (!mdrcnt && lp_disable_spoolss())
941 desc.errcode = ERRbuftoosmall;
943 *rdata_len = desc.usedlen;
945 *rparam = smb_realloc_limit(*rparam,*rparam_len);
951 SSVALS(*rparam,0,desc.errcode);
953 SSVAL(*rparam,4,desc.neededlen);
955 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
963 /****************************************************************************
964 View list of all print jobs on all queues.
965 ****************************************************************************/
967 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
968 char *param, int tpscnt,
969 char *data, int tdscnt,
970 int mdrcnt, int mprcnt,
971 char **rdata, char** rparam,
972 int *rdata_len, int *rparam_len)
974 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
975 char *output_format1 = skip_string(param,tpscnt,param_format);
976 char *p = skip_string(param,tpscnt,output_format1);
977 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
978 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
979 int services = lp_numservices();
981 struct pack_desc desc;
982 print_queue_struct **queue = NULL;
983 print_status_struct *status = NULL;
984 int *subcntarr = NULL;
985 int queuecnt = 0, subcnt = 0, succnt = 0;
987 if (!param_format || !output_format1 || !p) {
991 memset((char *)&desc,'\0',sizeof(desc));
993 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
995 if (!prefix_ok(param_format,"WrLeh")) {
998 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1000 * Patch from Scott Moomaw <scott@bridgewater.edu>
1001 * to return the 'invalid info level' error if an
1002 * unknown level was requested.
1006 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1010 SSVALS(*rparam,0,ERRunknownlevel);
1016 for (i = 0; i < services; i++) {
1017 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1022 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1023 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1026 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1027 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1028 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1031 memset(status,0,queuecnt*sizeof(print_status_struct));
1032 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1033 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1039 for (i = 0; i < services; i++) {
1040 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1041 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1042 subcnt += subcntarr[n];
1048 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1054 desc.buflen = mdrcnt;
1056 if (init_package(&desc,queuecnt,subcnt)) {
1059 for (i = 0; i < services; i++) {
1060 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1061 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1063 if (desc.errcode == NERR_Success) {
1070 SAFE_FREE(subcntarr);
1072 *rdata_len = desc.usedlen;
1074 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1078 SSVALS(*rparam,0,desc.errcode);
1080 SSVAL(*rparam,4,succnt);
1081 SSVAL(*rparam,6,queuecnt);
1083 for (i = 0; i < queuecnt; i++) {
1085 SAFE_FREE(queue[i]);
1096 SAFE_FREE(subcntarr);
1097 for (i = 0; i < queuecnt; i++) {
1099 SAFE_FREE(queue[i]);
1108 /****************************************************************************
1109 Get info level for a server list query.
1110 ****************************************************************************/
1112 static bool check_server_info(int uLevel, char* id)
1116 if (strcmp(id,"B16") != 0) {
1121 if (strcmp(id,"B16BBDz") != 0) {
1131 struct srv_info_struct {
1139 /*******************************************************************
1140 Get server info lists from the files saved by nmbd. Return the
1142 ******************************************************************/
1144 static int get_server_info(uint32 servertype,
1145 struct srv_info_struct **servers,
1151 bool local_list_only;
1154 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1156 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1160 /* request for everything is code for request all servers */
1161 if (servertype == SV_TYPE_ALL) {
1162 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1165 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1167 DEBUG(4,("Servertype search: %8x\n",servertype));
1169 for (i=0;lines[i];i++) {
1171 struct srv_info_struct *s;
1172 const char *ptr = lines[i];
1179 if (count == alloced) {
1181 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1183 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1184 file_lines_free(lines);
1187 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1189 s = &(*servers)[count];
1191 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1194 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1197 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1200 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1201 /* this allows us to cope with an old nmbd */
1202 fstrcpy(s->domain,lp_workgroup());
1205 if (sscanf(stype,"%X",&s->type) != 1) {
1206 DEBUG(4,("r:host file "));
1210 /* Filter the servers/domains we return based on what was asked for. */
1212 /* Check to see if we are being asked for a local list only. */
1213 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1214 DEBUG(4,("r: local list only"));
1218 /* doesn't match up: don't want it */
1219 if (!(servertype & s->type)) {
1220 DEBUG(4,("r:serv type "));
1224 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1225 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1226 DEBUG(4,("s: dom mismatch "));
1230 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1234 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1235 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1238 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1239 s->name, s->type, s->comment, s->domain));
1240 s->server_added = True;
1243 DEBUG(4,("%20s %8x %25s %15s\n",
1244 s->name, s->type, s->comment, s->domain));
1248 file_lines_free(lines);
1252 /*******************************************************************
1253 Fill in a server info structure.
1254 ******************************************************************/
1256 static int fill_srv_info(struct srv_info_struct *service,
1257 int uLevel, char **buf, int *buflen,
1258 char **stringbuf, int *stringspace, char *baseaddr)
1281 len = strlen(service->comment)+1;
1285 *buflen = struct_len;
1287 return struct_len + len;
1292 if (*buflen < struct_len) {
1299 p2 = p + struct_len;
1300 l2 = *buflen - struct_len;
1308 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1312 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1313 SIVAL(p,18,service->type);
1314 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1315 len += CopyAndAdvance(&p2,service->comment,&l2);
1320 *buf = p + struct_len;
1321 *buflen -= struct_len;
1332 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1334 return(strcmp(s1->name,s2->name));
1337 /****************************************************************************
1338 View list of servers available (or possibly domains). The info is
1339 extracted from lists saved by nmbd on the local host.
1340 ****************************************************************************/
1342 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1343 char *param, int tpscnt,
1344 char *data, int tdscnt,
1345 int mdrcnt, int mprcnt, char **rdata,
1346 char **rparam, int *rdata_len, int *rparam_len)
1348 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1349 char *str2 = skip_string(param,tpscnt,str1);
1350 char *p = skip_string(param,tpscnt,str2);
1351 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1352 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1353 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1355 int data_len, fixed_len, string_len;
1356 int f_len = 0, s_len = 0;
1357 struct srv_info_struct *servers=NULL;
1358 int counted=0,total=0;
1361 bool domain_request;
1364 if (!str1 || !str2 || !p) {
1368 /* If someone sets all the bits they don't really mean to set
1369 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1372 if (servertype == SV_TYPE_ALL) {
1373 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1376 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1377 any other bit (they may just set this bit on it's own) they
1378 want all the locally seen servers. However this bit can be
1379 set on its own so set the requested servers to be
1380 ALL - DOMAIN_ENUM. */
1382 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1383 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1386 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1387 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1391 if (!prefix_ok(str1,"WrLehD")) {
1394 if (!check_server_info(uLevel,str2)) {
1398 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1399 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1400 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1402 if (strcmp(str1, "WrLehDz") == 0) {
1403 if (skip_string(param,tpscnt,p) == NULL) {
1406 pull_ascii_fstring(domain, p);
1408 fstrcpy(domain, lp_workgroup());
1411 if (lp_browse_list()) {
1412 total = get_server_info(servertype,&servers,domain);
1415 data_len = fixed_len = string_len = 0;
1419 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1423 char *lastname=NULL;
1425 for (i=0;i<total;i++) {
1426 struct srv_info_struct *s = &servers[i];
1428 if (lastname && strequal(lastname,s->name)) {
1432 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1433 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1434 s->name, s->type, s->comment, s->domain));
1436 if (data_len <= buf_len) {
1439 string_len += s_len;
1446 *rdata_len = fixed_len + string_len;
1447 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1452 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1458 char *lastname=NULL;
1459 int count2 = counted;
1461 for (i = 0; i < total && count2;i++) {
1462 struct srv_info_struct *s = &servers[i];
1464 if (lastname && strequal(lastname,s->name)) {
1468 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1469 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1470 s->name, s->type, s->comment, s->domain));
1476 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1480 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1482 SSVAL(*rparam,4,counted);
1483 SSVAL(*rparam,6,counted+missed);
1487 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1488 domain,uLevel,counted,counted+missed));
1493 /****************************************************************************
1494 command 0x34 - suspected of being a "Lookup Names" stub api
1495 ****************************************************************************/
1497 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1498 char *param, int tpscnt,
1499 char *data, int tdscnt,
1500 int mdrcnt, int mprcnt, char **rdata,
1501 char **rparam, int *rdata_len, int *rparam_len)
1503 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1504 char *str2 = skip_string(param,tpscnt,str1);
1505 char *p = skip_string(param,tpscnt,str2);
1506 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1507 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1511 if (!str1 || !str2 || !p) {
1515 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1516 str1, str2, p, uLevel, buf_len));
1518 if (!prefix_ok(str1,"zWrLeh")) {
1525 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1530 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1532 SSVAL(*rparam,4,counted);
1533 SSVAL(*rparam,6,counted+missed);
1538 /****************************************************************************
1539 get info about a share
1540 ****************************************************************************/
1542 static bool check_share_info(int uLevel, char* id)
1546 if (strcmp(id,"B13") != 0) {
1551 if (strcmp(id,"B13BWz") != 0) {
1556 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1561 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1571 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1572 char** buf, int* buflen,
1573 char** stringbuf, int* stringspace, char* baseaddr)
1603 len += StrlenExpanded(conn,snum,lp_comment(snum));
1606 len += strlen(lp_pathname(snum)) + 1;
1609 *buflen = struct_len;
1614 return struct_len + len;
1619 if ((*buflen) < struct_len) {
1627 p2 = p + struct_len;
1628 l2 = (*buflen) - struct_len;
1635 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1641 type = STYPE_DISKTREE;
1642 if (lp_print_ok(snum)) {
1643 type = STYPE_PRINTQ;
1645 if (strequal("IPC",lp_fstype(snum))) {
1648 SSVAL(p,14,type); /* device type */
1649 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1650 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1654 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1655 SSVALS(p,22,-1); /* max uses */
1656 SSVAL(p,24,1); /* current uses */
1657 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1658 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1659 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1663 memset(p+40,0,SHPWLEN+2);
1674 (*buf) = p + struct_len;
1675 (*buflen) -= struct_len;
1677 (*stringspace) = l2;
1686 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1687 char *param, int tpscnt,
1688 char *data, int tdscnt,
1689 int mdrcnt,int mprcnt,
1690 char **rdata,char **rparam,
1691 int *rdata_len,int *rparam_len)
1693 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1694 char *str2 = skip_string(param,tpscnt,str1);
1695 char *netname = skip_string(param,tpscnt,str2);
1696 char *p = skip_string(param,tpscnt,netname);
1697 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1700 if (!str1 || !str2 || !netname || !p) {
1704 snum = find_service(netname);
1709 /* check it's a supported varient */
1710 if (!prefix_ok(str1,"zWrLh")) {
1713 if (!check_share_info(uLevel,str2)) {
1717 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1722 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1723 if (*rdata_len < 0) {
1728 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1732 SSVAL(*rparam,0,NERR_Success);
1733 SSVAL(*rparam,2,0); /* converter word */
1734 SSVAL(*rparam,4,*rdata_len);
1739 /****************************************************************************
1740 View the list of available shares.
1742 This function is the server side of the NetShareEnum() RAP call.
1743 It fills the return buffer with share names and share comments.
1744 Note that the return buffer normally (in all known cases) allows only
1745 twelve byte strings for share names (plus one for a nul terminator).
1746 Share names longer than 12 bytes must be skipped.
1747 ****************************************************************************/
1749 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1750 char *param, int tpscnt,
1751 char *data, int tdscnt,
1759 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1760 char *str2 = skip_string(param,tpscnt,str1);
1761 char *p = skip_string(param,tpscnt,str2);
1762 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1763 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1766 int total=0,counted=0;
1767 bool missed = False;
1769 int data_len, fixed_len, string_len;
1770 int f_len = 0, s_len = 0;
1772 if (!str1 || !str2 || !p) {
1776 if (!prefix_ok(str1,"WrLeh")) {
1779 if (!check_share_info(uLevel,str2)) {
1783 /* Ensure all the usershares are loaded. */
1785 load_registry_shares();
1786 count = load_usershare_shares();
1789 data_len = fixed_len = string_len = 0;
1790 for (i=0;i<count;i++) {
1791 fstring servicename_dos;
1792 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1795 push_ascii_fstring(servicename_dos, lp_servicename(i));
1796 /* Maximum name length = 13. */
1797 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1799 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1800 if (data_len <= buf_len) {
1803 string_len += s_len;
1810 *rdata_len = fixed_len + string_len;
1811 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1816 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1821 for( i = 0; i < count; i++ ) {
1822 fstring servicename_dos;
1823 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1827 push_ascii_fstring(servicename_dos, lp_servicename(i));
1828 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1829 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1836 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1840 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1842 SSVAL(*rparam,4,counted);
1843 SSVAL(*rparam,6,total);
1845 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1846 counted,total,uLevel,
1847 buf_len,*rdata_len,mdrcnt));
1852 /****************************************************************************
1854 ****************************************************************************/
1856 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1857 char *param, int tpscnt,
1858 char *data, int tdscnt,
1859 int mdrcnt,int mprcnt,
1860 char **rdata,char **rparam,
1861 int *rdata_len,int *rparam_len)
1863 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1864 char *str2 = skip_string(param,tpscnt,str1);
1865 char *p = skip_string(param,tpscnt,str2);
1866 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1869 char *pathname = NULL;
1870 char *command, *cmdname;
1871 unsigned int offset;
1875 if (!str1 || !str2 || !p) {
1879 /* check it's a supported varient */
1880 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1883 if (!check_share_info(uLevel,str2)) {
1890 /* Do we have a string ? */
1891 if (skip_string(data,mdrcnt,data) == NULL) {
1894 pull_ascii_fstring(sharename,data);
1895 snum = find_service(sharename);
1896 if (snum >= 0) { /* already exists */
1905 /* only support disk share adds */
1906 if (SVAL(data,14)!=STYPE_DISKTREE) {
1910 offset = IVAL(data, 16);
1911 if (offset >= mdrcnt) {
1912 res = ERRinvalidparam;
1916 /* Do we have a string ? */
1917 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1920 pull_ascii_fstring(comment, offset? (data+offset) : "");
1922 offset = IVAL(data, 26);
1924 if (offset >= mdrcnt) {
1925 res = ERRinvalidparam;
1929 /* Do we have a string ? */
1930 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1934 pull_ascii_talloc(talloc_tos(), &pathname, offset? (data+offset) : "");
1939 string_replace(sharename, '"', ' ');
1940 string_replace(pathname, '"', ' ');
1941 string_replace(comment, '"', ' ');
1943 cmdname = lp_add_share_cmd();
1945 if (!cmdname || *cmdname == '\0') {
1949 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1950 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1953 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1955 if ((res = smbrun(command, NULL)) != 0) {
1956 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1962 message_send_all(smbd_messaging_context(),
1963 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1970 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1974 SSVAL(*rparam,0,NERR_Success);
1975 SSVAL(*rparam,2,0); /* converter word */
1976 SSVAL(*rparam,4,*rdata_len);
1984 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1989 SSVAL(*rparam,0,res);
1994 /****************************************************************************
1995 view list of groups available
1996 ****************************************************************************/
1998 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1999 char *param, int tpscnt,
2000 char *data, int tdscnt,
2001 int mdrcnt,int mprcnt,
2002 char **rdata,char **rparam,
2003 int *rdata_len,int *rparam_len)
2007 int resume_context, cli_buf_size;
2008 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2009 char *str2 = skip_string(param,tpscnt,str1);
2010 char *p = skip_string(param,tpscnt,str2);
2012 struct pdb_search *search;
2013 struct samr_displayentry *entries;
2017 if (!str1 || !str2 || !p) {
2021 if (strcmp(str1,"WrLeh") != 0) {
2026 * W-> resume context (number of users to skip)
2027 * r -> return parameter pointer to receive buffer
2028 * L -> length of receive buffer
2029 * e -> return parameter number of entries
2030 * h -> return parameter total number of users
2033 if (strcmp("B21",str2) != 0) {
2037 /* get list of domain groups SID_DOMAIN_GRP=2 */
2039 search = pdb_search_groups();
2042 if (search == NULL) {
2043 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2047 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2048 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2049 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2050 "%d\n", resume_context, cli_buf_size));
2053 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2057 *rdata_len = cli_buf_size;
2058 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2065 for(i=0; i<num_entries; i++) {
2067 fstrcpy(name, entries[i].account_name);
2068 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2069 /* truncate the name at 21 chars. */
2070 memcpy(p, name, 21);
2071 DEBUG(10,("adding entry %d group %s\n", i, p));
2073 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2076 /* set overflow error */
2077 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2083 pdb_search_destroy(search);
2085 *rdata_len = PTR_DIFF(p,*rdata);
2088 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2092 SSVAL(*rparam, 0, errflags);
2093 SSVAL(*rparam, 2, 0); /* converter word */
2094 SSVAL(*rparam, 4, i); /* is this right?? */
2095 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2100 /*******************************************************************
2101 Get groups that a user is a member of.
2102 ******************************************************************/
2104 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2105 char *param, int tpscnt,
2106 char *data, int tdscnt,
2107 int mdrcnt,int mprcnt,
2108 char **rdata,char **rparam,
2109 int *rdata_len,int *rparam_len)
2111 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2112 char *str2 = skip_string(param,tpscnt,str1);
2113 char *UserName = skip_string(param,tpscnt,str2);
2114 char *p = skip_string(param,tpscnt,UserName);
2115 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2116 const char *level_string;
2118 struct samu *sampw = NULL;
2126 enum lsa_SidType type;
2127 TALLOC_CTX *mem_ctx;
2129 if (!str1 || !str2 || !UserName || !p) {
2134 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2139 /* check it's a supported varient */
2141 if ( strcmp(str1,"zWrLeh") != 0 )
2146 level_string = "B21";
2152 if (strcmp(level_string,str2) != 0)
2155 *rdata_len = mdrcnt + 1024;
2156 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2161 SSVAL(*rparam,0,NERR_Success);
2162 SSVAL(*rparam,2,0); /* converter word */
2166 mem_ctx = talloc_new(NULL);
2167 if (mem_ctx == NULL) {
2168 DEBUG(0, ("talloc_new failed\n"));
2172 if ( !(sampw = samu_new(mem_ctx)) ) {
2173 DEBUG(0, ("samu_new() failed!\n"));
2174 TALLOC_FREE(mem_ctx);
2178 /* Lookup the user information; This should only be one of
2179 our accounts (not remote domains) */
2181 become_root(); /* ROOT BLOCK */
2183 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2184 NULL, NULL, &user_sid, &type)) {
2185 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2189 if (type != SID_NAME_USER) {
2190 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2191 sid_type_lookup(type)));
2195 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2196 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2197 sid_string_static(&user_sid), UserName));
2205 result = pdb_enum_group_memberships(mem_ctx, sampw,
2206 &sids, &gids, &num_groups);
2208 if (!NT_STATUS_IS_OK(result)) {
2209 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2214 for (i=0; i<num_groups; i++) {
2216 const char *grp_name;
2218 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2219 pstrcpy(p, grp_name);
2225 *rdata_len = PTR_DIFF(p,*rdata);
2227 SSVAL(*rparam,4,count); /* is this right?? */
2228 SSVAL(*rparam,6,count); /* is this right?? */
2233 unbecome_root(); /* END ROOT BLOCK */
2235 TALLOC_FREE(mem_ctx);
2240 /*******************************************************************
2242 ******************************************************************/
2244 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2245 char *param, int tpscnt,
2246 char *data, int tdscnt,
2247 int mdrcnt,int mprcnt,
2248 char **rdata,char **rparam,
2249 int *rdata_len,int *rparam_len)
2254 int i, resume_context, cli_buf_size;
2255 struct pdb_search *search;
2256 struct samr_displayentry *users;
2258 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2259 char *str2 = skip_string(param,tpscnt,str1);
2260 char *p = skip_string(param,tpscnt,str2);
2262 if (!str1 || !str2 || !p) {
2266 if (strcmp(str1,"WrLeh") != 0)
2269 * W-> resume context (number of users to skip)
2270 * r -> return parameter pointer to receive buffer
2271 * L -> length of receive buffer
2272 * e -> return parameter number of entries
2273 * h -> return parameter total number of users
2276 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2277 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2278 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2279 resume_context, cli_buf_size));
2282 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2287 /* check it's a supported varient */
2288 if (strcmp("B21",str2) != 0)
2291 *rdata_len = cli_buf_size;
2292 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2300 search = pdb_search_users(ACB_NORMAL);
2302 if (search == NULL) {
2303 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2308 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2312 errflags=NERR_Success;
2314 for (i=0; i<num_users; i++) {
2315 const char *name = users[i].account_name;
2317 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2319 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2320 "%s\n",count_sent,p));
2324 /* set overflow error */
2325 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2326 "username %s\n",count_sent,name));
2332 pdb_search_destroy(search);
2334 *rdata_len = PTR_DIFF(p,*rdata);
2336 SSVAL(*rparam,0,errflags);
2337 SSVAL(*rparam,2,0); /* converter word */
2338 SSVAL(*rparam,4,count_sent); /* is this right?? */
2339 SSVAL(*rparam,6,num_users); /* is this right?? */
2344 /****************************************************************************
2345 Get the time of day info.
2346 ****************************************************************************/
2348 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2349 char *param, int tpscnt,
2350 char *data, int tdscnt,
2351 int mdrcnt,int mprcnt,
2352 char **rdata,char **rparam,
2353 int *rdata_len,int *rparam_len)
2356 time_t unixdate = time(NULL);
2360 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2366 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2371 SSVAL(*rparam,0,NERR_Success);
2372 SSVAL(*rparam,2,0); /* converter word */
2376 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2377 by NT in a "net time" operation,
2378 it seems to ignore the one below */
2380 /* the client expects to get localtime, not GMT, in this bit
2381 (I think, this needs testing) */
2382 t = localtime(&unixdate);
2387 SIVAL(p,4,0); /* msecs ? */
2388 SCVAL(p,8,t->tm_hour);
2389 SCVAL(p,9,t->tm_min);
2390 SCVAL(p,10,t->tm_sec);
2391 SCVAL(p,11,0); /* hundredths of seconds */
2392 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2393 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2394 SCVAL(p,16,t->tm_mday);
2395 SCVAL(p,17,t->tm_mon + 1);
2396 SSVAL(p,18,1900+t->tm_year);
2397 SCVAL(p,20,t->tm_wday);
2402 /****************************************************************************
2403 Set the user password.
2404 *****************************************************************************/
2406 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2407 char *param, int tpscnt,
2408 char *data, int tdscnt,
2409 int mdrcnt,int mprcnt,
2410 char **rdata,char **rparam,
2411 int *rdata_len,int *rparam_len)
2413 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2416 fstring pass1,pass2;
2418 /* Skip 2 strings. */
2419 p = skip_string(param,tpscnt,np);
2420 p = skip_string(param,tpscnt,p);
2426 /* Do we have a string ? */
2427 if (skip_string(param,tpscnt,p) == NULL) {
2430 pull_ascii_fstring(user,p);
2432 p = skip_string(param,tpscnt,p);
2437 memset(pass1,'\0',sizeof(pass1));
2438 memset(pass2,'\0',sizeof(pass2));
2440 * We use 31 here not 32 as we're checking
2441 * the last byte we want to access is safe.
2443 if (!is_offset_safe(param,tpscnt,p,31)) {
2447 memcpy(pass2,p+16,16);
2450 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2457 SSVAL(*rparam,0,NERR_badpass);
2458 SSVAL(*rparam,2,0); /* converter word */
2460 DEBUG(3,("Set password for <%s>\n",user));
2463 * Attempt to verify the old password against smbpasswd entries
2464 * Win98 clients send old and new password in plaintext for this call.
2468 auth_serversupplied_info *server_info = NULL;
2469 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2471 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2474 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2475 SSVAL(*rparam,0,NERR_Success);
2479 TALLOC_FREE(server_info);
2481 data_blob_clear_free(&password);
2485 * If the plaintext change failed, attempt
2486 * the old encrypted method. NT will generate this
2487 * after trying the samr method. Note that this
2488 * method is done as a last resort as this
2489 * password change method loses the NT password hash
2490 * and cannot change the UNIX password as no plaintext
2494 if(SVAL(*rparam,0) != NERR_Success) {
2495 struct samu *hnd = NULL;
2497 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2499 if (change_lanman_password(hnd,(uchar *)pass2)) {
2500 SSVAL(*rparam,0,NERR_Success);
2507 memset((char *)pass1,'\0',sizeof(fstring));
2508 memset((char *)pass2,'\0',sizeof(fstring));
2513 /****************************************************************************
2514 Set the user password (SamOEM version - gets plaintext).
2515 ****************************************************************************/
2517 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2518 char *param, int tpscnt,
2519 char *data, int tdscnt,
2520 int mdrcnt,int mprcnt,
2521 char **rdata,char **rparam,
2522 int *rdata_len,int *rparam_len)
2525 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2527 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2537 SSVAL(*rparam,0,NERR_badpass);
2540 * Check the parameter definition is correct.
2543 /* Do we have a string ? */
2544 if (skip_string(param,tpscnt,p) == 0) {
2547 if(!strequal(p, "zsT")) {
2548 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2551 p = skip_string(param, tpscnt, p);
2556 /* Do we have a string ? */
2557 if (skip_string(param,tpscnt,p) == 0) {
2560 if(!strequal(p, "B516B16")) {
2561 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2564 p = skip_string(param,tpscnt,p);
2568 /* Do we have a string ? */
2569 if (skip_string(param,tpscnt,p) == 0) {
2572 p += pull_ascii_fstring(user,p);
2574 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2577 * Pass the user through the NT -> unix user mapping
2581 (void)map_username(user);
2583 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2584 SSVAL(*rparam,0,NERR_Success);
2590 /****************************************************************************
2593 ****************************************************************************/
2595 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2596 char *param, int tpscnt,
2597 char *data, int tdscnt,
2598 int mdrcnt,int mprcnt,
2599 char **rdata,char **rparam,
2600 int *rdata_len,int *rparam_len)
2602 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2603 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2604 char *str2 = skip_string(param,tpscnt,str1);
2605 char *p = skip_string(param,tpscnt,str2);
2610 WERROR werr = WERR_OK;
2612 if (!str1 || !str2 || !p) {
2616 * We use 1 here not 2 as we're checking
2617 * the last byte we want to access is safe.
2619 if (!is_offset_safe(param,tpscnt,p,1)) {
2622 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2625 /* check it's a supported varient */
2626 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2630 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2636 if (!print_job_exists(sharename, jobid)) {
2637 errcode = NERR_JobNotFound;
2641 snum = lp_servicenumber( sharename);
2643 errcode = NERR_DestNotFound;
2647 errcode = NERR_notsupported;
2650 case 81: /* delete */
2651 if (print_job_delete(¤t_user, snum, jobid, &werr))
2652 errcode = NERR_Success;
2654 case 82: /* pause */
2655 if (print_job_pause(¤t_user, snum, jobid, &werr))
2656 errcode = NERR_Success;
2658 case 83: /* resume */
2659 if (print_job_resume(¤t_user, snum, jobid, &werr))
2660 errcode = NERR_Success;
2664 if (!W_ERROR_IS_OK(werr))
2665 errcode = W_ERROR_V(werr);
2668 SSVAL(*rparam,0,errcode);
2669 SSVAL(*rparam,2,0); /* converter word */
2674 /****************************************************************************
2675 Purge a print queue - or pause or resume it.
2676 ****************************************************************************/
2678 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2679 char *param, int tpscnt,
2680 char *data, int tdscnt,
2681 int mdrcnt,int mprcnt,
2682 char **rdata,char **rparam,
2683 int *rdata_len,int *rparam_len)
2685 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2686 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2687 char *str2 = skip_string(param,tpscnt,str1);
2688 char *QueueName = skip_string(param,tpscnt,str2);
2689 int errcode = NERR_notsupported;
2691 WERROR werr = WERR_OK;
2693 if (!str1 || !str2 || !QueueName) {
2697 /* check it's a supported varient */
2698 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2702 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2708 if (skip_string(param,tpscnt,QueueName) == NULL) {
2711 snum = print_queue_snum(QueueName);
2714 errcode = NERR_JobNotFound;
2719 case 74: /* Pause queue */
2720 if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success;
2722 case 75: /* Resume queue */
2723 if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success;
2725 case 103: /* Purge */
2726 if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success;
2730 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2733 SSVAL(*rparam,0,errcode);
2734 SSVAL(*rparam,2,0); /* converter word */
2739 /****************************************************************************
2740 set the property of a print job (undocumented?)
2741 ? function = 0xb -> set name of print job
2742 ? function = 0x6 -> move print job up/down
2743 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2744 or <WWsTP> <WB21BB16B10zWWzDDz>
2745 ****************************************************************************/
2747 static int check_printjob_info(struct pack_desc* desc,
2748 int uLevel, char* id)
2750 desc->subformat = NULL;
2752 case 0: desc->format = "W"; break;
2753 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2754 case 2: desc->format = "WWzWWDDzz"; break;
2755 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2756 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2758 DEBUG(0,("check_printjob_info: invalid level %d\n",
2762 if (id == NULL || strcmp(desc->format,id) != 0) {
2763 DEBUG(0,("check_printjob_info: invalid format %s\n",
2764 id ? id : "<NULL>" ));
2770 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2771 char *param, int tpscnt,
2772 char *data, int tdscnt,
2773 int mdrcnt,int mprcnt,
2774 char **rdata,char **rparam,
2775 int *rdata_len,int *rparam_len)
2777 struct pack_desc desc;
2778 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2779 char *str2 = skip_string(param,tpscnt,str1);
2780 char *p = skip_string(param,tpscnt,str2);
2783 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2784 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2787 if (!str1 || !str2 || !p) {
2791 * We use 1 here not 2 as we're checking
2792 * the last byte we want to access is safe.
2794 if (!is_offset_safe(param,tpscnt,p,1)) {
2797 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2800 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2805 if (!share_defined(sharename)) {
2806 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2813 /* check it's a supported varient */
2814 if ((strcmp(str1,"WWsTP")) ||
2815 (!check_printjob_info(&desc,uLevel,str2)))
2818 if (!print_job_exists(sharename, jobid)) {
2819 errcode=NERR_JobNotFound;
2823 errcode = NERR_notsupported;
2827 /* change job place in the queue,
2828 data gives the new place */
2829 place = SVAL(data,0);
2830 if (print_job_set_place(sharename, jobid, place)) {
2831 errcode=NERR_Success;
2836 /* change print job name, data gives the name */
2837 if (print_job_set_name(sharename, jobid, data)) {
2838 errcode=NERR_Success;
2847 SSVALS(*rparam,0,errcode);
2848 SSVAL(*rparam,2,0); /* converter word */
2854 /****************************************************************************
2855 Get info about the server.
2856 ****************************************************************************/
2858 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2859 char *param, int tpscnt,
2860 char *data, int tdscnt,
2861 int mdrcnt,int mprcnt,
2862 char **rdata,char **rparam,
2863 int *rdata_len,int *rparam_len)
2865 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2866 char *str2 = skip_string(param,tpscnt,str1);
2867 char *p = skip_string(param,tpscnt,str2);
2868 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2872 if (!str1 || !str2 || !p) {
2876 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2878 /* check it's a supported varient */
2879 if (!prefix_ok(str1,"WrLh")) {
2885 if (strcmp(str2,"B16") != 0) {
2891 if (strcmp(str2,"B16BBDz") != 0) {
2897 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2903 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2909 if (strcmp(str2,"DN") != 0) {
2915 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2924 *rdata_len = mdrcnt;
2925 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2931 p2 = p + struct_len;
2933 srvstr_push(NULL, 0, p,global_myname(),16,
2934 STR_ASCII|STR_UPPER|STR_TERMINATE);
2938 struct srv_info_struct *servers=NULL;
2940 char *comment = NULL;
2941 TALLOC_CTX *ctx = talloc_tos();
2942 uint32 servertype= lp_default_server_announce();
2944 comment = talloc_strdup(ctx,lp_serverstring());
2949 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2950 for (i=0;i<count;i++) {
2951 if (strequal(servers[i].name,global_myname())) {
2952 servertype = servers[i].type;
2953 TALLOC_FREE(comment);
2954 comment = talloc_strdup(ctx,
2955 servers[i].comment);
2965 SCVAL(p,0,lp_major_announce_version());
2966 SCVAL(p,1,lp_minor_announce_version());
2967 SIVAL(p,2,servertype);
2969 if (mdrcnt == struct_len) {
2972 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2973 comment = talloc_sub_advanced(ctx,
2974 lp_servicename(SNUM(conn)),
2978 get_current_username(),
2979 current_user_info.domain,
2984 if (mdrcnt - struct_len <= 0) {
2989 MIN(mdrcnt - struct_len,
2990 MAX_SERVER_STRING_LENGTH),
2992 p2 = skip_string(*rdata,*rdata_len,p2);
3000 return False; /* not yet implemented */
3003 *rdata_len = PTR_DIFF(p2,*rdata);
3006 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3010 SSVAL(*rparam,0,NERR_Success);
3011 SSVAL(*rparam,2,0); /* converter word */
3012 SSVAL(*rparam,4,*rdata_len);
3017 /****************************************************************************
3018 Get info about the server.
3019 ****************************************************************************/
3021 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3022 char *param, int tpscnt,
3023 char *data, int tdscnt,
3024 int mdrcnt,int mprcnt,
3025 char **rdata,char **rparam,
3026 int *rdata_len,int *rparam_len)
3028 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3029 char *str2 = skip_string(param,tpscnt,str1);
3030 char *p = skip_string(param,tpscnt,str2);
3032 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3034 if (!str1 || !str2 || !p) {
3038 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3041 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3046 /* check it's a supported varient */
3047 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3051 *rdata_len = mdrcnt + 1024;
3052 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3057 SSVAL(*rparam,0,NERR_Success);
3058 SSVAL(*rparam,2,0); /* converter word */
3061 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3066 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3067 pstrcpy(p2,get_local_machine_name());
3069 p2 = skip_string(*rdata,*rdata_len,p2);
3075 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3076 pstrcpy(p2,current_user_info.smb_name);
3077 p2 = skip_string(*rdata,*rdata_len,p2);
3083 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3084 pstrcpy(p2,lp_workgroup());
3086 p2 = skip_string(*rdata,*rdata_len,p2);
3092 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3093 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3096 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3097 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
3098 p2 = skip_string(*rdata,*rdata_len,p2);
3104 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3106 p2 = skip_string(*rdata,*rdata_len,p2);
3112 *rdata_len = PTR_DIFF(p2,*rdata);
3114 SSVAL(*rparam,4,*rdata_len);
3119 /****************************************************************************
3120 get info about a user
3122 struct user_info_11 {
3123 char usri11_name[21]; 0-20
3125 char *usri11_comment; 22-25
3126 char *usri11_usr_comment; 26-29
3127 unsigned short usri11_priv; 30-31
3128 unsigned long usri11_auth_flags; 32-35
3129 long usri11_password_age; 36-39
3130 char *usri11_homedir; 40-43
3131 char *usri11_parms; 44-47
3132 long usri11_last_logon; 48-51
3133 long usri11_last_logoff; 52-55
3134 unsigned short usri11_bad_pw_count; 56-57
3135 unsigned short usri11_num_logons; 58-59
3136 char *usri11_logon_server; 60-63
3137 unsigned short usri11_country_code; 64-65
3138 char *usri11_workstations; 66-69
3139 unsigned long usri11_max_storage; 70-73
3140 unsigned short usri11_units_per_week; 74-75
3141 unsigned char *usri11_logon_hours; 76-79
3142 unsigned short usri11_code_page; 80-81
3147 usri11_name specifies the user name for which information is retireved
3149 usri11_pad aligns the next data structure element to a word boundary
3151 usri11_comment is a null terminated ASCII comment
3153 usri11_user_comment is a null terminated ASCII comment about the user
3155 usri11_priv specifies the level of the privilege assigned to the user.
3156 The possible values are:
3158 Name Value Description
3159 USER_PRIV_GUEST 0 Guest privilege
3160 USER_PRIV_USER 1 User privilege
3161 USER_PRV_ADMIN 2 Administrator privilege
3163 usri11_auth_flags specifies the account operator privileges. The
3164 possible values are:
3166 Name Value Description
3167 AF_OP_PRINT 0 Print operator
3170 Leach, Naik [Page 28]
3174 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3177 AF_OP_COMM 1 Communications operator
3178 AF_OP_SERVER 2 Server operator
3179 AF_OP_ACCOUNTS 3 Accounts operator
3182 usri11_password_age specifies how many seconds have elapsed since the
3183 password was last changed.
3185 usri11_home_dir points to a null terminated ASCII string that contains
3186 the path name of the user's home directory.
3188 usri11_parms points to a null terminated ASCII string that is set
3189 aside for use by applications.
3191 usri11_last_logon specifies the time when the user last logged on.
3192 This value is stored as the number of seconds elapsed since
3193 00:00:00, January 1, 1970.
3195 usri11_last_logoff specifies the time when the user last logged off.
3196 This value is stored as the number of seconds elapsed since
3197 00:00:00, January 1, 1970. A value of 0 means the last logoff
3200 usri11_bad_pw_count specifies the number of incorrect passwords
3201 entered since the last successful logon.
3203 usri11_log1_num_logons specifies the number of times this user has
3204 logged on. A value of -1 means the number of logons is unknown.
3206 usri11_logon_server points to a null terminated ASCII string that
3207 contains the name of the server to which logon requests are sent.
3208 A null string indicates logon requests should be sent to the
3211 usri11_country_code specifies the country code for the user's language
3214 usri11_workstations points to a null terminated ASCII string that
3215 contains the names of workstations the user may log on from.
3216 There may be up to 8 workstations, with the names separated by
3217 commas. A null strings indicates there are no restrictions.
3219 usri11_max_storage specifies the maximum amount of disk space the user
3220 can occupy. A value of 0xffffffff indicates there are no
3223 usri11_units_per_week specifies the equal number of time units into
3224 which a week is divided. This value must be equal to 168.
3226 usri11_logon_hours points to a 21 byte (168 bits) string that
3227 specifies the time during which the user can log on. Each bit
3228 represents one unique hour in a week. The first bit (bit 0, word
3229 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3233 Leach, Naik [Page 29]
3237 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3240 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3241 are no restrictions.
3243 usri11_code_page specifies the code page for the user's language of
3246 All of the pointers in this data structure need to be treated
3247 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3248 to be ignored. The converter word returned in the parameters section
3249 needs to be subtracted from the lower 16 bits to calculate an offset
3250 into the return buffer where this ASCII string resides.
3252 There is no auxiliary data in the response.
3254 ****************************************************************************/
3256 #define usri11_name 0
3257 #define usri11_pad 21
3258 #define usri11_comment 22
3259 #define usri11_usr_comment 26
3260 #define usri11_full_name 30
3261 #define usri11_priv 34
3262 #define usri11_auth_flags 36
3263 #define usri11_password_age 40
3264 #define usri11_homedir 44
3265 #define usri11_parms 48
3266 #define usri11_last_logon 52
3267 #define usri11_last_logoff 56
3268 #define usri11_bad_pw_count 60
3269 #define usri11_num_logons 62
3270 #define usri11_logon_server 64
3271 #define usri11_country_code 68
3272 #define usri11_workstations 70
3273 #define usri11_max_storage 74
3274 #define usri11_units_per_week 78
3275 #define usri11_logon_hours 80
3276 #define usri11_code_page 84
3277 #define usri11_end 86
3279 #define USER_PRIV_GUEST 0
3280 #define USER_PRIV_USER 1
3281 #define USER_PRIV_ADMIN 2
3283 #define AF_OP_PRINT 0
3284 #define AF_OP_COMM 1
3285 #define AF_OP_SERVER 2
3286 #define AF_OP_ACCOUNTS 3
3289 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3290 char *param, int tpscnt,
3291 char *data, int tdscnt,
3292 int mdrcnt,int mprcnt,
3293 char **rdata,char **rparam,
3294 int *rdata_len,int *rparam_len)
3296 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3297 char *str2 = skip_string(param,tpscnt,str1);
3298 char *UserName = skip_string(param,tpscnt,str2);
3299 char *p = skip_string(param,tpscnt,UserName);
3300 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3302 const char *level_string;
3304 /* get NIS home of a previously validated user - simeon */
3305 /* With share level security vuid will always be zero.
3306 Don't depend on vuser being non-null !!. JRA */
3307 user_struct *vuser = get_valid_user_struct(vuid);
3309 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3310 vuser->user.unix_name));
3313 if (!str1 || !str2 || !UserName || !p) {
3318 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3323 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3325 /* check it's a supported variant */
3326 if (strcmp(str1,"zWrLh") != 0) {
3330 case 0: level_string = "B21"; break;
3331 case 1: level_string = "B21BB16DWzzWz"; break;
3332 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3333 case 10: level_string = "B21Bzzz"; break;
3334 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3335 default: return False;
3338 if (strcmp(level_string,str2) != 0) {
3342 *rdata_len = mdrcnt + 1024;
3343 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3348 SSVAL(*rparam,0,NERR_Success);
3349 SSVAL(*rparam,2,0); /* converter word */
3352 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3358 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3361 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3366 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3367 pstrcpy(p2,"Comment");
3368 p2 = skip_string(*rdata,*rdata_len,p2);
3373 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3374 pstrcpy(p2,"UserComment");
3375 p2 = skip_string(*rdata,*rdata_len,p2);
3380 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3381 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3382 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3383 p2 = skip_string(*rdata,*rdata_len,p2);
3390 /* modelled after NTAS 3.51 reply */
3391 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3392 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3393 SIVALS(p,usri11_password_age,-1); /* password age */
3394 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3395 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3396 p2 = skip_string(*rdata,*rdata_len,p2);
3400 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3402 p2 = skip_string(*rdata,*rdata_len,p2);
3406 SIVAL(p,usri11_last_logon,0); /* last logon */
3407 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3408 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3409 SSVALS(p,usri11_num_logons,-1); /* num logons */
3410 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3411 pstrcpy(p2,"\\\\*");
3412 p2 = skip_string(*rdata,*rdata_len,p2);
3416 SSVAL(p,usri11_country_code,0); /* country code */
3418 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3420 p2 = skip_string(*rdata,*rdata_len,p2);
3425 SIVALS(p,usri11_max_storage,-1); /* max storage */
3426 SSVAL(p,usri11_units_per_week,168); /* units per week */
3427 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3429 /* a simple way to get logon hours at all times. */
3431 SCVAL(p2,21,0); /* fix zero termination */
3432 p2 = skip_string(*rdata,*rdata_len,p2);
3437 SSVAL(p,usri11_code_page,0); /* code page */
3440 if (uLevel == 1 || uLevel == 2) {
3441 memset(p+22,' ',16); /* password */
3442 SIVALS(p,38,-1); /* password age */
3444 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3445 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3446 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3447 p2 = skip_string(*rdata,*rdata_len,p2);
3451 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3453 SSVAL(p,52,0); /* flags */
3454 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3455 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3456 p2 = skip_string(*rdata,*rdata_len,p2);
3461 SIVAL(p,60,0); /* auth_flags */
3462 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3463 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3464 p2 = skip_string(*rdata,*rdata_len,p2);
3468 SIVAL(p,68,0); /* urs_comment */
3469 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3471 p2 = skip_string(*rdata,*rdata_len,p2);
3475 SIVAL(p,76,0); /* workstations */
3476 SIVAL(p,80,0); /* last_logon */
3477 SIVAL(p,84,0); /* last_logoff */
3478 SIVALS(p,88,-1); /* acct_expires */
3479 SIVALS(p,92,-1); /* max_storage */
3480 SSVAL(p,96,168); /* units_per_week */
3481 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3484 SSVALS(p,102,-1); /* bad_pw_count */
3485 SSVALS(p,104,-1); /* num_logons */
3486 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3488 TALLOC_CTX *ctx = talloc_tos();
3489 int space_rem = *rdata_len - (p2 - *rdata);
3492 if (space_rem <= 0) {
3495 tmp = talloc_strdup(ctx, "\\\\%L");
3499 tmp = talloc_sub_basic(ctx,
3512 p2 = skip_string(*rdata,*rdata_len,p2);
3516 SSVAL(p,110,49); /* country_code */
3517 SSVAL(p,112,860); /* code page */
3521 *rdata_len = PTR_DIFF(p2,*rdata);
3523 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3528 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3529 char *param, int tpscnt,
3530 char *data, int tdscnt,
3531 int mdrcnt,int mprcnt,
3532 char **rdata,char **rparam,
3533 int *rdata_len,int *rparam_len)
3535 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3536 char *str2 = skip_string(param,tpscnt,str1);
3537 char *p = skip_string(param,tpscnt,str2);
3539 struct pack_desc desc;
3541 /* With share level security vuid will always be zero.
3542 Don't depend on vuser being non-null !!. JRA */
3543 user_struct *vuser = get_valid_user_struct(vuid);
3545 if (!str1 || !str2 || !p) {
3550 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3551 vuser->user.unix_name));
3554 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3555 name = get_safe_str_ptr(param,tpscnt,p,2);
3560 memset((char *)&desc,'\0',sizeof(desc));
3562 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3564 /* check it's a supported varient */
3565 if (strcmp(str1,"OOWb54WrLh") != 0) {
3568 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3572 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3579 desc.buflen = mdrcnt;
3580 desc.subformat = NULL;
3583 if (init_package(&desc,1,0)) {
3584 PACKI(&desc,"W",0); /* code */
3585 PACKS(&desc,"B21",name); /* eff. name */
3586 PACKS(&desc,"B",""); /* pad */
3587 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3588 PACKI(&desc,"D",0); /* auth flags XXX */
3589 PACKI(&desc,"W",0); /* num logons */
3590 PACKI(&desc,"W",0); /* bad pw count */
3591 PACKI(&desc,"D",0); /* last logon */
3592 PACKI(&desc,"D",-1); /* last logoff */
3593 PACKI(&desc,"D",-1); /* logoff time */
3594 PACKI(&desc,"D",-1); /* kickoff time */
3595 PACKI(&desc,"D",0); /* password age */
3596 PACKI(&desc,"D",0); /* password can change */
3597 PACKI(&desc,"D",-1); /* password must change */
3601 fstrcpy(mypath,"\\\\");
3602 fstrcat(mypath,get_local_machine_name());
3604 PACKS(&desc,"z",mypath); /* computer */
3607 PACKS(&desc,"z",lp_workgroup());/* domain */
3608 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3609 PACKI(&desc,"D",0x00000000); /* reserved */
3612 *rdata_len = desc.usedlen;
3614 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3618 SSVALS(*rparam,0,desc.errcode);
3620 SSVAL(*rparam,4,desc.neededlen);
3622 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3627 /****************************************************************************
3628 api_WAccessGetUserPerms
3629 ****************************************************************************/
3631 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3632 char *param, int tpscnt,
3633 char *data, int tdscnt,
3634 int mdrcnt,int mprcnt,
3635 char **rdata,char **rparam,
3636 int *rdata_len,int *rparam_len)
3638 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3639 char *str2 = skip_string(param,tpscnt,str1);
3640 char *user = skip_string(param,tpscnt,str2);
3641 char *resource = skip_string(param,tpscnt,user);
3643 if (!str1 || !str2 || !user || !resource) {
3647 if (skip_string(param,tpscnt,resource) == NULL) {
3650 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3652 /* check it's a supported varient */
3653 if (strcmp(str1,"zzh") != 0) {
3656 if (strcmp(str2,"") != 0) {
3661 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3665 SSVALS(*rparam,0,0); /* errorcode */
3666 SSVAL(*rparam,2,0); /* converter word */
3667 SSVAL(*rparam,4,0x7f); /* permission flags */
3672 /****************************************************************************
3673 api_WPrintJobEnumerate
3674 ****************************************************************************/
3676 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3677 char *param, int tpscnt,
3678 char *data, int tdscnt,
3679 int mdrcnt,int mprcnt,
3680 char **rdata,char **rparam,
3681 int *rdata_len,int *rparam_len)
3683 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3684 char *str2 = skip_string(param,tpscnt,str1);
3685 char *p = skip_string(param,tpscnt,str2);
3692 struct pack_desc desc;
3693 print_queue_struct *queue=NULL;
3694 print_status_struct status;
3697 if (!str1 || !str2 || !p) {
3701 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3703 memset((char *)&desc,'\0',sizeof(desc));
3704 memset((char *)&status,'\0',sizeof(status));
3706 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3708 /* check it's a supported varient */
3709 if (strcmp(str1,"WWrLh") != 0) {
3712 if (!check_printjob_info(&desc,uLevel,str2)) {
3716 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3720 snum = lp_servicenumber( sharename);
3721 if (snum < 0 || !VALID_SNUM(snum)) {
3725 count = print_queue_status(snum,&queue,&status);
3726 for (i = 0; i < count; i++) {
3727 if (queue[i].job == jobid) {
3733 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3738 desc.buflen = mdrcnt;
3741 * Don't return data but need to get correct length
3742 * init_package will return wrong size if buflen=0
3744 desc.buflen = getlen(desc.format);
3745 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3748 if (init_package(&desc,1,0)) {
3750 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3751 *rdata_len = desc.usedlen;
3753 desc.errcode = NERR_JobNotFound;
3759 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3763 SSVALS(*rparam,0,desc.errcode);
3765 SSVAL(*rparam,4,desc.neededlen);
3770 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3775 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3776 char *param, int tpscnt,
3777 char *data, int tdscnt,
3778 int mdrcnt,int mprcnt,
3779 char **rdata,char **rparam,
3780 int *rdata_len,int *rparam_len)
3782 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3783 char *str2 = skip_string(param,tpscnt,str1);
3784 char *p = skip_string(param,tpscnt,str2);
3790 struct pack_desc desc;
3791 print_queue_struct *queue=NULL;
3792 print_status_struct status;
3794 if (!str1 || !str2 || !p) {
3798 memset((char *)&desc,'\0',sizeof(desc));
3799 memset((char *)&status,'\0',sizeof(status));
3801 p = skip_string(param,tpscnt,p);
3805 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3807 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3809 /* check it's a supported variant */
3810 if (strcmp(str1,"zWrLeh") != 0) {
3815 return False; /* defined only for uLevel 0,1,2 */
3818 if (!check_printjob_info(&desc,uLevel,str2)) {
3822 snum = find_service(name);
3823 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3827 count = print_queue_status(snum,&queue,&status);
3829 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3835 desc.buflen = mdrcnt;
3837 if (init_package(&desc,count,0)) {
3839 for (i = 0; i < count; i++) {
3840 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3841 if (desc.errcode == NERR_Success) {
3847 *rdata_len = desc.usedlen;
3850 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3854 SSVALS(*rparam,0,desc.errcode);
3856 SSVAL(*rparam,4,succnt);
3857 SSVAL(*rparam,6,count);
3861 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3866 static int check_printdest_info(struct pack_desc* desc,
3867 int uLevel, char* id)
3869 desc->subformat = NULL;
3872 desc->format = "B9";
3875 desc->format = "B9B21WWzW";
3881 desc->format = "zzzWWzzzWW";
3884 DEBUG(0,("check_printdest_info: invalid level %d\n",
3888 if (id == NULL || strcmp(desc->format,id) != 0) {
3889 DEBUG(0,("check_printdest_info: invalid string %s\n",
3890 id ? id : "<NULL>" ));
3896 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3897 struct pack_desc* desc)
3901 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3902 buf[sizeof(buf)-1] = 0;
3906 PACKS(desc,"B9",buf); /* szName */
3908 PACKS(desc,"B21",""); /* szUserName */
3909 PACKI(desc,"W",0); /* uJobId */
3910 PACKI(desc,"W",0); /* fsStatus */
3911 PACKS(desc,"z",""); /* pszStatus */
3912 PACKI(desc,"W",0); /* time */
3916 if (uLevel == 2 || uLevel == 3) {
3917 PACKS(desc,"z",buf); /* pszPrinterName */
3919 PACKS(desc,"z",""); /* pszUserName */
3920 PACKS(desc,"z",""); /* pszLogAddr */
3921 PACKI(desc,"W",0); /* uJobId */
3922 PACKI(desc,"W",0); /* fsStatus */
3923 PACKS(desc,"z",""); /* pszStatus */
3924 PACKS(desc,"z",""); /* pszComment */
3925 PACKS(desc,"z","NULL"); /* pszDrivers */
3926 PACKI(desc,"W",0); /* time */
3927 PACKI(desc,"W",0); /* pad1 */
3932 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3933 char *param, int tpscnt,
3934 char *data, int tdscnt,
3935 int mdrcnt,int mprcnt,
3936 char **rdata,char **rparam,
3937 int *rdata_len,int *rparam_len)
3939 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3940 char *str2 = skip_string(param,tpscnt,str1);
3941 char *p = skip_string(param,tpscnt,str2);
3942 char* PrinterName = p;
3944 struct pack_desc desc;
3948 if (!str1 || !str2 || !p) {
3952 memset((char *)&desc,'\0',sizeof(desc));
3954 p = skip_string(param,tpscnt,p);
3958 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3960 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3962 /* check it's a supported varient */
3963 if (strcmp(str1,"zWrLh") != 0) {
3966 if (!check_printdest_info(&desc,uLevel,str2)) {
3970 snum = find_service(PrinterName);
3971 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3973 desc.errcode = NERR_DestNotFound;
3977 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3982 desc.buflen = mdrcnt;
3985 * Don't return data but need to get correct length
3986 * init_package will return wrong size if buflen=0
3988 desc.buflen = getlen(desc.format);
3989 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3991 if (init_package(&desc,1,0)) {
3992 fill_printdest_info(conn,snum,uLevel,&desc);
3994 *rdata_len = desc.usedlen;
3998 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4002 SSVALS(*rparam,0,desc.errcode);
4004 SSVAL(*rparam,4,desc.neededlen);
4006 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4012 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4013 char *param, int tpscnt,
4014 char *data, int tdscnt,
4015 int mdrcnt,int mprcnt,
4016 char **rdata,char **rparam,
4017 int *rdata_len,int *rparam_len)
4019 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4020 char *str2 = skip_string(param,tpscnt,str1);
4021 char *p = skip_string(param,tpscnt,str2);
4025 struct pack_desc desc;
4026 int services = lp_numservices();
4028 if (!str1 || !str2 || !p) {
4032 memset((char *)&desc,'\0',sizeof(desc));
4034 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4036 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4038 /* check it's a supported varient */
4039 if (strcmp(str1,"WrLeh") != 0) {
4042 if (!check_printdest_info(&desc,uLevel,str2)) {
4047 for (i = 0; i < services; i++) {
4048 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4054 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4061 desc.buflen = mdrcnt;
4062 if (init_package(&desc,queuecnt,0)) {
4065 for (i = 0; i < services; i++) {
4066 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4067 fill_printdest_info(conn,i,uLevel,&desc);
4069 if (desc.errcode == NERR_Success) {
4076 *rdata_len = desc.usedlen;
4079 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4083 SSVALS(*rparam,0,desc.errcode);
4085 SSVAL(*rparam,4,succnt);
4086 SSVAL(*rparam,6,queuecnt);
4088 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4093 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4094 char *param, int tpscnt,
4095 char *data, int tdscnt,
4096 int mdrcnt,int mprcnt,
4097 char **rdata,char **rparam,
4098 int *rdata_len,int *rparam_len)
4100 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4101 char *str2 = skip_string(param,tpscnt,str1);
4102 char *p = skip_string(param,tpscnt,str2);
4105 struct pack_desc desc;
4107 if (!str1 || !str2 || !p) {
4111 memset((char *)&desc,'\0',sizeof(desc));
4113 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4115 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4117 /* check it's a supported varient */
4118 if (strcmp(str1,"WrLeh") != 0) {
4121 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4126 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4132 desc.buflen = mdrcnt;
4133 if (init_package(&desc,1,0)) {
4134 PACKS(&desc,"B41","NULL");
4137 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4139 *rdata_len = desc.usedlen;
4142 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4146 SSVALS(*rparam,0,desc.errcode);
4148 SSVAL(*rparam,4,succnt);
4151 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4156 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4157 char *param, int tpscnt,
4158 char *data, int tdscnt,
4159 int mdrcnt,int mprcnt,
4160 char **rdata,char **rparam,
4161 int *rdata_len,int *rparam_len)
4163 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4164 char *str2 = skip_string(param,tpscnt,str1);
4165 char *p = skip_string(param,tpscnt,str2);
4168 struct pack_desc desc;
4170 if (!str1 || !str2 || !p) {
4173 memset((char *)&desc,'\0',sizeof(desc));
4175 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4177 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4179 /* check it's a supported varient */
4180 if (strcmp(str1,"WrLeh") != 0) {
4183 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4188 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4194 desc.buflen = mdrcnt;
4196 if (init_package(&desc,1,0)) {
4197 PACKS(&desc,"B13","lpd");
4200 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4202 *rdata_len = desc.usedlen;
4205 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4209 SSVALS(*rparam,0,desc.errcode);
4211 SSVAL(*rparam,4,succnt);
4214 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4219 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4220 char *param, int tpscnt,
4221 char *data, int tdscnt,
4222 int mdrcnt,int mprcnt,
4223 char **rdata,char **rparam,
4224 int *rdata_len,int *rparam_len)
4226 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4227 char *str2 = skip_string(param,tpscnt,str1);
4228 char *p = skip_string(param,tpscnt,str2);
4231 struct pack_desc desc;
4233 if (!str1 || !str2 || !p) {
4237 memset((char *)&desc,'\0',sizeof(desc));
4239 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4241 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4243 /* check it's a supported varient */
4244 if (strcmp(str1,"WrLeh") != 0) {
4247 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4252 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4257 memset((char *)&desc,'\0',sizeof(desc));
4259 desc.buflen = mdrcnt;
4261 if (init_package(&desc,1,0)) {
4262 PACKS(&desc,"B13","lp0");
4265 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4267 *rdata_len = desc.usedlen;
4270 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4274 SSVALS(*rparam,0,desc.errcode);
4276 SSVAL(*rparam,4,succnt);
4279 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4284 /****************************************************************************
4286 ****************************************************************************/
4288 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4289 char *param, int tpscnt,
4290 char *data, int tdscnt,
4291 int mdrcnt,int mprcnt,
4292 char **rdata,char **rparam,
4293 int *rdata_len,int *rparam_len)
4296 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4297 char *str2 = skip_string(param,tpscnt,str1);
4298 char *p = skip_string(param,tpscnt,str2);
4300 struct pack_desc desc;
4301 struct sessionid *session_list;
4302 int i, num_sessions;
4304 if (!str1 || !str2 || !p) {
4308 memset((char *)&desc,'\0',sizeof(desc));
4310 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4312 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4313 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4314 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4316 /* check it's a supported varient */
4317 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4320 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4324 num_sessions = list_sessions(talloc_tos(), &session_list);
4327 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4332 memset((char *)&desc,'\0',sizeof(desc));
4334 desc.buflen = mdrcnt;
4336 if (!init_package(&desc,num_sessions,0)) {
4340 for(i=0; i<num_sessions; i++) {
4341 PACKS(&desc, "z", session_list[i].remote_machine);
4342 PACKS(&desc, "z", session_list[i].username);
4343 PACKI(&desc, "W", 1); /* num conns */
4344 PACKI(&desc, "W", 0); /* num opens */
4345 PACKI(&desc, "W", 1); /* num users */
4346 PACKI(&desc, "D", 0); /* session time */
4347 PACKI(&desc, "D", 0); /* idle time */
4348 PACKI(&desc, "D", 0); /* flags */
4349 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4352 *rdata_len = desc.usedlen;
4355 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4359 SSVALS(*rparam,0,desc.errcode);
4360 SSVAL(*rparam,2,0); /* converter */
4361 SSVAL(*rparam,4,num_sessions); /* count */
4363 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4369 /****************************************************************************
4370 The buffer was too small.
4371 ****************************************************************************/
4373 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4374 int mdrcnt, int mprcnt,
4375 char **rdata, char **rparam,
4376 int *rdata_len, int *rparam_len)
4378 *rparam_len = MIN(*rparam_len,mprcnt);
4379 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4386 SSVAL(*rparam,0,NERR_BufTooSmall);
4388 DEBUG(3,("Supplied buffer too small in API command\n"));
4393 /****************************************************************************
4394 The request is not supported.
4395 ****************************************************************************/
4397 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4398 char *param, int tpscnt,
4399 char *data, int tdscnt,
4400 int mdrcnt, int mprcnt,
4401 char **rdata, char **rparam,
4402 int *rdata_len, int *rparam_len)
4405 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4412 SSVAL(*rparam,0,NERR_notsupported);
4413 SSVAL(*rparam,2,0); /* converter word */
4415 DEBUG(3,("Unsupported API command\n"));
4420 static const struct {
4423 bool (*fn)(connection_struct *, uint16,
4426 int,int,char **,char **,int *,int *);
4427 bool auth_user; /* Deny anonymous access? */
4428 } api_commands[] = {
4429 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4430 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4431 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4432 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4433 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4434 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4435 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4436 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4437 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4438 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4439 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4440 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4441 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4442 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4443 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4444 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4445 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4446 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4447 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4448 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4449 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4450 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4451 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4452 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4453 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4454 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4455 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4456 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4457 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4458 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4459 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4460 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4461 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4462 {NULL, -1, api_Unsupported}
4463 /* The following RAP calls are not implemented by Samba:
4465 RAP_WFileEnum2 - anon not OK
4470 /****************************************************************************
4471 Handle remote api calls.
4472 ****************************************************************************/
4474 void api_reply(connection_struct *conn, uint16 vuid,
4475 struct smb_request *req,
4476 char *data, char *params,
4477 int tdscnt, int tpscnt,
4478 int mdrcnt, int mprcnt)
4482 char *rparam = NULL;
4483 const char *name1 = NULL;
4484 const char *name2 = NULL;
4491 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4492 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4497 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4500 api_command = SVAL(params,0);
4501 /* Is there a string at position params+2 ? */
4502 if (skip_string(params,tpscnt,params+2)) {
4507 name2 = skip_string(params,tpscnt,params+2);
4512 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4516 tdscnt,tpscnt,mdrcnt,mprcnt));
4518 for (i=0;api_commands[i].name;i++) {
4519 if (api_commands[i].id == api_command && api_commands[i].fn) {
4520 DEBUG(3,("Doing %s\n",api_commands[i].name));
4525 /* Check whether this api call can be done anonymously */
4527 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4528 user_struct *user = get_valid_user_struct(vuid);
4530 if (!user || user->guest) {
4531 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4536 rdata = (char *)SMB_MALLOC(1024);
4538 memset(rdata,'\0',1024);
4541 rparam = (char *)SMB_MALLOC(1024);
4543 memset(rparam,'\0',1024);
4546 if(!rdata || !rparam) {
4547 DEBUG(0,("api_reply: malloc fail !\n"));
4550 reply_nterror(req, NT_STATUS_NO_MEMORY);
4554 reply = api_commands[i].fn(conn,
4556 params,tpscnt, /* params + length */
4557 data,tdscnt, /* data + length */
4559 &rdata,&rparam,&rdata_len,&rparam_len);
4562 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4563 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4564 &rdata,&rparam,&rdata_len,&rparam_len);
4567 /* if we get False back then it's actually unsupported */
4569 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4570 &rdata,&rparam,&rdata_len,&rparam_len);
4573 /* If api_Unsupported returns false we can't return anything. */
4575 send_trans_reply(req, rparam, rparam_len,
4576 rdata, rdata_len, False);