strchr and strrchr are macros when compiling with optimisation in gcc, so we can...
[ira/wip.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,'%'))) *p = 0;
870  
871   DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
872  
873   /* check it's a supported varient */
874   if (!prefix_ok(str1,"zWrLh")) return False;
875   if (!check_printq_info(&desc,uLevel,str2,str3)) {
876     /*
877      * Patch from Scott Moomaw <scott@bridgewater.edu>
878      * to return the 'invalid info level' error if an
879      * unknown level was requested.
880      */
881     *rdata_len = 0;
882     *rparam_len = 6;
883     *rparam = REALLOC(*rparam,*rparam_len);
884     SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
885     SSVAL(*rparam,2,0);
886     SSVAL(*rparam,4,0);
887     return(True);
888   }
889  
890   snum = lp_servicenumber(QueueName);
891   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
892     int pnum = lp_servicenumber(PRINTERS_NAME);
893     if (pnum >= 0) {
894       lp_add_printer(QueueName,pnum);
895       snum = lp_servicenumber(QueueName);
896     }
897   }
898   
899   if (snum < 0 || !VALID_SNUM(snum)) return(False);
900
901   if (uLevel==52) {
902           count = get_printerdrivernumber(snum);
903           DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
904   } else {
905           count = print_queue_status(snum, &queue,&status);
906   }
907
908   if (mdrcnt > 0) {
909     *rdata = REALLOC(*rdata,mdrcnt);
910     desc.base = *rdata;
911     desc.buflen = mdrcnt;
912   } else {
913     /*
914      * Don't return data but need to get correct length
915      *  init_package will return wrong size if buflen=0
916      */
917      desc.buflen = getlen(desc.format);
918      desc.base = tmpdata = (char *) malloc (desc.buflen);
919   }
920
921   if (init_package(&desc,1,count)) {
922           desc.subcount = count;
923           fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
924   } else if(uLevel == 0) {
925 #if 0
926         /*
927          * This is a *disgusting* hack.
928          * This is *so* bad that even I'm embarrassed (and I
929          * have no shame). Here's the deal :
930          * Until we get the correct SPOOLSS code into smbd
931          * then when we're running with NT SMB support then
932          * NT makes this call with a level of zero, and then
933          * immediately follows it with an open request to
934          * the \\SRVSVC pipe. If we allow that open to
935          * succeed then NT barfs when it cannot open the
936          * \\SPOOLSS pipe immediately after and continually
937          * whines saying "Printer name is invalid" forever
938          * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
939          * to fail, then NT downgrades to using the downlevel code
940          * and everything works as well as before. I hate
941          * myself for adding this code.... JRA.
942          */
943
944         fail_next_srvsvc_open();
945 #endif
946   }
947
948   *rdata_len = desc.usedlen;
949   
950   *rparam_len = 6;
951   *rparam = REALLOC(*rparam,*rparam_len);
952   SSVALS(*rparam,0,desc.errcode);
953   SSVAL(*rparam,2,0);
954   SSVAL(*rparam,4,desc.neededlen);
955   
956   DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
957
958   if (queue) free(queue);
959   if (tmpdata) free (tmpdata);
960
961   return(True);
962 }
963
964 /****************************************************************************
965  View list of all print jobs on all queues.
966 ****************************************************************************/
967
968 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
969                               int mdrcnt, int mprcnt,
970                               char **rdata, char** rparam,
971                               int *rdata_len, int *rparam_len)
972 {
973   char *param_format = param+2;
974   char *output_format1 = skip_string(param_format,1);
975   char *p = skip_string(output_format1,1);
976   int uLevel = SVAL(p,0);
977   char *output_format2 = p + 4;
978   int services = lp_numservices();
979   int i, n;
980   struct pack_desc desc;
981   print_queue_struct **queue = NULL;
982   print_status_struct *status = NULL;
983   int* subcntarr = NULL;
984   int queuecnt, subcnt=0, succnt=0;
985  
986   memset((char *)&desc,'\0',sizeof(desc));
987
988   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
989  
990   if (!prefix_ok(param_format,"WrLeh")) return False;
991   if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
992     /*
993      * Patch from Scott Moomaw <scott@bridgewater.edu>
994      * to return the 'invalid info level' error if an
995      * unknown level was requested.
996      */
997     *rdata_len = 0;
998     *rparam_len = 6;
999     *rparam = REALLOC(*rparam,*rparam_len);
1000     SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
1001     SSVAL(*rparam,2,0);
1002     SSVAL(*rparam,4,0);
1003     return(True);
1004   }
1005
1006   queuecnt = 0;
1007   for (i = 0; i < services; i++)
1008     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1009       queuecnt++;
1010   if (uLevel > 0) {
1011     if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1012       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1013       return False;
1014     }
1015     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1016     if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1017       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1018       return False;
1019     }
1020     memset(status,0,queuecnt*sizeof(print_status_struct));
1021     if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1022       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1023       return False;
1024     }
1025     subcnt = 0;
1026     n = 0;
1027     for (i = 0; i < services; i++)
1028       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1029         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1030         subcnt += subcntarr[n];
1031         n++;
1032       }
1033   }
1034   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1035   desc.base = *rdata;
1036   desc.buflen = mdrcnt;
1037
1038   if (init_package(&desc,queuecnt,subcnt)) {
1039     n = 0;
1040     succnt = 0;
1041     for (i = 0; i < services; i++)
1042       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1043         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1044         n++;
1045         if (desc.errcode == NERR_Success) succnt = n;
1046       }
1047   }
1048
1049   if (subcntarr) free(subcntarr);
1050  
1051   *rdata_len = desc.usedlen;
1052   *rparam_len = 8;
1053   *rparam = REALLOC(*rparam,*rparam_len);
1054   SSVALS(*rparam,0,desc.errcode);
1055   SSVAL(*rparam,2,0);
1056   SSVAL(*rparam,4,succnt);
1057   SSVAL(*rparam,6,queuecnt);
1058   
1059   for (i = 0; i < queuecnt; i++) {
1060     if (queue && queue[i]) free(queue[i]);
1061   }
1062
1063   if (queue) free(queue);
1064   if (status) free(status);
1065   
1066   return True;
1067 }
1068
1069 /****************************************************************************
1070   get info level for a server list query
1071   ****************************************************************************/
1072 static BOOL check_server_info(int uLevel, char* id)
1073 {
1074   switch( uLevel ) {
1075   case 0:
1076     if (strcmp(id,"B16") != 0) return False;
1077     break;
1078   case 1:
1079     if (strcmp(id,"B16BBDz") != 0) return False;
1080     break;
1081   default: 
1082     return False;
1083   }
1084   return True;
1085 }
1086
1087 struct srv_info_struct
1088 {
1089   fstring name;
1090   uint32 type;
1091   fstring comment;
1092   fstring domain;
1093   BOOL server_added;
1094 };
1095
1096
1097 /*******************************************************************
1098   get server info lists from the files saved by nmbd. Return the
1099   number of entries
1100   ******************************************************************/
1101 static int get_server_info(uint32 servertype, 
1102                            struct srv_info_struct **servers,
1103                            char *domain)
1104 {
1105   int count=0;
1106   int alloced=0;
1107   char **lines;
1108   BOOL local_list_only;
1109   int i;
1110
1111   lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1112   if (!lines) {
1113     DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1114     return(0);
1115   }
1116
1117   /* request for everything is code for request all servers */
1118   if (servertype == SV_TYPE_ALL) 
1119         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1120
1121   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1122
1123   DEBUG(4,("Servertype search: %8x\n",servertype));
1124
1125   for (i=0;lines[i];i++) {
1126     fstring stype;
1127     struct srv_info_struct *s;
1128     char *ptr = lines[i];
1129     BOOL ok = True;
1130
1131     if (!*ptr) continue;
1132     
1133     if (count == alloced) {
1134       alloced += 10;
1135       (*servers) = (struct srv_info_struct *)
1136         Realloc(*servers,sizeof(**servers)*alloced);
1137       if (!(*servers)) return(0);
1138       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1139     }
1140     s = &(*servers)[count];
1141     
1142     if (!next_token(&ptr,s->name   , NULL, sizeof(s->name))) continue;
1143     if (!next_token(&ptr,stype     , NULL, sizeof(stype))) continue;
1144     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1145     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1146       /* this allows us to cope with an old nmbd */
1147       pstrcpy(s->domain,global_myworkgroup); 
1148     }
1149     
1150     if (sscanf(stype,"%X",&s->type) != 1) { 
1151       DEBUG(4,("r:host file ")); 
1152       ok = False; 
1153     }
1154     
1155         /* Filter the servers/domains we return based on what was asked for. */
1156
1157         /* Check to see if we are being asked for a local list only. */
1158         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1159           DEBUG(4,("r: local list only"));
1160           ok = False;
1161         }
1162
1163     /* doesn't match up: don't want it */
1164     if (!(servertype & s->type)) { 
1165       DEBUG(4,("r:serv type ")); 
1166       ok = False; 
1167     }
1168     
1169     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1170         (s->type & SV_TYPE_DOMAIN_ENUM))
1171       {
1172         DEBUG(4,("s: dom mismatch "));
1173         ok = False;
1174       }
1175     
1176     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1177       {
1178         ok = False;
1179       }
1180     
1181         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1182         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1183
1184     if (ok)
1185       {
1186         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1187                  s->name, s->type, s->comment, s->domain));
1188         
1189         s->server_added = True;
1190         count++;
1191       }
1192     else
1193       {
1194         DEBUG(4,("%20s %8x %25s %15s\n",
1195                  s->name, s->type, s->comment, s->domain));
1196       }
1197   }
1198   
1199   file_lines_free(lines);
1200   return(count);
1201 }
1202
1203
1204 /*******************************************************************
1205   fill in a server info structure
1206   ******************************************************************/
1207 static int fill_srv_info(struct srv_info_struct *service, 
1208                          int uLevel, char **buf, int *buflen, 
1209                          char **stringbuf, int *stringspace, char *baseaddr)
1210 {
1211   int struct_len;
1212   char* p;
1213   char* p2;
1214   int l2;
1215   int len;
1216  
1217   switch (uLevel) {
1218   case 0: struct_len = 16; break;
1219   case 1: struct_len = 26; break;
1220   default: return -1;
1221   }  
1222  
1223   if (!buf)
1224     {
1225       len = 0;
1226       switch (uLevel) 
1227         {
1228         case 1:
1229           len = strlen(service->comment)+1;
1230           break;
1231         }
1232
1233       if (buflen) *buflen = struct_len;
1234       if (stringspace) *stringspace = len;
1235       return struct_len + len;
1236     }
1237   
1238   len = struct_len;
1239   p = *buf;
1240   if (*buflen < struct_len) return -1;
1241   if (stringbuf)
1242     {
1243       p2 = *stringbuf;
1244       l2 = *stringspace;
1245     }
1246   else
1247     {
1248       p2 = p + struct_len;
1249       l2 = *buflen - struct_len;
1250     }
1251   if (!baseaddr) baseaddr = p;
1252   
1253   switch (uLevel)
1254     {
1255     case 0:
1256             push_ascii(p,service->name, 15, STR_TERMINATE);
1257             break;
1258
1259     case 1:
1260             push_ascii(p,service->name,15, STR_TERMINATE);
1261             SIVAL(p,18,service->type);
1262             SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1263             len += CopyAndAdvance(&p2,service->comment,&l2);
1264             break;
1265     }
1266
1267   if (stringbuf)
1268     {
1269       *buf = p + struct_len;
1270       *buflen -= struct_len;
1271       *stringbuf = p2;
1272       *stringspace = l2;
1273     }
1274   else
1275     {
1276       *buf = p2;
1277       *buflen -= len;
1278     }
1279   return len;
1280 }
1281
1282
1283 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1284 {
1285   return(strcmp(s1->name,s2->name));
1286 }
1287
1288 /****************************************************************************
1289   view list of servers available (or possibly domains). The info is
1290   extracted from lists saved by nmbd on the local host
1291   ****************************************************************************/
1292 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1293                                int mdrcnt, int mprcnt, char **rdata, 
1294                                char **rparam, int *rdata_len, int *rparam_len)
1295 {
1296   char *str1 = param+2;
1297   char *str2 = skip_string(str1,1);
1298   char *p = skip_string(str2,1);
1299   int uLevel = SVAL(p,0);
1300   int buf_len = SVAL(p,2);
1301   uint32 servertype = IVAL(p,4);
1302   char *p2;
1303   int data_len, fixed_len, string_len;
1304   int f_len = 0, s_len = 0;
1305   struct srv_info_struct *servers=NULL;
1306   int counted=0,total=0;
1307   int i,missed;
1308   fstring domain;
1309   BOOL domain_request;
1310   BOOL local_request;
1311
1312   /* If someone sets all the bits they don't really mean to set
1313      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1314      known servers. */
1315
1316   if (servertype == SV_TYPE_ALL) 
1317     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1318
1319   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1320      any other bit (they may just set this bit on it's own) they 
1321      want all the locally seen servers. However this bit can be 
1322      set on its own so set the requested servers to be 
1323      ALL - DOMAIN_ENUM. */
1324
1325   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1326     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1327
1328   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1329   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1330
1331   p += 8;
1332
1333   if (!prefix_ok(str1,"WrLehD")) return False;
1334   if (!check_server_info(uLevel,str2)) return False;
1335   
1336   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1337   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1338   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1339
1340   if (strcmp(str1, "WrLehDz") == 0) {
1341           pull_ascii_fstring(domain, p);
1342   } else {
1343           fstrcpy(domain, global_myworkgroup);
1344   }
1345
1346   if (lp_browse_list())
1347     total = get_server_info(servertype,&servers,domain);
1348
1349   data_len = fixed_len = string_len = 0;
1350   missed = 0;
1351
1352   if (total > 0)
1353     qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1354
1355   {
1356     char *lastname=NULL;
1357
1358     for (i=0;i<total;i++)
1359     {
1360       struct srv_info_struct *s = &servers[i];
1361       if (lastname && strequal(lastname,s->name)) continue;
1362       lastname = s->name;
1363       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1364       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1365                s->name, s->type, s->comment, s->domain));
1366       
1367       if (data_len <= buf_len) {
1368           counted++;
1369           fixed_len += f_len;
1370           string_len += s_len;
1371       } else {
1372         missed++;
1373       }
1374     }
1375   }
1376
1377   *rdata_len = fixed_len + string_len;
1378   *rdata = REALLOC(*rdata,*rdata_len);
1379   memset(*rdata,'\0',*rdata_len);
1380   
1381   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1382   p = *rdata;
1383   f_len = fixed_len;
1384   s_len = string_len;
1385
1386   {
1387     char *lastname=NULL;
1388     int count2 = counted;
1389     for (i = 0; i < total && count2;i++)
1390       {
1391         struct srv_info_struct *s = &servers[i];
1392         if (lastname && strequal(lastname,s->name)) continue;
1393         lastname = s->name;
1394         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1395         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1396                  s->name, s->type, s->comment, s->domain));
1397         count2--;
1398       }
1399   }
1400   
1401   *rparam_len = 8;
1402   *rparam = REALLOC(*rparam,*rparam_len);
1403   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1404   SSVAL(*rparam,2,0);
1405   SSVAL(*rparam,4,counted);
1406   SSVAL(*rparam,6,counted+missed);
1407
1408   if (servers) free(servers);
1409
1410   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1411            domain,uLevel,counted,counted+missed));
1412
1413   return(True);
1414 }
1415
1416 /****************************************************************************
1417   command 0x34 - suspected of being a "Lookup Names" stub api
1418   ****************************************************************************/
1419 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1420                                int mdrcnt, int mprcnt, char **rdata, 
1421                                char **rparam, int *rdata_len, int *rparam_len)
1422 {
1423   char *str1 = param+2;
1424   char *str2 = skip_string(str1,1);
1425   char *p = skip_string(str2,1);
1426   int uLevel = SVAL(p,0);
1427   int buf_len = SVAL(p,2);
1428   int counted=0;
1429   int missed=0;
1430
1431         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1432                 str1, str2, p, uLevel, buf_len));
1433
1434   if (!prefix_ok(str1,"zWrLeh")) return False;
1435   
1436   *rdata_len = 0;
1437   
1438   *rparam_len = 8;
1439   *rparam = REALLOC(*rparam,*rparam_len);
1440
1441   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1442   SSVAL(*rparam,2,0);
1443   SSVAL(*rparam,4,counted);
1444   SSVAL(*rparam,6,counted+missed);
1445
1446   return(True);
1447 }
1448
1449 /****************************************************************************
1450   get info about a share
1451   ****************************************************************************/
1452 static BOOL check_share_info(int uLevel, char* id)
1453 {
1454   switch( uLevel ) {
1455   case 0:
1456     if (strcmp(id,"B13") != 0) return False;
1457     break;
1458   case 1:
1459     if (strcmp(id,"B13BWz") != 0) return False;
1460     break;
1461   case 2:
1462     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1463     break;
1464   case 91:
1465     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1466     break;
1467   default: return False;
1468   }
1469   return True;
1470 }
1471
1472 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1473                            char** buf, int* buflen,
1474                            char** stringbuf, int* stringspace, char* baseaddr)
1475 {
1476   int struct_len;
1477   char* p;
1478   char* p2;
1479   int l2;
1480   int len;
1481  
1482   switch( uLevel ) {
1483   case 0: struct_len = 13; break;
1484   case 1: struct_len = 20; break;
1485   case 2: struct_len = 40; break;
1486   case 91: struct_len = 68; break;
1487   default: return -1;
1488   }
1489   
1490  
1491   if (!buf)
1492     {
1493       len = 0;
1494       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1495       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1496       if (buflen) *buflen = struct_len;
1497       if (stringspace) *stringspace = len;
1498       return struct_len + len;
1499     }
1500   
1501   len = struct_len;
1502   p = *buf;
1503   if ((*buflen) < struct_len) return -1;
1504   if (stringbuf)
1505     {
1506       p2 = *stringbuf;
1507       l2 = *stringspace;
1508     }
1509   else
1510     {
1511       p2 = p + struct_len;
1512       l2 = (*buflen) - struct_len;
1513     }
1514   if (!baseaddr) baseaddr = p;
1515   
1516   push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1517   
1518   if (uLevel > 0)
1519     {
1520       int type;
1521       CVAL(p,13) = 0;
1522       type = STYPE_DISKTREE;
1523       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1524       if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
1525       SSVAL(p,14,type);         /* device type */
1526       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1527       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1528     }
1529   
1530   if (uLevel > 1)
1531     {
1532       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1533       SSVALS(p,22,-1);          /* max uses */
1534       SSVAL(p,24,1); /* current uses */
1535       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1536       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1537       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1538     }
1539   
1540   if (uLevel > 2)
1541     {
1542       memset(p+40,0,SHPWLEN+2);
1543       SSVAL(p,50,0);
1544       SIVAL(p,52,0);
1545       SSVAL(p,56,0);
1546       SSVAL(p,58,0);
1547       SIVAL(p,60,0);
1548       SSVAL(p,64,0);
1549       SSVAL(p,66,0);
1550     }
1551        
1552   if (stringbuf)
1553     {
1554       (*buf) = p + struct_len;
1555       (*buflen) -= struct_len;
1556       (*stringbuf) = p2;
1557       (*stringspace) = l2;
1558     }
1559   else
1560     {
1561       (*buf) = p2;
1562       (*buflen) -= len;
1563     }
1564   return len;
1565 }
1566
1567 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1568                                  int mdrcnt,int mprcnt,
1569                                  char **rdata,char **rparam,
1570                                  int *rdata_len,int *rparam_len)
1571 {
1572   char *str1 = param+2;
1573   char *str2 = skip_string(str1,1);
1574   char *netname = skip_string(str2,1);
1575   char *p = skip_string(netname,1);
1576   int uLevel = SVAL(p,0);
1577   int snum = find_service(netname);
1578   
1579   if (snum < 0) return False;
1580   
1581   /* check it's a supported varient */
1582   if (!prefix_ok(str1,"zWrLh")) return False;
1583   if (!check_share_info(uLevel,str2)) return False;
1584  
1585   *rdata = REALLOC(*rdata,mdrcnt);
1586   p = *rdata;
1587   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1588   if (*rdata_len < 0) return False;
1589  
1590   *rparam_len = 6;
1591   *rparam = REALLOC(*rparam,*rparam_len);
1592   SSVAL(*rparam,0,NERR_Success);
1593   SSVAL(*rparam,2,0);           /* converter word */
1594   SSVAL(*rparam,4,*rdata_len);
1595  
1596   return(True);
1597 }
1598
1599 /****************************************************************************
1600   view list of shares available
1601   ****************************************************************************/
1602 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1603                               int mdrcnt,int mprcnt,
1604                               char **rdata,char **rparam,
1605                               int *rdata_len,int *rparam_len)
1606 {
1607   char *str1 = param+2;
1608   char *str2 = skip_string(str1,1);
1609   char *p = skip_string(str2,1);
1610   int uLevel = SVAL(p,0);
1611   int buf_len = SVAL(p,2);
1612   char *p2;
1613   int count=lp_numservices();
1614   int total=0,counted=0;
1615   BOOL missed = False;
1616   int i;
1617   int data_len, fixed_len, string_len;
1618   int f_len = 0, s_len = 0;
1619  
1620   if (!prefix_ok(str1,"WrLeh")) return False;
1621   if (!check_share_info(uLevel,str2)) return False;
1622   
1623   data_len = fixed_len = string_len = 0;
1624   for (i=0;i<count;i++)
1625     if (lp_browseable(i) && lp_snum_ok(i))
1626     {
1627       total++;
1628       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1629       if (data_len <= buf_len)
1630       {
1631         counted++;
1632         fixed_len += f_len;
1633         string_len += s_len;
1634       }
1635       else
1636         missed = True;
1637     }
1638   *rdata_len = fixed_len + string_len;
1639   *rdata = REALLOC(*rdata,*rdata_len);
1640   memset(*rdata,0,*rdata_len);
1641   
1642   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1643   p = *rdata;
1644   f_len = fixed_len;
1645   s_len = string_len;
1646   for (i = 0; i < count;i++)
1647     if (lp_browseable(i) && lp_snum_ok(i))
1648       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1649         break;
1650   
1651   *rparam_len = 8;
1652   *rparam = REALLOC(*rparam,*rparam_len);
1653   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1654   SSVAL(*rparam,2,0);
1655   SSVAL(*rparam,4,counted);
1656   SSVAL(*rparam,6,total);
1657   
1658   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1659            counted,total,uLevel,
1660            buf_len,*rdata_len,mdrcnt));
1661   return(True);
1662 }
1663
1664
1665
1666 /****************************************************************************
1667   get the time of day info
1668   ****************************************************************************/
1669 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1670                              int mdrcnt,int mprcnt,
1671                              char **rdata,char **rparam,
1672                              int *rdata_len,int *rparam_len)
1673 {
1674   char *p;
1675   *rparam_len = 4;
1676   *rparam = REALLOC(*rparam,*rparam_len);
1677
1678   *rdata_len = 21;
1679   *rdata = REALLOC(*rdata,*rdata_len);
1680
1681   SSVAL(*rparam,0,NERR_Success);
1682   SSVAL(*rparam,2,0);           /* converter word */
1683
1684   p = *rdata;
1685
1686   {
1687     struct tm *t;
1688     time_t unixdate = time(NULL);
1689
1690     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1691                                     by NT in a "net time" operation,
1692                                     it seems to ignore the one below */
1693
1694     /* the client expects to get localtime, not GMT, in this bit 
1695        (I think, this needs testing) */
1696     t = LocalTime(&unixdate);
1697
1698     SIVAL(p,4,0);               /* msecs ? */
1699     CVAL(p,8) = t->tm_hour;
1700     CVAL(p,9) = t->tm_min;
1701     CVAL(p,10) = t->tm_sec;
1702     CVAL(p,11) = 0;             /* hundredths of seconds */
1703     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1704     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1705     CVAL(p,16) = t->tm_mday;
1706     CVAL(p,17) = t->tm_mon + 1;
1707     SSVAL(p,18,1900+t->tm_year);
1708     CVAL(p,20) = t->tm_wday;
1709   }
1710
1711
1712   return(True);
1713 }
1714
1715 /****************************************************************************
1716  Set the user password.
1717 *****************************************************************************/
1718
1719 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1720                                 int mdrcnt,int mprcnt,
1721                                 char **rdata,char **rparam,
1722                                 int *rdata_len,int *rparam_len)
1723 {
1724   char *p = skip_string(param+2,2);
1725   fstring user;
1726   fstring pass1,pass2;
1727
1728   pull_ascii_fstring(user,p);
1729
1730   p = skip_string(p,1);
1731
1732   memset(pass1,'\0',sizeof(pass1));
1733   memset(pass2,'\0',sizeof(pass2));
1734   memcpy(pass1,p,16);
1735   memcpy(pass2,p+16,16);
1736
1737   *rparam_len = 4;
1738   *rparam = REALLOC(*rparam,*rparam_len);
1739
1740   *rdata_len = 0;
1741
1742   SSVAL(*rparam,0,NERR_badpass);
1743   SSVAL(*rparam,2,0);           /* converter word */
1744
1745   DEBUG(3,("Set password for <%s>\n",user));
1746
1747   /*
1748    * Pass the user through the NT -> unix user mapping
1749    * function.
1750    */
1751
1752   (void)map_username(user);
1753
1754   /*
1755    * Do any UNIX username case mangling.
1756    */
1757   (void)Get_Pwnam( user, True);
1758
1759   /*
1760    * Attempt to verify the old password against smbpasswd entries
1761    * Win98 clients send old and new password in plaintext for this call.
1762    */
1763
1764   {
1765     fstring saved_pass2;
1766     SAM_ACCOUNT *sampass=NULL;
1767
1768     /*
1769      * Save the new password as change_oem_password overwrites it
1770      * with zeros.
1771      */
1772
1773     fstrcpy(saved_pass2, pass2);
1774
1775     if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1776         change_oem_password(sampass,pass2,False))
1777     {
1778       SSVAL(*rparam,0,NERR_Success);
1779
1780       /*
1781        * If unix password sync was requested, attempt to change
1782        * the /etc/passwd database also. Return failure if this cannot
1783        * be done.
1784        */
1785
1786       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1787         SSVAL(*rparam,0,NERR_badpass);
1788     }
1789         pdb_free_sam(sampass);
1790  }
1791   
1792
1793   /*
1794    * If the above failed, attempt the plaintext password change.
1795    * This tests against the /etc/passwd database only.
1796    */
1797
1798   if(SVAL(*rparam,0) != NERR_Success)
1799   {
1800     if (password_ok(user, pass1,strlen(pass1),NULL) &&
1801         chgpasswd(user,pass1,pass2,False))
1802     {
1803       SSVAL(*rparam,0,NERR_Success);
1804     }
1805   }
1806
1807   /*
1808    * If the plaintext change failed, attempt
1809    * the old encrypted method. NT will generate this
1810    * after trying the samr method. Note that this
1811    * method is done as a last resort as this
1812    * password change method loses the NT password hash
1813    * and cannot change the UNIX password as no plaintext
1814    * is received.
1815    */
1816
1817   if(SVAL(*rparam,0) != NERR_Success)
1818   {
1819     SAM_ACCOUNT *hnd = NULL;
1820
1821     if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
1822        change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1823     {
1824       SSVAL(*rparam,0,NERR_Success);
1825     }
1826         pdb_free_sam(hnd);
1827   }
1828
1829
1830   memset((char *)pass1,'\0',sizeof(fstring));
1831   memset((char *)pass2,'\0',sizeof(fstring));    
1832          
1833   return(True);
1834 }
1835
1836 /****************************************************************************
1837   Set the user password (SamOEM version - gets plaintext).
1838 ****************************************************************************/
1839
1840 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1841                                 int mdrcnt,int mprcnt,
1842                                 char **rdata,char **rparam,
1843                                 int *rdata_len,int *rparam_len)
1844 {
1845   fstring user;
1846   char *p = param + 2;
1847   *rparam_len = 2;
1848   *rparam = REALLOC(*rparam,*rparam_len);
1849
1850   *rdata_len = 0;
1851
1852   SSVAL(*rparam,0,NERR_badpass);
1853
1854   /*
1855    * Check the parameter definition is correct.
1856    */
1857   if(!strequal(param + 2, "zsT")) {
1858     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1859     return False;
1860   }
1861   p = skip_string(p, 1);
1862
1863   if(!strequal(p, "B516B16")) {
1864     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1865     return False;
1866   }
1867   p = skip_string(p,1);
1868
1869   p += pull_ascii_fstring(user,p);
1870
1871   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1872
1873   /*
1874    * Pass the user through the NT -> unix user mapping
1875    * function.
1876    */
1877
1878   (void)map_username(user);
1879
1880   /*
1881    * Do any UNIX username case mangling.
1882    */
1883   (void)Get_Pwnam( user, True);
1884
1885   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1886   {
1887     SSVAL(*rparam,0,NERR_Success);
1888   }
1889
1890   return(True);
1891 }
1892
1893 /****************************************************************************
1894   delete a print job
1895   Form: <W> <> 
1896   ****************************************************************************/
1897 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1898                                 int mdrcnt,int mprcnt,
1899                                 char **rdata,char **rparam,
1900                                 int *rdata_len,int *rparam_len)
1901 {
1902         int function = SVAL(param,0);
1903         char *str1 = param+2;
1904         char *str2 = skip_string(str1,1);
1905         char *p = skip_string(str2,1);
1906         int jobid, errcode;
1907         extern struct current_user current_user;
1908
1909         jobid = SVAL(p,0);
1910
1911         /* check it's a supported varient */
1912         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1913                 return(False);
1914
1915         *rparam_len = 4;
1916         *rparam = REALLOC(*rparam,*rparam_len); 
1917         *rdata_len = 0;
1918
1919         if (!print_job_exists(jobid)) {
1920                 errcode = NERR_JobNotFound;
1921                 goto out;
1922         }
1923
1924         errcode = NERR_notsupported;
1925         
1926         switch (function) {
1927         case 81:                /* delete */ 
1928                 if (print_job_delete(&current_user, jobid, &errcode)) 
1929                         errcode = NERR_Success;
1930                 break;
1931         case 82:                /* pause */
1932                 if (print_job_pause(&current_user, jobid, &errcode)) 
1933                         errcode = NERR_Success;
1934                 break;
1935         case 83:                /* resume */
1936                 if (print_job_resume(&current_user, jobid, &errcode)) 
1937                         errcode = NERR_Success;
1938                 break;
1939         }
1940         
1941  out:
1942         SSVAL(*rparam,0,errcode);       
1943         SSVAL(*rparam,2,0);             /* converter word */
1944
1945         return(True);
1946 }
1947
1948 /****************************************************************************
1949   Purge a print queue - or pause or resume it.
1950   ****************************************************************************/
1951 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1952                                  int mdrcnt,int mprcnt,
1953                                  char **rdata,char **rparam,
1954                                  int *rdata_len,int *rparam_len)
1955 {
1956         int function = SVAL(param,0);
1957         char *str1 = param+2;
1958         char *str2 = skip_string(str1,1);
1959         char *QueueName = skip_string(str2,1);
1960         int errcode = NERR_notsupported;
1961         int snum;
1962         extern struct current_user current_user;
1963
1964         /* check it's a supported varient */
1965         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1966                 return(False);
1967
1968         *rparam_len = 4;
1969         *rparam = REALLOC(*rparam,*rparam_len);
1970         *rdata_len = 0;
1971
1972         snum = print_queue_snum(QueueName);
1973
1974         if (snum == -1) {
1975                 errcode = NERR_JobNotFound;
1976                 goto out;
1977         }
1978
1979         switch (function) {
1980         case 74: /* Pause queue */
1981                 if (print_queue_pause(&current_user, snum, &errcode)) errcode = NERR_Success;
1982                 break;
1983         case 75: /* Resume queue */
1984                 if (print_queue_resume(&current_user, snum, &errcode)) errcode = NERR_Success;
1985                 break;
1986         case 103: /* Purge */
1987                 if (print_queue_purge(&current_user, snum, &errcode)) errcode = NERR_Success;
1988                 break;
1989         }
1990
1991  out:
1992         SSVAL(*rparam,0,errcode);
1993         SSVAL(*rparam,2,0);             /* converter word */
1994
1995         return(True);
1996 }
1997
1998
1999 /****************************************************************************
2000   set the property of a print job (undocumented?)
2001   ? function = 0xb -> set name of print job
2002   ? function = 0x6 -> move print job up/down
2003   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2004   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2005 ****************************************************************************/
2006 static int check_printjob_info(struct pack_desc* desc,
2007                                int uLevel, char* id)
2008 {
2009         desc->subformat = NULL;
2010         switch( uLevel ) {
2011         case 0: desc->format = "W"; break;
2012         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2013         case 2: desc->format = "WWzWWDDzz"; break;
2014         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2015         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2016         default: return False;
2017         }
2018         if (strcmp(desc->format,id) != 0) return False;
2019         return True;
2020 }
2021
2022 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2023                              int mdrcnt,int mprcnt,
2024                              char **rdata,char **rparam,
2025                              int *rdata_len,int *rparam_len)
2026 {
2027         struct pack_desc desc;
2028         char *str1 = param+2;
2029         char *str2 = skip_string(str1,1);
2030         char *p = skip_string(str2,1);
2031         int jobid;
2032         int uLevel = SVAL(p,2);
2033         int function = SVAL(p,4);
2034         int place, errcode;
2035
2036         jobid = SVAL(p,0);
2037         *rparam_len = 4;
2038         *rparam = REALLOC(*rparam,*rparam_len);
2039   
2040         *rdata_len = 0;
2041         
2042         /* check it's a supported varient */
2043         if ((strcmp(str1,"WWsTP")) || 
2044             (!check_printjob_info(&desc,uLevel,str2)))
2045                 return(False);
2046
2047         if (!print_job_exists(jobid)) {
2048                 errcode=NERR_JobNotFound;
2049                 goto out;
2050         }
2051
2052         errcode = NERR_notsupported;
2053
2054         switch (function) {
2055         case 0x6:
2056                 /* change job place in the queue, 
2057                    data gives the new place */
2058                 place = SVAL(data,0);
2059                 if (print_job_set_place(jobid, place)) {
2060                         errcode=NERR_Success;
2061                 }
2062                 break;
2063
2064         case 0xb:   
2065                 /* change print job name, data gives the name */
2066                 if (print_job_set_name(jobid, data)) {
2067                         errcode=NERR_Success;
2068                 }
2069                 break;
2070
2071         default:
2072                 return False;
2073         }
2074
2075  out:
2076         SSVALS(*rparam,0,errcode);
2077         SSVAL(*rparam,2,0);             /* converter word */
2078         
2079         return(True);
2080 }
2081
2082
2083 /****************************************************************************
2084   get info about the server
2085   ****************************************************************************/
2086 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2087                                   int mdrcnt,int mprcnt,
2088                                   char **rdata,char **rparam,
2089                                   int *rdata_len,int *rparam_len)
2090 {
2091   char *str1 = param+2;
2092   char *str2 = skip_string(str1,1);
2093   char *p = skip_string(str2,1);
2094   int uLevel = SVAL(p,0);
2095   char *p2;
2096   int struct_len;
2097
2098   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2099
2100   /* check it's a supported varient */
2101   if (!prefix_ok(str1,"WrLh")) return False;
2102   switch( uLevel ) {
2103   case 0:
2104     if (strcmp(str2,"B16") != 0) return False;
2105     struct_len = 16;
2106     break;
2107   case 1:
2108     if (strcmp(str2,"B16BBDz") != 0) return False;
2109     struct_len = 26;
2110     break;
2111   case 2:
2112     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2113         != 0) return False;
2114     struct_len = 134;
2115     break;
2116   case 3:
2117     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2118         != 0) return False;
2119     struct_len = 144;
2120     break;
2121   case 20:
2122     if (strcmp(str2,"DN") != 0) return False;
2123     struct_len = 6;
2124     break;
2125   case 50:
2126     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2127     struct_len = 42;
2128     break;
2129   default: return False;
2130   }
2131
2132   *rdata_len = mdrcnt;
2133   *rdata = REALLOC(*rdata,*rdata_len);
2134
2135   p = *rdata;
2136   p2 = p + struct_len;
2137   if (uLevel != 20) {
2138     srvstr_push(NULL, p,local_machine,16, 
2139                 STR_ASCII|STR_UPPER|STR_TERMINATE);
2140   }
2141   p += 16;
2142   if (uLevel > 0)
2143     {
2144       struct srv_info_struct *servers=NULL;
2145       int i,count;
2146       pstring comment;
2147       uint32 servertype= lp_default_server_announce();
2148
2149       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2150
2151       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2152         for (i=0;i<count;i++)
2153           if (strequal(servers[i].name,local_machine))
2154       {
2155             servertype = servers[i].type;
2156             pstrcpy(comment,servers[i].comment);            
2157           }
2158       }
2159       if (servers) free(servers);
2160
2161       SCVAL(p,0,lp_major_announce_version());
2162       SCVAL(p,1,lp_minor_announce_version());
2163       SIVAL(p,2,servertype);
2164
2165       if (mdrcnt == struct_len) {
2166         SIVAL(p,6,0);
2167       } else {
2168         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2169         standard_sub_conn(conn,comment);
2170         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2171         p2 = skip_string(p2,1);
2172       }
2173     }
2174   if (uLevel > 1)
2175     {
2176       return False;             /* not yet implemented */
2177     }
2178
2179   *rdata_len = PTR_DIFF(p2,*rdata);
2180
2181   *rparam_len = 6;
2182   *rparam = REALLOC(*rparam,*rparam_len);
2183   SSVAL(*rparam,0,NERR_Success);
2184   SSVAL(*rparam,2,0);           /* converter word */
2185   SSVAL(*rparam,4,*rdata_len);
2186
2187   return(True);
2188 }
2189
2190
2191 /****************************************************************************
2192   get info about the server
2193   ****************************************************************************/
2194 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2195                                 int mdrcnt,int mprcnt,
2196                                 char **rdata,char **rparam,
2197                                 int *rdata_len,int *rparam_len)
2198 {
2199   char *str1 = param+2;
2200   char *str2 = skip_string(str1,1);
2201   char *p = skip_string(str2,1);
2202   char *p2;
2203   extern userdom_struct current_user_info;
2204   int level = SVAL(p,0);
2205
2206   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2207
2208   *rparam_len = 6;
2209   *rparam = REALLOC(*rparam,*rparam_len);
2210
2211   /* check it's a supported varient */
2212   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2213     return(False);
2214
2215   *rdata_len = mdrcnt + 1024;
2216   *rdata = REALLOC(*rdata,*rdata_len);
2217
2218   SSVAL(*rparam,0,NERR_Success);
2219   SSVAL(*rparam,2,0);           /* converter word */
2220
2221   p = *rdata;
2222   p2 = p + 22;
2223
2224
2225   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2226   pstrcpy(p2,local_machine);
2227   strupper(p2);
2228   p2 = skip_string(p2,1);
2229   p += 4;
2230
2231   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2232   pstrcpy(p2,current_user_info.smb_name);
2233   p2 = skip_string(p2,1);
2234   p += 4;
2235
2236   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2237   pstrcpy(p2,global_myworkgroup);
2238   strupper(p2);
2239   p2 = skip_string(p2,1);
2240   p += 4;
2241
2242   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2243   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2244   p += 2;
2245
2246   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2247   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2248   p2 = skip_string(p2,1);
2249   p += 4;
2250
2251   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2252   pstrcpy(p2,"");
2253   p2 = skip_string(p2,1);
2254   p += 4;
2255
2256   *rdata_len = PTR_DIFF(p2,*rdata);
2257
2258   SSVAL(*rparam,4,*rdata_len);
2259
2260   return(True);
2261 }
2262
2263 /****************************************************************************
2264   get info about a user
2265
2266     struct user_info_11 {
2267         char                usri11_name[21];  0-20 
2268         char                usri11_pad;       21 
2269         char                *usri11_comment;  22-25 
2270         char            *usri11_usr_comment;  26-29
2271         unsigned short      usri11_priv;      30-31
2272         unsigned long       usri11_auth_flags; 32-35
2273         long                usri11_password_age; 36-39
2274         char                *usri11_homedir; 40-43
2275         char            *usri11_parms; 44-47
2276         long                usri11_last_logon; 48-51
2277         long                usri11_last_logoff; 52-55
2278         unsigned short      usri11_bad_pw_count; 56-57
2279         unsigned short      usri11_num_logons; 58-59
2280         char                *usri11_logon_server; 60-63
2281         unsigned short      usri11_country_code; 64-65
2282         char            *usri11_workstations; 66-69
2283         unsigned long       usri11_max_storage; 70-73
2284         unsigned short      usri11_units_per_week; 74-75
2285         unsigned char       *usri11_logon_hours; 76-79
2286         unsigned short      usri11_code_page; 80-81
2287     };
2288
2289 where:
2290
2291   usri11_name specifies the user name for which information is retireved
2292
2293   usri11_pad aligns the next data structure element to a word boundary
2294
2295   usri11_comment is a null terminated ASCII comment
2296
2297   usri11_user_comment is a null terminated ASCII comment about the user
2298
2299   usri11_priv specifies the level of the privilege assigned to the user.
2300        The possible values are:
2301
2302 Name             Value  Description
2303 USER_PRIV_GUEST  0      Guest privilege
2304 USER_PRIV_USER   1      User privilege
2305 USER_PRV_ADMIN   2      Administrator privilege
2306
2307   usri11_auth_flags specifies the account operator privileges. The
2308        possible values are:
2309
2310 Name            Value   Description
2311 AF_OP_PRINT     0       Print operator
2312
2313
2314 Leach, Naik                                        [Page 28]
2315 \f
2316
2317
2318 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2319
2320
2321 AF_OP_COMM      1       Communications operator
2322 AF_OP_SERVER    2       Server operator
2323 AF_OP_ACCOUNTS  3       Accounts operator
2324
2325
2326   usri11_password_age specifies how many seconds have elapsed since the
2327        password was last changed.
2328
2329   usri11_home_dir points to a null terminated ASCII string that contains
2330        the path name of the user's home directory.
2331
2332   usri11_parms points to a null terminated ASCII string that is set
2333        aside for use by applications.
2334
2335   usri11_last_logon specifies the time when the user last logged on.
2336        This value is stored as the number of seconds elapsed since
2337        00:00:00, January 1, 1970.
2338
2339   usri11_last_logoff specifies the time when the user last logged off.
2340        This value is stored as the number of seconds elapsed since
2341        00:00:00, January 1, 1970. A value of 0 means the last logoff
2342        time is unknown.
2343
2344   usri11_bad_pw_count specifies the number of incorrect passwords
2345        entered since the last successful logon.
2346
2347   usri11_log1_num_logons specifies the number of times this user has
2348        logged on. A value of -1 means the number of logons is unknown.
2349
2350   usri11_logon_server points to a null terminated ASCII string that
2351        contains the name of the server to which logon requests are sent.
2352        A null string indicates logon requests should be sent to the
2353        domain controller.
2354
2355   usri11_country_code specifies the country code for the user's language
2356        of choice.
2357
2358   usri11_workstations points to a null terminated ASCII string that
2359        contains the names of workstations the user may log on from.
2360        There may be up to 8 workstations, with the names separated by
2361        commas. A null strings indicates there are no restrictions.
2362
2363   usri11_max_storage specifies the maximum amount of disk space the user
2364        can occupy. A value of 0xffffffff indicates there are no
2365        restrictions.
2366
2367   usri11_units_per_week specifies the equal number of time units into
2368        which a week is divided. This value must be equal to 168.
2369
2370   usri11_logon_hours points to a 21 byte (168 bits) string that
2371        specifies the time during which the user can log on. Each bit
2372        represents one unique hour in a week. The first bit (bit 0, word
2373        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2374
2375
2376
2377 Leach, Naik                                        [Page 29]
2378 \f
2379
2380
2381 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2382
2383
2384        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2385        are no restrictions.
2386
2387   usri11_code_page specifies the code page for the user's language of
2388        choice
2389
2390 All of the pointers in this data structure need to be treated
2391 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2392 to be ignored. The converter word returned in the parameters section
2393 needs to be subtracted from the lower 16 bits to calculate an offset
2394 into the return buffer where this ASCII string resides.
2395
2396 There is no auxiliary data in the response.
2397
2398   ****************************************************************************/
2399
2400 #define usri11_name           0 
2401 #define usri11_pad            21
2402 #define usri11_comment        22
2403 #define usri11_usr_comment    26
2404 #define usri11_full_name      30
2405 #define usri11_priv           34
2406 #define usri11_auth_flags     36
2407 #define usri11_password_age   40
2408 #define usri11_homedir        44
2409 #define usri11_parms          48
2410 #define usri11_last_logon     52
2411 #define usri11_last_logoff    56
2412 #define usri11_bad_pw_count   60
2413 #define usri11_num_logons     62
2414 #define usri11_logon_server   64
2415 #define usri11_country_code   68
2416 #define usri11_workstations   70
2417 #define usri11_max_storage    74
2418 #define usri11_units_per_week 78
2419 #define usri11_logon_hours    80
2420 #define usri11_code_page      84
2421 #define usri11_end            86
2422
2423 #define USER_PRIV_GUEST 0
2424 #define USER_PRIV_USER 1
2425 #define USER_PRIV_ADMIN 2
2426
2427 #define AF_OP_PRINT     0 
2428 #define AF_OP_COMM      1
2429 #define AF_OP_SERVER    2
2430 #define AF_OP_ACCOUNTS  3
2431
2432
2433 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2434                                 int mdrcnt,int mprcnt,
2435                                 char **rdata,char **rparam,
2436                                 int *rdata_len,int *rparam_len)
2437 {
2438         char *str1 = param+2;
2439         char *str2 = skip_string(str1,1);
2440         char *UserName = skip_string(str2,1);
2441         char *p = skip_string(UserName,1);
2442         int uLevel = SVAL(p,0);
2443         char *p2;
2444
2445     /* get NIS home of a previously validated user - simeon */
2446     /* With share level security vuid will always be zero.
2447        Don't depend on vuser being non-null !!. JRA */
2448     user_struct *vuser = get_valid_user_struct(vuid);
2449     if(vuser != NULL)
2450       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2451                vuser->user.unix_name));
2452
2453     *rparam_len = 6;
2454     *rparam = REALLOC(*rparam,*rparam_len);
2455
2456     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2457   
2458         /* check it's a supported variant */
2459         if (strcmp(str1,"zWrLh") != 0) return False;
2460         switch( uLevel )
2461         {
2462                 case 0: p2 = "B21"; break;
2463                 case 1: p2 = "B21BB16DWzzWz"; break;
2464                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2465                 case 10: p2 = "B21Bzzz"; break;
2466                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2467                 default: return False;
2468         }
2469
2470         if (strcmp(p2,str2) != 0) return False;
2471
2472         *rdata_len = mdrcnt + 1024;
2473         *rdata = REALLOC(*rdata,*rdata_len);
2474
2475         SSVAL(*rparam,0,NERR_Success);
2476         SSVAL(*rparam,2,0);             /* converter word */
2477
2478         p = *rdata;
2479         p2 = p + usri11_end;
2480
2481         memset(p,0,21); 
2482         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2483
2484         if (uLevel > 0)
2485         {
2486                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2487                 *p2 = 0;
2488         }
2489         if (uLevel >= 10)
2490         {
2491                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2492                 pstrcpy(p2,"Comment");
2493                 p2 = skip_string(p2,1);
2494
2495                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2496                 pstrcpy(p2,"UserComment");
2497                 p2 = skip_string(p2,1);
2498
2499                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2500                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2501                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2502                 p2 = skip_string(p2,1);
2503         }
2504
2505         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2506         {         
2507                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2508                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2509                 SIVALS(p,usri11_password_age,-1);               /* password age */
2510                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2511                 pstrcpy(p2, lp_logon_home());
2512                 standard_sub_conn(conn, p2);
2513                 p2 = skip_string(p2,1);
2514                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2515                 pstrcpy(p2,"");
2516                 p2 = skip_string(p2,1);
2517                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2518                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2519                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2520                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2521                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2522                 pstrcpy(p2,"\\\\*");
2523                 p2 = skip_string(p2,1);
2524                 SSVAL(p,usri11_country_code,0);         /* country code */
2525
2526                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2527                 pstrcpy(p2,"");
2528                 p2 = skip_string(p2,1);
2529
2530                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2531                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2532                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2533
2534                 /* a simple way to get logon hours at all times. */
2535                 memset(p2,0xff,21);
2536                 SCVAL(p2,21,0);           /* fix zero termination */
2537                 p2 = skip_string(p2,1);
2538
2539                 SSVAL(p,usri11_code_page,0);            /* code page */
2540         }
2541         if (uLevel == 1 || uLevel == 2)
2542         {
2543                 memset(p+22,' ',16);    /* password */
2544                 SIVALS(p,38,-1);                /* password age */
2545                 SSVAL(p,42,
2546                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2547                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2548                 pstrcpy(p2,lp_logon_home());
2549                 standard_sub_conn(conn, p2);
2550                 p2 = skip_string(p2,1);
2551                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2552                 *p2++ = 0;
2553                 SSVAL(p,52,0);          /* flags */
2554                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2555                 pstrcpy(p2,lp_logon_script());
2556                 standard_sub_conn( conn, p2 );             
2557                 p2 = skip_string(p2,1);
2558                 if (uLevel == 2)
2559                 {
2560                         SIVAL(p,60,0);          /* auth_flags */
2561                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2562                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2563                         p2 = skip_string(p2,1);
2564                         SIVAL(p,68,0);          /* urs_comment */
2565                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2566                         pstrcpy(p2,"");
2567                         p2 = skip_string(p2,1);
2568                         SIVAL(p,76,0);          /* workstations */
2569                         SIVAL(p,80,0);          /* last_logon */
2570                         SIVAL(p,84,0);          /* last_logoff */
2571                         SIVALS(p,88,-1);                /* acct_expires */
2572                         SIVALS(p,92,-1);                /* max_storage */
2573                         SSVAL(p,96,168);        /* units_per_week */
2574                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2575                         memset(p2,-1,21);
2576                         p2 += 21;
2577                         SSVALS(p,102,-1);       /* bad_pw_count */
2578                         SSVALS(p,104,-1);       /* num_logons */
2579                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2580                         pstrcpy(p2,"\\\\%L");
2581                         standard_sub_conn(conn, p2);
2582                         p2 = skip_string(p2,1);
2583                         SSVAL(p,110,49);        /* country_code */
2584                         SSVAL(p,112,860);       /* code page */
2585                 }
2586         }
2587
2588         *rdata_len = PTR_DIFF(p2,*rdata);
2589
2590         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2591
2592         return(True);
2593 }
2594
2595 /*******************************************************************
2596   get groups that a user is a member of
2597   ******************************************************************/
2598 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2599                                  int mdrcnt,int mprcnt,
2600                                  char **rdata,char **rparam,
2601                                  int *rdata_len,int *rparam_len)
2602 {
2603   char *str1 = param+2;
2604   char *str2 = skip_string(str1,1);
2605   char *UserName = skip_string(str2,1);
2606   char *p = skip_string(UserName,1);
2607   int uLevel = SVAL(p,0);
2608   char *p2;
2609   int count=0;
2610
2611   *rparam_len = 8;
2612   *rparam = REALLOC(*rparam,*rparam_len);
2613
2614   /* check it's a supported varient */
2615   if (strcmp(str1,"zWrLeh") != 0) return False;
2616   switch( uLevel ) {
2617   case 0: p2 = "B21"; break;
2618   default: return False;
2619   }
2620   if (strcmp(p2,str2) != 0) return False;
2621
2622   *rdata_len = mdrcnt + 1024;
2623   *rdata = REALLOC(*rdata,*rdata_len);
2624
2625   SSVAL(*rparam,0,NERR_Success);
2626   SSVAL(*rparam,2,0);           /* converter word */
2627
2628   p = *rdata;
2629
2630   /* XXXX we need a real SAM database some day */
2631   pstrcpy(p,"Users"); p += 21; count++;
2632   pstrcpy(p,"Domain Users"); p += 21; count++;
2633   pstrcpy(p,"Guests"); p += 21; count++;
2634   pstrcpy(p,"Domain Guests"); p += 21; count++;
2635
2636   *rdata_len = PTR_DIFF(p,*rdata);
2637
2638   SSVAL(*rparam,4,count);       /* is this right?? */
2639   SSVAL(*rparam,6,count);       /* is this right?? */
2640
2641   return(True);
2642 }
2643
2644
2645 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2646                                 int mdrcnt,int mprcnt,
2647                                 char **rdata,char **rparam,
2648                                 int *rdata_len,int *rparam_len)
2649 {
2650   char *str1 = param+2;
2651   char *str2 = skip_string(str1,1);
2652   char *p = skip_string(str2,1);
2653   int uLevel;
2654   struct pack_desc desc;
2655   char* name;
2656
2657   uLevel = SVAL(p,0);
2658   name = p + 2;
2659
2660   memset((char *)&desc,'\0',sizeof(desc));
2661
2662   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2663
2664   /* check it's a supported varient */
2665   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2666   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2667   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2668   desc.base = *rdata;
2669   desc.buflen = mdrcnt;
2670   desc.subformat = NULL;
2671   desc.format = str2;
2672   
2673   if (init_package(&desc,1,0))
2674   {
2675     PACKI(&desc,"W",0);         /* code */
2676     PACKS(&desc,"B21",name);    /* eff. name */
2677     PACKS(&desc,"B","");                /* pad */
2678     PACKI(&desc,"W",
2679           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2680     PACKI(&desc,"D",0);         /* auth flags XXX */
2681     PACKI(&desc,"W",0);         /* num logons */
2682     PACKI(&desc,"W",0);         /* bad pw count */
2683     PACKI(&desc,"D",0);         /* last logon */
2684     PACKI(&desc,"D",-1);                /* last logoff */
2685     PACKI(&desc,"D",-1);                /* logoff time */
2686     PACKI(&desc,"D",-1);                /* kickoff time */
2687     PACKI(&desc,"D",0);         /* password age */
2688     PACKI(&desc,"D",0);         /* password can change */
2689     PACKI(&desc,"D",-1);                /* password must change */
2690     {
2691       fstring mypath;
2692       fstrcpy(mypath,"\\\\");
2693       fstrcat(mypath,local_machine);
2694       strupper(mypath);
2695       PACKS(&desc,"z",mypath); /* computer */
2696     }
2697     PACKS(&desc,"z",global_myworkgroup);/* domain */
2698
2699 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2700 /* made sure all macros are fully substituted and available */
2701     {
2702       pstring logon_script;
2703       pstrcpy(logon_script,lp_logon_script());
2704       standard_sub_conn( conn, logon_script );
2705       PACKS(&desc,"z", logon_script);           /* script path */
2706     }
2707 /* End of JHT mods */
2708
2709     PACKI(&desc,"D",0x00000000);                /* reserved */
2710   }
2711
2712   *rdata_len = desc.usedlen;
2713   *rparam_len = 6;
2714   *rparam = REALLOC(*rparam,*rparam_len);
2715   SSVALS(*rparam,0,desc.errcode);
2716   SSVAL(*rparam,2,0);
2717   SSVAL(*rparam,4,desc.neededlen);
2718
2719   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2720   return(True);
2721 }
2722
2723
2724 /****************************************************************************
2725   api_WAccessGetUserPerms
2726   ****************************************************************************/
2727 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2728                                     int mdrcnt,int mprcnt,
2729                                     char **rdata,char **rparam,
2730                                     int *rdata_len,int *rparam_len)
2731 {
2732   char *str1 = param+2;
2733   char *str2 = skip_string(str1,1);
2734   char *user = skip_string(str2,1);
2735   char *resource = skip_string(user,1);
2736
2737   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2738
2739   /* check it's a supported varient */
2740   if (strcmp(str1,"zzh") != 0) return False;
2741   if (strcmp(str2,"") != 0) return False;
2742
2743   *rparam_len = 6;
2744   *rparam = REALLOC(*rparam,*rparam_len);
2745   SSVALS(*rparam,0,0);          /* errorcode */
2746   SSVAL(*rparam,2,0);           /* converter word */
2747   SSVAL(*rparam,4,0x7f);        /* permission flags */
2748
2749   return(True);
2750 }
2751
2752 /****************************************************************************
2753   api_WPrintJobEnumerate
2754   ****************************************************************************/
2755 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2756                                  int mdrcnt,int mprcnt,
2757                                  char **rdata,char **rparam,
2758                                  int *rdata_len,int *rparam_len)
2759 {
2760   char *str1 = param+2;
2761   char *str2 = skip_string(str1,1);
2762   char *p = skip_string(str2,1);
2763   int uLevel;
2764   int count;
2765   int i;
2766   int snum;
2767   int job;
2768   struct pack_desc desc;
2769   print_queue_struct *queue=NULL;
2770   print_status_struct status;
2771   char *tmpdata=NULL;
2772
2773   uLevel = SVAL(p,2);
2774
2775   memset((char *)&desc,'\0',sizeof(desc));
2776   memset((char *)&status,'\0',sizeof(status));
2777
2778   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2779
2780   /* check it's a supported varient */
2781   if (strcmp(str1,"WWrLh") != 0) return False;
2782   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2783
2784   job = SVAL(p,0);
2785   snum = print_job_snum(job);
2786
2787   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2788
2789   count = print_queue_status(snum,&queue,&status);
2790   for (i = 0; i < count; i++) {
2791     if (queue[i].job == job) break;
2792   }
2793
2794   if (mdrcnt > 0) {
2795     *rdata = REALLOC(*rdata,mdrcnt);
2796     desc.base = *rdata;
2797     desc.buflen = mdrcnt;
2798   } else {
2799     /*
2800      * Don't return data but need to get correct length
2801      *  init_package will return wrong size if buflen=0
2802      */
2803     desc.buflen = getlen(desc.format);
2804     desc.base = tmpdata = (char *)malloc ( desc.buflen );
2805   }
2806
2807   if (init_package(&desc,1,0)) {
2808     if (i < count) {
2809       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2810       *rdata_len = desc.usedlen;
2811     }
2812     else {
2813       desc.errcode = NERR_JobNotFound;
2814       *rdata_len = 0;
2815     }
2816   }
2817
2818   *rparam_len = 6;
2819   *rparam = REALLOC(*rparam,*rparam_len);
2820   SSVALS(*rparam,0,desc.errcode);
2821   SSVAL(*rparam,2,0);
2822   SSVAL(*rparam,4,desc.neededlen);
2823
2824   if (queue) free(queue);
2825   if (tmpdata) free(tmpdata);
2826
2827   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2828   return(True);
2829 }
2830
2831 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2832                                    int mdrcnt,int mprcnt,
2833                                    char **rdata,char **rparam,
2834                                    int *rdata_len,int *rparam_len)
2835 {
2836   char *str1 = param+2;
2837   char *str2 = skip_string(str1,1);
2838   char *p = skip_string(str2,1);
2839   char* name = p;
2840   int uLevel;
2841   int count;
2842   int i, succnt=0;
2843   int snum;
2844   struct pack_desc desc;
2845   print_queue_struct *queue=NULL;
2846   print_status_struct status;
2847
2848   memset((char *)&desc,'\0',sizeof(desc));
2849   memset((char *)&status,'\0',sizeof(status));
2850
2851   p = skip_string(p,1);
2852   uLevel = SVAL(p,0);
2853
2854   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2855
2856   /* check it's a supported varient */
2857   if (strcmp(str1,"zWrLeh") != 0) return False;
2858   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2859   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2860
2861   snum = lp_servicenumber(name);
2862   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2863     int pnum = lp_servicenumber(PRINTERS_NAME);
2864     if (pnum >= 0) {
2865       lp_add_printer(name,pnum);
2866       snum = lp_servicenumber(name);
2867     }
2868   }
2869
2870   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2871
2872   count = print_queue_status(snum,&queue,&status);
2873   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2874   desc.base = *rdata;
2875   desc.buflen = mdrcnt;
2876
2877   if (init_package(&desc,count,0)) {
2878     succnt = 0;
2879     for (i = 0; i < count; i++) {
2880       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2881       if (desc.errcode == NERR_Success) succnt = i+1;
2882     }
2883   }
2884
2885   *rdata_len = desc.usedlen;
2886
2887   *rparam_len = 8;
2888   *rparam = REALLOC(*rparam,*rparam_len);
2889   SSVALS(*rparam,0,desc.errcode);
2890   SSVAL(*rparam,2,0);
2891   SSVAL(*rparam,4,succnt);
2892   SSVAL(*rparam,6,count);
2893
2894   if (queue) free(queue);
2895
2896   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2897   return(True);
2898 }
2899
2900 static int check_printdest_info(struct pack_desc* desc,
2901                                 int uLevel, char* id)
2902 {
2903   desc->subformat = NULL;
2904   switch( uLevel ) {
2905   case 0: desc->format = "B9"; break;
2906   case 1: desc->format = "B9B21WWzW"; break;
2907   case 2: desc->format = "z"; break;
2908   case 3: desc->format = "zzzWWzzzWW"; break;
2909   default: return False;
2910   }
2911   if (strcmp(desc->format,id) != 0) return False;
2912   return True;
2913 }
2914
2915 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2916                                 struct pack_desc* desc)
2917 {
2918   char buf[100];
2919   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2920   buf[sizeof(buf)-1] = 0;
2921   strupper(buf);
2922   if (uLevel <= 1) {
2923     PACKS(desc,"B9",buf);       /* szName */
2924     if (uLevel == 1) {
2925       PACKS(desc,"B21","");     /* szUserName */
2926       PACKI(desc,"W",0);                /* uJobId */
2927       PACKI(desc,"W",0);                /* fsStatus */
2928       PACKS(desc,"z","");       /* pszStatus */
2929       PACKI(desc,"W",0);                /* time */
2930     }
2931   }
2932   if (uLevel == 2 || uLevel == 3) {
2933     PACKS(desc,"z",buf);                /* pszPrinterName */
2934     if (uLevel == 3) {
2935       PACKS(desc,"z","");       /* pszUserName */
2936       PACKS(desc,"z","");       /* pszLogAddr */
2937       PACKI(desc,"W",0);                /* uJobId */
2938       PACKI(desc,"W",0);                /* fsStatus */
2939       PACKS(desc,"z","");       /* pszStatus */
2940       PACKS(desc,"z","");       /* pszComment */
2941       PACKS(desc,"z","NULL"); /* pszDrivers */
2942       PACKI(desc,"W",0);                /* time */
2943       PACKI(desc,"W",0);                /* pad1 */
2944     }
2945   }
2946 }
2947
2948 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2949                                   int mdrcnt,int mprcnt,
2950                                   char **rdata,char **rparam,
2951                                   int *rdata_len,int *rparam_len)
2952 {
2953   char *str1 = param+2;
2954   char *str2 = skip_string(str1,1);
2955   char *p = skip_string(str2,1);
2956   char* PrinterName = p;
2957   int uLevel;
2958   struct pack_desc desc;
2959   int snum;
2960   char *tmpdata=NULL;
2961
2962   memset((char *)&desc,'\0',sizeof(desc));
2963
2964   p = skip_string(p,1);
2965   uLevel = SVAL(p,0);
2966
2967   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2968
2969   /* check it's a supported varient */
2970   if (strcmp(str1,"zWrLh") != 0) return False;
2971   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2972
2973   snum = lp_servicenumber(PrinterName);
2974   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2975     int pnum = lp_servicenumber(PRINTERS_NAME);
2976     if (pnum >= 0) {
2977       lp_add_printer(PrinterName,pnum);
2978       snum = lp_servicenumber(PrinterName);
2979     }
2980   }
2981
2982   if (snum < 0) {
2983     *rdata_len = 0;
2984     desc.errcode = NERR_DestNotFound;
2985     desc.neededlen = 0;
2986   }
2987   else {
2988     if (mdrcnt > 0) {
2989       *rdata = REALLOC(*rdata,mdrcnt);
2990       desc.base = *rdata;
2991       desc.buflen = mdrcnt;
2992     } else {
2993       /*
2994        * Don't return data but need to get correct length
2995        *  init_package will return wrong size if buflen=0
2996        */
2997       desc.buflen = getlen(desc.format);
2998       desc.base = tmpdata = (char *)malloc ( desc.buflen );
2999     }
3000     if (init_package(&desc,1,0)) {
3001       fill_printdest_info(conn,snum,uLevel,&desc);
3002     }
3003     *rdata_len = desc.usedlen;
3004   }
3005
3006   *rparam_len = 6;
3007   *rparam = REALLOC(*rparam,*rparam_len);
3008   SSVALS(*rparam,0,desc.errcode);
3009   SSVAL(*rparam,2,0);
3010   SSVAL(*rparam,4,desc.neededlen);
3011
3012   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3013   if (tmpdata) free (tmpdata);
3014   return(True);
3015 }
3016
3017 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3018                                int mdrcnt,int mprcnt,
3019                                char **rdata,char **rparam,
3020                                int *rdata_len,int *rparam_len)
3021 {
3022   char *str1 = param+2;
3023   char *str2 = skip_string(str1,1);
3024   char *p = skip_string(str2,1);
3025   int uLevel;
3026   int queuecnt;
3027   int i, n, succnt=0;
3028   struct pack_desc desc;
3029   int services = lp_numservices();
3030
3031   memset((char *)&desc,'\0',sizeof(desc));
3032
3033   uLevel = SVAL(p,0);
3034
3035   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3036
3037   /* check it's a supported varient */
3038   if (strcmp(str1,"WrLeh") != 0) return False;
3039   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3040
3041   queuecnt = 0;
3042   for (i = 0; i < services; i++)
3043     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3044       queuecnt++;
3045
3046   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3047   desc.base = *rdata;
3048   desc.buflen = mdrcnt;
3049   if (init_package(&desc,queuecnt,0)) {    
3050     succnt = 0;
3051     n = 0;
3052     for (i = 0; i < services; i++) {
3053       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3054         fill_printdest_info(conn,i,uLevel,&desc);
3055         n++;
3056         if (desc.errcode == NERR_Success) succnt = n;
3057       }
3058     }
3059   }
3060
3061   *rdata_len = desc.usedlen;
3062
3063   *rparam_len = 8;
3064   *rparam = REALLOC(*rparam,*rparam_len);
3065   SSVALS(*rparam,0,desc.errcode);
3066   SSVAL(*rparam,2,0);
3067   SSVAL(*rparam,4,succnt);
3068   SSVAL(*rparam,6,queuecnt);
3069
3070   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3071   return(True);
3072 }
3073
3074 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3075                                  int mdrcnt,int mprcnt,
3076                                  char **rdata,char **rparam,
3077                                  int *rdata_len,int *rparam_len)
3078 {
3079   char *str1 = param+2;
3080   char *str2 = skip_string(str1,1);
3081   char *p = skip_string(str2,1);
3082   int uLevel;
3083   int succnt;
3084   struct pack_desc desc;
3085
3086   memset((char *)&desc,'\0',sizeof(desc));
3087
3088   uLevel = SVAL(p,0);
3089
3090   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3091
3092   /* check it's a supported varient */
3093   if (strcmp(str1,"WrLeh") != 0) return False;
3094   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3095
3096   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3097   desc.base = *rdata;
3098   desc.buflen = mdrcnt;
3099   if (init_package(&desc,1,0)) {
3100     PACKS(&desc,"B41","NULL");
3101   }
3102
3103   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3104
3105   *rdata_len = desc.usedlen;
3106
3107   *rparam_len = 8;
3108   *rparam = REALLOC(*rparam,*rparam_len);
3109   SSVALS(*rparam,0,desc.errcode);
3110   SSVAL(*rparam,2,0);
3111   SSVAL(*rparam,4,succnt);
3112   SSVAL(*rparam,6,1);
3113
3114   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3115   return(True);
3116 }
3117
3118 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3119                                 int mdrcnt,int mprcnt,
3120                                 char **rdata,char **rparam,
3121                                 int *rdata_len,int *rparam_len)
3122 {
3123   char *str1 = param+2;
3124   char *str2 = skip_string(str1,1);
3125   char *p = skip_string(str2,1);
3126   int uLevel;
3127   int succnt;
3128   struct pack_desc desc;
3129
3130   memset((char *)&desc,'\0',sizeof(desc));
3131
3132   uLevel = SVAL(p,0);
3133
3134   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3135
3136   /* check it's a supported varient */
3137   if (strcmp(str1,"WrLeh") != 0) return False;
3138   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3139
3140   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3141   desc.base = *rdata;
3142   desc.buflen = mdrcnt;
3143   desc.format = str2;
3144   if (init_package(&desc,1,0)) {
3145     PACKS(&desc,"B13","lpd");
3146   }
3147
3148   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3149
3150   *rdata_len = desc.usedlen;
3151
3152   *rparam_len = 8;
3153   *rparam = REALLOC(*rparam,*rparam_len);
3154   SSVALS(*rparam,0,desc.errcode);
3155   SSVAL(*rparam,2,0);
3156   SSVAL(*rparam,4,succnt);
3157   SSVAL(*rparam,6,1);
3158
3159   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3160   return(True);
3161 }
3162
3163 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3164                                int mdrcnt,int mprcnt,
3165                                char **rdata,char **rparam,
3166                                int *rdata_len,int *rparam_len)
3167 {
3168   char *str1 = param+2;
3169   char *str2 = skip_string(str1,1);
3170   char *p = skip_string(str2,1);
3171   int uLevel;
3172   int succnt;
3173   struct pack_desc desc;
3174
3175   memset((char *)&desc,'\0',sizeof(desc));
3176
3177   uLevel = SVAL(p,0);
3178
3179   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3180
3181   /* check it's a supported varient */
3182   if (strcmp(str1,"WrLeh") != 0) return False;
3183   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3184
3185   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3186   memset((char *)&desc,'\0',sizeof(desc));
3187   desc.base = *rdata;
3188   desc.buflen = mdrcnt;
3189   desc.format = str2;
3190   if (init_package(&desc,1,0)) {
3191     PACKS(&desc,"B13","lp0");
3192   }
3193
3194   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3195
3196   *rdata_len = desc.usedlen;
3197
3198   *rparam_len = 8;
3199   *rparam = REALLOC(*rparam,*rparam_len);
3200   SSVALS(*rparam,0,desc.errcode);
3201   SSVAL(*rparam,2,0);
3202   SSVAL(*rparam,4,succnt);
3203   SSVAL(*rparam,6,1);
3204
3205   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3206   return(True);
3207 }
3208
3209 /****************************************************************************
3210  The buffer was too small
3211  ****************************************************************************/
3212
3213 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3214                          int mdrcnt,int mprcnt,
3215                          char **rdata,char **rparam,
3216                          int *rdata_len,int *rparam_len)
3217 {
3218   *rparam_len = MIN(*rparam_len,mprcnt);
3219   *rparam = REALLOC(*rparam,*rparam_len);
3220
3221   *rdata_len = 0;
3222
3223   SSVAL(*rparam,0,NERR_BufTooSmall);
3224
3225   DEBUG(3,("Supplied buffer too small in API command\n"));
3226
3227   return(True);
3228 }
3229
3230
3231 /****************************************************************************
3232  The request is not supported
3233  ****************************************************************************/
3234
3235 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3236                             int mdrcnt,int mprcnt,
3237                             char **rdata,char **rparam,
3238                             int *rdata_len,int *rparam_len)
3239 {
3240   *rparam_len = 4;
3241   *rparam = REALLOC(*rparam,*rparam_len);
3242
3243   *rdata_len = 0;
3244
3245   SSVAL(*rparam,0,NERR_notsupported);
3246   SSVAL(*rparam,2,0);           /* converter word */
3247
3248   DEBUG(3,("Unsupported API command\n"));
3249
3250   return(True);
3251 }
3252
3253
3254
3255
3256 struct
3257 {
3258   char *name;
3259   int id;
3260   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3261              int,int,char **,char **,int *,int *);
3262   int flags;
3263 } api_commands[] = {
3264   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3265   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3266   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3267   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3268   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3269   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3270   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3271   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3272   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3273   {"WPrintQueuePause",  74, api_WPrintQueueCtrl,0},
3274   {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3275   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3276   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3277   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3278   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3279   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3280   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3281   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3282   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3283   {"WPrintQueuePurge",  103,    api_WPrintQueueCtrl,0},
3284   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3285   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3286   {"SetUserPassword",   115,    api_SetUserPassword,0},
3287   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3288   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3289   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3290   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3291   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3292   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3293   {NULL,                -1,     api_Unsupported,0}};
3294
3295
3296 /****************************************************************************
3297  Handle remote api calls
3298  ****************************************************************************/
3299
3300 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3301                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3302 {
3303   int api_command;
3304   char *rdata = NULL;
3305   char *rparam = NULL;
3306   int rdata_len = 0;
3307   int rparam_len = 0;
3308   BOOL reply=False;
3309   int i;
3310
3311   if (!params) {
3312           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3313           return 0;
3314   }
3315
3316   api_command = SVAL(params,0);
3317
3318   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3319            api_command,
3320            params+2,
3321            skip_string(params+2,1),
3322            tdscnt,tpscnt,mdrcnt,mprcnt));
3323
3324   for (i=0;api_commands[i].name;i++) {
3325     if (api_commands[i].id == api_command && api_commands[i].fn) {
3326         DEBUG(3,("Doing %s\n",api_commands[i].name));
3327         break;
3328     }
3329   }
3330
3331   rdata = (char *)malloc(1024);
3332   if (rdata)
3333     memset(rdata,'\0',1024);
3334
3335   rparam = (char *)malloc(1024);
3336   if (rparam)
3337     memset(rparam,'\0',1024);
3338
3339   if(!rdata || !rparam) {
3340     DEBUG(0,("api_reply: malloc fail !\n"));
3341     return -1;
3342   }
3343
3344   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3345                              &rdata,&rparam,&rdata_len,&rparam_len);
3346
3347
3348   if (rdata_len > mdrcnt ||
3349       rparam_len > mprcnt) {
3350       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3351                            &rdata,&rparam,&rdata_len,&rparam_len);
3352   }
3353
3354   /* if we get False back then it's actually unsupported */
3355   if (!reply)
3356     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3357                     &rdata,&rparam,&rdata_len,&rparam_len);
3358
3359   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3360
3361   if (rdata )
3362     free(rdata);
3363   if (rparam)
3364     free(rparam);
3365   
3366   return -1;
3367 }