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 pstring global_myname;
41 extern fstring global_myworkgroup;
43 #define NERR_Success 0
44 #define NERR_badpass 86
45 #define NERR_notsupported 50
47 #define NERR_BASE (2100)
48 #define NERR_BufTooSmall (NERR_BASE+23)
49 #define NERR_JobNotFound (NERR_BASE+51)
50 #define NERR_DestNotFound (NERR_BASE+52)
52 #define ACCESS_READ 0x01
53 #define ACCESS_WRITE 0x02
54 #define ACCESS_CREATE 0x04
56 #define SHPWLEN 8 /* share password length */
58 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
59 int mdrcnt,int mprcnt,
60 char **rdata,char **rparam,
61 int *rdata_len,int *rparam_len);
62 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
63 int mdrcnt,int mprcnt,
64 char **rdata,char **rparam,
65 int *rdata_len,int *rparam_len);
68 static int CopyExpanded(connection_struct *conn,
69 int snum, char** dst, char* src, int* n)
74 if (!src || !dst || !n || !(*dst)) return(0);
76 StrnCpy(buf,src,sizeof(buf)/2);
77 pstring_sub(buf,"%S",lp_servicename(snum));
78 standard_sub_conn(conn,buf);
79 StrnCpy(*dst,buf,*n-1);
86 static int CopyAndAdvance(char** dst, char* src, int* n)
89 if (!src || !dst || !n || !(*dst)) return(0);
90 StrnCpy(*dst,src,*n-1);
97 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
101 StrnCpy(buf,s,sizeof(buf)/2);
102 pstring_sub(buf,"%S",lp_servicename(snum));
103 standard_sub_conn(conn,buf);
104 return strlen(buf) + 1;
107 static char* Expand(connection_struct *conn, int snum, char* s)
110 if (!s) return(NULL);
111 StrnCpy(buf,s,sizeof(buf)/2);
112 pstring_sub(buf,"%S",lp_servicename(snum));
113 standard_sub_conn(conn,buf);
117 /*******************************************************************
118 check a API string for validity when we only need to check the prefix
119 ******************************************************************/
120 static BOOL prefix_ok(char *str,char *prefix)
122 return(strncmp(str,prefix,strlen(prefix)) == 0);
126 char* format; /* formatstring for structure */
127 char* subformat; /* subformat for structure */
128 char* base; /* baseaddress of buffer */
129 int buflen; /* remaining size for fixed part; on init: length of base */
130 int subcount; /* count of substructures */
131 char* structbuf; /* pointer into buffer for remaining fixed part */
132 int stringlen; /* remaining size for variable part */
133 char* stringbuf; /* pointer into buffer for remaining variable part */
134 int neededlen; /* total needed size */
135 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
136 char* curpos; /* current position; pointer into format or subformat */
140 static int get_counter(char** p)
143 if (!p || !(*p)) return(1);
144 if (!isdigit((int)**p)) return 1;
148 n = 10 * n + (i - '0');
155 static int getlen(char* p)
161 case 'W': /* word (2 byte) */
164 case 'K': /* status word? (2 byte) */
167 case 'N': /* count of substructures (word) at end */
170 case 'D': /* double word (4 byte) */
171 case 'z': /* offset to zero terminated string (4 byte) */
172 case 'l': /* offset to user data (4 byte) */
175 case 'b': /* offset to data (with counter) (4 byte) */
179 case 'B': /* byte (with optional counter) */
180 n += get_counter(&p);
187 static BOOL init_package(struct pack_desc* p, int count, int subcount)
192 if (!p->format || !p->base) return(False);
194 i = count * getlen(p->format);
195 if (p->subformat) i += subcount * getlen(p->subformat);
196 p->structbuf = p->base;
200 p->curpos = p->format;
206 * This is the old error code we used. Aparently
207 * WinNT/2k systems return ERRbuftoosmall (2123) and
208 * OS/2 needs this. I'm leaving this here so we can revert
211 p->errcode = ERRmoredata;
213 p->errcode = ERRbuftoosmall;
217 p->errcode = NERR_Success;
220 p->stringbuf = p->base + i;
222 return(p->errcode == NERR_Success);
226 static int package(struct pack_desc* p, ...)
229 static int package(va_alist)
235 int needed=0, stringneeded;
237 int is_string=0, stringused;
244 p = va_arg(args,struct pack_desc *);
249 p->curpos = p->format;
251 p->curpos = p->subformat;
256 str = va_arg(args,char*);
257 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
266 switch( *p->curpos++ ) {
267 case 'W': /* word (2 byte) */
269 temp = va_arg(args,int);
270 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
272 case 'K': /* status word? (2 byte) */
274 temp = va_arg(args,int);
275 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
277 case 'N': /* count of substructures (word) at end */
279 p->subcount = va_arg(args,int);
280 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
282 case 'D': /* double word (4 byte) */
284 temp = va_arg(args,int);
285 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
287 case 'B': /* byte (with optional counter) */
288 needed = get_counter(&p->curpos);
290 char *s = va_arg(args,char*);
291 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
294 case 'z': /* offset to zero terminated string (4 byte) */
295 str = va_arg(args,char*);
296 stringneeded = (str ? strlen(str)+1 : 0);
299 case 'l': /* offset to user data (4 byte) */
300 str = va_arg(args,char*);
301 stringneeded = va_arg(args,int);
304 case 'b': /* offset to data (with counter) (4 byte) */
305 str = va_arg(args,char*);
306 stringneeded = get_counter(&p->curpos);
311 if (stringneeded >= 0) {
313 if (p->buflen >= needed) {
314 stringused = stringneeded;
315 if (stringused > p->stringlen) {
316 stringused = (is_string ? p->stringlen : 0);
317 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
320 SIVAL(p->structbuf,0,0);
322 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
323 memcpy(p->stringbuf,str?str:"",stringused);
324 if (is_string) p->stringbuf[stringused-1] = '\0';
325 p->stringbuf += stringused;
326 p->stringlen -= stringused;
327 p->usedlen += stringused;
330 p->neededlen += stringneeded;
332 p->neededlen += needed;
333 if (p->buflen >= needed) {
334 p->structbuf += needed;
336 p->usedlen += needed;
339 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
345 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
346 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
348 #define PACK(desc,t,v) package(desc,v)
349 #define PACKl(desc,t,v,l) package(desc,v,l)
352 static void PACKI(struct pack_desc* desc,char *t,int v)
357 static void PACKS(struct pack_desc* desc,char *t,char *v)
363 /****************************************************************************
365 ****************************************************************************/
366 static void PackDriverData(struct pack_desc* desc)
368 char drivdata[4+4+32];
369 SIVAL(drivdata,0,sizeof drivdata); /* cb */
370 SIVAL(drivdata,4,1000); /* lVersion */
371 memset(drivdata+8,0,32); /* szDeviceName */
372 pstrcpy(drivdata+8,"NULL");
373 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
376 static int check_printq_info(struct pack_desc* desc,
377 int uLevel, char *id1, char *id2)
379 desc->subformat = NULL;
382 desc->format = "B13";
385 desc->format = "B13BWWWzzzzzWW";
388 desc->format = "B13BWWWzzzzzWN";
389 desc->subformat = "WB21BB16B10zWWzDDz";
392 desc->format = "zWWWWzzzzWWzzl";
395 desc->format = "zWWWWzzzzWNzzl";
396 desc->subformat = "WWzWWDDzz";
405 desc->format = "WzzzzzzzzN";
406 desc->subformat = "z";
408 default: return False;
410 if (strcmp(desc->format,id1) != 0) return False;
411 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
416 #define JOB_STATUS_QUEUED 0
417 #define JOB_STATUS_PAUSED 1
418 #define JOB_STATUS_SPOOLING 2
419 #define JOB_STATUS_PRINTING 3
420 #define JOB_STATUS_PRINTED 4
422 #define QUEUE_STATUS_PAUSED 1
423 #define QUEUE_STATUS_ERROR 2
425 /* turn a print job status into a on the wire status
427 static int printj_status(int v)
431 return JOB_STATUS_QUEUED;
433 return JOB_STATUS_PAUSED;
435 return JOB_STATUS_SPOOLING;
437 return JOB_STATUS_PRINTING;
442 /* turn a print queue status into a on the wire status
444 static int printq_status(int v)
450 return QUEUE_STATUS_PAUSED;
452 return QUEUE_STATUS_ERROR;
455 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
456 struct pack_desc* desc,
457 print_queue_struct* queue, int n)
459 time_t t = queue->time;
461 /* the client expects localtime */
464 PACKI(desc,"W",queue->job); /* uJobId */
466 PACKS(desc,"B21",queue->user); /* szUserName */
467 PACKS(desc,"B",""); /* pad */
468 PACKS(desc,"B16",""); /* szNotifyName */
469 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
470 PACKS(desc,"z",""); /* pszParms */
471 PACKI(desc,"W",n+1); /* uPosition */
472 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
473 PACKS(desc,"z",""); /* pszStatus */
474 PACKI(desc,"D",t); /* ulSubmitted */
475 PACKI(desc,"D",queue->size); /* ulSize */
476 PACKS(desc,"z",queue->file); /* pszComment */
478 if (uLevel == 2 || uLevel == 3) {
479 PACKI(desc,"W",queue->priority); /* uPriority */
480 PACKS(desc,"z",queue->user); /* pszUserName */
481 PACKI(desc,"W",n+1); /* uPosition */
482 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
483 PACKI(desc,"D",t); /* ulSubmitted */
484 PACKI(desc,"D",queue->size); /* ulSize */
485 PACKS(desc,"z","Samba"); /* pszComment */
486 PACKS(desc,"z",queue->file); /* pszDocument */
488 PACKS(desc,"z",""); /* pszNotifyName */
489 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
490 PACKS(desc,"z",""); /* pszParms */
491 PACKS(desc,"z",""); /* pszStatus */
492 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
493 PACKS(desc,"z","lpd"); /* pszQProcName */
494 PACKS(desc,"z",""); /* pszQProcParms */
495 PACKS(desc,"z","NULL"); /* pszDriverName */
496 PackDriverData(desc); /* pDriverData */
497 PACKS(desc,"z",""); /* pszPrinterName */
502 /********************************************************************
503 Return a driver name given an snum.
504 Looks in a tdb first. Returns True if from tdb, False otherwise.
505 ********************************************************************/
507 static BOOL get_driver_name(int snum, pstring drivername)
509 NT_PRINTER_INFO_LEVEL *info = NULL;
512 get_a_printer (&info, 2, lp_servicename(snum));
514 pstrcpy( drivername, info->info_2->drivername);
516 free_a_printer(&info, 2);
518 pstrcpy( drivername, lp_printerdriver(snum));
524 /********************************************************************
525 Respond to the DosPrintQInfo command with a level of 52
526 This is used to get printer driver information for Win9x clients
527 ********************************************************************/
528 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
529 struct pack_desc* desc,
530 int count, print_queue_struct* queue,
531 print_status_struct* status)
535 pstring tok,driver,datafile,langmon,helpfile,datatype;
544 * Check in the tdb *first* before checking the legacy
545 * files. This allows an NT upload to take precedence over
546 * the existing fileset. JRA.
548 * we need to lookup the driver name prior to making the call
549 * to get_a_printer_driver_9x_compatible() and not rely on the
550 * 'print driver' parameter --jerry
554 if ((get_driver_name(snum,drivername)) &&
555 ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
559 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
563 /* didn't find driver in tdb */
565 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
566 snum, drivername, lp_driverfile(snum)));
568 lines = file_lines_load(lp_driverfile(snum),NULL, False);
571 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
573 desc->errcode=NERR_notsupported;
577 /* lookup the long printer driver name in the file description */
578 for (i=0;lines[i] && !ok;i++)
581 if (next_token(&p,tok,":",sizeof(tok)) &&
582 (strlen(drivername) == strlen(tok)) &&
583 (!strncmp(tok,drivername,strlen(drivername))))
592 /* driver file name */
593 if (!next_token(&p,driver,":",sizeof(driver)))
597 if (!next_token(&p,datafile,":",sizeof(datafile)))
601 * for the next tokens - which may be empty - I have
602 * to check for empty tokens first because the
603 * next_token function will skip all empty token
612 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
615 /* language monitor */
621 else if (!next_token(&p,langmon,":",sizeof(langmon)))
624 /* default data type */
625 if (!next_token(&p,datatype,":",sizeof(datatype)))
628 PACKI(desc,"W",0x0400); /* don't know */
629 PACKS(desc,"z",drivername); /* long printer name */
630 PACKS(desc,"z",driver); /* Driverfile Name */
631 PACKS(desc,"z",datafile); /* Datafile name */
632 PACKS(desc,"z",langmon); /* language monitor */
635 fstrcpy(location, "\\\\");
636 fstrcat(location, global_myname);
637 fstrcat(location, "\\print$\\WIN40\\0");
638 PACKS(desc,"z",location); /* share to retrieve files */
642 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
644 PACKS(desc,"z",datatype); /* default data type */
645 PACKS(desc,"z",helpfile); /* helpfile name */
646 PACKS(desc,"z",driver); /* driver name */
648 DEBUG(3,("printerdriver:%s:\n",drivername));
649 DEBUG(3,("Driver:%s:\n",driver));
650 DEBUG(3,("Data File:%s:\n",datafile));
651 DEBUG(3,("Language Monitor:%s:\n",langmon));
653 DEBUG(3,("lp_driverlocation:%s:\n",location));
655 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
656 DEBUG(3,("Data Type:%s:\n",datatype));
657 DEBUG(3,("Help File:%s:\n",helpfile));
658 PACKI(desc,"N",count); /* number of files to copy */
660 for (i=0;i<count;i++)
662 /* no need to check return value here
663 * - it was already tested in
664 * get_printerdrivernumber */
665 next_token(&p,tok,",",sizeof(tok));
666 PACKS(desc,"z",tok); /* driver files to copy */
667 DEBUG(3,("file:%s:\n",tok));
670 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
671 SERVICE(snum),count));
673 desc->errcode=NERR_Success;
679 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
680 desc->errcode=NERR_notsupported;
683 file_lines_free(lines);
687 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
688 struct pack_desc* desc,
689 int count, print_queue_struct* queue,
690 print_status_struct* status)
695 PACKS(desc,"B13",SERVICE(snum));
700 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
703 PACKI(desc,"K",printq_status(status->status));
707 if (uLevel == 1 || uLevel == 2) {
708 PACKS(desc,"B",""); /* alignment */
709 PACKI(desc,"W",5); /* priority */
710 PACKI(desc,"W",0); /* start time */
711 PACKI(desc,"W",0); /* until time */
712 PACKS(desc,"z",""); /* pSepFile */
713 PACKS(desc,"z","lpd"); /* pPrProc */
714 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
715 PACKS(desc,"z",""); /* pParms */
717 PACKS(desc,"z","UNKNOWN PRINTER");
718 PACKI(desc,"W",LPSTAT_ERROR);
720 else if (!status || !status->message[0]) {
721 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
722 PACKI(desc,"W",LPSTAT_OK); /* status */
724 PACKS(desc,"z",status->message);
725 PACKI(desc,"W",printq_status(status->status)); /* status */
727 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
730 if (uLevel == 3 || uLevel == 4) {
733 PACKI(desc,"W",5); /* uPriority */
734 PACKI(desc,"W",0); /* uStarttime */
735 PACKI(desc,"W",0); /* uUntiltime */
736 PACKI(desc,"W",5); /* pad1 */
737 PACKS(desc,"z",""); /* pszSepFile */
738 PACKS(desc,"z","WinPrint"); /* pszPrProc */
739 PACKS(desc,"z",""); /* pszParms */
740 if (!status || !status->message[0]) {
741 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
742 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
744 PACKS(desc,"z",status->message); /* pszComment */
745 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
747 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
748 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
749 get_driver_name(snum,drivername);
750 PACKS(desc,"z",drivername); /* pszDriverName */
751 PackDriverData(desc); /* pDriverData */
754 if (uLevel == 2 || uLevel == 4) {
756 for (i=0;i<count;i++)
757 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
761 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
765 /* This function returns the number of files for a given driver */
766 static int get_printerdrivernumber(int snum)
777 * Check in the tdb *first* before checking the legacy
778 * files. This allows an NT upload to take precedence over
779 * the existing fileset. JRA.
781 * we need to lookup the driver name prior to making the call
782 * to get_a_printer_driver_9x_compatible() and not rely on the
783 * 'print driver' parameter --jerry
786 if ((get_driver_name(snum,drivername)) &&
787 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
790 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
794 /* didn't find driver in tdb */
796 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
797 snum, drivername, lp_driverfile(snum)));
799 lines = file_lines_load(lp_driverfile(snum), NULL, False);
802 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
806 /* lookup the long printer driver name in the file description */
807 for (i=0;lines[i] && !ok;i++)
810 if (next_token(&p,tok,":",sizeof(tok)) &&
811 (strlen(drivername) == strlen(tok)) &&
812 (!strncmp(tok,drivername,strlen(drivername))))
824 if (*p++ == ':') i--;
827 DEBUG(3,("Can't determine number of printer driver files\n"));
831 /* count the number of files */
832 while (next_token(&p,tok,",",sizeof(tok)))
840 file_lines_free(lines);
845 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
846 uint16 vuid, char *param,char *data,
847 int mdrcnt,int mprcnt,
848 char **rdata,char **rparam,
849 int *rdata_len,int *rparam_len)
851 char *str1 = param+2;
852 char *str2 = skip_string(str1,1);
853 char *p = skip_string(str2,1);
859 struct pack_desc desc;
860 print_queue_struct *queue=NULL;
861 print_status_struct status;
863 memset((char *)&status,'\0',sizeof(status));
864 memset((char *)&desc,'\0',sizeof(desc));
866 p = skip_string(p,1);
870 /* remove any trailing username */
871 if ((p = strchr(QueueName,'%'))) *p = 0;
873 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
875 /* check it's a supported varient */
876 if (!prefix_ok(str1,"zWrLh")) return False;
877 if (!check_printq_info(&desc,uLevel,str2,str3)) {
879 * Patch from Scott Moomaw <scott@bridgewater.edu>
880 * to return the 'invalid info level' error if an
881 * unknown level was requested.
885 *rparam = REALLOC(*rparam,*rparam_len);
886 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
892 snum = lp_servicenumber(QueueName);
893 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
894 int pnum = lp_servicenumber(PRINTERS_NAME);
896 lp_add_printer(QueueName,pnum);
897 snum = lp_servicenumber(QueueName);
901 if (snum < 0 || !VALID_SNUM(snum)) return(False);
904 count = get_printerdrivernumber(snum);
905 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
907 count = print_queue_status(snum, &queue,&status);
910 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
912 desc.buflen = mdrcnt;
913 if (init_package(&desc,1,count)) {
914 desc.subcount = count;
915 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
916 } else if(uLevel == 0) {
919 * This is a *disgusting* hack.
920 * This is *so* bad that even I'm embarrassed (and I
921 * have no shame). Here's the deal :
922 * Until we get the correct SPOOLSS code into smbd
923 * then when we're running with NT SMB support then
924 * NT makes this call with a level of zero, and then
925 * immediately follows it with an open request to
926 * the \\SRVSVC pipe. If we allow that open to
927 * succeed then NT barfs when it cannot open the
928 * \\SPOOLSS pipe immediately after and continually
929 * whines saying "Printer name is invalid" forever
930 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
931 * to fail, then NT downgrades to using the downlevel code
932 * and everything works as well as before. I hate
933 * myself for adding this code.... JRA.
936 fail_next_srvsvc_open();
940 *rdata_len = desc.usedlen;
943 *rparam = REALLOC(*rparam,*rparam_len);
944 SSVALS(*rparam,0,desc.errcode);
946 SSVAL(*rparam,4,desc.neededlen);
948 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
950 if (queue) free(queue);
955 /****************************************************************************
956 View list of all print jobs on all queues.
957 ****************************************************************************/
959 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
960 int mdrcnt, int mprcnt,
961 char **rdata, char** rparam,
962 int *rdata_len, int *rparam_len)
964 char *param_format = param+2;
965 char *output_format1 = skip_string(param_format,1);
966 char *p = skip_string(output_format1,1);
967 int uLevel = SVAL(p,0);
968 char *output_format2 = p + 4;
969 int services = lp_numservices();
971 struct pack_desc desc;
972 print_queue_struct **queue = NULL;
973 print_status_struct *status = NULL;
974 int* subcntarr = NULL;
975 int queuecnt, subcnt=0, succnt=0;
977 memset((char *)&desc,'\0',sizeof(desc));
979 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
981 if (!prefix_ok(param_format,"WrLeh")) return False;
982 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
984 * Patch from Scott Moomaw <scott@bridgewater.edu>
985 * to return the 'invalid info level' error if an
986 * unknown level was requested.
990 *rparam = REALLOC(*rparam,*rparam_len);
991 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
998 for (i = 0; i < services; i++)
999 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1002 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1003 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1006 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1007 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1008 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1011 memset(status,0,queuecnt*sizeof(print_status_struct));
1012 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1013 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1018 for (i = 0; i < services; i++)
1019 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1020 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1021 subcnt += subcntarr[n];
1025 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1027 desc.buflen = mdrcnt;
1029 if (init_package(&desc,queuecnt,subcnt)) {
1032 for (i = 0; i < services; i++)
1033 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1034 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1036 if (desc.errcode == NERR_Success) succnt = n;
1040 if (subcntarr) free(subcntarr);
1042 *rdata_len = desc.usedlen;
1044 *rparam = REALLOC(*rparam,*rparam_len);
1045 SSVALS(*rparam,0,desc.errcode);
1047 SSVAL(*rparam,4,succnt);
1048 SSVAL(*rparam,6,queuecnt);
1050 for (i = 0; i < queuecnt; i++) {
1051 if (queue && queue[i]) free(queue[i]);
1054 if (queue) free(queue);
1055 if (status) free(status);
1060 /****************************************************************************
1061 get info level for a server list query
1062 ****************************************************************************/
1063 static BOOL check_server_info(int uLevel, char* id)
1067 if (strcmp(id,"B16") != 0) return False;
1070 if (strcmp(id,"B16BBDz") != 0) return False;
1078 struct srv_info_struct
1088 /*******************************************************************
1089 get server info lists from the files saved by nmbd. Return the
1091 ******************************************************************/
1092 static int get_server_info(uint32 servertype,
1093 struct srv_info_struct **servers,
1099 BOOL local_list_only;
1102 lines = file_lines_load(lock_path(SERVER_LIST), NULL, False);
1104 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1108 /* request for everything is code for request all servers */
1109 if (servertype == SV_TYPE_ALL)
1110 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1112 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1114 DEBUG(4,("Servertype search: %8x\n",servertype));
1116 for (i=0;lines[i];i++) {
1118 struct srv_info_struct *s;
1119 char *ptr = lines[i];
1122 if (!*ptr) continue;
1124 if (count == alloced) {
1126 (*servers) = (struct srv_info_struct *)
1127 Realloc(*servers,sizeof(**servers)*alloced);
1128 if (!(*servers)) return(0);
1129 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1131 s = &(*servers)[count];
1133 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1134 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1135 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1136 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1137 /* this allows us to cope with an old nmbd */
1138 pstrcpy(s->domain,global_myworkgroup);
1141 if (sscanf(stype,"%X",&s->type) != 1) {
1142 DEBUG(4,("r:host file "));
1146 /* Filter the servers/domains we return based on what was asked for. */
1148 /* Check to see if we are being asked for a local list only. */
1149 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1150 DEBUG(4,("r: local list only"));
1154 /* doesn't match up: don't want it */
1155 if (!(servertype & s->type)) {
1156 DEBUG(4,("r:serv type "));
1160 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1161 (s->type & SV_TYPE_DOMAIN_ENUM))
1163 DEBUG(4,("s: dom mismatch "));
1167 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1172 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1173 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1177 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1178 s->name, s->type, s->comment, s->domain));
1180 s->server_added = True;
1185 DEBUG(4,("%20s %8x %25s %15s\n",
1186 s->name, s->type, s->comment, s->domain));
1190 file_lines_free(lines);
1195 /*******************************************************************
1196 fill in a server info structure
1197 ******************************************************************/
1198 static int fill_srv_info(struct srv_info_struct *service,
1199 int uLevel, char **buf, int *buflen,
1200 char **stringbuf, int *stringspace, char *baseaddr)
1209 case 0: struct_len = 16; break;
1210 case 1: struct_len = 26; break;
1220 len = strlen(service->comment)+1;
1224 if (buflen) *buflen = struct_len;
1225 if (stringspace) *stringspace = len;
1226 return struct_len + len;
1231 if (*buflen < struct_len) return -1;
1239 p2 = p + struct_len;
1240 l2 = *buflen - struct_len;
1242 if (!baseaddr) baseaddr = p;
1247 StrnCpy(p,service->name,15);
1251 StrnCpy(p,service->name,15);
1252 SIVAL(p,18,service->type);
1253 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1254 len += CopyAndAdvance(&p2,service->comment,&l2);
1260 *buf = p + struct_len;
1261 *buflen -= struct_len;
1274 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1276 return(strcmp(s1->name,s2->name));
1279 /****************************************************************************
1280 view list of servers available (or possibly domains). The info is
1281 extracted from lists saved by nmbd on the local host
1282 ****************************************************************************/
1283 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1284 int mdrcnt, int mprcnt, char **rdata,
1285 char **rparam, int *rdata_len, int *rparam_len)
1287 char *str1 = param+2;
1288 char *str2 = skip_string(str1,1);
1289 char *p = skip_string(str2,1);
1290 int uLevel = SVAL(p,0);
1291 int buf_len = SVAL(p,2);
1292 uint32 servertype = IVAL(p,4);
1294 int data_len, fixed_len, string_len;
1295 int f_len = 0, s_len = 0;
1296 struct srv_info_struct *servers=NULL;
1297 int counted=0,total=0;
1300 BOOL domain_request;
1303 /* If someone sets all the bits they don't really mean to set
1304 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1307 if (servertype == SV_TYPE_ALL)
1308 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1310 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1311 any other bit (they may just set this bit on it's own) they
1312 want all the locally seen servers. However this bit can be
1313 set on its own so set the requested servers to be
1314 ALL - DOMAIN_ENUM. */
1316 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1317 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1319 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1320 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1324 if (!prefix_ok(str1,"WrLehD")) return False;
1325 if (!check_server_info(uLevel,str2)) return False;
1327 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1328 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1329 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1331 if (strcmp(str1, "WrLehDz") == 0) {
1332 StrnCpy(domain, p, sizeof(fstring)-1);
1334 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1337 if (lp_browse_list())
1338 total = get_server_info(servertype,&servers,domain);
1340 data_len = fixed_len = string_len = 0;
1343 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1346 char *lastname=NULL;
1348 for (i=0;i<total;i++)
1350 struct srv_info_struct *s = &servers[i];
1351 if (lastname && strequal(lastname,s->name)) continue;
1353 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1354 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1355 s->name, s->type, s->comment, s->domain));
1357 if (data_len <= buf_len) {
1360 string_len += s_len;
1367 *rdata_len = fixed_len + string_len;
1368 *rdata = REALLOC(*rdata,*rdata_len);
1369 memset(*rdata,'\0',*rdata_len);
1371 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1377 char *lastname=NULL;
1378 int count2 = counted;
1379 for (i = 0; i < total && count2;i++)
1381 struct srv_info_struct *s = &servers[i];
1382 if (lastname && strequal(lastname,s->name)) continue;
1384 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1385 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1386 s->name, s->type, s->comment, s->domain));
1392 *rparam = REALLOC(*rparam,*rparam_len);
1393 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1395 SSVAL(*rparam,4,counted);
1396 SSVAL(*rparam,6,counted+missed);
1398 if (servers) free(servers);
1400 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1401 domain,uLevel,counted,counted+missed));
1406 /****************************************************************************
1407 command 0x34 - suspected of being a "Lookup Names" stub api
1408 ****************************************************************************/
1409 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1410 int mdrcnt, int mprcnt, char **rdata,
1411 char **rparam, int *rdata_len, int *rparam_len)
1413 char *str1 = param+2;
1414 char *str2 = skip_string(str1,1);
1415 char *p = skip_string(str2,1);
1416 int uLevel = SVAL(p,0);
1417 int buf_len = SVAL(p,2);
1421 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1422 str1, str2, p, uLevel, buf_len));
1424 if (!prefix_ok(str1,"zWrLeh")) return False;
1429 *rparam = REALLOC(*rparam,*rparam_len);
1431 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1433 SSVAL(*rparam,4,counted);
1434 SSVAL(*rparam,6,counted+missed);
1439 /****************************************************************************
1440 get info about a share
1441 ****************************************************************************/
1442 static BOOL check_share_info(int uLevel, char* id)
1446 if (strcmp(id,"B13") != 0) return False;
1449 if (strcmp(id,"B13BWz") != 0) return False;
1452 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1455 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1457 default: return False;
1462 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1463 char** buf, int* buflen,
1464 char** stringbuf, int* stringspace, char* baseaddr)
1473 case 0: struct_len = 13; break;
1474 case 1: struct_len = 20; break;
1475 case 2: struct_len = 40; break;
1476 case 91: struct_len = 68; break;
1484 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1485 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1486 if (buflen) *buflen = struct_len;
1487 if (stringspace) *stringspace = len;
1488 return struct_len + len;
1493 if ((*buflen) < struct_len) return -1;
1501 p2 = p + struct_len;
1502 l2 = (*buflen) - struct_len;
1504 if (!baseaddr) baseaddr = p;
1506 StrnCpy(p,lp_servicename(snum),13);
1512 type = STYPE_DISKTREE;
1513 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1514 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1515 SSVAL(p,14,type); /* device type */
1516 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1517 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1522 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1523 SSVALS(p,22,-1); /* max uses */
1524 SSVAL(p,24,1); /* current uses */
1525 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1526 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1527 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1532 memset(p+40,0,SHPWLEN+2);
1544 (*buf) = p + struct_len;
1545 (*buflen) -= struct_len;
1547 (*stringspace) = l2;
1557 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1558 int mdrcnt,int mprcnt,
1559 char **rdata,char **rparam,
1560 int *rdata_len,int *rparam_len)
1562 char *str1 = param+2;
1563 char *str2 = skip_string(str1,1);
1564 char *netname = skip_string(str2,1);
1565 char *p = skip_string(netname,1);
1566 int uLevel = SVAL(p,0);
1567 int snum = find_service(netname);
1569 if (snum < 0) return False;
1571 /* check it's a supported varient */
1572 if (!prefix_ok(str1,"zWrLh")) return False;
1573 if (!check_share_info(uLevel,str2)) return False;
1575 *rdata = REALLOC(*rdata,mdrcnt);
1577 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1578 if (*rdata_len < 0) return False;
1581 *rparam = REALLOC(*rparam,*rparam_len);
1582 SSVAL(*rparam,0,NERR_Success);
1583 SSVAL(*rparam,2,0); /* converter word */
1584 SSVAL(*rparam,4,*rdata_len);
1589 /****************************************************************************
1590 view list of shares available
1591 ****************************************************************************/
1592 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1593 int mdrcnt,int mprcnt,
1594 char **rdata,char **rparam,
1595 int *rdata_len,int *rparam_len)
1597 char *str1 = param+2;
1598 char *str2 = skip_string(str1,1);
1599 char *p = skip_string(str2,1);
1600 int uLevel = SVAL(p,0);
1601 int buf_len = SVAL(p,2);
1603 int count=lp_numservices();
1604 int total=0,counted=0;
1605 BOOL missed = False;
1607 int data_len, fixed_len, string_len;
1608 int f_len = 0, s_len = 0;
1610 if (!prefix_ok(str1,"WrLeh")) return False;
1611 if (!check_share_info(uLevel,str2)) return False;
1613 data_len = fixed_len = string_len = 0;
1614 for (i=0;i<count;i++)
1615 if (lp_browseable(i) && lp_snum_ok(i))
1618 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1619 if (data_len <= buf_len)
1623 string_len += s_len;
1628 *rdata_len = fixed_len + string_len;
1629 *rdata = REALLOC(*rdata,*rdata_len);
1630 memset(*rdata,0,*rdata_len);
1632 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1636 for (i = 0; i < count;i++)
1637 if (lp_browseable(i) && lp_snum_ok(i))
1638 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1642 *rparam = REALLOC(*rparam,*rparam_len);
1643 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1645 SSVAL(*rparam,4,counted);
1646 SSVAL(*rparam,6,total);
1648 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1649 counted,total,uLevel,
1650 buf_len,*rdata_len,mdrcnt));
1656 /****************************************************************************
1657 get the time of day info
1658 ****************************************************************************/
1659 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1660 int mdrcnt,int mprcnt,
1661 char **rdata,char **rparam,
1662 int *rdata_len,int *rparam_len)
1666 *rparam = REALLOC(*rparam,*rparam_len);
1669 *rdata = REALLOC(*rdata,*rdata_len);
1671 SSVAL(*rparam,0,NERR_Success);
1672 SSVAL(*rparam,2,0); /* converter word */
1678 time_t unixdate = time(NULL);
1680 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1681 by NT in a "net time" operation,
1682 it seems to ignore the one below */
1684 /* the client expects to get localtime, not GMT, in this bit
1685 (I think, this needs testing) */
1686 t = LocalTime(&unixdate);
1688 SIVAL(p,4,0); /* msecs ? */
1689 CVAL(p,8) = t->tm_hour;
1690 CVAL(p,9) = t->tm_min;
1691 CVAL(p,10) = t->tm_sec;
1692 CVAL(p,11) = 0; /* hundredths of seconds */
1693 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1694 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1695 CVAL(p,16) = t->tm_mday;
1696 CVAL(p,17) = t->tm_mon + 1;
1697 SSVAL(p,18,1900+t->tm_year);
1698 CVAL(p,20) = t->tm_wday;
1705 /****************************************************************************
1706 Set the user password.
1707 *****************************************************************************/
1709 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1710 int mdrcnt,int mprcnt,
1711 char **rdata,char **rparam,
1712 int *rdata_len,int *rparam_len)
1714 char *p = skip_string(param+2,2);
1716 fstring pass1,pass2;
1720 p = skip_string(p,1);
1722 memset(pass1,'\0',sizeof(pass1));
1723 memset(pass2,'\0',sizeof(pass2));
1725 memcpy(pass2,p+16,16);
1728 *rparam = REALLOC(*rparam,*rparam_len);
1732 SSVAL(*rparam,0,NERR_badpass);
1733 SSVAL(*rparam,2,0); /* converter word */
1735 DEBUG(3,("Set password for <%s>\n",user));
1738 * Pass the user through the NT -> unix user mapping
1742 (void)map_username(user);
1745 * Do any UNIX username case mangling.
1747 (void)Get_Pwnam( user, True);
1750 * Attempt to verify the old password against smbpasswd entries
1751 * Win98 clients send old and new password in plaintext for this call.
1755 fstring saved_pass2;
1756 SAM_ACCOUNT *sampass;
1759 * Save the new password as change_oem_password overwrites it
1763 fstrcpy(saved_pass2, pass2);
1765 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1766 change_oem_password(sampass,pass2,False))
1768 SSVAL(*rparam,0,NERR_Success);
1771 * If unix password sync was requested, attempt to change
1772 * the /etc/passwd database also. Return failure if this cannot
1776 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1777 SSVAL(*rparam,0,NERR_badpass);
1782 * If the above failed, attempt the plaintext password change.
1783 * This tests against the /etc/passwd database only.
1786 if(SVAL(*rparam,0) != NERR_Success)
1788 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1789 chgpasswd(user,pass1,pass2,False))
1791 SSVAL(*rparam,0,NERR_Success);
1796 * If the plaintext change failed, attempt
1797 * the old encrypted method. NT will generate this
1798 * after trying the samr method. Note that this
1799 * method is done as a last resort as this
1800 * password change method loses the NT password hash
1801 * and cannot change the UNIX password as no plaintext
1805 if(SVAL(*rparam,0) != NERR_Success)
1807 SAM_ACCOUNT *hnd = NULL;
1809 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
1810 change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1812 SSVAL(*rparam,0,NERR_Success);
1816 memset((char *)pass1,'\0',sizeof(fstring));
1817 memset((char *)pass2,'\0',sizeof(fstring));
1822 /****************************************************************************
1823 Set the user password (SamOEM version - gets plaintext).
1824 ****************************************************************************/
1826 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1827 int mdrcnt,int mprcnt,
1828 char **rdata,char **rparam,
1829 int *rdata_len,int *rparam_len)
1832 char *p = param + 2;
1834 *rparam = REALLOC(*rparam,*rparam_len);
1838 SSVAL(*rparam,0,NERR_badpass);
1841 * Check the parameter definition is correct.
1843 if(!strequal(param + 2, "zsT")) {
1844 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1847 p = skip_string(p, 1);
1849 if(!strequal(p, "B516B16")) {
1850 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1853 p = skip_string(p,1);
1856 p = skip_string(p,1);
1858 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1861 * Pass the user through the NT -> unix user mapping
1865 (void)map_username(user);
1868 * Do any UNIX username case mangling.
1870 (void)Get_Pwnam( user, True);
1872 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1874 SSVAL(*rparam,0,NERR_Success);
1880 /****************************************************************************
1883 ****************************************************************************/
1884 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1885 int mdrcnt,int mprcnt,
1886 char **rdata,char **rparam,
1887 int *rdata_len,int *rparam_len)
1889 int function = SVAL(param,0);
1890 char *str1 = param+2;
1891 char *str2 = skip_string(str1,1);
1892 char *p = skip_string(str2,1);
1894 extern struct current_user current_user;
1898 /* check it's a supported varient */
1899 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1903 *rparam = REALLOC(*rparam,*rparam_len);
1906 if (!print_job_exists(jobid)) {
1907 errcode = NERR_JobNotFound;
1911 errcode = NERR_notsupported;
1914 case 81: /* delete */
1915 if (print_job_delete(¤t_user, jobid, &errcode))
1916 errcode = NERR_Success;
1918 case 82: /* pause */
1919 if (print_job_pause(¤t_user, jobid, &errcode))
1920 errcode = NERR_Success;
1922 case 83: /* resume */
1923 if (print_job_resume(¤t_user, jobid, &errcode))
1924 errcode = NERR_Success;
1929 SSVAL(*rparam,0,errcode);
1930 SSVAL(*rparam,2,0); /* converter word */
1935 /****************************************************************************
1936 Purge a print queue - or pause or resume it.
1937 ****************************************************************************/
1938 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1939 int mdrcnt,int mprcnt,
1940 char **rdata,char **rparam,
1941 int *rdata_len,int *rparam_len)
1943 int function = SVAL(param,0);
1944 char *str1 = param+2;
1945 char *str2 = skip_string(str1,1);
1946 char *QueueName = skip_string(str2,1);
1947 int errcode = NERR_notsupported;
1950 /* check it's a supported varient */
1951 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1955 *rparam = REALLOC(*rparam,*rparam_len);
1958 snum = print_queue_snum(QueueName);
1961 errcode = NERR_JobNotFound;
1966 case 74: /* Pause queue */
1967 if (print_queue_pause(NULL, snum, &errcode)) errcode = NERR_Success;
1969 case 75: /* Resume queue */
1970 if (print_queue_resume(NULL, snum, &errcode)) errcode = NERR_Success;
1972 case 103: /* Purge */
1973 if (print_queue_purge(NULL, snum, &errcode)) errcode = NERR_Success;
1978 SSVAL(*rparam,0,errcode);
1979 SSVAL(*rparam,2,0); /* converter word */
1985 /****************************************************************************
1986 set the property of a print job (undocumented?)
1987 ? function = 0xb -> set name of print job
1988 ? function = 0x6 -> move print job up/down
1989 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1990 or <WWsTP> <WB21BB16B10zWWzDDz>
1991 ****************************************************************************/
1992 static int check_printjob_info(struct pack_desc* desc,
1993 int uLevel, char* id)
1995 desc->subformat = NULL;
1997 case 0: desc->format = "W"; break;
1998 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1999 case 2: desc->format = "WWzWWDDzz"; break;
2000 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2001 default: return False;
2003 if (strcmp(desc->format,id) != 0) return False;
2007 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2008 int mdrcnt,int mprcnt,
2009 char **rdata,char **rparam,
2010 int *rdata_len,int *rparam_len)
2012 struct pack_desc desc;
2013 char *str1 = param+2;
2014 char *str2 = skip_string(str1,1);
2015 char *p = skip_string(str2,1);
2017 int uLevel = SVAL(p,2);
2018 int function = SVAL(p,4);
2023 *rparam = REALLOC(*rparam,*rparam_len);
2027 /* check it's a supported varient */
2028 if ((strcmp(str1,"WWsTP")) ||
2029 (!check_printjob_info(&desc,uLevel,str2)))
2032 if (!print_job_exists(jobid)) {
2033 errcode=NERR_JobNotFound;
2037 errcode = NERR_notsupported;
2041 /* change job place in the queue,
2042 data gives the new place */
2043 place = SVAL(data,0);
2044 if (print_job_set_place(jobid, place)) {
2045 errcode=NERR_Success;
2050 /* change print job name, data gives the name */
2051 if (print_job_set_name(jobid, data)) {
2052 errcode=NERR_Success;
2061 SSVALS(*rparam,0,errcode);
2062 SSVAL(*rparam,2,0); /* converter word */
2068 /****************************************************************************
2069 get info about the server
2070 ****************************************************************************/
2071 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2072 int mdrcnt,int mprcnt,
2073 char **rdata,char **rparam,
2074 int *rdata_len,int *rparam_len)
2076 char *str1 = param+2;
2077 char *str2 = skip_string(str1,1);
2078 char *p = skip_string(str2,1);
2079 int uLevel = SVAL(p,0);
2083 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2085 /* check it's a supported varient */
2086 if (!prefix_ok(str1,"WrLh")) return False;
2089 if (strcmp(str2,"B16") != 0) return False;
2093 if (strcmp(str2,"B16BBDz") != 0) return False;
2097 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2102 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2107 if (strcmp(str2,"DN") != 0) return False;
2111 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2114 default: return False;
2117 *rdata_len = mdrcnt;
2118 *rdata = REALLOC(*rdata,*rdata_len);
2121 p2 = p + struct_len;
2123 StrnCpy(p,local_machine,16);
2129 struct srv_info_struct *servers=NULL;
2132 uint32 servertype= lp_default_server_announce();
2134 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2136 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2137 for (i=0;i<count;i++)
2138 if (strequal(servers[i].name,local_machine))
2140 servertype = servers[i].type;
2141 pstrcpy(comment,servers[i].comment);
2144 if (servers) free(servers);
2146 SCVAL(p,0,lp_major_announce_version());
2147 SCVAL(p,1,lp_minor_announce_version());
2148 SIVAL(p,2,servertype);
2150 if (mdrcnt == struct_len) {
2153 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2154 standard_sub_conn(conn,comment);
2155 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2156 p2 = skip_string(p2,1);
2161 return False; /* not yet implemented */
2164 *rdata_len = PTR_DIFF(p2,*rdata);
2167 *rparam = REALLOC(*rparam,*rparam_len);
2168 SSVAL(*rparam,0,NERR_Success);
2169 SSVAL(*rparam,2,0); /* converter word */
2170 SSVAL(*rparam,4,*rdata_len);
2176 /****************************************************************************
2177 get info about the server
2178 ****************************************************************************/
2179 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2180 int mdrcnt,int mprcnt,
2181 char **rdata,char **rparam,
2182 int *rdata_len,int *rparam_len)
2184 char *str1 = param+2;
2185 char *str2 = skip_string(str1,1);
2186 char *p = skip_string(str2,1);
2188 extern pstring sesssetup_user;
2189 int level = SVAL(p,0);
2191 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2194 *rparam = REALLOC(*rparam,*rparam_len);
2196 /* check it's a supported varient */
2197 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2200 *rdata_len = mdrcnt + 1024;
2201 *rdata = REALLOC(*rdata,*rdata_len);
2203 SSVAL(*rparam,0,NERR_Success);
2204 SSVAL(*rparam,2,0); /* converter word */
2210 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2211 pstrcpy(p2,local_machine);
2213 p2 = skip_string(p2,1);
2216 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2217 pstrcpy(p2,sesssetup_user);
2218 p2 = skip_string(p2,1);
2221 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2222 pstrcpy(p2,global_myworkgroup);
2224 p2 = skip_string(p2,1);
2227 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2228 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2231 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2232 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2233 p2 = skip_string(p2,1);
2236 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2238 p2 = skip_string(p2,1);
2241 *rdata_len = PTR_DIFF(p2,*rdata);
2243 SSVAL(*rparam,4,*rdata_len);
2248 /****************************************************************************
2249 get info about a user
2251 struct user_info_11 {
2252 char usri11_name[21]; 0-20
2254 char *usri11_comment; 22-25
2255 char *usri11_usr_comment; 26-29
2256 unsigned short usri11_priv; 30-31
2257 unsigned long usri11_auth_flags; 32-35
2258 long usri11_password_age; 36-39
2259 char *usri11_homedir; 40-43
2260 char *usri11_parms; 44-47
2261 long usri11_last_logon; 48-51
2262 long usri11_last_logoff; 52-55
2263 unsigned short usri11_bad_pw_count; 56-57
2264 unsigned short usri11_num_logons; 58-59
2265 char *usri11_logon_server; 60-63
2266 unsigned short usri11_country_code; 64-65
2267 char *usri11_workstations; 66-69
2268 unsigned long usri11_max_storage; 70-73
2269 unsigned short usri11_units_per_week; 74-75
2270 unsigned char *usri11_logon_hours; 76-79
2271 unsigned short usri11_code_page; 80-81
2276 usri11_name specifies the user name for which information is retireved
2278 usri11_pad aligns the next data structure element to a word boundary
2280 usri11_comment is a null terminated ASCII comment
2282 usri11_user_comment is a null terminated ASCII comment about the user
2284 usri11_priv specifies the level of the privilege assigned to the user.
2285 The possible values are:
2287 Name Value Description
2288 USER_PRIV_GUEST 0 Guest privilege
2289 USER_PRIV_USER 1 User privilege
2290 USER_PRV_ADMIN 2 Administrator privilege
2292 usri11_auth_flags specifies the account operator privileges. The
2293 possible values are:
2295 Name Value Description
2296 AF_OP_PRINT 0 Print operator
2299 Leach, Naik [Page 28]
2303 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2306 AF_OP_COMM 1 Communications operator
2307 AF_OP_SERVER 2 Server operator
2308 AF_OP_ACCOUNTS 3 Accounts operator
2311 usri11_password_age specifies how many seconds have elapsed since the
2312 password was last changed.
2314 usri11_home_dir points to a null terminated ASCII string that contains
2315 the path name of the user's home directory.
2317 usri11_parms points to a null terminated ASCII string that is set
2318 aside for use by applications.
2320 usri11_last_logon specifies the time when the user last logged on.
2321 This value is stored as the number of seconds elapsed since
2322 00:00:00, January 1, 1970.
2324 usri11_last_logoff specifies the time when the user last logged off.
2325 This value is stored as the number of seconds elapsed since
2326 00:00:00, January 1, 1970. A value of 0 means the last logoff
2329 usri11_bad_pw_count specifies the number of incorrect passwords
2330 entered since the last successful logon.
2332 usri11_log1_num_logons specifies the number of times this user has
2333 logged on. A value of -1 means the number of logons is unknown.
2335 usri11_logon_server points to a null terminated ASCII string that
2336 contains the name of the server to which logon requests are sent.
2337 A null string indicates logon requests should be sent to the
2340 usri11_country_code specifies the country code for the user's language
2343 usri11_workstations points to a null terminated ASCII string that
2344 contains the names of workstations the user may log on from.
2345 There may be up to 8 workstations, with the names separated by
2346 commas. A null strings indicates there are no restrictions.
2348 usri11_max_storage specifies the maximum amount of disk space the user
2349 can occupy. A value of 0xffffffff indicates there are no
2352 usri11_units_per_week specifies the equal number of time units into
2353 which a week is divided. This value must be equal to 168.
2355 usri11_logon_hours points to a 21 byte (168 bits) string that
2356 specifies the time during which the user can log on. Each bit
2357 represents one unique hour in a week. The first bit (bit 0, word
2358 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2362 Leach, Naik [Page 29]
2366 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2369 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2370 are no restrictions.
2372 usri11_code_page specifies the code page for the user's language of
2375 All of the pointers in this data structure need to be treated
2376 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2377 to be ignored. The converter word returned in the parameters section
2378 needs to be subtracted from the lower 16 bits to calculate an offset
2379 into the return buffer where this ASCII string resides.
2381 There is no auxiliary data in the response.
2383 ****************************************************************************/
2385 #define usri11_name 0
2386 #define usri11_pad 21
2387 #define usri11_comment 22
2388 #define usri11_usr_comment 26
2389 #define usri11_full_name 30
2390 #define usri11_priv 34
2391 #define usri11_auth_flags 36
2392 #define usri11_password_age 40
2393 #define usri11_homedir 44
2394 #define usri11_parms 48
2395 #define usri11_last_logon 52
2396 #define usri11_last_logoff 56
2397 #define usri11_bad_pw_count 60
2398 #define usri11_num_logons 62
2399 #define usri11_logon_server 64
2400 #define usri11_country_code 68
2401 #define usri11_workstations 70
2402 #define usri11_max_storage 74
2403 #define usri11_units_per_week 78
2404 #define usri11_logon_hours 80
2405 #define usri11_code_page 84
2406 #define usri11_end 86
2408 #define USER_PRIV_GUEST 0
2409 #define USER_PRIV_USER 1
2410 #define USER_PRIV_ADMIN 2
2412 #define AF_OP_PRINT 0
2413 #define AF_OP_COMM 1
2414 #define AF_OP_SERVER 2
2415 #define AF_OP_ACCOUNTS 3
2418 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2419 int mdrcnt,int mprcnt,
2420 char **rdata,char **rparam,
2421 int *rdata_len,int *rparam_len)
2423 char *str1 = param+2;
2424 char *str2 = skip_string(str1,1);
2425 char *UserName = skip_string(str2,1);
2426 char *p = skip_string(UserName,1);
2427 int uLevel = SVAL(p,0);
2430 /* get NIS home of a previously validated user - simeon */
2431 /* With share level security vuid will always be zero.
2432 Don't depend on vuser being non-null !!. JRA */
2433 user_struct *vuser = get_valid_user_struct(vuid);
2435 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2436 vuser->user.unix_name));
2439 *rparam = REALLOC(*rparam,*rparam_len);
2441 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2443 /* check it's a supported variant */
2444 if (strcmp(str1,"zWrLh") != 0) return False;
2447 case 0: p2 = "B21"; break;
2448 case 1: p2 = "B21BB16DWzzWz"; break;
2449 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2450 case 10: p2 = "B21Bzzz"; break;
2451 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2452 default: return False;
2455 if (strcmp(p2,str2) != 0) return False;
2457 *rdata_len = mdrcnt + 1024;
2458 *rdata = REALLOC(*rdata,*rdata_len);
2460 SSVAL(*rparam,0,NERR_Success);
2461 SSVAL(*rparam,2,0); /* converter word */
2464 p2 = p + usri11_end;
2467 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2471 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2476 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2477 pstrcpy(p2,"Comment");
2478 p2 = skip_string(p2,1);
2480 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2481 pstrcpy(p2,"UserComment");
2482 p2 = skip_string(p2,1);
2484 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2485 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2486 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2487 p2 = skip_string(p2,1);
2490 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2492 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2493 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2494 SIVALS(p,usri11_password_age,-1); /* password age */
2495 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2496 pstrcpy(p2, lp_logon_home());
2497 standard_sub_conn(conn, p2);
2498 p2 = skip_string(p2,1);
2499 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2501 p2 = skip_string(p2,1);
2502 SIVAL(p,usri11_last_logon,0); /* last logon */
2503 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2504 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2505 SSVALS(p,usri11_num_logons,-1); /* num logons */
2506 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2507 pstrcpy(p2,"\\\\*");
2508 p2 = skip_string(p2,1);
2509 SSVAL(p,usri11_country_code,0); /* country code */
2511 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2513 p2 = skip_string(p2,1);
2515 SIVALS(p,usri11_max_storage,-1); /* max storage */
2516 SSVAL(p,usri11_units_per_week,168); /* units per week */
2517 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2519 /* a simple way to get logon hours at all times. */
2521 SCVAL(p2,21,0); /* fix zero termination */
2522 p2 = skip_string(p2,1);
2524 SSVAL(p,usri11_code_page,0); /* code page */
2526 if (uLevel == 1 || uLevel == 2)
2528 memset(p+22,' ',16); /* password */
2529 SIVALS(p,38,-1); /* password age */
2531 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2532 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2533 pstrcpy(p2,lp_logon_home());
2534 standard_sub_conn(conn, p2);
2535 p2 = skip_string(p2,1);
2536 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2538 SSVAL(p,52,0); /* flags */
2539 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2540 pstrcpy(p2,lp_logon_script());
2541 standard_sub_conn( conn, p2 );
2542 p2 = skip_string(p2,1);
2545 SIVAL(p,60,0); /* auth_flags */
2546 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2547 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2548 p2 = skip_string(p2,1);
2549 SIVAL(p,68,0); /* urs_comment */
2550 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2552 p2 = skip_string(p2,1);
2553 SIVAL(p,76,0); /* workstations */
2554 SIVAL(p,80,0); /* last_logon */
2555 SIVAL(p,84,0); /* last_logoff */
2556 SIVALS(p,88,-1); /* acct_expires */
2557 SIVALS(p,92,-1); /* max_storage */
2558 SSVAL(p,96,168); /* units_per_week */
2559 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2562 SSVALS(p,102,-1); /* bad_pw_count */
2563 SSVALS(p,104,-1); /* num_logons */
2564 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2565 pstrcpy(p2,"\\\\%L");
2566 standard_sub_conn(conn, p2);
2567 p2 = skip_string(p2,1);
2568 SSVAL(p,110,49); /* country_code */
2569 SSVAL(p,112,860); /* code page */
2573 *rdata_len = PTR_DIFF(p2,*rdata);
2575 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2580 /*******************************************************************
2581 get groups that a user is a member of
2582 ******************************************************************/
2583 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2584 int mdrcnt,int mprcnt,
2585 char **rdata,char **rparam,
2586 int *rdata_len,int *rparam_len)
2588 char *str1 = param+2;
2589 char *str2 = skip_string(str1,1);
2590 char *UserName = skip_string(str2,1);
2591 char *p = skip_string(UserName,1);
2592 int uLevel = SVAL(p,0);
2597 *rparam = REALLOC(*rparam,*rparam_len);
2599 /* check it's a supported varient */
2600 if (strcmp(str1,"zWrLeh") != 0) return False;
2602 case 0: p2 = "B21"; break;
2603 default: return False;
2605 if (strcmp(p2,str2) != 0) return False;
2607 *rdata_len = mdrcnt + 1024;
2608 *rdata = REALLOC(*rdata,*rdata_len);
2610 SSVAL(*rparam,0,NERR_Success);
2611 SSVAL(*rparam,2,0); /* converter word */
2615 /* XXXX we need a real SAM database some day */
2616 pstrcpy(p,"Users"); p += 21; count++;
2617 pstrcpy(p,"Domain Users"); p += 21; count++;
2618 pstrcpy(p,"Guests"); p += 21; count++;
2619 pstrcpy(p,"Domain Guests"); p += 21; count++;
2621 *rdata_len = PTR_DIFF(p,*rdata);
2623 SSVAL(*rparam,4,count); /* is this right?? */
2624 SSVAL(*rparam,6,count); /* is this right?? */
2630 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2631 int mdrcnt,int mprcnt,
2632 char **rdata,char **rparam,
2633 int *rdata_len,int *rparam_len)
2635 char *str1 = param+2;
2636 char *str2 = skip_string(str1,1);
2637 char *p = skip_string(str2,1);
2639 struct pack_desc desc;
2645 memset((char *)&desc,'\0',sizeof(desc));
2647 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2649 /* check it's a supported varient */
2650 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2651 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2652 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2654 desc.buflen = mdrcnt;
2655 desc.subformat = NULL;
2658 if (init_package(&desc,1,0))
2660 PACKI(&desc,"W",0); /* code */
2661 PACKS(&desc,"B21",name); /* eff. name */
2662 PACKS(&desc,"B",""); /* pad */
2664 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2665 PACKI(&desc,"D",0); /* auth flags XXX */
2666 PACKI(&desc,"W",0); /* num logons */
2667 PACKI(&desc,"W",0); /* bad pw count */
2668 PACKI(&desc,"D",0); /* last logon */
2669 PACKI(&desc,"D",-1); /* last logoff */
2670 PACKI(&desc,"D",-1); /* logoff time */
2671 PACKI(&desc,"D",-1); /* kickoff time */
2672 PACKI(&desc,"D",0); /* password age */
2673 PACKI(&desc,"D",0); /* password can change */
2674 PACKI(&desc,"D",-1); /* password must change */
2677 fstrcpy(mypath,"\\\\");
2678 fstrcat(mypath,local_machine);
2680 PACKS(&desc,"z",mypath); /* computer */
2682 PACKS(&desc,"z",global_myworkgroup);/* domain */
2684 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2685 /* made sure all macros are fully substituted and available */
2687 pstring logon_script;
2688 pstrcpy(logon_script,lp_logon_script());
2689 standard_sub_conn( conn, logon_script );
2690 PACKS(&desc,"z", logon_script); /* script path */
2692 /* End of JHT mods */
2694 PACKI(&desc,"D",0x00000000); /* reserved */
2697 *rdata_len = desc.usedlen;
2699 *rparam = REALLOC(*rparam,*rparam_len);
2700 SSVALS(*rparam,0,desc.errcode);
2702 SSVAL(*rparam,4,desc.neededlen);
2704 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2709 /****************************************************************************
2710 api_WAccessGetUserPerms
2711 ****************************************************************************/
2712 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2713 int mdrcnt,int mprcnt,
2714 char **rdata,char **rparam,
2715 int *rdata_len,int *rparam_len)
2717 char *str1 = param+2;
2718 char *str2 = skip_string(str1,1);
2719 char *user = skip_string(str2,1);
2720 char *resource = skip_string(user,1);
2722 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2724 /* check it's a supported varient */
2725 if (strcmp(str1,"zzh") != 0) return False;
2726 if (strcmp(str2,"") != 0) return False;
2729 *rparam = REALLOC(*rparam,*rparam_len);
2730 SSVALS(*rparam,0,0); /* errorcode */
2731 SSVAL(*rparam,2,0); /* converter word */
2732 SSVAL(*rparam,4,0x7f); /* permission flags */
2737 /****************************************************************************
2738 api_WPrintJobEnumerate
2739 ****************************************************************************/
2740 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2741 int mdrcnt,int mprcnt,
2742 char **rdata,char **rparam,
2743 int *rdata_len,int *rparam_len)
2745 char *str1 = param+2;
2746 char *str2 = skip_string(str1,1);
2747 char *p = skip_string(str2,1);
2753 struct pack_desc desc;
2754 print_queue_struct *queue=NULL;
2755 print_status_struct status;
2759 memset((char *)&desc,'\0',sizeof(desc));
2760 memset((char *)&status,'\0',sizeof(status));
2762 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2764 /* check it's a supported varient */
2765 if (strcmp(str1,"WWrLh") != 0) return False;
2766 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2769 snum = print_job_snum(job);
2771 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2773 count = print_queue_status(snum,&queue,&status);
2774 for (i = 0; i < count; i++) {
2775 if (queue[i].job == job) break;
2777 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2779 desc.buflen = mdrcnt;
2781 if (init_package(&desc,1,0)) {
2783 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2784 *rdata_len = desc.usedlen;
2787 desc.errcode = NERR_JobNotFound;
2793 *rparam = REALLOC(*rparam,*rparam_len);
2794 SSVALS(*rparam,0,desc.errcode);
2796 SSVAL(*rparam,4,desc.neededlen);
2798 if (queue) free(queue);
2800 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2804 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2805 int mdrcnt,int mprcnt,
2806 char **rdata,char **rparam,
2807 int *rdata_len,int *rparam_len)
2809 char *str1 = param+2;
2810 char *str2 = skip_string(str1,1);
2811 char *p = skip_string(str2,1);
2817 struct pack_desc desc;
2818 print_queue_struct *queue=NULL;
2819 print_status_struct status;
2821 memset((char *)&desc,'\0',sizeof(desc));
2822 memset((char *)&status,'\0',sizeof(status));
2824 p = skip_string(p,1);
2827 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2829 /* check it's a supported varient */
2830 if (strcmp(str1,"zWrLeh") != 0) return False;
2831 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2832 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2834 snum = lp_servicenumber(name);
2835 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2836 int pnum = lp_servicenumber(PRINTERS_NAME);
2838 lp_add_printer(name,pnum);
2839 snum = lp_servicenumber(name);
2843 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2845 count = print_queue_status(snum,&queue,&status);
2846 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2848 desc.buflen = mdrcnt;
2850 if (init_package(&desc,count,0)) {
2852 for (i = 0; i < count; i++) {
2853 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2854 if (desc.errcode == NERR_Success) succnt = i+1;
2858 *rdata_len = desc.usedlen;
2861 *rparam = REALLOC(*rparam,*rparam_len);
2862 SSVALS(*rparam,0,desc.errcode);
2864 SSVAL(*rparam,4,succnt);
2865 SSVAL(*rparam,6,count);
2867 if (queue) free(queue);
2869 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2873 static int check_printdest_info(struct pack_desc* desc,
2874 int uLevel, char* id)
2876 desc->subformat = NULL;
2878 case 0: desc->format = "B9"; break;
2879 case 1: desc->format = "B9B21WWzW"; break;
2880 case 2: desc->format = "z"; break;
2881 case 3: desc->format = "zzzWWzzzWW"; break;
2882 default: return False;
2884 if (strcmp(desc->format,id) != 0) return False;
2888 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2889 struct pack_desc* desc)
2892 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2893 buf[sizeof(buf)-1] = 0;
2896 PACKS(desc,"B9",buf); /* szName */
2898 PACKS(desc,"B21",""); /* szUserName */
2899 PACKI(desc,"W",0); /* uJobId */
2900 PACKI(desc,"W",0); /* fsStatus */
2901 PACKS(desc,"z",""); /* pszStatus */
2902 PACKI(desc,"W",0); /* time */
2905 if (uLevel == 2 || uLevel == 3) {
2906 PACKS(desc,"z",buf); /* pszPrinterName */
2908 PACKS(desc,"z",""); /* pszUserName */
2909 PACKS(desc,"z",""); /* pszLogAddr */
2910 PACKI(desc,"W",0); /* uJobId */
2911 PACKI(desc,"W",0); /* fsStatus */
2912 PACKS(desc,"z",""); /* pszStatus */
2913 PACKS(desc,"z",""); /* pszComment */
2914 PACKS(desc,"z","NULL"); /* pszDrivers */
2915 PACKI(desc,"W",0); /* time */
2916 PACKI(desc,"W",0); /* pad1 */
2921 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2922 int mdrcnt,int mprcnt,
2923 char **rdata,char **rparam,
2924 int *rdata_len,int *rparam_len)
2926 char *str1 = param+2;
2927 char *str2 = skip_string(str1,1);
2928 char *p = skip_string(str2,1);
2929 char* PrinterName = p;
2931 struct pack_desc desc;
2934 memset((char *)&desc,'\0',sizeof(desc));
2936 p = skip_string(p,1);
2939 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2941 /* check it's a supported varient */
2942 if (strcmp(str1,"zWrLh") != 0) return False;
2943 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2945 snum = lp_servicenumber(PrinterName);
2946 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2947 int pnum = lp_servicenumber(PRINTERS_NAME);
2949 lp_add_printer(PrinterName,pnum);
2950 snum = lp_servicenumber(PrinterName);
2956 desc.errcode = NERR_DestNotFound;
2960 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2962 desc.buflen = mdrcnt;
2963 if (init_package(&desc,1,0)) {
2964 fill_printdest_info(conn,snum,uLevel,&desc);
2966 *rdata_len = desc.usedlen;
2970 *rparam = REALLOC(*rparam,*rparam_len);
2971 SSVALS(*rparam,0,desc.errcode);
2973 SSVAL(*rparam,4,desc.neededlen);
2975 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2979 static BOOL api_WPrintDestEnum(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);
2990 struct pack_desc desc;
2991 int services = lp_numservices();
2993 memset((char *)&desc,'\0',sizeof(desc));
2997 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2999 /* check it's a supported varient */
3000 if (strcmp(str1,"WrLeh") != 0) return False;
3001 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3004 for (i = 0; i < services; i++)
3005 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3008 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3010 desc.buflen = mdrcnt;
3011 if (init_package(&desc,queuecnt,0)) {
3014 for (i = 0; i < services; i++) {
3015 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3016 fill_printdest_info(conn,i,uLevel,&desc);
3018 if (desc.errcode == NERR_Success) succnt = n;
3023 *rdata_len = desc.usedlen;
3026 *rparam = REALLOC(*rparam,*rparam_len);
3027 SSVALS(*rparam,0,desc.errcode);
3029 SSVAL(*rparam,4,succnt);
3030 SSVAL(*rparam,6,queuecnt);
3032 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3036 static BOOL api_WPrintDriverEnum(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,("WPrintDriverEnum 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,"B41") != 0) return False;
3058 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3060 desc.buflen = mdrcnt;
3061 if (init_package(&desc,1,0)) {
3062 PACKS(&desc,"B41","NULL");
3065 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3067 *rdata_len = desc.usedlen;
3070 *rparam = REALLOC(*rparam,*rparam_len);
3071 SSVALS(*rparam,0,desc.errcode);
3073 SSVAL(*rparam,4,succnt);
3076 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3080 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3081 int mdrcnt,int mprcnt,
3082 char **rdata,char **rparam,
3083 int *rdata_len,int *rparam_len)
3085 char *str1 = param+2;
3086 char *str2 = skip_string(str1,1);
3087 char *p = skip_string(str2,1);
3090 struct pack_desc desc;
3092 memset((char *)&desc,'\0',sizeof(desc));
3096 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3098 /* check it's a supported varient */
3099 if (strcmp(str1,"WrLeh") != 0) return False;
3100 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3102 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3104 desc.buflen = mdrcnt;
3106 if (init_package(&desc,1,0)) {
3107 PACKS(&desc,"B13","lpd");
3110 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3112 *rdata_len = desc.usedlen;
3115 *rparam = REALLOC(*rparam,*rparam_len);
3116 SSVALS(*rparam,0,desc.errcode);
3118 SSVAL(*rparam,4,succnt);
3121 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3125 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3126 int mdrcnt,int mprcnt,
3127 char **rdata,char **rparam,
3128 int *rdata_len,int *rparam_len)
3130 char *str1 = param+2;
3131 char *str2 = skip_string(str1,1);
3132 char *p = skip_string(str2,1);
3135 struct pack_desc desc;
3137 memset((char *)&desc,'\0',sizeof(desc));
3141 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3143 /* check it's a supported varient */
3144 if (strcmp(str1,"WrLeh") != 0) return False;
3145 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3147 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3148 memset((char *)&desc,'\0',sizeof(desc));
3150 desc.buflen = mdrcnt;
3152 if (init_package(&desc,1,0)) {
3153 PACKS(&desc,"B13","lp0");
3156 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3158 *rdata_len = desc.usedlen;
3161 *rparam = REALLOC(*rparam,*rparam_len);
3162 SSVALS(*rparam,0,desc.errcode);
3164 SSVAL(*rparam,4,succnt);
3167 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3171 /****************************************************************************
3172 The buffer was too small
3173 ****************************************************************************/
3175 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3176 int mdrcnt,int mprcnt,
3177 char **rdata,char **rparam,
3178 int *rdata_len,int *rparam_len)
3180 *rparam_len = MIN(*rparam_len,mprcnt);
3181 *rparam = REALLOC(*rparam,*rparam_len);
3185 SSVAL(*rparam,0,NERR_BufTooSmall);
3187 DEBUG(3,("Supplied buffer too small in API command\n"));
3193 /****************************************************************************
3194 The request is not supported
3195 ****************************************************************************/
3197 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3198 int mdrcnt,int mprcnt,
3199 char **rdata,char **rparam,
3200 int *rdata_len,int *rparam_len)
3203 *rparam = REALLOC(*rparam,*rparam_len);
3207 SSVAL(*rparam,0,NERR_notsupported);
3208 SSVAL(*rparam,2,0); /* converter word */
3210 DEBUG(3,("Unsupported API command\n"));
3222 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3223 int,int,char **,char **,int *,int *);
3225 } api_commands[] = {
3226 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3227 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3228 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3229 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3230 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3231 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3232 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3233 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3234 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3235 {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0},
3236 {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3237 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3238 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3239 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3240 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3241 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3242 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3243 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3244 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3245 {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0},
3246 {"NetServerEnum", 104, api_RNetServerEnum,0},
3247 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3248 {"SetUserPassword", 115, api_SetUserPassword,0},
3249 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3250 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3251 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3252 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3253 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3254 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3255 {NULL, -1, api_Unsupported,0}};
3258 /****************************************************************************
3259 Handle remote api calls
3260 ****************************************************************************/
3262 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3263 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3267 char *rparam = NULL;
3274 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3278 api_command = SVAL(params,0);
3280 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3283 skip_string(params+2,1),
3284 tdscnt,tpscnt,mdrcnt,mprcnt));
3286 for (i=0;api_commands[i].name;i++) {
3287 if (api_commands[i].id == api_command && api_commands[i].fn) {
3288 DEBUG(3,("Doing %s\n",api_commands[i].name));
3293 rdata = (char *)malloc(1024);
3295 memset(rdata,'\0',1024);
3297 rparam = (char *)malloc(1024);
3299 memset(rparam,'\0',1024);
3301 if(!rdata || !rparam) {
3302 DEBUG(0,("api_reply: malloc fail !\n"));
3306 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3307 &rdata,&rparam,&rdata_len,&rparam_len);
3310 if (rdata_len > mdrcnt ||
3311 rparam_len > mprcnt) {
3312 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3313 &rdata,&rparam,&rdata_len,&rparam_len);
3316 /* if we get False back then it's actually unsupported */
3318 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3319 &rdata,&rparam,&rdata_len,&rparam_len);
3321 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);