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);
119 (*p_space_remaining) -= l;
123 static int CopyAndAdvance(char **dst, char *src, int *n)
126 if (!src || !dst || !n || !(*dst)) {
129 l = push_ascii(*dst,src,*n, STR_TERMINATE);
138 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
140 TALLOC_CTX *ctx = talloc_tos();
145 buf = talloc_strdup(ctx,s);
149 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
153 buf = talloc_sub_advanced(ctx,
154 lp_servicename(SNUM(conn)),
158 get_current_username(),
159 current_user_info.domain,
164 return strlen(buf) + 1;
167 static char *Expand(connection_struct *conn, int snum, char *s)
169 TALLOC_CTX *ctx = talloc_tos();
175 buf = talloc_strdup(ctx,s);
179 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
183 return talloc_sub_advanced(ctx,
184 lp_servicename(SNUM(conn)),
188 get_current_username(),
189 current_user_info.domain,
193 /*******************************************************************
194 Check a API string for validity when we only need to check the prefix.
195 ******************************************************************/
197 static bool prefix_ok(const char *str, const char *prefix)
199 return(strncmp(str,prefix,strlen(prefix)) == 0);
203 const char *format; /* formatstring for structure */
204 const char *subformat; /* subformat for structure */
205 char *base; /* baseaddress of buffer */
206 int buflen; /* remaining size for fixed part; on init: length of base */
207 int subcount; /* count of substructures */
208 char *structbuf; /* pointer into buffer for remaining fixed part */
209 int stringlen; /* remaining size for variable part */
210 char *stringbuf; /* pointer into buffer for remaining variable part */
211 int neededlen; /* total needed size */
212 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
213 const char *curpos; /* current position; pointer into format or subformat */
217 static int get_counter(const char **p)
223 if (!isdigit((int)**p)) {
229 n = 10 * n + (i - '0');
237 static int getlen(const char *p)
246 case 'W': /* word (2 byte) */
249 case 'K': /* status word? (2 byte) */
252 case 'N': /* count of substructures (word) at end */
255 case 'D': /* double word (4 byte) */
256 case 'z': /* offset to zero terminated string (4 byte) */
257 case 'l': /* offset to user data (4 byte) */
260 case 'b': /* offset to data (with counter) (4 byte) */
264 case 'B': /* byte (with optional counter) */
265 n += get_counter(&p);
272 static bool init_package(struct pack_desc *p, int count, int subcount)
277 if (!p->format || !p->base) {
281 i = count * getlen(p->format);
283 i += subcount * getlen(p->subformat);
285 p->structbuf = p->base;
289 p->curpos = p->format;
295 * This is the old error code we used. Aparently
296 * WinNT/2k systems return ERRbuftoosmall (2123) and
297 * OS/2 needs this. I'm leaving this here so we can revert
300 p->errcode = ERRmoredata;
302 p->errcode = ERRbuftoosmall;
305 p->errcode = NERR_Success;
309 p->stringbuf = p->base + i;
311 return (p->errcode == NERR_Success);
314 static int package(struct pack_desc *p, ...)
317 int needed=0, stringneeded;
318 const char *str=NULL;
319 int is_string=0, stringused;
326 p->curpos = p->format;
328 p->curpos = p->subformat;
333 str = va_arg(args,char*);
334 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
343 switch( *p->curpos++ ) {
344 case 'W': /* word (2 byte) */
346 temp = va_arg(args,int);
347 if (p->buflen >= needed) {
348 SSVAL(p->structbuf,0,temp);
351 case 'K': /* status word? (2 byte) */
353 temp = va_arg(args,int);
354 if (p->buflen >= needed) {
355 SSVAL(p->structbuf,0,temp);
358 case 'N': /* count of substructures (word) at end */
360 p->subcount = va_arg(args,int);
361 if (p->buflen >= needed) {
362 SSVAL(p->structbuf,0,p->subcount);
365 case 'D': /* double word (4 byte) */
367 temp = va_arg(args,int);
368 if (p->buflen >= needed) {
369 SIVAL(p->structbuf,0,temp);
372 case 'B': /* byte (with optional counter) */
373 needed = get_counter(&p->curpos);
375 char *s = va_arg(args,char*);
376 if (p->buflen >= needed) {
377 StrnCpy(p->structbuf,s?s:"",needed-1);
381 case 'z': /* offset to zero terminated string (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = (str ? strlen(str)+1 : 0);
386 case 'l': /* offset to user data (4 byte) */
387 str = va_arg(args,char*);
388 stringneeded = va_arg(args,int);
391 case 'b': /* offset to data (with counter) (4 byte) */
392 str = va_arg(args,char*);
393 stringneeded = get_counter(&p->curpos);
399 if (stringneeded >= 0) {
401 if (p->buflen >= needed) {
402 stringused = stringneeded;
403 if (stringused > p->stringlen) {
404 stringused = (is_string ? p->stringlen : 0);
405 if (p->errcode == NERR_Success) {
406 p->errcode = ERRmoredata;
410 SIVAL(p->structbuf,0,0);
412 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
413 memcpy(p->stringbuf,str?str:"",stringused);
415 p->stringbuf[stringused-1] = '\0';
417 p->stringbuf += stringused;
418 p->stringlen -= stringused;
419 p->usedlen += stringused;
422 p->neededlen += stringneeded;
425 p->neededlen += needed;
426 if (p->buflen >= needed) {
427 p->structbuf += needed;
429 p->usedlen += needed;
431 if (p->errcode == NERR_Success) {
432 p->errcode = ERRmoredata;
439 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
440 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
442 #define PACK(desc,t,v) package(desc,v)
443 #define PACKl(desc,t,v,l) package(desc,v,l)
446 static void PACKI(struct pack_desc* desc, const char *t,int v)
451 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
456 /****************************************************************************
458 ****************************************************************************/
460 static void PackDriverData(struct pack_desc* desc)
462 char drivdata[4+4+32];
463 SIVAL(drivdata,0,sizeof drivdata); /* cb */
464 SIVAL(drivdata,4,1000); /* lVersion */
465 memset(drivdata+8,0,32); /* szDeviceName */
466 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
467 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
470 static int check_printq_info(struct pack_desc* desc,
471 unsigned int uLevel, char *id1, char *id2)
473 desc->subformat = NULL;
476 desc->format = "B13";
479 desc->format = "B13BWWWzzzzzWW";
482 desc->format = "B13BWWWzzzzzWN";
483 desc->subformat = "WB21BB16B10zWWzDDz";
486 desc->format = "zWWWWzzzzWWzzl";
489 desc->format = "zWWWWzzzzWNzzl";
490 desc->subformat = "WWzWWDDzz";
499 desc->format = "WzzzzzzzzN";
500 desc->subformat = "z";
503 DEBUG(0,("check_printq_info: invalid level %d\n",
507 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
508 DEBUG(0,("check_printq_info: invalid format %s\n",
509 id1 ? id1 : "<NULL>" ));
512 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
513 DEBUG(0,("check_printq_info: invalid subformat %s\n",
514 id2 ? id2 : "<NULL>" ));
521 #define RAP_JOB_STATUS_QUEUED 0
522 #define RAP_JOB_STATUS_PAUSED 1
523 #define RAP_JOB_STATUS_SPOOLING 2
524 #define RAP_JOB_STATUS_PRINTING 3
525 #define RAP_JOB_STATUS_PRINTED 4
527 #define RAP_QUEUE_STATUS_PAUSED 1
528 #define RAP_QUEUE_STATUS_ERROR 2
530 /* turn a print job status into a on the wire status
532 static int printj_status(int v)
536 return RAP_JOB_STATUS_QUEUED;
538 return RAP_JOB_STATUS_PAUSED;
540 return RAP_JOB_STATUS_SPOOLING;
542 return RAP_JOB_STATUS_PRINTING;
547 /* turn a print queue status into a on the wire status
549 static int printq_status(int v)
555 return RAP_QUEUE_STATUS_PAUSED;
557 return RAP_QUEUE_STATUS_ERROR;
560 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
561 struct pack_desc *desc,
562 print_queue_struct *queue, int n)
564 time_t t = queue->time;
566 /* the client expects localtime */
567 t -= get_time_zone(t);
569 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
571 PACKS(desc,"B21",queue->fs_user); /* szUserName */
572 PACKS(desc,"B",""); /* pad */
573 PACKS(desc,"B16",""); /* szNotifyName */
574 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
575 PACKS(desc,"z",""); /* pszParms */
576 PACKI(desc,"W",n+1); /* uPosition */
577 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
578 PACKS(desc,"z",""); /* pszStatus */
579 PACKI(desc,"D",t); /* ulSubmitted */
580 PACKI(desc,"D",queue->size); /* ulSize */
581 PACKS(desc,"z",queue->fs_file); /* pszComment */
583 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
584 PACKI(desc,"W",queue->priority); /* uPriority */
585 PACKS(desc,"z",queue->fs_user); /* pszUserName */
586 PACKI(desc,"W",n+1); /* uPosition */
587 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
588 PACKI(desc,"D",t); /* ulSubmitted */
589 PACKI(desc,"D",queue->size); /* ulSize */
590 PACKS(desc,"z","Samba"); /* pszComment */
591 PACKS(desc,"z",queue->fs_file); /* pszDocument */
593 PACKS(desc,"z",""); /* pszNotifyName */
594 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
595 PACKS(desc,"z",""); /* pszParms */
596 PACKS(desc,"z",""); /* pszStatus */
597 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
598 PACKS(desc,"z","lpd"); /* pszQProcName */
599 PACKS(desc,"z",""); /* pszQProcParms */
600 PACKS(desc,"z","NULL"); /* pszDriverName */
601 PackDriverData(desc); /* pDriverData */
602 PACKS(desc,"z",""); /* pszPrinterName */
603 } else if (uLevel == 4) { /* OS2 */
604 PACKS(desc,"z",""); /* pszSpoolFileName */
605 PACKS(desc,"z",""); /* pszPortName */
606 PACKS(desc,"z",""); /* pszStatus */
607 PACKI(desc,"D",0); /* ulPagesSpooled */
608 PACKI(desc,"D",0); /* ulPagesSent */
609 PACKI(desc,"D",0); /* ulPagesPrinted */
610 PACKI(desc,"D",0); /* ulTimePrinted */
611 PACKI(desc,"D",0); /* ulExtendJobStatus */
612 PACKI(desc,"D",0); /* ulStartPage */
613 PACKI(desc,"D",0); /* ulEndPage */
618 /********************************************************************
619 Return a driver name given an snum.
620 Returns True if from tdb, False otherwise.
621 ********************************************************************/
623 static bool get_driver_name(int snum, char **pp_drivername)
625 NT_PRINTER_INFO_LEVEL *info = NULL;
628 get_a_printer (NULL, &info, 2, lp_servicename(snum));
630 *pp_drivername = talloc_strdup(talloc_tos(),
631 info->info_2->drivername);
633 free_a_printer(&info, 2);
634 if (!*pp_drivername) {
642 /********************************************************************
643 Respond to the DosPrintQInfo command with a level of 52
644 This is used to get printer driver information for Win9x clients
645 ********************************************************************/
646 static void fill_printq_info_52(connection_struct *conn, int snum,
647 struct pack_desc* desc, int count )
651 NT_PRINTER_DRIVER_INFO_LEVEL driver;
652 NT_PRINTER_INFO_LEVEL *printer = NULL;
656 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
657 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
658 lp_servicename(snum)));
662 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
665 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
666 printer->info_2->drivername));
670 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
671 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
672 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
674 PACKI(desc, "W", 0x0400); /* don't know */
675 PACKS(desc, "z", driver.info_3->name); /* long printer name */
676 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
677 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
678 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
680 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
681 standard_sub_basic( "", "", location, sizeof(location)-1 );
682 PACKS(desc,"z", location); /* share to retrieve files */
684 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
685 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
686 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
688 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
689 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
690 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
691 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
692 DEBUG(3,("Driver Location: %s:\n",location));
693 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
694 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
695 PACKI(desc,"N",count); /* number of files to copy */
697 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
699 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
700 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
701 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
706 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
709 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
711 desc->errcode=NERR_Success;
715 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
716 desc->errcode=NERR_notsupported;
720 free_a_printer( &printer, 2 );
723 free_a_printer_driver( driver, 3 );
727 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
728 struct pack_desc* desc,
729 int count, print_queue_struct* queue,
730 print_status_struct* status)
735 PACKS(desc,"B13",SERVICE(snum));
740 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
743 PACKI(desc,"K",printq_status(status->status));
747 if (uLevel == 1 || uLevel == 2) {
748 PACKS(desc,"B",""); /* alignment */
749 PACKI(desc,"W",5); /* priority */
750 PACKI(desc,"W",0); /* start time */
751 PACKI(desc,"W",0); /* until time */
752 PACKS(desc,"z",""); /* pSepFile */
753 PACKS(desc,"z","lpd"); /* pPrProc */
754 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
755 PACKS(desc,"z",""); /* pParms */
757 PACKS(desc,"z","UNKNOWN PRINTER");
758 PACKI(desc,"W",LPSTAT_ERROR);
760 else if (!status || !status->message[0]) {
761 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
762 PACKI(desc,"W",LPSTAT_OK); /* status */
764 PACKS(desc,"z",status->message);
765 PACKI(desc,"W",printq_status(status->status)); /* status */
767 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
770 if (uLevel == 3 || uLevel == 4) {
771 char *drivername = NULL;
773 PACKI(desc,"W",5); /* uPriority */
774 PACKI(desc,"W",0); /* uStarttime */
775 PACKI(desc,"W",0); /* uUntiltime */
776 PACKI(desc,"W",5); /* pad1 */
777 PACKS(desc,"z",""); /* pszSepFile */
778 PACKS(desc,"z","WinPrint"); /* pszPrProc */
779 PACKS(desc,"z",NULL); /* pszParms */
780 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
781 /* "don't ask" that it's done this way to fix corrupted
782 Win9X/ME printer comments. */
784 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
786 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
788 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
789 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
790 get_driver_name(snum,&drivername);
794 PACKS(desc,"z",drivername); /* pszDriverName */
795 PackDriverData(desc); /* pDriverData */
798 if (uLevel == 2 || uLevel == 4) {
800 for (i=0;i<count;i++)
801 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
805 fill_printq_info_52( conn, snum, desc, count );
808 /* This function returns the number of files for a given driver */
809 static int get_printerdrivernumber(int snum)
812 NT_PRINTER_DRIVER_INFO_LEVEL driver;
813 NT_PRINTER_INFO_LEVEL *printer = NULL;
817 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
818 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
819 lp_servicename(snum)));
823 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
826 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
827 printer->info_2->drivername));
831 /* count the number of files */
832 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
837 free_a_printer( &printer, 2 );
840 free_a_printer_driver( driver, 3 );
845 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
846 char *param, int tpscnt,
847 char *data, int tdscnt,
848 int mdrcnt,int mprcnt,
849 char **rdata,char **rparam,
850 int *rdata_len,int *rparam_len)
852 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
853 char *str2 = skip_string(param,tpscnt,str1);
854 char *p = skip_string(param,tpscnt,str2);
860 struct pack_desc desc;
861 print_queue_struct *queue=NULL;
862 print_status_struct status;
865 if (!str1 || !str2 || !p) {
868 memset((char *)&status,'\0',sizeof(status));
869 memset((char *)&desc,'\0',sizeof(desc));
871 p = skip_string(param,tpscnt,p);
875 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
876 str3 = get_safe_str_ptr(param,tpscnt,p,4);
877 /* str3 may be null here and is checked in check_printq_info(). */
879 /* remove any trailing username */
880 if ((p = strchr_m(QueueName,'%')))
883 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
885 /* check it's a supported varient */
886 if (!prefix_ok(str1,"zWrLh"))
888 if (!check_printq_info(&desc,uLevel,str2,str3)) {
890 * Patch from Scott Moomaw <scott@bridgewater.edu>
891 * to return the 'invalid info level' error if an
892 * unknown level was requested.
896 *rparam = smb_realloc_limit(*rparam,*rparam_len);
900 SSVALS(*rparam,0,ERRunknownlevel);
906 snum = find_service(QueueName);
907 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
911 count = get_printerdrivernumber(snum);
912 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
914 count = print_queue_status(snum, &queue,&status);
918 *rdata = smb_realloc_limit(*rdata,mdrcnt);
924 desc.buflen = mdrcnt;
927 * Don't return data but need to get correct length
928 * init_package will return wrong size if buflen=0
930 desc.buflen = getlen(desc.format);
931 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
934 if (init_package(&desc,1,count)) {
935 desc.subcount = count;
936 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
939 *rdata_len = desc.usedlen;
942 * We must set the return code to ERRbuftoosmall
943 * in order to support lanman style printing with Win NT/2k
946 if (!mdrcnt && lp_disable_spoolss())
947 desc.errcode = ERRbuftoosmall;
949 *rdata_len = desc.usedlen;
951 *rparam = smb_realloc_limit(*rparam,*rparam_len);
957 SSVALS(*rparam,0,desc.errcode);
959 SSVAL(*rparam,4,desc.neededlen);
961 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
969 /****************************************************************************
970 View list of all print jobs on all queues.
971 ****************************************************************************/
973 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
974 char *param, int tpscnt,
975 char *data, int tdscnt,
976 int mdrcnt, int mprcnt,
977 char **rdata, char** rparam,
978 int *rdata_len, int *rparam_len)
980 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
981 char *output_format1 = skip_string(param,tpscnt,param_format);
982 char *p = skip_string(param,tpscnt,output_format1);
983 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
984 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
985 int services = lp_numservices();
987 struct pack_desc desc;
988 print_queue_struct **queue = NULL;
989 print_status_struct *status = NULL;
990 int *subcntarr = NULL;
991 int queuecnt = 0, subcnt = 0, succnt = 0;
993 if (!param_format || !output_format1 || !p) {
997 memset((char *)&desc,'\0',sizeof(desc));
999 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1001 if (!prefix_ok(param_format,"WrLeh")) {
1004 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1006 * Patch from Scott Moomaw <scott@bridgewater.edu>
1007 * to return the 'invalid info level' error if an
1008 * unknown level was requested.
1012 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1016 SSVALS(*rparam,0,ERRunknownlevel);
1022 for (i = 0; i < services; i++) {
1023 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1028 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1029 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1032 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1033 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1034 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1037 memset(status,0,queuecnt*sizeof(print_status_struct));
1038 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1039 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1045 for (i = 0; i < services; i++) {
1046 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1047 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1048 subcnt += subcntarr[n];
1054 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1060 desc.buflen = mdrcnt;
1062 if (init_package(&desc,queuecnt,subcnt)) {
1065 for (i = 0; i < services; i++) {
1066 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1067 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1069 if (desc.errcode == NERR_Success) {
1076 SAFE_FREE(subcntarr);
1078 *rdata_len = desc.usedlen;
1080 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1084 SSVALS(*rparam,0,desc.errcode);
1086 SSVAL(*rparam,4,succnt);
1087 SSVAL(*rparam,6,queuecnt);
1089 for (i = 0; i < queuecnt; i++) {
1091 SAFE_FREE(queue[i]);
1102 SAFE_FREE(subcntarr);
1103 for (i = 0; i < queuecnt; i++) {
1105 SAFE_FREE(queue[i]);
1114 /****************************************************************************
1115 Get info level for a server list query.
1116 ****************************************************************************/
1118 static bool check_server_info(int uLevel, char* id)
1122 if (strcmp(id,"B16") != 0) {
1127 if (strcmp(id,"B16BBDz") != 0) {
1137 struct srv_info_struct {
1145 /*******************************************************************
1146 Get server info lists from the files saved by nmbd. Return the
1148 ******************************************************************/
1150 static int get_server_info(uint32 servertype,
1151 struct srv_info_struct **servers,
1157 bool local_list_only;
1160 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1162 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1166 /* request for everything is code for request all servers */
1167 if (servertype == SV_TYPE_ALL) {
1168 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1171 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1173 DEBUG(4,("Servertype search: %8x\n",servertype));
1175 for (i=0;lines[i];i++) {
1177 struct srv_info_struct *s;
1178 const char *ptr = lines[i];
1185 if (count == alloced) {
1187 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1189 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1190 file_lines_free(lines);
1193 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1195 s = &(*servers)[count];
1197 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1200 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1203 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1206 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1207 /* this allows us to cope with an old nmbd */
1208 fstrcpy(s->domain,lp_workgroup());
1211 if (sscanf(stype,"%X",&s->type) != 1) {
1212 DEBUG(4,("r:host file "));
1216 /* Filter the servers/domains we return based on what was asked for. */
1218 /* Check to see if we are being asked for a local list only. */
1219 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1220 DEBUG(4,("r: local list only"));
1224 /* doesn't match up: don't want it */
1225 if (!(servertype & s->type)) {
1226 DEBUG(4,("r:serv type "));
1230 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1231 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1232 DEBUG(4,("s: dom mismatch "));
1236 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1240 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1241 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1244 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1245 s->name, s->type, s->comment, s->domain));
1246 s->server_added = True;
1249 DEBUG(4,("%20s %8x %25s %15s\n",
1250 s->name, s->type, s->comment, s->domain));
1254 file_lines_free(lines);
1258 /*******************************************************************
1259 Fill in a server info structure.
1260 ******************************************************************/
1262 static int fill_srv_info(struct srv_info_struct *service,
1263 int uLevel, char **buf, int *buflen,
1264 char **stringbuf, int *stringspace, char *baseaddr)
1287 len = strlen(service->comment)+1;
1291 *buflen = struct_len;
1293 return struct_len + len;
1298 if (*buflen < struct_len) {
1305 p2 = p + struct_len;
1306 l2 = *buflen - struct_len;
1314 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1318 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1319 SIVAL(p,18,service->type);
1320 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1321 len += CopyAndAdvance(&p2,service->comment,&l2);
1326 *buf = p + struct_len;
1327 *buflen -= struct_len;
1338 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1340 return(strcmp(s1->name,s2->name));
1343 /****************************************************************************
1344 View list of servers available (or possibly domains). The info is
1345 extracted from lists saved by nmbd on the local host.
1346 ****************************************************************************/
1348 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1349 char *param, int tpscnt,
1350 char *data, int tdscnt,
1351 int mdrcnt, int mprcnt, char **rdata,
1352 char **rparam, int *rdata_len, int *rparam_len)
1354 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1355 char *str2 = skip_string(param,tpscnt,str1);
1356 char *p = skip_string(param,tpscnt,str2);
1357 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1358 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1359 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1361 int data_len, fixed_len, string_len;
1362 int f_len = 0, s_len = 0;
1363 struct srv_info_struct *servers=NULL;
1364 int counted=0,total=0;
1367 bool domain_request;
1370 if (!str1 || !str2 || !p) {
1374 /* If someone sets all the bits they don't really mean to set
1375 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1378 if (servertype == SV_TYPE_ALL) {
1379 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1382 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1383 any other bit (they may just set this bit on its own) they
1384 want all the locally seen servers. However this bit can be
1385 set on its own so set the requested servers to be
1386 ALL - DOMAIN_ENUM. */
1388 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1389 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1392 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1393 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1397 if (!prefix_ok(str1,"WrLehD")) {
1400 if (!check_server_info(uLevel,str2)) {
1404 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1405 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1406 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1408 if (strcmp(str1, "WrLehDz") == 0) {
1409 if (skip_string(param,tpscnt,p) == NULL) {
1412 pull_ascii_fstring(domain, p);
1414 fstrcpy(domain, lp_workgroup());
1417 if (lp_browse_list()) {
1418 total = get_server_info(servertype,&servers,domain);
1421 data_len = fixed_len = string_len = 0;
1425 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1429 char *lastname=NULL;
1431 for (i=0;i<total;i++) {
1432 struct srv_info_struct *s = &servers[i];
1434 if (lastname && strequal(lastname,s->name)) {
1438 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1439 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1440 s->name, s->type, s->comment, s->domain));
1442 if (data_len <= buf_len) {
1445 string_len += s_len;
1452 *rdata_len = fixed_len + string_len;
1453 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1458 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1464 char *lastname=NULL;
1465 int count2 = counted;
1467 for (i = 0; i < total && count2;i++) {
1468 struct srv_info_struct *s = &servers[i];
1470 if (lastname && strequal(lastname,s->name)) {
1474 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1475 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1476 s->name, s->type, s->comment, s->domain));
1482 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1486 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1488 SSVAL(*rparam,4,counted);
1489 SSVAL(*rparam,6,counted+missed);
1493 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1494 domain,uLevel,counted,counted+missed));
1499 /****************************************************************************
1500 command 0x34 - suspected of being a "Lookup Names" stub api
1501 ****************************************************************************/
1503 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1504 char *param, int tpscnt,
1505 char *data, int tdscnt,
1506 int mdrcnt, int mprcnt, char **rdata,
1507 char **rparam, int *rdata_len, int *rparam_len)
1509 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1510 char *str2 = skip_string(param,tpscnt,str1);
1511 char *p = skip_string(param,tpscnt,str2);
1512 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1513 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1517 if (!str1 || !str2 || !p) {
1521 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1522 str1, str2, p, uLevel, buf_len));
1524 if (!prefix_ok(str1,"zWrLeh")) {
1531 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1536 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1538 SSVAL(*rparam,4,counted);
1539 SSVAL(*rparam,6,counted+missed);
1544 /****************************************************************************
1545 get info about a share
1546 ****************************************************************************/
1548 static bool check_share_info(int uLevel, char* id)
1552 if (strcmp(id,"B13") != 0) {
1557 if (strcmp(id,"B13BWz") != 0) {
1562 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1567 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1577 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1578 char** buf, int* buflen,
1579 char** stringbuf, int* stringspace, char* baseaddr)
1609 len += StrlenExpanded(conn,snum,lp_comment(snum));
1612 len += strlen(lp_pathname(snum)) + 1;
1615 *buflen = struct_len;
1620 return struct_len + len;
1625 if ((*buflen) < struct_len) {
1633 p2 = p + struct_len;
1634 l2 = (*buflen) - struct_len;
1641 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1647 type = STYPE_DISKTREE;
1648 if (lp_print_ok(snum)) {
1649 type = STYPE_PRINTQ;
1651 if (strequal("IPC",lp_fstype(snum))) {
1654 SSVAL(p,14,type); /* device type */
1655 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1656 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1660 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1661 SSVALS(p,22,-1); /* max uses */
1662 SSVAL(p,24,1); /* current uses */
1663 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1664 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1665 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1669 memset(p+40,0,SHPWLEN+2);
1680 (*buf) = p + struct_len;
1681 (*buflen) -= struct_len;
1683 (*stringspace) = l2;
1692 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1693 char *param, int tpscnt,
1694 char *data, int tdscnt,
1695 int mdrcnt,int mprcnt,
1696 char **rdata,char **rparam,
1697 int *rdata_len,int *rparam_len)
1699 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1700 char *str2 = skip_string(param,tpscnt,str1);
1701 char *netname = skip_string(param,tpscnt,str2);
1702 char *p = skip_string(param,tpscnt,netname);
1703 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1706 if (!str1 || !str2 || !netname || !p) {
1710 snum = find_service(netname);
1715 /* check it's a supported varient */
1716 if (!prefix_ok(str1,"zWrLh")) {
1719 if (!check_share_info(uLevel,str2)) {
1723 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1728 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1729 if (*rdata_len < 0) {
1734 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1738 SSVAL(*rparam,0,NERR_Success);
1739 SSVAL(*rparam,2,0); /* converter word */
1740 SSVAL(*rparam,4,*rdata_len);
1745 /****************************************************************************
1746 View the list of available shares.
1748 This function is the server side of the NetShareEnum() RAP call.
1749 It fills the return buffer with share names and share comments.
1750 Note that the return buffer normally (in all known cases) allows only
1751 twelve byte strings for share names (plus one for a nul terminator).
1752 Share names longer than 12 bytes must be skipped.
1753 ****************************************************************************/
1755 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1756 char *param, int tpscnt,
1757 char *data, int tdscnt,
1765 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1766 char *str2 = skip_string(param,tpscnt,str1);
1767 char *p = skip_string(param,tpscnt,str2);
1768 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1769 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1772 int total=0,counted=0;
1773 bool missed = False;
1775 int data_len, fixed_len, string_len;
1776 int f_len = 0, s_len = 0;
1778 if (!str1 || !str2 || !p) {
1782 if (!prefix_ok(str1,"WrLeh")) {
1785 if (!check_share_info(uLevel,str2)) {
1789 /* Ensure all the usershares are loaded. */
1791 load_registry_shares();
1792 count = load_usershare_shares();
1795 data_len = fixed_len = string_len = 0;
1796 for (i=0;i<count;i++) {
1797 fstring servicename_dos;
1798 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1801 push_ascii_fstring(servicename_dos, lp_servicename(i));
1802 /* Maximum name length = 13. */
1803 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1805 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1806 if (data_len <= buf_len) {
1809 string_len += s_len;
1816 *rdata_len = fixed_len + string_len;
1817 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1822 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1827 for( i = 0; i < count; i++ ) {
1828 fstring servicename_dos;
1829 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1833 push_ascii_fstring(servicename_dos, lp_servicename(i));
1834 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1835 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1842 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1846 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1848 SSVAL(*rparam,4,counted);
1849 SSVAL(*rparam,6,total);
1851 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1852 counted,total,uLevel,
1853 buf_len,*rdata_len,mdrcnt));
1858 /****************************************************************************
1860 ****************************************************************************/
1862 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1863 char *param, int tpscnt,
1864 char *data, int tdscnt,
1865 int mdrcnt,int mprcnt,
1866 char **rdata,char **rparam,
1867 int *rdata_len,int *rparam_len)
1869 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1870 char *str2 = skip_string(param,tpscnt,str1);
1871 char *p = skip_string(param,tpscnt,str2);
1872 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1875 char *pathname = NULL;
1876 char *command, *cmdname;
1877 unsigned int offset;
1881 if (!str1 || !str2 || !p) {
1885 /* check it's a supported varient */
1886 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1889 if (!check_share_info(uLevel,str2)) {
1896 /* Do we have a string ? */
1897 if (skip_string(data,mdrcnt,data) == NULL) {
1900 pull_ascii_fstring(sharename,data);
1901 snum = find_service(sharename);
1902 if (snum >= 0) { /* already exists */
1911 /* only support disk share adds */
1912 if (SVAL(data,14)!=STYPE_DISKTREE) {
1916 offset = IVAL(data, 16);
1917 if (offset >= mdrcnt) {
1918 res = ERRinvalidparam;
1922 /* Do we have a string ? */
1923 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1926 pull_ascii_fstring(comment, offset? (data+offset) : "");
1928 offset = IVAL(data, 26);
1930 if (offset >= mdrcnt) {
1931 res = ERRinvalidparam;
1935 /* Do we have a string ? */
1936 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1940 pull_ascii_talloc(talloc_tos(), &pathname, offset? (data+offset) : "");
1945 string_replace(sharename, '"', ' ');
1946 string_replace(pathname, '"', ' ');
1947 string_replace(comment, '"', ' ');
1949 cmdname = lp_add_share_cmd();
1951 if (!cmdname || *cmdname == '\0') {
1955 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1956 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1959 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1961 if ((res = smbrun(command, NULL)) != 0) {
1962 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1968 message_send_all(smbd_messaging_context(),
1969 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1976 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1980 SSVAL(*rparam,0,NERR_Success);
1981 SSVAL(*rparam,2,0); /* converter word */
1982 SSVAL(*rparam,4,*rdata_len);
1990 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1995 SSVAL(*rparam,0,res);
2000 /****************************************************************************
2001 view list of groups available
2002 ****************************************************************************/
2004 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2005 char *param, int tpscnt,
2006 char *data, int tdscnt,
2007 int mdrcnt,int mprcnt,
2008 char **rdata,char **rparam,
2009 int *rdata_len,int *rparam_len)
2013 int resume_context, cli_buf_size;
2014 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2015 char *str2 = skip_string(param,tpscnt,str1);
2016 char *p = skip_string(param,tpscnt,str2);
2018 struct pdb_search *search;
2019 struct samr_displayentry *entries;
2023 if (!str1 || !str2 || !p) {
2027 if (strcmp(str1,"WrLeh") != 0) {
2032 * W-> resume context (number of users to skip)
2033 * r -> return parameter pointer to receive buffer
2034 * L -> length of receive buffer
2035 * e -> return parameter number of entries
2036 * h -> return parameter total number of users
2039 if (strcmp("B21",str2) != 0) {
2043 /* get list of domain groups SID_DOMAIN_GRP=2 */
2045 search = pdb_search_groups();
2048 if (search == NULL) {
2049 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2053 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2054 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2055 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2056 "%d\n", resume_context, cli_buf_size));
2059 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2063 *rdata_len = cli_buf_size;
2064 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2071 for(i=0; i<num_entries; i++) {
2073 fstrcpy(name, entries[i].account_name);
2074 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2075 /* truncate the name at 21 chars. */
2076 memcpy(p, name, 21);
2077 DEBUG(10,("adding entry %d group %s\n", i, p));
2079 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2082 /* set overflow error */
2083 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2089 pdb_search_destroy(search);
2091 *rdata_len = PTR_DIFF(p,*rdata);
2094 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2098 SSVAL(*rparam, 0, errflags);
2099 SSVAL(*rparam, 2, 0); /* converter word */
2100 SSVAL(*rparam, 4, i); /* is this right?? */
2101 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2106 /*******************************************************************
2107 Get groups that a user is a member of.
2108 ******************************************************************/
2110 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2111 char *param, int tpscnt,
2112 char *data, int tdscnt,
2113 int mdrcnt,int mprcnt,
2114 char **rdata,char **rparam,
2115 int *rdata_len,int *rparam_len)
2117 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2118 char *str2 = skip_string(param,tpscnt,str1);
2119 char *UserName = skip_string(param,tpscnt,str2);
2120 char *p = skip_string(param,tpscnt,UserName);
2121 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2122 const char *level_string;
2124 struct samu *sampw = NULL;
2132 enum lsa_SidType type;
2134 TALLOC_CTX *mem_ctx;
2136 if (!str1 || !str2 || !UserName || !p) {
2141 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2146 /* check it's a supported varient */
2148 if ( strcmp(str1,"zWrLeh") != 0 )
2153 level_string = "B21";
2159 if (strcmp(level_string,str2) != 0)
2162 *rdata_len = mdrcnt + 1024;
2163 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2168 SSVAL(*rparam,0,NERR_Success);
2169 SSVAL(*rparam,2,0); /* converter word */
2172 endp = *rdata + *rdata_len;
2174 mem_ctx = talloc_new(NULL);
2175 if (mem_ctx == NULL) {
2176 DEBUG(0, ("talloc_new failed\n"));
2180 if ( !(sampw = samu_new(mem_ctx)) ) {
2181 DEBUG(0, ("samu_new() failed!\n"));
2182 TALLOC_FREE(mem_ctx);
2186 /* Lookup the user information; This should only be one of
2187 our accounts (not remote domains) */
2189 become_root(); /* ROOT BLOCK */
2191 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2192 NULL, NULL, &user_sid, &type)) {
2193 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2197 if (type != SID_NAME_USER) {
2198 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2199 sid_type_lookup(type)));
2203 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2204 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2205 sid_string_static(&user_sid), UserName));
2213 result = pdb_enum_group_memberships(mem_ctx, sampw,
2214 &sids, &gids, &num_groups);
2216 if (!NT_STATUS_IS_OK(result)) {
2217 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2222 for (i=0; i<num_groups; i++) {
2223 const char *grp_name;
2225 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2226 strlcpy(p, grp_name, PTR_DIFF(endp,p));
2232 *rdata_len = PTR_DIFF(p,*rdata);
2234 SSVAL(*rparam,4,count); /* is this right?? */
2235 SSVAL(*rparam,6,count); /* is this right?? */
2240 unbecome_root(); /* END ROOT BLOCK */
2242 TALLOC_FREE(mem_ctx);
2247 /*******************************************************************
2249 ******************************************************************/
2251 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2252 char *param, int tpscnt,
2253 char *data, int tdscnt,
2254 int mdrcnt,int mprcnt,
2255 char **rdata,char **rparam,
2256 int *rdata_len,int *rparam_len)
2261 int i, resume_context, cli_buf_size;
2262 struct pdb_search *search;
2263 struct samr_displayentry *users;
2265 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2266 char *str2 = skip_string(param,tpscnt,str1);
2267 char *p = skip_string(param,tpscnt,str2);
2270 if (!str1 || !str2 || !p) {
2274 if (strcmp(str1,"WrLeh") != 0)
2277 * W-> resume context (number of users to skip)
2278 * r -> return parameter pointer to receive buffer
2279 * L -> length of receive buffer
2280 * e -> return parameter number of entries
2281 * h -> return parameter total number of users
2284 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2285 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2286 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2287 resume_context, cli_buf_size));
2290 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2295 /* check it's a supported varient */
2296 if (strcmp("B21",str2) != 0)
2299 *rdata_len = cli_buf_size;
2300 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2306 endp = *rdata + *rdata_len;
2309 search = pdb_search_users(ACB_NORMAL);
2311 if (search == NULL) {
2312 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2317 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2321 errflags=NERR_Success;
2323 for (i=0; i<num_users; i++) {
2324 const char *name = users[i].account_name;
2326 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2327 strlcpy(p,name,PTR_DIFF(endp,p));
2328 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2329 "%s\n",count_sent,p));
2333 /* set overflow error */
2334 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2335 "username %s\n",count_sent,name));
2341 pdb_search_destroy(search);
2343 *rdata_len = PTR_DIFF(p,*rdata);
2345 SSVAL(*rparam,0,errflags);
2346 SSVAL(*rparam,2,0); /* converter word */
2347 SSVAL(*rparam,4,count_sent); /* is this right?? */
2348 SSVAL(*rparam,6,num_users); /* is this right?? */
2353 /****************************************************************************
2354 Get the time of day info.
2355 ****************************************************************************/
2357 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2358 char *param, int tpscnt,
2359 char *data, int tdscnt,
2360 int mdrcnt,int mprcnt,
2361 char **rdata,char **rparam,
2362 int *rdata_len,int *rparam_len)
2365 time_t unixdate = time(NULL);
2369 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2375 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2380 SSVAL(*rparam,0,NERR_Success);
2381 SSVAL(*rparam,2,0); /* converter word */
2385 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2386 by NT in a "net time" operation,
2387 it seems to ignore the one below */
2389 /* the client expects to get localtime, not GMT, in this bit
2390 (I think, this needs testing) */
2391 t = localtime(&unixdate);
2396 SIVAL(p,4,0); /* msecs ? */
2397 SCVAL(p,8,t->tm_hour);
2398 SCVAL(p,9,t->tm_min);
2399 SCVAL(p,10,t->tm_sec);
2400 SCVAL(p,11,0); /* hundredths of seconds */
2401 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2402 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2403 SCVAL(p,16,t->tm_mday);
2404 SCVAL(p,17,t->tm_mon + 1);
2405 SSVAL(p,18,1900+t->tm_year);
2406 SCVAL(p,20,t->tm_wday);
2411 /****************************************************************************
2412 Set the user password.
2413 *****************************************************************************/
2415 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2416 char *param, int tpscnt,
2417 char *data, int tdscnt,
2418 int mdrcnt,int mprcnt,
2419 char **rdata,char **rparam,
2420 int *rdata_len,int *rparam_len)
2422 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2425 fstring pass1,pass2;
2427 /* Skip 2 strings. */
2428 p = skip_string(param,tpscnt,np);
2429 p = skip_string(param,tpscnt,p);
2435 /* Do we have a string ? */
2436 if (skip_string(param,tpscnt,p) == NULL) {
2439 pull_ascii_fstring(user,p);
2441 p = skip_string(param,tpscnt,p);
2446 memset(pass1,'\0',sizeof(pass1));
2447 memset(pass2,'\0',sizeof(pass2));
2449 * We use 31 here not 32 as we're checking
2450 * the last byte we want to access is safe.
2452 if (!is_offset_safe(param,tpscnt,p,31)) {
2456 memcpy(pass2,p+16,16);
2459 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2466 SSVAL(*rparam,0,NERR_badpass);
2467 SSVAL(*rparam,2,0); /* converter word */
2469 DEBUG(3,("Set password for <%s>\n",user));
2472 * Attempt to verify the old password against smbpasswd entries
2473 * Win98 clients send old and new password in plaintext for this call.
2477 auth_serversupplied_info *server_info = NULL;
2478 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2480 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2483 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2484 SSVAL(*rparam,0,NERR_Success);
2488 TALLOC_FREE(server_info);
2490 data_blob_clear_free(&password);
2494 * If the plaintext change failed, attempt
2495 * the old encrypted method. NT will generate this
2496 * after trying the samr method. Note that this
2497 * method is done as a last resort as this
2498 * password change method loses the NT password hash
2499 * and cannot change the UNIX password as no plaintext
2503 if(SVAL(*rparam,0) != NERR_Success) {
2504 struct samu *hnd = NULL;
2506 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2508 if (change_lanman_password(hnd,(uchar *)pass2)) {
2509 SSVAL(*rparam,0,NERR_Success);
2516 memset((char *)pass1,'\0',sizeof(fstring));
2517 memset((char *)pass2,'\0',sizeof(fstring));
2522 /****************************************************************************
2523 Set the user password (SamOEM version - gets plaintext).
2524 ****************************************************************************/
2526 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2527 char *param, int tpscnt,
2528 char *data, int tdscnt,
2529 int mdrcnt,int mprcnt,
2530 char **rdata,char **rparam,
2531 int *rdata_len,int *rparam_len)
2534 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2536 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2546 SSVAL(*rparam,0,NERR_badpass);
2549 * Check the parameter definition is correct.
2552 /* Do we have a string ? */
2553 if (skip_string(param,tpscnt,p) == 0) {
2556 if(!strequal(p, "zsT")) {
2557 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2560 p = skip_string(param, tpscnt, p);
2565 /* Do we have a string ? */
2566 if (skip_string(param,tpscnt,p) == 0) {
2569 if(!strequal(p, "B516B16")) {
2570 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2573 p = skip_string(param,tpscnt,p);
2577 /* Do we have a string ? */
2578 if (skip_string(param,tpscnt,p) == 0) {
2581 p += pull_ascii_fstring(user,p);
2583 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2586 * Pass the user through the NT -> unix user mapping
2590 (void)map_username(user);
2592 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2593 SSVAL(*rparam,0,NERR_Success);
2599 /****************************************************************************
2602 ****************************************************************************/
2604 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2605 char *param, int tpscnt,
2606 char *data, int tdscnt,
2607 int mdrcnt,int mprcnt,
2608 char **rdata,char **rparam,
2609 int *rdata_len,int *rparam_len)
2611 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2612 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2613 char *str2 = skip_string(param,tpscnt,str1);
2614 char *p = skip_string(param,tpscnt,str2);
2619 WERROR werr = WERR_OK;
2621 if (!str1 || !str2 || !p) {
2625 * We use 1 here not 2 as we're checking
2626 * the last byte we want to access is safe.
2628 if (!is_offset_safe(param,tpscnt,p,1)) {
2631 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2634 /* check it's a supported varient */
2635 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2639 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2645 if (!print_job_exists(sharename, jobid)) {
2646 errcode = NERR_JobNotFound;
2650 snum = lp_servicenumber( sharename);
2652 errcode = NERR_DestNotFound;
2656 errcode = NERR_notsupported;
2659 case 81: /* delete */
2660 if (print_job_delete(¤t_user, snum, jobid, &werr))
2661 errcode = NERR_Success;
2663 case 82: /* pause */
2664 if (print_job_pause(¤t_user, snum, jobid, &werr))
2665 errcode = NERR_Success;
2667 case 83: /* resume */
2668 if (print_job_resume(¤t_user, snum, jobid, &werr))
2669 errcode = NERR_Success;
2673 if (!W_ERROR_IS_OK(werr))
2674 errcode = W_ERROR_V(werr);
2677 SSVAL(*rparam,0,errcode);
2678 SSVAL(*rparam,2,0); /* converter word */
2683 /****************************************************************************
2684 Purge a print queue - or pause or resume it.
2685 ****************************************************************************/
2687 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2688 char *param, int tpscnt,
2689 char *data, int tdscnt,
2690 int mdrcnt,int mprcnt,
2691 char **rdata,char **rparam,
2692 int *rdata_len,int *rparam_len)
2694 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2695 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2696 char *str2 = skip_string(param,tpscnt,str1);
2697 char *QueueName = skip_string(param,tpscnt,str2);
2698 int errcode = NERR_notsupported;
2700 WERROR werr = WERR_OK;
2702 if (!str1 || !str2 || !QueueName) {
2706 /* check it's a supported varient */
2707 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2711 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2717 if (skip_string(param,tpscnt,QueueName) == NULL) {
2720 snum = print_queue_snum(QueueName);
2723 errcode = NERR_JobNotFound;
2728 case 74: /* Pause queue */
2729 if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success;
2731 case 75: /* Resume queue */
2732 if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success;
2734 case 103: /* Purge */
2735 if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success;
2739 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2742 SSVAL(*rparam,0,errcode);
2743 SSVAL(*rparam,2,0); /* converter word */
2748 /****************************************************************************
2749 set the property of a print job (undocumented?)
2750 ? function = 0xb -> set name of print job
2751 ? function = 0x6 -> move print job up/down
2752 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2753 or <WWsTP> <WB21BB16B10zWWzDDz>
2754 ****************************************************************************/
2756 static int check_printjob_info(struct pack_desc* desc,
2757 int uLevel, char* id)
2759 desc->subformat = NULL;
2761 case 0: desc->format = "W"; break;
2762 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2763 case 2: desc->format = "WWzWWDDzz"; break;
2764 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2765 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2767 DEBUG(0,("check_printjob_info: invalid level %d\n",
2771 if (id == NULL || strcmp(desc->format,id) != 0) {
2772 DEBUG(0,("check_printjob_info: invalid format %s\n",
2773 id ? id : "<NULL>" ));
2779 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2780 char *param, int tpscnt,
2781 char *data, int tdscnt,
2782 int mdrcnt,int mprcnt,
2783 char **rdata,char **rparam,
2784 int *rdata_len,int *rparam_len)
2786 struct pack_desc desc;
2787 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2788 char *str2 = skip_string(param,tpscnt,str1);
2789 char *p = skip_string(param,tpscnt,str2);
2792 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2793 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2796 if (!str1 || !str2 || !p) {
2800 * We use 1 here not 2 as we're checking
2801 * the last byte we want to access is safe.
2803 if (!is_offset_safe(param,tpscnt,p,1)) {
2806 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2809 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2814 if (!share_defined(sharename)) {
2815 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2822 /* check it's a supported varient */
2823 if ((strcmp(str1,"WWsTP")) ||
2824 (!check_printjob_info(&desc,uLevel,str2)))
2827 if (!print_job_exists(sharename, jobid)) {
2828 errcode=NERR_JobNotFound;
2832 errcode = NERR_notsupported;
2836 /* change job place in the queue,
2837 data gives the new place */
2838 place = SVAL(data,0);
2839 if (print_job_set_place(sharename, jobid, place)) {
2840 errcode=NERR_Success;
2845 /* change print job name, data gives the name */
2846 if (print_job_set_name(sharename, jobid, data)) {
2847 errcode=NERR_Success;
2856 SSVALS(*rparam,0,errcode);
2857 SSVAL(*rparam,2,0); /* converter word */
2863 /****************************************************************************
2864 Get info about the server.
2865 ****************************************************************************/
2867 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2868 char *param, int tpscnt,
2869 char *data, int tdscnt,
2870 int mdrcnt,int mprcnt,
2871 char **rdata,char **rparam,
2872 int *rdata_len,int *rparam_len)
2874 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2875 char *str2 = skip_string(param,tpscnt,str1);
2876 char *p = skip_string(param,tpscnt,str2);
2877 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2881 if (!str1 || !str2 || !p) {
2885 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2887 /* check it's a supported varient */
2888 if (!prefix_ok(str1,"WrLh")) {
2894 if (strcmp(str2,"B16") != 0) {
2900 if (strcmp(str2,"B16BBDz") != 0) {
2906 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2912 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2918 if (strcmp(str2,"DN") != 0) {
2924 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2933 *rdata_len = mdrcnt;
2934 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2940 p2 = p + struct_len;
2942 srvstr_push(NULL, 0, p,global_myname(),16,
2943 STR_ASCII|STR_UPPER|STR_TERMINATE);
2947 struct srv_info_struct *servers=NULL;
2949 char *comment = NULL;
2950 TALLOC_CTX *ctx = talloc_tos();
2951 uint32 servertype= lp_default_server_announce();
2953 comment = talloc_strdup(ctx,lp_serverstring());
2958 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2959 for (i=0;i<count;i++) {
2960 if (strequal(servers[i].name,global_myname())) {
2961 servertype = servers[i].type;
2962 TALLOC_FREE(comment);
2963 comment = talloc_strdup(ctx,
2964 servers[i].comment);
2974 SCVAL(p,0,lp_major_announce_version());
2975 SCVAL(p,1,lp_minor_announce_version());
2976 SIVAL(p,2,servertype);
2978 if (mdrcnt == struct_len) {
2981 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2982 comment = talloc_sub_advanced(ctx,
2983 lp_servicename(SNUM(conn)),
2987 get_current_username(),
2988 current_user_info.domain,
2993 if (mdrcnt - struct_len <= 0) {
2998 MIN(mdrcnt - struct_len,
2999 MAX_SERVER_STRING_LENGTH),
3001 p2 = skip_string(*rdata,*rdata_len,p2);
3009 return False; /* not yet implemented */
3012 *rdata_len = PTR_DIFF(p2,*rdata);
3015 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3019 SSVAL(*rparam,0,NERR_Success);
3020 SSVAL(*rparam,2,0); /* converter word */
3021 SSVAL(*rparam,4,*rdata_len);
3026 /****************************************************************************
3027 Get info about the server.
3028 ****************************************************************************/
3030 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3031 char *param, int tpscnt,
3032 char *data, int tdscnt,
3033 int mdrcnt,int mprcnt,
3034 char **rdata,char **rparam,
3035 int *rdata_len,int *rparam_len)
3037 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3038 char *str2 = skip_string(param,tpscnt,str1);
3039 char *p = skip_string(param,tpscnt,str2);
3042 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3044 if (!str1 || !str2 || !p) {
3048 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3051 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3056 /* check it's a supported varient */
3057 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3061 *rdata_len = mdrcnt + 1024;
3062 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3067 SSVAL(*rparam,0,NERR_Success);
3068 SSVAL(*rparam,2,0); /* converter word */
3071 endp = *rdata + *rdata_len;
3073 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3078 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3079 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3081 p2 = skip_string(*rdata,*rdata_len,p2);
3087 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3088 strlcpy(p2,current_user_info.smb_name,PTR_DIFF(endp,p2));
3089 p2 = skip_string(*rdata,*rdata_len,p2);
3095 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3096 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3098 p2 = skip_string(*rdata,*rdata_len,p2);
3104 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3105 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3108 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3109 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3110 p2 = skip_string(*rdata,*rdata_len,p2);
3116 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3117 strlcpy(p2,"",PTR_DIFF(endp,p2));
3118 p2 = skip_string(*rdata,*rdata_len,p2);
3124 *rdata_len = PTR_DIFF(p2,*rdata);
3126 SSVAL(*rparam,4,*rdata_len);
3131 /****************************************************************************
3132 get info about a user
3134 struct user_info_11 {
3135 char usri11_name[21]; 0-20
3137 char *usri11_comment; 22-25
3138 char *usri11_usr_comment; 26-29
3139 unsigned short usri11_priv; 30-31
3140 unsigned long usri11_auth_flags; 32-35
3141 long usri11_password_age; 36-39
3142 char *usri11_homedir; 40-43
3143 char *usri11_parms; 44-47
3144 long usri11_last_logon; 48-51
3145 long usri11_last_logoff; 52-55
3146 unsigned short usri11_bad_pw_count; 56-57
3147 unsigned short usri11_num_logons; 58-59
3148 char *usri11_logon_server; 60-63
3149 unsigned short usri11_country_code; 64-65
3150 char *usri11_workstations; 66-69
3151 unsigned long usri11_max_storage; 70-73
3152 unsigned short usri11_units_per_week; 74-75
3153 unsigned char *usri11_logon_hours; 76-79
3154 unsigned short usri11_code_page; 80-81
3159 usri11_name specifies the user name for which information is retireved
3161 usri11_pad aligns the next data structure element to a word boundary
3163 usri11_comment is a null terminated ASCII comment
3165 usri11_user_comment is a null terminated ASCII comment about the user
3167 usri11_priv specifies the level of the privilege assigned to the user.
3168 The possible values are:
3170 Name Value Description
3171 USER_PRIV_GUEST 0 Guest privilege
3172 USER_PRIV_USER 1 User privilege
3173 USER_PRV_ADMIN 2 Administrator privilege
3175 usri11_auth_flags specifies the account operator privileges. The
3176 possible values are:
3178 Name Value Description
3179 AF_OP_PRINT 0 Print operator
3182 Leach, Naik [Page 28]
3186 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3189 AF_OP_COMM 1 Communications operator
3190 AF_OP_SERVER 2 Server operator
3191 AF_OP_ACCOUNTS 3 Accounts operator
3194 usri11_password_age specifies how many seconds have elapsed since the
3195 password was last changed.
3197 usri11_home_dir points to a null terminated ASCII string that contains
3198 the path name of the user's home directory.
3200 usri11_parms points to a null terminated ASCII string that is set
3201 aside for use by applications.
3203 usri11_last_logon specifies the time when the user last logged on.
3204 This value is stored as the number of seconds elapsed since
3205 00:00:00, January 1, 1970.
3207 usri11_last_logoff specifies the time when the user last logged off.
3208 This value is stored as the number of seconds elapsed since
3209 00:00:00, January 1, 1970. A value of 0 means the last logoff
3212 usri11_bad_pw_count specifies the number of incorrect passwords
3213 entered since the last successful logon.
3215 usri11_log1_num_logons specifies the number of times this user has
3216 logged on. A value of -1 means the number of logons is unknown.
3218 usri11_logon_server points to a null terminated ASCII string that
3219 contains the name of the server to which logon requests are sent.
3220 A null string indicates logon requests should be sent to the
3223 usri11_country_code specifies the country code for the user's language
3226 usri11_workstations points to a null terminated ASCII string that
3227 contains the names of workstations the user may log on from.
3228 There may be up to 8 workstations, with the names separated by
3229 commas. A null strings indicates there are no restrictions.
3231 usri11_max_storage specifies the maximum amount of disk space the user
3232 can occupy. A value of 0xffffffff indicates there are no
3235 usri11_units_per_week specifies the equal number of time units into
3236 which a week is divided. This value must be equal to 168.
3238 usri11_logon_hours points to a 21 byte (168 bits) string that
3239 specifies the time during which the user can log on. Each bit
3240 represents one unique hour in a week. The first bit (bit 0, word
3241 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3245 Leach, Naik [Page 29]
3249 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3252 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3253 are no restrictions.
3255 usri11_code_page specifies the code page for the user's language of
3258 All of the pointers in this data structure need to be treated
3259 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3260 to be ignored. The converter word returned in the parameters section
3261 needs to be subtracted from the lower 16 bits to calculate an offset
3262 into the return buffer where this ASCII string resides.
3264 There is no auxiliary data in the response.
3266 ****************************************************************************/
3268 #define usri11_name 0
3269 #define usri11_pad 21
3270 #define usri11_comment 22
3271 #define usri11_usr_comment 26
3272 #define usri11_full_name 30
3273 #define usri11_priv 34
3274 #define usri11_auth_flags 36
3275 #define usri11_password_age 40
3276 #define usri11_homedir 44
3277 #define usri11_parms 48
3278 #define usri11_last_logon 52
3279 #define usri11_last_logoff 56
3280 #define usri11_bad_pw_count 60
3281 #define usri11_num_logons 62
3282 #define usri11_logon_server 64
3283 #define usri11_country_code 68
3284 #define usri11_workstations 70
3285 #define usri11_max_storage 74
3286 #define usri11_units_per_week 78
3287 #define usri11_logon_hours 80
3288 #define usri11_code_page 84
3289 #define usri11_end 86
3291 #define USER_PRIV_GUEST 0
3292 #define USER_PRIV_USER 1
3293 #define USER_PRIV_ADMIN 2
3295 #define AF_OP_PRINT 0
3296 #define AF_OP_COMM 1
3297 #define AF_OP_SERVER 2
3298 #define AF_OP_ACCOUNTS 3
3301 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3302 char *param, int tpscnt,
3303 char *data, int tdscnt,
3304 int mdrcnt,int mprcnt,
3305 char **rdata,char **rparam,
3306 int *rdata_len,int *rparam_len)
3308 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3309 char *str2 = skip_string(param,tpscnt,str1);
3310 char *UserName = skip_string(param,tpscnt,str2);
3311 char *p = skip_string(param,tpscnt,UserName);
3312 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3315 const char *level_string;
3317 /* get NIS home of a previously validated user - simeon */
3318 /* With share level security vuid will always be zero.
3319 Don't depend on vuser being non-null !!. JRA */
3320 user_struct *vuser = get_valid_user_struct(vuid);
3322 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3323 vuser->user.unix_name));
3326 if (!str1 || !str2 || !UserName || !p) {
3331 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3336 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3338 /* check it's a supported variant */
3339 if (strcmp(str1,"zWrLh") != 0) {
3343 case 0: level_string = "B21"; break;
3344 case 1: level_string = "B21BB16DWzzWz"; break;
3345 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3346 case 10: level_string = "B21Bzzz"; break;
3347 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3348 default: return False;
3351 if (strcmp(level_string,str2) != 0) {
3355 *rdata_len = mdrcnt + 1024;
3356 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3361 SSVAL(*rparam,0,NERR_Success);
3362 SSVAL(*rparam,2,0); /* converter word */
3365 endp = *rdata + *rdata_len;
3366 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3372 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3375 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3380 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3381 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3382 p2 = skip_string(*rdata,*rdata_len,p2);
3387 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3388 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3389 p2 = skip_string(*rdata,*rdata_len,p2);
3394 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3395 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3396 strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2));
3397 p2 = skip_string(*rdata,*rdata_len,p2);
3404 /* modelled after NTAS 3.51 reply */
3405 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3406 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3407 SIVALS(p,usri11_password_age,-1); /* password age */
3408 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3409 strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2));
3410 p2 = skip_string(*rdata,*rdata_len,p2);
3414 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3415 strlcpy(p2,"",PTR_DIFF(endp,p2));
3416 p2 = skip_string(*rdata,*rdata_len,p2);
3420 SIVAL(p,usri11_last_logon,0); /* last logon */
3421 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3422 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3423 SSVALS(p,usri11_num_logons,-1); /* num logons */
3424 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3425 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3426 p2 = skip_string(*rdata,*rdata_len,p2);
3430 SSVAL(p,usri11_country_code,0); /* country code */
3432 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3433 strlcpy(p2,"",PTR_DIFF(endp,p2));
3434 p2 = skip_string(*rdata,*rdata_len,p2);
3439 SIVALS(p,usri11_max_storage,-1); /* max storage */
3440 SSVAL(p,usri11_units_per_week,168); /* units per week */
3441 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3443 /* a simple way to get logon hours at all times. */
3445 SCVAL(p2,21,0); /* fix zero termination */
3446 p2 = skip_string(*rdata,*rdata_len,p2);
3451 SSVAL(p,usri11_code_page,0); /* code page */
3454 if (uLevel == 1 || uLevel == 2) {
3455 memset(p+22,' ',16); /* password */
3456 SIVALS(p,38,-1); /* password age */
3458 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3459 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3460 strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2));
3461 p2 = skip_string(*rdata,*rdata_len,p2);
3465 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3467 SSVAL(p,52,0); /* flags */
3468 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3469 strlcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "",PTR_DIFF(endp,p2));
3470 p2 = skip_string(*rdata,*rdata_len,p2);
3475 SIVAL(p,60,0); /* auth_flags */
3476 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3477 strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2));
3478 p2 = skip_string(*rdata,*rdata_len,p2);
3482 SIVAL(p,68,0); /* urs_comment */
3483 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3484 strlcpy(p2,"",PTR_DIFF(endp,p2));
3485 p2 = skip_string(*rdata,*rdata_len,p2);
3489 SIVAL(p,76,0); /* workstations */
3490 SIVAL(p,80,0); /* last_logon */
3491 SIVAL(p,84,0); /* last_logoff */
3492 SIVALS(p,88,-1); /* acct_expires */
3493 SIVALS(p,92,-1); /* max_storage */
3494 SSVAL(p,96,168); /* units_per_week */
3495 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3498 SSVALS(p,102,-1); /* bad_pw_count */
3499 SSVALS(p,104,-1); /* num_logons */
3500 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3502 TALLOC_CTX *ctx = talloc_tos();
3503 int space_rem = *rdata_len - (p2 - *rdata);
3506 if (space_rem <= 0) {
3509 tmp = talloc_strdup(ctx, "\\\\%L");
3513 tmp = talloc_sub_basic(ctx,
3526 p2 = skip_string(*rdata,*rdata_len,p2);
3530 SSVAL(p,110,49); /* country_code */
3531 SSVAL(p,112,860); /* code page */
3535 *rdata_len = PTR_DIFF(p2,*rdata);
3537 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3542 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3543 char *param, int tpscnt,
3544 char *data, int tdscnt,
3545 int mdrcnt,int mprcnt,
3546 char **rdata,char **rparam,
3547 int *rdata_len,int *rparam_len)
3549 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3550 char *str2 = skip_string(param,tpscnt,str1);
3551 char *p = skip_string(param,tpscnt,str2);
3553 struct pack_desc desc;
3555 /* With share level security vuid will always be zero.
3556 Don't depend on vuser being non-null !!. JRA */
3557 user_struct *vuser = get_valid_user_struct(vuid);
3559 if (!str1 || !str2 || !p) {
3564 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3565 vuser->user.unix_name));
3568 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3569 name = get_safe_str_ptr(param,tpscnt,p,2);
3574 memset((char *)&desc,'\0',sizeof(desc));
3576 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3578 /* check it's a supported varient */
3579 if (strcmp(str1,"OOWb54WrLh") != 0) {
3582 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3586 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3593 desc.buflen = mdrcnt;
3594 desc.subformat = NULL;
3597 if (init_package(&desc,1,0)) {
3598 PACKI(&desc,"W",0); /* code */
3599 PACKS(&desc,"B21",name); /* eff. name */
3600 PACKS(&desc,"B",""); /* pad */
3601 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3602 PACKI(&desc,"D",0); /* auth flags XXX */
3603 PACKI(&desc,"W",0); /* num logons */
3604 PACKI(&desc,"W",0); /* bad pw count */
3605 PACKI(&desc,"D",0); /* last logon */
3606 PACKI(&desc,"D",-1); /* last logoff */
3607 PACKI(&desc,"D",-1); /* logoff time */
3608 PACKI(&desc,"D",-1); /* kickoff time */
3609 PACKI(&desc,"D",0); /* password age */
3610 PACKI(&desc,"D",0); /* password can change */
3611 PACKI(&desc,"D",-1); /* password must change */
3615 fstrcpy(mypath,"\\\\");
3616 fstrcat(mypath,get_local_machine_name());
3618 PACKS(&desc,"z",mypath); /* computer */
3621 PACKS(&desc,"z",lp_workgroup());/* domain */
3622 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3623 PACKI(&desc,"D",0x00000000); /* reserved */
3626 *rdata_len = desc.usedlen;
3628 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3632 SSVALS(*rparam,0,desc.errcode);
3634 SSVAL(*rparam,4,desc.neededlen);
3636 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3641 /****************************************************************************
3642 api_WAccessGetUserPerms
3643 ****************************************************************************/
3645 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3646 char *param, int tpscnt,
3647 char *data, int tdscnt,
3648 int mdrcnt,int mprcnt,
3649 char **rdata,char **rparam,
3650 int *rdata_len,int *rparam_len)
3652 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3653 char *str2 = skip_string(param,tpscnt,str1);
3654 char *user = skip_string(param,tpscnt,str2);
3655 char *resource = skip_string(param,tpscnt,user);
3657 if (!str1 || !str2 || !user || !resource) {
3661 if (skip_string(param,tpscnt,resource) == NULL) {
3664 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3666 /* check it's a supported varient */
3667 if (strcmp(str1,"zzh") != 0) {
3670 if (strcmp(str2,"") != 0) {
3675 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3679 SSVALS(*rparam,0,0); /* errorcode */
3680 SSVAL(*rparam,2,0); /* converter word */
3681 SSVAL(*rparam,4,0x7f); /* permission flags */
3686 /****************************************************************************
3687 api_WPrintJobEnumerate
3688 ****************************************************************************/
3690 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3691 char *param, int tpscnt,
3692 char *data, int tdscnt,
3693 int mdrcnt,int mprcnt,
3694 char **rdata,char **rparam,
3695 int *rdata_len,int *rparam_len)
3697 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3698 char *str2 = skip_string(param,tpscnt,str1);
3699 char *p = skip_string(param,tpscnt,str2);
3706 struct pack_desc desc;
3707 print_queue_struct *queue=NULL;
3708 print_status_struct status;
3711 if (!str1 || !str2 || !p) {
3715 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3717 memset((char *)&desc,'\0',sizeof(desc));
3718 memset((char *)&status,'\0',sizeof(status));
3720 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3722 /* check it's a supported varient */
3723 if (strcmp(str1,"WWrLh") != 0) {
3726 if (!check_printjob_info(&desc,uLevel,str2)) {
3730 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3734 snum = lp_servicenumber( sharename);
3735 if (snum < 0 || !VALID_SNUM(snum)) {
3739 count = print_queue_status(snum,&queue,&status);
3740 for (i = 0; i < count; i++) {
3741 if (queue[i].job == jobid) {
3747 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3752 desc.buflen = mdrcnt;
3755 * Don't return data but need to get correct length
3756 * init_package will return wrong size if buflen=0
3758 desc.buflen = getlen(desc.format);
3759 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3762 if (init_package(&desc,1,0)) {
3764 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3765 *rdata_len = desc.usedlen;
3767 desc.errcode = NERR_JobNotFound;
3773 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3777 SSVALS(*rparam,0,desc.errcode);
3779 SSVAL(*rparam,4,desc.neededlen);
3784 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3789 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3790 char *param, int tpscnt,
3791 char *data, int tdscnt,
3792 int mdrcnt,int mprcnt,
3793 char **rdata,char **rparam,
3794 int *rdata_len,int *rparam_len)
3796 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3797 char *str2 = skip_string(param,tpscnt,str1);
3798 char *p = skip_string(param,tpscnt,str2);
3804 struct pack_desc desc;
3805 print_queue_struct *queue=NULL;
3806 print_status_struct status;
3808 if (!str1 || !str2 || !p) {
3812 memset((char *)&desc,'\0',sizeof(desc));
3813 memset((char *)&status,'\0',sizeof(status));
3815 p = skip_string(param,tpscnt,p);
3819 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3821 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3823 /* check it's a supported variant */
3824 if (strcmp(str1,"zWrLeh") != 0) {
3829 return False; /* defined only for uLevel 0,1,2 */
3832 if (!check_printjob_info(&desc,uLevel,str2)) {
3836 snum = find_service(name);
3837 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3841 count = print_queue_status(snum,&queue,&status);
3843 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3849 desc.buflen = mdrcnt;
3851 if (init_package(&desc,count,0)) {
3853 for (i = 0; i < count; i++) {
3854 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3855 if (desc.errcode == NERR_Success) {
3861 *rdata_len = desc.usedlen;
3864 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3868 SSVALS(*rparam,0,desc.errcode);
3870 SSVAL(*rparam,4,succnt);
3871 SSVAL(*rparam,6,count);
3875 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3880 static int check_printdest_info(struct pack_desc* desc,
3881 int uLevel, char* id)
3883 desc->subformat = NULL;
3886 desc->format = "B9";
3889 desc->format = "B9B21WWzW";
3895 desc->format = "zzzWWzzzWW";
3898 DEBUG(0,("check_printdest_info: invalid level %d\n",
3902 if (id == NULL || strcmp(desc->format,id) != 0) {
3903 DEBUG(0,("check_printdest_info: invalid string %s\n",
3904 id ? id : "<NULL>" ));
3910 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3911 struct pack_desc* desc)
3915 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3916 buf[sizeof(buf)-1] = 0;
3920 PACKS(desc,"B9",buf); /* szName */
3922 PACKS(desc,"B21",""); /* szUserName */
3923 PACKI(desc,"W",0); /* uJobId */
3924 PACKI(desc,"W",0); /* fsStatus */
3925 PACKS(desc,"z",""); /* pszStatus */
3926 PACKI(desc,"W",0); /* time */
3930 if (uLevel == 2 || uLevel == 3) {
3931 PACKS(desc,"z",buf); /* pszPrinterName */
3933 PACKS(desc,"z",""); /* pszUserName */
3934 PACKS(desc,"z",""); /* pszLogAddr */
3935 PACKI(desc,"W",0); /* uJobId */
3936 PACKI(desc,"W",0); /* fsStatus */
3937 PACKS(desc,"z",""); /* pszStatus */
3938 PACKS(desc,"z",""); /* pszComment */
3939 PACKS(desc,"z","NULL"); /* pszDrivers */
3940 PACKI(desc,"W",0); /* time */
3941 PACKI(desc,"W",0); /* pad1 */
3946 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3947 char *param, int tpscnt,
3948 char *data, int tdscnt,
3949 int mdrcnt,int mprcnt,
3950 char **rdata,char **rparam,
3951 int *rdata_len,int *rparam_len)
3953 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3954 char *str2 = skip_string(param,tpscnt,str1);
3955 char *p = skip_string(param,tpscnt,str2);
3956 char* PrinterName = p;
3958 struct pack_desc desc;
3962 if (!str1 || !str2 || !p) {
3966 memset((char *)&desc,'\0',sizeof(desc));
3968 p = skip_string(param,tpscnt,p);
3972 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3974 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3976 /* check it's a supported varient */
3977 if (strcmp(str1,"zWrLh") != 0) {
3980 if (!check_printdest_info(&desc,uLevel,str2)) {
3984 snum = find_service(PrinterName);
3985 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3987 desc.errcode = NERR_DestNotFound;
3991 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3996 desc.buflen = mdrcnt;
3999 * Don't return data but need to get correct length
4000 * init_package will return wrong size if buflen=0
4002 desc.buflen = getlen(desc.format);
4003 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4005 if (init_package(&desc,1,0)) {
4006 fill_printdest_info(conn,snum,uLevel,&desc);
4008 *rdata_len = desc.usedlen;
4012 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4016 SSVALS(*rparam,0,desc.errcode);
4018 SSVAL(*rparam,4,desc.neededlen);
4020 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4026 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4027 char *param, int tpscnt,
4028 char *data, int tdscnt,
4029 int mdrcnt,int mprcnt,
4030 char **rdata,char **rparam,
4031 int *rdata_len,int *rparam_len)
4033 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4034 char *str2 = skip_string(param,tpscnt,str1);
4035 char *p = skip_string(param,tpscnt,str2);
4039 struct pack_desc desc;
4040 int services = lp_numservices();
4042 if (!str1 || !str2 || !p) {
4046 memset((char *)&desc,'\0',sizeof(desc));
4048 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4050 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4052 /* check it's a supported varient */
4053 if (strcmp(str1,"WrLeh") != 0) {
4056 if (!check_printdest_info(&desc,uLevel,str2)) {
4061 for (i = 0; i < services; i++) {
4062 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4068 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4075 desc.buflen = mdrcnt;
4076 if (init_package(&desc,queuecnt,0)) {
4079 for (i = 0; i < services; i++) {
4080 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4081 fill_printdest_info(conn,i,uLevel,&desc);
4083 if (desc.errcode == NERR_Success) {
4090 *rdata_len = desc.usedlen;
4093 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4097 SSVALS(*rparam,0,desc.errcode);
4099 SSVAL(*rparam,4,succnt);
4100 SSVAL(*rparam,6,queuecnt);
4102 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4107 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4108 char *param, int tpscnt,
4109 char *data, int tdscnt,
4110 int mdrcnt,int mprcnt,
4111 char **rdata,char **rparam,
4112 int *rdata_len,int *rparam_len)
4114 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4115 char *str2 = skip_string(param,tpscnt,str1);
4116 char *p = skip_string(param,tpscnt,str2);
4119 struct pack_desc desc;
4121 if (!str1 || !str2 || !p) {
4125 memset((char *)&desc,'\0',sizeof(desc));
4127 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4129 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4131 /* check it's a supported varient */
4132 if (strcmp(str1,"WrLeh") != 0) {
4135 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4140 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4146 desc.buflen = mdrcnt;
4147 if (init_package(&desc,1,0)) {
4148 PACKS(&desc,"B41","NULL");
4151 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4153 *rdata_len = desc.usedlen;
4156 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4160 SSVALS(*rparam,0,desc.errcode);
4162 SSVAL(*rparam,4,succnt);
4165 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4170 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4171 char *param, int tpscnt,
4172 char *data, int tdscnt,
4173 int mdrcnt,int mprcnt,
4174 char **rdata,char **rparam,
4175 int *rdata_len,int *rparam_len)
4177 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4178 char *str2 = skip_string(param,tpscnt,str1);
4179 char *p = skip_string(param,tpscnt,str2);
4182 struct pack_desc desc;
4184 if (!str1 || !str2 || !p) {
4187 memset((char *)&desc,'\0',sizeof(desc));
4189 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4191 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4193 /* check it's a supported varient */
4194 if (strcmp(str1,"WrLeh") != 0) {
4197 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4202 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4208 desc.buflen = mdrcnt;
4210 if (init_package(&desc,1,0)) {
4211 PACKS(&desc,"B13","lpd");
4214 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4216 *rdata_len = desc.usedlen;
4219 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4223 SSVALS(*rparam,0,desc.errcode);
4225 SSVAL(*rparam,4,succnt);
4228 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4233 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4234 char *param, int tpscnt,
4235 char *data, int tdscnt,
4236 int mdrcnt,int mprcnt,
4237 char **rdata,char **rparam,
4238 int *rdata_len,int *rparam_len)
4240 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4241 char *str2 = skip_string(param,tpscnt,str1);
4242 char *p = skip_string(param,tpscnt,str2);
4245 struct pack_desc desc;
4247 if (!str1 || !str2 || !p) {
4251 memset((char *)&desc,'\0',sizeof(desc));
4253 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4255 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4257 /* check it's a supported varient */
4258 if (strcmp(str1,"WrLeh") != 0) {
4261 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4266 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4271 memset((char *)&desc,'\0',sizeof(desc));
4273 desc.buflen = mdrcnt;
4275 if (init_package(&desc,1,0)) {
4276 PACKS(&desc,"B13","lp0");
4279 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4281 *rdata_len = desc.usedlen;
4284 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4288 SSVALS(*rparam,0,desc.errcode);
4290 SSVAL(*rparam,4,succnt);
4293 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4298 /****************************************************************************
4300 ****************************************************************************/
4302 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4303 char *param, int tpscnt,
4304 char *data, int tdscnt,
4305 int mdrcnt,int mprcnt,
4306 char **rdata,char **rparam,
4307 int *rdata_len,int *rparam_len)
4310 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4311 char *str2 = skip_string(param,tpscnt,str1);
4312 char *p = skip_string(param,tpscnt,str2);
4314 struct pack_desc desc;
4315 struct sessionid *session_list;
4316 int i, num_sessions;
4318 if (!str1 || !str2 || !p) {
4322 memset((char *)&desc,'\0',sizeof(desc));
4324 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4326 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4327 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4328 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4330 /* check it's a supported varient */
4331 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4334 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4338 num_sessions = list_sessions(talloc_tos(), &session_list);
4341 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4346 memset((char *)&desc,'\0',sizeof(desc));
4348 desc.buflen = mdrcnt;
4350 if (!init_package(&desc,num_sessions,0)) {
4354 for(i=0; i<num_sessions; i++) {
4355 PACKS(&desc, "z", session_list[i].remote_machine);
4356 PACKS(&desc, "z", session_list[i].username);
4357 PACKI(&desc, "W", 1); /* num conns */
4358 PACKI(&desc, "W", 0); /* num opens */
4359 PACKI(&desc, "W", 1); /* num users */
4360 PACKI(&desc, "D", 0); /* session time */
4361 PACKI(&desc, "D", 0); /* idle time */
4362 PACKI(&desc, "D", 0); /* flags */
4363 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4366 *rdata_len = desc.usedlen;
4369 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4373 SSVALS(*rparam,0,desc.errcode);
4374 SSVAL(*rparam,2,0); /* converter */
4375 SSVAL(*rparam,4,num_sessions); /* count */
4377 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4383 /****************************************************************************
4384 The buffer was too small.
4385 ****************************************************************************/
4387 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4388 int mdrcnt, int mprcnt,
4389 char **rdata, char **rparam,
4390 int *rdata_len, int *rparam_len)
4392 *rparam_len = MIN(*rparam_len,mprcnt);
4393 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4400 SSVAL(*rparam,0,NERR_BufTooSmall);
4402 DEBUG(3,("Supplied buffer too small in API command\n"));
4407 /****************************************************************************
4408 The request is not supported.
4409 ****************************************************************************/
4411 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4412 char *param, int tpscnt,
4413 char *data, int tdscnt,
4414 int mdrcnt, int mprcnt,
4415 char **rdata, char **rparam,
4416 int *rdata_len, int *rparam_len)
4419 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4426 SSVAL(*rparam,0,NERR_notsupported);
4427 SSVAL(*rparam,2,0); /* converter word */
4429 DEBUG(3,("Unsupported API command\n"));
4434 static const struct {
4437 bool (*fn)(connection_struct *, uint16,
4440 int,int,char **,char **,int *,int *);
4441 bool auth_user; /* Deny anonymous access? */
4442 } api_commands[] = {
4443 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4444 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4445 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4446 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4447 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4448 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4449 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4450 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4451 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4452 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4453 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4454 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4455 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4456 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4457 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4458 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4459 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4460 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4461 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4462 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4463 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4464 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4465 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4466 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4467 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4468 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4469 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4470 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4471 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4472 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4473 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4474 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4475 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4476 {NULL, -1, api_Unsupported}
4477 /* The following RAP calls are not implemented by Samba:
4479 RAP_WFileEnum2 - anon not OK
4484 /****************************************************************************
4485 Handle remote api calls.
4486 ****************************************************************************/
4488 void api_reply(connection_struct *conn, uint16 vuid,
4489 struct smb_request *req,
4490 char *data, char *params,
4491 int tdscnt, int tpscnt,
4492 int mdrcnt, int mprcnt)
4496 char *rparam = NULL;
4497 const char *name1 = NULL;
4498 const char *name2 = NULL;
4505 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4506 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4511 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4514 api_command = SVAL(params,0);
4515 /* Is there a string at position params+2 ? */
4516 if (skip_string(params,tpscnt,params+2)) {
4521 name2 = skip_string(params,tpscnt,params+2);
4526 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4530 tdscnt,tpscnt,mdrcnt,mprcnt));
4532 for (i=0;api_commands[i].name;i++) {
4533 if (api_commands[i].id == api_command && api_commands[i].fn) {
4534 DEBUG(3,("Doing %s\n",api_commands[i].name));
4539 /* Check whether this api call can be done anonymously */
4541 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4542 user_struct *user = get_valid_user_struct(vuid);
4544 if (!user || user->guest) {
4545 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4550 rdata = (char *)SMB_MALLOC(1024);
4552 memset(rdata,'\0',1024);
4555 rparam = (char *)SMB_MALLOC(1024);
4557 memset(rparam,'\0',1024);
4560 if(!rdata || !rparam) {
4561 DEBUG(0,("api_reply: malloc fail !\n"));
4564 reply_nterror(req, NT_STATUS_NO_MEMORY);
4568 reply = api_commands[i].fn(conn,
4570 params,tpscnt, /* params + length */
4571 data,tdscnt, /* data + length */
4573 &rdata,&rparam,&rdata_len,&rparam_len);
4576 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4577 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4578 &rdata,&rparam,&rdata_len,&rparam_len);
4581 /* if we get False back then it's actually unsupported */
4583 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4584 &rdata,&rparam,&rdata_len,&rparam_len);
4587 /* If api_Unsupported returns false we can't return anything. */
4589 send_trans_reply(req, rparam, rparam_len,
4590 rdata, rdata_len, False);