3 Unix SMB/Netbios implementation.
5 Inter-process communication and named pipe handling
6 Copyright (C) Andrew Tridgell 1992-1998
9 Copyright (C) John H Terpstra 1995-1998
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 This file handles the named pipe and mailslot calls
27 in the SMBtrans protocol
37 extern int DEBUGLEVEL;
39 extern fstring local_machine;
40 extern fstring global_myworkgroup;
42 #define NERR_Success 0
43 #define NERR_badpass 86
44 #define NERR_notsupported 50
46 #define NERR_BASE (2100)
47 #define NERR_BufTooSmall (NERR_BASE+23)
48 #define NERR_JobNotFound (NERR_BASE+51)
49 #define NERR_DestNotFound (NERR_BASE+52)
51 #define ACCESS_READ 0x01
52 #define ACCESS_WRITE 0x02
53 #define ACCESS_CREATE 0x04
55 #define SHPWLEN 8 /* share password length */
57 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
58 int mdrcnt,int mprcnt,
59 char **rdata,char **rparam,
60 int *rdata_len,int *rparam_len);
61 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
62 int mdrcnt,int mprcnt,
63 char **rdata,char **rparam,
64 int *rdata_len,int *rparam_len);
67 static int CopyExpanded(connection_struct *conn,
68 int snum, char** dst, char* src, int* n)
73 if (!src || !dst || !n || !(*dst)) return(0);
75 StrnCpy(buf,src,sizeof(buf)/2);
76 pstring_sub(buf,"%S",lp_servicename(snum));
77 standard_sub_conn(conn,buf);
85 static int CopyAndAdvance(char** dst, char* src, int* n)
88 if (!src || !dst || !n || !(*dst)) return(0);
89 StrnCpy(*dst,src,*n-1);
96 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
100 StrnCpy(buf,s,sizeof(buf)/2);
101 pstring_sub(buf,"%S",lp_servicename(snum));
102 standard_sub_conn(conn,buf);
103 return strlen(buf) + 1;
106 static char* Expand(connection_struct *conn, int snum, char* s)
109 if (!s) return(NULL);
110 StrnCpy(buf,s,sizeof(buf)/2);
111 pstring_sub(buf,"%S",lp_servicename(snum));
112 standard_sub_conn(conn,buf);
116 /*******************************************************************
117 check a API string for validity when we only need to check the prefix
118 ******************************************************************/
119 static BOOL prefix_ok(char *str,char *prefix)
121 return(strncmp(str,prefix,strlen(prefix)) == 0);
125 char* format; /* formatstring for structure */
126 char* subformat; /* subformat for structure */
127 char* base; /* baseaddress of buffer */
128 int buflen; /* remaining size for fixed part; on init: length of base */
129 int subcount; /* count of substructures */
130 char* structbuf; /* pointer into buffer for remaining fixed part */
131 int stringlen; /* remaining size for variable part */
132 char* stringbuf; /* pointer into buffer for remaining variable part */
133 int neededlen; /* total needed size */
134 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
135 char* curpos; /* current position; pointer into format or subformat */
139 static int get_counter(char** p)
142 if (!p || !(*p)) return(1);
143 if (!isdigit((int)**p)) return 1;
147 n = 10 * n + (i - '0');
154 static int getlen(char* p)
160 case 'W': /* word (2 byte) */
163 case 'K': /* status word? (2 byte) */
166 case 'N': /* count of substructures (word) at end */
169 case 'D': /* double word (4 byte) */
170 case 'z': /* offset to zero terminated string (4 byte) */
171 case 'l': /* offset to user data (4 byte) */
174 case 'b': /* offset to data (with counter) (4 byte) */
178 case 'B': /* byte (with optional counter) */
179 n += get_counter(&p);
186 static BOOL init_package(struct pack_desc* p, int count, int subcount)
191 if (!p->format || !p->base) return(False);
193 i = count * getlen(p->format);
194 if (p->subformat) i += subcount * getlen(p->subformat);
195 p->structbuf = p->base;
199 p->curpos = p->format;
203 p->errcode = ERRmoredata;
206 p->errcode = NERR_Success;
209 p->stringbuf = p->base + i;
211 return(p->errcode == NERR_Success);
215 static int package(struct pack_desc* p, ...)
218 static int package(va_alist)
224 int needed=0, stringneeded;
226 int is_string=0, stringused;
233 p = va_arg(args,struct pack_desc *);
238 p->curpos = p->format;
240 p->curpos = p->subformat;
245 str = va_arg(args,char*);
246 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
255 switch( *p->curpos++ ) {
256 case 'W': /* word (2 byte) */
258 temp = va_arg(args,int);
259 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
261 case 'K': /* status word? (2 byte) */
263 temp = va_arg(args,int);
264 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
266 case 'N': /* count of substructures (word) at end */
268 p->subcount = va_arg(args,int);
269 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
271 case 'D': /* double word (4 byte) */
273 temp = va_arg(args,int);
274 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
276 case 'B': /* byte (with optional counter) */
277 needed = get_counter(&p->curpos);
279 char *s = va_arg(args,char*);
280 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
283 case 'z': /* offset to zero terminated string (4 byte) */
284 str = va_arg(args,char*);
285 stringneeded = (str ? strlen(str)+1 : 0);
288 case 'l': /* offset to user data (4 byte) */
289 str = va_arg(args,char*);
290 stringneeded = va_arg(args,int);
293 case 'b': /* offset to data (with counter) (4 byte) */
294 str = va_arg(args,char*);
295 stringneeded = get_counter(&p->curpos);
300 if (stringneeded >= 0) {
302 if (p->buflen >= needed) {
303 stringused = stringneeded;
304 if (stringused > p->stringlen) {
305 stringused = (is_string ? p->stringlen : 0);
306 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
309 SIVAL(p->structbuf,0,0);
311 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
312 memcpy(p->stringbuf,str?str:"",stringused);
313 if (is_string) p->stringbuf[stringused-1] = '\0';
314 p->stringbuf += stringused;
315 p->stringlen -= stringused;
316 p->usedlen += stringused;
319 p->neededlen += stringneeded;
321 p->neededlen += needed;
322 if (p->buflen >= needed) {
323 p->structbuf += needed;
325 p->usedlen += needed;
328 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
334 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
335 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
337 #define PACK(desc,t,v) package(desc,v)
338 #define PACKl(desc,t,v,l) package(desc,v,l)
341 static void PACKI(struct pack_desc* desc,char *t,int v)
346 static void PACKS(struct pack_desc* desc,char *t,char *v)
352 /****************************************************************************
354 ****************************************************************************/
355 static void PackDriverData(struct pack_desc* desc)
357 char drivdata[4+4+32];
358 SIVAL(drivdata,0,sizeof drivdata); /* cb */
359 SIVAL(drivdata,4,1000); /* lVersion */
360 memset(drivdata+8,0,32); /* szDeviceName */
361 pstrcpy(drivdata+8,"NULL");
362 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
365 static int check_printq_info(struct pack_desc* desc,
366 int uLevel, char *id1, char *id2)
368 desc->subformat = NULL;
371 desc->format = "B13";
374 desc->format = "B13BWWWzzzzzWW";
377 desc->format = "B13BWWWzzzzzWN";
378 desc->subformat = "WB21BB16B10zWWzDDz";
381 desc->format = "zWWWWzzzzWWzzl";
384 desc->format = "zWWWWzzzzWNzzl";
385 desc->subformat = "WWzWWDDzz";
394 desc->format = "WzzzzzzzzN";
395 desc->subformat = "z";
397 default: return False;
399 if (strcmp(desc->format,id1) != 0) return False;
400 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
405 #define JOB_STATUS_QUEUED 0
406 #define JOB_STATUS_PAUSED 1
407 #define JOB_STATUS_SPOOLING 2
408 #define JOB_STATUS_PRINTING 3
409 #define JOB_STATUS_PRINTED 4
411 #define QUEUE_STATUS_PAUSED 1
412 #define QUEUE_STATUS_ERROR 2
414 /* turn a print job status into a on the wire status
416 static int printj_status(int v)
420 return JOB_STATUS_QUEUED;
422 return JOB_STATUS_PAUSED;
424 return JOB_STATUS_SPOOLING;
426 return JOB_STATUS_PRINTING;
431 /* turn a print queue status into a on the wire status
433 static int printq_status(int v)
439 return QUEUE_STATUS_PAUSED;
441 return QUEUE_STATUS_ERROR;
444 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
445 struct pack_desc* desc,
446 print_queue_struct* queue, int n)
448 time_t t = queue->time;
450 /* the client expects localtime */
453 PACKI(desc,"W",queue->job); /* uJobId */
455 PACKS(desc,"B21",queue->user); /* szUserName */
456 PACKS(desc,"B",""); /* pad */
457 PACKS(desc,"B16",""); /* szNotifyName */
458 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
459 PACKS(desc,"z",""); /* pszParms */
460 PACKI(desc,"W",n+1); /* uPosition */
461 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
462 PACKS(desc,"z",""); /* pszStatus */
463 PACKI(desc,"D",t); /* ulSubmitted */
464 PACKI(desc,"D",queue->size); /* ulSize */
465 PACKS(desc,"z",queue->file); /* pszComment */
467 if (uLevel == 2 || uLevel == 3) {
468 PACKI(desc,"W",queue->priority); /* uPriority */
469 PACKS(desc,"z",queue->user); /* pszUserName */
470 PACKI(desc,"W",n+1); /* uPosition */
471 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
472 PACKI(desc,"D",t); /* ulSubmitted */
473 PACKI(desc,"D",queue->size); /* ulSize */
474 PACKS(desc,"z","Samba"); /* pszComment */
475 PACKS(desc,"z",queue->file); /* pszDocument */
477 PACKS(desc,"z",""); /* pszNotifyName */
478 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
479 PACKS(desc,"z",""); /* pszParms */
480 PACKS(desc,"z",""); /* pszStatus */
481 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
482 PACKS(desc,"z","lpd"); /* pszQProcName */
483 PACKS(desc,"z",""); /* pszQProcParms */
484 PACKS(desc,"z","NULL"); /* pszDriverName */
485 PackDriverData(desc); /* pDriverData */
486 PACKS(desc,"z",""); /* pszPrinterName */
492 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
493 struct pack_desc* desc,
494 int count, print_queue_struct* queue,
495 print_status_struct* status)
499 pstring tok,driver,datafile,langmon,helpfile,datatype;
506 * Check in the tdb *first* before checking the legacy
507 * files. This allows an NT upload to take precedence over
508 * the existing fileset. JRA.
511 if ((ok = get_a_printer_driver_9x_compatible(gen_line, lp_printerdriver(snum)) ) == True) {
513 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", lp_printerdriver(snum), gen_line));
515 /* didn't find driver in tdb either... oh well */
516 DEBUG(10,("9x driver not found in tdb\n"));
519 DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
520 snum, lp_printerdriver(snum), lp_driverfile(snum)));
522 lines = file_lines_load(lp_driverfile(snum),NULL);
525 DEBUG(3,("fill_printq_info: Can't open %s - %s\n",
526 lp_driverfile(snum),strerror(errno)));
527 desc->errcode=NERR_notsupported;
530 /* lookup the long printer driver name in the file
532 for (i=0;lines[i] && !ok;i++) {
534 if (next_token(&p,tok,":",sizeof(tok)) &&
535 (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
536 (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
544 if ((line = strdup(p)) == NULL)
548 file_lines_free(lines);
550 /* driver file name */
551 if (!next_token(&p,driver,":",sizeof(driver)))
555 if (!next_token(&p,datafile,":",sizeof(datafile)))
559 * for the next tokens - which may be empty - I have
560 * to check for empty tokens first because the
561 * next_token function will skip all empty token
568 } else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
571 /* language monitor */
575 } else if (!next_token(&p,langmon,":",sizeof(langmon)))
578 /* default data type */
579 if (!next_token(&p,datatype,":",sizeof(datatype)))
582 PACKI(desc,"W",0x0400); /* don't know */
583 PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */
584 PACKS(desc,"z",driver); /* Driverfile Name */
585 PACKS(desc,"z",datafile); /* Datafile name */
586 PACKS(desc,"z",langmon); /* language monitor */
587 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
588 PACKS(desc,"z",datatype); /* default data type */
589 PACKS(desc,"z",helpfile); /* helpfile name */
590 PACKS(desc,"z",driver); /* driver name */
591 DEBUG(3,("Driver:%s:\n",driver));
592 DEBUG(3,("Data File:%s:\n",datafile));
593 DEBUG(3,("Language Monitor:%s:\n",langmon));
594 DEBUG(3,("Data Type:%s:\n",datatype));
595 DEBUG(3,("Help File:%s:\n",helpfile));
596 PACKI(desc,"N",count); /* number of files to copy */
598 for (i=0;i<count;i++) {
599 /* no need to check return value here
600 * - it was already tested in
601 * get_printerdrivernumber */
602 next_token(&p,tok,",",sizeof(tok));
603 PACKS(desc,"z",tok); /* driver files to copy */
604 DEBUG(3,("file:%s:\n",tok));
607 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
608 SERVICE(snum),count));
615 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
616 desc->errcode=NERR_notsupported;
622 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
623 struct pack_desc* desc,
624 int count, print_queue_struct* queue,
625 print_status_struct* status)
630 PACKS(desc,"B13",SERVICE(snum));
635 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
638 PACKI(desc,"K",printq_status(status->status));
642 if (uLevel == 1 || uLevel == 2) {
643 PACKS(desc,"B",""); /* alignment */
644 PACKI(desc,"W",5); /* priority */
645 PACKI(desc,"W",0); /* start time */
646 PACKI(desc,"W",0); /* until time */
647 PACKS(desc,"z",""); /* pSepFile */
648 PACKS(desc,"z","lpd"); /* pPrProc */
649 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
650 PACKS(desc,"z",""); /* pParms */
652 PACKS(desc,"z","UNKNOWN PRINTER");
653 PACKI(desc,"W",LPSTAT_ERROR);
655 else if (!status || !status->message[0]) {
656 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
657 PACKI(desc,"W",LPSTAT_OK); /* status */
659 PACKS(desc,"z",status->message);
660 PACKI(desc,"W",printq_status(status->status)); /* status */
662 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
665 if (uLevel == 3 || uLevel == 4) {
666 PACKI(desc,"W",5); /* uPriority */
667 PACKI(desc,"W",0); /* uStarttime */
668 PACKI(desc,"W",0); /* uUntiltime */
669 PACKI(desc,"W",5); /* pad1 */
670 PACKS(desc,"z",""); /* pszSepFile */
671 PACKS(desc,"z","WinPrint"); /* pszPrProc */
672 PACKS(desc,"z",""); /* pszParms */
673 if (!status || !status->message[0]) {
674 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
675 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
677 PACKS(desc,"z",status->message); /* pszComment */
678 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
680 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
681 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
682 PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */
683 PackDriverData(desc); /* pDriverData */
686 if (uLevel == 2 || uLevel == 4) {
688 for (i=0;i<count;i++)
689 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
693 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
697 /* This function returns the number of files for a given driver */
698 static int get_printerdrivernumber(int snum)
706 DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
707 snum, lp_printerdriver(snum), lp_driverfile(snum)));
708 lines = file_lines_load(lp_driverfile(snum), NULL);
710 DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",
711 lp_driverfile(snum),strerror(errno)));
715 /* lookup the long printer driver name in the file
717 for (i=0;lines[i] && !ok;i++) {
719 if (next_token(&p,tok,":",sizeof(tok)) &&
720 (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
721 (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
727 /* no printers.def, or driver not found, check the NT driver tdb */
728 if ((ok = get_a_printer_driver_9x_compatible(gen_line, lp_printerdriver(snum)))==True ) {
730 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n",
731 lp_printerdriver(snum), gen_line));
733 /* didn't find driver in tdb either... oh well */
734 DEBUG(10,("9x driver not found in tdb\n"));
740 file_lines_free(lines);
746 if (*p++ == ':') i--;
751 /* count the number of files */
752 while (next_token(&p,tok,",",sizeof(tok)))
760 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
761 uint16 vuid, char *param,char *data,
762 int mdrcnt,int mprcnt,
763 char **rdata,char **rparam,
764 int *rdata_len,int *rparam_len)
766 char *str1 = param+2;
767 char *str2 = skip_string(str1,1);
768 char *p = skip_string(str2,1);
774 struct pack_desc desc;
775 print_queue_struct *queue=NULL;
776 print_status_struct status;
778 memset((char *)&status,'\0',sizeof(status));
779 memset((char *)&desc,'\0',sizeof(desc));
781 p = skip_string(p,1);
785 /* remove any trailing username */
786 if ((p = strchr(QueueName,'%'))) *p = 0;
788 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
790 /* check it's a supported varient */
791 if (!prefix_ok(str1,"zWrLh")) return False;
792 if (!check_printq_info(&desc,uLevel,str2,str3)) {
794 * Patch from Scott Moomaw <scott@bridgewater.edu>
795 * to return the 'invalid info level' error if an
796 * unknown level was requested.
800 *rparam = REALLOC(*rparam,*rparam_len);
801 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
807 snum = lp_servicenumber(QueueName);
808 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
809 int pnum = lp_servicenumber(PRINTERS_NAME);
811 lp_add_printer(QueueName,pnum);
812 snum = lp_servicenumber(QueueName);
816 if (snum < 0 || !VALID_SNUM(snum)) return(False);
819 count = get_printerdrivernumber(snum);
820 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
822 count = print_queue_status(snum, &queue,&status);
825 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
827 desc.buflen = mdrcnt;
828 if (init_package(&desc,1,count)) {
829 desc.subcount = count;
830 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
831 } else if(uLevel == 0) {
834 * This is a *disgusting* hack.
835 * This is *so* bad that even I'm embarrassed (and I
836 * have no shame). Here's the deal :
837 * Until we get the correct SPOOLSS code into smbd
838 * then when we're running with NT SMB support then
839 * NT makes this call with a level of zero, and then
840 * immediately follows it with an open request to
841 * the \\SRVSVC pipe. If we allow that open to
842 * succeed then NT barfs when it cannot open the
843 * \\SPOOLSS pipe immediately after and continually
844 * whines saying "Printer name is invalid" forever
845 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
846 * to fail, then NT downgrades to using the downlevel code
847 * and everything works as well as before. I hate
848 * myself for adding this code.... JRA.
851 fail_next_srvsvc_open();
855 *rdata_len = desc.usedlen;
858 *rparam = REALLOC(*rparam,*rparam_len);
859 SSVALS(*rparam,0,desc.errcode);
861 SSVAL(*rparam,4,desc.neededlen);
863 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
865 if (queue) free(queue);
871 /****************************************************************************
872 view list of all print jobs on all queues
873 ****************************************************************************/
874 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
875 int mdrcnt, int mprcnt,
876 char **rdata, char** rparam,
877 int *rdata_len, int *rparam_len)
879 char *param_format = param+2;
880 char *output_format1 = skip_string(param_format,1);
881 char *p = skip_string(output_format1,1);
882 int uLevel = SVAL(p,0);
883 char *output_format2 = p + 4;
884 int services = lp_numservices();
886 struct pack_desc desc;
887 print_queue_struct **queue = NULL;
888 print_status_struct *status = NULL;
889 int* subcntarr = NULL;
890 int queuecnt, subcnt=0, succnt=0;
892 memset((char *)&desc,'\0',sizeof(desc));
894 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
896 if (!prefix_ok(param_format,"WrLeh")) return False;
897 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
899 * Patch from Scott Moomaw <scott@bridgewater.edu>
900 * to return the 'invalid info level' error if an
901 * unknown level was requested.
905 *rparam = REALLOC(*rparam,*rparam_len);
906 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
913 for (i = 0; i < services; i++)
914 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
917 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
918 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
921 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
922 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
923 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
926 memset(status,0,queuecnt*sizeof(print_status_struct));
927 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
928 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
933 for (i = 0; i < services; i++)
934 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
935 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
936 subcnt += subcntarr[n];
940 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
942 desc.buflen = mdrcnt;
944 if (init_package(&desc,queuecnt,subcnt)) {
947 for (i = 0; i < services; i++)
948 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
949 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
951 if (desc.errcode == NERR_Success) succnt = n;
955 if (subcntarr) free(subcntarr);
957 *rdata_len = desc.usedlen;
959 *rparam = REALLOC(*rparam,*rparam_len);
960 SSVALS(*rparam,0,desc.errcode);
962 SSVAL(*rparam,4,succnt);
963 SSVAL(*rparam,6,queuecnt);
965 for (i = 0; i < queuecnt; i++) {
966 if (queue && queue[i]) free(queue[i]);
969 if (queue) free(queue);
970 if (status) free(status);
975 /****************************************************************************
976 get info level for a server list query
977 ****************************************************************************/
978 static BOOL check_server_info(int uLevel, char* id)
982 if (strcmp(id,"B16") != 0) return False;
985 if (strcmp(id,"B16BBDz") != 0) return False;
993 struct srv_info_struct
1003 /*******************************************************************
1004 get server info lists from the files saved by nmbd. Return the
1006 ******************************************************************/
1007 static int get_server_info(uint32 servertype,
1008 struct srv_info_struct **servers,
1014 BOOL local_list_only;
1017 lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1019 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1023 /* request for everything is code for request all servers */
1024 if (servertype == SV_TYPE_ALL)
1025 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1027 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1029 DEBUG(4,("Servertype search: %8x\n",servertype));
1031 for (i=0;lines[i];i++) {
1033 struct srv_info_struct *s;
1034 char *ptr = lines[i];
1037 if (!*ptr) continue;
1039 if (count == alloced) {
1041 (*servers) = (struct srv_info_struct *)
1042 Realloc(*servers,sizeof(**servers)*alloced);
1043 if (!(*servers)) return(0);
1044 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1046 s = &(*servers)[count];
1048 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1049 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1050 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1051 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1052 /* this allows us to cope with an old nmbd */
1053 pstrcpy(s->domain,global_myworkgroup);
1056 if (sscanf(stype,"%X",&s->type) != 1) {
1057 DEBUG(4,("r:host file "));
1061 /* Filter the servers/domains we return based on what was asked for. */
1063 /* Check to see if we are being asked for a local list only. */
1064 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1065 DEBUG(4,("r: local list only"));
1069 /* doesn't match up: don't want it */
1070 if (!(servertype & s->type)) {
1071 DEBUG(4,("r:serv type "));
1075 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1076 (s->type & SV_TYPE_DOMAIN_ENUM))
1078 DEBUG(4,("s: dom mismatch "));
1082 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1087 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1088 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1092 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1093 s->name, s->type, s->comment, s->domain));
1095 s->server_added = True;
1100 DEBUG(4,("%20s %8x %25s %15s\n",
1101 s->name, s->type, s->comment, s->domain));
1105 file_lines_free(lines);
1110 /*******************************************************************
1111 fill in a server info structure
1112 ******************************************************************/
1113 static int fill_srv_info(struct srv_info_struct *service,
1114 int uLevel, char **buf, int *buflen,
1115 char **stringbuf, int *stringspace, char *baseaddr)
1124 case 0: struct_len = 16; break;
1125 case 1: struct_len = 26; break;
1135 len = strlen(service->comment)+1;
1139 if (buflen) *buflen = struct_len;
1140 if (stringspace) *stringspace = len;
1141 return struct_len + len;
1146 if (*buflen < struct_len) return -1;
1154 p2 = p + struct_len;
1155 l2 = *buflen - struct_len;
1157 if (!baseaddr) baseaddr = p;
1162 StrnCpy(p,service->name,15);
1166 StrnCpy(p,service->name,15);
1167 SIVAL(p,18,service->type);
1168 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1169 len += CopyAndAdvance(&p2,service->comment,&l2);
1175 *buf = p + struct_len;
1176 *buflen -= struct_len;
1189 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1191 return(strcmp(s1->name,s2->name));
1194 /****************************************************************************
1195 view list of servers available (or possibly domains). The info is
1196 extracted from lists saved by nmbd on the local host
1197 ****************************************************************************/
1198 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1199 int mdrcnt, int mprcnt, char **rdata,
1200 char **rparam, int *rdata_len, int *rparam_len)
1202 char *str1 = param+2;
1203 char *str2 = skip_string(str1,1);
1204 char *p = skip_string(str2,1);
1205 int uLevel = SVAL(p,0);
1206 int buf_len = SVAL(p,2);
1207 uint32 servertype = IVAL(p,4);
1209 int data_len, fixed_len, string_len;
1210 int f_len = 0, s_len = 0;
1211 struct srv_info_struct *servers=NULL;
1212 int counted=0,total=0;
1215 BOOL domain_request;
1218 /* If someone sets all the bits they don't really mean to set
1219 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1222 if (servertype == SV_TYPE_ALL)
1223 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1225 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1226 any other bit (they may just set this bit on it's own) they
1227 want all the locally seen servers. However this bit can be
1228 set on its own so set the requested servers to be
1229 ALL - DOMAIN_ENUM. */
1231 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1232 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1234 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1235 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1239 if (!prefix_ok(str1,"WrLehD")) return False;
1240 if (!check_server_info(uLevel,str2)) return False;
1242 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1243 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1244 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1246 if (strcmp(str1, "WrLehDz") == 0) {
1247 StrnCpy(domain, p, sizeof(fstring)-1);
1249 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1252 if (lp_browse_list())
1253 total = get_server_info(servertype,&servers,domain);
1255 data_len = fixed_len = string_len = 0;
1258 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1261 char *lastname=NULL;
1263 for (i=0;i<total;i++)
1265 struct srv_info_struct *s = &servers[i];
1266 if (lastname && strequal(lastname,s->name)) continue;
1268 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1269 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1270 s->name, s->type, s->comment, s->domain));
1272 if (data_len <= buf_len) {
1275 string_len += s_len;
1282 *rdata_len = fixed_len + string_len;
1283 *rdata = REALLOC(*rdata,*rdata_len);
1284 memset(*rdata,'\0',*rdata_len);
1286 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1292 char *lastname=NULL;
1293 int count2 = counted;
1294 for (i = 0; i < total && count2;i++)
1296 struct srv_info_struct *s = &servers[i];
1297 if (lastname && strequal(lastname,s->name)) continue;
1299 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1300 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1301 s->name, s->type, s->comment, s->domain));
1307 *rparam = REALLOC(*rparam,*rparam_len);
1308 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1310 SSVAL(*rparam,4,counted);
1311 SSVAL(*rparam,6,counted+missed);
1313 if (servers) free(servers);
1315 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1316 domain,uLevel,counted,counted+missed));
1321 /****************************************************************************
1322 command 0x34 - suspected of being a "Lookup Names" stub api
1323 ****************************************************************************/
1324 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1325 int mdrcnt, int mprcnt, char **rdata,
1326 char **rparam, int *rdata_len, int *rparam_len)
1328 char *str1 = param+2;
1329 char *str2 = skip_string(str1,1);
1330 char *p = skip_string(str2,1);
1331 int uLevel = SVAL(p,0);
1332 int buf_len = SVAL(p,2);
1336 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1337 str1, str2, p, uLevel, buf_len));
1339 if (!prefix_ok(str1,"zWrLeh")) return False;
1344 *rparam = REALLOC(*rparam,*rparam_len);
1346 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1348 SSVAL(*rparam,4,counted);
1349 SSVAL(*rparam,6,counted+missed);
1354 /****************************************************************************
1355 get info about a share
1356 ****************************************************************************/
1357 static BOOL check_share_info(int uLevel, char* id)
1361 if (strcmp(id,"B13") != 0) return False;
1364 if (strcmp(id,"B13BWz") != 0) return False;
1367 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1370 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1372 default: return False;
1377 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1378 char** buf, int* buflen,
1379 char** stringbuf, int* stringspace, char* baseaddr)
1388 case 0: struct_len = 13; break;
1389 case 1: struct_len = 20; break;
1390 case 2: struct_len = 40; break;
1391 case 91: struct_len = 68; break;
1399 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1400 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1401 if (buflen) *buflen = struct_len;
1402 if (stringspace) *stringspace = len;
1403 return struct_len + len;
1408 if ((*buflen) < struct_len) return -1;
1416 p2 = p + struct_len;
1417 l2 = (*buflen) - struct_len;
1419 if (!baseaddr) baseaddr = p;
1421 StrnCpy(p,lp_servicename(snum),13);
1427 type = STYPE_DISKTREE;
1428 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1429 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1430 SSVAL(p,14,type); /* device type */
1431 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1432 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1437 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1438 SSVALS(p,22,-1); /* max uses */
1439 SSVAL(p,24,1); /* current uses */
1440 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1441 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1442 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1447 memset(p+40,0,SHPWLEN+2);
1459 (*buf) = p + struct_len;
1460 (*buflen) -= struct_len;
1462 (*stringspace) = l2;
1472 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1473 int mdrcnt,int mprcnt,
1474 char **rdata,char **rparam,
1475 int *rdata_len,int *rparam_len)
1477 char *str1 = param+2;
1478 char *str2 = skip_string(str1,1);
1479 char *netname = skip_string(str2,1);
1480 char *p = skip_string(netname,1);
1481 int uLevel = SVAL(p,0);
1482 int snum = find_service(netname);
1484 if (snum < 0) return False;
1486 /* check it's a supported varient */
1487 if (!prefix_ok(str1,"zWrLh")) return False;
1488 if (!check_share_info(uLevel,str2)) return False;
1490 *rdata = REALLOC(*rdata,mdrcnt);
1492 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1493 if (*rdata_len < 0) return False;
1496 *rparam = REALLOC(*rparam,*rparam_len);
1497 SSVAL(*rparam,0,NERR_Success);
1498 SSVAL(*rparam,2,0); /* converter word */
1499 SSVAL(*rparam,4,*rdata_len);
1504 /****************************************************************************
1505 view list of shares available
1506 ****************************************************************************/
1507 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1508 int mdrcnt,int mprcnt,
1509 char **rdata,char **rparam,
1510 int *rdata_len,int *rparam_len)
1512 char *str1 = param+2;
1513 char *str2 = skip_string(str1,1);
1514 char *p = skip_string(str2,1);
1515 int uLevel = SVAL(p,0);
1516 int buf_len = SVAL(p,2);
1518 int count=lp_numservices();
1519 int total=0,counted=0;
1520 BOOL missed = False;
1522 int data_len, fixed_len, string_len;
1523 int f_len = 0, s_len = 0;
1525 if (!prefix_ok(str1,"WrLeh")) return False;
1526 if (!check_share_info(uLevel,str2)) return False;
1528 data_len = fixed_len = string_len = 0;
1529 for (i=0;i<count;i++)
1530 if (lp_browseable(i) && lp_snum_ok(i))
1533 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1534 if (data_len <= buf_len)
1538 string_len += s_len;
1543 *rdata_len = fixed_len + string_len;
1544 *rdata = REALLOC(*rdata,*rdata_len);
1545 memset(*rdata,0,*rdata_len);
1547 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1551 for (i = 0; i < count;i++)
1552 if (lp_browseable(i) && lp_snum_ok(i))
1553 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1557 *rparam = REALLOC(*rparam,*rparam_len);
1558 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1560 SSVAL(*rparam,4,counted);
1561 SSVAL(*rparam,6,total);
1563 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1564 counted,total,uLevel,
1565 buf_len,*rdata_len,mdrcnt));
1571 /****************************************************************************
1572 get the time of day info
1573 ****************************************************************************/
1574 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1575 int mdrcnt,int mprcnt,
1576 char **rdata,char **rparam,
1577 int *rdata_len,int *rparam_len)
1581 *rparam = REALLOC(*rparam,*rparam_len);
1584 *rdata = REALLOC(*rdata,*rdata_len);
1586 SSVAL(*rparam,0,NERR_Success);
1587 SSVAL(*rparam,2,0); /* converter word */
1593 time_t unixdate = time(NULL);
1595 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1596 by NT in a "net time" operation,
1597 it seems to ignore the one below */
1599 /* the client expects to get localtime, not GMT, in this bit
1600 (I think, this needs testing) */
1601 t = LocalTime(&unixdate);
1603 SIVAL(p,4,0); /* msecs ? */
1604 CVAL(p,8) = t->tm_hour;
1605 CVAL(p,9) = t->tm_min;
1606 CVAL(p,10) = t->tm_sec;
1607 CVAL(p,11) = 0; /* hundredths of seconds */
1608 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1609 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1610 CVAL(p,16) = t->tm_mday;
1611 CVAL(p,17) = t->tm_mon + 1;
1612 SSVAL(p,18,1900+t->tm_year);
1613 CVAL(p,20) = t->tm_wday;
1620 /****************************************************************************
1621 Set the user password.
1622 *****************************************************************************/
1624 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1625 int mdrcnt,int mprcnt,
1626 char **rdata,char **rparam,
1627 int *rdata_len,int *rparam_len)
1629 char *p = skip_string(param+2,2);
1631 fstring pass1,pass2;
1635 p = skip_string(p,1);
1637 memset(pass1,'\0',sizeof(pass1));
1638 memset(pass2,'\0',sizeof(pass2));
1640 memcpy(pass2,p+16,16);
1643 *rparam = REALLOC(*rparam,*rparam_len);
1647 SSVAL(*rparam,0,NERR_badpass);
1648 SSVAL(*rparam,2,0); /* converter word */
1650 DEBUG(3,("Set password for <%s>\n",user));
1653 * Pass the user through the NT -> unix user mapping
1657 (void)map_username(user);
1660 * Do any UNIX username case mangling.
1662 (void)Get_Pwnam( user, True);
1665 * Attempt to verify the old password against smbpasswd entries
1666 * Win98 clients send old and new password in plaintext for this call.
1670 fstring saved_pass2;
1671 struct smb_passwd *smbpw = NULL;
1674 * Save the new password as change_oem_password overwrites it
1678 fstrcpy(saved_pass2, pass2);
1680 if (check_plaintext_password(user,pass1,strlen(pass1),&smbpw) &&
1681 change_oem_password(smbpw,pass2,False))
1683 SSVAL(*rparam,0,NERR_Success);
1686 * If unix password sync was requested, attempt to change
1687 * the /etc/passwd database also. Return failure if this cannot
1691 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1692 SSVAL(*rparam,0,NERR_badpass);
1697 * If the above failed, attempt the plaintext password change.
1698 * This tests against the /etc/passwd database only.
1701 if(SVAL(*rparam,0) != NERR_Success)
1703 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1704 chgpasswd(user,pass1,pass2,False))
1706 SSVAL(*rparam,0,NERR_Success);
1711 * If the plaintext change failed, attempt
1712 * the old encrypted method. NT will generate this
1713 * after trying the samr method. Note that this
1714 * method is done as a last resort as this
1715 * password change method loses the NT password hash
1716 * and cannot change the UNIX password as no plaintext
1720 if(SVAL(*rparam,0) != NERR_Success)
1722 struct smb_passwd *sampw = NULL;
1724 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) &&
1725 change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
1727 SSVAL(*rparam,0,NERR_Success);
1731 memset((char *)pass1,'\0',sizeof(fstring));
1732 memset((char *)pass2,'\0',sizeof(fstring));
1737 /****************************************************************************
1738 Set the user password (SamOEM version - gets plaintext).
1739 ****************************************************************************/
1741 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1742 int mdrcnt,int mprcnt,
1743 char **rdata,char **rparam,
1744 int *rdata_len,int *rparam_len)
1747 char *p = param + 2;
1749 *rparam = REALLOC(*rparam,*rparam_len);
1753 SSVAL(*rparam,0,NERR_badpass);
1756 * Check the parameter definition is correct.
1758 if(!strequal(param + 2, "zsT")) {
1759 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1762 p = skip_string(p, 1);
1764 if(!strequal(p, "B516B16")) {
1765 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1768 p = skip_string(p,1);
1771 p = skip_string(p,1);
1773 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1776 * Pass the user through the NT -> unix user mapping
1780 (void)map_username(user);
1783 * Do any UNIX username case mangling.
1785 (void)Get_Pwnam( user, True);
1787 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1789 SSVAL(*rparam,0,NERR_Success);
1795 /****************************************************************************
1798 ****************************************************************************/
1799 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1800 int mdrcnt,int mprcnt,
1801 char **rdata,char **rparam,
1802 int *rdata_len,int *rparam_len)
1804 int function = SVAL(param,0);
1805 char *str1 = param+2;
1806 char *str2 = skip_string(str1,1);
1807 char *p = skip_string(str2,1);
1809 extern struct current_user current_user;
1813 /* check it's a supported varient */
1814 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1818 *rparam = REALLOC(*rparam,*rparam_len);
1821 if (!print_job_exists(jobid)) {
1822 errcode = NERR_JobNotFound;
1826 errcode = NERR_notsupported;
1829 case 81: /* delete */
1830 if (print_job_delete(¤t_user, jobid))
1831 errcode = NERR_Success;
1833 case 82: /* pause */
1834 if (print_job_pause(¤t_user, jobid))
1835 errcode = NERR_Success;
1837 case 83: /* resume */
1838 if (print_job_resume(¤t_user, jobid))
1839 errcode = NERR_Success;
1844 SSVAL(*rparam,0,errcode);
1845 SSVAL(*rparam,2,0); /* converter word */
1850 /****************************************************************************
1851 Purge a print queue - or pause or resume it.
1852 ****************************************************************************/
1853 static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
1854 int mdrcnt,int mprcnt,
1855 char **rdata,char **rparam,
1856 int *rdata_len,int *rparam_len)
1858 int function = SVAL(param,0);
1859 char *str1 = param+2;
1860 char *str2 = skip_string(str1,1);
1861 char *QueueName = skip_string(str2,1);
1862 int errcode = NERR_notsupported;
1865 /* check it's a supported varient */
1866 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1870 *rparam = REALLOC(*rparam,*rparam_len);
1873 snum = print_queue_snum(QueueName);
1876 errcode = NERR_JobNotFound;
1881 case 74: /* Pause queue */
1882 if (print_queue_pause(NULL, snum)) errcode = NERR_Success;
1884 case 75: /* Resume queue */
1885 if (print_queue_resume(NULL, snum)) errcode = NERR_Success;
1887 case 103: /* Purge */
1888 if (print_queue_purge(NULL, snum)) errcode = NERR_Success;
1893 SSVAL(*rparam,0,errcode);
1894 SSVAL(*rparam,2,0); /* converter word */
1900 /****************************************************************************
1901 set the property of a print job (undocumented?)
1902 ? function = 0xb -> set name of print job
1903 ? function = 0x6 -> move print job up/down
1904 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1905 or <WWsTP> <WB21BB16B10zWWzDDz>
1906 ****************************************************************************/
1907 static int check_printjob_info(struct pack_desc* desc,
1908 int uLevel, char* id)
1910 desc->subformat = NULL;
1912 case 0: desc->format = "W"; break;
1913 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1914 case 2: desc->format = "WWzWWDDzz"; break;
1915 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1916 default: return False;
1918 if (strcmp(desc->format,id) != 0) return False;
1922 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1923 int mdrcnt,int mprcnt,
1924 char **rdata,char **rparam,
1925 int *rdata_len,int *rparam_len)
1927 struct pack_desc desc;
1928 char *str1 = param+2;
1929 char *str2 = skip_string(str1,1);
1930 char *p = skip_string(str2,1);
1932 int uLevel = SVAL(p,2);
1933 int function = SVAL(p,4);
1938 *rparam = REALLOC(*rparam,*rparam_len);
1942 /* check it's a supported varient */
1943 if ((strcmp(str1,"WWsTP")) ||
1944 (!check_printjob_info(&desc,uLevel,str2)))
1947 if (!print_job_exists(jobid)) {
1948 errcode=NERR_JobNotFound;
1952 errcode = NERR_notsupported;
1956 /* change job place in the queue,
1957 data gives the new place */
1958 place = SVAL(data,0);
1959 if (print_job_set_place(jobid, place)) {
1960 errcode=NERR_Success;
1965 /* change print job name, data gives the name */
1966 if (print_job_set_name(jobid, data)) {
1967 errcode=NERR_Success;
1976 SSVALS(*rparam,0,errcode);
1977 SSVAL(*rparam,2,0); /* converter word */
1983 /****************************************************************************
1984 get info about the server
1985 ****************************************************************************/
1986 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1987 int mdrcnt,int mprcnt,
1988 char **rdata,char **rparam,
1989 int *rdata_len,int *rparam_len)
1991 char *str1 = param+2;
1992 char *str2 = skip_string(str1,1);
1993 char *p = skip_string(str2,1);
1994 int uLevel = SVAL(p,0);
1998 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2000 /* check it's a supported varient */
2001 if (!prefix_ok(str1,"WrLh")) return False;
2004 if (strcmp(str2,"B16") != 0) return False;
2008 if (strcmp(str2,"B16BBDz") != 0) return False;
2012 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2017 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2022 if (strcmp(str2,"DN") != 0) return False;
2026 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2029 default: return False;
2032 *rdata_len = mdrcnt;
2033 *rdata = REALLOC(*rdata,*rdata_len);
2036 p2 = p + struct_len;
2038 StrnCpy(p,local_machine,16);
2044 struct srv_info_struct *servers=NULL;
2047 uint32 servertype= lp_default_server_announce();
2049 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2051 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2052 for (i=0;i<count;i++)
2053 if (strequal(servers[i].name,local_machine))
2055 servertype = servers[i].type;
2056 pstrcpy(comment,servers[i].comment);
2059 if (servers) free(servers);
2061 SCVAL(p,0,lp_major_announce_version());
2062 SCVAL(p,1,lp_minor_announce_version());
2063 SIVAL(p,2,servertype);
2065 if (mdrcnt == struct_len) {
2068 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2069 standard_sub_conn(conn,comment);
2070 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2071 p2 = skip_string(p2,1);
2076 return False; /* not yet implemented */
2079 *rdata_len = PTR_DIFF(p2,*rdata);
2082 *rparam = REALLOC(*rparam,*rparam_len);
2083 SSVAL(*rparam,0,NERR_Success);
2084 SSVAL(*rparam,2,0); /* converter word */
2085 SSVAL(*rparam,4,*rdata_len);
2091 /****************************************************************************
2092 get info about the server
2093 ****************************************************************************/
2094 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2095 int mdrcnt,int mprcnt,
2096 char **rdata,char **rparam,
2097 int *rdata_len,int *rparam_len)
2099 char *str1 = param+2;
2100 char *str2 = skip_string(str1,1);
2101 char *p = skip_string(str2,1);
2103 extern pstring sesssetup_user;
2104 int level = SVAL(p,0);
2106 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2109 *rparam = REALLOC(*rparam,*rparam_len);
2111 /* check it's a supported varient */
2112 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2115 *rdata_len = mdrcnt + 1024;
2116 *rdata = REALLOC(*rdata,*rdata_len);
2118 SSVAL(*rparam,0,NERR_Success);
2119 SSVAL(*rparam,2,0); /* converter word */
2125 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2126 pstrcpy(p2,local_machine);
2128 p2 = skip_string(p2,1);
2131 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2132 pstrcpy(p2,sesssetup_user);
2133 p2 = skip_string(p2,1);
2136 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2137 pstrcpy(p2,global_myworkgroup);
2139 p2 = skip_string(p2,1);
2142 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2143 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2146 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2147 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2148 p2 = skip_string(p2,1);
2151 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2153 p2 = skip_string(p2,1);
2156 *rdata_len = PTR_DIFF(p2,*rdata);
2158 SSVAL(*rparam,4,*rdata_len);
2163 /****************************************************************************
2164 get info about a user
2166 struct user_info_11 {
2167 char usri11_name[21]; 0-20
2169 char *usri11_comment; 22-25
2170 char *usri11_usr_comment; 26-29
2171 unsigned short usri11_priv; 30-31
2172 unsigned long usri11_auth_flags; 32-35
2173 long usri11_password_age; 36-39
2174 char *usri11_homedir; 40-43
2175 char *usri11_parms; 44-47
2176 long usri11_last_logon; 48-51
2177 long usri11_last_logoff; 52-55
2178 unsigned short usri11_bad_pw_count; 56-57
2179 unsigned short usri11_num_logons; 58-59
2180 char *usri11_logon_server; 60-63
2181 unsigned short usri11_country_code; 64-65
2182 char *usri11_workstations; 66-69
2183 unsigned long usri11_max_storage; 70-73
2184 unsigned short usri11_units_per_week; 74-75
2185 unsigned char *usri11_logon_hours; 76-79
2186 unsigned short usri11_code_page; 80-81
2191 usri11_name specifies the user name for which information is retireved
2193 usri11_pad aligns the next data structure element to a word boundary
2195 usri11_comment is a null terminated ASCII comment
2197 usri11_user_comment is a null terminated ASCII comment about the user
2199 usri11_priv specifies the level of the privilege assigned to the user.
2200 The possible values are:
2202 Name Value Description
2203 USER_PRIV_GUEST 0 Guest privilege
2204 USER_PRIV_USER 1 User privilege
2205 USER_PRV_ADMIN 2 Administrator privilege
2207 usri11_auth_flags specifies the account operator privileges. The
2208 possible values are:
2210 Name Value Description
2211 AF_OP_PRINT 0 Print operator
2214 Leach, Naik [Page 28]
\r\f
2217 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2220 AF_OP_COMM 1 Communications operator
2221 AF_OP_SERVER 2 Server operator
2222 AF_OP_ACCOUNTS 3 Accounts operator
2225 usri11_password_age specifies how many seconds have elapsed since the
2226 password was last changed.
2228 usri11_home_dir points to a null terminated ASCII string that contains
2229 the path name of the user's home directory.
2231 usri11_parms points to a null terminated ASCII string that is set
2232 aside for use by applications.
2234 usri11_last_logon specifies the time when the user last logged on.
2235 This value is stored as the number of seconds elapsed since
2236 00:00:00, January 1, 1970.
2238 usri11_last_logoff specifies the time when the user last logged off.
2239 This value is stored as the number of seconds elapsed since
2240 00:00:00, January 1, 1970. A value of 0 means the last logoff
2243 usri11_bad_pw_count specifies the number of incorrect passwords
2244 entered since the last successful logon.
2246 usri11_log1_num_logons specifies the number of times this user has
2247 logged on. A value of -1 means the number of logons is unknown.
2249 usri11_logon_server points to a null terminated ASCII string that
2250 contains the name of the server to which logon requests are sent.
2251 A null string indicates logon requests should be sent to the
2254 usri11_country_code specifies the country code for the user's language
2257 usri11_workstations points to a null terminated ASCII string that
2258 contains the names of workstations the user may log on from.
2259 There may be up to 8 workstations, with the names separated by
2260 commas. A null strings indicates there are no restrictions.
2262 usri11_max_storage specifies the maximum amount of disk space the user
2263 can occupy. A value of 0xffffffff indicates there are no
2266 usri11_units_per_week specifies the equal number of time units into
2267 which a week is divided. This value must be equal to 168.
2269 usri11_logon_hours points to a 21 byte (168 bits) string that
2270 specifies the time during which the user can log on. Each bit
2271 represents one unique hour in a week. The first bit (bit 0, word
2272 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2276 Leach, Naik [Page 29]
\r\f
2279 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2282 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2283 are no restrictions.
2285 usri11_code_page specifies the code page for the user's language of
2288 All of the pointers in this data structure need to be treated
2289 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2290 to be ignored. The converter word returned in the parameters section
2291 needs to be subtracted from the lower 16 bits to calculate an offset
2292 into the return buffer where this ASCII string resides.
2294 There is no auxiliary data in the response.
2296 ****************************************************************************/
2298 #define usri11_name 0
2299 #define usri11_pad 21
2300 #define usri11_comment 22
2301 #define usri11_usr_comment 26
2302 #define usri11_full_name 30
2303 #define usri11_priv 34
2304 #define usri11_auth_flags 36
2305 #define usri11_password_age 40
2306 #define usri11_homedir 44
2307 #define usri11_parms 48
2308 #define usri11_last_logon 52
2309 #define usri11_last_logoff 56
2310 #define usri11_bad_pw_count 60
2311 #define usri11_num_logons 62
2312 #define usri11_logon_server 64
2313 #define usri11_country_code 68
2314 #define usri11_workstations 70
2315 #define usri11_max_storage 74
2316 #define usri11_units_per_week 78
2317 #define usri11_logon_hours 80
2318 #define usri11_code_page 84
2319 #define usri11_end 86
2321 #define USER_PRIV_GUEST 0
2322 #define USER_PRIV_USER 1
2323 #define USER_PRIV_ADMIN 2
2325 #define AF_OP_PRINT 0
2326 #define AF_OP_COMM 1
2327 #define AF_OP_SERVER 2
2328 #define AF_OP_ACCOUNTS 3
2331 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2332 int mdrcnt,int mprcnt,
2333 char **rdata,char **rparam,
2334 int *rdata_len,int *rparam_len)
2336 char *str1 = param+2;
2337 char *str2 = skip_string(str1,1);
2338 char *UserName = skip_string(str2,1);
2339 char *p = skip_string(UserName,1);
2340 int uLevel = SVAL(p,0);
2343 /* get NIS home of a previously validated user - simeon */
2344 /* With share level security vuid will always be zero.
2345 Don't depend on vuser being non-null !!. JRA */
2346 user_struct *vuser = get_valid_user_struct(vuid);
2348 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2349 vuser->user.unix_name));
2352 *rparam = REALLOC(*rparam,*rparam_len);
2354 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2356 /* check it's a supported variant */
2357 if (strcmp(str1,"zWrLh") != 0) return False;
2360 case 0: p2 = "B21"; break;
2361 case 1: p2 = "B21BB16DWzzWz"; break;
2362 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2363 case 10: p2 = "B21Bzzz"; break;
2364 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2365 default: return False;
2368 if (strcmp(p2,str2) != 0) return False;
2370 *rdata_len = mdrcnt + 1024;
2371 *rdata = REALLOC(*rdata,*rdata_len);
2373 SSVAL(*rparam,0,NERR_Success);
2374 SSVAL(*rparam,2,0); /* converter word */
2377 p2 = p + usri11_end;
2380 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2384 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2389 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2390 pstrcpy(p2,"Comment");
2391 p2 = skip_string(p2,1);
2393 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2394 pstrcpy(p2,"UserComment");
2395 p2 = skip_string(p2,1);
2397 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2398 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2399 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2400 p2 = skip_string(p2,1);
2403 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2405 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2406 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2407 SIVALS(p,usri11_password_age,-1); /* password age */
2408 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2409 pstrcpy(p2, lp_logon_home());
2410 p2 = skip_string(p2,1);
2411 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2413 p2 = skip_string(p2,1);
2414 SIVAL(p,usri11_last_logon,0); /* last logon */
2415 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2416 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2417 SSVALS(p,usri11_num_logons,-1); /* num logons */
2418 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2419 pstrcpy(p2,"\\\\*");
2420 p2 = skip_string(p2,1);
2421 SSVAL(p,usri11_country_code,0); /* country code */
2423 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2425 p2 = skip_string(p2,1);
2427 SIVALS(p,usri11_max_storage,-1); /* max storage */
2428 SSVAL(p,usri11_units_per_week,168); /* units per week */
2429 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2431 /* a simple way to get logon hours at all times. */
2433 SCVAL(p2,21,0); /* fix zero termination */
2434 p2 = skip_string(p2,1);
2436 SSVAL(p,usri11_code_page,0); /* code page */
2438 if (uLevel == 1 || uLevel == 2)
2440 memset(p+22,' ',16); /* password */
2441 SIVALS(p,38,-1); /* password age */
2443 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2444 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2445 pstrcpy(p2,lp_logon_home());
2446 p2 = skip_string(p2,1);
2447 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2449 SSVAL(p,52,0); /* flags */
2450 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2451 pstrcpy(p2,lp_logon_script());
2452 standard_sub_conn( conn, p2 );
2453 p2 = skip_string(p2,1);
2456 SIVAL(p,60,0); /* auth_flags */
2457 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2458 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2459 p2 = skip_string(p2,1);
2460 SIVAL(p,68,0); /* urs_comment */
2461 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2463 p2 = skip_string(p2,1);
2464 SIVAL(p,76,0); /* workstations */
2465 SIVAL(p,80,0); /* last_logon */
2466 SIVAL(p,84,0); /* last_logoff */
2467 SIVALS(p,88,-1); /* acct_expires */
2468 SIVALS(p,92,-1); /* max_storage */
2469 SSVAL(p,96,168); /* units_per_week */
2470 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2473 SSVALS(p,102,-1); /* bad_pw_count */
2474 SSVALS(p,104,-1); /* num_logons */
2475 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2476 pstrcpy(p2,"\\\\%L");
2477 standard_sub_conn(conn, p2);
2478 p2 = skip_string(p2,1);
2479 SSVAL(p,110,49); /* country_code */
2480 SSVAL(p,112,860); /* code page */
2484 *rdata_len = PTR_DIFF(p2,*rdata);
2486 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2491 /*******************************************************************
2492 get groups that a user is a member of
2493 ******************************************************************/
2494 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2495 int mdrcnt,int mprcnt,
2496 char **rdata,char **rparam,
2497 int *rdata_len,int *rparam_len)
2499 char *str1 = param+2;
2500 char *str2 = skip_string(str1,1);
2501 char *UserName = skip_string(str2,1);
2502 char *p = skip_string(UserName,1);
2503 int uLevel = SVAL(p,0);
2508 *rparam = REALLOC(*rparam,*rparam_len);
2510 /* check it's a supported varient */
2511 if (strcmp(str1,"zWrLeh") != 0) return False;
2513 case 0: p2 = "B21"; break;
2514 default: return False;
2516 if (strcmp(p2,str2) != 0) return False;
2518 *rdata_len = mdrcnt + 1024;
2519 *rdata = REALLOC(*rdata,*rdata_len);
2521 SSVAL(*rparam,0,NERR_Success);
2522 SSVAL(*rparam,2,0); /* converter word */
2526 /* XXXX we need a real SAM database some day */
2527 pstrcpy(p,"Users"); p += 21; count++;
2528 pstrcpy(p,"Domain Users"); p += 21; count++;
2529 pstrcpy(p,"Guests"); p += 21; count++;
2530 pstrcpy(p,"Domain Guests"); p += 21; count++;
2532 *rdata_len = PTR_DIFF(p,*rdata);
2534 SSVAL(*rparam,4,count); /* is this right?? */
2535 SSVAL(*rparam,6,count); /* is this right?? */
2541 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2542 int mdrcnt,int mprcnt,
2543 char **rdata,char **rparam,
2544 int *rdata_len,int *rparam_len)
2546 char *str1 = param+2;
2547 char *str2 = skip_string(str1,1);
2548 char *p = skip_string(str2,1);
2550 struct pack_desc desc;
2556 memset((char *)&desc,'\0',sizeof(desc));
2558 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2560 /* check it's a supported varient */
2561 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2562 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2563 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2565 desc.buflen = mdrcnt;
2566 desc.subformat = NULL;
2569 if (init_package(&desc,1,0))
2571 PACKI(&desc,"W",0); /* code */
2572 PACKS(&desc,"B21",name); /* eff. name */
2573 PACKS(&desc,"B",""); /* pad */
2575 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2576 PACKI(&desc,"D",0); /* auth flags XXX */
2577 PACKI(&desc,"W",0); /* num logons */
2578 PACKI(&desc,"W",0); /* bad pw count */
2579 PACKI(&desc,"D",0); /* last logon */
2580 PACKI(&desc,"D",-1); /* last logoff */
2581 PACKI(&desc,"D",-1); /* logoff time */
2582 PACKI(&desc,"D",-1); /* kickoff time */
2583 PACKI(&desc,"D",0); /* password age */
2584 PACKI(&desc,"D",0); /* password can change */
2585 PACKI(&desc,"D",-1); /* password must change */
2588 fstrcpy(mypath,"\\\\");
2589 fstrcat(mypath,local_machine);
2591 PACKS(&desc,"z",mypath); /* computer */
2593 PACKS(&desc,"z",global_myworkgroup);/* domain */
2595 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2596 /* made sure all macros are fully substituted and available */
2598 pstring logon_script;
2599 pstrcpy(logon_script,lp_logon_script());
2600 standard_sub_conn( conn, logon_script );
2601 PACKS(&desc,"z", logon_script); /* script path */
2603 /* End of JHT mods */
2605 PACKI(&desc,"D",0x00000000); /* reserved */
2608 *rdata_len = desc.usedlen;
2610 *rparam = REALLOC(*rparam,*rparam_len);
2611 SSVALS(*rparam,0,desc.errcode);
2613 SSVAL(*rparam,4,desc.neededlen);
2615 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2620 /****************************************************************************
2621 api_WAccessGetUserPerms
2622 ****************************************************************************/
2623 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2624 int mdrcnt,int mprcnt,
2625 char **rdata,char **rparam,
2626 int *rdata_len,int *rparam_len)
2628 char *str1 = param+2;
2629 char *str2 = skip_string(str1,1);
2630 char *user = skip_string(str2,1);
2631 char *resource = skip_string(user,1);
2633 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2635 /* check it's a supported varient */
2636 if (strcmp(str1,"zzh") != 0) return False;
2637 if (strcmp(str2,"") != 0) return False;
2640 *rparam = REALLOC(*rparam,*rparam_len);
2641 SSVALS(*rparam,0,0); /* errorcode */
2642 SSVAL(*rparam,2,0); /* converter word */
2643 SSVAL(*rparam,4,0x7f); /* permission flags */
2648 /****************************************************************************
2649 api_WPrintJobEnumerate
2650 ****************************************************************************/
2651 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2652 int mdrcnt,int mprcnt,
2653 char **rdata,char **rparam,
2654 int *rdata_len,int *rparam_len)
2656 char *str1 = param+2;
2657 char *str2 = skip_string(str1,1);
2658 char *p = skip_string(str2,1);
2664 struct pack_desc desc;
2665 print_queue_struct *queue=NULL;
2666 print_status_struct status;
2670 memset((char *)&desc,'\0',sizeof(desc));
2671 memset((char *)&status,'\0',sizeof(status));
2673 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2675 /* check it's a supported varient */
2676 if (strcmp(str1,"WWrLh") != 0) return False;
2677 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2680 snum = print_job_snum(job);
2682 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2684 count = print_queue_status(snum,&queue,&status);
2685 for (i = 0; i < count; i++) {
2686 if (queue[i].job == job) break;
2688 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2690 desc.buflen = mdrcnt;
2692 if (init_package(&desc,1,0)) {
2694 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2695 *rdata_len = desc.usedlen;
2698 desc.errcode = NERR_JobNotFound;
2704 *rparam = REALLOC(*rparam,*rparam_len);
2705 SSVALS(*rparam,0,desc.errcode);
2707 SSVAL(*rparam,4,desc.neededlen);
2709 if (queue) free(queue);
2711 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2715 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2716 int mdrcnt,int mprcnt,
2717 char **rdata,char **rparam,
2718 int *rdata_len,int *rparam_len)
2720 char *str1 = param+2;
2721 char *str2 = skip_string(str1,1);
2722 char *p = skip_string(str2,1);
2728 struct pack_desc desc;
2729 print_queue_struct *queue=NULL;
2730 print_status_struct status;
2732 memset((char *)&desc,'\0',sizeof(desc));
2733 memset((char *)&status,'\0',sizeof(status));
2735 p = skip_string(p,1);
2738 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2740 /* check it's a supported varient */
2741 if (strcmp(str1,"zWrLeh") != 0) return False;
2742 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2743 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2745 snum = lp_servicenumber(name);
2746 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2747 int pnum = lp_servicenumber(PRINTERS_NAME);
2749 lp_add_printer(name,pnum);
2750 snum = lp_servicenumber(name);
2754 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2756 count = print_queue_status(snum,&queue,&status);
2757 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2759 desc.buflen = mdrcnt;
2761 if (init_package(&desc,count,0)) {
2763 for (i = 0; i < count; i++) {
2764 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2765 if (desc.errcode == NERR_Success) succnt = i+1;
2769 *rdata_len = desc.usedlen;
2772 *rparam = REALLOC(*rparam,*rparam_len);
2773 SSVALS(*rparam,0,desc.errcode);
2775 SSVAL(*rparam,4,succnt);
2776 SSVAL(*rparam,6,count);
2778 if (queue) free(queue);
2780 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2784 static int check_printdest_info(struct pack_desc* desc,
2785 int uLevel, char* id)
2787 desc->subformat = NULL;
2789 case 0: desc->format = "B9"; break;
2790 case 1: desc->format = "B9B21WWzW"; break;
2791 case 2: desc->format = "z"; break;
2792 case 3: desc->format = "zzzWWzzzWW"; break;
2793 default: return False;
2795 if (strcmp(desc->format,id) != 0) return False;
2799 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2800 struct pack_desc* desc)
2803 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2804 buf[sizeof(buf)-1] = 0;
2807 PACKS(desc,"B9",buf); /* szName */
2809 PACKS(desc,"B21",""); /* szUserName */
2810 PACKI(desc,"W",0); /* uJobId */
2811 PACKI(desc,"W",0); /* fsStatus */
2812 PACKS(desc,"z",""); /* pszStatus */
2813 PACKI(desc,"W",0); /* time */
2816 if (uLevel == 2 || uLevel == 3) {
2817 PACKS(desc,"z",buf); /* pszPrinterName */
2819 PACKS(desc,"z",""); /* pszUserName */
2820 PACKS(desc,"z",""); /* pszLogAddr */
2821 PACKI(desc,"W",0); /* uJobId */
2822 PACKI(desc,"W",0); /* fsStatus */
2823 PACKS(desc,"z",""); /* pszStatus */
2824 PACKS(desc,"z",""); /* pszComment */
2825 PACKS(desc,"z","NULL"); /* pszDrivers */
2826 PACKI(desc,"W",0); /* time */
2827 PACKI(desc,"W",0); /* pad1 */
2832 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2833 int mdrcnt,int mprcnt,
2834 char **rdata,char **rparam,
2835 int *rdata_len,int *rparam_len)
2837 char *str1 = param+2;
2838 char *str2 = skip_string(str1,1);
2839 char *p = skip_string(str2,1);
2840 char* PrinterName = p;
2842 struct pack_desc desc;
2845 memset((char *)&desc,'\0',sizeof(desc));
2847 p = skip_string(p,1);
2850 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2852 /* check it's a supported varient */
2853 if (strcmp(str1,"zWrLh") != 0) return False;
2854 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2856 snum = lp_servicenumber(PrinterName);
2857 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2858 int pnum = lp_servicenumber(PRINTERS_NAME);
2860 lp_add_printer(PrinterName,pnum);
2861 snum = lp_servicenumber(PrinterName);
2867 desc.errcode = NERR_DestNotFound;
2871 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2873 desc.buflen = mdrcnt;
2874 if (init_package(&desc,1,0)) {
2875 fill_printdest_info(conn,snum,uLevel,&desc);
2877 *rdata_len = desc.usedlen;
2881 *rparam = REALLOC(*rparam,*rparam_len);
2882 SSVALS(*rparam,0,desc.errcode);
2884 SSVAL(*rparam,4,desc.neededlen);
2886 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2890 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2891 int mdrcnt,int mprcnt,
2892 char **rdata,char **rparam,
2893 int *rdata_len,int *rparam_len)
2895 char *str1 = param+2;
2896 char *str2 = skip_string(str1,1);
2897 char *p = skip_string(str2,1);
2901 struct pack_desc desc;
2902 int services = lp_numservices();
2904 memset((char *)&desc,'\0',sizeof(desc));
2908 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2910 /* check it's a supported varient */
2911 if (strcmp(str1,"WrLeh") != 0) return False;
2912 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2915 for (i = 0; i < services; i++)
2916 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2919 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2921 desc.buflen = mdrcnt;
2922 if (init_package(&desc,queuecnt,0)) {
2925 for (i = 0; i < services; i++) {
2926 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2927 fill_printdest_info(conn,i,uLevel,&desc);
2929 if (desc.errcode == NERR_Success) succnt = n;
2934 *rdata_len = desc.usedlen;
2937 *rparam = REALLOC(*rparam,*rparam_len);
2938 SSVALS(*rparam,0,desc.errcode);
2940 SSVAL(*rparam,4,succnt);
2941 SSVAL(*rparam,6,queuecnt);
2943 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2947 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2948 int mdrcnt,int mprcnt,
2949 char **rdata,char **rparam,
2950 int *rdata_len,int *rparam_len)
2952 char *str1 = param+2;
2953 char *str2 = skip_string(str1,1);
2954 char *p = skip_string(str2,1);
2957 struct pack_desc desc;
2959 memset((char *)&desc,'\0',sizeof(desc));
2963 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2965 /* check it's a supported varient */
2966 if (strcmp(str1,"WrLeh") != 0) return False;
2967 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2969 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2971 desc.buflen = mdrcnt;
2972 if (init_package(&desc,1,0)) {
2973 PACKS(&desc,"B41","NULL");
2976 succnt = (desc.errcode == NERR_Success ? 1 : 0);
2978 *rdata_len = desc.usedlen;
2981 *rparam = REALLOC(*rparam,*rparam_len);
2982 SSVALS(*rparam,0,desc.errcode);
2984 SSVAL(*rparam,4,succnt);
2987 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2991 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2992 int mdrcnt,int mprcnt,
2993 char **rdata,char **rparam,
2994 int *rdata_len,int *rparam_len)
2996 char *str1 = param+2;
2997 char *str2 = skip_string(str1,1);
2998 char *p = skip_string(str2,1);
3001 struct pack_desc desc;
3003 memset((char *)&desc,'\0',sizeof(desc));
3007 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3009 /* check it's a supported varient */
3010 if (strcmp(str1,"WrLeh") != 0) return False;
3011 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3013 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3015 desc.buflen = mdrcnt;
3017 if (init_package(&desc,1,0)) {
3018 PACKS(&desc,"B13","lpd");
3021 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3023 *rdata_len = desc.usedlen;
3026 *rparam = REALLOC(*rparam,*rparam_len);
3027 SSVALS(*rparam,0,desc.errcode);
3029 SSVAL(*rparam,4,succnt);
3032 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3036 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3037 int mdrcnt,int mprcnt,
3038 char **rdata,char **rparam,
3039 int *rdata_len,int *rparam_len)
3041 char *str1 = param+2;
3042 char *str2 = skip_string(str1,1);
3043 char *p = skip_string(str2,1);
3046 struct pack_desc desc;
3048 memset((char *)&desc,'\0',sizeof(desc));
3052 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3054 /* check it's a supported varient */
3055 if (strcmp(str1,"WrLeh") != 0) return False;
3056 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3058 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3059 memset((char *)&desc,'\0',sizeof(desc));
3061 desc.buflen = mdrcnt;
3063 if (init_package(&desc,1,0)) {
3064 PACKS(&desc,"B13","lp0");
3067 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3069 *rdata_len = desc.usedlen;
3072 *rparam = REALLOC(*rparam,*rparam_len);
3073 SSVALS(*rparam,0,desc.errcode);
3075 SSVAL(*rparam,4,succnt);
3078 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3082 /****************************************************************************
3083 The buffer was too small
3084 ****************************************************************************/
3086 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3087 int mdrcnt,int mprcnt,
3088 char **rdata,char **rparam,
3089 int *rdata_len,int *rparam_len)
3091 *rparam_len = MIN(*rparam_len,mprcnt);
3092 *rparam = REALLOC(*rparam,*rparam_len);
3096 SSVAL(*rparam,0,NERR_BufTooSmall);
3098 DEBUG(3,("Supplied buffer too small in API command\n"));
3104 /****************************************************************************
3105 The request is not supported
3106 ****************************************************************************/
3108 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3109 int mdrcnt,int mprcnt,
3110 char **rdata,char **rparam,
3111 int *rdata_len,int *rparam_len)
3114 *rparam = REALLOC(*rparam,*rparam_len);
3118 SSVAL(*rparam,0,NERR_notsupported);
3119 SSVAL(*rparam,2,0); /* converter word */
3121 DEBUG(3,("Unsupported API command\n"));
3133 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3134 int,int,char **,char **,int *,int *);
3136 } api_commands[] = {
3137 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3138 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3139 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3140 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3141 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3142 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3143 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3144 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3145 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3146 {"WPrintQueuePause", 74, api_WPrintQueuePurge,0},
3147 {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
3148 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3149 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3150 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3151 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3152 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3153 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3154 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3155 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3156 {"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
3157 {"NetServerEnum", 104, api_RNetServerEnum,0},
3158 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3159 {"SetUserPassword", 115, api_SetUserPassword,0},
3160 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3161 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3162 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3163 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3164 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3165 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3166 {NULL, -1, api_Unsupported,0}};
3169 /****************************************************************************
3170 Handle remote api calls
3171 ****************************************************************************/
3173 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3174 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3178 char *rparam = NULL;
3185 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3189 api_command = SVAL(params,0);
3191 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3194 skip_string(params+2,1),
3195 tdscnt,tpscnt,mdrcnt,mprcnt));
3197 for (i=0;api_commands[i].name;i++) {
3198 if (api_commands[i].id == api_command && api_commands[i].fn) {
3199 DEBUG(3,("Doing %s\n",api_commands[i].name));
3204 rdata = (char *)malloc(1024);
3206 memset(rdata,'\0',1024);
3208 rparam = (char *)malloc(1024);
3210 memset(rparam,'\0',1024);
3212 if(!rdata || !rparam) {
3213 DEBUG(0,("api_reply: malloc fail !\n"));
3217 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3218 &rdata,&rparam,&rdata_len,&rparam_len);
3221 if (rdata_len > mdrcnt ||
3222 rparam_len > mprcnt) {
3223 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3224 &rdata,&rparam,&rdata_len,&rparam_len);
3227 /* if we get False back then it's actually unsupported */
3229 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3230 &rdata,&rparam,&rdata_len,&rparam_len);
3232 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);