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 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
741 /* "don't ask" that it's done this way to fix corrupted
742 Win9X/ME printer comments. */
744 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
746 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
748 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
749 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
750 get_driver_name(snum,drivername);
751 PACKS(desc,"z",drivername); /* pszDriverName */
752 PackDriverData(desc); /* pDriverData */
755 if (uLevel == 2 || uLevel == 4) {
757 for (i=0;i<count;i++)
758 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
762 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
766 /* This function returns the number of files for a given driver */
767 static int get_printerdrivernumber(int snum)
778 * Check in the tdb *first* before checking the legacy
779 * files. This allows an NT upload to take precedence over
780 * the existing fileset. JRA.
782 * we need to lookup the driver name prior to making the call
783 * to get_a_printer_driver_9x_compatible() and not rely on the
784 * 'print driver' parameter --jerry
787 if ((get_driver_name(snum,drivername)) &&
788 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
791 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
795 /* didn't find driver in tdb */
797 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
798 snum, drivername, lp_driverfile(snum)));
800 lines = file_lines_load(lp_driverfile(snum), NULL, False);
803 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
807 /* lookup the long printer driver name in the file description */
808 for (i=0;lines[i] && !ok;i++)
811 if (next_token(&p,tok,":",sizeof(tok)) &&
812 (strlen(drivername) == strlen(tok)) &&
813 (!strncmp(tok,drivername,strlen(drivername))))
825 if (*p++ == ':') i--;
828 DEBUG(3,("Can't determine number of printer driver files\n"));
832 /* count the number of files */
833 while (next_token(&p,tok,",",sizeof(tok)))
841 file_lines_free(lines);
846 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
847 uint16 vuid, char *param,char *data,
848 int mdrcnt,int mprcnt,
849 char **rdata,char **rparam,
850 int *rdata_len,int *rparam_len)
852 char *str1 = param+2;
853 char *str2 = skip_string(str1,1);
854 char *p = skip_string(str2,1);
860 struct pack_desc desc;
861 print_queue_struct *queue=NULL;
862 print_status_struct status;
864 memset((char *)&status,'\0',sizeof(status));
865 memset((char *)&desc,'\0',sizeof(desc));
867 p = skip_string(p,1);
871 /* remove any trailing username */
872 if ((p = strchr(QueueName,'%'))) *p = 0;
874 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
876 /* check it's a supported varient */
877 if (!prefix_ok(str1,"zWrLh")) return False;
878 if (!check_printq_info(&desc,uLevel,str2,str3)) {
880 * Patch from Scott Moomaw <scott@bridgewater.edu>
881 * to return the 'invalid info level' error if an
882 * unknown level was requested.
886 *rparam = REALLOC(*rparam,*rparam_len);
887 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
893 snum = lp_servicenumber(QueueName);
894 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
895 int pnum = lp_servicenumber(PRINTERS_NAME);
897 lp_add_printer(QueueName,pnum);
898 snum = lp_servicenumber(QueueName);
902 if (snum < 0 || !VALID_SNUM(snum)) return(False);
905 count = get_printerdrivernumber(snum);
906 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
908 count = print_queue_status(snum, &queue,&status);
911 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
913 desc.buflen = mdrcnt;
914 if (init_package(&desc,1,count)) {
915 desc.subcount = count;
916 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
917 } else if(uLevel == 0) {
920 * This is a *disgusting* hack.
921 * This is *so* bad that even I'm embarrassed (and I
922 * have no shame). Here's the deal :
923 * Until we get the correct SPOOLSS code into smbd
924 * then when we're running with NT SMB support then
925 * NT makes this call with a level of zero, and then
926 * immediately follows it with an open request to
927 * the \\SRVSVC pipe. If we allow that open to
928 * succeed then NT barfs when it cannot open the
929 * \\SPOOLSS pipe immediately after and continually
930 * whines saying "Printer name is invalid" forever
931 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
932 * to fail, then NT downgrades to using the downlevel code
933 * and everything works as well as before. I hate
934 * myself for adding this code.... JRA.
937 fail_next_srvsvc_open();
941 *rdata_len = desc.usedlen;
944 *rparam = REALLOC(*rparam,*rparam_len);
945 SSVALS(*rparam,0,desc.errcode);
947 SSVAL(*rparam,4,desc.neededlen);
949 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
951 if (queue) free(queue);
956 /****************************************************************************
957 View list of all print jobs on all queues.
958 ****************************************************************************/
960 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
961 int mdrcnt, int mprcnt,
962 char **rdata, char** rparam,
963 int *rdata_len, int *rparam_len)
965 char *param_format = param+2;
966 char *output_format1 = skip_string(param_format,1);
967 char *p = skip_string(output_format1,1);
968 int uLevel = SVAL(p,0);
969 char *output_format2 = p + 4;
970 int services = lp_numservices();
972 struct pack_desc desc;
973 print_queue_struct **queue = NULL;
974 print_status_struct *status = NULL;
975 int* subcntarr = NULL;
976 int queuecnt, subcnt=0, succnt=0;
978 memset((char *)&desc,'\0',sizeof(desc));
980 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
982 if (!prefix_ok(param_format,"WrLeh")) return False;
983 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
985 * Patch from Scott Moomaw <scott@bridgewater.edu>
986 * to return the 'invalid info level' error if an
987 * unknown level was requested.
991 *rparam = REALLOC(*rparam,*rparam_len);
992 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
999 for (i = 0; i < services; i++)
1000 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1003 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1004 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1007 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1008 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1009 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1012 memset(status,0,queuecnt*sizeof(print_status_struct));
1013 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1014 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1019 for (i = 0; i < services; i++)
1020 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1021 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1022 subcnt += subcntarr[n];
1026 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1028 desc.buflen = mdrcnt;
1030 if (init_package(&desc,queuecnt,subcnt)) {
1033 for (i = 0; i < services; i++)
1034 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1035 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1037 if (desc.errcode == NERR_Success) succnt = n;
1041 if (subcntarr) free(subcntarr);
1043 *rdata_len = desc.usedlen;
1045 *rparam = REALLOC(*rparam,*rparam_len);
1046 SSVALS(*rparam,0,desc.errcode);
1048 SSVAL(*rparam,4,succnt);
1049 SSVAL(*rparam,6,queuecnt);
1051 for (i = 0; i < queuecnt; i++) {
1052 if (queue && queue[i]) free(queue[i]);
1055 if (queue) free(queue);
1056 if (status) free(status);
1061 /****************************************************************************
1062 get info level for a server list query
1063 ****************************************************************************/
1064 static BOOL check_server_info(int uLevel, char* id)
1068 if (strcmp(id,"B16") != 0) return False;
1071 if (strcmp(id,"B16BBDz") != 0) return False;
1079 struct srv_info_struct
1089 /*******************************************************************
1090 get server info lists from the files saved by nmbd. Return the
1092 ******************************************************************/
1093 static int get_server_info(uint32 servertype,
1094 struct srv_info_struct **servers,
1100 BOOL local_list_only;
1103 lines = file_lines_load(lock_path(SERVER_LIST), NULL, False);
1105 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1109 /* request for everything is code for request all servers */
1110 if (servertype == SV_TYPE_ALL)
1111 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1113 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1115 DEBUG(4,("Servertype search: %8x\n",servertype));
1117 for (i=0;lines[i];i++) {
1119 struct srv_info_struct *s;
1120 char *ptr = lines[i];
1123 if (!*ptr) continue;
1125 if (count == alloced) {
1127 (*servers) = (struct srv_info_struct *)
1128 Realloc(*servers,sizeof(**servers)*alloced);
1129 if (!(*servers)) return(0);
1130 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1132 s = &(*servers)[count];
1134 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1135 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1136 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1137 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1138 /* this allows us to cope with an old nmbd */
1139 pstrcpy(s->domain,global_myworkgroup);
1142 if (sscanf(stype,"%X",&s->type) != 1) {
1143 DEBUG(4,("r:host file "));
1147 /* Filter the servers/domains we return based on what was asked for. */
1149 /* Check to see if we are being asked for a local list only. */
1150 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1151 DEBUG(4,("r: local list only"));
1155 /* doesn't match up: don't want it */
1156 if (!(servertype & s->type)) {
1157 DEBUG(4,("r:serv type "));
1161 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1162 (s->type & SV_TYPE_DOMAIN_ENUM))
1164 DEBUG(4,("s: dom mismatch "));
1168 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1173 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1174 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1178 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1179 s->name, s->type, s->comment, s->domain));
1181 s->server_added = True;
1186 DEBUG(4,("%20s %8x %25s %15s\n",
1187 s->name, s->type, s->comment, s->domain));
1191 file_lines_free(lines);
1196 /*******************************************************************
1197 fill in a server info structure
1198 ******************************************************************/
1199 static int fill_srv_info(struct srv_info_struct *service,
1200 int uLevel, char **buf, int *buflen,
1201 char **stringbuf, int *stringspace, char *baseaddr)
1210 case 0: struct_len = 16; break;
1211 case 1: struct_len = 26; break;
1221 len = strlen(service->comment)+1;
1225 if (buflen) *buflen = struct_len;
1226 if (stringspace) *stringspace = len;
1227 return struct_len + len;
1232 if (*buflen < struct_len) return -1;
1240 p2 = p + struct_len;
1241 l2 = *buflen - struct_len;
1243 if (!baseaddr) baseaddr = p;
1248 StrnCpy(p,service->name,15);
1252 StrnCpy(p,service->name,15);
1253 SIVAL(p,18,service->type);
1254 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1255 len += CopyAndAdvance(&p2,service->comment,&l2);
1261 *buf = p + struct_len;
1262 *buflen -= struct_len;
1275 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1277 return(strcmp(s1->name,s2->name));
1280 /****************************************************************************
1281 view list of servers available (or possibly domains). The info is
1282 extracted from lists saved by nmbd on the local host
1283 ****************************************************************************/
1284 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1285 int mdrcnt, int mprcnt, char **rdata,
1286 char **rparam, int *rdata_len, int *rparam_len)
1288 char *str1 = param+2;
1289 char *str2 = skip_string(str1,1);
1290 char *p = skip_string(str2,1);
1291 int uLevel = SVAL(p,0);
1292 int buf_len = SVAL(p,2);
1293 uint32 servertype = IVAL(p,4);
1295 int data_len, fixed_len, string_len;
1296 int f_len = 0, s_len = 0;
1297 struct srv_info_struct *servers=NULL;
1298 int counted=0,total=0;
1301 BOOL domain_request;
1304 /* If someone sets all the bits they don't really mean to set
1305 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1308 if (servertype == SV_TYPE_ALL)
1309 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1311 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1312 any other bit (they may just set this bit on it's own) they
1313 want all the locally seen servers. However this bit can be
1314 set on its own so set the requested servers to be
1315 ALL - DOMAIN_ENUM. */
1317 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1318 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1320 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1321 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1325 if (!prefix_ok(str1,"WrLehD")) return False;
1326 if (!check_server_info(uLevel,str2)) return False;
1328 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1329 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1330 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1332 if (strcmp(str1, "WrLehDz") == 0) {
1333 StrnCpy(domain, p, sizeof(fstring)-1);
1335 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1338 if (lp_browse_list())
1339 total = get_server_info(servertype,&servers,domain);
1341 data_len = fixed_len = string_len = 0;
1344 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1347 char *lastname=NULL;
1349 for (i=0;i<total;i++)
1351 struct srv_info_struct *s = &servers[i];
1352 if (lastname && strequal(lastname,s->name)) continue;
1354 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1355 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1356 s->name, s->type, s->comment, s->domain));
1358 if (data_len <= buf_len) {
1361 string_len += s_len;
1368 *rdata_len = fixed_len + string_len;
1369 *rdata = REALLOC(*rdata,*rdata_len);
1370 memset(*rdata,'\0',*rdata_len);
1372 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1378 char *lastname=NULL;
1379 int count2 = counted;
1380 for (i = 0; i < total && count2;i++)
1382 struct srv_info_struct *s = &servers[i];
1383 if (lastname && strequal(lastname,s->name)) continue;
1385 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1386 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1387 s->name, s->type, s->comment, s->domain));
1393 *rparam = REALLOC(*rparam,*rparam_len);
1394 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1396 SSVAL(*rparam,4,counted);
1397 SSVAL(*rparam,6,counted+missed);
1399 if (servers) free(servers);
1401 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1402 domain,uLevel,counted,counted+missed));
1407 /****************************************************************************
1408 command 0x34 - suspected of being a "Lookup Names" stub api
1409 ****************************************************************************/
1410 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1411 int mdrcnt, int mprcnt, char **rdata,
1412 char **rparam, int *rdata_len, int *rparam_len)
1414 char *str1 = param+2;
1415 char *str2 = skip_string(str1,1);
1416 char *p = skip_string(str2,1);
1417 int uLevel = SVAL(p,0);
1418 int buf_len = SVAL(p,2);
1422 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1423 str1, str2, p, uLevel, buf_len));
1425 if (!prefix_ok(str1,"zWrLeh")) return False;
1430 *rparam = REALLOC(*rparam,*rparam_len);
1432 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1434 SSVAL(*rparam,4,counted);
1435 SSVAL(*rparam,6,counted+missed);
1440 /****************************************************************************
1441 get info about a share
1442 ****************************************************************************/
1443 static BOOL check_share_info(int uLevel, char* id)
1447 if (strcmp(id,"B13") != 0) return False;
1450 if (strcmp(id,"B13BWz") != 0) return False;
1453 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1456 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1458 default: return False;
1463 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1464 char** buf, int* buflen,
1465 char** stringbuf, int* stringspace, char* baseaddr)
1474 case 0: struct_len = 13; break;
1475 case 1: struct_len = 20; break;
1476 case 2: struct_len = 40; break;
1477 case 91: struct_len = 68; break;
1485 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1486 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1487 if (buflen) *buflen = struct_len;
1488 if (stringspace) *stringspace = len;
1489 return struct_len + len;
1494 if ((*buflen) < struct_len) return -1;
1502 p2 = p + struct_len;
1503 l2 = (*buflen) - struct_len;
1505 if (!baseaddr) baseaddr = p;
1507 StrnCpy(p,lp_servicename(snum),13);
1513 type = STYPE_DISKTREE;
1514 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1515 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1516 SSVAL(p,14,type); /* device type */
1517 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1518 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1523 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1524 SSVALS(p,22,-1); /* max uses */
1525 SSVAL(p,24,1); /* current uses */
1526 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1527 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1528 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1533 memset(p+40,0,SHPWLEN+2);
1545 (*buf) = p + struct_len;
1546 (*buflen) -= struct_len;
1548 (*stringspace) = l2;
1558 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1559 int mdrcnt,int mprcnt,
1560 char **rdata,char **rparam,
1561 int *rdata_len,int *rparam_len)
1563 char *str1 = param+2;
1564 char *str2 = skip_string(str1,1);
1565 char *netname = skip_string(str2,1);
1566 char *p = skip_string(netname,1);
1567 int uLevel = SVAL(p,0);
1568 int snum = find_service(netname);
1570 if (snum < 0) return False;
1572 /* check it's a supported varient */
1573 if (!prefix_ok(str1,"zWrLh")) return False;
1574 if (!check_share_info(uLevel,str2)) return False;
1576 *rdata = REALLOC(*rdata,mdrcnt);
1578 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1579 if (*rdata_len < 0) return False;
1582 *rparam = REALLOC(*rparam,*rparam_len);
1583 SSVAL(*rparam,0,NERR_Success);
1584 SSVAL(*rparam,2,0); /* converter word */
1585 SSVAL(*rparam,4,*rdata_len);
1590 /****************************************************************************
1591 view list of shares available
1592 ****************************************************************************/
1593 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1594 int mdrcnt,int mprcnt,
1595 char **rdata,char **rparam,
1596 int *rdata_len,int *rparam_len)
1598 char *str1 = param+2;
1599 char *str2 = skip_string(str1,1);
1600 char *p = skip_string(str2,1);
1601 int uLevel = SVAL(p,0);
1602 int buf_len = SVAL(p,2);
1604 int count=lp_numservices();
1605 int total=0,counted=0;
1606 BOOL missed = False;
1608 int data_len, fixed_len, string_len;
1609 int f_len = 0, s_len = 0;
1611 if (!prefix_ok(str1,"WrLeh")) return False;
1612 if (!check_share_info(uLevel,str2)) return False;
1614 data_len = fixed_len = string_len = 0;
1615 for (i=0;i<count;i++)
1616 if (lp_browseable(i) && lp_snum_ok(i))
1619 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1620 if (data_len <= buf_len)
1624 string_len += s_len;
1629 *rdata_len = fixed_len + string_len;
1630 *rdata = REALLOC(*rdata,*rdata_len);
1631 memset(*rdata,0,*rdata_len);
1633 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1637 for (i = 0; i < count;i++)
1638 if (lp_browseable(i) && lp_snum_ok(i))
1639 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1643 *rparam = REALLOC(*rparam,*rparam_len);
1644 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1646 SSVAL(*rparam,4,counted);
1647 SSVAL(*rparam,6,total);
1649 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1650 counted,total,uLevel,
1651 buf_len,*rdata_len,mdrcnt));
1657 /****************************************************************************
1658 get the time of day info
1659 ****************************************************************************/
1660 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1661 int mdrcnt,int mprcnt,
1662 char **rdata,char **rparam,
1663 int *rdata_len,int *rparam_len)
1667 *rparam = REALLOC(*rparam,*rparam_len);
1670 *rdata = REALLOC(*rdata,*rdata_len);
1672 SSVAL(*rparam,0,NERR_Success);
1673 SSVAL(*rparam,2,0); /* converter word */
1679 time_t unixdate = time(NULL);
1681 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1682 by NT in a "net time" operation,
1683 it seems to ignore the one below */
1685 /* the client expects to get localtime, not GMT, in this bit
1686 (I think, this needs testing) */
1687 t = LocalTime(&unixdate);
1689 SIVAL(p,4,0); /* msecs ? */
1690 CVAL(p,8) = t->tm_hour;
1691 CVAL(p,9) = t->tm_min;
1692 CVAL(p,10) = t->tm_sec;
1693 CVAL(p,11) = 0; /* hundredths of seconds */
1694 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1695 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1696 CVAL(p,16) = t->tm_mday;
1697 CVAL(p,17) = t->tm_mon + 1;
1698 SSVAL(p,18,1900+t->tm_year);
1699 CVAL(p,20) = t->tm_wday;
1706 /****************************************************************************
1707 Set the user password.
1708 *****************************************************************************/
1710 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1711 int mdrcnt,int mprcnt,
1712 char **rdata,char **rparam,
1713 int *rdata_len,int *rparam_len)
1715 char *p = skip_string(param+2,2);
1717 fstring pass1,pass2;
1721 p = skip_string(p,1);
1723 memset(pass1,'\0',sizeof(pass1));
1724 memset(pass2,'\0',sizeof(pass2));
1726 memcpy(pass2,p+16,16);
1729 *rparam = REALLOC(*rparam,*rparam_len);
1733 SSVAL(*rparam,0,NERR_badpass);
1734 SSVAL(*rparam,2,0); /* converter word */
1736 DEBUG(3,("Set password for <%s>\n",user));
1739 * Pass the user through the NT -> unix user mapping
1743 (void)map_username(user);
1746 * Do any UNIX username case mangling.
1748 (void)Get_Pwnam( user, True);
1751 * Attempt to verify the old password against smbpasswd entries
1752 * Win98 clients send old and new password in plaintext for this call.
1756 fstring saved_pass2;
1757 SAM_ACCOUNT *sampass;
1760 * Save the new password as change_oem_password overwrites it
1764 fstrcpy(saved_pass2, pass2);
1766 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1767 change_oem_password(sampass,pass2,False))
1769 SSVAL(*rparam,0,NERR_Success);
1772 * If unix password sync was requested, attempt to change
1773 * the /etc/passwd database also. Return failure if this cannot
1777 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1778 SSVAL(*rparam,0,NERR_badpass);
1783 * If the above failed, attempt the plaintext password change.
1784 * This tests against the /etc/passwd database only.
1787 if(SVAL(*rparam,0) != NERR_Success)
1789 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1790 chgpasswd(user,pass1,pass2,False))
1792 SSVAL(*rparam,0,NERR_Success);
1797 * If the plaintext change failed, attempt
1798 * the old encrypted method. NT will generate this
1799 * after trying the samr method. Note that this
1800 * method is done as a last resort as this
1801 * password change method loses the NT password hash
1802 * and cannot change the UNIX password as no plaintext
1806 if(SVAL(*rparam,0) != NERR_Success)
1808 SAM_ACCOUNT *hnd = NULL;
1810 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
1811 change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1813 SSVAL(*rparam,0,NERR_Success);
1817 memset((char *)pass1,'\0',sizeof(fstring));
1818 memset((char *)pass2,'\0',sizeof(fstring));
1823 /****************************************************************************
1824 Set the user password (SamOEM version - gets plaintext).
1825 ****************************************************************************/
1827 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1828 int mdrcnt,int mprcnt,
1829 char **rdata,char **rparam,
1830 int *rdata_len,int *rparam_len)
1833 char *p = param + 2;
1835 *rparam = REALLOC(*rparam,*rparam_len);
1839 SSVAL(*rparam,0,NERR_badpass);
1842 * Check the parameter definition is correct.
1844 if(!strequal(param + 2, "zsT")) {
1845 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1848 p = skip_string(p, 1);
1850 if(!strequal(p, "B516B16")) {
1851 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1854 p = skip_string(p,1);
1857 p = skip_string(p,1);
1859 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1862 * Pass the user through the NT -> unix user mapping
1866 (void)map_username(user);
1869 * Do any UNIX username case mangling.
1871 (void)Get_Pwnam( user, True);
1873 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1875 SSVAL(*rparam,0,NERR_Success);
1881 /****************************************************************************
1884 ****************************************************************************/
1885 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1886 int mdrcnt,int mprcnt,
1887 char **rdata,char **rparam,
1888 int *rdata_len,int *rparam_len)
1890 int function = SVAL(param,0);
1891 char *str1 = param+2;
1892 char *str2 = skip_string(str1,1);
1893 char *p = skip_string(str2,1);
1895 extern struct current_user current_user;
1899 /* check it's a supported varient */
1900 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1904 *rparam = REALLOC(*rparam,*rparam_len);
1907 if (!print_job_exists(jobid)) {
1908 errcode = NERR_JobNotFound;
1912 errcode = NERR_notsupported;
1915 case 81: /* delete */
1916 if (print_job_delete(¤t_user, jobid, &errcode))
1917 errcode = NERR_Success;
1919 case 82: /* pause */
1920 if (print_job_pause(¤t_user, jobid, &errcode))
1921 errcode = NERR_Success;
1923 case 83: /* resume */
1924 if (print_job_resume(¤t_user, jobid, &errcode))
1925 errcode = NERR_Success;
1930 SSVAL(*rparam,0,errcode);
1931 SSVAL(*rparam,2,0); /* converter word */
1936 /****************************************************************************
1937 Purge a print queue - or pause or resume it.
1938 ****************************************************************************/
1939 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1940 int mdrcnt,int mprcnt,
1941 char **rdata,char **rparam,
1942 int *rdata_len,int *rparam_len)
1944 int function = SVAL(param,0);
1945 char *str1 = param+2;
1946 char *str2 = skip_string(str1,1);
1947 char *QueueName = skip_string(str2,1);
1948 int errcode = NERR_notsupported;
1950 extern struct current_user current_user;
1952 /* check it's a supported varient */
1953 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1957 *rparam = REALLOC(*rparam,*rparam_len);
1960 snum = print_queue_snum(QueueName);
1963 errcode = NERR_JobNotFound;
1968 case 74: /* Pause queue */
1969 if (print_queue_pause(¤t_user, snum, &errcode)) errcode = NERR_Success;
1971 case 75: /* Resume queue */
1972 if (print_queue_resume(¤t_user, snum, &errcode)) errcode = NERR_Success;
1974 case 103: /* Purge */
1975 if (print_queue_purge(¤t_user, snum, &errcode)) errcode = NERR_Success;
1980 SSVAL(*rparam,0,errcode);
1981 SSVAL(*rparam,2,0); /* converter word */
1987 /****************************************************************************
1988 set the property of a print job (undocumented?)
1989 ? function = 0xb -> set name of print job
1990 ? function = 0x6 -> move print job up/down
1991 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1992 or <WWsTP> <WB21BB16B10zWWzDDz>
1993 ****************************************************************************/
1994 static int check_printjob_info(struct pack_desc* desc,
1995 int uLevel, char* id)
1997 desc->subformat = NULL;
1999 case 0: desc->format = "W"; break;
2000 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2001 case 2: desc->format = "WWzWWDDzz"; break;
2002 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2003 default: return False;
2005 if (strcmp(desc->format,id) != 0) return False;
2009 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2010 int mdrcnt,int mprcnt,
2011 char **rdata,char **rparam,
2012 int *rdata_len,int *rparam_len)
2014 struct pack_desc desc;
2015 char *str1 = param+2;
2016 char *str2 = skip_string(str1,1);
2017 char *p = skip_string(str2,1);
2019 int uLevel = SVAL(p,2);
2020 int function = SVAL(p,4);
2025 *rparam = REALLOC(*rparam,*rparam_len);
2029 /* check it's a supported varient */
2030 if ((strcmp(str1,"WWsTP")) ||
2031 (!check_printjob_info(&desc,uLevel,str2)))
2034 if (!print_job_exists(jobid)) {
2035 errcode=NERR_JobNotFound;
2039 errcode = NERR_notsupported;
2043 /* change job place in the queue,
2044 data gives the new place */
2045 place = SVAL(data,0);
2046 if (print_job_set_place(jobid, place)) {
2047 errcode=NERR_Success;
2052 /* change print job name, data gives the name */
2053 if (print_job_set_name(jobid, data)) {
2054 errcode=NERR_Success;
2063 SSVALS(*rparam,0,errcode);
2064 SSVAL(*rparam,2,0); /* converter word */
2070 /****************************************************************************
2071 get info about the server
2072 ****************************************************************************/
2073 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2074 int mdrcnt,int mprcnt,
2075 char **rdata,char **rparam,
2076 int *rdata_len,int *rparam_len)
2078 char *str1 = param+2;
2079 char *str2 = skip_string(str1,1);
2080 char *p = skip_string(str2,1);
2081 int uLevel = SVAL(p,0);
2085 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2087 /* check it's a supported varient */
2088 if (!prefix_ok(str1,"WrLh")) return False;
2091 if (strcmp(str2,"B16") != 0) return False;
2095 if (strcmp(str2,"B16BBDz") != 0) return False;
2099 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2104 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2109 if (strcmp(str2,"DN") != 0) return False;
2113 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2116 default: return False;
2119 *rdata_len = mdrcnt;
2120 *rdata = REALLOC(*rdata,*rdata_len);
2123 p2 = p + struct_len;
2125 StrnCpy(p,local_machine,16);
2131 struct srv_info_struct *servers=NULL;
2134 uint32 servertype= lp_default_server_announce();
2136 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2138 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2139 for (i=0;i<count;i++)
2140 if (strequal(servers[i].name,local_machine))
2142 servertype = servers[i].type;
2143 pstrcpy(comment,servers[i].comment);
2146 if (servers) free(servers);
2148 SCVAL(p,0,lp_major_announce_version());
2149 SCVAL(p,1,lp_minor_announce_version());
2150 SIVAL(p,2,servertype);
2152 if (mdrcnt == struct_len) {
2155 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2156 standard_sub_conn(conn,comment);
2157 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2158 p2 = skip_string(p2,1);
2163 return False; /* not yet implemented */
2166 *rdata_len = PTR_DIFF(p2,*rdata);
2169 *rparam = REALLOC(*rparam,*rparam_len);
2170 SSVAL(*rparam,0,NERR_Success);
2171 SSVAL(*rparam,2,0); /* converter word */
2172 SSVAL(*rparam,4,*rdata_len);
2178 /****************************************************************************
2179 get info about the server
2180 ****************************************************************************/
2181 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2182 int mdrcnt,int mprcnt,
2183 char **rdata,char **rparam,
2184 int *rdata_len,int *rparam_len)
2186 char *str1 = param+2;
2187 char *str2 = skip_string(str1,1);
2188 char *p = skip_string(str2,1);
2190 extern userdom_struct current_user_info;
2191 int level = SVAL(p,0);
2193 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2196 *rparam = REALLOC(*rparam,*rparam_len);
2198 /* check it's a supported varient */
2199 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2202 *rdata_len = mdrcnt + 1024;
2203 *rdata = REALLOC(*rdata,*rdata_len);
2205 SSVAL(*rparam,0,NERR_Success);
2206 SSVAL(*rparam,2,0); /* converter word */
2212 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2213 pstrcpy(p2,local_machine);
2215 p2 = skip_string(p2,1);
2218 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2219 pstrcpy(p2,current_user_info.smb_name);
2220 p2 = skip_string(p2,1);
2223 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2224 pstrcpy(p2,global_myworkgroup);
2226 p2 = skip_string(p2,1);
2229 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2230 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2233 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2234 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2235 p2 = skip_string(p2,1);
2238 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2240 p2 = skip_string(p2,1);
2243 *rdata_len = PTR_DIFF(p2,*rdata);
2245 SSVAL(*rparam,4,*rdata_len);
2250 /****************************************************************************
2251 get info about a user
2253 struct user_info_11 {
2254 char usri11_name[21]; 0-20
2256 char *usri11_comment; 22-25
2257 char *usri11_usr_comment; 26-29
2258 unsigned short usri11_priv; 30-31
2259 unsigned long usri11_auth_flags; 32-35
2260 long usri11_password_age; 36-39
2261 char *usri11_homedir; 40-43
2262 char *usri11_parms; 44-47
2263 long usri11_last_logon; 48-51
2264 long usri11_last_logoff; 52-55
2265 unsigned short usri11_bad_pw_count; 56-57
2266 unsigned short usri11_num_logons; 58-59
2267 char *usri11_logon_server; 60-63
2268 unsigned short usri11_country_code; 64-65
2269 char *usri11_workstations; 66-69
2270 unsigned long usri11_max_storage; 70-73
2271 unsigned short usri11_units_per_week; 74-75
2272 unsigned char *usri11_logon_hours; 76-79
2273 unsigned short usri11_code_page; 80-81
2278 usri11_name specifies the user name for which information is retireved
2280 usri11_pad aligns the next data structure element to a word boundary
2282 usri11_comment is a null terminated ASCII comment
2284 usri11_user_comment is a null terminated ASCII comment about the user
2286 usri11_priv specifies the level of the privilege assigned to the user.
2287 The possible values are:
2289 Name Value Description
2290 USER_PRIV_GUEST 0 Guest privilege
2291 USER_PRIV_USER 1 User privilege
2292 USER_PRV_ADMIN 2 Administrator privilege
2294 usri11_auth_flags specifies the account operator privileges. The
2295 possible values are:
2297 Name Value Description
2298 AF_OP_PRINT 0 Print operator
2301 Leach, Naik [Page 28]
2305 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2308 AF_OP_COMM 1 Communications operator
2309 AF_OP_SERVER 2 Server operator
2310 AF_OP_ACCOUNTS 3 Accounts operator
2313 usri11_password_age specifies how many seconds have elapsed since the
2314 password was last changed.
2316 usri11_home_dir points to a null terminated ASCII string that contains
2317 the path name of the user's home directory.
2319 usri11_parms points to a null terminated ASCII string that is set
2320 aside for use by applications.
2322 usri11_last_logon specifies the time when the user last logged on.
2323 This value is stored as the number of seconds elapsed since
2324 00:00:00, January 1, 1970.
2326 usri11_last_logoff specifies the time when the user last logged off.
2327 This value is stored as the number of seconds elapsed since
2328 00:00:00, January 1, 1970. A value of 0 means the last logoff
2331 usri11_bad_pw_count specifies the number of incorrect passwords
2332 entered since the last successful logon.
2334 usri11_log1_num_logons specifies the number of times this user has
2335 logged on. A value of -1 means the number of logons is unknown.
2337 usri11_logon_server points to a null terminated ASCII string that
2338 contains the name of the server to which logon requests are sent.
2339 A null string indicates logon requests should be sent to the
2342 usri11_country_code specifies the country code for the user's language
2345 usri11_workstations points to a null terminated ASCII string that
2346 contains the names of workstations the user may log on from.
2347 There may be up to 8 workstations, with the names separated by
2348 commas. A null strings indicates there are no restrictions.
2350 usri11_max_storage specifies the maximum amount of disk space the user
2351 can occupy. A value of 0xffffffff indicates there are no
2354 usri11_units_per_week specifies the equal number of time units into
2355 which a week is divided. This value must be equal to 168.
2357 usri11_logon_hours points to a 21 byte (168 bits) string that
2358 specifies the time during which the user can log on. Each bit
2359 represents one unique hour in a week. The first bit (bit 0, word
2360 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2364 Leach, Naik [Page 29]
2368 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2371 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2372 are no restrictions.
2374 usri11_code_page specifies the code page for the user's language of
2377 All of the pointers in this data structure need to be treated
2378 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2379 to be ignored. The converter word returned in the parameters section
2380 needs to be subtracted from the lower 16 bits to calculate an offset
2381 into the return buffer where this ASCII string resides.
2383 There is no auxiliary data in the response.
2385 ****************************************************************************/
2387 #define usri11_name 0
2388 #define usri11_pad 21
2389 #define usri11_comment 22
2390 #define usri11_usr_comment 26
2391 #define usri11_full_name 30
2392 #define usri11_priv 34
2393 #define usri11_auth_flags 36
2394 #define usri11_password_age 40
2395 #define usri11_homedir 44
2396 #define usri11_parms 48
2397 #define usri11_last_logon 52
2398 #define usri11_last_logoff 56
2399 #define usri11_bad_pw_count 60
2400 #define usri11_num_logons 62
2401 #define usri11_logon_server 64
2402 #define usri11_country_code 68
2403 #define usri11_workstations 70
2404 #define usri11_max_storage 74
2405 #define usri11_units_per_week 78
2406 #define usri11_logon_hours 80
2407 #define usri11_code_page 84
2408 #define usri11_end 86
2410 #define USER_PRIV_GUEST 0
2411 #define USER_PRIV_USER 1
2412 #define USER_PRIV_ADMIN 2
2414 #define AF_OP_PRINT 0
2415 #define AF_OP_COMM 1
2416 #define AF_OP_SERVER 2
2417 #define AF_OP_ACCOUNTS 3
2420 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2421 int mdrcnt,int mprcnt,
2422 char **rdata,char **rparam,
2423 int *rdata_len,int *rparam_len)
2425 char *str1 = param+2;
2426 char *str2 = skip_string(str1,1);
2427 char *UserName = skip_string(str2,1);
2428 char *p = skip_string(UserName,1);
2429 int uLevel = SVAL(p,0);
2432 /* get NIS home of a previously validated user - simeon */
2433 /* With share level security vuid will always be zero.
2434 Don't depend on vuser being non-null !!. JRA */
2435 user_struct *vuser = get_valid_user_struct(vuid);
2437 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2438 vuser->user.unix_name));
2441 *rparam = REALLOC(*rparam,*rparam_len);
2443 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2445 /* check it's a supported variant */
2446 if (strcmp(str1,"zWrLh") != 0) return False;
2449 case 0: p2 = "B21"; break;
2450 case 1: p2 = "B21BB16DWzzWz"; break;
2451 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2452 case 10: p2 = "B21Bzzz"; break;
2453 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2454 default: return False;
2457 if (strcmp(p2,str2) != 0) return False;
2459 *rdata_len = mdrcnt + 1024;
2460 *rdata = REALLOC(*rdata,*rdata_len);
2462 SSVAL(*rparam,0,NERR_Success);
2463 SSVAL(*rparam,2,0); /* converter word */
2466 p2 = p + usri11_end;
2469 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2473 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2478 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2479 pstrcpy(p2,"Comment");
2480 p2 = skip_string(p2,1);
2482 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2483 pstrcpy(p2,"UserComment");
2484 p2 = skip_string(p2,1);
2486 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2487 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2488 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2489 p2 = skip_string(p2,1);
2492 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2494 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2495 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2496 SIVALS(p,usri11_password_age,-1); /* password age */
2497 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2498 pstrcpy(p2, lp_logon_home());
2499 standard_sub_conn(conn, p2);
2500 p2 = skip_string(p2,1);
2501 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2503 p2 = skip_string(p2,1);
2504 SIVAL(p,usri11_last_logon,0); /* last logon */
2505 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2506 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2507 SSVALS(p,usri11_num_logons,-1); /* num logons */
2508 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2509 pstrcpy(p2,"\\\\*");
2510 p2 = skip_string(p2,1);
2511 SSVAL(p,usri11_country_code,0); /* country code */
2513 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2515 p2 = skip_string(p2,1);
2517 SIVALS(p,usri11_max_storage,-1); /* max storage */
2518 SSVAL(p,usri11_units_per_week,168); /* units per week */
2519 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2521 /* a simple way to get logon hours at all times. */
2523 SCVAL(p2,21,0); /* fix zero termination */
2524 p2 = skip_string(p2,1);
2526 SSVAL(p,usri11_code_page,0); /* code page */
2528 if (uLevel == 1 || uLevel == 2)
2530 memset(p+22,' ',16); /* password */
2531 SIVALS(p,38,-1); /* password age */
2533 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2534 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2535 pstrcpy(p2,lp_logon_home());
2536 standard_sub_conn(conn, p2);
2537 p2 = skip_string(p2,1);
2538 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2540 SSVAL(p,52,0); /* flags */
2541 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2542 pstrcpy(p2,lp_logon_script());
2543 standard_sub_conn( conn, p2 );
2544 p2 = skip_string(p2,1);
2547 SIVAL(p,60,0); /* auth_flags */
2548 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2549 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2550 p2 = skip_string(p2,1);
2551 SIVAL(p,68,0); /* urs_comment */
2552 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2554 p2 = skip_string(p2,1);
2555 SIVAL(p,76,0); /* workstations */
2556 SIVAL(p,80,0); /* last_logon */
2557 SIVAL(p,84,0); /* last_logoff */
2558 SIVALS(p,88,-1); /* acct_expires */
2559 SIVALS(p,92,-1); /* max_storage */
2560 SSVAL(p,96,168); /* units_per_week */
2561 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2564 SSVALS(p,102,-1); /* bad_pw_count */
2565 SSVALS(p,104,-1); /* num_logons */
2566 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2567 pstrcpy(p2,"\\\\%L");
2568 standard_sub_conn(conn, p2);
2569 p2 = skip_string(p2,1);
2570 SSVAL(p,110,49); /* country_code */
2571 SSVAL(p,112,860); /* code page */
2575 *rdata_len = PTR_DIFF(p2,*rdata);
2577 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2582 /*******************************************************************
2583 get groups that a user is a member of
2584 ******************************************************************/
2585 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2586 int mdrcnt,int mprcnt,
2587 char **rdata,char **rparam,
2588 int *rdata_len,int *rparam_len)
2590 char *str1 = param+2;
2591 char *str2 = skip_string(str1,1);
2592 char *UserName = skip_string(str2,1);
2593 char *p = skip_string(UserName,1);
2594 int uLevel = SVAL(p,0);
2599 *rparam = REALLOC(*rparam,*rparam_len);
2601 /* check it's a supported varient */
2602 if (strcmp(str1,"zWrLeh") != 0) return False;
2604 case 0: p2 = "B21"; break;
2605 default: return False;
2607 if (strcmp(p2,str2) != 0) return False;
2609 *rdata_len = mdrcnt + 1024;
2610 *rdata = REALLOC(*rdata,*rdata_len);
2612 SSVAL(*rparam,0,NERR_Success);
2613 SSVAL(*rparam,2,0); /* converter word */
2617 /* XXXX we need a real SAM database some day */
2618 pstrcpy(p,"Users"); p += 21; count++;
2619 pstrcpy(p,"Domain Users"); p += 21; count++;
2620 pstrcpy(p,"Guests"); p += 21; count++;
2621 pstrcpy(p,"Domain Guests"); p += 21; count++;
2623 *rdata_len = PTR_DIFF(p,*rdata);
2625 SSVAL(*rparam,4,count); /* is this right?? */
2626 SSVAL(*rparam,6,count); /* is this right?? */
2632 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2633 int mdrcnt,int mprcnt,
2634 char **rdata,char **rparam,
2635 int *rdata_len,int *rparam_len)
2637 char *str1 = param+2;
2638 char *str2 = skip_string(str1,1);
2639 char *p = skip_string(str2,1);
2641 struct pack_desc desc;
2647 memset((char *)&desc,'\0',sizeof(desc));
2649 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2651 /* check it's a supported varient */
2652 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2653 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2654 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2656 desc.buflen = mdrcnt;
2657 desc.subformat = NULL;
2660 if (init_package(&desc,1,0))
2662 PACKI(&desc,"W",0); /* code */
2663 PACKS(&desc,"B21",name); /* eff. name */
2664 PACKS(&desc,"B",""); /* pad */
2666 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2667 PACKI(&desc,"D",0); /* auth flags XXX */
2668 PACKI(&desc,"W",0); /* num logons */
2669 PACKI(&desc,"W",0); /* bad pw count */
2670 PACKI(&desc,"D",0); /* last logon */
2671 PACKI(&desc,"D",-1); /* last logoff */
2672 PACKI(&desc,"D",-1); /* logoff time */
2673 PACKI(&desc,"D",-1); /* kickoff time */
2674 PACKI(&desc,"D",0); /* password age */
2675 PACKI(&desc,"D",0); /* password can change */
2676 PACKI(&desc,"D",-1); /* password must change */
2679 fstrcpy(mypath,"\\\\");
2680 fstrcat(mypath,local_machine);
2682 PACKS(&desc,"z",mypath); /* computer */
2684 PACKS(&desc,"z",global_myworkgroup);/* domain */
2686 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2687 /* made sure all macros are fully substituted and available */
2689 pstring logon_script;
2690 pstrcpy(logon_script,lp_logon_script());
2691 standard_sub_conn( conn, logon_script );
2692 PACKS(&desc,"z", logon_script); /* script path */
2694 /* End of JHT mods */
2696 PACKI(&desc,"D",0x00000000); /* reserved */
2699 *rdata_len = desc.usedlen;
2701 *rparam = REALLOC(*rparam,*rparam_len);
2702 SSVALS(*rparam,0,desc.errcode);
2704 SSVAL(*rparam,4,desc.neededlen);
2706 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2711 /****************************************************************************
2712 api_WAccessGetUserPerms
2713 ****************************************************************************/
2714 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2715 int mdrcnt,int mprcnt,
2716 char **rdata,char **rparam,
2717 int *rdata_len,int *rparam_len)
2719 char *str1 = param+2;
2720 char *str2 = skip_string(str1,1);
2721 char *user = skip_string(str2,1);
2722 char *resource = skip_string(user,1);
2724 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2726 /* check it's a supported varient */
2727 if (strcmp(str1,"zzh") != 0) return False;
2728 if (strcmp(str2,"") != 0) return False;
2731 *rparam = REALLOC(*rparam,*rparam_len);
2732 SSVALS(*rparam,0,0); /* errorcode */
2733 SSVAL(*rparam,2,0); /* converter word */
2734 SSVAL(*rparam,4,0x7f); /* permission flags */
2739 /****************************************************************************
2740 api_WPrintJobEnumerate
2741 ****************************************************************************/
2742 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2743 int mdrcnt,int mprcnt,
2744 char **rdata,char **rparam,
2745 int *rdata_len,int *rparam_len)
2747 char *str1 = param+2;
2748 char *str2 = skip_string(str1,1);
2749 char *p = skip_string(str2,1);
2755 struct pack_desc desc;
2756 print_queue_struct *queue=NULL;
2757 print_status_struct status;
2761 memset((char *)&desc,'\0',sizeof(desc));
2762 memset((char *)&status,'\0',sizeof(status));
2764 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2766 /* check it's a supported varient */
2767 if (strcmp(str1,"WWrLh") != 0) return False;
2768 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2771 snum = print_job_snum(job);
2773 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2775 count = print_queue_status(snum,&queue,&status);
2776 for (i = 0; i < count; i++) {
2777 if (queue[i].job == job) break;
2779 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2781 desc.buflen = mdrcnt;
2783 if (init_package(&desc,1,0)) {
2785 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2786 *rdata_len = desc.usedlen;
2789 desc.errcode = NERR_JobNotFound;
2795 *rparam = REALLOC(*rparam,*rparam_len);
2796 SSVALS(*rparam,0,desc.errcode);
2798 SSVAL(*rparam,4,desc.neededlen);
2800 if (queue) free(queue);
2802 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2806 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2807 int mdrcnt,int mprcnt,
2808 char **rdata,char **rparam,
2809 int *rdata_len,int *rparam_len)
2811 char *str1 = param+2;
2812 char *str2 = skip_string(str1,1);
2813 char *p = skip_string(str2,1);
2819 struct pack_desc desc;
2820 print_queue_struct *queue=NULL;
2821 print_status_struct status;
2823 memset((char *)&desc,'\0',sizeof(desc));
2824 memset((char *)&status,'\0',sizeof(status));
2826 p = skip_string(p,1);
2829 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2831 /* check it's a supported varient */
2832 if (strcmp(str1,"zWrLeh") != 0) return False;
2833 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2834 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2836 snum = lp_servicenumber(name);
2837 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2838 int pnum = lp_servicenumber(PRINTERS_NAME);
2840 lp_add_printer(name,pnum);
2841 snum = lp_servicenumber(name);
2845 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2847 count = print_queue_status(snum,&queue,&status);
2848 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2850 desc.buflen = mdrcnt;
2852 if (init_package(&desc,count,0)) {
2854 for (i = 0; i < count; i++) {
2855 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2856 if (desc.errcode == NERR_Success) succnt = i+1;
2860 *rdata_len = desc.usedlen;
2863 *rparam = REALLOC(*rparam,*rparam_len);
2864 SSVALS(*rparam,0,desc.errcode);
2866 SSVAL(*rparam,4,succnt);
2867 SSVAL(*rparam,6,count);
2869 if (queue) free(queue);
2871 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2875 static int check_printdest_info(struct pack_desc* desc,
2876 int uLevel, char* id)
2878 desc->subformat = NULL;
2880 case 0: desc->format = "B9"; break;
2881 case 1: desc->format = "B9B21WWzW"; break;
2882 case 2: desc->format = "z"; break;
2883 case 3: desc->format = "zzzWWzzzWW"; break;
2884 default: return False;
2886 if (strcmp(desc->format,id) != 0) return False;
2890 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2891 struct pack_desc* desc)
2894 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2895 buf[sizeof(buf)-1] = 0;
2898 PACKS(desc,"B9",buf); /* szName */
2900 PACKS(desc,"B21",""); /* szUserName */
2901 PACKI(desc,"W",0); /* uJobId */
2902 PACKI(desc,"W",0); /* fsStatus */
2903 PACKS(desc,"z",""); /* pszStatus */
2904 PACKI(desc,"W",0); /* time */
2907 if (uLevel == 2 || uLevel == 3) {
2908 PACKS(desc,"z",buf); /* pszPrinterName */
2910 PACKS(desc,"z",""); /* pszUserName */
2911 PACKS(desc,"z",""); /* pszLogAddr */
2912 PACKI(desc,"W",0); /* uJobId */
2913 PACKI(desc,"W",0); /* fsStatus */
2914 PACKS(desc,"z",""); /* pszStatus */
2915 PACKS(desc,"z",""); /* pszComment */
2916 PACKS(desc,"z","NULL"); /* pszDrivers */
2917 PACKI(desc,"W",0); /* time */
2918 PACKI(desc,"W",0); /* pad1 */
2923 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2924 int mdrcnt,int mprcnt,
2925 char **rdata,char **rparam,
2926 int *rdata_len,int *rparam_len)
2928 char *str1 = param+2;
2929 char *str2 = skip_string(str1,1);
2930 char *p = skip_string(str2,1);
2931 char* PrinterName = p;
2933 struct pack_desc desc;
2936 memset((char *)&desc,'\0',sizeof(desc));
2938 p = skip_string(p,1);
2941 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2943 /* check it's a supported varient */
2944 if (strcmp(str1,"zWrLh") != 0) return False;
2945 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2947 snum = lp_servicenumber(PrinterName);
2948 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2949 int pnum = lp_servicenumber(PRINTERS_NAME);
2951 lp_add_printer(PrinterName,pnum);
2952 snum = lp_servicenumber(PrinterName);
2958 desc.errcode = NERR_DestNotFound;
2962 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2964 desc.buflen = mdrcnt;
2965 if (init_package(&desc,1,0)) {
2966 fill_printdest_info(conn,snum,uLevel,&desc);
2968 *rdata_len = desc.usedlen;
2972 *rparam = REALLOC(*rparam,*rparam_len);
2973 SSVALS(*rparam,0,desc.errcode);
2975 SSVAL(*rparam,4,desc.neededlen);
2977 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2981 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2982 int mdrcnt,int mprcnt,
2983 char **rdata,char **rparam,
2984 int *rdata_len,int *rparam_len)
2986 char *str1 = param+2;
2987 char *str2 = skip_string(str1,1);
2988 char *p = skip_string(str2,1);
2992 struct pack_desc desc;
2993 int services = lp_numservices();
2995 memset((char *)&desc,'\0',sizeof(desc));
2999 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3001 /* check it's a supported varient */
3002 if (strcmp(str1,"WrLeh") != 0) return False;
3003 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3006 for (i = 0; i < services; i++)
3007 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3010 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3012 desc.buflen = mdrcnt;
3013 if (init_package(&desc,queuecnt,0)) {
3016 for (i = 0; i < services; i++) {
3017 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3018 fill_printdest_info(conn,i,uLevel,&desc);
3020 if (desc.errcode == NERR_Success) succnt = n;
3025 *rdata_len = desc.usedlen;
3028 *rparam = REALLOC(*rparam,*rparam_len);
3029 SSVALS(*rparam,0,desc.errcode);
3031 SSVAL(*rparam,4,succnt);
3032 SSVAL(*rparam,6,queuecnt);
3034 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3038 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3039 int mdrcnt,int mprcnt,
3040 char **rdata,char **rparam,
3041 int *rdata_len,int *rparam_len)
3043 char *str1 = param+2;
3044 char *str2 = skip_string(str1,1);
3045 char *p = skip_string(str2,1);
3048 struct pack_desc desc;
3050 memset((char *)&desc,'\0',sizeof(desc));
3054 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3056 /* check it's a supported varient */
3057 if (strcmp(str1,"WrLeh") != 0) return False;
3058 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3060 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3062 desc.buflen = mdrcnt;
3063 if (init_package(&desc,1,0)) {
3064 PACKS(&desc,"B41","NULL");
3067 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3069 *rdata_len = desc.usedlen;
3072 *rparam = REALLOC(*rparam,*rparam_len);
3073 SSVALS(*rparam,0,desc.errcode);
3075 SSVAL(*rparam,4,succnt);
3078 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3082 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3083 int mdrcnt,int mprcnt,
3084 char **rdata,char **rparam,
3085 int *rdata_len,int *rparam_len)
3087 char *str1 = param+2;
3088 char *str2 = skip_string(str1,1);
3089 char *p = skip_string(str2,1);
3092 struct pack_desc desc;
3094 memset((char *)&desc,'\0',sizeof(desc));
3098 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3100 /* check it's a supported varient */
3101 if (strcmp(str1,"WrLeh") != 0) return False;
3102 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3104 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3106 desc.buflen = mdrcnt;
3108 if (init_package(&desc,1,0)) {
3109 PACKS(&desc,"B13","lpd");
3112 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3114 *rdata_len = desc.usedlen;
3117 *rparam = REALLOC(*rparam,*rparam_len);
3118 SSVALS(*rparam,0,desc.errcode);
3120 SSVAL(*rparam,4,succnt);
3123 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3127 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3128 int mdrcnt,int mprcnt,
3129 char **rdata,char **rparam,
3130 int *rdata_len,int *rparam_len)
3132 char *str1 = param+2;
3133 char *str2 = skip_string(str1,1);
3134 char *p = skip_string(str2,1);
3137 struct pack_desc desc;
3139 memset((char *)&desc,'\0',sizeof(desc));
3143 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3145 /* check it's a supported varient */
3146 if (strcmp(str1,"WrLeh") != 0) return False;
3147 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3149 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3150 memset((char *)&desc,'\0',sizeof(desc));
3152 desc.buflen = mdrcnt;
3154 if (init_package(&desc,1,0)) {
3155 PACKS(&desc,"B13","lp0");
3158 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3160 *rdata_len = desc.usedlen;
3163 *rparam = REALLOC(*rparam,*rparam_len);
3164 SSVALS(*rparam,0,desc.errcode);
3166 SSVAL(*rparam,4,succnt);
3169 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3173 /****************************************************************************
3174 The buffer was too small
3175 ****************************************************************************/
3177 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3178 int mdrcnt,int mprcnt,
3179 char **rdata,char **rparam,
3180 int *rdata_len,int *rparam_len)
3182 *rparam_len = MIN(*rparam_len,mprcnt);
3183 *rparam = REALLOC(*rparam,*rparam_len);
3187 SSVAL(*rparam,0,NERR_BufTooSmall);
3189 DEBUG(3,("Supplied buffer too small in API command\n"));
3195 /****************************************************************************
3196 The request is not supported
3197 ****************************************************************************/
3199 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3200 int mdrcnt,int mprcnt,
3201 char **rdata,char **rparam,
3202 int *rdata_len,int *rparam_len)
3205 *rparam = REALLOC(*rparam,*rparam_len);
3209 SSVAL(*rparam,0,NERR_notsupported);
3210 SSVAL(*rparam,2,0); /* converter word */
3212 DEBUG(3,("Unsupported API command\n"));
3224 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3225 int,int,char **,char **,int *,int *);
3227 } api_commands[] = {
3228 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3229 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3230 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3231 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3232 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3233 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3234 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3235 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3236 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3237 {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0},
3238 {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3239 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3240 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3241 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3242 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3243 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3244 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3245 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3246 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3247 {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0},
3248 {"NetServerEnum", 104, api_RNetServerEnum,0},
3249 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3250 {"SetUserPassword", 115, api_SetUserPassword,0},
3251 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3252 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3253 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3254 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3255 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3256 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3257 {NULL, -1, api_Unsupported,0}};
3260 /****************************************************************************
3261 Handle remote api calls
3262 ****************************************************************************/
3264 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3265 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3269 char *rparam = NULL;
3276 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3280 api_command = SVAL(params,0);
3282 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3285 skip_string(params+2,1),
3286 tdscnt,tpscnt,mdrcnt,mprcnt));
3288 for (i=0;api_commands[i].name;i++) {
3289 if (api_commands[i].id == api_command && api_commands[i].fn) {
3290 DEBUG(3,("Doing %s\n",api_commands[i].name));
3295 rdata = (char *)malloc(1024);
3297 memset(rdata,'\0',1024);
3299 rparam = (char *)malloc(1024);
3301 memset(rparam,'\0',1024);
3303 if(!rdata || !rparam) {
3304 DEBUG(0,("api_reply: malloc fail !\n"));
3308 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3309 &rdata,&rparam,&rdata_len,&rparam_len);
3312 if (rdata_len > mdrcnt ||
3313 rparam_len > mprcnt) {
3314 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3315 &rdata,&rparam,&rdata_len,&rparam_len);
3318 /* if we get False back then it's actually unsupported */
3320 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3321 &rdata,&rparam,&rdata_len,&rparam_len);
3323 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);