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)
498 pstring tok,driver,datafile,langmon,helpfile,datatype;
502 lines = file_lines_load(lp_driverfile(snum),NULL);
504 DEBUG(3,("fill_printq_info: Can't open %s - %s\n",
505 lp_driverfile(snum),strerror(errno)));
506 desc->errcode=NERR_notsupported;
510 /* lookup the long printer driver name in the file
512 for (i=0;lines[i] && !ok;i++) {
514 if (next_token(&p,tok,":",sizeof(tok)) &&
515 (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
516 (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
521 file_lines_free(lines);
523 /* driver file name */
524 if (ok && !next_token(&p,driver,":",sizeof(driver))) ok = 0;
526 if (ok && !next_token(&p,datafile,":",sizeof(datafile))) ok = 0;
528 * for the next tokens - which may be empty - I have
529 * to check for empty tokens first because the
530 * next_token function will skip all empty token
537 } else if (!next_token(&p,helpfile,":",sizeof(helpfile))) ok = 0;
541 /* language monitor */
545 } else if (!next_token(&p,langmon,":",sizeof(langmon)))
549 /* default data type */
550 if (ok && !next_token(&p,datatype,":",sizeof(datatype)))
554 PACKI(desc,"W",0x0400); /* don't know */
555 PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */
556 PACKS(desc,"z",driver); /* Driverfile Name */
557 PACKS(desc,"z",datafile); /* Datafile name */
558 PACKS(desc,"z",langmon); /* language monitor */
559 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
560 PACKS(desc,"z",datatype); /* default data type */
561 PACKS(desc,"z",helpfile); /* helpfile name */
562 PACKS(desc,"z",driver); /* driver name */
563 DEBUG(3,("Driver:%s:\n",driver));
564 DEBUG(3,("Data File:%s:\n",datafile));
565 DEBUG(3,("Language Monitor:%s:\n",langmon));
566 DEBUG(3,("Data Type:%s:\n",datatype));
567 DEBUG(3,("Help File:%s:\n",helpfile));
568 PACKI(desc,"N",count); /* number of files to copy */
569 for (i=0;i<count;i++) {
570 /* no need to check return value here
571 * - it was already tested in
572 * get_printerdrivernumber */
573 next_token(&p,tok,",",sizeof(tok));
574 PACKS(desc,"z",tok); /* driver files to copy */
575 DEBUG(3,("file:%s:\n",tok));
578 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
579 SERVICE(snum),count));
581 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
582 desc->errcode=NERR_notsupported;
588 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
589 struct pack_desc* desc,
590 int count, print_queue_struct* queue,
591 print_status_struct* status)
596 PACKS(desc,"B13",SERVICE(snum));
601 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
604 PACKI(desc,"K",printq_status(status->status));
608 if (uLevel == 1 || uLevel == 2) {
609 PACKS(desc,"B",""); /* alignment */
610 PACKI(desc,"W",5); /* priority */
611 PACKI(desc,"W",0); /* start time */
612 PACKI(desc,"W",0); /* until time */
613 PACKS(desc,"z",""); /* pSepFile */
614 PACKS(desc,"z","lpd"); /* pPrProc */
615 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
616 PACKS(desc,"z",""); /* pParms */
618 PACKS(desc,"z","UNKNOWN PRINTER");
619 PACKI(desc,"W",LPSTAT_ERROR);
621 else if (!status || !status->message[0]) {
622 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
623 PACKI(desc,"W",LPSTAT_OK); /* status */
625 PACKS(desc,"z",status->message);
626 PACKI(desc,"W",printq_status(status->status)); /* status */
628 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
631 if (uLevel == 3 || uLevel == 4) {
632 PACKI(desc,"W",5); /* uPriority */
633 PACKI(desc,"W",0); /* uStarttime */
634 PACKI(desc,"W",0); /* uUntiltime */
635 PACKI(desc,"W",5); /* pad1 */
636 PACKS(desc,"z",""); /* pszSepFile */
637 PACKS(desc,"z","WinPrint"); /* pszPrProc */
638 PACKS(desc,"z",""); /* pszParms */
639 if (!status || !status->message[0]) {
640 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
641 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
643 PACKS(desc,"z",status->message); /* pszComment */
644 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
646 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
647 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
648 PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */
649 PackDriverData(desc); /* pDriverData */
652 if (uLevel == 2 || uLevel == 4) {
654 for (i=0;i<count;i++)
655 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
659 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
663 /* This function returns the number of files for a given driver */
664 static int get_printerdrivernumber(int snum)
671 lines = file_lines_load(lp_driverfile(snum), NULL);
673 DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",
674 lp_driverfile(snum),strerror(errno)));
678 /* lookup the long printer driver name in the file description */
679 for (i=0;lines[i] && !ok; i++) {
681 if (next_token(&p,tok,":",sizeof(tok)) &&
682 (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
687 file_lines_free(lines);
693 if (*p++ == ':') i--;
698 /* count the number of files */
699 while (next_token(&p,tok,",",sizeof(tok)))
707 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
708 uint16 vuid, char *param,char *data,
709 int mdrcnt,int mprcnt,
710 char **rdata,char **rparam,
711 int *rdata_len,int *rparam_len)
713 char *str1 = param+2;
714 char *str2 = skip_string(str1,1);
715 char *p = skip_string(str2,1);
721 struct pack_desc desc;
722 print_queue_struct *queue=NULL;
723 print_status_struct status;
725 memset((char *)&status,'\0',sizeof(status));
726 memset((char *)&desc,'\0',sizeof(desc));
728 p = skip_string(p,1);
732 /* remove any trailing username */
733 if ((p = strchr(QueueName,'%'))) *p = 0;
735 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
737 /* check it's a supported varient */
738 if (!prefix_ok(str1,"zWrLh")) return False;
739 if (!check_printq_info(&desc,uLevel,str2,str3)) {
741 * Patch from Scott Moomaw <scott@bridgewater.edu>
742 * to return the 'invalid info level' error if an
743 * unknown level was requested.
747 *rparam = REALLOC(*rparam,*rparam_len);
748 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
754 snum = lp_servicenumber(QueueName);
755 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
756 int pnum = lp_servicenumber(PRINTERS_NAME);
758 lp_add_printer(QueueName,pnum);
759 snum = lp_servicenumber(QueueName);
763 if (snum < 0 || !VALID_SNUM(snum)) return(False);
766 count = get_printerdrivernumber(snum);
767 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
769 count = print_queue_status(snum, &queue,&status);
772 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
774 desc.buflen = mdrcnt;
775 if (init_package(&desc,1,count)) {
776 desc.subcount = count;
777 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
778 } else if(uLevel == 0) {
781 * This is a *disgusting* hack.
782 * This is *so* bad that even I'm embarrassed (and I
783 * have no shame). Here's the deal :
784 * Until we get the correct SPOOLSS code into smbd
785 * then when we're running with NT SMB support then
786 * NT makes this call with a level of zero, and then
787 * immediately follows it with an open request to
788 * the \\SRVSVC pipe. If we allow that open to
789 * succeed then NT barfs when it cannot open the
790 * \\SPOOLSS pipe immediately after and continually
791 * whines saying "Printer name is invalid" forever
792 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
793 * to fail, then NT downgrades to using the downlevel code
794 * and everything works as well as before. I hate
795 * myself for adding this code.... JRA.
798 fail_next_srvsvc_open();
802 *rdata_len = desc.usedlen;
805 *rparam = REALLOC(*rparam,*rparam_len);
806 SSVALS(*rparam,0,desc.errcode);
808 SSVAL(*rparam,4,desc.neededlen);
810 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
812 if (queue) free(queue);
818 /****************************************************************************
819 view list of all print jobs on all queues
820 ****************************************************************************/
821 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
822 int mdrcnt, int mprcnt,
823 char **rdata, char** rparam,
824 int *rdata_len, int *rparam_len)
826 char *param_format = param+2;
827 char *output_format1 = skip_string(param_format,1);
828 char *p = skip_string(output_format1,1);
829 int uLevel = SVAL(p,0);
830 char *output_format2 = p + 4;
831 int services = lp_numservices();
833 struct pack_desc desc;
834 print_queue_struct **queue = NULL;
835 print_status_struct *status = NULL;
836 int* subcntarr = NULL;
837 int queuecnt, subcnt=0, succnt=0;
839 memset((char *)&desc,'\0',sizeof(desc));
841 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
843 if (!prefix_ok(param_format,"WrLeh")) return False;
844 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
846 * Patch from Scott Moomaw <scott@bridgewater.edu>
847 * to return the 'invalid info level' error if an
848 * unknown level was requested.
852 *rparam = REALLOC(*rparam,*rparam_len);
853 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
860 for (i = 0; i < services; i++)
861 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
864 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
865 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
868 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
869 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
870 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
873 memset(status,0,queuecnt*sizeof(print_status_struct));
874 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
875 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
880 for (i = 0; i < services; i++)
881 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
882 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
883 subcnt += subcntarr[n];
887 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
889 desc.buflen = mdrcnt;
891 if (init_package(&desc,queuecnt,subcnt)) {
894 for (i = 0; i < services; i++)
895 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
896 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
898 if (desc.errcode == NERR_Success) succnt = n;
902 if (subcntarr) free(subcntarr);
904 *rdata_len = desc.usedlen;
906 *rparam = REALLOC(*rparam,*rparam_len);
907 SSVALS(*rparam,0,desc.errcode);
909 SSVAL(*rparam,4,succnt);
910 SSVAL(*rparam,6,queuecnt);
912 for (i = 0; i < queuecnt; i++) {
913 if (queue && queue[i]) free(queue[i]);
916 if (queue) free(queue);
917 if (status) free(status);
922 /****************************************************************************
923 get info level for a server list query
924 ****************************************************************************/
925 static BOOL check_server_info(int uLevel, char* id)
929 if (strcmp(id,"B16") != 0) return False;
932 if (strcmp(id,"B16BBDz") != 0) return False;
940 struct srv_info_struct
950 /*******************************************************************
951 get server info lists from the files saved by nmbd. Return the
953 ******************************************************************/
954 static int get_server_info(uint32 servertype,
955 struct srv_info_struct **servers,
961 BOOL local_list_only;
964 lines = file_lines_load(lock_path(SERVER_LIST), NULL);
966 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
970 /* request for everything is code for request all servers */
971 if (servertype == SV_TYPE_ALL)
972 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
974 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
976 DEBUG(4,("Servertype search: %8x\n",servertype));
978 for (i=0;lines[i];i++) {
980 struct srv_info_struct *s;
981 char *ptr = lines[i];
986 if (count == alloced) {
988 (*servers) = (struct srv_info_struct *)
989 Realloc(*servers,sizeof(**servers)*alloced);
990 if (!(*servers)) return(0);
991 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
993 s = &(*servers)[count];
995 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
996 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
997 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
998 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
999 /* this allows us to cope with an old nmbd */
1000 pstrcpy(s->domain,global_myworkgroup);
1003 if (sscanf(stype,"%X",&s->type) != 1) {
1004 DEBUG(4,("r:host file "));
1008 /* Filter the servers/domains we return based on what was asked for. */
1010 /* Check to see if we are being asked for a local list only. */
1011 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1012 DEBUG(4,("r: local list only"));
1016 /* doesn't match up: don't want it */
1017 if (!(servertype & s->type)) {
1018 DEBUG(4,("r:serv type "));
1022 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1023 (s->type & SV_TYPE_DOMAIN_ENUM))
1025 DEBUG(4,("s: dom mismatch "));
1029 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1034 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1035 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1039 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1040 s->name, s->type, s->comment, s->domain));
1042 s->server_added = True;
1047 DEBUG(4,("%20s %8x %25s %15s\n",
1048 s->name, s->type, s->comment, s->domain));
1052 file_lines_free(lines);
1057 /*******************************************************************
1058 fill in a server info structure
1059 ******************************************************************/
1060 static int fill_srv_info(struct srv_info_struct *service,
1061 int uLevel, char **buf, int *buflen,
1062 char **stringbuf, int *stringspace, char *baseaddr)
1071 case 0: struct_len = 16; break;
1072 case 1: struct_len = 26; break;
1082 len = strlen(service->comment)+1;
1086 if (buflen) *buflen = struct_len;
1087 if (stringspace) *stringspace = len;
1088 return struct_len + len;
1093 if (*buflen < struct_len) return -1;
1101 p2 = p + struct_len;
1102 l2 = *buflen - struct_len;
1104 if (!baseaddr) baseaddr = p;
1109 StrnCpy(p,service->name,15);
1113 StrnCpy(p,service->name,15);
1114 SIVAL(p,18,service->type);
1115 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1116 len += CopyAndAdvance(&p2,service->comment,&l2);
1122 *buf = p + struct_len;
1123 *buflen -= struct_len;
1136 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1138 return(strcmp(s1->name,s2->name));
1141 /****************************************************************************
1142 view list of servers available (or possibly domains). The info is
1143 extracted from lists saved by nmbd on the local host
1144 ****************************************************************************/
1145 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1146 int mdrcnt, int mprcnt, char **rdata,
1147 char **rparam, int *rdata_len, int *rparam_len)
1149 char *str1 = param+2;
1150 char *str2 = skip_string(str1,1);
1151 char *p = skip_string(str2,1);
1152 int uLevel = SVAL(p,0);
1153 int buf_len = SVAL(p,2);
1154 uint32 servertype = IVAL(p,4);
1156 int data_len, fixed_len, string_len;
1157 int f_len = 0, s_len = 0;
1158 struct srv_info_struct *servers=NULL;
1159 int counted=0,total=0;
1162 BOOL domain_request;
1165 /* If someone sets all the bits they don't really mean to set
1166 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1169 if (servertype == SV_TYPE_ALL)
1170 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1172 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1173 any other bit (they may just set this bit on it's own) they
1174 want all the locally seen servers. However this bit can be
1175 set on its own so set the requested servers to be
1176 ALL - DOMAIN_ENUM. */
1178 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1179 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1181 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1182 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1186 if (!prefix_ok(str1,"WrLehD")) return False;
1187 if (!check_server_info(uLevel,str2)) return False;
1189 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1190 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1191 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1193 if (strcmp(str1, "WrLehDz") == 0) {
1194 StrnCpy(domain, p, sizeof(fstring)-1);
1196 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1199 if (lp_browse_list())
1200 total = get_server_info(servertype,&servers,domain);
1202 data_len = fixed_len = string_len = 0;
1205 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1208 char *lastname=NULL;
1210 for (i=0;i<total;i++)
1212 struct srv_info_struct *s = &servers[i];
1213 if (lastname && strequal(lastname,s->name)) continue;
1215 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1216 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1217 s->name, s->type, s->comment, s->domain));
1219 if (data_len <= buf_len) {
1222 string_len += s_len;
1229 *rdata_len = fixed_len + string_len;
1230 *rdata = REALLOC(*rdata,*rdata_len);
1231 memset(*rdata,'\0',*rdata_len);
1233 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1239 char *lastname=NULL;
1240 int count2 = counted;
1241 for (i = 0; i < total && count2;i++)
1243 struct srv_info_struct *s = &servers[i];
1244 if (lastname && strequal(lastname,s->name)) continue;
1246 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1247 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1248 s->name, s->type, s->comment, s->domain));
1254 *rparam = REALLOC(*rparam,*rparam_len);
1255 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1257 SSVAL(*rparam,4,counted);
1258 SSVAL(*rparam,6,counted+missed);
1260 if (servers) free(servers);
1262 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1263 domain,uLevel,counted,counted+missed));
1268 /****************************************************************************
1269 command 0x34 - suspected of being a "Lookup Names" stub api
1270 ****************************************************************************/
1271 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1272 int mdrcnt, int mprcnt, char **rdata,
1273 char **rparam, int *rdata_len, int *rparam_len)
1275 char *str1 = param+2;
1276 char *str2 = skip_string(str1,1);
1277 char *p = skip_string(str2,1);
1278 int uLevel = SVAL(p,0);
1279 int buf_len = SVAL(p,2);
1283 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1284 str1, str2, p, uLevel, buf_len));
1286 if (!prefix_ok(str1,"zWrLeh")) return False;
1291 *rparam = REALLOC(*rparam,*rparam_len);
1293 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1295 SSVAL(*rparam,4,counted);
1296 SSVAL(*rparam,6,counted+missed);
1301 /****************************************************************************
1302 get info about a share
1303 ****************************************************************************/
1304 static BOOL check_share_info(int uLevel, char* id)
1308 if (strcmp(id,"B13") != 0) return False;
1311 if (strcmp(id,"B13BWz") != 0) return False;
1314 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1317 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1319 default: return False;
1324 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1325 char** buf, int* buflen,
1326 char** stringbuf, int* stringspace, char* baseaddr)
1335 case 0: struct_len = 13; break;
1336 case 1: struct_len = 20; break;
1337 case 2: struct_len = 40; break;
1338 case 91: struct_len = 68; break;
1346 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1347 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1348 if (buflen) *buflen = struct_len;
1349 if (stringspace) *stringspace = len;
1350 return struct_len + len;
1355 if ((*buflen) < struct_len) return -1;
1363 p2 = p + struct_len;
1364 l2 = (*buflen) - struct_len;
1366 if (!baseaddr) baseaddr = p;
1368 StrnCpy(p,lp_servicename(snum),13);
1374 type = STYPE_DISKTREE;
1375 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1376 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1377 SSVAL(p,14,type); /* device type */
1378 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1379 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1384 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1385 SSVALS(p,22,-1); /* max uses */
1386 SSVAL(p,24,1); /* current uses */
1387 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1388 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1389 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1394 memset(p+40,0,SHPWLEN+2);
1406 (*buf) = p + struct_len;
1407 (*buflen) -= struct_len;
1409 (*stringspace) = l2;
1419 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1420 int mdrcnt,int mprcnt,
1421 char **rdata,char **rparam,
1422 int *rdata_len,int *rparam_len)
1424 char *str1 = param+2;
1425 char *str2 = skip_string(str1,1);
1426 char *netname = skip_string(str2,1);
1427 char *p = skip_string(netname,1);
1428 int uLevel = SVAL(p,0);
1429 int snum = find_service(netname);
1431 if (snum < 0) return False;
1433 /* check it's a supported varient */
1434 if (!prefix_ok(str1,"zWrLh")) return False;
1435 if (!check_share_info(uLevel,str2)) return False;
1437 *rdata = REALLOC(*rdata,mdrcnt);
1439 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1440 if (*rdata_len < 0) return False;
1443 *rparam = REALLOC(*rparam,*rparam_len);
1444 SSVAL(*rparam,0,NERR_Success);
1445 SSVAL(*rparam,2,0); /* converter word */
1446 SSVAL(*rparam,4,*rdata_len);
1451 /****************************************************************************
1452 view list of shares available
1453 ****************************************************************************/
1454 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1455 int mdrcnt,int mprcnt,
1456 char **rdata,char **rparam,
1457 int *rdata_len,int *rparam_len)
1459 char *str1 = param+2;
1460 char *str2 = skip_string(str1,1);
1461 char *p = skip_string(str2,1);
1462 int uLevel = SVAL(p,0);
1463 int buf_len = SVAL(p,2);
1465 int count=lp_numservices();
1466 int total=0,counted=0;
1467 BOOL missed = False;
1469 int data_len, fixed_len, string_len;
1470 int f_len = 0, s_len = 0;
1472 if (!prefix_ok(str1,"WrLeh")) return False;
1473 if (!check_share_info(uLevel,str2)) return False;
1475 data_len = fixed_len = string_len = 0;
1476 for (i=0;i<count;i++)
1477 if (lp_browseable(i) && lp_snum_ok(i))
1480 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1481 if (data_len <= buf_len)
1485 string_len += s_len;
1490 *rdata_len = fixed_len + string_len;
1491 *rdata = REALLOC(*rdata,*rdata_len);
1492 memset(*rdata,0,*rdata_len);
1494 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1498 for (i = 0; i < count;i++)
1499 if (lp_browseable(i) && lp_snum_ok(i))
1500 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1504 *rparam = REALLOC(*rparam,*rparam_len);
1505 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1507 SSVAL(*rparam,4,counted);
1508 SSVAL(*rparam,6,total);
1510 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1511 counted,total,uLevel,
1512 buf_len,*rdata_len,mdrcnt));
1518 /****************************************************************************
1519 get the time of day info
1520 ****************************************************************************/
1521 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1522 int mdrcnt,int mprcnt,
1523 char **rdata,char **rparam,
1524 int *rdata_len,int *rparam_len)
1528 *rparam = REALLOC(*rparam,*rparam_len);
1531 *rdata = REALLOC(*rdata,*rdata_len);
1533 SSVAL(*rparam,0,NERR_Success);
1534 SSVAL(*rparam,2,0); /* converter word */
1540 time_t unixdate = time(NULL);
1542 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1543 by NT in a "net time" operation,
1544 it seems to ignore the one below */
1546 /* the client expects to get localtime, not GMT, in this bit
1547 (I think, this needs testing) */
1548 t = LocalTime(&unixdate);
1550 SIVAL(p,4,0); /* msecs ? */
1551 CVAL(p,8) = t->tm_hour;
1552 CVAL(p,9) = t->tm_min;
1553 CVAL(p,10) = t->tm_sec;
1554 CVAL(p,11) = 0; /* hundredths of seconds */
1555 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1556 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1557 CVAL(p,16) = t->tm_mday;
1558 CVAL(p,17) = t->tm_mon + 1;
1559 SSVAL(p,18,1900+t->tm_year);
1560 CVAL(p,20) = t->tm_wday;
1567 /****************************************************************************
1568 Set the user password.
1569 *****************************************************************************/
1571 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1572 int mdrcnt,int mprcnt,
1573 char **rdata,char **rparam,
1574 int *rdata_len,int *rparam_len)
1576 char *p = skip_string(param+2,2);
1578 fstring pass1,pass2;
1582 p = skip_string(p,1);
1584 memset(pass1,'\0',sizeof(pass1));
1585 memset(pass2,'\0',sizeof(pass2));
1587 memcpy(pass2,p+16,16);
1590 *rparam = REALLOC(*rparam,*rparam_len);
1594 SSVAL(*rparam,0,NERR_badpass);
1595 SSVAL(*rparam,2,0); /* converter word */
1597 DEBUG(3,("Set password for <%s>\n",user));
1600 * Pass the user through the NT -> unix user mapping
1604 (void)map_username(user);
1607 * Do any UNIX username case mangling.
1609 (void)Get_Pwnam( user, True);
1612 * Attempt to verify the old password against smbpasswd entries
1613 * Win98 clients send old and new password in plaintext for this call.
1617 fstring saved_pass2;
1618 struct smb_passwd *smbpw = NULL;
1621 * Save the new password as change_oem_password overwrites it
1625 fstrcpy(saved_pass2, pass2);
1627 if (check_plaintext_password(user,pass1,strlen(pass1),&smbpw) &&
1628 change_oem_password(smbpw,pass2,False))
1630 SSVAL(*rparam,0,NERR_Success);
1633 * If unix password sync was requested, attempt to change
1634 * the /etc/passwd database also. Return failure if this cannot
1638 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1639 SSVAL(*rparam,0,NERR_badpass);
1644 * If the above failed, attempt the plaintext password change.
1645 * This tests against the /etc/passwd database only.
1648 if(SVAL(*rparam,0) != NERR_Success)
1650 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1651 chgpasswd(user,pass1,pass2,False))
1653 SSVAL(*rparam,0,NERR_Success);
1658 * If the plaintext change failed, attempt
1659 * the old encrypted method. NT will generate this
1660 * after trying the samr method. Note that this
1661 * method is done as a last resort as this
1662 * password change method loses the NT password hash
1663 * and cannot change the UNIX password as no plaintext
1667 if(SVAL(*rparam,0) != NERR_Success)
1669 struct smb_passwd *sampw = NULL;
1671 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) &&
1672 change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
1674 SSVAL(*rparam,0,NERR_Success);
1678 memset((char *)pass1,'\0',sizeof(fstring));
1679 memset((char *)pass2,'\0',sizeof(fstring));
1684 /****************************************************************************
1685 Set the user password (SamOEM version - gets plaintext).
1686 ****************************************************************************/
1688 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1689 int mdrcnt,int mprcnt,
1690 char **rdata,char **rparam,
1691 int *rdata_len,int *rparam_len)
1694 char *p = param + 2;
1696 *rparam = REALLOC(*rparam,*rparam_len);
1700 SSVAL(*rparam,0,NERR_badpass);
1703 * Check the parameter definition is correct.
1705 if(!strequal(param + 2, "zsT")) {
1706 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1709 p = skip_string(p, 1);
1711 if(!strequal(p, "B516B16")) {
1712 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1715 p = skip_string(p,1);
1718 p = skip_string(p,1);
1720 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1723 * Pass the user through the NT -> unix user mapping
1727 (void)map_username(user);
1730 * Do any UNIX username case mangling.
1732 (void)Get_Pwnam( user, True);
1734 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1736 SSVAL(*rparam,0,NERR_Success);
1742 /****************************************************************************
1745 ****************************************************************************/
1746 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1747 int mdrcnt,int mprcnt,
1748 char **rdata,char **rparam,
1749 int *rdata_len,int *rparam_len)
1751 int function = SVAL(param,0);
1752 char *str1 = param+2;
1753 char *str2 = skip_string(str1,1);
1754 char *p = skip_string(str2,1);
1759 /* check it's a supported varient */
1760 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1764 *rparam = REALLOC(*rparam,*rparam_len);
1767 if (!print_job_exists(jobid)) {
1768 errcode = NERR_JobNotFound;
1772 errcode = NERR_notsupported;
1775 case 81: /* delete */
1776 if (print_job_delete(NULL, jobid)) errcode = NERR_Success;
1778 case 82: /* pause */
1779 if (print_job_pause(NULL, jobid)) errcode = NERR_Success;
1781 case 83: /* resume */
1782 if (print_job_resume(NULL, jobid)) errcode = NERR_Success;
1787 SSVAL(*rparam,0,errcode);
1788 SSVAL(*rparam,2,0); /* converter word */
1793 /****************************************************************************
1794 Purge a print queue - or pause or resume it.
1795 ****************************************************************************/
1796 static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
1797 int mdrcnt,int mprcnt,
1798 char **rdata,char **rparam,
1799 int *rdata_len,int *rparam_len)
1801 int function = SVAL(param,0);
1802 char *str1 = param+2;
1803 char *str2 = skip_string(str1,1);
1804 char *QueueName = skip_string(str2,1);
1805 int errcode = NERR_notsupported;
1808 /* check it's a supported varient */
1809 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1813 *rparam = REALLOC(*rparam,*rparam_len);
1816 snum = print_queue_snum(QueueName);
1819 errcode = NERR_JobNotFound;
1824 case 74: /* Pause queue */
1825 if (print_queue_pause(NULL, snum)) errcode = NERR_Success;
1827 case 75: /* Resume queue */
1828 if (print_queue_resume(NULL, snum)) errcode = NERR_Success;
1830 case 103: /* Purge */
1831 if (print_queue_purge(NULL, snum)) errcode = NERR_Success;
1836 SSVAL(*rparam,0,errcode);
1837 SSVAL(*rparam,2,0); /* converter word */
1843 /****************************************************************************
1844 set the property of a print job (undocumented?)
1845 ? function = 0xb -> set name of print job
1846 ? function = 0x6 -> move print job up/down
1847 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1848 or <WWsTP> <WB21BB16B10zWWzDDz>
1849 ****************************************************************************/
1850 static int check_printjob_info(struct pack_desc* desc,
1851 int uLevel, char* id)
1853 desc->subformat = NULL;
1855 case 0: desc->format = "W"; break;
1856 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1857 case 2: desc->format = "WWzWWDDzz"; break;
1858 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1859 default: return False;
1861 if (strcmp(desc->format,id) != 0) return False;
1865 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1866 int mdrcnt,int mprcnt,
1867 char **rdata,char **rparam,
1868 int *rdata_len,int *rparam_len)
1870 struct pack_desc desc;
1871 char *str1 = param+2;
1872 char *str2 = skip_string(str1,1);
1873 char *p = skip_string(str2,1);
1875 int uLevel = SVAL(p,2);
1876 int function = SVAL(p,4);
1881 *rparam = REALLOC(*rparam,*rparam_len);
1885 /* check it's a supported varient */
1886 if ((strcmp(str1,"WWsTP")) ||
1887 (!check_printjob_info(&desc,uLevel,str2)))
1890 if (!print_job_exists(jobid)) {
1891 errcode=NERR_JobNotFound;
1895 errcode = NERR_notsupported;
1899 /* change job place in the queue,
1900 data gives the new place */
1901 place = SVAL(data,0);
1902 if (print_job_set_place(jobid, place)) {
1903 errcode=NERR_Success;
1908 /* change print job name, data gives the name */
1909 if (print_job_set_name(jobid, data)) {
1910 errcode=NERR_Success;
1919 SSVALS(*rparam,0,errcode);
1920 SSVAL(*rparam,2,0); /* converter word */
1926 /****************************************************************************
1927 get info about the server
1928 ****************************************************************************/
1929 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1930 int mdrcnt,int mprcnt,
1931 char **rdata,char **rparam,
1932 int *rdata_len,int *rparam_len)
1934 char *str1 = param+2;
1935 char *str2 = skip_string(str1,1);
1936 char *p = skip_string(str2,1);
1937 int uLevel = SVAL(p,0);
1941 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
1943 /* check it's a supported varient */
1944 if (!prefix_ok(str1,"WrLh")) return False;
1947 if (strcmp(str2,"B16") != 0) return False;
1951 if (strcmp(str2,"B16BBDz") != 0) return False;
1955 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
1960 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
1965 if (strcmp(str2,"DN") != 0) return False;
1969 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
1972 default: return False;
1975 *rdata_len = mdrcnt;
1976 *rdata = REALLOC(*rdata,*rdata_len);
1979 p2 = p + struct_len;
1981 StrnCpy(p,local_machine,16);
1987 struct srv_info_struct *servers=NULL;
1990 uint32 servertype= lp_default_server_announce();
1992 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
1994 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
1995 for (i=0;i<count;i++)
1996 if (strequal(servers[i].name,local_machine))
1998 servertype = servers[i].type;
1999 pstrcpy(comment,servers[i].comment);
2002 if (servers) free(servers);
2004 SCVAL(p,0,lp_major_announce_version());
2005 SCVAL(p,1,lp_minor_announce_version());
2006 SIVAL(p,2,servertype);
2008 if (mdrcnt == struct_len) {
2011 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2012 standard_sub_conn(conn,comment);
2013 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2014 p2 = skip_string(p2,1);
2019 return False; /* not yet implemented */
2022 *rdata_len = PTR_DIFF(p2,*rdata);
2025 *rparam = REALLOC(*rparam,*rparam_len);
2026 SSVAL(*rparam,0,NERR_Success);
2027 SSVAL(*rparam,2,0); /* converter word */
2028 SSVAL(*rparam,4,*rdata_len);
2034 /****************************************************************************
2035 get info about the server
2036 ****************************************************************************/
2037 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2038 int mdrcnt,int mprcnt,
2039 char **rdata,char **rparam,
2040 int *rdata_len,int *rparam_len)
2042 char *str1 = param+2;
2043 char *str2 = skip_string(str1,1);
2044 char *p = skip_string(str2,1);
2046 extern pstring sesssetup_user;
2047 int level = SVAL(p,0);
2049 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2052 *rparam = REALLOC(*rparam,*rparam_len);
2054 /* check it's a supported varient */
2055 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2058 *rdata_len = mdrcnt + 1024;
2059 *rdata = REALLOC(*rdata,*rdata_len);
2061 SSVAL(*rparam,0,NERR_Success);
2062 SSVAL(*rparam,2,0); /* converter word */
2068 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2069 pstrcpy(p2,local_machine);
2071 p2 = skip_string(p2,1);
2074 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2075 pstrcpy(p2,sesssetup_user);
2076 p2 = skip_string(p2,1);
2079 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2080 pstrcpy(p2,global_myworkgroup);
2082 p2 = skip_string(p2,1);
2085 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2086 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2089 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2090 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2091 p2 = skip_string(p2,1);
2094 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2096 p2 = skip_string(p2,1);
2099 *rdata_len = PTR_DIFF(p2,*rdata);
2101 SSVAL(*rparam,4,*rdata_len);
2106 /****************************************************************************
2107 get info about a user
2109 struct user_info_11 {
2110 char usri11_name[21]; 0-20
2112 char *usri11_comment; 22-25
2113 char *usri11_usr_comment; 26-29
2114 unsigned short usri11_priv; 30-31
2115 unsigned long usri11_auth_flags; 32-35
2116 long usri11_password_age; 36-39
2117 char *usri11_homedir; 40-43
2118 char *usri11_parms; 44-47
2119 long usri11_last_logon; 48-51
2120 long usri11_last_logoff; 52-55
2121 unsigned short usri11_bad_pw_count; 56-57
2122 unsigned short usri11_num_logons; 58-59
2123 char *usri11_logon_server; 60-63
2124 unsigned short usri11_country_code; 64-65
2125 char *usri11_workstations; 66-69
2126 unsigned long usri11_max_storage; 70-73
2127 unsigned short usri11_units_per_week; 74-75
2128 unsigned char *usri11_logon_hours; 76-79
2129 unsigned short usri11_code_page; 80-81
2134 usri11_name specifies the user name for which information is retireved
2136 usri11_pad aligns the next data structure element to a word boundary
2138 usri11_comment is a null terminated ASCII comment
2140 usri11_user_comment is a null terminated ASCII comment about the user
2142 usri11_priv specifies the level of the privilege assigned to the user.
2143 The possible values are:
2145 Name Value Description
2146 USER_PRIV_GUEST 0 Guest privilege
2147 USER_PRIV_USER 1 User privilege
2148 USER_PRV_ADMIN 2 Administrator privilege
2150 usri11_auth_flags specifies the account operator privileges. The
2151 possible values are:
2153 Name Value Description
2154 AF_OP_PRINT 0 Print operator
2157 Leach, Naik [Page 28]
\r\f
2160 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2163 AF_OP_COMM 1 Communications operator
2164 AF_OP_SERVER 2 Server operator
2165 AF_OP_ACCOUNTS 3 Accounts operator
2168 usri11_password_age specifies how many seconds have elapsed since the
2169 password was last changed.
2171 usri11_home_dir points to a null terminated ASCII string that contains
2172 the path name of the user's home directory.
2174 usri11_parms points to a null terminated ASCII string that is set
2175 aside for use by applications.
2177 usri11_last_logon specifies the time when the user last logged on.
2178 This value is stored as the number of seconds elapsed since
2179 00:00:00, January 1, 1970.
2181 usri11_last_logoff specifies the time when the user last logged off.
2182 This value is stored as the number of seconds elapsed since
2183 00:00:00, January 1, 1970. A value of 0 means the last logoff
2186 usri11_bad_pw_count specifies the number of incorrect passwords
2187 entered since the last successful logon.
2189 usri11_log1_num_logons specifies the number of times this user has
2190 logged on. A value of -1 means the number of logons is unknown.
2192 usri11_logon_server points to a null terminated ASCII string that
2193 contains the name of the server to which logon requests are sent.
2194 A null string indicates logon requests should be sent to the
2197 usri11_country_code specifies the country code for the user's language
2200 usri11_workstations points to a null terminated ASCII string that
2201 contains the names of workstations the user may log on from.
2202 There may be up to 8 workstations, with the names separated by
2203 commas. A null strings indicates there are no restrictions.
2205 usri11_max_storage specifies the maximum amount of disk space the user
2206 can occupy. A value of 0xffffffff indicates there are no
2209 usri11_units_per_week specifies the equal number of time units into
2210 which a week is divided. This value must be equal to 168.
2212 usri11_logon_hours points to a 21 byte (168 bits) string that
2213 specifies the time during which the user can log on. Each bit
2214 represents one unique hour in a week. The first bit (bit 0, word
2215 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2219 Leach, Naik [Page 29]
\r\f
2222 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2225 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2226 are no restrictions.
2228 usri11_code_page specifies the code page for the user's language of
2231 All of the pointers in this data structure need to be treated
2232 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2233 to be ignored. The converter word returned in the parameters section
2234 needs to be subtracted from the lower 16 bits to calculate an offset
2235 into the return buffer where this ASCII string resides.
2237 There is no auxiliary data in the response.
2239 ****************************************************************************/
2241 #define usri11_name 0
2242 #define usri11_pad 21
2243 #define usri11_comment 22
2244 #define usri11_usr_comment 26
2245 #define usri11_full_name 30
2246 #define usri11_priv 34
2247 #define usri11_auth_flags 36
2248 #define usri11_password_age 40
2249 #define usri11_homedir 44
2250 #define usri11_parms 48
2251 #define usri11_last_logon 52
2252 #define usri11_last_logoff 56
2253 #define usri11_bad_pw_count 60
2254 #define usri11_num_logons 62
2255 #define usri11_logon_server 64
2256 #define usri11_country_code 68
2257 #define usri11_workstations 70
2258 #define usri11_max_storage 74
2259 #define usri11_units_per_week 78
2260 #define usri11_logon_hours 80
2261 #define usri11_code_page 84
2262 #define usri11_end 86
2264 #define USER_PRIV_GUEST 0
2265 #define USER_PRIV_USER 1
2266 #define USER_PRIV_ADMIN 2
2268 #define AF_OP_PRINT 0
2269 #define AF_OP_COMM 1
2270 #define AF_OP_SERVER 2
2271 #define AF_OP_ACCOUNTS 3
2274 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2275 int mdrcnt,int mprcnt,
2276 char **rdata,char **rparam,
2277 int *rdata_len,int *rparam_len)
2279 char *str1 = param+2;
2280 char *str2 = skip_string(str1,1);
2281 char *UserName = skip_string(str2,1);
2282 char *p = skip_string(UserName,1);
2283 int uLevel = SVAL(p,0);
2286 /* get NIS home of a previously validated user - simeon */
2287 /* With share level security vuid will always be zero.
2288 Don't depend on vuser being non-null !!. JRA */
2289 user_struct *vuser = get_valid_user_struct(vuid);
2291 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2292 vuser->user.unix_name));
2295 *rparam = REALLOC(*rparam,*rparam_len);
2297 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2299 /* check it's a supported variant */
2300 if (strcmp(str1,"zWrLh") != 0) return False;
2303 case 0: p2 = "B21"; break;
2304 case 1: p2 = "B21BB16DWzzWz"; break;
2305 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2306 case 10: p2 = "B21Bzzz"; break;
2307 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2308 default: return False;
2311 if (strcmp(p2,str2) != 0) return False;
2313 *rdata_len = mdrcnt + 1024;
2314 *rdata = REALLOC(*rdata,*rdata_len);
2316 SSVAL(*rparam,0,NERR_Success);
2317 SSVAL(*rparam,2,0); /* converter word */
2320 p2 = p + usri11_end;
2323 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2327 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2332 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2333 pstrcpy(p2,"Comment");
2334 p2 = skip_string(p2,1);
2336 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2337 pstrcpy(p2,"UserComment");
2338 p2 = skip_string(p2,1);
2340 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2341 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2342 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2343 p2 = skip_string(p2,1);
2346 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2348 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2349 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2350 SIVALS(p,usri11_password_age,-1); /* password age */
2351 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2352 pstrcpy(p2, lp_logon_home());
2353 p2 = skip_string(p2,1);
2354 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2356 p2 = skip_string(p2,1);
2357 SIVAL(p,usri11_last_logon,0); /* last logon */
2358 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2359 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2360 SSVALS(p,usri11_num_logons,-1); /* num logons */
2361 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2362 pstrcpy(p2,"\\\\*");
2363 p2 = skip_string(p2,1);
2364 SSVAL(p,usri11_country_code,0); /* country code */
2366 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2368 p2 = skip_string(p2,1);
2370 SIVALS(p,usri11_max_storage,-1); /* max storage */
2371 SSVAL(p,usri11_units_per_week,168); /* units per week */
2372 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2374 /* a simple way to get logon hours at all times. */
2376 SCVAL(p2,21,0); /* fix zero termination */
2377 p2 = skip_string(p2,1);
2379 SSVAL(p,usri11_code_page,0); /* code page */
2381 if (uLevel == 1 || uLevel == 2)
2383 memset(p+22,' ',16); /* password */
2384 SIVALS(p,38,-1); /* password age */
2386 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2387 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2388 pstrcpy(p2,lp_logon_home());
2389 p2 = skip_string(p2,1);
2390 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2392 SSVAL(p,52,0); /* flags */
2393 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2394 pstrcpy(p2,lp_logon_script());
2395 standard_sub_conn( conn, p2 );
2396 p2 = skip_string(p2,1);
2399 SIVAL(p,60,0); /* auth_flags */
2400 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2401 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2402 p2 = skip_string(p2,1);
2403 SIVAL(p,68,0); /* urs_comment */
2404 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2406 p2 = skip_string(p2,1);
2407 SIVAL(p,76,0); /* workstations */
2408 SIVAL(p,80,0); /* last_logon */
2409 SIVAL(p,84,0); /* last_logoff */
2410 SIVALS(p,88,-1); /* acct_expires */
2411 SIVALS(p,92,-1); /* max_storage */
2412 SSVAL(p,96,168); /* units_per_week */
2413 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2416 SSVALS(p,102,-1); /* bad_pw_count */
2417 SSVALS(p,104,-1); /* num_logons */
2418 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2419 pstrcpy(p2,"\\\\%L");
2420 standard_sub_conn(conn, p2);
2421 p2 = skip_string(p2,1);
2422 SSVAL(p,110,49); /* country_code */
2423 SSVAL(p,112,860); /* code page */
2427 *rdata_len = PTR_DIFF(p2,*rdata);
2429 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2434 /*******************************************************************
2435 get groups that a user is a member of
2436 ******************************************************************/
2437 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2438 int mdrcnt,int mprcnt,
2439 char **rdata,char **rparam,
2440 int *rdata_len,int *rparam_len)
2442 char *str1 = param+2;
2443 char *str2 = skip_string(str1,1);
2444 char *UserName = skip_string(str2,1);
2445 char *p = skip_string(UserName,1);
2446 int uLevel = SVAL(p,0);
2451 *rparam = REALLOC(*rparam,*rparam_len);
2453 /* check it's a supported varient */
2454 if (strcmp(str1,"zWrLeh") != 0) return False;
2456 case 0: p2 = "B21"; break;
2457 default: return False;
2459 if (strcmp(p2,str2) != 0) return False;
2461 *rdata_len = mdrcnt + 1024;
2462 *rdata = REALLOC(*rdata,*rdata_len);
2464 SSVAL(*rparam,0,NERR_Success);
2465 SSVAL(*rparam,2,0); /* converter word */
2469 /* XXXX we need a real SAM database some day */
2470 pstrcpy(p,"Users"); p += 21; count++;
2471 pstrcpy(p,"Domain Users"); p += 21; count++;
2472 pstrcpy(p,"Guests"); p += 21; count++;
2473 pstrcpy(p,"Domain Guests"); p += 21; count++;
2475 *rdata_len = PTR_DIFF(p,*rdata);
2477 SSVAL(*rparam,4,count); /* is this right?? */
2478 SSVAL(*rparam,6,count); /* is this right?? */
2484 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2485 int mdrcnt,int mprcnt,
2486 char **rdata,char **rparam,
2487 int *rdata_len,int *rparam_len)
2489 char *str1 = param+2;
2490 char *str2 = skip_string(str1,1);
2491 char *p = skip_string(str2,1);
2493 struct pack_desc desc;
2499 memset((char *)&desc,'\0',sizeof(desc));
2501 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2503 /* check it's a supported varient */
2504 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2505 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2506 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2508 desc.buflen = mdrcnt;
2509 desc.subformat = NULL;
2512 if (init_package(&desc,1,0))
2514 PACKI(&desc,"W",0); /* code */
2515 PACKS(&desc,"B21",name); /* eff. name */
2516 PACKS(&desc,"B",""); /* pad */
2518 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2519 PACKI(&desc,"D",0); /* auth flags XXX */
2520 PACKI(&desc,"W",0); /* num logons */
2521 PACKI(&desc,"W",0); /* bad pw count */
2522 PACKI(&desc,"D",0); /* last logon */
2523 PACKI(&desc,"D",-1); /* last logoff */
2524 PACKI(&desc,"D",-1); /* logoff time */
2525 PACKI(&desc,"D",-1); /* kickoff time */
2526 PACKI(&desc,"D",0); /* password age */
2527 PACKI(&desc,"D",0); /* password can change */
2528 PACKI(&desc,"D",-1); /* password must change */
2531 fstrcpy(mypath,"\\\\");
2532 fstrcat(mypath,local_machine);
2534 PACKS(&desc,"z",mypath); /* computer */
2536 PACKS(&desc,"z",global_myworkgroup);/* domain */
2538 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2539 /* made sure all macros are fully substituted and available */
2541 pstring logon_script;
2542 pstrcpy(logon_script,lp_logon_script());
2543 standard_sub_conn( conn, logon_script );
2544 PACKS(&desc,"z", logon_script); /* script path */
2546 /* End of JHT mods */
2548 PACKI(&desc,"D",0x00000000); /* reserved */
2551 *rdata_len = desc.usedlen;
2553 *rparam = REALLOC(*rparam,*rparam_len);
2554 SSVALS(*rparam,0,desc.errcode);
2556 SSVAL(*rparam,4,desc.neededlen);
2558 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2563 /****************************************************************************
2564 api_WAccessGetUserPerms
2565 ****************************************************************************/
2566 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2567 int mdrcnt,int mprcnt,
2568 char **rdata,char **rparam,
2569 int *rdata_len,int *rparam_len)
2571 char *str1 = param+2;
2572 char *str2 = skip_string(str1,1);
2573 char *user = skip_string(str2,1);
2574 char *resource = skip_string(user,1);
2576 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2578 /* check it's a supported varient */
2579 if (strcmp(str1,"zzh") != 0) return False;
2580 if (strcmp(str2,"") != 0) return False;
2583 *rparam = REALLOC(*rparam,*rparam_len);
2584 SSVALS(*rparam,0,0); /* errorcode */
2585 SSVAL(*rparam,2,0); /* converter word */
2586 SSVAL(*rparam,4,0x7f); /* permission flags */
2591 /****************************************************************************
2592 api_WPrintJobEnumerate
2593 ****************************************************************************/
2594 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2595 int mdrcnt,int mprcnt,
2596 char **rdata,char **rparam,
2597 int *rdata_len,int *rparam_len)
2599 char *str1 = param+2;
2600 char *str2 = skip_string(str1,1);
2601 char *p = skip_string(str2,1);
2607 struct pack_desc desc;
2608 print_queue_struct *queue=NULL;
2609 print_status_struct status;
2613 memset((char *)&desc,'\0',sizeof(desc));
2614 memset((char *)&status,'\0',sizeof(status));
2616 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2618 /* check it's a supported varient */
2619 if (strcmp(str1,"WWrLh") != 0) return False;
2620 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2623 snum = print_job_snum(job);
2625 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2627 count = print_queue_status(snum,&queue,&status);
2628 for (i = 0; i < count; i++) {
2629 if (queue[i].job == job) break;
2631 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2633 desc.buflen = mdrcnt;
2635 if (init_package(&desc,1,0)) {
2637 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2638 *rdata_len = desc.usedlen;
2641 desc.errcode = NERR_JobNotFound;
2647 *rparam = REALLOC(*rparam,*rparam_len);
2648 SSVALS(*rparam,0,desc.errcode);
2650 SSVAL(*rparam,4,desc.neededlen);
2652 if (queue) free(queue);
2654 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2658 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2659 int mdrcnt,int mprcnt,
2660 char **rdata,char **rparam,
2661 int *rdata_len,int *rparam_len)
2663 char *str1 = param+2;
2664 char *str2 = skip_string(str1,1);
2665 char *p = skip_string(str2,1);
2671 struct pack_desc desc;
2672 print_queue_struct *queue=NULL;
2673 print_status_struct status;
2675 memset((char *)&desc,'\0',sizeof(desc));
2676 memset((char *)&status,'\0',sizeof(status));
2678 p = skip_string(p,1);
2681 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2683 /* check it's a supported varient */
2684 if (strcmp(str1,"zWrLeh") != 0) return False;
2685 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2686 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2688 snum = lp_servicenumber(name);
2689 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2690 int pnum = lp_servicenumber(PRINTERS_NAME);
2692 lp_add_printer(name,pnum);
2693 snum = lp_servicenumber(name);
2697 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2699 count = print_queue_status(snum,&queue,&status);
2700 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2702 desc.buflen = mdrcnt;
2704 if (init_package(&desc,count,0)) {
2706 for (i = 0; i < count; i++) {
2707 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2708 if (desc.errcode == NERR_Success) succnt = i+1;
2712 *rdata_len = desc.usedlen;
2715 *rparam = REALLOC(*rparam,*rparam_len);
2716 SSVALS(*rparam,0,desc.errcode);
2718 SSVAL(*rparam,4,succnt);
2719 SSVAL(*rparam,6,count);
2721 if (queue) free(queue);
2723 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2727 static int check_printdest_info(struct pack_desc* desc,
2728 int uLevel, char* id)
2730 desc->subformat = NULL;
2732 case 0: desc->format = "B9"; break;
2733 case 1: desc->format = "B9B21WWzW"; break;
2734 case 2: desc->format = "z"; break;
2735 case 3: desc->format = "zzzWWzzzWW"; break;
2736 default: return False;
2738 if (strcmp(desc->format,id) != 0) return False;
2742 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2743 struct pack_desc* desc)
2746 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2747 buf[sizeof(buf)-1] = 0;
2750 PACKS(desc,"B9",buf); /* szName */
2752 PACKS(desc,"B21",""); /* szUserName */
2753 PACKI(desc,"W",0); /* uJobId */
2754 PACKI(desc,"W",0); /* fsStatus */
2755 PACKS(desc,"z",""); /* pszStatus */
2756 PACKI(desc,"W",0); /* time */
2759 if (uLevel == 2 || uLevel == 3) {
2760 PACKS(desc,"z",buf); /* pszPrinterName */
2762 PACKS(desc,"z",""); /* pszUserName */
2763 PACKS(desc,"z",""); /* pszLogAddr */
2764 PACKI(desc,"W",0); /* uJobId */
2765 PACKI(desc,"W",0); /* fsStatus */
2766 PACKS(desc,"z",""); /* pszStatus */
2767 PACKS(desc,"z",""); /* pszComment */
2768 PACKS(desc,"z","NULL"); /* pszDrivers */
2769 PACKI(desc,"W",0); /* time */
2770 PACKI(desc,"W",0); /* pad1 */
2775 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2776 int mdrcnt,int mprcnt,
2777 char **rdata,char **rparam,
2778 int *rdata_len,int *rparam_len)
2780 char *str1 = param+2;
2781 char *str2 = skip_string(str1,1);
2782 char *p = skip_string(str2,1);
2783 char* PrinterName = p;
2785 struct pack_desc desc;
2788 memset((char *)&desc,'\0',sizeof(desc));
2790 p = skip_string(p,1);
2793 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2795 /* check it's a supported varient */
2796 if (strcmp(str1,"zWrLh") != 0) return False;
2797 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2799 snum = lp_servicenumber(PrinterName);
2800 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2801 int pnum = lp_servicenumber(PRINTERS_NAME);
2803 lp_add_printer(PrinterName,pnum);
2804 snum = lp_servicenumber(PrinterName);
2810 desc.errcode = NERR_DestNotFound;
2814 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2816 desc.buflen = mdrcnt;
2817 if (init_package(&desc,1,0)) {
2818 fill_printdest_info(conn,snum,uLevel,&desc);
2820 *rdata_len = desc.usedlen;
2824 *rparam = REALLOC(*rparam,*rparam_len);
2825 SSVALS(*rparam,0,desc.errcode);
2827 SSVAL(*rparam,4,desc.neededlen);
2829 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2833 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2834 int mdrcnt,int mprcnt,
2835 char **rdata,char **rparam,
2836 int *rdata_len,int *rparam_len)
2838 char *str1 = param+2;
2839 char *str2 = skip_string(str1,1);
2840 char *p = skip_string(str2,1);
2844 struct pack_desc desc;
2845 int services = lp_numservices();
2847 memset((char *)&desc,'\0',sizeof(desc));
2851 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2853 /* check it's a supported varient */
2854 if (strcmp(str1,"WrLeh") != 0) return False;
2855 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2858 for (i = 0; i < services; i++)
2859 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2862 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2864 desc.buflen = mdrcnt;
2865 if (init_package(&desc,queuecnt,0)) {
2868 for (i = 0; i < services; i++) {
2869 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2870 fill_printdest_info(conn,i,uLevel,&desc);
2872 if (desc.errcode == NERR_Success) succnt = n;
2877 *rdata_len = desc.usedlen;
2880 *rparam = REALLOC(*rparam,*rparam_len);
2881 SSVALS(*rparam,0,desc.errcode);
2883 SSVAL(*rparam,4,succnt);
2884 SSVAL(*rparam,6,queuecnt);
2886 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2890 static BOOL api_WPrintDriverEnum(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);
2900 struct pack_desc desc;
2902 memset((char *)&desc,'\0',sizeof(desc));
2906 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2908 /* check it's a supported varient */
2909 if (strcmp(str1,"WrLeh") != 0) return False;
2910 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2912 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2914 desc.buflen = mdrcnt;
2915 if (init_package(&desc,1,0)) {
2916 PACKS(&desc,"B41","NULL");
2919 succnt = (desc.errcode == NERR_Success ? 1 : 0);
2921 *rdata_len = desc.usedlen;
2924 *rparam = REALLOC(*rparam,*rparam_len);
2925 SSVALS(*rparam,0,desc.errcode);
2927 SSVAL(*rparam,4,succnt);
2930 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2934 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2935 int mdrcnt,int mprcnt,
2936 char **rdata,char **rparam,
2937 int *rdata_len,int *rparam_len)
2939 char *str1 = param+2;
2940 char *str2 = skip_string(str1,1);
2941 char *p = skip_string(str2,1);
2944 struct pack_desc desc;
2946 memset((char *)&desc,'\0',sizeof(desc));
2950 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
2952 /* check it's a supported varient */
2953 if (strcmp(str1,"WrLeh") != 0) return False;
2954 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
2956 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2958 desc.buflen = mdrcnt;
2960 if (init_package(&desc,1,0)) {
2961 PACKS(&desc,"B13","lpd");
2964 succnt = (desc.errcode == NERR_Success ? 1 : 0);
2966 *rdata_len = desc.usedlen;
2969 *rparam = REALLOC(*rparam,*rparam_len);
2970 SSVALS(*rparam,0,desc.errcode);
2972 SSVAL(*rparam,4,succnt);
2975 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
2979 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2980 int mdrcnt,int mprcnt,
2981 char **rdata,char **rparam,
2982 int *rdata_len,int *rparam_len)
2984 char *str1 = param+2;
2985 char *str2 = skip_string(str1,1);
2986 char *p = skip_string(str2,1);
2989 struct pack_desc desc;
2991 memset((char *)&desc,'\0',sizeof(desc));
2995 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
2997 /* check it's a supported varient */
2998 if (strcmp(str1,"WrLeh") != 0) return False;
2999 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3001 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3002 memset((char *)&desc,'\0',sizeof(desc));
3004 desc.buflen = mdrcnt;
3006 if (init_package(&desc,1,0)) {
3007 PACKS(&desc,"B13","lp0");
3010 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3012 *rdata_len = desc.usedlen;
3015 *rparam = REALLOC(*rparam,*rparam_len);
3016 SSVALS(*rparam,0,desc.errcode);
3018 SSVAL(*rparam,4,succnt);
3021 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3025 /****************************************************************************
3026 The buffer was too small
3027 ****************************************************************************/
3029 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3030 int mdrcnt,int mprcnt,
3031 char **rdata,char **rparam,
3032 int *rdata_len,int *rparam_len)
3034 *rparam_len = MIN(*rparam_len,mprcnt);
3035 *rparam = REALLOC(*rparam,*rparam_len);
3039 SSVAL(*rparam,0,NERR_BufTooSmall);
3041 DEBUG(3,("Supplied buffer too small in API command\n"));
3047 /****************************************************************************
3048 The request is not supported
3049 ****************************************************************************/
3051 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3052 int mdrcnt,int mprcnt,
3053 char **rdata,char **rparam,
3054 int *rdata_len,int *rparam_len)
3057 *rparam = REALLOC(*rparam,*rparam_len);
3061 SSVAL(*rparam,0,NERR_notsupported);
3062 SSVAL(*rparam,2,0); /* converter word */
3064 DEBUG(3,("Unsupported API command\n"));
3076 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3077 int,int,char **,char **,int *,int *);
3079 } api_commands[] = {
3080 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3081 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3082 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3083 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3084 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3085 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3086 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3087 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3088 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3089 {"WPrintQueuePause", 74, api_WPrintQueuePurge,0},
3090 {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
3091 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3092 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3093 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3094 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3095 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3096 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3097 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3098 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3099 {"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
3100 {"NetServerEnum", 104, api_RNetServerEnum,0},
3101 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3102 {"SetUserPassword", 115, api_SetUserPassword,0},
3103 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3104 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3105 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3106 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3107 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3108 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3109 {NULL, -1, api_Unsupported,0}};
3112 /****************************************************************************
3113 Handle remote api calls
3114 ****************************************************************************/
3116 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3117 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3121 char *rparam = NULL;
3128 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3132 api_command = SVAL(params,0);
3134 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3137 skip_string(params+2,1),
3138 tdscnt,tpscnt,mdrcnt,mprcnt));
3140 for (i=0;api_commands[i].name;i++) {
3141 if (api_commands[i].id == api_command && api_commands[i].fn) {
3142 DEBUG(3,("Doing %s\n",api_commands[i].name));
3147 rdata = (char *)malloc(1024);
3149 memset(rdata,'\0',1024);
3151 rparam = (char *)malloc(1024);
3153 memset(rparam,'\0',1024);
3155 if(!rdata || !rparam) {
3156 DEBUG(0,("api_reply: malloc fail !\n"));
3160 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3161 &rdata,&rparam,&rdata_len,&rparam_len);
3164 if (rdata_len > mdrcnt ||
3165 rparam_len > mprcnt) {
3166 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3167 &rdata,&rparam,&rdata_len,&rparam_len);
3170 /* if we get False back then it's actually unsupported */
3172 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3173 &rdata,&rparam,&rdata_len,&rparam_len);
3175 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);