Removed 'extern int DEBUGLEVEL' as it is now in the smb.h header.
[samba.git] / source3 / 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 fstring local_machine;
37 extern pstring global_myname;
38 extern fstring global_myworkgroup;
39
40 #define NERR_Success 0
41 #define NERR_badpass 86
42 #define NERR_notsupported 50
43
44 #define NERR_BASE (2100)
45 #define NERR_BufTooSmall (NERR_BASE+23)
46 #define NERR_JobNotFound (NERR_BASE+51)
47 #define NERR_DestNotFound (NERR_BASE+52)
48
49 #define ACCESS_READ 0x01
50 #define ACCESS_WRITE 0x02
51 #define ACCESS_CREATE 0x04
52
53 #define SHPWLEN 8               /* share password length */
54
55 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
56                             int mdrcnt,int mprcnt,
57                             char **rdata,char **rparam,
58                             int *rdata_len,int *rparam_len);
59 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
60                          int mdrcnt,int mprcnt,
61                          char **rdata,char **rparam,
62                          int *rdata_len,int *rparam_len);
63
64
65 static int CopyExpanded(connection_struct *conn, 
66                         int snum, char** dst, char* src, int* n)
67 {
68         pstring buf;
69         int l;
70
71         if (!src || !dst || !n || !(*dst)) return(0);
72
73         StrnCpy(buf,src,sizeof(buf)/2);
74         pstring_sub(buf,"%S",lp_servicename(snum));
75         standard_sub_conn(conn,buf);
76         l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
77         (*dst) += l;
78         (*n) -= l;
79         return l;
80 }
81
82 static int CopyAndAdvance(char** dst, char* src, int* n)
83 {
84   int l;
85   if (!src || !dst || !n || !(*dst)) return(0);
86   l = push_ascii(*dst,src,*n-1, STR_TERMINATE);
87   (*dst) += l;
88   (*n) -= l;
89   return l;
90 }
91
92 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
93 {
94         pstring buf;
95         if (!s) return(0);
96         StrnCpy(buf,s,sizeof(buf)/2);
97         pstring_sub(buf,"%S",lp_servicename(snum));
98         standard_sub_conn(conn,buf);
99         return strlen(buf) + 1;
100 }
101
102 static char* Expand(connection_struct *conn, int snum, char* s)
103 {
104         static pstring buf;
105         if (!s) return(NULL);
106         StrnCpy(buf,s,sizeof(buf)/2);
107         pstring_sub(buf,"%S",lp_servicename(snum));
108         standard_sub_conn(conn,buf);
109         return &buf[0];
110 }
111
112 /*******************************************************************
113   check a API string for validity when we only need to check the prefix
114   ******************************************************************/
115 static BOOL prefix_ok(char *str,char *prefix)
116 {
117   return(strncmp(str,prefix,strlen(prefix)) == 0);
118 }
119
120 struct pack_desc {
121   char* format;     /* formatstring for structure */
122   char* subformat;  /* subformat for structure */
123   char* base;       /* baseaddress of buffer */
124   int buflen;      /* remaining size for fixed part; on init: length of base */
125   int subcount;     /* count of substructures */
126   char* structbuf;  /* pointer into buffer for remaining fixed part */
127   int stringlen;    /* remaining size for variable part */              
128   char* stringbuf;  /* pointer into buffer for remaining variable part */
129   int neededlen;    /* total needed size */
130   int usedlen;      /* total used size (usedlen <= neededlen and usedlen <= buflen) */
131   char* curpos;     /* current position; pointer into format or subformat */
132   int errcode;
133 };
134
135 static int get_counter(char** p)
136 {
137   int i, n;
138   if (!p || !(*p)) return(1);
139   if (!isdigit((int)**p)) return 1;
140   for (n = 0;;) {
141     i = **p;
142     if (isdigit(i))
143       n = 10 * n + (i - '0');
144     else
145       return n;
146     (*p)++;
147   }
148 }
149
150 static int getlen(char* p)
151 {
152   int n = 0;
153   if (!p) return(0);
154   while (*p) {
155     switch( *p++ ) {
156     case 'W':                   /* word (2 byte) */
157       n += 2;
158       break;
159     case 'K':                   /* status word? (2 byte) */
160       n += 2;
161       break;
162     case 'N':                   /* count of substructures (word) at end */
163       n += 2;
164       break;
165     case 'D':                   /* double word (4 byte) */
166     case 'z':                   /* offset to zero terminated string (4 byte) */
167     case 'l':                   /* offset to user data (4 byte) */
168       n += 4;
169       break;
170     case 'b':                   /* offset to data (with counter) (4 byte) */
171       n += 4;
172       get_counter(&p);
173       break;
174     case 'B':                   /* byte (with optional counter) */
175       n += get_counter(&p);
176       break;
177     }
178   }
179   return n;
180 }
181
182 static BOOL init_package(struct pack_desc* p, int count, int subcount)
183 {
184   int n = p->buflen;
185   int i;
186
187   if (!p->format || !p->base) return(False);
188
189   i = count * getlen(p->format);
190   if (p->subformat) i += subcount * getlen(p->subformat);
191   p->structbuf = p->base;
192   p->neededlen = 0;
193   p->usedlen = 0;
194   p->subcount = 0;
195   p->curpos = p->format;
196   if (i > n) {
197     p->neededlen = i;
198     i = n = 0;
199 #if 0
200     /*
201      * This is the old error code we used. Aparently
202      * WinNT/2k systems return ERRbuftoosmall (2123) and
203      * OS/2 needs this. I'm leaving this here so we can revert
204      * if needed. JRA.
205      */
206     p->errcode = ERRmoredata;
207 #else
208         p->errcode = ERRbuftoosmall;
209 #endif
210   }
211   else
212     p->errcode = NERR_Success;
213   p->buflen = i;
214   n -= i;
215   p->stringbuf = p->base + i;
216   p->stringlen = n;
217   return(p->errcode == NERR_Success);
218 }
219
220 static int package(struct pack_desc* p, ...)
221 {
222   va_list args;
223   int needed=0, stringneeded;
224   char* str=NULL;
225   int is_string=0, stringused;
226   int32 temp;
227
228   va_start(args,p);
229
230   if (!*p->curpos) {
231     if (!p->subcount)
232       p->curpos = p->format;
233     else {
234       p->curpos = p->subformat;
235       p->subcount--;
236     }
237   }
238 #if CHECK_TYPES
239   str = va_arg(args,char*);
240   SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
241 #endif
242   stringneeded = -1;
243
244   if (!p->curpos) {
245     va_end(args);
246     return(0);
247   }
248
249   switch( *p->curpos++ ) {
250   case 'W':                     /* word (2 byte) */
251     needed = 2;
252     temp = va_arg(args,int);
253     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
254     break;
255   case 'K':                     /* status word? (2 byte) */
256     needed = 2;
257     temp = va_arg(args,int);
258     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
259     break;
260   case 'N':                     /* count of substructures (word) at end */
261     needed = 2;
262     p->subcount = va_arg(args,int);
263     if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
264     break;
265   case 'D':                     /* double word (4 byte) */
266     needed = 4;
267     temp = va_arg(args,int);
268     if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
269     break;
270   case 'B':                     /* byte (with optional counter) */
271     needed = get_counter(&p->curpos);
272     {
273       char *s = va_arg(args,char*);
274       if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
275     }
276     break;
277   case 'z':                     /* offset to zero terminated string (4 byte) */
278     str = va_arg(args,char*);
279     stringneeded = (str ? strlen(str)+1 : 0);
280     is_string = 1;
281     break;
282   case 'l':                     /* offset to user data (4 byte) */
283     str = va_arg(args,char*);
284     stringneeded = va_arg(args,int);
285     is_string = 0;
286     break;
287   case 'b':                     /* offset to data (with counter) (4 byte) */
288     str = va_arg(args,char*);
289     stringneeded = get_counter(&p->curpos);
290     is_string = 0;
291     break;
292   }
293   va_end(args);
294   if (stringneeded >= 0) {
295     needed = 4;
296     if (p->buflen >= needed) {
297       stringused = stringneeded;
298       if (stringused > p->stringlen) {
299         stringused = (is_string ? p->stringlen : 0);
300         if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
301       }
302       if (!stringused)
303         SIVAL(p->structbuf,0,0);
304       else {
305         SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
306         memcpy(p->stringbuf,str?str:"",stringused);
307         if (is_string) p->stringbuf[stringused-1] = '\0';
308         p->stringbuf += stringused;
309         p->stringlen -= stringused;
310         p->usedlen += stringused;
311       }
312     }
313     p->neededlen += stringneeded;
314   }
315   p->neededlen += needed;
316   if (p->buflen >= needed) {
317     p->structbuf += needed;
318     p->buflen -= needed;
319     p->usedlen += needed;
320   }
321   else {
322     if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
323   }
324   return 1;
325 }
326
327 #if CHECK_TYPES
328 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
329 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
330 #else
331 #define PACK(desc,t,v) package(desc,v)
332 #define PACKl(desc,t,v,l) package(desc,v,l)
333 #endif
334
335 static void PACKI(struct pack_desc* desc,char *t,int v)
336 {
337   PACK(desc,t,v);
338 }
339
340 static void PACKS(struct pack_desc* desc,char *t,char *v)
341 {
342   PACK(desc,t,v);
343 }
344
345
346 /****************************************************************************
347   get a print queue
348   ****************************************************************************/
349 static void PackDriverData(struct pack_desc* desc)
350 {
351   char drivdata[4+4+32];
352   SIVAL(drivdata,0,sizeof drivdata); /* cb */
353   SIVAL(drivdata,4,1000);       /* lVersion */
354   memset(drivdata+8,0,32);      /* szDeviceName */
355   push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
356   PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
357 }
358
359 static int check_printq_info(struct pack_desc* desc,
360                              int uLevel, char *id1, char *id2)
361 {
362   desc->subformat = NULL;
363   switch( uLevel ) {
364   case 0:
365     desc->format = "B13";
366     break;
367   case 1:
368     desc->format = "B13BWWWzzzzzWW";
369     break;
370   case 2:
371     desc->format = "B13BWWWzzzzzWN";
372     desc->subformat = "WB21BB16B10zWWzDDz";
373     break;
374   case 3:
375     desc->format = "zWWWWzzzzWWzzl";
376     break;
377   case 4:
378     desc->format = "zWWWWzzzzWNzzl";
379     desc->subformat = "WWzWWDDzz";
380     break;
381   case 5:
382     desc->format = "z";
383     break;
384   case 51:
385     desc->format = "K";
386     break;
387   case 52:
388     desc->format = "WzzzzzzzzN";
389     desc->subformat = "z";
390     break;
391   default: return False;
392   }
393   if (strcmp(desc->format,id1) != 0) return False;
394   if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
395   return True;
396 }
397
398
399 #define RAP_JOB_STATUS_QUEUED 0
400 #define RAP_JOB_STATUS_PAUSED 1
401 #define RAP_JOB_STATUS_SPOOLING 2
402 #define RAP_JOB_STATUS_PRINTING 3
403 #define RAP_JOB_STATUS_PRINTED 4
404
405 #define RAP_QUEUE_STATUS_PAUSED 1
406 #define RAP_QUEUE_STATUS_ERROR 2
407
408 /* turn a print job status into a on the wire status 
409 */
410 static int printj_status(int v)
411 {
412         switch (v) {
413         case LPQ_QUEUED:
414                 return RAP_JOB_STATUS_QUEUED;
415         case LPQ_PAUSED:
416                 return RAP_JOB_STATUS_PAUSED;
417         case LPQ_SPOOLING:
418                 return RAP_JOB_STATUS_SPOOLING;
419         case LPQ_PRINTING:
420                 return RAP_JOB_STATUS_PRINTING;
421         }
422         return 0;
423 }
424
425 /* turn a print queue status into a on the wire status 
426 */
427 static int printq_status(int v)
428 {
429         switch (v) {
430         case LPQ_QUEUED:
431                 return 0;
432         case LPQ_PAUSED:
433                 return RAP_QUEUE_STATUS_PAUSED;
434         }
435         return RAP_QUEUE_STATUS_ERROR;
436 }
437
438 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
439                                struct pack_desc* desc,
440                                print_queue_struct* queue, int n)
441 {
442   time_t t = queue->time;
443
444   /* the client expects localtime */
445   t -= TimeDiff(t);
446
447   PACKI(desc,"W",queue->job); /* uJobId */
448   if (uLevel == 1) {
449     PACKS(desc,"B21",queue->user); /* szUserName */
450     PACKS(desc,"B","");         /* pad */
451     PACKS(desc,"B16","");       /* szNotifyName */
452     PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
453     PACKS(desc,"z","");         /* pszParms */
454     PACKI(desc,"W",n+1);                /* uPosition */
455     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
456     PACKS(desc,"z","");         /* pszStatus */
457     PACKI(desc,"D",t); /* ulSubmitted */
458     PACKI(desc,"D",queue->size); /* ulSize */
459     PACKS(desc,"z",queue->file); /* pszComment */
460   }
461   if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
462     PACKI(desc,"W",queue->priority);            /* uPriority */
463     PACKS(desc,"z",queue->user); /* pszUserName */
464     PACKI(desc,"W",n+1);                /* uPosition */
465     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
466     PACKI(desc,"D",t); /* ulSubmitted */
467     PACKI(desc,"D",queue->size); /* ulSize */
468     PACKS(desc,"z","Samba");    /* pszComment */
469     PACKS(desc,"z",queue->file); /* pszDocument */
470     if (uLevel == 3) {
471       PACKS(desc,"z","");       /* pszNotifyName */
472       PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
473       PACKS(desc,"z","");       /* pszParms */
474       PACKS(desc,"z","");       /* pszStatus */
475       PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
476       PACKS(desc,"z","lpd");    /* pszQProcName */
477       PACKS(desc,"z","");       /* pszQProcParms */
478       PACKS(desc,"z","NULL"); /* pszDriverName */
479       PackDriverData(desc);     /* pDriverData */
480       PACKS(desc,"z","");       /* pszPrinterName */
481     } else if (uLevel == 4) {   /* OS2 */
482       PACKS(desc,"z","");       /* pszSpoolFileName  */
483        PACKS(desc,"z","");       /* pszPortName       */
484        PACKS(desc,"z","");       /* pszStatus         */
485        PACKI(desc,"D",0);        /* ulPagesSpooled    */
486        PACKI(desc,"D",0);        /* ulPagesSent       */
487        PACKI(desc,"D",0);        /* ulPagesPrinted    */
488        PACKI(desc,"D",0);        /* ulTimePrinted     */
489        PACKI(desc,"D",0);        /* ulExtendJobStatus */
490        PACKI(desc,"D",0);        /* ulStartPage       */
491        PACKI(desc,"D",0);        /* ulEndPage         */
492     }
493   }
494 }
495
496 /********************************************************************
497  Return a driver name given an snum.
498  Looks in a tdb first. Returns True if from tdb, False otherwise.
499  ********************************************************************/
500
501 static BOOL get_driver_name(int snum, pstring drivername)
502 {
503         NT_PRINTER_INFO_LEVEL *info = NULL;
504         BOOL in_tdb = False;
505
506         get_a_printer (&info, 2, lp_servicename(snum));
507         if (info != NULL) {
508                 pstrcpy( drivername, info->info_2->drivername);
509                 in_tdb = True;
510                 free_a_printer(&info, 2);
511         } else {
512                 pstrcpy( drivername, lp_printerdriver(snum));
513         }
514
515         return in_tdb;
516 }
517
518 /********************************************************************
519  Respond to the DosPrintQInfo command with a level of 52
520  This is used to get printer driver information for Win9x clients
521  ********************************************************************/
522 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
523                                 struct pack_desc* desc,
524                                 int count, print_queue_struct* queue,
525                                 print_status_struct* status)
526 {
527         int i;
528         BOOL ok = False;
529         pstring tok,driver,datafile,langmon,helpfile,datatype;
530         char *p;
531         char **lines = NULL;
532         pstring gen_line;
533         BOOL in_tdb = False;
534         fstring location;
535         pstring drivername;
536
537         /*
538          * Check in the tdb *first* before checking the legacy
539          * files. This allows an NT upload to take precedence over
540          * the existing fileset. JRA.
541          * 
542          * we need to lookup the driver name prior to making the call
543          * to get_a_printer_driver_9x_compatible() and not rely on the
544          * 'print driver' parameter --jerry
545          */
546
547
548         if ((get_driver_name(snum,drivername)) && 
549             ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
550         {
551                 in_tdb = True;
552                 p = gen_line;
553                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
554         } 
555         else 
556         {
557                 /* didn't find driver in tdb */
558
559                 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
560                            snum, drivername, lp_driverfile(snum)));
561
562                 lines = file_lines_load(lp_driverfile(snum),NULL);
563                 if (!lines) 
564                 {
565                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
566                                   strerror(errno)));
567                         desc->errcode=NERR_notsupported;
568                         goto done;
569                 } 
570
571                 /* lookup the long printer driver name in the file description */
572                 for (i=0;lines[i] && !ok;i++) 
573                 {
574                         p = lines[i];
575                         if (next_token(&p,tok,":",sizeof(tok)) &&
576                            (strlen(drivername) == strlen(tok)) &&
577                            (!strncmp(tok,drivername,strlen(drivername))))
578                         {
579                                 ok = True;
580                         }
581                 }
582         }
583
584         if (ok)
585         {
586                 /* driver file name */
587                 if (!next_token(&p,driver,":",sizeof(driver)))
588                         goto err;
589
590                 /* data file name */
591                 if (!next_token(&p,datafile,":",sizeof(datafile)))
592                         goto err;
593
594                 /*
595                  * for the next tokens - which may be empty - I have
596                  * to check for empty tokens first because the
597                  * next_token function will skip all empty token
598                  * fields */
599
600                 /* help file */
601                 if (*p == ':') 
602                 {
603                         *helpfile = '\0';
604                         p++;
605                 } 
606                 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
607                         goto err;
608         
609                 /* language monitor */
610                 if (*p == ':') 
611                 {
612                         *langmon = '\0';
613                         p++;
614                 } 
615                 else if (!next_token(&p,langmon,":",sizeof(langmon)))
616                         goto err;
617         
618                 /* default data type */
619                 if (!next_token(&p,datatype,":",sizeof(datatype))) 
620                         goto err;
621         
622                 PACKI(desc,"W",0x0400);               /* don't know */
623                 PACKS(desc,"z",drivername);    /* long printer name */
624                 PACKS(desc,"z",driver);                    /* Driverfile Name */
625                 PACKS(desc,"z",datafile);                  /* Datafile name */
626                 PACKS(desc,"z",langmon);                         /* language monitor */
627                 if (in_tdb)
628                 {
629                         fstrcpy(location, "\\\\");
630                         fstrcat(location, global_myname);
631                         fstrcat(location, "\\print$\\WIN40\\0");
632                         PACKS(desc,"z",location);   /* share to retrieve files */
633                 }
634                 else
635                 {
636                         PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
637                 }
638                 PACKS(desc,"z",datatype);                        /* default data type */
639                 PACKS(desc,"z",helpfile);                  /* helpfile name */
640                 PACKS(desc,"z",driver);                    /* driver name */
641
642                 DEBUG(3,("printerdriver:%s:\n",drivername));
643                 DEBUG(3,("Driver:%s:\n",driver));
644                 DEBUG(3,("Data File:%s:\n",datafile));
645                 DEBUG(3,("Language Monitor:%s:\n",langmon));
646                 if (in_tdb)
647                         DEBUG(3,("lp_driverlocation:%s:\n",location));
648                 else
649                         DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
650                 DEBUG(3,("Data Type:%s:\n",datatype));
651                 DEBUG(3,("Help File:%s:\n",helpfile));
652                 PACKI(desc,"N",count);                     /* number of files to copy */
653
654                 for (i=0;i<count;i++) 
655                 {
656                         /* no need to check return value here
657                          * - it was already tested in
658                          * get_printerdrivernumber */
659                         next_token(&p,tok,",",sizeof(tok));
660                         PACKS(desc,"z",tok);         /* driver files to copy */
661                         DEBUG(3,("file:%s:\n",tok));
662                 }
663                 
664                 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
665                           SERVICE(snum),count));
666
667                 desc->errcode=NERR_Success;
668                 goto done;
669         }
670
671   err:
672
673         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
674         desc->errcode=NERR_notsupported;
675
676  done:
677         file_lines_free(lines); 
678 }
679
680
681 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
682                              struct pack_desc* desc,
683                              int count, print_queue_struct* queue,
684                              print_status_struct* status)
685 {
686         switch (uLevel) {
687         case 1:
688         case 2:
689                 PACKS(desc,"B13",SERVICE(snum));
690                 break;
691         case 3:
692         case 4:
693         case 5:
694                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
695                 break;
696         case 51:
697                 PACKI(desc,"K",printq_status(status->status));
698                 break;
699         }
700
701         if (uLevel == 1 || uLevel == 2) {
702                 PACKS(desc,"B","");             /* alignment */
703                 PACKI(desc,"W",5);              /* priority */
704                 PACKI(desc,"W",0);              /* start time */
705                 PACKI(desc,"W",0);              /* until time */
706                 PACKS(desc,"z","");             /* pSepFile */
707                 PACKS(desc,"z","lpd");  /* pPrProc */
708                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
709                 PACKS(desc,"z","");             /* pParms */
710                 if (snum < 0) {
711                         PACKS(desc,"z","UNKNOWN PRINTER");
712                         PACKI(desc,"W",LPSTAT_ERROR);
713                 }
714                 else if (!status || !status->message[0]) {
715                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
716                         PACKI(desc,"W",LPSTAT_OK); /* status */
717                 } else {
718                         PACKS(desc,"z",status->message);
719                         PACKI(desc,"W",printq_status(status->status)); /* status */
720                 }
721                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
722         }
723
724         if (uLevel == 3 || uLevel == 4) {
725                 pstring drivername;
726
727                 PACKI(desc,"W",5);              /* uPriority */
728                 PACKI(desc,"W",0);              /* uStarttime */
729                 PACKI(desc,"W",0);              /* uUntiltime */
730                 PACKI(desc,"W",5);              /* pad1 */
731                 PACKS(desc,"z","");             /* pszSepFile */
732                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
733                 PACKS(desc,"z",NULL);           /* pszParms */
734                 PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
735                 /* "don't ask" that it's done this way to fix corrupted 
736                    Win9X/ME printer comments. */
737                 if (!status) {
738                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
739                 } else {
740                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
741                 }
742                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
743                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
744                 get_driver_name(snum,drivername);
745                 PACKS(desc,"z",drivername);             /* pszDriverName */
746                 PackDriverData(desc);   /* pDriverData */
747         }
748
749         if (uLevel == 2 || uLevel == 4) {
750                 int i;
751                 for (i=0;i<count;i++)
752                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
753         }
754
755         if (uLevel==52) {
756                 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
757         }
758 }
759
760 /* This function returns the number of files for a given driver */
761 static int get_printerdrivernumber(int snum)
762 {
763         int i, result = 0;
764         BOOL ok = False;
765         pstring tok;
766         char *p;
767         char **lines = NULL;
768         pstring gen_line;
769         pstring drivername;
770         
771         /*
772          * Check in the tdb *first* before checking the legacy
773          * files. This allows an NT upload to take precedence over
774          * the existing fileset. JRA.
775          *
776          * we need to lookup the driver name prior to making the call
777          * to get_a_printer_driver_9x_compatible() and not rely on the
778          * 'print driver' parameter --jerry
779          */
780         
781         if ((get_driver_name(snum,drivername)) && 
782             (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True)) 
783         {
784                 p = gen_line;
785                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
786         } 
787         else 
788         {
789                 /* didn't find driver in tdb */
790         
791                 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
792                           snum, drivername, lp_driverfile(snum)));
793                 
794                 lines = file_lines_load(lp_driverfile(snum), NULL);
795                 if (!lines) 
796                 {
797                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
798                         goto done;
799                 } 
800
801                 /* lookup the long printer driver name in the file description */
802                 for (i=0;lines[i] && !ok;i++) 
803                 {
804                         p = lines[i];
805                         if (next_token(&p,tok,":",sizeof(tok)) &&
806                            (strlen(drivername) == strlen(tok)) &&
807                            (!strncmp(tok,drivername,strlen(drivername)))) 
808                         {
809                                 ok = True;
810                         }
811                 }
812         }
813         
814         if( ok ) 
815         {
816                 /* skip 5 fields */
817                 i = 5;
818                 while (*p && i) {
819                         if (*p++ == ':') i--;
820                 }
821                 if (!*p || i) {
822                         DEBUG(3,("Can't determine number of printer driver files\n"));
823                         goto done;
824                 }
825                 
826                 /* count the number of files */
827                 while (next_token(&p,tok,",",sizeof(tok)))
828                         i++;
829         
830                 result = i;
831         }
832
833  done:
834
835         file_lines_free(lines);
836
837         return result;
838 }
839
840 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
841                                  uint16 vuid, char *param,char *data,
842                                  int mdrcnt,int mprcnt,
843                                  char **rdata,char **rparam,
844                                  int *rdata_len,int *rparam_len)
845 {
846         char *str1 = param+2;
847         char *str2 = skip_string(str1,1);
848         char *p = skip_string(str2,1);
849         char *QueueName = p;
850         int uLevel;
851         int count=0;
852         int snum;
853         char* str3;
854         struct pack_desc desc;
855         print_queue_struct *queue=NULL;
856         print_status_struct status;
857         char* tmpdata=NULL;
858
859         memset((char *)&status,'\0',sizeof(status));
860         memset((char *)&desc,'\0',sizeof(desc));
861  
862         p = skip_string(p,1);
863         uLevel = SVAL(p,0);
864         str3 = p + 4;
865  
866         /* remove any trailing username */
867         if ((p = strchr_m(QueueName,'%')))
868                 *p = 0;
869  
870         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
871  
872         /* check it's a supported varient */
873         if (!prefix_ok(str1,"zWrLh"))
874                 return False;
875         if (!check_printq_info(&desc,uLevel,str2,str3)) {
876                 /*
877                  * Patch from Scott Moomaw <scott@bridgewater.edu>
878                  * to return the 'invalid info level' error if an
879                  * unknown level was requested.
880                  */
881                 *rdata_len = 0;
882                 *rparam_len = 6;
883                 *rparam = REALLOC(*rparam,*rparam_len);
884                 SSVALS(*rparam,0,ERRunknownlevel);
885                 SSVAL(*rparam,2,0);
886                 SSVAL(*rparam,4,0);
887                 return(True);
888         }
889  
890         snum = lp_servicenumber(QueueName);
891         if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
892                 int pnum = lp_servicenumber(PRINTERS_NAME);
893                 if (pnum >= 0) {
894                         lp_add_printer(QueueName,pnum);
895                         snum = lp_servicenumber(QueueName);
896                 }
897         }
898   
899         if (snum < 0 || !VALID_SNUM(snum))
900                 return(False);
901
902         if (uLevel==52) {
903                 count = get_printerdrivernumber(snum);
904                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
905         } else {
906                 count = print_queue_status(snum, &queue,&status);
907         }
908
909         if (mdrcnt > 0) {
910                 *rdata = REALLOC(*rdata,mdrcnt);
911                 desc.base = *rdata;
912                 desc.buflen = mdrcnt;
913         } else {
914                 /*
915                  * Don't return data but need to get correct length
916                  * init_package will return wrong size if buflen=0
917                  */
918                 desc.buflen = getlen(desc.format);
919                 desc.base = tmpdata = (char *) malloc (desc.buflen);
920         }
921
922         if (init_package(&desc,1,count)) {
923                 desc.subcount = count;
924                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
925         }
926
927         *rdata_len = desc.usedlen;
928   
929         /*
930          * We must set the return code to ERRbuftoosmall
931          * in order to support lanman style printing with Win NT/2k
932          * clients       --jerry
933          */
934         if (!mdrcnt && lp_disable_spoolss())
935                 desc.errcode = ERRbuftoosmall;
936  
937     *rdata_len = desc.usedlen;
938         *rparam_len = 6;
939         *rparam = REALLOC(*rparam,*rparam_len);
940         SSVALS(*rparam,0,desc.errcode);
941         SSVAL(*rparam,2,0);
942         SSVAL(*rparam,4,desc.neededlen);
943   
944         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
945
946         SAFE_FREE(queue);
947         SAFE_FREE(tmpdata);
948
949         return(True);
950 }
951
952 /****************************************************************************
953  View list of all print jobs on all queues.
954 ****************************************************************************/
955
956 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
957                               int mdrcnt, int mprcnt,
958                               char **rdata, char** rparam,
959                               int *rdata_len, int *rparam_len)
960 {
961   char *param_format = param+2;
962   char *output_format1 = skip_string(param_format,1);
963   char *p = skip_string(output_format1,1);
964   int uLevel = SVAL(p,0);
965   char *output_format2 = p + 4;
966   int services = lp_numservices();
967   int i, n;
968   struct pack_desc desc;
969   print_queue_struct **queue = NULL;
970   print_status_struct *status = NULL;
971   int* subcntarr = NULL;
972   int queuecnt, subcnt=0, succnt=0;
973  
974   memset((char *)&desc,'\0',sizeof(desc));
975
976   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
977  
978   if (!prefix_ok(param_format,"WrLeh")) return False;
979   if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
980     /*
981      * Patch from Scott Moomaw <scott@bridgewater.edu>
982      * to return the 'invalid info level' error if an
983      * unknown level was requested.
984      */
985     *rdata_len = 0;
986     *rparam_len = 6;
987     *rparam = REALLOC(*rparam,*rparam_len);
988     SSVALS(*rparam,0,ERRunknownlevel);
989     SSVAL(*rparam,2,0);
990     SSVAL(*rparam,4,0);
991     return(True);
992   }
993
994   queuecnt = 0;
995   for (i = 0; i < services; i++)
996     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
997       queuecnt++;
998   if (uLevel > 0) {
999     if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1000       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1001       return False;
1002     }
1003     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1004     if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1005       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1006       return False;
1007     }
1008     memset(status,0,queuecnt*sizeof(print_status_struct));
1009     if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1010       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1011       return False;
1012     }
1013     subcnt = 0;
1014     n = 0;
1015     for (i = 0; i < services; i++)
1016       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1017         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1018         subcnt += subcntarr[n];
1019         n++;
1020       }
1021   }
1022   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1023   desc.base = *rdata;
1024   desc.buflen = mdrcnt;
1025
1026   if (init_package(&desc,queuecnt,subcnt)) {
1027     n = 0;
1028     succnt = 0;
1029     for (i = 0; i < services; i++)
1030       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1031         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1032         n++;
1033         if (desc.errcode == NERR_Success) succnt = n;
1034       }
1035   }
1036
1037   SAFE_FREE(subcntarr);
1038  
1039   *rdata_len = desc.usedlen;
1040   *rparam_len = 8;
1041   *rparam = REALLOC(*rparam,*rparam_len);
1042   SSVALS(*rparam,0,desc.errcode);
1043   SSVAL(*rparam,2,0);
1044   SSVAL(*rparam,4,succnt);
1045   SSVAL(*rparam,6,queuecnt);
1046   
1047   for (i = 0; i < queuecnt; i++) {
1048     if (queue) SAFE_FREE(queue[i]);
1049   }
1050
1051   SAFE_FREE(queue);
1052   SAFE_FREE(status);
1053   
1054   return True;
1055 }
1056
1057 /****************************************************************************
1058   get info level for a server list query
1059   ****************************************************************************/
1060 static BOOL check_server_info(int uLevel, char* id)
1061 {
1062   switch( uLevel ) {
1063   case 0:
1064     if (strcmp(id,"B16") != 0) return False;
1065     break;
1066   case 1:
1067     if (strcmp(id,"B16BBDz") != 0) return False;
1068     break;
1069   default: 
1070     return False;
1071   }
1072   return True;
1073 }
1074
1075 struct srv_info_struct
1076 {
1077   fstring name;
1078   uint32 type;
1079   fstring comment;
1080   fstring domain;
1081   BOOL server_added;
1082 };
1083
1084
1085 /*******************************************************************
1086   get server info lists from the files saved by nmbd. Return the
1087   number of entries
1088   ******************************************************************/
1089 static int get_server_info(uint32 servertype, 
1090                            struct srv_info_struct **servers,
1091                            char *domain)
1092 {
1093   int count=0;
1094   int alloced=0;
1095   char **lines;
1096   BOOL local_list_only;
1097   int i;
1098
1099   lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1100   if (!lines) {
1101     DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1102     return(0);
1103   }
1104
1105   /* request for everything is code for request all servers */
1106   if (servertype == SV_TYPE_ALL) 
1107         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1108
1109   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1110
1111   DEBUG(4,("Servertype search: %8x\n",servertype));
1112
1113   for (i=0;lines[i];i++) {
1114     fstring stype;
1115     struct srv_info_struct *s;
1116     char *ptr = lines[i];
1117     BOOL ok = True;
1118
1119     if (!*ptr) continue;
1120     
1121     if (count == alloced) {
1122       struct srv_info_struct *ts;
1123       
1124       alloced += 10;
1125       ts = (struct srv_info_struct *)
1126         Realloc(*servers,sizeof(**servers)*alloced);
1127       if (!ts) {
1128         DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1129         return(0);
1130       }
1131       else *servers = ts;
1132       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1133     }
1134     s = &(*servers)[count];
1135     
1136     if (!next_token(&ptr,s->name   , NULL, sizeof(s->name))) continue;
1137     if (!next_token(&ptr,stype     , NULL, sizeof(stype))) continue;
1138     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1139     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1140       /* this allows us to cope with an old nmbd */
1141       pstrcpy(s->domain,global_myworkgroup); 
1142     }
1143     
1144     if (sscanf(stype,"%X",&s->type) != 1) { 
1145       DEBUG(4,("r:host file ")); 
1146       ok = False; 
1147     }
1148     
1149         /* Filter the servers/domains we return based on what was asked for. */
1150
1151         /* Check to see if we are being asked for a local list only. */
1152         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1153           DEBUG(4,("r: local list only"));
1154           ok = False;
1155         }
1156
1157     /* doesn't match up: don't want it */
1158     if (!(servertype & s->type)) { 
1159       DEBUG(4,("r:serv type ")); 
1160       ok = False; 
1161     }
1162     
1163     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1164         (s->type & SV_TYPE_DOMAIN_ENUM))
1165       {
1166         DEBUG(4,("s: dom mismatch "));
1167         ok = False;
1168       }
1169     
1170     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1171       {
1172         ok = False;
1173       }
1174     
1175         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1176         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1177
1178     if (ok)
1179       {
1180         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1181                  s->name, s->type, s->comment, s->domain));
1182         
1183         s->server_added = True;
1184         count++;
1185       }
1186     else
1187       {
1188         DEBUG(4,("%20s %8x %25s %15s\n",
1189                  s->name, s->type, s->comment, s->domain));
1190       }
1191   }
1192   
1193   file_lines_free(lines);
1194   return(count);
1195 }
1196
1197
1198 /*******************************************************************
1199   fill in a server info structure
1200   ******************************************************************/
1201 static int fill_srv_info(struct srv_info_struct *service, 
1202                          int uLevel, char **buf, int *buflen, 
1203                          char **stringbuf, int *stringspace, char *baseaddr)
1204 {
1205   int struct_len;
1206   char* p;
1207   char* p2;
1208   int l2;
1209   int len;
1210  
1211   switch (uLevel) {
1212   case 0: struct_len = 16; break;
1213   case 1: struct_len = 26; break;
1214   default: return -1;
1215   }  
1216  
1217   if (!buf)
1218     {
1219       len = 0;
1220       switch (uLevel) 
1221         {
1222         case 1:
1223           len = strlen(service->comment)+1;
1224           break;
1225         }
1226
1227       if (buflen) *buflen = struct_len;
1228       if (stringspace) *stringspace = len;
1229       return struct_len + len;
1230     }
1231   
1232   len = struct_len;
1233   p = *buf;
1234   if (*buflen < struct_len) return -1;
1235   if (stringbuf)
1236     {
1237       p2 = *stringbuf;
1238       l2 = *stringspace;
1239     }
1240   else
1241     {
1242       p2 = p + struct_len;
1243       l2 = *buflen - struct_len;
1244     }
1245   if (!baseaddr) baseaddr = p;
1246   
1247   switch (uLevel)
1248     {
1249     case 0:
1250             push_ascii(p,service->name, 15, STR_TERMINATE);
1251             break;
1252
1253     case 1:
1254             push_ascii(p,service->name,15, STR_TERMINATE);
1255             SIVAL(p,18,service->type);
1256             SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1257             len += CopyAndAdvance(&p2,service->comment,&l2);
1258             break;
1259     }
1260
1261   if (stringbuf)
1262     {
1263       *buf = p + struct_len;
1264       *buflen -= struct_len;
1265       *stringbuf = p2;
1266       *stringspace = l2;
1267     }
1268   else
1269     {
1270       *buf = p2;
1271       *buflen -= len;
1272     }
1273   return len;
1274 }
1275
1276
1277 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1278 {
1279   return(strcmp(s1->name,s2->name));
1280 }
1281
1282 /****************************************************************************
1283   view list of servers available (or possibly domains). The info is
1284   extracted from lists saved by nmbd on the local host
1285   ****************************************************************************/
1286 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1287                                int mdrcnt, int mprcnt, char **rdata, 
1288                                char **rparam, int *rdata_len, int *rparam_len)
1289 {
1290   char *str1 = param+2;
1291   char *str2 = skip_string(str1,1);
1292   char *p = skip_string(str2,1);
1293   int uLevel = SVAL(p,0);
1294   int buf_len = SVAL(p,2);
1295   uint32 servertype = IVAL(p,4);
1296   char *p2;
1297   int data_len, fixed_len, string_len;
1298   int f_len = 0, s_len = 0;
1299   struct srv_info_struct *servers=NULL;
1300   int counted=0,total=0;
1301   int i,missed;
1302   fstring domain;
1303   BOOL domain_request;
1304   BOOL local_request;
1305
1306   /* If someone sets all the bits they don't really mean to set
1307      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1308      known servers. */
1309
1310   if (servertype == SV_TYPE_ALL) 
1311     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1312
1313   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1314      any other bit (they may just set this bit on it's own) they 
1315      want all the locally seen servers. However this bit can be 
1316      set on its own so set the requested servers to be 
1317      ALL - DOMAIN_ENUM. */
1318
1319   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1320     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1321
1322   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1323   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1324
1325   p += 8;
1326
1327   if (!prefix_ok(str1,"WrLehD")) return False;
1328   if (!check_server_info(uLevel,str2)) return False;
1329   
1330   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1331   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1332   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1333
1334   if (strcmp(str1, "WrLehDz") == 0) {
1335           pull_ascii_fstring(domain, p);
1336   } else {
1337           fstrcpy(domain, global_myworkgroup);
1338   }
1339
1340   if (lp_browse_list())
1341     total = get_server_info(servertype,&servers,domain);
1342
1343   data_len = fixed_len = string_len = 0;
1344   missed = 0;
1345
1346   if (total > 0)
1347     qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1348
1349   {
1350     char *lastname=NULL;
1351
1352     for (i=0;i<total;i++)
1353     {
1354       struct srv_info_struct *s = &servers[i];
1355       if (lastname && strequal(lastname,s->name)) continue;
1356       lastname = s->name;
1357       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1358       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1359                s->name, s->type, s->comment, s->domain));
1360       
1361       if (data_len <= buf_len) {
1362           counted++;
1363           fixed_len += f_len;
1364           string_len += s_len;
1365       } else {
1366         missed++;
1367       }
1368     }
1369   }
1370
1371   *rdata_len = fixed_len + string_len;
1372   *rdata = REALLOC(*rdata,*rdata_len);
1373   memset(*rdata,'\0',*rdata_len);
1374   
1375   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1376   p = *rdata;
1377   f_len = fixed_len;
1378   s_len = string_len;
1379
1380   {
1381     char *lastname=NULL;
1382     int count2 = counted;
1383     for (i = 0; i < total && count2;i++)
1384       {
1385         struct srv_info_struct *s = &servers[i];
1386         if (lastname && strequal(lastname,s->name)) continue;
1387         lastname = s->name;
1388         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1389         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1390                  s->name, s->type, s->comment, s->domain));
1391         count2--;
1392       }
1393   }
1394   
1395   *rparam_len = 8;
1396   *rparam = REALLOC(*rparam,*rparam_len);
1397   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1398   SSVAL(*rparam,2,0);
1399   SSVAL(*rparam,4,counted);
1400   SSVAL(*rparam,6,counted+missed);
1401
1402   SAFE_FREE(servers);
1403
1404   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1405            domain,uLevel,counted,counted+missed));
1406
1407   return(True);
1408 }
1409
1410 /****************************************************************************
1411   command 0x34 - suspected of being a "Lookup Names" stub api
1412   ****************************************************************************/
1413 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1414                                int mdrcnt, int mprcnt, char **rdata, 
1415                                char **rparam, int *rdata_len, int *rparam_len)
1416 {
1417   char *str1 = param+2;
1418   char *str2 = skip_string(str1,1);
1419   char *p = skip_string(str2,1);
1420   int uLevel = SVAL(p,0);
1421   int buf_len = SVAL(p,2);
1422   int counted=0;
1423   int missed=0;
1424
1425         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1426                 str1, str2, p, uLevel, buf_len));
1427
1428   if (!prefix_ok(str1,"zWrLeh")) return False;
1429   
1430   *rdata_len = 0;
1431   
1432   *rparam_len = 8;
1433   *rparam = REALLOC(*rparam,*rparam_len);
1434
1435   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1436   SSVAL(*rparam,2,0);
1437   SSVAL(*rparam,4,counted);
1438   SSVAL(*rparam,6,counted+missed);
1439
1440   return(True);
1441 }
1442
1443 /****************************************************************************
1444   get info about a share
1445   ****************************************************************************/
1446 static BOOL check_share_info(int uLevel, char* id)
1447 {
1448   switch( uLevel ) {
1449   case 0:
1450     if (strcmp(id,"B13") != 0) return False;
1451     break;
1452   case 1:
1453     if (strcmp(id,"B13BWz") != 0) return False;
1454     break;
1455   case 2:
1456     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1457     break;
1458   case 91:
1459     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1460     break;
1461   default: return False;
1462   }
1463   return True;
1464 }
1465
1466 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1467                            char** buf, int* buflen,
1468                            char** stringbuf, int* stringspace, char* baseaddr)
1469 {
1470   int struct_len;
1471   char* p;
1472   char* p2;
1473   int l2;
1474   int len;
1475  
1476   switch( uLevel ) {
1477   case 0: struct_len = 13; break;
1478   case 1: struct_len = 20; break;
1479   case 2: struct_len = 40; break;
1480   case 91: struct_len = 68; break;
1481   default: return -1;
1482   }
1483   
1484  
1485   if (!buf)
1486     {
1487       len = 0;
1488       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1489       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1490       if (buflen) *buflen = struct_len;
1491       if (stringspace) *stringspace = len;
1492       return struct_len + len;
1493     }
1494   
1495   len = struct_len;
1496   p = *buf;
1497   if ((*buflen) < struct_len) return -1;
1498   if (stringbuf)
1499     {
1500       p2 = *stringbuf;
1501       l2 = *stringspace;
1502     }
1503   else
1504     {
1505       p2 = p + struct_len;
1506       l2 = (*buflen) - struct_len;
1507     }
1508   if (!baseaddr) baseaddr = p;
1509   
1510   push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1511   
1512   if (uLevel > 0)
1513     {
1514       int type;
1515       CVAL(p,13) = 0;
1516       type = STYPE_DISKTREE;
1517       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1518       if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
1519       SSVAL(p,14,type);         /* device type */
1520       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1521       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1522     }
1523   
1524   if (uLevel > 1)
1525     {
1526       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1527       SSVALS(p,22,-1);          /* max uses */
1528       SSVAL(p,24,1); /* current uses */
1529       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1530       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1531       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1532     }
1533   
1534   if (uLevel > 2)
1535     {
1536       memset(p+40,0,SHPWLEN+2);
1537       SSVAL(p,50,0);
1538       SIVAL(p,52,0);
1539       SSVAL(p,56,0);
1540       SSVAL(p,58,0);
1541       SIVAL(p,60,0);
1542       SSVAL(p,64,0);
1543       SSVAL(p,66,0);
1544     }
1545        
1546   if (stringbuf)
1547     {
1548       (*buf) = p + struct_len;
1549       (*buflen) -= struct_len;
1550       (*stringbuf) = p2;
1551       (*stringspace) = l2;
1552     }
1553   else
1554     {
1555       (*buf) = p2;
1556       (*buflen) -= len;
1557     }
1558   return len;
1559 }
1560
1561 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1562                                  int mdrcnt,int mprcnt,
1563                                  char **rdata,char **rparam,
1564                                  int *rdata_len,int *rparam_len)
1565 {
1566   char *str1 = param+2;
1567   char *str2 = skip_string(str1,1);
1568   char *netname = skip_string(str2,1);
1569   char *p = skip_string(netname,1);
1570   int uLevel = SVAL(p,0);
1571   int snum = find_service(netname);
1572   
1573   if (snum < 0) return False;
1574   
1575   /* check it's a supported varient */
1576   if (!prefix_ok(str1,"zWrLh")) return False;
1577   if (!check_share_info(uLevel,str2)) return False;
1578  
1579   *rdata = REALLOC(*rdata,mdrcnt);
1580   p = *rdata;
1581   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1582   if (*rdata_len < 0) return False;
1583  
1584   *rparam_len = 6;
1585   *rparam = REALLOC(*rparam,*rparam_len);
1586   SSVAL(*rparam,0,NERR_Success);
1587   SSVAL(*rparam,2,0);           /* converter word */
1588   SSVAL(*rparam,4,*rdata_len);
1589  
1590   return(True);
1591 }
1592
1593 /****************************************************************************
1594   view list of shares available
1595   ****************************************************************************/
1596 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1597                               int mdrcnt,int mprcnt,
1598                               char **rdata,char **rparam,
1599                               int *rdata_len,int *rparam_len)
1600 {
1601   char *str1 = param+2;
1602   char *str2 = skip_string(str1,1);
1603   char *p = skip_string(str2,1);
1604   int uLevel = SVAL(p,0);
1605   int buf_len = SVAL(p,2);
1606   char *p2;
1607   int count=lp_numservices();
1608   int total=0,counted=0;
1609   BOOL missed = False;
1610   int i;
1611   int data_len, fixed_len, string_len;
1612   int f_len = 0, s_len = 0;
1613  
1614   if (!prefix_ok(str1,"WrLeh")) return False;
1615   if (!check_share_info(uLevel,str2)) return False;
1616   
1617   data_len = fixed_len = string_len = 0;
1618   for (i=0;i<count;i++)
1619     if (lp_browseable(i) && lp_snum_ok(i))
1620     {
1621       total++;
1622       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1623       if (data_len <= buf_len)
1624       {
1625         counted++;
1626         fixed_len += f_len;
1627         string_len += s_len;
1628       }
1629       else
1630         missed = True;
1631     }
1632   *rdata_len = fixed_len + string_len;
1633   *rdata = REALLOC(*rdata,*rdata_len);
1634   memset(*rdata,0,*rdata_len);
1635   
1636   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1637   p = *rdata;
1638   f_len = fixed_len;
1639   s_len = string_len;
1640   for (i = 0; i < count;i++)
1641     if (lp_browseable(i) && lp_snum_ok(i))
1642       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1643         break;
1644   
1645   *rparam_len = 8;
1646   *rparam = REALLOC(*rparam,*rparam_len);
1647   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1648   SSVAL(*rparam,2,0);
1649   SSVAL(*rparam,4,counted);
1650   SSVAL(*rparam,6,total);
1651   
1652   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1653            counted,total,uLevel,
1654            buf_len,*rdata_len,mdrcnt));
1655   return(True);
1656 }
1657
1658
1659 /****************************************************************************
1660   view list of groups available
1661   ****************************************************************************/
1662 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1663                               int mdrcnt,int mprcnt,
1664                               char **rdata,char **rparam,
1665                               int *rdata_len,int *rparam_len)
1666 {
1667         char *str1 = param+2;
1668         char *str2 = skip_string(str1,1);
1669         char *p = skip_string(str2,1);
1670         int uLevel = SVAL(p,0);
1671         char *p2;
1672         int count=0;
1673
1674         if (!prefix_ok(str1,"WrLeh")) return False;
1675   
1676         /* check it's a supported variant */
1677         switch( uLevel )
1678         {
1679                 case 0: 
1680                         p2 = "B21"; 
1681                         break;
1682                 default: 
1683                         return False;
1684         }
1685
1686         if (strcmp(p2,str2) != 0) return False;
1687
1688         *rdata_len = mdrcnt + 1024;
1689         *rdata = REALLOC(*rdata,*rdata_len);
1690
1691         SSVAL(*rparam,0,NERR_Success);
1692         SSVAL(*rparam,2,0);             /* converter word */
1693
1694         p = *rdata;
1695
1696         /* XXXX we need a real SAM database some day */
1697         pstrcpy(p,"Users"); p += 21; count++;
1698         pstrcpy(p,"Domain Users"); p += 21; count++;
1699         pstrcpy(p,"Guests"); p += 21; count++;
1700         pstrcpy(p,"Domain Guests"); p += 21; count++;
1701
1702         *rdata_len = PTR_DIFF(p,*rdata);
1703
1704         *rparam_len = 8;
1705         *rparam = REALLOC(*rparam,*rparam_len);
1706
1707         SSVAL(*rparam,4,count); /* is this right?? */
1708         SSVAL(*rparam,6,count); /* is this right?? */
1709
1710         DEBUG(3,("api_RNetGroupEnum gave %d entries\n", count));
1711
1712         return(True);
1713 }
1714
1715 /****************************************************************************
1716   view list of groups available
1717   ****************************************************************************/
1718 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1719                               int mdrcnt,int mprcnt,
1720                               char **rdata,char **rparam,
1721                               int *rdata_len,int *rparam_len)
1722 {
1723         char *str1 = param+2;
1724         char *str2 = skip_string(str1,1);
1725         char *p = skip_string(str2,1);
1726         int uLevel = SVAL(p,0);
1727         char *p2;
1728         int count=0;
1729
1730         if (!prefix_ok(str1,"WrLeh")) return False;
1731   
1732         /* check it's a supported variant */
1733         switch( uLevel )
1734         {
1735                 case 0: 
1736                         p2 = "B21"; 
1737                         break;
1738                 default: 
1739                         return False;
1740         }
1741
1742         if (strcmp(p2,str2) != 0) return False;
1743
1744         *rdata_len = mdrcnt + 1024;
1745         *rdata = REALLOC(*rdata,*rdata_len);
1746
1747         SSVAL(*rparam,0,NERR_Success);
1748         SSVAL(*rparam,2,0);             /* converter word */
1749
1750         p = *rdata;
1751
1752         /* XXXX we need a real SAM database some day */
1753         pstrcpy(p,"Users"); p += 21; count++;
1754         pstrcpy(p,"Domain Users"); p += 21; count++;
1755         pstrcpy(p,"Guests"); p += 21; count++;
1756         pstrcpy(p,"Domain Guests"); p += 21; count++;
1757
1758         *rdata_len = PTR_DIFF(p,*rdata);
1759
1760         *rparam_len = 8;
1761         *rparam = REALLOC(*rparam,*rparam_len);
1762
1763         SSVAL(*rparam,4,count); /* is this right?? */
1764         SSVAL(*rparam,6,count); /* is this right?? */
1765
1766         DEBUG(3,("api_RNetUserEnum gave %d entries\n", count));
1767
1768         return(True);
1769 }
1770
1771
1772
1773 /****************************************************************************
1774   get the time of day info
1775   ****************************************************************************/
1776 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1777                              int mdrcnt,int mprcnt,
1778                              char **rdata,char **rparam,
1779                              int *rdata_len,int *rparam_len)
1780 {
1781   char *p;
1782   *rparam_len = 4;
1783   *rparam = REALLOC(*rparam,*rparam_len);
1784
1785   *rdata_len = 21;
1786   *rdata = REALLOC(*rdata,*rdata_len);
1787
1788   SSVAL(*rparam,0,NERR_Success);
1789   SSVAL(*rparam,2,0);           /* converter word */
1790
1791   p = *rdata;
1792
1793   {
1794     struct tm *t;
1795     time_t unixdate = time(NULL);
1796
1797     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1798                                     by NT in a "net time" operation,
1799                                     it seems to ignore the one below */
1800
1801     /* the client expects to get localtime, not GMT, in this bit 
1802        (I think, this needs testing) */
1803     t = LocalTime(&unixdate);
1804
1805     SIVAL(p,4,0);               /* msecs ? */
1806     CVAL(p,8) = t->tm_hour;
1807     CVAL(p,9) = t->tm_min;
1808     CVAL(p,10) = t->tm_sec;
1809     CVAL(p,11) = 0;             /* hundredths of seconds */
1810     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1811     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1812     CVAL(p,16) = t->tm_mday;
1813     CVAL(p,17) = t->tm_mon + 1;
1814     SSVAL(p,18,1900+t->tm_year);
1815     CVAL(p,20) = t->tm_wday;
1816   }
1817
1818
1819   return(True);
1820 }
1821
1822 /****************************************************************************
1823  Set the user password.
1824 *****************************************************************************/
1825
1826 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1827                                 int mdrcnt,int mprcnt,
1828                                 char **rdata,char **rparam,
1829                                 int *rdata_len,int *rparam_len)
1830 {
1831   char *p = skip_string(param+2,2);
1832   fstring user;
1833   fstring pass1,pass2;
1834
1835   struct passwd *passwd;
1836
1837   pull_ascii_fstring(user,p);
1838
1839   p = skip_string(p,1);
1840
1841   memset(pass1,'\0',sizeof(pass1));
1842   memset(pass2,'\0',sizeof(pass2));
1843   memcpy(pass1,p,16);
1844   memcpy(pass2,p+16,16);
1845
1846   *rparam_len = 4;
1847   *rparam = REALLOC(*rparam,*rparam_len);
1848
1849   *rdata_len = 0;
1850
1851   SSVAL(*rparam,0,NERR_badpass);
1852   SSVAL(*rparam,2,0);           /* converter word */
1853
1854   DEBUG(3,("Set password for <%s>\n",user));
1855
1856   /*
1857    * Pass the user through the NT -> unix user mapping
1858    * function.
1859    */
1860
1861   (void)map_username(user);
1862
1863   /*
1864    * Do any UNIX username case mangling.
1865    */
1866   passwd = Get_Pwnam( user, True);
1867
1868   /*
1869    * Attempt to verify the old password against smbpasswd entries
1870    * Win98 clients send old and new password in plaintext for this call.
1871    */
1872
1873   {
1874     fstring saved_pass2;
1875     SAM_ACCOUNT *sampass=NULL;
1876
1877     /*
1878      * Save the new password as change_oem_password overwrites it
1879      * with zeros.
1880      */
1881
1882     fstrcpy(saved_pass2, pass2);
1883
1884     if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1885         change_oem_password(sampass,pass2))
1886     {
1887       SSVAL(*rparam,0,NERR_Success);
1888
1889       /*
1890        * If unix password sync was requested, attempt to change
1891        * the /etc/passwd database also. Return failure if this cannot
1892        * be done.
1893        */
1894
1895       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1896         SSVAL(*rparam,0,NERR_badpass);
1897     }
1898         pdb_free_sam(&sampass);
1899  }
1900   
1901
1902   /*
1903    * If the above failed, attempt the plaintext password change.
1904    * This tests against the /etc/passwd database only.
1905    */
1906
1907   if(SVAL(*rparam,0) != NERR_Success)
1908   {
1909           if NT_STATUS_IS_OK(pass_check(passwd, user, pass1, 
1910                                         strlen(pass1), NULL, False)) 
1911                   {
1912                           if (chgpasswd(user,pass1,pass2,False)) {
1913                                   SSVAL(*rparam,0,NERR_Success);
1914                           }
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       SAFE_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   SAFE_FREE(queue);
2943   SAFE_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   SAFE_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   SAFE_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   SAFE_FREE(rdata);
3482   SAFE_FREE(rparam);
3483   
3484   return -1;
3485 }