Fix up a number of intertwined issues:
[sfrench/samba-autobuild/.git] / source / smbd / lanman.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Inter-process communication and named pipe handling
5    Copyright (C) Andrew Tridgell 1992-1998
6
7    SMB Version handling
8    Copyright (C) John H Terpstra 1995-1998
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    */
24 /*
25    This file handles the named pipe and mailslot calls
26    in the SMBtrans protocol
27    */
28
29 #include "includes.h"
30
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
35
36 extern int DEBUGLEVEL;
37
38 extern fstring local_machine;
39 extern pstring global_myname;
40 extern fstring global_myworkgroup;
41
42 #define NERR_Success 0
43 #define NERR_badpass 86
44 #define NERR_notsupported 50
45
46 #define NERR_BASE (2100)
47 #define NERR_BufTooSmall (NERR_BASE+23)
48 #define NERR_JobNotFound (NERR_BASE+51)
49 #define NERR_DestNotFound (NERR_BASE+52)
50
51 #define ACCESS_READ 0x01
52 #define ACCESS_WRITE 0x02
53 #define ACCESS_CREATE 0x04
54
55 #define SHPWLEN 8               /* share password length */
56
57 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
58                             int mdrcnt,int mprcnt,
59                             char **rdata,char **rparam,
60                             int *rdata_len,int *rparam_len);
61 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
62                          int mdrcnt,int mprcnt,
63                          char **rdata,char **rparam,
64                          int *rdata_len,int *rparam_len);
65
66
67 static int CopyExpanded(connection_struct *conn, 
68                         int snum, char** dst, char* src, int* n)
69 {
70         pstring buf;
71         int l;
72
73         if (!src || !dst || !n || !(*dst)) return(0);
74
75         StrnCpy(buf,src,sizeof(buf)/2);
76         pstring_sub(buf,"%S",lp_servicename(snum));
77         standard_sub_conn(conn,buf);
78         l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
79         (*dst) += l;
80         (*n) -= l;
81         return l;
82 }
83
84 static int CopyAndAdvance(char** dst, char* src, int* n)
85 {
86   int l;
87   if (!src || !dst || !n || !(*dst)) return(0);
88   l = push_ascii(*dst,src,*n-1, STR_TERMINATE);
89   (*dst) += l;
90   (*n) -= l;
91   return l;
92 }
93
94 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
95 {
96         pstring buf;
97         if (!s) return(0);
98         StrnCpy(buf,s,sizeof(buf)/2);
99         pstring_sub(buf,"%S",lp_servicename(snum));
100         standard_sub_conn(conn,buf);
101         return strlen(buf) + 1;
102 }
103
104 static char* Expand(connection_struct *conn, int snum, char* s)
105 {
106         static pstring buf;
107         if (!s) return(NULL);
108         StrnCpy(buf,s,sizeof(buf)/2);
109         pstring_sub(buf,"%S",lp_servicename(snum));
110         standard_sub_conn(conn,buf);
111         return &buf[0];
112 }
113
114 /*******************************************************************
115   check a API string for validity when we only need to check the prefix
116   ******************************************************************/
117 static BOOL prefix_ok(char *str,char *prefix)
118 {
119   return(strncmp(str,prefix,strlen(prefix)) == 0);
120 }
121
122 struct pack_desc {
123   char* format;     /* formatstring for structure */
124   char* subformat;  /* subformat for structure */
125   char* base;       /* baseaddress of buffer */
126   int buflen;      /* remaining size for fixed part; on init: length of base */
127   int subcount;     /* count of substructures */
128   char* structbuf;  /* pointer into buffer for remaining fixed part */
129   int stringlen;    /* remaining size for variable part */              
130   char* stringbuf;  /* pointer into buffer for remaining variable part */
131   int neededlen;    /* total needed size */
132   int usedlen;      /* total used size (usedlen <= neededlen and usedlen <= buflen) */
133   char* curpos;     /* current position; pointer into format or subformat */
134   int errcode;
135 };
136
137 static int get_counter(char** p)
138 {
139   int i, n;
140   if (!p || !(*p)) return(1);
141   if (!isdigit((int)**p)) return 1;
142   for (n = 0;;) {
143     i = **p;
144     if (isdigit(i))
145       n = 10 * n + (i - '0');
146     else
147       return n;
148     (*p)++;
149   }
150 }
151
152 static int getlen(char* p)
153 {
154   int n = 0;
155   if (!p) return(0);
156   while (*p) {
157     switch( *p++ ) {
158     case 'W':                   /* word (2 byte) */
159       n += 2;
160       break;
161     case 'K':                   /* status word? (2 byte) */
162       n += 2;
163       break;
164     case 'N':                   /* count of substructures (word) at end */
165       n += 2;
166       break;
167     case 'D':                   /* double word (4 byte) */
168     case 'z':                   /* offset to zero terminated string (4 byte) */
169     case 'l':                   /* offset to user data (4 byte) */
170       n += 4;
171       break;
172     case 'b':                   /* offset to data (with counter) (4 byte) */
173       n += 4;
174       get_counter(&p);
175       break;
176     case 'B':                   /* byte (with optional counter) */
177       n += get_counter(&p);
178       break;
179     }
180   }
181   return n;
182 }
183
184 static BOOL init_package(struct pack_desc* p, int count, int subcount)
185 {
186   int n = p->buflen;
187   int i;
188
189   if (!p->format || !p->base) return(False);
190
191   i = count * getlen(p->format);
192   if (p->subformat) i += subcount * getlen(p->subformat);
193   p->structbuf = p->base;
194   p->neededlen = 0;
195   p->usedlen = 0;
196   p->subcount = 0;
197   p->curpos = p->format;
198   if (i > n) {
199     p->neededlen = i;
200     i = n = 0;
201 #if 0
202     /*
203      * This is the old error code we used. Aparently
204      * WinNT/2k systems return ERRbuftoosmall (2123) and
205      * OS/2 needs this. I'm leaving this here so we can revert
206      * if needed. JRA.
207      */
208     p->errcode = ERRmoredata;
209 #else
210         p->errcode = ERRbuftoosmall;
211 #endif
212   }
213   else
214     p->errcode = NERR_Success;
215   p->buflen = i;
216   n -= i;
217   p->stringbuf = p->base + i;
218   p->stringlen = n;
219   return(p->errcode == NERR_Success);
220 }
221
222 static int package(struct pack_desc* p, ...)
223 {
224   va_list args;
225   int needed=0, stringneeded;
226   char* str=NULL;
227   int is_string=0, stringused;
228   int32 temp;
229
230   va_start(args,p);
231
232   if (!*p->curpos) {
233     if (!p->subcount)
234       p->curpos = p->format;
235     else {
236       p->curpos = p->subformat;
237       p->subcount--;
238     }
239   }
240 #if CHECK_TYPES
241   str = va_arg(args,char*);
242   SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
243 #endif
244   stringneeded = -1;
245
246   if (!p->curpos) {
247     va_end(args);
248     return(0);
249   }
250
251   switch( *p->curpos++ ) {
252   case 'W':                     /* word (2 byte) */
253     needed = 2;
254     temp = va_arg(args,int);
255     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
256     break;
257   case 'K':                     /* status word? (2 byte) */
258     needed = 2;
259     temp = va_arg(args,int);
260     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
261     break;
262   case 'N':                     /* count of substructures (word) at end */
263     needed = 2;
264     p->subcount = va_arg(args,int);
265     if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
266     break;
267   case 'D':                     /* double word (4 byte) */
268     needed = 4;
269     temp = va_arg(args,int);
270     if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
271     break;
272   case 'B':                     /* byte (with optional counter) */
273     needed = get_counter(&p->curpos);
274     {
275       char *s = va_arg(args,char*);
276       if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
277     }
278     break;
279   case 'z':                     /* offset to zero terminated string (4 byte) */
280     str = va_arg(args,char*);
281     stringneeded = (str ? strlen(str)+1 : 0);
282     is_string = 1;
283     break;
284   case 'l':                     /* offset to user data (4 byte) */
285     str = va_arg(args,char*);
286     stringneeded = va_arg(args,int);
287     is_string = 0;
288     break;
289   case 'b':                     /* offset to data (with counter) (4 byte) */
290     str = va_arg(args,char*);
291     stringneeded = get_counter(&p->curpos);
292     is_string = 0;
293     break;
294   }
295   va_end(args);
296   if (stringneeded >= 0) {
297     needed = 4;
298     if (p->buflen >= needed) {
299       stringused = stringneeded;
300       if (stringused > p->stringlen) {
301         stringused = (is_string ? p->stringlen : 0);
302         if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
303       }
304       if (!stringused)
305         SIVAL(p->structbuf,0,0);
306       else {
307         SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
308         memcpy(p->stringbuf,str?str:"",stringused);
309         if (is_string) p->stringbuf[stringused-1] = '\0';
310         p->stringbuf += stringused;
311         p->stringlen -= stringused;
312         p->usedlen += stringused;
313       }
314     }
315     p->neededlen += stringneeded;
316   }
317   p->neededlen += needed;
318   if (p->buflen >= needed) {
319     p->structbuf += needed;
320     p->buflen -= needed;
321     p->usedlen += needed;
322   }
323   else {
324     if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
325   }
326   return 1;
327 }
328
329 #if CHECK_TYPES
330 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
331 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
332 #else
333 #define PACK(desc,t,v) package(desc,v)
334 #define PACKl(desc,t,v,l) package(desc,v,l)
335 #endif
336
337 static void PACKI(struct pack_desc* desc,char *t,int v)
338 {
339   PACK(desc,t,v);
340 }
341
342 static void PACKS(struct pack_desc* desc,char *t,char *v)
343 {
344   PACK(desc,t,v);
345 }
346
347
348 /****************************************************************************
349   get a print queue
350   ****************************************************************************/
351 static void PackDriverData(struct pack_desc* desc)
352 {
353   char drivdata[4+4+32];
354   SIVAL(drivdata,0,sizeof drivdata); /* cb */
355   SIVAL(drivdata,4,1000);       /* lVersion */
356   memset(drivdata+8,0,32);      /* szDeviceName */
357   push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
358   PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
359 }
360
361 static int check_printq_info(struct pack_desc* desc,
362                              int uLevel, char *id1, char *id2)
363 {
364   desc->subformat = NULL;
365   switch( uLevel ) {
366   case 0:
367     desc->format = "B13";
368     break;
369   case 1:
370     desc->format = "B13BWWWzzzzzWW";
371     break;
372   case 2:
373     desc->format = "B13BWWWzzzzzWN";
374     desc->subformat = "WB21BB16B10zWWzDDz";
375     break;
376   case 3:
377     desc->format = "zWWWWzzzzWWzzl";
378     break;
379   case 4:
380     desc->format = "zWWWWzzzzWNzzl";
381     desc->subformat = "WWzWWDDzz";
382     break;
383   case 5:
384     desc->format = "z";
385     break;
386   case 51:
387     desc->format = "K";
388     break;
389   case 52:
390     desc->format = "WzzzzzzzzN";
391     desc->subformat = "z";
392     break;
393   default: return False;
394   }
395   if (strcmp(desc->format,id1) != 0) return False;
396   if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
397   return True;
398 }
399
400
401 #define RAP_JOB_STATUS_QUEUED 0
402 #define RAP_JOB_STATUS_PAUSED 1
403 #define RAP_JOB_STATUS_SPOOLING 2
404 #define RAP_JOB_STATUS_PRINTING 3
405 #define RAP_JOB_STATUS_PRINTED 4
406
407 #define RAP_QUEUE_STATUS_PAUSED 1
408 #define RAP_QUEUE_STATUS_ERROR 2
409
410 /* turn a print job status into a on the wire status 
411 */
412 static int printj_status(int v)
413 {
414         switch (v) {
415         case LPQ_QUEUED:
416                 return RAP_JOB_STATUS_QUEUED;
417         case LPQ_PAUSED:
418                 return RAP_JOB_STATUS_PAUSED;
419         case LPQ_SPOOLING:
420                 return RAP_JOB_STATUS_SPOOLING;
421         case LPQ_PRINTING:
422                 return RAP_JOB_STATUS_PRINTING;
423         }
424         return 0;
425 }
426
427 /* turn a print queue status into a on the wire status 
428 */
429 static int printq_status(int v)
430 {
431         switch (v) {
432         case LPQ_QUEUED:
433                 return 0;
434         case LPQ_PAUSED:
435                 return RAP_QUEUE_STATUS_PAUSED;
436         }
437         return RAP_QUEUE_STATUS_ERROR;
438 }
439
440 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
441                                struct pack_desc* desc,
442                                print_queue_struct* queue, int n)
443 {
444   time_t t = queue->time;
445
446   /* the client expects localtime */
447   t -= TimeDiff(t);
448
449   PACKI(desc,"W",queue->job); /* uJobId */
450   if (uLevel == 1) {
451     PACKS(desc,"B21",queue->user); /* szUserName */
452     PACKS(desc,"B","");         /* pad */
453     PACKS(desc,"B16","");       /* szNotifyName */
454     PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
455     PACKS(desc,"z","");         /* pszParms */
456     PACKI(desc,"W",n+1);                /* uPosition */
457     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
458     PACKS(desc,"z","");         /* pszStatus */
459     PACKI(desc,"D",t); /* ulSubmitted */
460     PACKI(desc,"D",queue->size); /* ulSize */
461     PACKS(desc,"z",queue->file); /* pszComment */
462   }
463   if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
464     PACKI(desc,"W",queue->priority);            /* uPriority */
465     PACKS(desc,"z",queue->user); /* pszUserName */
466     PACKI(desc,"W",n+1);                /* uPosition */
467     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
468     PACKI(desc,"D",t); /* ulSubmitted */
469     PACKI(desc,"D",queue->size); /* ulSize */
470     PACKS(desc,"z","Samba");    /* pszComment */
471     PACKS(desc,"z",queue->file); /* pszDocument */
472     if (uLevel == 3) {
473       PACKS(desc,"z","");       /* pszNotifyName */
474       PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
475       PACKS(desc,"z","");       /* pszParms */
476       PACKS(desc,"z","");       /* pszStatus */
477       PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
478       PACKS(desc,"z","lpd");    /* pszQProcName */
479       PACKS(desc,"z","");       /* pszQProcParms */
480       PACKS(desc,"z","NULL"); /* pszDriverName */
481       PackDriverData(desc);     /* pDriverData */
482       PACKS(desc,"z","");       /* pszPrinterName */
483     } else if (uLevel == 4) {   /* OS2 */
484       PACKS(desc,"z","");       /* pszSpoolFileName  */
485        PACKS(desc,"z","");       /* pszPortName       */
486        PACKS(desc,"z","");       /* pszStatus         */
487        PACKI(desc,"D",0);        /* ulPagesSpooled    */
488        PACKI(desc,"D",0);        /* ulPagesSent       */
489        PACKI(desc,"D",0);        /* ulPagesPrinted    */
490        PACKI(desc,"D",0);        /* ulTimePrinted     */
491        PACKI(desc,"D",0);        /* ulExtendJobStatus */
492        PACKI(desc,"D",0);        /* ulStartPage       */
493        PACKI(desc,"D",0);        /* ulEndPage         */
494     }
495   }
496 }
497
498 /********************************************************************
499  Return a driver name given an snum.
500  Looks in a tdb first. Returns True if from tdb, False otherwise.
501  ********************************************************************/
502
503 static BOOL get_driver_name(int snum, pstring drivername)
504 {
505         NT_PRINTER_INFO_LEVEL *info = NULL;
506         BOOL in_tdb = False;
507
508         get_a_printer (&info, 2, lp_servicename(snum));
509         if (info != NULL) {
510                 pstrcpy( drivername, info->info_2->drivername);
511                 in_tdb = True;
512                 free_a_printer(&info, 2);
513         } else {
514                 pstrcpy( drivername, lp_printerdriver(snum));
515         }
516
517         return in_tdb;
518 }
519
520 /********************************************************************
521  Respond to the DosPrintQInfo command with a level of 52
522  This is used to get printer driver information for Win9x clients
523  ********************************************************************/
524 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
525                                 struct pack_desc* desc,
526                                 int count, print_queue_struct* queue,
527                                 print_status_struct* status)
528 {
529         int i;
530         BOOL ok = False;
531         pstring tok,driver,datafile,langmon,helpfile,datatype;
532         char *p;
533         char **lines = NULL;
534         pstring gen_line;
535         BOOL in_tdb = False;
536         fstring location;
537         pstring drivername;
538
539         /*
540          * Check in the tdb *first* before checking the legacy
541          * files. This allows an NT upload to take precedence over
542          * the existing fileset. JRA.
543          * 
544          * we need to lookup the driver name prior to making the call
545          * to get_a_printer_driver_9x_compatible() and not rely on the
546          * 'print driver' parameter --jerry
547          */
548
549
550         if ((get_driver_name(snum,drivername)) && 
551             ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
552         {
553                 in_tdb = True;
554                 p = gen_line;
555                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
556         } 
557         else 
558         {
559                 /* didn't find driver in tdb */
560
561                 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
562                            snum, drivername, lp_driverfile(snum)));
563
564                 lines = file_lines_load(lp_driverfile(snum),NULL);
565                 if (!lines) 
566                 {
567                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
568                                   strerror(errno)));
569                         desc->errcode=NERR_notsupported;
570                         goto done;
571                 } 
572
573                 /* lookup the long printer driver name in the file description */
574                 for (i=0;lines[i] && !ok;i++) 
575                 {
576                         p = lines[i];
577                         if (next_token(&p,tok,":",sizeof(tok)) &&
578                            (strlen(drivername) == strlen(tok)) &&
579                            (!strncmp(tok,drivername,strlen(drivername))))
580                         {
581                                 ok = True;
582                         }
583                 }
584         }
585
586         if (ok)
587         {
588                 /* driver file name */
589                 if (!next_token(&p,driver,":",sizeof(driver)))
590                         goto err;
591
592                 /* data file name */
593                 if (!next_token(&p,datafile,":",sizeof(datafile)))
594                         goto err;
595
596                 /*
597                  * for the next tokens - which may be empty - I have
598                  * to check for empty tokens first because the
599                  * next_token function will skip all empty token
600                  * fields */
601
602                 /* help file */
603                 if (*p == ':') 
604                 {
605                         *helpfile = '\0';
606                         p++;
607                 } 
608                 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
609                         goto err;
610         
611                 /* language monitor */
612                 if (*p == ':') 
613                 {
614                         *langmon = '\0';
615                         p++;
616                 } 
617                 else if (!next_token(&p,langmon,":",sizeof(langmon)))
618                         goto err;
619         
620                 /* default data type */
621                 if (!next_token(&p,datatype,":",sizeof(datatype))) 
622                         goto err;
623         
624                 PACKI(desc,"W",0x0400);               /* don't know */
625                 PACKS(desc,"z",drivername);    /* long printer name */
626                 PACKS(desc,"z",driver);                    /* Driverfile Name */
627                 PACKS(desc,"z",datafile);                  /* Datafile name */
628                 PACKS(desc,"z",langmon);                         /* language monitor */
629                 if (in_tdb)
630                 {
631                         fstrcpy(location, "\\\\");
632                         fstrcat(location, global_myname);
633                         fstrcat(location, "\\print$\\WIN40\\0");
634                         PACKS(desc,"z",location);   /* share to retrieve files */
635                 }
636                 else
637                 {
638                         PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
639                 }
640                 PACKS(desc,"z",datatype);                        /* default data type */
641                 PACKS(desc,"z",helpfile);                  /* helpfile name */
642                 PACKS(desc,"z",driver);                    /* driver name */
643
644                 DEBUG(3,("printerdriver:%s:\n",drivername));
645                 DEBUG(3,("Driver:%s:\n",driver));
646                 DEBUG(3,("Data File:%s:\n",datafile));
647                 DEBUG(3,("Language Monitor:%s:\n",langmon));
648                 if (in_tdb)
649                         DEBUG(3,("lp_driverlocation:%s:\n",location));
650                 else
651                         DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
652                 DEBUG(3,("Data Type:%s:\n",datatype));
653                 DEBUG(3,("Help File:%s:\n",helpfile));
654                 PACKI(desc,"N",count);                     /* number of files to copy */
655
656                 for (i=0;i<count;i++) 
657                 {
658                         /* no need to check return value here
659                          * - it was already tested in
660                          * get_printerdrivernumber */
661                         next_token(&p,tok,",",sizeof(tok));
662                         PACKS(desc,"z",tok);         /* driver files to copy */
663                         DEBUG(3,("file:%s:\n",tok));
664                 }
665                 
666                 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
667                           SERVICE(snum),count));
668
669                 desc->errcode=NERR_Success;
670                 goto done;
671         }
672
673   err:
674
675         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
676         desc->errcode=NERR_notsupported;
677
678  done:
679         file_lines_free(lines); 
680 }
681
682
683 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
684                              struct pack_desc* desc,
685                              int count, print_queue_struct* queue,
686                              print_status_struct* status)
687 {
688         switch (uLevel) {
689         case 1:
690         case 2:
691                 PACKS(desc,"B13",SERVICE(snum));
692                 break;
693         case 3:
694         case 4:
695         case 5:
696                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
697                 break;
698         case 51:
699                 PACKI(desc,"K",printq_status(status->status));
700                 break;
701         }
702
703         if (uLevel == 1 || uLevel == 2) {
704                 PACKS(desc,"B","");             /* alignment */
705                 PACKI(desc,"W",5);              /* priority */
706                 PACKI(desc,"W",0);              /* start time */
707                 PACKI(desc,"W",0);              /* until time */
708                 PACKS(desc,"z","");             /* pSepFile */
709                 PACKS(desc,"z","lpd");  /* pPrProc */
710                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
711                 PACKS(desc,"z","");             /* pParms */
712                 if (snum < 0) {
713                         PACKS(desc,"z","UNKNOWN PRINTER");
714                         PACKI(desc,"W",LPSTAT_ERROR);
715                 }
716                 else if (!status || !status->message[0]) {
717                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
718                         PACKI(desc,"W",LPSTAT_OK); /* status */
719                 } else {
720                         PACKS(desc,"z",status->message);
721                         PACKI(desc,"W",printq_status(status->status)); /* status */
722                 }
723                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
724         }
725
726         if (uLevel == 3 || uLevel == 4) {
727                 pstring drivername;
728
729                 PACKI(desc,"W",5);              /* uPriority */
730                 PACKI(desc,"W",0);              /* uStarttime */
731                 PACKI(desc,"W",0);              /* uUntiltime */
732                 PACKI(desc,"W",5);              /* pad1 */
733                 PACKS(desc,"z","");             /* pszSepFile */
734                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
735                 PACKS(desc,"z",NULL);           /* pszParms */
736                 PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
737                 /* "don't ask" that it's done this way to fix corrupted 
738                    Win9X/ME printer comments. */
739                 if (!status) {
740                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
741                 } else {
742                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
743                 }
744                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
745                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
746                 get_driver_name(snum,drivername);
747                 PACKS(desc,"z",drivername);             /* pszDriverName */
748                 PackDriverData(desc);   /* pDriverData */
749         }
750
751         if (uLevel == 2 || uLevel == 4) {
752                 int i;
753                 for (i=0;i<count;i++)
754                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
755         }
756
757         if (uLevel==52) {
758                 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
759         }
760 }
761
762 /* This function returns the number of files for a given driver */
763 static int get_printerdrivernumber(int snum)
764 {
765         int i, result = 0;
766         BOOL ok = False;
767         pstring tok;
768         char *p;
769         char **lines = NULL;
770         pstring gen_line;
771         pstring drivername;
772         
773         /*
774          * Check in the tdb *first* before checking the legacy
775          * files. This allows an NT upload to take precedence over
776          * the existing fileset. JRA.
777          *
778          * we need to lookup the driver name prior to making the call
779          * to get_a_printer_driver_9x_compatible() and not rely on the
780          * 'print driver' parameter --jerry
781          */
782         
783         if ((get_driver_name(snum,drivername)) && 
784             (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True)) 
785         {
786                 p = gen_line;
787                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
788         } 
789         else 
790         {
791                 /* didn't find driver in tdb */
792         
793                 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
794                           snum, drivername, lp_driverfile(snum)));
795                 
796                 lines = file_lines_load(lp_driverfile(snum), NULL);
797                 if (!lines) 
798                 {
799                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
800                         goto done;
801                 } 
802
803                 /* lookup the long printer driver name in the file description */
804                 for (i=0;lines[i] && !ok;i++) 
805                 {
806                         p = lines[i];
807                         if (next_token(&p,tok,":",sizeof(tok)) &&
808                            (strlen(drivername) == strlen(tok)) &&
809                            (!strncmp(tok,drivername,strlen(drivername)))) 
810                         {
811                                 ok = True;
812                         }
813                 }
814         }
815         
816         if( ok ) 
817         {
818                 /* skip 5 fields */
819                 i = 5;
820                 while (*p && i) {
821                         if (*p++ == ':') i--;
822                 }
823                 if (!*p || i) {
824                         DEBUG(3,("Can't determine number of printer driver files\n"));
825                         goto done;
826                 }
827                 
828                 /* count the number of files */
829                 while (next_token(&p,tok,",",sizeof(tok)))
830                         i++;
831         
832                 result = i;
833         }
834
835  done:
836
837         file_lines_free(lines);
838
839         return result;
840 }
841
842 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
843                                  uint16 vuid, char *param,char *data,
844                                  int mdrcnt,int mprcnt,
845                                  char **rdata,char **rparam,
846                                  int *rdata_len,int *rparam_len)
847 {
848         char *str1 = param+2;
849         char *str2 = skip_string(str1,1);
850         char *p = skip_string(str2,1);
851         char *QueueName = p;
852         int uLevel;
853         int count=0;
854         int snum;
855         char* str3;
856         struct pack_desc desc;
857         print_queue_struct *queue=NULL;
858         print_status_struct status;
859         char* tmpdata=NULL;
860
861         memset((char *)&status,'\0',sizeof(status));
862         memset((char *)&desc,'\0',sizeof(desc));
863  
864         p = skip_string(p,1);
865         uLevel = SVAL(p,0);
866         str3 = p + 4;
867  
868         /* remove any trailing username */
869         if ((p = strchr_m(QueueName,'%')))
870                 *p = 0;
871  
872         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
873  
874         /* check it's a supported varient */
875         if (!prefix_ok(str1,"zWrLh"))
876                 return False;
877         if (!check_printq_info(&desc,uLevel,str2,str3)) {
878                 /*
879                  * Patch from Scott Moomaw <scott@bridgewater.edu>
880                  * to return the 'invalid info level' error if an
881                  * unknown level was requested.
882                  */
883                 *rdata_len = 0;
884                 *rparam_len = 6;
885                 *rparam = REALLOC(*rparam,*rparam_len);
886                 SSVALS(*rparam,0,ERRunknownlevel);
887                 SSVAL(*rparam,2,0);
888                 SSVAL(*rparam,4,0);
889                 return(True);
890         }
891  
892         snum = lp_servicenumber(QueueName);
893         if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
894                 int pnum = lp_servicenumber(PRINTERS_NAME);
895                 if (pnum >= 0) {
896                         lp_add_printer(QueueName,pnum);
897                         snum = lp_servicenumber(QueueName);
898                 }
899         }
900   
901         if (snum < 0 || !VALID_SNUM(snum))
902                 return(False);
903
904         if (uLevel==52) {
905                 count = get_printerdrivernumber(snum);
906                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
907         } else {
908                 count = print_queue_status(snum, &queue,&status);
909         }
910
911         if (mdrcnt > 0) {
912                 *rdata = REALLOC(*rdata,mdrcnt);
913                 desc.base = *rdata;
914                 desc.buflen = mdrcnt;
915         } else {
916                 /*
917                  * Don't return data but need to get correct length
918                  * init_package will return wrong size if buflen=0
919                  */
920                 desc.buflen = getlen(desc.format);
921                 desc.base = tmpdata = (char *) malloc (desc.buflen);
922         }
923
924         if (init_package(&desc,1,count)) {
925                 desc.subcount = count;
926                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
927         }
928
929         *rdata_len = desc.usedlen;
930   
931         /*
932          * We must set the return code to ERRbuftoosmall
933          * in order to support lanman style printing with Win NT/2k
934          * clients       --jerry
935          */
936         if (!mdrcnt && lp_disable_spoolss())
937                 desc.errcode = ERRbuftoosmall;
938  
939     *rdata_len = desc.usedlen;
940         *rparam_len = 6;
941         *rparam = REALLOC(*rparam,*rparam_len);
942         SSVALS(*rparam,0,desc.errcode);
943         SSVAL(*rparam,2,0);
944         SSVAL(*rparam,4,desc.neededlen);
945   
946         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
947
948         SAFE_FREE(queue);
949         SAFE_FREE(tmpdata);
950
951         return(True);
952 }
953
954 /****************************************************************************
955  View list of all print jobs on all queues.
956 ****************************************************************************/
957
958 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
959                               int mdrcnt, int mprcnt,
960                               char **rdata, char** rparam,
961                               int *rdata_len, int *rparam_len)
962 {
963   char *param_format = param+2;
964   char *output_format1 = skip_string(param_format,1);
965   char *p = skip_string(output_format1,1);
966   int uLevel = SVAL(p,0);
967   char *output_format2 = p + 4;
968   int services = lp_numservices();
969   int i, n;
970   struct pack_desc desc;
971   print_queue_struct **queue = NULL;
972   print_status_struct *status = NULL;
973   int* subcntarr = NULL;
974   int queuecnt, subcnt=0, succnt=0;
975  
976   memset((char *)&desc,'\0',sizeof(desc));
977
978   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
979  
980   if (!prefix_ok(param_format,"WrLeh")) return False;
981   if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
982     /*
983      * Patch from Scott Moomaw <scott@bridgewater.edu>
984      * to return the 'invalid info level' error if an
985      * unknown level was requested.
986      */
987     *rdata_len = 0;
988     *rparam_len = 6;
989     *rparam = REALLOC(*rparam,*rparam_len);
990     SSVALS(*rparam,0,ERRunknownlevel);
991     SSVAL(*rparam,2,0);
992     SSVAL(*rparam,4,0);
993     return(True);
994   }
995
996   queuecnt = 0;
997   for (i = 0; i < services; i++)
998     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
999       queuecnt++;
1000   if (uLevel > 0) {
1001     if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1002       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1003       return False;
1004     }
1005     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1006     if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1007       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1008       return False;
1009     }
1010     memset(status,0,queuecnt*sizeof(print_status_struct));
1011     if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1012       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1013       return False;
1014     }
1015     subcnt = 0;
1016     n = 0;
1017     for (i = 0; i < services; i++)
1018       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1019         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1020         subcnt += subcntarr[n];
1021         n++;
1022       }
1023   }
1024   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1025   desc.base = *rdata;
1026   desc.buflen = mdrcnt;
1027
1028   if (init_package(&desc,queuecnt,subcnt)) {
1029     n = 0;
1030     succnt = 0;
1031     for (i = 0; i < services; i++)
1032       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1033         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1034         n++;
1035         if (desc.errcode == NERR_Success) succnt = n;
1036       }
1037   }
1038
1039   SAFE_FREE(subcntarr);
1040  
1041   *rdata_len = desc.usedlen;
1042   *rparam_len = 8;
1043   *rparam = REALLOC(*rparam,*rparam_len);
1044   SSVALS(*rparam,0,desc.errcode);
1045   SSVAL(*rparam,2,0);
1046   SSVAL(*rparam,4,succnt);
1047   SSVAL(*rparam,6,queuecnt);
1048   
1049   for (i = 0; i < queuecnt; i++) {
1050     if (queue) SAFE_FREE(queue[i]);
1051   }
1052
1053   SAFE_FREE(queue);
1054   SAFE_FREE(status);
1055   
1056   return True;
1057 }
1058
1059 /****************************************************************************
1060   get info level for a server list query
1061   ****************************************************************************/
1062 static BOOL check_server_info(int uLevel, char* id)
1063 {
1064   switch( uLevel ) {
1065   case 0:
1066     if (strcmp(id,"B16") != 0) return False;
1067     break;
1068   case 1:
1069     if (strcmp(id,"B16BBDz") != 0) return False;
1070     break;
1071   default: 
1072     return False;
1073   }
1074   return True;
1075 }
1076
1077 struct srv_info_struct
1078 {
1079   fstring name;
1080   uint32 type;
1081   fstring comment;
1082   fstring domain;
1083   BOOL server_added;
1084 };
1085
1086
1087 /*******************************************************************
1088   get server info lists from the files saved by nmbd. Return the
1089   number of entries
1090   ******************************************************************/
1091 static int get_server_info(uint32 servertype, 
1092                            struct srv_info_struct **servers,
1093                            char *domain)
1094 {
1095   int count=0;
1096   int alloced=0;
1097   char **lines;
1098   BOOL local_list_only;
1099   int i;
1100
1101   lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1102   if (!lines) {
1103     DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1104     return(0);
1105   }
1106
1107   /* request for everything is code for request all servers */
1108   if (servertype == SV_TYPE_ALL) 
1109         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1110
1111   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1112
1113   DEBUG(4,("Servertype search: %8x\n",servertype));
1114
1115   for (i=0;lines[i];i++) {
1116     fstring stype;
1117     struct srv_info_struct *s;
1118     char *ptr = lines[i];
1119     BOOL ok = True;
1120
1121     if (!*ptr) continue;
1122     
1123     if (count == alloced) {
1124       struct srv_info_struct *ts;
1125       
1126       alloced += 10;
1127       ts = (struct srv_info_struct *)
1128         Realloc(*servers,sizeof(**servers)*alloced);
1129       if (!ts) {
1130         DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1131         return(0);
1132       }
1133       else *servers = ts;
1134       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1135     }
1136     s = &(*servers)[count];
1137     
1138     if (!next_token(&ptr,s->name   , NULL, sizeof(s->name))) continue;
1139     if (!next_token(&ptr,stype     , NULL, sizeof(stype))) continue;
1140     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1141     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1142       /* this allows us to cope with an old nmbd */
1143       pstrcpy(s->domain,global_myworkgroup); 
1144     }
1145     
1146     if (sscanf(stype,"%X",&s->type) != 1) { 
1147       DEBUG(4,("r:host file ")); 
1148       ok = False; 
1149     }
1150     
1151         /* Filter the servers/domains we return based on what was asked for. */
1152
1153         /* Check to see if we are being asked for a local list only. */
1154         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1155           DEBUG(4,("r: local list only"));
1156           ok = False;
1157         }
1158
1159     /* doesn't match up: don't want it */
1160     if (!(servertype & s->type)) { 
1161       DEBUG(4,("r:serv type ")); 
1162       ok = False; 
1163     }
1164     
1165     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1166         (s->type & SV_TYPE_DOMAIN_ENUM))
1167       {
1168         DEBUG(4,("s: dom mismatch "));
1169         ok = False;
1170       }
1171     
1172     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1173       {
1174         ok = False;
1175       }
1176     
1177         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1178         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1179
1180     if (ok)
1181       {
1182         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1183                  s->name, s->type, s->comment, s->domain));
1184         
1185         s->server_added = True;
1186         count++;
1187       }
1188     else
1189       {
1190         DEBUG(4,("%20s %8x %25s %15s\n",
1191                  s->name, s->type, s->comment, s->domain));
1192       }
1193   }
1194   
1195   file_lines_free(lines);
1196   return(count);
1197 }
1198
1199
1200 /*******************************************************************
1201   fill in a server info structure
1202   ******************************************************************/
1203 static int fill_srv_info(struct srv_info_struct *service, 
1204                          int uLevel, char **buf, int *buflen, 
1205                          char **stringbuf, int *stringspace, char *baseaddr)
1206 {
1207   int struct_len;
1208   char* p;
1209   char* p2;
1210   int l2;
1211   int len;
1212  
1213   switch (uLevel) {
1214   case 0: struct_len = 16; break;
1215   case 1: struct_len = 26; break;
1216   default: return -1;
1217   }  
1218  
1219   if (!buf)
1220     {
1221       len = 0;
1222       switch (uLevel) 
1223         {
1224         case 1:
1225           len = strlen(service->comment)+1;
1226           break;
1227         }
1228
1229       if (buflen) *buflen = struct_len;
1230       if (stringspace) *stringspace = len;
1231       return struct_len + len;
1232     }
1233   
1234   len = struct_len;
1235   p = *buf;
1236   if (*buflen < struct_len) return -1;
1237   if (stringbuf)
1238     {
1239       p2 = *stringbuf;
1240       l2 = *stringspace;
1241     }
1242   else
1243     {
1244       p2 = p + struct_len;
1245       l2 = *buflen - struct_len;
1246     }
1247   if (!baseaddr) baseaddr = p;
1248   
1249   switch (uLevel)
1250     {
1251     case 0:
1252             push_ascii(p,service->name, 15, STR_TERMINATE);
1253             break;
1254
1255     case 1:
1256             push_ascii(p,service->name,15, STR_TERMINATE);
1257             SIVAL(p,18,service->type);
1258             SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1259             len += CopyAndAdvance(&p2,service->comment,&l2);
1260             break;
1261     }
1262
1263   if (stringbuf)
1264     {
1265       *buf = p + struct_len;
1266       *buflen -= struct_len;
1267       *stringbuf = p2;
1268       *stringspace = l2;
1269     }
1270   else
1271     {
1272       *buf = p2;
1273       *buflen -= len;
1274     }
1275   return len;
1276 }
1277
1278
1279 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1280 {
1281   return(strcmp(s1->name,s2->name));
1282 }
1283
1284 /****************************************************************************
1285   view list of servers available (or possibly domains). The info is
1286   extracted from lists saved by nmbd on the local host
1287   ****************************************************************************/
1288 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1289                                int mdrcnt, int mprcnt, char **rdata, 
1290                                char **rparam, int *rdata_len, int *rparam_len)
1291 {
1292   char *str1 = param+2;
1293   char *str2 = skip_string(str1,1);
1294   char *p = skip_string(str2,1);
1295   int uLevel = SVAL(p,0);
1296   int buf_len = SVAL(p,2);
1297   uint32 servertype = IVAL(p,4);
1298   char *p2;
1299   int data_len, fixed_len, string_len;
1300   int f_len = 0, s_len = 0;
1301   struct srv_info_struct *servers=NULL;
1302   int counted=0,total=0;
1303   int i,missed;
1304   fstring domain;
1305   BOOL domain_request;
1306   BOOL local_request;
1307
1308   /* If someone sets all the bits they don't really mean to set
1309      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1310      known servers. */
1311
1312   if (servertype == SV_TYPE_ALL) 
1313     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1314
1315   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1316      any other bit (they may just set this bit on it's own) they 
1317      want all the locally seen servers. However this bit can be 
1318      set on its own so set the requested servers to be 
1319      ALL - DOMAIN_ENUM. */
1320
1321   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1322     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1323
1324   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1325   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1326
1327   p += 8;
1328
1329   if (!prefix_ok(str1,"WrLehD")) return False;
1330   if (!check_server_info(uLevel,str2)) return False;
1331   
1332   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1333   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1334   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1335
1336   if (strcmp(str1, "WrLehDz") == 0) {
1337           pull_ascii_fstring(domain, p);
1338   } else {
1339           fstrcpy(domain, global_myworkgroup);
1340   }
1341
1342   if (lp_browse_list())
1343     total = get_server_info(servertype,&servers,domain);
1344
1345   data_len = fixed_len = string_len = 0;
1346   missed = 0;
1347
1348   if (total > 0)
1349     qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1350
1351   {
1352     char *lastname=NULL;
1353
1354     for (i=0;i<total;i++)
1355     {
1356       struct srv_info_struct *s = &servers[i];
1357       if (lastname && strequal(lastname,s->name)) continue;
1358       lastname = s->name;
1359       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1360       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1361                s->name, s->type, s->comment, s->domain));
1362       
1363       if (data_len <= buf_len) {
1364           counted++;
1365           fixed_len += f_len;
1366           string_len += s_len;
1367       } else {
1368         missed++;
1369       }
1370     }
1371   }
1372
1373   *rdata_len = fixed_len + string_len;
1374   *rdata = REALLOC(*rdata,*rdata_len);
1375   memset(*rdata,'\0',*rdata_len);
1376   
1377   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1378   p = *rdata;
1379   f_len = fixed_len;
1380   s_len = string_len;
1381
1382   {
1383     char *lastname=NULL;
1384     int count2 = counted;
1385     for (i = 0; i < total && count2;i++)
1386       {
1387         struct srv_info_struct *s = &servers[i];
1388         if (lastname && strequal(lastname,s->name)) continue;
1389         lastname = s->name;
1390         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1391         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1392                  s->name, s->type, s->comment, s->domain));
1393         count2--;
1394       }
1395   }
1396   
1397   *rparam_len = 8;
1398   *rparam = REALLOC(*rparam,*rparam_len);
1399   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1400   SSVAL(*rparam,2,0);
1401   SSVAL(*rparam,4,counted);
1402   SSVAL(*rparam,6,counted+missed);
1403
1404   SAFE_FREE(servers);
1405
1406   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1407            domain,uLevel,counted,counted+missed));
1408
1409   return(True);
1410 }
1411
1412 /****************************************************************************
1413   command 0x34 - suspected of being a "Lookup Names" stub api
1414   ****************************************************************************/
1415 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1416                                int mdrcnt, int mprcnt, char **rdata, 
1417                                char **rparam, int *rdata_len, int *rparam_len)
1418 {
1419   char *str1 = param+2;
1420   char *str2 = skip_string(str1,1);
1421   char *p = skip_string(str2,1);
1422   int uLevel = SVAL(p,0);
1423   int buf_len = SVAL(p,2);
1424   int counted=0;
1425   int missed=0;
1426
1427         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1428                 str1, str2, p, uLevel, buf_len));
1429
1430   if (!prefix_ok(str1,"zWrLeh")) return False;
1431   
1432   *rdata_len = 0;
1433   
1434   *rparam_len = 8;
1435   *rparam = REALLOC(*rparam,*rparam_len);
1436
1437   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1438   SSVAL(*rparam,2,0);
1439   SSVAL(*rparam,4,counted);
1440   SSVAL(*rparam,6,counted+missed);
1441
1442   return(True);
1443 }
1444
1445 /****************************************************************************
1446   get info about a share
1447   ****************************************************************************/
1448 static BOOL check_share_info(int uLevel, char* id)
1449 {
1450   switch( uLevel ) {
1451   case 0:
1452     if (strcmp(id,"B13") != 0) return False;
1453     break;
1454   case 1:
1455     if (strcmp(id,"B13BWz") != 0) return False;
1456     break;
1457   case 2:
1458     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1459     break;
1460   case 91:
1461     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1462     break;
1463   default: return False;
1464   }
1465   return True;
1466 }
1467
1468 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1469                            char** buf, int* buflen,
1470                            char** stringbuf, int* stringspace, char* baseaddr)
1471 {
1472   int struct_len;
1473   char* p;
1474   char* p2;
1475   int l2;
1476   int len;
1477  
1478   switch( uLevel ) {
1479   case 0: struct_len = 13; break;
1480   case 1: struct_len = 20; break;
1481   case 2: struct_len = 40; break;
1482   case 91: struct_len = 68; break;
1483   default: return -1;
1484   }
1485   
1486  
1487   if (!buf)
1488     {
1489       len = 0;
1490       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1491       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1492       if (buflen) *buflen = struct_len;
1493       if (stringspace) *stringspace = len;
1494       return struct_len + len;
1495     }
1496   
1497   len = struct_len;
1498   p = *buf;
1499   if ((*buflen) < struct_len) return -1;
1500   if (stringbuf)
1501     {
1502       p2 = *stringbuf;
1503       l2 = *stringspace;
1504     }
1505   else
1506     {
1507       p2 = p + struct_len;
1508       l2 = (*buflen) - struct_len;
1509     }
1510   if (!baseaddr) baseaddr = p;
1511   
1512   push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1513   
1514   if (uLevel > 0)
1515     {
1516       int type;
1517       CVAL(p,13) = 0;
1518       type = STYPE_DISKTREE;
1519       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1520       if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
1521       SSVAL(p,14,type);         /* device type */
1522       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1523       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1524     }
1525   
1526   if (uLevel > 1)
1527     {
1528       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1529       SSVALS(p,22,-1);          /* max uses */
1530       SSVAL(p,24,1); /* current uses */
1531       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1532       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1533       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1534     }
1535   
1536   if (uLevel > 2)
1537     {
1538       memset(p+40,0,SHPWLEN+2);
1539       SSVAL(p,50,0);
1540       SIVAL(p,52,0);
1541       SSVAL(p,56,0);
1542       SSVAL(p,58,0);
1543       SIVAL(p,60,0);
1544       SSVAL(p,64,0);
1545       SSVAL(p,66,0);
1546     }
1547        
1548   if (stringbuf)
1549     {
1550       (*buf) = p + struct_len;
1551       (*buflen) -= struct_len;
1552       (*stringbuf) = p2;
1553       (*stringspace) = l2;
1554     }
1555   else
1556     {
1557       (*buf) = p2;
1558       (*buflen) -= len;
1559     }
1560   return len;
1561 }
1562
1563 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1564                                  int mdrcnt,int mprcnt,
1565                                  char **rdata,char **rparam,
1566                                  int *rdata_len,int *rparam_len)
1567 {
1568   char *str1 = param+2;
1569   char *str2 = skip_string(str1,1);
1570   char *netname = skip_string(str2,1);
1571   char *p = skip_string(netname,1);
1572   int uLevel = SVAL(p,0);
1573   int snum = find_service(netname);
1574   
1575   if (snum < 0) return False;
1576   
1577   /* check it's a supported varient */
1578   if (!prefix_ok(str1,"zWrLh")) return False;
1579   if (!check_share_info(uLevel,str2)) return False;
1580  
1581   *rdata = REALLOC(*rdata,mdrcnt);
1582   p = *rdata;
1583   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1584   if (*rdata_len < 0) return False;
1585  
1586   *rparam_len = 6;
1587   *rparam = REALLOC(*rparam,*rparam_len);
1588   SSVAL(*rparam,0,NERR_Success);
1589   SSVAL(*rparam,2,0);           /* converter word */
1590   SSVAL(*rparam,4,*rdata_len);
1591  
1592   return(True);
1593 }
1594
1595 /****************************************************************************
1596   view list of shares available
1597   ****************************************************************************/
1598 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1599                               int mdrcnt,int mprcnt,
1600                               char **rdata,char **rparam,
1601                               int *rdata_len,int *rparam_len)
1602 {
1603   char *str1 = param+2;
1604   char *str2 = skip_string(str1,1);
1605   char *p = skip_string(str2,1);
1606   int uLevel = SVAL(p,0);
1607   int buf_len = SVAL(p,2);
1608   char *p2;
1609   int count=lp_numservices();
1610   int total=0,counted=0;
1611   BOOL missed = False;
1612   int i;
1613   int data_len, fixed_len, string_len;
1614   int f_len = 0, s_len = 0;
1615  
1616   if (!prefix_ok(str1,"WrLeh")) return False;
1617   if (!check_share_info(uLevel,str2)) return False;
1618   
1619   data_len = fixed_len = string_len = 0;
1620   for (i=0;i<count;i++)
1621     if (lp_browseable(i) && lp_snum_ok(i))
1622     {
1623       total++;
1624       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1625       if (data_len <= buf_len)
1626       {
1627         counted++;
1628         fixed_len += f_len;
1629         string_len += s_len;
1630       }
1631       else
1632         missed = True;
1633     }
1634   *rdata_len = fixed_len + string_len;
1635   *rdata = REALLOC(*rdata,*rdata_len);
1636   memset(*rdata,0,*rdata_len);
1637   
1638   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1639   p = *rdata;
1640   f_len = fixed_len;
1641   s_len = string_len;
1642   for (i = 0; i < count;i++)
1643     if (lp_browseable(i) && lp_snum_ok(i))
1644       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1645         break;
1646   
1647   *rparam_len = 8;
1648   *rparam = REALLOC(*rparam,*rparam_len);
1649   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1650   SSVAL(*rparam,2,0);
1651   SSVAL(*rparam,4,counted);
1652   SSVAL(*rparam,6,total);
1653   
1654   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1655            counted,total,uLevel,
1656            buf_len,*rdata_len,mdrcnt));
1657   return(True);
1658 }
1659
1660
1661 /****************************************************************************
1662   view list of groups available
1663   ****************************************************************************/
1664 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1665                               int mdrcnt,int mprcnt,
1666                               char **rdata,char **rparam,
1667                               int *rdata_len,int *rparam_len)
1668 {
1669         char *str1 = param+2;
1670         char *str2 = skip_string(str1,1);
1671         char *p = skip_string(str2,1);
1672         int uLevel = SVAL(p,0);
1673         char *p2;
1674         int count=0;
1675
1676         if (!prefix_ok(str1,"WrLeh")) return False;
1677   
1678         /* check it's a supported variant */
1679         switch( uLevel )
1680         {
1681                 case 0: 
1682                         p2 = "B21"; 
1683                         break;
1684                 default: 
1685                         return False;
1686         }
1687
1688         if (strcmp(p2,str2) != 0) return False;
1689
1690         *rdata_len = mdrcnt + 1024;
1691         *rdata = REALLOC(*rdata,*rdata_len);
1692
1693         SSVAL(*rparam,0,NERR_Success);
1694         SSVAL(*rparam,2,0);             /* converter word */
1695
1696         p = *rdata;
1697
1698         /* XXXX we need a real SAM database some day */
1699         pstrcpy(p,"Users"); p += 21; count++;
1700         pstrcpy(p,"Domain Users"); p += 21; count++;
1701         pstrcpy(p,"Guests"); p += 21; count++;
1702         pstrcpy(p,"Domain Guests"); p += 21; count++;
1703
1704         *rdata_len = PTR_DIFF(p,*rdata);
1705
1706         *rparam_len = 8;
1707         *rparam = REALLOC(*rparam,*rparam_len);
1708
1709         SSVAL(*rparam,4,count); /* is this right?? */
1710         SSVAL(*rparam,6,count); /* is this right?? */
1711
1712         DEBUG(3,("api_RNetGroupEnum gave %d entries\n", count));
1713
1714         return(True);
1715 }
1716
1717 /****************************************************************************
1718   view list of groups available
1719   ****************************************************************************/
1720 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1721                               int mdrcnt,int mprcnt,
1722                               char **rdata,char **rparam,
1723                               int *rdata_len,int *rparam_len)
1724 {
1725         char *str1 = param+2;
1726         char *str2 = skip_string(str1,1);
1727         char *p = skip_string(str2,1);
1728         int uLevel = SVAL(p,0);
1729         char *p2;
1730         int count=0;
1731
1732         if (!prefix_ok(str1,"WrLeh")) return False;
1733   
1734         /* check it's a supported variant */
1735         switch( uLevel )
1736         {
1737                 case 0: 
1738                         p2 = "B21"; 
1739                         break;
1740                 default: 
1741                         return False;
1742         }
1743
1744         if (strcmp(p2,str2) != 0) return False;
1745
1746         *rdata_len = mdrcnt + 1024;
1747         *rdata = REALLOC(*rdata,*rdata_len);
1748
1749         SSVAL(*rparam,0,NERR_Success);
1750         SSVAL(*rparam,2,0);             /* converter word */
1751
1752         p = *rdata;
1753
1754         /* XXXX we need a real SAM database some day */
1755         pstrcpy(p,"Users"); p += 21; count++;
1756         pstrcpy(p,"Domain Users"); p += 21; count++;
1757         pstrcpy(p,"Guests"); p += 21; count++;
1758         pstrcpy(p,"Domain Guests"); p += 21; count++;
1759
1760         *rdata_len = PTR_DIFF(p,*rdata);
1761
1762         *rparam_len = 8;
1763         *rparam = REALLOC(*rparam,*rparam_len);
1764
1765         SSVAL(*rparam,4,count); /* is this right?? */
1766         SSVAL(*rparam,6,count); /* is this right?? */
1767
1768         DEBUG(3,("api_RNetUserEnum gave %d entries\n", count));
1769
1770         return(True);
1771 }
1772
1773
1774
1775 /****************************************************************************
1776   get the time of day info
1777   ****************************************************************************/
1778 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1779                              int mdrcnt,int mprcnt,
1780                              char **rdata,char **rparam,
1781                              int *rdata_len,int *rparam_len)
1782 {
1783   char *p;
1784   *rparam_len = 4;
1785   *rparam = REALLOC(*rparam,*rparam_len);
1786
1787   *rdata_len = 21;
1788   *rdata = REALLOC(*rdata,*rdata_len);
1789
1790   SSVAL(*rparam,0,NERR_Success);
1791   SSVAL(*rparam,2,0);           /* converter word */
1792
1793   p = *rdata;
1794
1795   {
1796     struct tm *t;
1797     time_t unixdate = time(NULL);
1798
1799     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1800                                     by NT in a "net time" operation,
1801                                     it seems to ignore the one below */
1802
1803     /* the client expects to get localtime, not GMT, in this bit 
1804        (I think, this needs testing) */
1805     t = LocalTime(&unixdate);
1806
1807     SIVAL(p,4,0);               /* msecs ? */
1808     CVAL(p,8) = t->tm_hour;
1809     CVAL(p,9) = t->tm_min;
1810     CVAL(p,10) = t->tm_sec;
1811     CVAL(p,11) = 0;             /* hundredths of seconds */
1812     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1813     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1814     CVAL(p,16) = t->tm_mday;
1815     CVAL(p,17) = t->tm_mon + 1;
1816     SSVAL(p,18,1900+t->tm_year);
1817     CVAL(p,20) = t->tm_wday;
1818   }
1819
1820
1821   return(True);
1822 }
1823
1824 /****************************************************************************
1825  Set the user password.
1826 *****************************************************************************/
1827
1828 static BOOL api_SetUserPassword(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)
1832 {
1833   char *p = skip_string(param+2,2);
1834   fstring user;
1835   fstring pass1,pass2;
1836
1837   struct passwd *passwd;
1838
1839   pull_ascii_fstring(user,p);
1840
1841   p = skip_string(p,1);
1842
1843   memset(pass1,'\0',sizeof(pass1));
1844   memset(pass2,'\0',sizeof(pass2));
1845   memcpy(pass1,p,16);
1846   memcpy(pass2,p+16,16);
1847
1848   *rparam_len = 4;
1849   *rparam = REALLOC(*rparam,*rparam_len);
1850
1851   *rdata_len = 0;
1852
1853   SSVAL(*rparam,0,NERR_badpass);
1854   SSVAL(*rparam,2,0);           /* converter word */
1855
1856   DEBUG(3,("Set password for <%s>\n",user));
1857
1858   /*
1859    * Pass the user through the NT -> unix user mapping
1860    * function.
1861    */
1862
1863   (void)map_username(user);
1864
1865   /*
1866    * Do any UNIX username case mangling.
1867    */
1868   passwd = Get_Pwnam( user, True);
1869
1870   /*
1871    * Attempt to verify the old password against smbpasswd entries
1872    * Win98 clients send old and new password in plaintext for this call.
1873    */
1874
1875   {
1876     fstring saved_pass2;
1877     SAM_ACCOUNT *sampass=NULL;
1878
1879     /*
1880      * Save the new password as change_oem_password overwrites it
1881      * with zeros.
1882      */
1883
1884     fstrcpy(saved_pass2, pass2);
1885
1886     if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1887         change_oem_password(sampass,pass2))
1888     {
1889       SSVAL(*rparam,0,NERR_Success);
1890
1891       /*
1892        * If unix password sync was requested, attempt to change
1893        * the /etc/passwd database also. Return failure if this cannot
1894        * be done.
1895        */
1896
1897       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1898         SSVAL(*rparam,0,NERR_badpass);
1899     }
1900         pdb_free_sam(&sampass);
1901  }
1902   
1903
1904   /*
1905    * If the above failed, attempt the plaintext password change.
1906    * This tests against the /etc/passwd database only.
1907    */
1908
1909   if(SVAL(*rparam,0) != NERR_Success)
1910   {
1911           if NT_STATUS_IS_OK(pass_check(passwd, user, pass1, 
1912                                         strlen(pass1), NULL, False)) 
1913                   {
1914                           if (chgpasswd(user,pass1,pass2,False)) {
1915                                   SSVAL(*rparam,0,NERR_Success);
1916                           }
1917                   }
1918   }
1919   
1920   /*
1921    * If the plaintext change failed, attempt
1922    * the old encrypted method. NT will generate this
1923    * after trying the samr method. Note that this
1924    * method is done as a last resort as this
1925    * password change method loses the NT password hash
1926    * and cannot change the UNIX password as no plaintext
1927    * is received.
1928    */
1929
1930   if(SVAL(*rparam,0) != NERR_Success)
1931   {
1932     SAM_ACCOUNT *hnd = NULL;
1933
1934     if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
1935        change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1936     {
1937       SSVAL(*rparam,0,NERR_Success);
1938     }
1939         pdb_free_sam(&hnd);
1940   }
1941
1942
1943   memset((char *)pass1,'\0',sizeof(fstring));
1944   memset((char *)pass2,'\0',sizeof(fstring));    
1945          
1946   return(True);
1947 }
1948
1949 /****************************************************************************
1950   Set the user password (SamOEM version - gets plaintext).
1951 ****************************************************************************/
1952
1953 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1954                                 int mdrcnt,int mprcnt,
1955                                 char **rdata,char **rparam,
1956                                 int *rdata_len,int *rparam_len)
1957 {
1958   fstring user;
1959   char *p = param + 2;
1960   *rparam_len = 2;
1961   *rparam = REALLOC(*rparam,*rparam_len);
1962
1963   *rdata_len = 0;
1964
1965   SSVAL(*rparam,0,NERR_badpass);
1966
1967   /*
1968    * Check the parameter definition is correct.
1969    */
1970   if(!strequal(param + 2, "zsT")) {
1971     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1972     return False;
1973   }
1974   p = skip_string(p, 1);
1975
1976   if(!strequal(p, "B516B16")) {
1977     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1978     return False;
1979   }
1980   p = skip_string(p,1);
1981
1982   p += pull_ascii_fstring(user,p);
1983
1984   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1985
1986   /*
1987    * Pass the user through the NT -> unix user mapping
1988    * function.
1989    */
1990
1991   (void)map_username(user);
1992
1993   /*
1994    * Do any UNIX username case mangling.
1995    */
1996   (void)Get_Pwnam( user, True);
1997
1998   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1999   {
2000     SSVAL(*rparam,0,NERR_Success);
2001   }
2002
2003   return(True);
2004 }
2005
2006 /****************************************************************************
2007   delete a print job
2008   Form: <W> <> 
2009   ****************************************************************************/
2010 static BOOL api_RDosPrintJobDel(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)
2014 {
2015         int function = SVAL(param,0);
2016         char *str1 = param+2;
2017         char *str2 = skip_string(str1,1);
2018         char *p = skip_string(str2,1);
2019         int jobid, errcode;
2020         extern struct current_user current_user;
2021         WERROR werr = WERR_OK;
2022
2023         jobid = SVAL(p,0);
2024
2025         /* check it's a supported varient */
2026         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2027                 return(False);
2028
2029         *rparam_len = 4;
2030         *rparam = REALLOC(*rparam,*rparam_len); 
2031         *rdata_len = 0;
2032
2033         if (!print_job_exists(jobid)) {
2034                 errcode = NERR_JobNotFound;
2035                 goto out;
2036         }
2037
2038         errcode = NERR_notsupported;
2039         
2040         switch (function) {
2041         case 81:                /* delete */ 
2042                 if (print_job_delete(&current_user, jobid, &werr)) 
2043                         errcode = NERR_Success;
2044                 break;
2045         case 82:                /* pause */
2046                 if (print_job_pause(&current_user, jobid, &werr)) 
2047                         errcode = NERR_Success;
2048                 break;
2049         case 83:                /* resume */
2050                 if (print_job_resume(&current_user, jobid, &werr)) 
2051                         errcode = NERR_Success;
2052                 break;
2053         }
2054
2055         if (!W_ERROR_IS_OK(werr))
2056                 errcode = W_ERROR_V(werr);
2057         
2058  out:
2059         SSVAL(*rparam,0,errcode);       
2060         SSVAL(*rparam,2,0);             /* converter word */
2061
2062         return(True);
2063 }
2064
2065 /****************************************************************************
2066   Purge a print queue - or pause or resume it.
2067   ****************************************************************************/
2068 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2069                                  int mdrcnt,int mprcnt,
2070                                  char **rdata,char **rparam,
2071                                  int *rdata_len,int *rparam_len)
2072 {
2073         int function = SVAL(param,0);
2074         char *str1 = param+2;
2075         char *str2 = skip_string(str1,1);
2076         char *QueueName = skip_string(str2,1);
2077         int errcode = NERR_notsupported;
2078         int snum;
2079         WERROR werr = WERR_OK;
2080         extern struct current_user current_user;
2081
2082         /* check it's a supported varient */
2083         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2084                 return(False);
2085
2086         *rparam_len = 4;
2087         *rparam = REALLOC(*rparam,*rparam_len);
2088         *rdata_len = 0;
2089
2090         snum = print_queue_snum(QueueName);
2091
2092         if (snum == -1) {
2093                 errcode = NERR_JobNotFound;
2094                 goto out;
2095         }
2096
2097         switch (function) {
2098         case 74: /* Pause queue */
2099                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2100                 break;
2101         case 75: /* Resume queue */
2102                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2103                 break;
2104         case 103: /* Purge */
2105                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2106                 break;
2107         }
2108
2109         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2110
2111  out:
2112         SSVAL(*rparam,0,errcode);
2113         SSVAL(*rparam,2,0);             /* converter word */
2114
2115         return(True);
2116 }
2117
2118
2119 /****************************************************************************
2120   set the property of a print job (undocumented?)
2121   ? function = 0xb -> set name of print job
2122   ? function = 0x6 -> move print job up/down
2123   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2124   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2125 ****************************************************************************/
2126 static int check_printjob_info(struct pack_desc* desc,
2127                                int uLevel, char* id)
2128 {
2129         desc->subformat = NULL;
2130         switch( uLevel ) {
2131         case 0: desc->format = "W"; break;
2132         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2133         case 2: desc->format = "WWzWWDDzz"; break;
2134         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2135         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2136         default: return False;
2137         }
2138         if (strcmp(desc->format,id) != 0) return False;
2139         return True;
2140 }
2141
2142 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2143                              int mdrcnt,int mprcnt,
2144                              char **rdata,char **rparam,
2145                              int *rdata_len,int *rparam_len)
2146 {
2147         struct pack_desc desc;
2148         char *str1 = param+2;
2149         char *str2 = skip_string(str1,1);
2150         char *p = skip_string(str2,1);
2151         int jobid;
2152         int uLevel = SVAL(p,2);
2153         int function = SVAL(p,4);
2154         int place, errcode;
2155
2156         jobid = SVAL(p,0);
2157         *rparam_len = 4;
2158         *rparam = REALLOC(*rparam,*rparam_len);
2159   
2160         *rdata_len = 0;
2161         
2162         /* check it's a supported varient */
2163         if ((strcmp(str1,"WWsTP")) || 
2164             (!check_printjob_info(&desc,uLevel,str2)))
2165                 return(False);
2166
2167         if (!print_job_exists(jobid)) {
2168                 errcode=NERR_JobNotFound;
2169                 goto out;
2170         }
2171
2172         errcode = NERR_notsupported;
2173
2174         switch (function) {
2175         case 0x6:
2176                 /* change job place in the queue, 
2177                    data gives the new place */
2178                 place = SVAL(data,0);
2179                 if (print_job_set_place(jobid, place)) {
2180                         errcode=NERR_Success;
2181                 }
2182                 break;
2183
2184         case 0xb:   
2185                 /* change print job name, data gives the name */
2186                 if (print_job_set_name(jobid, data)) {
2187                         errcode=NERR_Success;
2188                 }
2189                 break;
2190
2191         default:
2192                 return False;
2193         }
2194
2195  out:
2196         SSVALS(*rparam,0,errcode);
2197         SSVAL(*rparam,2,0);             /* converter word */
2198         
2199         return(True);
2200 }
2201
2202
2203 /****************************************************************************
2204   get info about the server
2205   ****************************************************************************/
2206 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2207                                   int mdrcnt,int mprcnt,
2208                                   char **rdata,char **rparam,
2209                                   int *rdata_len,int *rparam_len)
2210 {
2211   char *str1 = param+2;
2212   char *str2 = skip_string(str1,1);
2213   char *p = skip_string(str2,1);
2214   int uLevel = SVAL(p,0);
2215   char *p2;
2216   int struct_len;
2217
2218   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2219
2220   /* check it's a supported varient */
2221   if (!prefix_ok(str1,"WrLh")) return False;
2222   switch( uLevel ) {
2223   case 0:
2224     if (strcmp(str2,"B16") != 0) return False;
2225     struct_len = 16;
2226     break;
2227   case 1:
2228     if (strcmp(str2,"B16BBDz") != 0) return False;
2229     struct_len = 26;
2230     break;
2231   case 2:
2232     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2233         != 0) return False;
2234     struct_len = 134;
2235     break;
2236   case 3:
2237     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2238         != 0) return False;
2239     struct_len = 144;
2240     break;
2241   case 20:
2242     if (strcmp(str2,"DN") != 0) return False;
2243     struct_len = 6;
2244     break;
2245   case 50:
2246     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2247     struct_len = 42;
2248     break;
2249   default: return False;
2250   }
2251
2252   *rdata_len = mdrcnt;
2253   *rdata = REALLOC(*rdata,*rdata_len);
2254
2255   p = *rdata;
2256   p2 = p + struct_len;
2257   if (uLevel != 20) {
2258     srvstr_push(NULL, p,local_machine,16, 
2259                 STR_ASCII|STR_UPPER|STR_TERMINATE);
2260   }
2261   p += 16;
2262   if (uLevel > 0)
2263     {
2264       struct srv_info_struct *servers=NULL;
2265       int i,count;
2266       pstring comment;
2267       uint32 servertype= lp_default_server_announce();
2268
2269       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2270
2271       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2272         for (i=0;i<count;i++)
2273           if (strequal(servers[i].name,local_machine))
2274       {
2275             servertype = servers[i].type;
2276             pstrcpy(comment,servers[i].comment);            
2277           }
2278       }
2279       SAFE_FREE(servers);
2280
2281       SCVAL(p,0,lp_major_announce_version());
2282       SCVAL(p,1,lp_minor_announce_version());
2283       SIVAL(p,2,servertype);
2284
2285       if (mdrcnt == struct_len) {
2286         SIVAL(p,6,0);
2287       } else {
2288         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2289         standard_sub_conn(conn,comment);
2290         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2291         p2 = skip_string(p2,1);
2292       }
2293     }
2294   if (uLevel > 1)
2295     {
2296       return False;             /* not yet implemented */
2297     }
2298
2299   *rdata_len = PTR_DIFF(p2,*rdata);
2300
2301   *rparam_len = 6;
2302   *rparam = REALLOC(*rparam,*rparam_len);
2303   SSVAL(*rparam,0,NERR_Success);
2304   SSVAL(*rparam,2,0);           /* converter word */
2305   SSVAL(*rparam,4,*rdata_len);
2306
2307   return(True);
2308 }
2309
2310
2311 /****************************************************************************
2312   get info about the server
2313   ****************************************************************************/
2314 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2315                                 int mdrcnt,int mprcnt,
2316                                 char **rdata,char **rparam,
2317                                 int *rdata_len,int *rparam_len)
2318 {
2319   char *str1 = param+2;
2320   char *str2 = skip_string(str1,1);
2321   char *p = skip_string(str2,1);
2322   char *p2;
2323   extern userdom_struct current_user_info;
2324   int level = SVAL(p,0);
2325
2326   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2327
2328   *rparam_len = 6;
2329   *rparam = REALLOC(*rparam,*rparam_len);
2330
2331   /* check it's a supported varient */
2332   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2333     return(False);
2334
2335   *rdata_len = mdrcnt + 1024;
2336   *rdata = REALLOC(*rdata,*rdata_len);
2337
2338   SSVAL(*rparam,0,NERR_Success);
2339   SSVAL(*rparam,2,0);           /* converter word */
2340
2341   p = *rdata;
2342   p2 = p + 22;
2343
2344
2345   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2346   pstrcpy(p2,local_machine);
2347   strupper(p2);
2348   p2 = skip_string(p2,1);
2349   p += 4;
2350
2351   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2352   pstrcpy(p2,current_user_info.smb_name);
2353   p2 = skip_string(p2,1);
2354   p += 4;
2355
2356   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2357   pstrcpy(p2,global_myworkgroup);
2358   strupper(p2);
2359   p2 = skip_string(p2,1);
2360   p += 4;
2361
2362   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2363   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2364   p += 2;
2365
2366   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2367   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2368   p2 = skip_string(p2,1);
2369   p += 4;
2370
2371   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2372   pstrcpy(p2,"");
2373   p2 = skip_string(p2,1);
2374   p += 4;
2375
2376   *rdata_len = PTR_DIFF(p2,*rdata);
2377
2378   SSVAL(*rparam,4,*rdata_len);
2379
2380   return(True);
2381 }
2382
2383 /****************************************************************************
2384   get info about a user
2385
2386     struct user_info_11 {
2387         char                usri11_name[21];  0-20 
2388         char                usri11_pad;       21 
2389         char                *usri11_comment;  22-25 
2390         char            *usri11_usr_comment;  26-29
2391         unsigned short      usri11_priv;      30-31
2392         unsigned long       usri11_auth_flags; 32-35
2393         long                usri11_password_age; 36-39
2394         char                *usri11_homedir; 40-43
2395         char            *usri11_parms; 44-47
2396         long                usri11_last_logon; 48-51
2397         long                usri11_last_logoff; 52-55
2398         unsigned short      usri11_bad_pw_count; 56-57
2399         unsigned short      usri11_num_logons; 58-59
2400         char                *usri11_logon_server; 60-63
2401         unsigned short      usri11_country_code; 64-65
2402         char            *usri11_workstations; 66-69
2403         unsigned long       usri11_max_storage; 70-73
2404         unsigned short      usri11_units_per_week; 74-75
2405         unsigned char       *usri11_logon_hours; 76-79
2406         unsigned short      usri11_code_page; 80-81
2407     };
2408
2409 where:
2410
2411   usri11_name specifies the user name for which information is retireved
2412
2413   usri11_pad aligns the next data structure element to a word boundary
2414
2415   usri11_comment is a null terminated ASCII comment
2416
2417   usri11_user_comment is a null terminated ASCII comment about the user
2418
2419   usri11_priv specifies the level of the privilege assigned to the user.
2420        The possible values are:
2421
2422 Name             Value  Description
2423 USER_PRIV_GUEST  0      Guest privilege
2424 USER_PRIV_USER   1      User privilege
2425 USER_PRV_ADMIN   2      Administrator privilege
2426
2427   usri11_auth_flags specifies the account operator privileges. The
2428        possible values are:
2429
2430 Name            Value   Description
2431 AF_OP_PRINT     0       Print operator
2432
2433
2434 Leach, Naik                                        [Page 28]
2435 \f
2436
2437
2438 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2439
2440
2441 AF_OP_COMM      1       Communications operator
2442 AF_OP_SERVER    2       Server operator
2443 AF_OP_ACCOUNTS  3       Accounts operator
2444
2445
2446   usri11_password_age specifies how many seconds have elapsed since the
2447        password was last changed.
2448
2449   usri11_home_dir points to a null terminated ASCII string that contains
2450        the path name of the user's home directory.
2451
2452   usri11_parms points to a null terminated ASCII string that is set
2453        aside for use by applications.
2454
2455   usri11_last_logon specifies the time when the user last logged on.
2456        This value is stored as the number of seconds elapsed since
2457        00:00:00, January 1, 1970.
2458
2459   usri11_last_logoff specifies the time when the user last logged off.
2460        This value is stored as the number of seconds elapsed since
2461        00:00:00, January 1, 1970. A value of 0 means the last logoff
2462        time is unknown.
2463
2464   usri11_bad_pw_count specifies the number of incorrect passwords
2465        entered since the last successful logon.
2466
2467   usri11_log1_num_logons specifies the number of times this user has
2468        logged on. A value of -1 means the number of logons is unknown.
2469
2470   usri11_logon_server points to a null terminated ASCII string that
2471        contains the name of the server to which logon requests are sent.
2472        A null string indicates logon requests should be sent to the
2473        domain controller.
2474
2475   usri11_country_code specifies the country code for the user's language
2476        of choice.
2477
2478   usri11_workstations points to a null terminated ASCII string that
2479        contains the names of workstations the user may log on from.
2480        There may be up to 8 workstations, with the names separated by
2481        commas. A null strings indicates there are no restrictions.
2482
2483   usri11_max_storage specifies the maximum amount of disk space the user
2484        can occupy. A value of 0xffffffff indicates there are no
2485        restrictions.
2486
2487   usri11_units_per_week specifies the equal number of time units into
2488        which a week is divided. This value must be equal to 168.
2489
2490   usri11_logon_hours points to a 21 byte (168 bits) string that
2491        specifies the time during which the user can log on. Each bit
2492        represents one unique hour in a week. The first bit (bit 0, word
2493        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2494
2495
2496
2497 Leach, Naik                                        [Page 29]
2498 \f
2499
2500
2501 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2502
2503
2504        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2505        are no restrictions.
2506
2507   usri11_code_page specifies the code page for the user's language of
2508        choice
2509
2510 All of the pointers in this data structure need to be treated
2511 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2512 to be ignored. The converter word returned in the parameters section
2513 needs to be subtracted from the lower 16 bits to calculate an offset
2514 into the return buffer where this ASCII string resides.
2515
2516 There is no auxiliary data in the response.
2517
2518   ****************************************************************************/
2519
2520 #define usri11_name           0 
2521 #define usri11_pad            21
2522 #define usri11_comment        22
2523 #define usri11_usr_comment    26
2524 #define usri11_full_name      30
2525 #define usri11_priv           34
2526 #define usri11_auth_flags     36
2527 #define usri11_password_age   40
2528 #define usri11_homedir        44
2529 #define usri11_parms          48
2530 #define usri11_last_logon     52
2531 #define usri11_last_logoff    56
2532 #define usri11_bad_pw_count   60
2533 #define usri11_num_logons     62
2534 #define usri11_logon_server   64
2535 #define usri11_country_code   68
2536 #define usri11_workstations   70
2537 #define usri11_max_storage    74
2538 #define usri11_units_per_week 78
2539 #define usri11_logon_hours    80
2540 #define usri11_code_page      84
2541 #define usri11_end            86
2542
2543 #define USER_PRIV_GUEST 0
2544 #define USER_PRIV_USER 1
2545 #define USER_PRIV_ADMIN 2
2546
2547 #define AF_OP_PRINT     0 
2548 #define AF_OP_COMM      1
2549 #define AF_OP_SERVER    2
2550 #define AF_OP_ACCOUNTS  3
2551
2552
2553 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2554                                 int mdrcnt,int mprcnt,
2555                                 char **rdata,char **rparam,
2556                                 int *rdata_len,int *rparam_len)
2557 {
2558         char *str1 = param+2;
2559         char *str2 = skip_string(str1,1);
2560         char *UserName = skip_string(str2,1);
2561         char *p = skip_string(UserName,1);
2562         int uLevel = SVAL(p,0);
2563         char *p2;
2564
2565     /* get NIS home of a previously validated user - simeon */
2566     /* With share level security vuid will always be zero.
2567        Don't depend on vuser being non-null !!. JRA */
2568     user_struct *vuser = get_valid_user_struct(vuid);
2569     if(vuser != NULL)
2570       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2571                vuser->user.unix_name));
2572
2573     *rparam_len = 6;
2574     *rparam = REALLOC(*rparam,*rparam_len);
2575
2576     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2577   
2578         /* check it's a supported variant */
2579         if (strcmp(str1,"zWrLh") != 0) return False;
2580         switch( uLevel )
2581         {
2582                 case 0: p2 = "B21"; break;
2583                 case 1: p2 = "B21BB16DWzzWz"; break;
2584                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2585                 case 10: p2 = "B21Bzzz"; break;
2586                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2587                 default: return False;
2588         }
2589
2590         if (strcmp(p2,str2) != 0) return False;
2591
2592         *rdata_len = mdrcnt + 1024;
2593         *rdata = REALLOC(*rdata,*rdata_len);
2594
2595         SSVAL(*rparam,0,NERR_Success);
2596         SSVAL(*rparam,2,0);             /* converter word */
2597
2598         p = *rdata;
2599         p2 = p + usri11_end;
2600
2601         memset(p,0,21); 
2602         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2603
2604         if (uLevel > 0)
2605         {
2606                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2607                 *p2 = 0;
2608         }
2609         if (uLevel >= 10)
2610         {
2611                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2612                 pstrcpy(p2,"Comment");
2613                 p2 = skip_string(p2,1);
2614
2615                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2616                 pstrcpy(p2,"UserComment");
2617                 p2 = skip_string(p2,1);
2618
2619                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2620                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2621                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2622                 p2 = skip_string(p2,1);
2623         }
2624
2625         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2626         {         
2627                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2628                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2629                 SIVALS(p,usri11_password_age,-1);               /* password age */
2630                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2631                 pstrcpy(p2, lp_logon_home());
2632                 standard_sub_conn(conn, p2);
2633                 p2 = skip_string(p2,1);
2634                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2635                 pstrcpy(p2,"");
2636                 p2 = skip_string(p2,1);
2637                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2638                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2639                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2640                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2641                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2642                 pstrcpy(p2,"\\\\*");
2643                 p2 = skip_string(p2,1);
2644                 SSVAL(p,usri11_country_code,0);         /* country code */
2645
2646                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2647                 pstrcpy(p2,"");
2648                 p2 = skip_string(p2,1);
2649
2650                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2651                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2652                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2653
2654                 /* a simple way to get logon hours at all times. */
2655                 memset(p2,0xff,21);
2656                 SCVAL(p2,21,0);           /* fix zero termination */
2657                 p2 = skip_string(p2,1);
2658
2659                 SSVAL(p,usri11_code_page,0);            /* code page */
2660         }
2661         if (uLevel == 1 || uLevel == 2)
2662         {
2663                 memset(p+22,' ',16);    /* password */
2664                 SIVALS(p,38,-1);                /* password age */
2665                 SSVAL(p,42,
2666                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2667                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2668                 pstrcpy(p2,lp_logon_home());
2669                 standard_sub_conn(conn, p2);
2670                 p2 = skip_string(p2,1);
2671                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2672                 *p2++ = 0;
2673                 SSVAL(p,52,0);          /* flags */
2674                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2675                 pstrcpy(p2,lp_logon_script());
2676                 standard_sub_conn( conn, p2 );             
2677                 p2 = skip_string(p2,1);
2678                 if (uLevel == 2)
2679                 {
2680                         SIVAL(p,60,0);          /* auth_flags */
2681                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2682                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2683                         p2 = skip_string(p2,1);
2684                         SIVAL(p,68,0);          /* urs_comment */
2685                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2686                         pstrcpy(p2,"");
2687                         p2 = skip_string(p2,1);
2688                         SIVAL(p,76,0);          /* workstations */
2689                         SIVAL(p,80,0);          /* last_logon */
2690                         SIVAL(p,84,0);          /* last_logoff */
2691                         SIVALS(p,88,-1);                /* acct_expires */
2692                         SIVALS(p,92,-1);                /* max_storage */
2693                         SSVAL(p,96,168);        /* units_per_week */
2694                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2695                         memset(p2,-1,21);
2696                         p2 += 21;
2697                         SSVALS(p,102,-1);       /* bad_pw_count */
2698                         SSVALS(p,104,-1);       /* num_logons */
2699                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2700                         pstrcpy(p2,"\\\\%L");
2701                         standard_sub_conn(conn, p2);
2702                         p2 = skip_string(p2,1);
2703                         SSVAL(p,110,49);        /* country_code */
2704                         SSVAL(p,112,860);       /* code page */
2705                 }
2706         }
2707
2708         *rdata_len = PTR_DIFF(p2,*rdata);
2709
2710         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2711
2712         return(True);
2713 }
2714
2715 /*******************************************************************
2716   get groups that a user is a member of
2717   ******************************************************************/
2718 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2719                                  int mdrcnt,int mprcnt,
2720                                  char **rdata,char **rparam,
2721                                  int *rdata_len,int *rparam_len)
2722 {
2723   char *str1 = param+2;
2724   char *str2 = skip_string(str1,1);
2725   char *UserName = skip_string(str2,1);
2726   char *p = skip_string(UserName,1);
2727   int uLevel = SVAL(p,0);
2728   char *p2;
2729   int count=0;
2730
2731   *rparam_len = 8;
2732   *rparam = REALLOC(*rparam,*rparam_len);
2733
2734   /* check it's a supported varient */
2735   if (strcmp(str1,"zWrLeh") != 0) return False;
2736   switch( uLevel ) {
2737   case 0: p2 = "B21"; break;
2738   default: return False;
2739   }
2740   if (strcmp(p2,str2) != 0) return False;
2741
2742   *rdata_len = mdrcnt + 1024;
2743   *rdata = REALLOC(*rdata,*rdata_len);
2744
2745   SSVAL(*rparam,0,NERR_Success);
2746   SSVAL(*rparam,2,0);           /* converter word */
2747
2748   p = *rdata;
2749
2750   /* XXXX we need a real SAM database some day */
2751   pstrcpy(p,"Users"); p += 21; count++;
2752   pstrcpy(p,"Domain Users"); p += 21; count++;
2753   pstrcpy(p,"Guests"); p += 21; count++;
2754   pstrcpy(p,"Domain Guests"); p += 21; count++;
2755
2756   *rdata_len = PTR_DIFF(p,*rdata);
2757
2758   SSVAL(*rparam,4,count);       /* is this right?? */
2759   SSVAL(*rparam,6,count);       /* is this right?? */
2760
2761   return(True);
2762 }
2763
2764
2765 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2766                                 int mdrcnt,int mprcnt,
2767                                 char **rdata,char **rparam,
2768                                 int *rdata_len,int *rparam_len)
2769 {
2770   char *str1 = param+2;
2771   char *str2 = skip_string(str1,1);
2772   char *p = skip_string(str2,1);
2773   int uLevel;
2774   struct pack_desc desc;
2775   char* name;
2776
2777   uLevel = SVAL(p,0);
2778   name = p + 2;
2779
2780   memset((char *)&desc,'\0',sizeof(desc));
2781
2782   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2783
2784   /* check it's a supported varient */
2785   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2786   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2787   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2788   desc.base = *rdata;
2789   desc.buflen = mdrcnt;
2790   desc.subformat = NULL;
2791   desc.format = str2;
2792   
2793   if (init_package(&desc,1,0))
2794   {
2795     PACKI(&desc,"W",0);         /* code */
2796     PACKS(&desc,"B21",name);    /* eff. name */
2797     PACKS(&desc,"B","");                /* pad */
2798     PACKI(&desc,"W",
2799           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2800     PACKI(&desc,"D",0);         /* auth flags XXX */
2801     PACKI(&desc,"W",0);         /* num logons */
2802     PACKI(&desc,"W",0);         /* bad pw count */
2803     PACKI(&desc,"D",0);         /* last logon */
2804     PACKI(&desc,"D",-1);                /* last logoff */
2805     PACKI(&desc,"D",-1);                /* logoff time */
2806     PACKI(&desc,"D",-1);                /* kickoff time */
2807     PACKI(&desc,"D",0);         /* password age */
2808     PACKI(&desc,"D",0);         /* password can change */
2809     PACKI(&desc,"D",-1);                /* password must change */
2810     {
2811       fstring mypath;
2812       fstrcpy(mypath,"\\\\");
2813       fstrcat(mypath,local_machine);
2814       strupper(mypath);
2815       PACKS(&desc,"z",mypath); /* computer */
2816     }
2817     PACKS(&desc,"z",global_myworkgroup);/* domain */
2818
2819 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2820 /* made sure all macros are fully substituted and available */
2821     {
2822       pstring logon_script;
2823       pstrcpy(logon_script,lp_logon_script());
2824       standard_sub_conn( conn, logon_script );
2825       PACKS(&desc,"z", logon_script);           /* script path */
2826     }
2827 /* End of JHT mods */
2828
2829     PACKI(&desc,"D",0x00000000);                /* reserved */
2830   }
2831
2832   *rdata_len = desc.usedlen;
2833   *rparam_len = 6;
2834   *rparam = REALLOC(*rparam,*rparam_len);
2835   SSVALS(*rparam,0,desc.errcode);
2836   SSVAL(*rparam,2,0);
2837   SSVAL(*rparam,4,desc.neededlen);
2838
2839   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2840   return(True);
2841 }
2842
2843
2844 /****************************************************************************
2845   api_WAccessGetUserPerms
2846   ****************************************************************************/
2847 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2848                                     int mdrcnt,int mprcnt,
2849                                     char **rdata,char **rparam,
2850                                     int *rdata_len,int *rparam_len)
2851 {
2852   char *str1 = param+2;
2853   char *str2 = skip_string(str1,1);
2854   char *user = skip_string(str2,1);
2855   char *resource = skip_string(user,1);
2856
2857   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2858
2859   /* check it's a supported varient */
2860   if (strcmp(str1,"zzh") != 0) return False;
2861   if (strcmp(str2,"") != 0) return False;
2862
2863   *rparam_len = 6;
2864   *rparam = REALLOC(*rparam,*rparam_len);
2865   SSVALS(*rparam,0,0);          /* errorcode */
2866   SSVAL(*rparam,2,0);           /* converter word */
2867   SSVAL(*rparam,4,0x7f);        /* permission flags */
2868
2869   return(True);
2870 }
2871
2872 /****************************************************************************
2873   api_WPrintJobEnumerate
2874   ****************************************************************************/
2875 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2876                                  int mdrcnt,int mprcnt,
2877                                  char **rdata,char **rparam,
2878                                  int *rdata_len,int *rparam_len)
2879 {
2880   char *str1 = param+2;
2881   char *str2 = skip_string(str1,1);
2882   char *p = skip_string(str2,1);
2883   int uLevel;
2884   int count;
2885   int i;
2886   int snum;
2887   int job;
2888   struct pack_desc desc;
2889   print_queue_struct *queue=NULL;
2890   print_status_struct status;
2891   char *tmpdata=NULL;
2892
2893   uLevel = SVAL(p,2);
2894
2895   memset((char *)&desc,'\0',sizeof(desc));
2896   memset((char *)&status,'\0',sizeof(status));
2897
2898   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2899
2900   /* check it's a supported varient */
2901   if (strcmp(str1,"WWrLh") != 0) return False;
2902   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2903
2904   job = SVAL(p,0);
2905   snum = print_job_snum(job);
2906
2907   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2908
2909   count = print_queue_status(snum,&queue,&status);
2910   for (i = 0; i < count; i++) {
2911     if (queue[i].job == job) break;
2912   }
2913
2914   if (mdrcnt > 0) {
2915     *rdata = REALLOC(*rdata,mdrcnt);
2916     desc.base = *rdata;
2917     desc.buflen = mdrcnt;
2918   } else {
2919     /*
2920      * Don't return data but need to get correct length
2921      *  init_package will return wrong size if buflen=0
2922      */
2923     desc.buflen = getlen(desc.format);
2924     desc.base = tmpdata = (char *)malloc ( desc.buflen );
2925   }
2926
2927   if (init_package(&desc,1,0)) {
2928     if (i < count) {
2929       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2930       *rdata_len = desc.usedlen;
2931     }
2932     else {
2933       desc.errcode = NERR_JobNotFound;
2934       *rdata_len = 0;
2935     }
2936   }
2937
2938   *rparam_len = 6;
2939   *rparam = REALLOC(*rparam,*rparam_len);
2940   SSVALS(*rparam,0,desc.errcode);
2941   SSVAL(*rparam,2,0);
2942   SSVAL(*rparam,4,desc.neededlen);
2943
2944   SAFE_FREE(queue);
2945   SAFE_FREE(tmpdata);
2946
2947   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2948   return(True);
2949 }
2950
2951 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2952                                    int mdrcnt,int mprcnt,
2953                                    char **rdata,char **rparam,
2954                                    int *rdata_len,int *rparam_len)
2955 {
2956   char *str1 = param+2;
2957   char *str2 = skip_string(str1,1);
2958   char *p = skip_string(str2,1);
2959   char* name = p;
2960   int uLevel;
2961   int count;
2962   int i, succnt=0;
2963   int snum;
2964   struct pack_desc desc;
2965   print_queue_struct *queue=NULL;
2966   print_status_struct status;
2967
2968   memset((char *)&desc,'\0',sizeof(desc));
2969   memset((char *)&status,'\0',sizeof(status));
2970
2971   p = skip_string(p,1);
2972   uLevel = SVAL(p,0);
2973
2974   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2975
2976   /* check it's a supported varient */
2977   if (strcmp(str1,"zWrLeh") != 0) return False;
2978   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2979   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2980
2981   snum = lp_servicenumber(name);
2982   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2983     int pnum = lp_servicenumber(PRINTERS_NAME);
2984     if (pnum >= 0) {
2985       lp_add_printer(name,pnum);
2986       snum = lp_servicenumber(name);
2987     }
2988   }
2989
2990   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2991
2992   count = print_queue_status(snum,&queue,&status);
2993   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2994   desc.base = *rdata;
2995   desc.buflen = mdrcnt;
2996
2997   if (init_package(&desc,count,0)) {
2998     succnt = 0;
2999     for (i = 0; i < count; i++) {
3000       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3001       if (desc.errcode == NERR_Success) succnt = i+1;
3002     }
3003   }
3004
3005   *rdata_len = desc.usedlen;
3006
3007   *rparam_len = 8;
3008   *rparam = REALLOC(*rparam,*rparam_len);
3009   SSVALS(*rparam,0,desc.errcode);
3010   SSVAL(*rparam,2,0);
3011   SSVAL(*rparam,4,succnt);
3012   SSVAL(*rparam,6,count);
3013
3014   SAFE_FREE(queue);
3015
3016   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3017   return(True);
3018 }
3019
3020 static int check_printdest_info(struct pack_desc* desc,
3021                                 int uLevel, char* id)
3022 {
3023   desc->subformat = NULL;
3024   switch( uLevel ) {
3025   case 0: desc->format = "B9"; break;
3026   case 1: desc->format = "B9B21WWzW"; break;
3027   case 2: desc->format = "z"; break;
3028   case 3: desc->format = "zzzWWzzzWW"; break;
3029   default: return False;
3030   }
3031   if (strcmp(desc->format,id) != 0) return False;
3032   return True;
3033 }
3034
3035 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3036                                 struct pack_desc* desc)
3037 {
3038   char buf[100];
3039   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3040   buf[sizeof(buf)-1] = 0;
3041   strupper(buf);
3042   if (uLevel <= 1) {
3043     PACKS(desc,"B9",buf);       /* szName */
3044     if (uLevel == 1) {
3045       PACKS(desc,"B21","");     /* szUserName */
3046       PACKI(desc,"W",0);                /* uJobId */
3047       PACKI(desc,"W",0);                /* fsStatus */
3048       PACKS(desc,"z","");       /* pszStatus */
3049       PACKI(desc,"W",0);                /* time */
3050     }
3051   }
3052   if (uLevel == 2 || uLevel == 3) {
3053     PACKS(desc,"z",buf);                /* pszPrinterName */
3054     if (uLevel == 3) {
3055       PACKS(desc,"z","");       /* pszUserName */
3056       PACKS(desc,"z","");       /* pszLogAddr */
3057       PACKI(desc,"W",0);                /* uJobId */
3058       PACKI(desc,"W",0);                /* fsStatus */
3059       PACKS(desc,"z","");       /* pszStatus */
3060       PACKS(desc,"z","");       /* pszComment */
3061       PACKS(desc,"z","NULL"); /* pszDrivers */
3062       PACKI(desc,"W",0);                /* time */
3063       PACKI(desc,"W",0);                /* pad1 */
3064     }
3065   }
3066 }
3067
3068 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3069                                   int mdrcnt,int mprcnt,
3070                                   char **rdata,char **rparam,
3071                                   int *rdata_len,int *rparam_len)
3072 {
3073   char *str1 = param+2;
3074   char *str2 = skip_string(str1,1);
3075   char *p = skip_string(str2,1);
3076   char* PrinterName = p;
3077   int uLevel;
3078   struct pack_desc desc;
3079   int snum;
3080   char *tmpdata=NULL;
3081
3082   memset((char *)&desc,'\0',sizeof(desc));
3083
3084   p = skip_string(p,1);
3085   uLevel = SVAL(p,0);
3086
3087   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3088
3089   /* check it's a supported varient */
3090   if (strcmp(str1,"zWrLh") != 0) return False;
3091   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3092
3093   snum = lp_servicenumber(PrinterName);
3094   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
3095     int pnum = lp_servicenumber(PRINTERS_NAME);
3096     if (pnum >= 0) {
3097       lp_add_printer(PrinterName,pnum);
3098       snum = lp_servicenumber(PrinterName);
3099     }
3100   }
3101
3102   if (snum < 0) {
3103     *rdata_len = 0;
3104     desc.errcode = NERR_DestNotFound;
3105     desc.neededlen = 0;
3106   }
3107   else {
3108     if (mdrcnt > 0) {
3109       *rdata = REALLOC(*rdata,mdrcnt);
3110       desc.base = *rdata;
3111       desc.buflen = mdrcnt;
3112     } else {
3113       /*
3114        * Don't return data but need to get correct length
3115        *  init_package will return wrong size if buflen=0
3116        */
3117       desc.buflen = getlen(desc.format);
3118       desc.base = tmpdata = (char *)malloc ( desc.buflen );
3119     }
3120     if (init_package(&desc,1,0)) {
3121       fill_printdest_info(conn,snum,uLevel,&desc);
3122     }
3123     *rdata_len = desc.usedlen;
3124   }
3125
3126   *rparam_len = 6;
3127   *rparam = REALLOC(*rparam,*rparam_len);
3128   SSVALS(*rparam,0,desc.errcode);
3129   SSVAL(*rparam,2,0);
3130   SSVAL(*rparam,4,desc.neededlen);
3131
3132   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3133   SAFE_FREE(tmpdata);
3134   return(True);
3135 }
3136
3137 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3138                                int mdrcnt,int mprcnt,
3139                                char **rdata,char **rparam,
3140                                int *rdata_len,int *rparam_len)
3141 {
3142   char *str1 = param+2;
3143   char *str2 = skip_string(str1,1);
3144   char *p = skip_string(str2,1);
3145   int uLevel;
3146   int queuecnt;
3147   int i, n, succnt=0;
3148   struct pack_desc desc;
3149   int services = lp_numservices();
3150
3151   memset((char *)&desc,'\0',sizeof(desc));
3152
3153   uLevel = SVAL(p,0);
3154
3155   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3156
3157   /* check it's a supported varient */
3158   if (strcmp(str1,"WrLeh") != 0) return False;
3159   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3160
3161   queuecnt = 0;
3162   for (i = 0; i < services; i++)
3163     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3164       queuecnt++;
3165
3166   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3167   desc.base = *rdata;
3168   desc.buflen = mdrcnt;
3169   if (init_package(&desc,queuecnt,0)) {    
3170     succnt = 0;
3171     n = 0;
3172     for (i = 0; i < services; i++) {
3173       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3174         fill_printdest_info(conn,i,uLevel,&desc);
3175         n++;
3176         if (desc.errcode == NERR_Success) succnt = n;
3177       }
3178     }
3179   }
3180
3181   *rdata_len = desc.usedlen;
3182
3183   *rparam_len = 8;
3184   *rparam = REALLOC(*rparam,*rparam_len);
3185   SSVALS(*rparam,0,desc.errcode);
3186   SSVAL(*rparam,2,0);
3187   SSVAL(*rparam,4,succnt);
3188   SSVAL(*rparam,6,queuecnt);
3189
3190   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3191   return(True);
3192 }
3193
3194 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3195                                  int mdrcnt,int mprcnt,
3196                                  char **rdata,char **rparam,
3197                                  int *rdata_len,int *rparam_len)
3198 {
3199   char *str1 = param+2;
3200   char *str2 = skip_string(str1,1);
3201   char *p = skip_string(str2,1);
3202   int uLevel;
3203   int succnt;
3204   struct pack_desc desc;
3205
3206   memset((char *)&desc,'\0',sizeof(desc));
3207
3208   uLevel = SVAL(p,0);
3209
3210   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3211
3212   /* check it's a supported varient */
3213   if (strcmp(str1,"WrLeh") != 0) return False;
3214   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3215
3216   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3217   desc.base = *rdata;
3218   desc.buflen = mdrcnt;
3219   if (init_package(&desc,1,0)) {
3220     PACKS(&desc,"B41","NULL");
3221   }
3222
3223   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3224
3225   *rdata_len = desc.usedlen;
3226
3227   *rparam_len = 8;
3228   *rparam = REALLOC(*rparam,*rparam_len);
3229   SSVALS(*rparam,0,desc.errcode);
3230   SSVAL(*rparam,2,0);
3231   SSVAL(*rparam,4,succnt);
3232   SSVAL(*rparam,6,1);
3233
3234   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3235   return(True);
3236 }
3237
3238 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3239                                 int mdrcnt,int mprcnt,
3240                                 char **rdata,char **rparam,
3241                                 int *rdata_len,int *rparam_len)
3242 {
3243   char *str1 = param+2;
3244   char *str2 = skip_string(str1,1);
3245   char *p = skip_string(str2,1);
3246   int uLevel;
3247   int succnt;
3248   struct pack_desc desc;
3249
3250   memset((char *)&desc,'\0',sizeof(desc));
3251
3252   uLevel = SVAL(p,0);
3253
3254   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3255
3256   /* check it's a supported varient */
3257   if (strcmp(str1,"WrLeh") != 0) return False;
3258   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3259
3260   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3261   desc.base = *rdata;
3262   desc.buflen = mdrcnt;
3263   desc.format = str2;
3264   if (init_package(&desc,1,0)) {
3265     PACKS(&desc,"B13","lpd");
3266   }
3267
3268   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3269
3270   *rdata_len = desc.usedlen;
3271
3272   *rparam_len = 8;
3273   *rparam = REALLOC(*rparam,*rparam_len);
3274   SSVALS(*rparam,0,desc.errcode);
3275   SSVAL(*rparam,2,0);
3276   SSVAL(*rparam,4,succnt);
3277   SSVAL(*rparam,6,1);
3278
3279   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3280   return(True);
3281 }
3282
3283 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3284                                int mdrcnt,int mprcnt,
3285                                char **rdata,char **rparam,
3286                                int *rdata_len,int *rparam_len)
3287 {
3288   char *str1 = param+2;
3289   char *str2 = skip_string(str1,1);
3290   char *p = skip_string(str2,1);
3291   int uLevel;
3292   int succnt;
3293   struct pack_desc desc;
3294
3295   memset((char *)&desc,'\0',sizeof(desc));
3296
3297   uLevel = SVAL(p,0);
3298
3299   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3300
3301   /* check it's a supported varient */
3302   if (strcmp(str1,"WrLeh") != 0) return False;
3303   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3304
3305   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3306   memset((char *)&desc,'\0',sizeof(desc));
3307   desc.base = *rdata;
3308   desc.buflen = mdrcnt;
3309   desc.format = str2;
3310   if (init_package(&desc,1,0)) {
3311     PACKS(&desc,"B13","lp0");
3312   }
3313
3314   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3315
3316   *rdata_len = desc.usedlen;
3317
3318   *rparam_len = 8;
3319   *rparam = REALLOC(*rparam,*rparam_len);
3320   SSVALS(*rparam,0,desc.errcode);
3321   SSVAL(*rparam,2,0);
3322   SSVAL(*rparam,4,succnt);
3323   SSVAL(*rparam,6,1);
3324
3325   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3326   return(True);
3327 }
3328
3329 /****************************************************************************
3330  The buffer was too small
3331  ****************************************************************************/
3332
3333 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3334                          int mdrcnt,int mprcnt,
3335                          char **rdata,char **rparam,
3336                          int *rdata_len,int *rparam_len)
3337 {
3338   *rparam_len = MIN(*rparam_len,mprcnt);
3339   *rparam = REALLOC(*rparam,*rparam_len);
3340
3341   *rdata_len = 0;
3342
3343   SSVAL(*rparam,0,NERR_BufTooSmall);
3344
3345   DEBUG(3,("Supplied buffer too small in API command\n"));
3346
3347   return(True);
3348 }
3349
3350
3351 /****************************************************************************
3352  The request is not supported
3353  ****************************************************************************/
3354
3355 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3356                             int mdrcnt,int mprcnt,
3357                             char **rdata,char **rparam,
3358                             int *rdata_len,int *rparam_len)
3359 {
3360   *rparam_len = 4;
3361   *rparam = REALLOC(*rparam,*rparam_len);
3362
3363   *rdata_len = 0;
3364
3365   SSVAL(*rparam,0,NERR_notsupported);
3366   SSVAL(*rparam,2,0);           /* converter word */
3367
3368   DEBUG(3,("Unsupported API command\n"));
3369
3370   return(True);
3371 }
3372
3373
3374
3375
3376 struct
3377 {
3378   char *name;
3379   int id;
3380   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3381              int,int,char **,char **,int *,int *);
3382   int flags;
3383 } api_commands[] = {
3384   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3385   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3386   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3387   {"RNetGroupEnum",     47,     api_RNetGroupEnum,0},
3388   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3389   {"RNetUserEnum",      53,     api_RNetUserEnum,0},
3390   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3391   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3392   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3393   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3394   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3395   {"WPrintQueuePause",  74, api_WPrintQueueCtrl,0},
3396   {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3397   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3398   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3399   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3400   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3401   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3402   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3403   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3404   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3405   {"WPrintQueuePurge",  103,    api_WPrintQueueCtrl,0},
3406   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3407   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3408   {"SetUserPassword",   115,    api_SetUserPassword,0},
3409   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3410   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3411   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3412   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3413   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3414   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3415   {NULL,                -1,     api_Unsupported,0}};
3416
3417
3418 /****************************************************************************
3419  Handle remote api calls
3420  ****************************************************************************/
3421
3422 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3423                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3424 {
3425   int api_command;
3426   char *rdata = NULL;
3427   char *rparam = NULL;
3428   int rdata_len = 0;
3429   int rparam_len = 0;
3430   BOOL reply=False;
3431   int i;
3432
3433   if (!params) {
3434           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3435           return 0;
3436   }
3437
3438   api_command = SVAL(params,0);
3439
3440   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3441            api_command,
3442            params+2,
3443            skip_string(params+2,1),
3444            tdscnt,tpscnt,mdrcnt,mprcnt));
3445
3446   for (i=0;api_commands[i].name;i++) {
3447     if (api_commands[i].id == api_command && api_commands[i].fn) {
3448         DEBUG(3,("Doing %s\n",api_commands[i].name));
3449         break;
3450     }
3451   }
3452
3453   rdata = (char *)malloc(1024);
3454   if (rdata)
3455     memset(rdata,'\0',1024);
3456
3457   rparam = (char *)malloc(1024);
3458   if (rparam)
3459     memset(rparam,'\0',1024);
3460
3461   if(!rdata || !rparam) {
3462     DEBUG(0,("api_reply: malloc fail !\n"));
3463     return -1;
3464   }
3465
3466   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3467                              &rdata,&rparam,&rdata_len,&rparam_len);
3468
3469
3470   if (rdata_len > mdrcnt ||
3471       rparam_len > mprcnt) {
3472       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3473                            &rdata,&rparam,&rdata_len,&rparam_len);
3474   }
3475
3476   /* if we get False back then it's actually unsupported */
3477   if (!reply)
3478     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3479                     &rdata,&rparam,&rdata_len,&rparam_len);
3480
3481   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3482
3483   SAFE_FREE(rdata);
3484   SAFE_FREE(rparam);
3485   
3486   return -1;
3487 }