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;
1345 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1348 char *lastname=NULL;
1350 for (i=0;i<total;i++)
1352 struct srv_info_struct *s = &servers[i];
1353 if (lastname && strequal(lastname,s->name)) continue;
1355 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1356 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1357 s->name, s->type, s->comment, s->domain));
1359 if (data_len <= buf_len) {
1362 string_len += s_len;
1369 *rdata_len = fixed_len + string_len;
1370 *rdata = REALLOC(*rdata,*rdata_len);
1371 memset(*rdata,'\0',*rdata_len);
1373 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1379 char *lastname=NULL;
1380 int count2 = counted;
1381 for (i = 0; i < total && count2;i++)
1383 struct srv_info_struct *s = &servers[i];
1384 if (lastname && strequal(lastname,s->name)) continue;
1386 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1387 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1388 s->name, s->type, s->comment, s->domain));
1394 *rparam = REALLOC(*rparam,*rparam_len);
1395 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1397 SSVAL(*rparam,4,counted);
1398 SSVAL(*rparam,6,counted+missed);
1400 if (servers) free(servers);
1402 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1403 domain,uLevel,counted,counted+missed));
1408 /****************************************************************************
1409 command 0x34 - suspected of being a "Lookup Names" stub api
1410 ****************************************************************************/
1411 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1412 int mdrcnt, int mprcnt, char **rdata,
1413 char **rparam, int *rdata_len, int *rparam_len)
1415 char *str1 = param+2;
1416 char *str2 = skip_string(str1,1);
1417 char *p = skip_string(str2,1);
1418 int uLevel = SVAL(p,0);
1419 int buf_len = SVAL(p,2);
1423 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1424 str1, str2, p, uLevel, buf_len));
1426 if (!prefix_ok(str1,"zWrLeh")) return False;
1431 *rparam = REALLOC(*rparam,*rparam_len);
1433 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1435 SSVAL(*rparam,4,counted);
1436 SSVAL(*rparam,6,counted+missed);
1441 /****************************************************************************
1442 get info about a share
1443 ****************************************************************************/
1444 static BOOL check_share_info(int uLevel, char* id)
1448 if (strcmp(id,"B13") != 0) return False;
1451 if (strcmp(id,"B13BWz") != 0) return False;
1454 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1457 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1459 default: return False;
1464 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1465 char** buf, int* buflen,
1466 char** stringbuf, int* stringspace, char* baseaddr)
1475 case 0: struct_len = 13; break;
1476 case 1: struct_len = 20; break;
1477 case 2: struct_len = 40; break;
1478 case 91: struct_len = 68; break;
1486 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1487 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1488 if (buflen) *buflen = struct_len;
1489 if (stringspace) *stringspace = len;
1490 return struct_len + len;
1495 if ((*buflen) < struct_len) return -1;
1503 p2 = p + struct_len;
1504 l2 = (*buflen) - struct_len;
1506 if (!baseaddr) baseaddr = p;
1508 StrnCpy(p,lp_servicename(snum),13);
1514 type = STYPE_DISKTREE;
1515 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1516 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1517 SSVAL(p,14,type); /* device type */
1518 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1519 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1524 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1525 SSVALS(p,22,-1); /* max uses */
1526 SSVAL(p,24,1); /* current uses */
1527 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1528 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1529 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1534 memset(p+40,0,SHPWLEN+2);
1546 (*buf) = p + struct_len;
1547 (*buflen) -= struct_len;
1549 (*stringspace) = l2;
1559 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1560 int mdrcnt,int mprcnt,
1561 char **rdata,char **rparam,
1562 int *rdata_len,int *rparam_len)
1564 char *str1 = param+2;
1565 char *str2 = skip_string(str1,1);
1566 char *netname = skip_string(str2,1);
1567 char *p = skip_string(netname,1);
1568 int uLevel = SVAL(p,0);
1569 int snum = find_service(netname);
1571 if (snum < 0) return False;
1573 /* check it's a supported varient */
1574 if (!prefix_ok(str1,"zWrLh")) return False;
1575 if (!check_share_info(uLevel,str2)) return False;
1577 *rdata = REALLOC(*rdata,mdrcnt);
1579 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1580 if (*rdata_len < 0) return False;
1583 *rparam = REALLOC(*rparam,*rparam_len);
1584 SSVAL(*rparam,0,NERR_Success);
1585 SSVAL(*rparam,2,0); /* converter word */
1586 SSVAL(*rparam,4,*rdata_len);
1591 /****************************************************************************
1592 view list of shares available
1593 ****************************************************************************/
1594 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1595 int mdrcnt,int mprcnt,
1596 char **rdata,char **rparam,
1597 int *rdata_len,int *rparam_len)
1599 char *str1 = param+2;
1600 char *str2 = skip_string(str1,1);
1601 char *p = skip_string(str2,1);
1602 int uLevel = SVAL(p,0);
1603 int buf_len = SVAL(p,2);
1605 int count=lp_numservices();
1606 int total=0,counted=0;
1607 BOOL missed = False;
1609 int data_len, fixed_len, string_len;
1610 int f_len = 0, s_len = 0;
1612 if (!prefix_ok(str1,"WrLeh")) return False;
1613 if (!check_share_info(uLevel,str2)) return False;
1615 data_len = fixed_len = string_len = 0;
1616 for (i=0;i<count;i++)
1617 if (lp_browseable(i) && lp_snum_ok(i))
1620 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1621 if (data_len <= buf_len)
1625 string_len += s_len;
1630 *rdata_len = fixed_len + string_len;
1631 *rdata = REALLOC(*rdata,*rdata_len);
1632 memset(*rdata,0,*rdata_len);
1634 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1638 for (i = 0; i < count;i++)
1639 if (lp_browseable(i) && lp_snum_ok(i))
1640 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1644 *rparam = REALLOC(*rparam,*rparam_len);
1645 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1647 SSVAL(*rparam,4,counted);
1648 SSVAL(*rparam,6,total);
1650 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1651 counted,total,uLevel,
1652 buf_len,*rdata_len,mdrcnt));
1658 /****************************************************************************
1659 get the time of day info
1660 ****************************************************************************/
1661 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1662 int mdrcnt,int mprcnt,
1663 char **rdata,char **rparam,
1664 int *rdata_len,int *rparam_len)
1668 *rparam = REALLOC(*rparam,*rparam_len);
1671 *rdata = REALLOC(*rdata,*rdata_len);
1673 SSVAL(*rparam,0,NERR_Success);
1674 SSVAL(*rparam,2,0); /* converter word */
1680 time_t unixdate = time(NULL);
1682 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1683 by NT in a "net time" operation,
1684 it seems to ignore the one below */
1686 /* the client expects to get localtime, not GMT, in this bit
1687 (I think, this needs testing) */
1688 t = LocalTime(&unixdate);
1690 SIVAL(p,4,0); /* msecs ? */
1691 CVAL(p,8) = t->tm_hour;
1692 CVAL(p,9) = t->tm_min;
1693 CVAL(p,10) = t->tm_sec;
1694 CVAL(p,11) = 0; /* hundredths of seconds */
1695 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1696 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1697 CVAL(p,16) = t->tm_mday;
1698 CVAL(p,17) = t->tm_mon + 1;
1699 SSVAL(p,18,1900+t->tm_year);
1700 CVAL(p,20) = t->tm_wday;
1707 /****************************************************************************
1708 Set the user password.
1709 *****************************************************************************/
1711 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1712 int mdrcnt,int mprcnt,
1713 char **rdata,char **rparam,
1714 int *rdata_len,int *rparam_len)
1716 char *p = skip_string(param+2,2);
1718 fstring pass1,pass2;
1722 p = skip_string(p,1);
1724 memset(pass1,'\0',sizeof(pass1));
1725 memset(pass2,'\0',sizeof(pass2));
1727 memcpy(pass2,p+16,16);
1730 *rparam = REALLOC(*rparam,*rparam_len);
1734 SSVAL(*rparam,0,NERR_badpass);
1735 SSVAL(*rparam,2,0); /* converter word */
1737 DEBUG(3,("Set password for <%s>\n",user));
1740 * Pass the user through the NT -> unix user mapping
1744 (void)map_username(user);
1747 * Do any UNIX username case mangling.
1749 (void)Get_Pwnam( user, True);
1752 * Attempt to verify the old password against smbpasswd entries
1753 * Win98 clients send old and new password in plaintext for this call.
1757 fstring saved_pass2;
1758 SAM_ACCOUNT *sampass;
1761 * Save the new password as change_oem_password overwrites it
1765 fstrcpy(saved_pass2, pass2);
1767 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1768 change_oem_password(sampass,pass2,False))
1770 SSVAL(*rparam,0,NERR_Success);
1773 * If unix password sync was requested, attempt to change
1774 * the /etc/passwd database also. Return failure if this cannot
1778 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1779 SSVAL(*rparam,0,NERR_badpass);
1784 * If the above failed, attempt the plaintext password change.
1785 * This tests against the /etc/passwd database only.
1788 if(SVAL(*rparam,0) != NERR_Success)
1790 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1791 chgpasswd(user,pass1,pass2,False))
1793 SSVAL(*rparam,0,NERR_Success);
1798 * If the plaintext change failed, attempt
1799 * the old encrypted method. NT will generate this
1800 * after trying the samr method. Note that this
1801 * method is done as a last resort as this
1802 * password change method loses the NT password hash
1803 * and cannot change the UNIX password as no plaintext
1807 if(SVAL(*rparam,0) != NERR_Success)
1809 SAM_ACCOUNT *hnd = NULL;
1811 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
1812 change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1814 SSVAL(*rparam,0,NERR_Success);
1818 memset((char *)pass1,'\0',sizeof(fstring));
1819 memset((char *)pass2,'\0',sizeof(fstring));
1824 /****************************************************************************
1825 Set the user password (SamOEM version - gets plaintext).
1826 ****************************************************************************/
1828 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1829 int mdrcnt,int mprcnt,
1830 char **rdata,char **rparam,
1831 int *rdata_len,int *rparam_len)
1834 char *p = param + 2;
1836 *rparam = REALLOC(*rparam,*rparam_len);
1840 SSVAL(*rparam,0,NERR_badpass);
1843 * Check the parameter definition is correct.
1845 if(!strequal(param + 2, "zsT")) {
1846 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1849 p = skip_string(p, 1);
1851 if(!strequal(p, "B516B16")) {
1852 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1855 p = skip_string(p,1);
1858 p = skip_string(p,1);
1860 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1863 * Pass the user through the NT -> unix user mapping
1867 (void)map_username(user);
1870 * Do any UNIX username case mangling.
1872 (void)Get_Pwnam( user, True);
1874 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1876 SSVAL(*rparam,0,NERR_Success);
1882 /****************************************************************************
1885 ****************************************************************************/
1886 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1887 int mdrcnt,int mprcnt,
1888 char **rdata,char **rparam,
1889 int *rdata_len,int *rparam_len)
1891 int function = SVAL(param,0);
1892 char *str1 = param+2;
1893 char *str2 = skip_string(str1,1);
1894 char *p = skip_string(str2,1);
1896 extern struct current_user current_user;
1900 /* check it's a supported varient */
1901 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1905 *rparam = REALLOC(*rparam,*rparam_len);
1908 if (!print_job_exists(jobid)) {
1909 errcode = NERR_JobNotFound;
1913 errcode = NERR_notsupported;
1916 case 81: /* delete */
1917 if (print_job_delete(¤t_user, jobid, &errcode))
1918 errcode = NERR_Success;
1920 case 82: /* pause */
1921 if (print_job_pause(¤t_user, jobid, &errcode))
1922 errcode = NERR_Success;
1924 case 83: /* resume */
1925 if (print_job_resume(¤t_user, jobid, &errcode))
1926 errcode = NERR_Success;
1931 SSVAL(*rparam,0,errcode);
1932 SSVAL(*rparam,2,0); /* converter word */
1937 /****************************************************************************
1938 Purge a print queue - or pause or resume it.
1939 ****************************************************************************/
1940 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1941 int mdrcnt,int mprcnt,
1942 char **rdata,char **rparam,
1943 int *rdata_len,int *rparam_len)
1945 int function = SVAL(param,0);
1946 char *str1 = param+2;
1947 char *str2 = skip_string(str1,1);
1948 char *QueueName = skip_string(str2,1);
1949 int errcode = NERR_notsupported;
1951 extern struct current_user current_user;
1953 /* check it's a supported varient */
1954 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1958 *rparam = REALLOC(*rparam,*rparam_len);
1961 snum = print_queue_snum(QueueName);
1964 errcode = NERR_JobNotFound;
1969 case 74: /* Pause queue */
1970 if (print_queue_pause(¤t_user, snum, &errcode)) errcode = NERR_Success;
1972 case 75: /* Resume queue */
1973 if (print_queue_resume(¤t_user, snum, &errcode)) errcode = NERR_Success;
1975 case 103: /* Purge */
1976 if (print_queue_purge(¤t_user, snum, &errcode)) errcode = NERR_Success;
1981 SSVAL(*rparam,0,errcode);
1982 SSVAL(*rparam,2,0); /* converter word */
1988 /****************************************************************************
1989 set the property of a print job (undocumented?)
1990 ? function = 0xb -> set name of print job
1991 ? function = 0x6 -> move print job up/down
1992 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1993 or <WWsTP> <WB21BB16B10zWWzDDz>
1994 ****************************************************************************/
1995 static int check_printjob_info(struct pack_desc* desc,
1996 int uLevel, char* id)
1998 desc->subformat = NULL;
2000 case 0: desc->format = "W"; break;
2001 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2002 case 2: desc->format = "WWzWWDDzz"; break;
2003 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2004 default: return False;
2006 if (strcmp(desc->format,id) != 0) return False;
2010 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2011 int mdrcnt,int mprcnt,
2012 char **rdata,char **rparam,
2013 int *rdata_len,int *rparam_len)
2015 struct pack_desc desc;
2016 char *str1 = param+2;
2017 char *str2 = skip_string(str1,1);
2018 char *p = skip_string(str2,1);
2020 int uLevel = SVAL(p,2);
2021 int function = SVAL(p,4);
2026 *rparam = REALLOC(*rparam,*rparam_len);
2030 /* check it's a supported varient */
2031 if ((strcmp(str1,"WWsTP")) ||
2032 (!check_printjob_info(&desc,uLevel,str2)))
2035 if (!print_job_exists(jobid)) {
2036 errcode=NERR_JobNotFound;
2040 errcode = NERR_notsupported;
2044 /* change job place in the queue,
2045 data gives the new place */
2046 place = SVAL(data,0);
2047 if (print_job_set_place(jobid, place)) {
2048 errcode=NERR_Success;
2053 /* change print job name, data gives the name */
2054 if (print_job_set_name(jobid, data)) {
2055 errcode=NERR_Success;
2064 SSVALS(*rparam,0,errcode);
2065 SSVAL(*rparam,2,0); /* converter word */
2071 /****************************************************************************
2072 get info about the server
2073 ****************************************************************************/
2074 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2075 int mdrcnt,int mprcnt,
2076 char **rdata,char **rparam,
2077 int *rdata_len,int *rparam_len)
2079 char *str1 = param+2;
2080 char *str2 = skip_string(str1,1);
2081 char *p = skip_string(str2,1);
2082 int uLevel = SVAL(p,0);
2086 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2088 /* check it's a supported varient */
2089 if (!prefix_ok(str1,"WrLh")) return False;
2092 if (strcmp(str2,"B16") != 0) return False;
2096 if (strcmp(str2,"B16BBDz") != 0) return False;
2100 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2105 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2110 if (strcmp(str2,"DN") != 0) return False;
2114 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2117 default: return False;
2120 *rdata_len = mdrcnt;
2121 *rdata = REALLOC(*rdata,*rdata_len);
2124 p2 = p + struct_len;
2126 StrnCpy(p,local_machine,16);
2132 struct srv_info_struct *servers=NULL;
2135 uint32 servertype= lp_default_server_announce();
2137 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2139 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2140 for (i=0;i<count;i++)
2141 if (strequal(servers[i].name,local_machine))
2143 servertype = servers[i].type;
2144 pstrcpy(comment,servers[i].comment);
2147 if (servers) free(servers);
2149 SCVAL(p,0,lp_major_announce_version());
2150 SCVAL(p,1,lp_minor_announce_version());
2151 SIVAL(p,2,servertype);
2153 if (mdrcnt == struct_len) {
2156 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2157 standard_sub_conn(conn,comment);
2158 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2159 p2 = skip_string(p2,1);
2164 return False; /* not yet implemented */
2167 *rdata_len = PTR_DIFF(p2,*rdata);
2170 *rparam = REALLOC(*rparam,*rparam_len);
2171 SSVAL(*rparam,0,NERR_Success);
2172 SSVAL(*rparam,2,0); /* converter word */
2173 SSVAL(*rparam,4,*rdata_len);
2179 /****************************************************************************
2180 get info about the server
2181 ****************************************************************************/
2182 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2183 int mdrcnt,int mprcnt,
2184 char **rdata,char **rparam,
2185 int *rdata_len,int *rparam_len)
2187 char *str1 = param+2;
2188 char *str2 = skip_string(str1,1);
2189 char *p = skip_string(str2,1);
2191 extern userdom_struct current_user_info;
2192 int level = SVAL(p,0);
2194 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2197 *rparam = REALLOC(*rparam,*rparam_len);
2199 /* check it's a supported varient */
2200 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2203 *rdata_len = mdrcnt + 1024;
2204 *rdata = REALLOC(*rdata,*rdata_len);
2206 SSVAL(*rparam,0,NERR_Success);
2207 SSVAL(*rparam,2,0); /* converter word */
2213 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2214 pstrcpy(p2,local_machine);
2216 p2 = skip_string(p2,1);
2219 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2220 pstrcpy(p2,current_user_info.smb_name);
2221 p2 = skip_string(p2,1);
2224 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2225 pstrcpy(p2,global_myworkgroup);
2227 p2 = skip_string(p2,1);
2230 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2231 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2234 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2235 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2236 p2 = skip_string(p2,1);
2239 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2241 p2 = skip_string(p2,1);
2244 *rdata_len = PTR_DIFF(p2,*rdata);
2246 SSVAL(*rparam,4,*rdata_len);
2251 /****************************************************************************
2252 get info about a user
2254 struct user_info_11 {
2255 char usri11_name[21]; 0-20
2257 char *usri11_comment; 22-25
2258 char *usri11_usr_comment; 26-29
2259 unsigned short usri11_priv; 30-31
2260 unsigned long usri11_auth_flags; 32-35
2261 long usri11_password_age; 36-39
2262 char *usri11_homedir; 40-43
2263 char *usri11_parms; 44-47
2264 long usri11_last_logon; 48-51
2265 long usri11_last_logoff; 52-55
2266 unsigned short usri11_bad_pw_count; 56-57
2267 unsigned short usri11_num_logons; 58-59
2268 char *usri11_logon_server; 60-63
2269 unsigned short usri11_country_code; 64-65
2270 char *usri11_workstations; 66-69
2271 unsigned long usri11_max_storage; 70-73
2272 unsigned short usri11_units_per_week; 74-75
2273 unsigned char *usri11_logon_hours; 76-79
2274 unsigned short usri11_code_page; 80-81
2279 usri11_name specifies the user name for which information is retireved
2281 usri11_pad aligns the next data structure element to a word boundary
2283 usri11_comment is a null terminated ASCII comment
2285 usri11_user_comment is a null terminated ASCII comment about the user
2287 usri11_priv specifies the level of the privilege assigned to the user.
2288 The possible values are:
2290 Name Value Description
2291 USER_PRIV_GUEST 0 Guest privilege
2292 USER_PRIV_USER 1 User privilege
2293 USER_PRV_ADMIN 2 Administrator privilege
2295 usri11_auth_flags specifies the account operator privileges. The
2296 possible values are:
2298 Name Value Description
2299 AF_OP_PRINT 0 Print operator
2302 Leach, Naik [Page 28]
2306 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2309 AF_OP_COMM 1 Communications operator
2310 AF_OP_SERVER 2 Server operator
2311 AF_OP_ACCOUNTS 3 Accounts operator
2314 usri11_password_age specifies how many seconds have elapsed since the
2315 password was last changed.
2317 usri11_home_dir points to a null terminated ASCII string that contains
2318 the path name of the user's home directory.
2320 usri11_parms points to a null terminated ASCII string that is set
2321 aside for use by applications.
2323 usri11_last_logon specifies the time when the user last logged on.
2324 This value is stored as the number of seconds elapsed since
2325 00:00:00, January 1, 1970.
2327 usri11_last_logoff specifies the time when the user last logged off.
2328 This value is stored as the number of seconds elapsed since
2329 00:00:00, January 1, 1970. A value of 0 means the last logoff
2332 usri11_bad_pw_count specifies the number of incorrect passwords
2333 entered since the last successful logon.
2335 usri11_log1_num_logons specifies the number of times this user has
2336 logged on. A value of -1 means the number of logons is unknown.
2338 usri11_logon_server points to a null terminated ASCII string that
2339 contains the name of the server to which logon requests are sent.
2340 A null string indicates logon requests should be sent to the
2343 usri11_country_code specifies the country code for the user's language
2346 usri11_workstations points to a null terminated ASCII string that
2347 contains the names of workstations the user may log on from.
2348 There may be up to 8 workstations, with the names separated by
2349 commas. A null strings indicates there are no restrictions.
2351 usri11_max_storage specifies the maximum amount of disk space the user
2352 can occupy. A value of 0xffffffff indicates there are no
2355 usri11_units_per_week specifies the equal number of time units into
2356 which a week is divided. This value must be equal to 168.
2358 usri11_logon_hours points to a 21 byte (168 bits) string that
2359 specifies the time during which the user can log on. Each bit
2360 represents one unique hour in a week. The first bit (bit 0, word
2361 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2365 Leach, Naik [Page 29]
2369 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2372 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2373 are no restrictions.
2375 usri11_code_page specifies the code page for the user's language of
2378 All of the pointers in this data structure need to be treated
2379 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2380 to be ignored. The converter word returned in the parameters section
2381 needs to be subtracted from the lower 16 bits to calculate an offset
2382 into the return buffer where this ASCII string resides.
2384 There is no auxiliary data in the response.
2386 ****************************************************************************/
2388 #define usri11_name 0
2389 #define usri11_pad 21
2390 #define usri11_comment 22
2391 #define usri11_usr_comment 26
2392 #define usri11_full_name 30
2393 #define usri11_priv 34
2394 #define usri11_auth_flags 36
2395 #define usri11_password_age 40
2396 #define usri11_homedir 44
2397 #define usri11_parms 48
2398 #define usri11_last_logon 52
2399 #define usri11_last_logoff 56
2400 #define usri11_bad_pw_count 60
2401 #define usri11_num_logons 62
2402 #define usri11_logon_server 64
2403 #define usri11_country_code 68
2404 #define usri11_workstations 70
2405 #define usri11_max_storage 74
2406 #define usri11_units_per_week 78
2407 #define usri11_logon_hours 80
2408 #define usri11_code_page 84
2409 #define usri11_end 86
2411 #define USER_PRIV_GUEST 0
2412 #define USER_PRIV_USER 1
2413 #define USER_PRIV_ADMIN 2
2415 #define AF_OP_PRINT 0
2416 #define AF_OP_COMM 1
2417 #define AF_OP_SERVER 2
2418 #define AF_OP_ACCOUNTS 3
2421 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2422 int mdrcnt,int mprcnt,
2423 char **rdata,char **rparam,
2424 int *rdata_len,int *rparam_len)
2426 char *str1 = param+2;
2427 char *str2 = skip_string(str1,1);
2428 char *UserName = skip_string(str2,1);
2429 char *p = skip_string(UserName,1);
2430 int uLevel = SVAL(p,0);
2433 /* get NIS home of a previously validated user - simeon */
2434 /* With share level security vuid will always be zero.
2435 Don't depend on vuser being non-null !!. JRA */
2436 user_struct *vuser = get_valid_user_struct(vuid);
2438 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2439 vuser->user.unix_name));
2442 *rparam = REALLOC(*rparam,*rparam_len);
2444 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2446 /* check it's a supported variant */
2447 if (strcmp(str1,"zWrLh") != 0) return False;
2450 case 0: p2 = "B21"; break;
2451 case 1: p2 = "B21BB16DWzzWz"; break;
2452 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2453 case 10: p2 = "B21Bzzz"; break;
2454 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2455 default: return False;
2458 if (strcmp(p2,str2) != 0) return False;
2460 *rdata_len = mdrcnt + 1024;
2461 *rdata = REALLOC(*rdata,*rdata_len);
2463 SSVAL(*rparam,0,NERR_Success);
2464 SSVAL(*rparam,2,0); /* converter word */
2467 p2 = p + usri11_end;
2470 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2474 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2479 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2480 pstrcpy(p2,"Comment");
2481 p2 = skip_string(p2,1);
2483 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2484 pstrcpy(p2,"UserComment");
2485 p2 = skip_string(p2,1);
2487 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2488 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2489 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2490 p2 = skip_string(p2,1);
2493 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2495 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2496 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2497 SIVALS(p,usri11_password_age,-1); /* password age */
2498 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2499 pstrcpy(p2, lp_logon_home());
2500 standard_sub_conn(conn, p2);
2501 p2 = skip_string(p2,1);
2502 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2504 p2 = skip_string(p2,1);
2505 SIVAL(p,usri11_last_logon,0); /* last logon */
2506 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2507 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2508 SSVALS(p,usri11_num_logons,-1); /* num logons */
2509 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2510 pstrcpy(p2,"\\\\*");
2511 p2 = skip_string(p2,1);
2512 SSVAL(p,usri11_country_code,0); /* country code */
2514 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2516 p2 = skip_string(p2,1);
2518 SIVALS(p,usri11_max_storage,-1); /* max storage */
2519 SSVAL(p,usri11_units_per_week,168); /* units per week */
2520 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2522 /* a simple way to get logon hours at all times. */
2524 SCVAL(p2,21,0); /* fix zero termination */
2525 p2 = skip_string(p2,1);
2527 SSVAL(p,usri11_code_page,0); /* code page */
2529 if (uLevel == 1 || uLevel == 2)
2531 memset(p+22,' ',16); /* password */
2532 SIVALS(p,38,-1); /* password age */
2534 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2535 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2536 pstrcpy(p2,lp_logon_home());
2537 standard_sub_conn(conn, p2);
2538 p2 = skip_string(p2,1);
2539 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2541 SSVAL(p,52,0); /* flags */
2542 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2543 pstrcpy(p2,lp_logon_script());
2544 standard_sub_conn( conn, p2 );
2545 p2 = skip_string(p2,1);
2548 SIVAL(p,60,0); /* auth_flags */
2549 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2550 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2551 p2 = skip_string(p2,1);
2552 SIVAL(p,68,0); /* urs_comment */
2553 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2555 p2 = skip_string(p2,1);
2556 SIVAL(p,76,0); /* workstations */
2557 SIVAL(p,80,0); /* last_logon */
2558 SIVAL(p,84,0); /* last_logoff */
2559 SIVALS(p,88,-1); /* acct_expires */
2560 SIVALS(p,92,-1); /* max_storage */
2561 SSVAL(p,96,168); /* units_per_week */
2562 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2565 SSVALS(p,102,-1); /* bad_pw_count */
2566 SSVALS(p,104,-1); /* num_logons */
2567 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2568 pstrcpy(p2,"\\\\%L");
2569 standard_sub_conn(conn, p2);
2570 p2 = skip_string(p2,1);
2571 SSVAL(p,110,49); /* country_code */
2572 SSVAL(p,112,860); /* code page */
2576 *rdata_len = PTR_DIFF(p2,*rdata);
2578 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2583 /*******************************************************************
2584 get groups that a user is a member of
2585 ******************************************************************/
2586 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2587 int mdrcnt,int mprcnt,
2588 char **rdata,char **rparam,
2589 int *rdata_len,int *rparam_len)
2591 char *str1 = param+2;
2592 char *str2 = skip_string(str1,1);
2593 char *UserName = skip_string(str2,1);
2594 char *p = skip_string(UserName,1);
2595 int uLevel = SVAL(p,0);
2600 *rparam = REALLOC(*rparam,*rparam_len);
2602 /* check it's a supported varient */
2603 if (strcmp(str1,"zWrLeh") != 0) return False;
2605 case 0: p2 = "B21"; break;
2606 default: return False;
2608 if (strcmp(p2,str2) != 0) return False;
2610 *rdata_len = mdrcnt + 1024;
2611 *rdata = REALLOC(*rdata,*rdata_len);
2613 SSVAL(*rparam,0,NERR_Success);
2614 SSVAL(*rparam,2,0); /* converter word */
2618 /* XXXX we need a real SAM database some day */
2619 pstrcpy(p,"Users"); p += 21; count++;
2620 pstrcpy(p,"Domain Users"); p += 21; count++;
2621 pstrcpy(p,"Guests"); p += 21; count++;
2622 pstrcpy(p,"Domain Guests"); p += 21; count++;
2624 *rdata_len = PTR_DIFF(p,*rdata);
2626 SSVAL(*rparam,4,count); /* is this right?? */
2627 SSVAL(*rparam,6,count); /* is this right?? */
2633 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2634 int mdrcnt,int mprcnt,
2635 char **rdata,char **rparam,
2636 int *rdata_len,int *rparam_len)
2638 char *str1 = param+2;
2639 char *str2 = skip_string(str1,1);
2640 char *p = skip_string(str2,1);
2642 struct pack_desc desc;
2648 memset((char *)&desc,'\0',sizeof(desc));
2650 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2652 /* check it's a supported varient */
2653 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2654 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2655 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2657 desc.buflen = mdrcnt;
2658 desc.subformat = NULL;
2661 if (init_package(&desc,1,0))
2663 PACKI(&desc,"W",0); /* code */
2664 PACKS(&desc,"B21",name); /* eff. name */
2665 PACKS(&desc,"B",""); /* pad */
2667 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2668 PACKI(&desc,"D",0); /* auth flags XXX */
2669 PACKI(&desc,"W",0); /* num logons */
2670 PACKI(&desc,"W",0); /* bad pw count */
2671 PACKI(&desc,"D",0); /* last logon */
2672 PACKI(&desc,"D",-1); /* last logoff */
2673 PACKI(&desc,"D",-1); /* logoff time */
2674 PACKI(&desc,"D",-1); /* kickoff time */
2675 PACKI(&desc,"D",0); /* password age */
2676 PACKI(&desc,"D",0); /* password can change */
2677 PACKI(&desc,"D",-1); /* password must change */
2680 fstrcpy(mypath,"\\\\");
2681 fstrcat(mypath,local_machine);
2683 PACKS(&desc,"z",mypath); /* computer */
2685 PACKS(&desc,"z",global_myworkgroup);/* domain */
2687 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2688 /* made sure all macros are fully substituted and available */
2690 pstring logon_script;
2691 pstrcpy(logon_script,lp_logon_script());
2692 standard_sub_conn( conn, logon_script );
2693 PACKS(&desc,"z", logon_script); /* script path */
2695 /* End of JHT mods */
2697 PACKI(&desc,"D",0x00000000); /* reserved */
2700 *rdata_len = desc.usedlen;
2702 *rparam = REALLOC(*rparam,*rparam_len);
2703 SSVALS(*rparam,0,desc.errcode);
2705 SSVAL(*rparam,4,desc.neededlen);
2707 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2712 /****************************************************************************
2713 api_WAccessGetUserPerms
2714 ****************************************************************************/
2715 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2716 int mdrcnt,int mprcnt,
2717 char **rdata,char **rparam,
2718 int *rdata_len,int *rparam_len)
2720 char *str1 = param+2;
2721 char *str2 = skip_string(str1,1);
2722 char *user = skip_string(str2,1);
2723 char *resource = skip_string(user,1);
2725 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2727 /* check it's a supported varient */
2728 if (strcmp(str1,"zzh") != 0) return False;
2729 if (strcmp(str2,"") != 0) return False;
2732 *rparam = REALLOC(*rparam,*rparam_len);
2733 SSVALS(*rparam,0,0); /* errorcode */
2734 SSVAL(*rparam,2,0); /* converter word */
2735 SSVAL(*rparam,4,0x7f); /* permission flags */
2740 /****************************************************************************
2741 api_WPrintJobEnumerate
2742 ****************************************************************************/
2743 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2744 int mdrcnt,int mprcnt,
2745 char **rdata,char **rparam,
2746 int *rdata_len,int *rparam_len)
2748 char *str1 = param+2;
2749 char *str2 = skip_string(str1,1);
2750 char *p = skip_string(str2,1);
2756 struct pack_desc desc;
2757 print_queue_struct *queue=NULL;
2758 print_status_struct status;
2762 memset((char *)&desc,'\0',sizeof(desc));
2763 memset((char *)&status,'\0',sizeof(status));
2765 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2767 /* check it's a supported varient */
2768 if (strcmp(str1,"WWrLh") != 0) return False;
2769 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2772 snum = print_job_snum(job);
2774 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2776 count = print_queue_status(snum,&queue,&status);
2777 for (i = 0; i < count; i++) {
2778 if (queue[i].job == job) break;
2780 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2782 desc.buflen = mdrcnt;
2784 if (init_package(&desc,1,0)) {
2786 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2787 *rdata_len = desc.usedlen;
2790 desc.errcode = NERR_JobNotFound;
2796 *rparam = REALLOC(*rparam,*rparam_len);
2797 SSVALS(*rparam,0,desc.errcode);
2799 SSVAL(*rparam,4,desc.neededlen);
2801 if (queue) free(queue);
2803 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2807 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2808 int mdrcnt,int mprcnt,
2809 char **rdata,char **rparam,
2810 int *rdata_len,int *rparam_len)
2812 char *str1 = param+2;
2813 char *str2 = skip_string(str1,1);
2814 char *p = skip_string(str2,1);
2820 struct pack_desc desc;
2821 print_queue_struct *queue=NULL;
2822 print_status_struct status;
2824 memset((char *)&desc,'\0',sizeof(desc));
2825 memset((char *)&status,'\0',sizeof(status));
2827 p = skip_string(p,1);
2830 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2832 /* check it's a supported varient */
2833 if (strcmp(str1,"zWrLeh") != 0) return False;
2834 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2835 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2837 snum = lp_servicenumber(name);
2838 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2839 int pnum = lp_servicenumber(PRINTERS_NAME);
2841 lp_add_printer(name,pnum);
2842 snum = lp_servicenumber(name);
2846 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2848 count = print_queue_status(snum,&queue,&status);
2849 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2851 desc.buflen = mdrcnt;
2853 if (init_package(&desc,count,0)) {
2855 for (i = 0; i < count; i++) {
2856 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2857 if (desc.errcode == NERR_Success) succnt = i+1;
2861 *rdata_len = desc.usedlen;
2864 *rparam = REALLOC(*rparam,*rparam_len);
2865 SSVALS(*rparam,0,desc.errcode);
2867 SSVAL(*rparam,4,succnt);
2868 SSVAL(*rparam,6,count);
2870 if (queue) free(queue);
2872 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2876 static int check_printdest_info(struct pack_desc* desc,
2877 int uLevel, char* id)
2879 desc->subformat = NULL;
2881 case 0: desc->format = "B9"; break;
2882 case 1: desc->format = "B9B21WWzW"; break;
2883 case 2: desc->format = "z"; break;
2884 case 3: desc->format = "zzzWWzzzWW"; break;
2885 default: return False;
2887 if (strcmp(desc->format,id) != 0) return False;
2891 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2892 struct pack_desc* desc)
2895 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2896 buf[sizeof(buf)-1] = 0;
2899 PACKS(desc,"B9",buf); /* szName */
2901 PACKS(desc,"B21",""); /* szUserName */
2902 PACKI(desc,"W",0); /* uJobId */
2903 PACKI(desc,"W",0); /* fsStatus */
2904 PACKS(desc,"z",""); /* pszStatus */
2905 PACKI(desc,"W",0); /* time */
2908 if (uLevel == 2 || uLevel == 3) {
2909 PACKS(desc,"z",buf); /* pszPrinterName */
2911 PACKS(desc,"z",""); /* pszUserName */
2912 PACKS(desc,"z",""); /* pszLogAddr */
2913 PACKI(desc,"W",0); /* uJobId */
2914 PACKI(desc,"W",0); /* fsStatus */
2915 PACKS(desc,"z",""); /* pszStatus */
2916 PACKS(desc,"z",""); /* pszComment */
2917 PACKS(desc,"z","NULL"); /* pszDrivers */
2918 PACKI(desc,"W",0); /* time */
2919 PACKI(desc,"W",0); /* pad1 */
2924 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2925 int mdrcnt,int mprcnt,
2926 char **rdata,char **rparam,
2927 int *rdata_len,int *rparam_len)
2929 char *str1 = param+2;
2930 char *str2 = skip_string(str1,1);
2931 char *p = skip_string(str2,1);
2932 char* PrinterName = p;
2934 struct pack_desc desc;
2937 memset((char *)&desc,'\0',sizeof(desc));
2939 p = skip_string(p,1);
2942 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2944 /* check it's a supported varient */
2945 if (strcmp(str1,"zWrLh") != 0) return False;
2946 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2948 snum = lp_servicenumber(PrinterName);
2949 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2950 int pnum = lp_servicenumber(PRINTERS_NAME);
2952 lp_add_printer(PrinterName,pnum);
2953 snum = lp_servicenumber(PrinterName);
2959 desc.errcode = NERR_DestNotFound;
2963 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2965 desc.buflen = mdrcnt;
2966 if (init_package(&desc,1,0)) {
2967 fill_printdest_info(conn,snum,uLevel,&desc);
2969 *rdata_len = desc.usedlen;
2973 *rparam = REALLOC(*rparam,*rparam_len);
2974 SSVALS(*rparam,0,desc.errcode);
2976 SSVAL(*rparam,4,desc.neededlen);
2978 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2982 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2983 int mdrcnt,int mprcnt,
2984 char **rdata,char **rparam,
2985 int *rdata_len,int *rparam_len)
2987 char *str1 = param+2;
2988 char *str2 = skip_string(str1,1);
2989 char *p = skip_string(str2,1);
2993 struct pack_desc desc;
2994 int services = lp_numservices();
2996 memset((char *)&desc,'\0',sizeof(desc));
3000 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3002 /* check it's a supported varient */
3003 if (strcmp(str1,"WrLeh") != 0) return False;
3004 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3007 for (i = 0; i < services; i++)
3008 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3011 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3013 desc.buflen = mdrcnt;
3014 if (init_package(&desc,queuecnt,0)) {
3017 for (i = 0; i < services; i++) {
3018 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3019 fill_printdest_info(conn,i,uLevel,&desc);
3021 if (desc.errcode == NERR_Success) succnt = n;
3026 *rdata_len = desc.usedlen;
3029 *rparam = REALLOC(*rparam,*rparam_len);
3030 SSVALS(*rparam,0,desc.errcode);
3032 SSVAL(*rparam,4,succnt);
3033 SSVAL(*rparam,6,queuecnt);
3035 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3039 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3040 int mdrcnt,int mprcnt,
3041 char **rdata,char **rparam,
3042 int *rdata_len,int *rparam_len)
3044 char *str1 = param+2;
3045 char *str2 = skip_string(str1,1);
3046 char *p = skip_string(str2,1);
3049 struct pack_desc desc;
3051 memset((char *)&desc,'\0',sizeof(desc));
3055 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3057 /* check it's a supported varient */
3058 if (strcmp(str1,"WrLeh") != 0) return False;
3059 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3061 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3063 desc.buflen = mdrcnt;
3064 if (init_package(&desc,1,0)) {
3065 PACKS(&desc,"B41","NULL");
3068 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3070 *rdata_len = desc.usedlen;
3073 *rparam = REALLOC(*rparam,*rparam_len);
3074 SSVALS(*rparam,0,desc.errcode);
3076 SSVAL(*rparam,4,succnt);
3079 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3083 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3084 int mdrcnt,int mprcnt,
3085 char **rdata,char **rparam,
3086 int *rdata_len,int *rparam_len)
3088 char *str1 = param+2;
3089 char *str2 = skip_string(str1,1);
3090 char *p = skip_string(str2,1);
3093 struct pack_desc desc;
3095 memset((char *)&desc,'\0',sizeof(desc));
3099 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3101 /* check it's a supported varient */
3102 if (strcmp(str1,"WrLeh") != 0) return False;
3103 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3105 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3107 desc.buflen = mdrcnt;
3109 if (init_package(&desc,1,0)) {
3110 PACKS(&desc,"B13","lpd");
3113 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3115 *rdata_len = desc.usedlen;
3118 *rparam = REALLOC(*rparam,*rparam_len);
3119 SSVALS(*rparam,0,desc.errcode);
3121 SSVAL(*rparam,4,succnt);
3124 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3128 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3129 int mdrcnt,int mprcnt,
3130 char **rdata,char **rparam,
3131 int *rdata_len,int *rparam_len)
3133 char *str1 = param+2;
3134 char *str2 = skip_string(str1,1);
3135 char *p = skip_string(str2,1);
3138 struct pack_desc desc;
3140 memset((char *)&desc,'\0',sizeof(desc));
3144 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3146 /* check it's a supported varient */
3147 if (strcmp(str1,"WrLeh") != 0) return False;
3148 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3150 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3151 memset((char *)&desc,'\0',sizeof(desc));
3153 desc.buflen = mdrcnt;
3155 if (init_package(&desc,1,0)) {
3156 PACKS(&desc,"B13","lp0");
3159 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3161 *rdata_len = desc.usedlen;
3164 *rparam = REALLOC(*rparam,*rparam_len);
3165 SSVALS(*rparam,0,desc.errcode);
3167 SSVAL(*rparam,4,succnt);
3170 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3174 /****************************************************************************
3175 The buffer was too small
3176 ****************************************************************************/
3178 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3179 int mdrcnt,int mprcnt,
3180 char **rdata,char **rparam,
3181 int *rdata_len,int *rparam_len)
3183 *rparam_len = MIN(*rparam_len,mprcnt);
3184 *rparam = REALLOC(*rparam,*rparam_len);
3188 SSVAL(*rparam,0,NERR_BufTooSmall);
3190 DEBUG(3,("Supplied buffer too small in API command\n"));
3196 /****************************************************************************
3197 The request is not supported
3198 ****************************************************************************/
3200 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3201 int mdrcnt,int mprcnt,
3202 char **rdata,char **rparam,
3203 int *rdata_len,int *rparam_len)
3206 *rparam = REALLOC(*rparam,*rparam_len);
3210 SSVAL(*rparam,0,NERR_notsupported);
3211 SSVAL(*rparam,2,0); /* converter word */
3213 DEBUG(3,("Unsupported API command\n"));
3225 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3226 int,int,char **,char **,int *,int *);
3228 } api_commands[] = {
3229 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3230 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3231 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3232 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3233 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3234 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3235 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3236 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3237 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3238 {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0},
3239 {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3240 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3241 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3242 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3243 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3244 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3245 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3246 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3247 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3248 {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0},
3249 {"NetServerEnum", 104, api_RNetServerEnum,0},
3250 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3251 {"SetUserPassword", 115, api_SetUserPassword,0},
3252 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3253 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3254 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3255 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3256 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3257 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3258 {NULL, -1, api_Unsupported,0}};
3261 /****************************************************************************
3262 Handle remote api calls
3263 ****************************************************************************/
3265 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3266 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3270 char *rparam = NULL;
3277 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3281 api_command = SVAL(params,0);
3283 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3286 skip_string(params+2,1),
3287 tdscnt,tpscnt,mdrcnt,mprcnt));
3289 for (i=0;api_commands[i].name;i++) {
3290 if (api_commands[i].id == api_command && api_commands[i].fn) {
3291 DEBUG(3,("Doing %s\n",api_commands[i].name));
3296 rdata = (char *)malloc(1024);
3298 memset(rdata,'\0',1024);
3300 rparam = (char *)malloc(1024);
3302 memset(rparam,'\0',1024);
3304 if(!rdata || !rparam) {
3305 DEBUG(0,("api_reply: malloc fail !\n"));
3309 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3310 &rdata,&rparam,&rdata_len,&rparam_len);
3313 if (rdata_len > mdrcnt ||
3314 rparam_len > mprcnt) {
3315 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3316 &rdata,&rparam,&rdata_len,&rparam_len);
3319 /* if we get False back then it's actually unsupported */
3321 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3322 &rdata,&rparam,&rdata_len,&rparam_len);
3324 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);