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