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