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