get rid of some sompiler warnings on IRIX
[ddiss/samba.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 (NULL, &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( NULL, &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( NULL, &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)) {
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
1932                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
1933
1934                         become_root();
1935                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2))) {
1936                                 SSVAL(*rparam,0,NERR_Success);
1937                         }
1938                         unbecome_root();
1939
1940                         free_server_info(&server_info);
1941                 }
1942                 data_blob_clear_free(&password);
1943         }
1944
1945         /*
1946          * If the plaintext change failed, attempt
1947          * the old encrypted method. NT will generate this
1948          * after trying the samr method. Note that this
1949          * method is done as a last resort as this
1950          * password change method loses the NT password hash
1951          * and cannot change the UNIX password as no plaintext
1952          * is received.
1953          */
1954
1955         if(SVAL(*rparam,0) != NERR_Success) {
1956                 SAM_ACCOUNT *hnd = NULL;
1957
1958                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
1959                         become_root();
1960                         if (change_lanman_password(hnd,(uchar *)pass2)) {
1961                                 SSVAL(*rparam,0,NERR_Success);
1962                         }
1963                         unbecome_root();
1964                         pdb_free_sam(&hnd);
1965                 }
1966         }
1967
1968         memset((char *)pass1,'\0',sizeof(fstring));
1969         memset((char *)pass2,'\0',sizeof(fstring));      
1970          
1971         return(True);
1972 }
1973
1974 /****************************************************************************
1975   Set the user password (SamOEM version - gets plaintext).
1976 ****************************************************************************/
1977
1978 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1979                                 int mdrcnt,int mprcnt,
1980                                 char **rdata,char **rparam,
1981                                 int *rdata_len,int *rparam_len)
1982 {
1983   fstring user;
1984   char *p = param + 2;
1985   *rparam_len = 2;
1986   *rparam = REALLOC(*rparam,*rparam_len);
1987
1988   *rdata_len = 0;
1989
1990   SSVAL(*rparam,0,NERR_badpass);
1991
1992   /*
1993    * Check the parameter definition is correct.
1994    */
1995   if(!strequal(param + 2, "zsT")) {
1996     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1997     return False;
1998   }
1999   p = skip_string(p, 1);
2000
2001   if(!strequal(p, "B516B16")) {
2002     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2003     return False;
2004   }
2005   p = skip_string(p,1);
2006
2007   p += pull_ascii_fstring(user,p);
2008
2009   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2010
2011   /*
2012    * Pass the user through the NT -> unix user mapping
2013    * function.
2014    */
2015
2016   (void)map_username(user);
2017
2018   if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL)))
2019   {
2020     SSVAL(*rparam,0,NERR_Success);
2021   }
2022
2023   return(True);
2024 }
2025
2026 /****************************************************************************
2027   delete a print job
2028   Form: <W> <> 
2029   ****************************************************************************/
2030 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2031                                 int mdrcnt,int mprcnt,
2032                                 char **rdata,char **rparam,
2033                                 int *rdata_len,int *rparam_len)
2034 {
2035         int function = SVAL(param,0);
2036         char *str1 = param+2;
2037         char *str2 = skip_string(str1,1);
2038         char *p = skip_string(str2,1);
2039         uint32 jobid;
2040         int snum;
2041         int errcode;
2042         extern struct current_user current_user;
2043         WERROR werr = WERR_OK;
2044
2045         if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid))
2046                 return False;
2047
2048         /* check it's a supported varient */
2049         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2050                 return(False);
2051
2052         *rparam_len = 4;
2053         *rparam = REALLOC(*rparam,*rparam_len); 
2054         *rdata_len = 0;
2055
2056         if (!print_job_exists(snum, jobid)) {
2057                 errcode = NERR_JobNotFound;
2058                 goto out;
2059         }
2060
2061         errcode = NERR_notsupported;
2062         
2063         switch (function) {
2064         case 81:                /* delete */ 
2065                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2066                         errcode = NERR_Success;
2067                 break;
2068         case 82:                /* pause */
2069                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2070                         errcode = NERR_Success;
2071                 break;
2072         case 83:                /* resume */
2073                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2074                         errcode = NERR_Success;
2075                 break;
2076         }
2077
2078         if (!W_ERROR_IS_OK(werr))
2079                 errcode = W_ERROR_V(werr);
2080         
2081  out:
2082         SSVAL(*rparam,0,errcode);       
2083         SSVAL(*rparam,2,0);             /* converter word */
2084
2085         return(True);
2086 }
2087
2088 /****************************************************************************
2089   Purge a print queue - or pause or resume it.
2090   ****************************************************************************/
2091 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2092                                  int mdrcnt,int mprcnt,
2093                                  char **rdata,char **rparam,
2094                                  int *rdata_len,int *rparam_len)
2095 {
2096         int function = SVAL(param,0);
2097         char *str1 = param+2;
2098         char *str2 = skip_string(str1,1);
2099         char *QueueName = skip_string(str2,1);
2100         int errcode = NERR_notsupported;
2101         int snum;
2102         WERROR werr = WERR_OK;
2103         extern struct current_user current_user;
2104
2105         /* check it's a supported varient */
2106         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2107                 return(False);
2108
2109         *rparam_len = 4;
2110         *rparam = REALLOC(*rparam,*rparam_len);
2111         *rdata_len = 0;
2112
2113         snum = print_queue_snum(QueueName);
2114
2115         if (snum == -1) {
2116                 errcode = NERR_JobNotFound;
2117                 goto out;
2118         }
2119
2120         switch (function) {
2121         case 74: /* Pause queue */
2122                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2123                 break;
2124         case 75: /* Resume queue */
2125                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2126                 break;
2127         case 103: /* Purge */
2128                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2129                 break;
2130         }
2131
2132         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2133
2134  out:
2135         SSVAL(*rparam,0,errcode);
2136         SSVAL(*rparam,2,0);             /* converter word */
2137
2138         return(True);
2139 }
2140
2141
2142 /****************************************************************************
2143   set the property of a print job (undocumented?)
2144   ? function = 0xb -> set name of print job
2145   ? function = 0x6 -> move print job up/down
2146   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2147   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2148 ****************************************************************************/
2149 static int check_printjob_info(struct pack_desc* desc,
2150                                int uLevel, char* id)
2151 {
2152         desc->subformat = NULL;
2153         switch( uLevel ) {
2154         case 0: desc->format = "W"; break;
2155         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2156         case 2: desc->format = "WWzWWDDzz"; break;
2157         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2158         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2159         default: return False;
2160         }
2161         if (strcmp(desc->format,id) != 0) return False;
2162         return True;
2163 }
2164
2165 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2166                              int mdrcnt,int mprcnt,
2167                              char **rdata,char **rparam,
2168                              int *rdata_len,int *rparam_len)
2169 {
2170         struct pack_desc desc;
2171         char *str1 = param+2;
2172         char *str2 = skip_string(str1,1);
2173         char *p = skip_string(str2,1);
2174         uint32 jobid;
2175         int snum;
2176         int uLevel = SVAL(p,2);
2177         int function = SVAL(p,4);
2178         int place, errcode;
2179
2180         if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid))
2181                 return False;
2182         *rparam_len = 4;
2183         *rparam = REALLOC(*rparam,*rparam_len);
2184   
2185         *rdata_len = 0;
2186         
2187         /* check it's a supported varient */
2188         if ((strcmp(str1,"WWsTP")) || 
2189             (!check_printjob_info(&desc,uLevel,str2)))
2190                 return(False);
2191
2192         if (!print_job_exists(snum, jobid)) {
2193                 errcode=NERR_JobNotFound;
2194                 goto out;
2195         }
2196
2197         errcode = NERR_notsupported;
2198
2199         switch (function) {
2200         case 0x6:
2201                 /* change job place in the queue, 
2202                    data gives the new place */
2203                 place = SVAL(data,0);
2204                 if (print_job_set_place(snum, jobid, place)) {
2205                         errcode=NERR_Success;
2206                 }
2207                 break;
2208
2209         case 0xb:   
2210                 /* change print job name, data gives the name */
2211                 if (print_job_set_name(snum, jobid, data)) {
2212                         errcode=NERR_Success;
2213                 }
2214                 break;
2215
2216         default:
2217                 return False;
2218         }
2219
2220  out:
2221         SSVALS(*rparam,0,errcode);
2222         SSVAL(*rparam,2,0);             /* converter word */
2223         
2224         return(True);
2225 }
2226
2227
2228 /****************************************************************************
2229   get info about the server
2230   ****************************************************************************/
2231 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2232                                   int mdrcnt,int mprcnt,
2233                                   char **rdata,char **rparam,
2234                                   int *rdata_len,int *rparam_len)
2235 {
2236   char *str1 = param+2;
2237   char *str2 = skip_string(str1,1);
2238   char *p = skip_string(str2,1);
2239   int uLevel = SVAL(p,0);
2240   char *p2;
2241   int struct_len;
2242
2243   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2244
2245   /* check it's a supported varient */
2246   if (!prefix_ok(str1,"WrLh")) return False;
2247   switch( uLevel ) {
2248   case 0:
2249     if (strcmp(str2,"B16") != 0) return False;
2250     struct_len = 16;
2251     break;
2252   case 1:
2253     if (strcmp(str2,"B16BBDz") != 0) return False;
2254     struct_len = 26;
2255     break;
2256   case 2:
2257     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2258         != 0) return False;
2259     struct_len = 134;
2260     break;
2261   case 3:
2262     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2263         != 0) return False;
2264     struct_len = 144;
2265     break;
2266   case 20:
2267     if (strcmp(str2,"DN") != 0) return False;
2268     struct_len = 6;
2269     break;
2270   case 50:
2271     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2272     struct_len = 42;
2273     break;
2274   default: return False;
2275   }
2276
2277   *rdata_len = mdrcnt;
2278   *rdata = REALLOC(*rdata,*rdata_len);
2279
2280   p = *rdata;
2281   p2 = p + struct_len;
2282   if (uLevel != 20) {
2283     srvstr_push(NULL, p,local_machine,16, 
2284                 STR_ASCII|STR_UPPER|STR_TERMINATE);
2285   }
2286   p += 16;
2287   if (uLevel > 0)
2288     {
2289       struct srv_info_struct *servers=NULL;
2290       int i,count;
2291       pstring comment;
2292       uint32 servertype= lp_default_server_announce();
2293
2294       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2295
2296       if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2297         for (i=0;i<count;i++)
2298           if (strequal(servers[i].name,local_machine))
2299       {
2300             servertype = servers[i].type;
2301             pstrcpy(comment,servers[i].comment);            
2302           }
2303       }
2304       SAFE_FREE(servers);
2305
2306       SCVAL(p,0,lp_major_announce_version());
2307       SCVAL(p,1,lp_minor_announce_version());
2308       SIVAL(p,2,servertype);
2309
2310       if (mdrcnt == struct_len) {
2311         SIVAL(p,6,0);
2312       } else {
2313         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2314         standard_sub_conn(conn,comment,sizeof(comment));
2315         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2316         p2 = skip_string(p2,1);
2317       }
2318     }
2319   if (uLevel > 1)
2320     {
2321       return False;             /* not yet implemented */
2322     }
2323
2324   *rdata_len = PTR_DIFF(p2,*rdata);
2325
2326   *rparam_len = 6;
2327   *rparam = REALLOC(*rparam,*rparam_len);
2328   SSVAL(*rparam,0,NERR_Success);
2329   SSVAL(*rparam,2,0);           /* converter word */
2330   SSVAL(*rparam,4,*rdata_len);
2331
2332   return(True);
2333 }
2334
2335
2336 /****************************************************************************
2337   get info about the server
2338   ****************************************************************************/
2339 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2340                                 int mdrcnt,int mprcnt,
2341                                 char **rdata,char **rparam,
2342                                 int *rdata_len,int *rparam_len)
2343 {
2344   char *str1 = param+2;
2345   char *str2 = skip_string(str1,1);
2346   char *p = skip_string(str2,1);
2347   char *p2;
2348   extern userdom_struct current_user_info;
2349   int level = SVAL(p,0);
2350
2351   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2352
2353   *rparam_len = 6;
2354   *rparam = REALLOC(*rparam,*rparam_len);
2355
2356   /* check it's a supported varient */
2357   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2358     return(False);
2359
2360   *rdata_len = mdrcnt + 1024;
2361   *rdata = REALLOC(*rdata,*rdata_len);
2362
2363   SSVAL(*rparam,0,NERR_Success);
2364   SSVAL(*rparam,2,0);           /* converter word */
2365
2366   p = *rdata;
2367   p2 = p + 22;
2368
2369
2370   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2371   pstrcpy(p2,local_machine);
2372   strupper_m(p2);
2373   p2 = skip_string(p2,1);
2374   p += 4;
2375
2376   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2377   pstrcpy(p2,current_user_info.smb_name);
2378   p2 = skip_string(p2,1);
2379   p += 4;
2380
2381   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2382   pstrcpy(p2,lp_workgroup());
2383   strupper_m(p2);
2384   p2 = skip_string(p2,1);
2385   p += 4;
2386
2387   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2388   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2389   p += 2;
2390
2391   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2392   pstrcpy(p2,lp_workgroup());   /* don't know.  login domain?? */
2393   p2 = skip_string(p2,1);
2394   p += 4;
2395
2396   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2397   pstrcpy(p2,"");
2398   p2 = skip_string(p2,1);
2399   p += 4;
2400
2401   *rdata_len = PTR_DIFF(p2,*rdata);
2402
2403   SSVAL(*rparam,4,*rdata_len);
2404
2405   return(True);
2406 }
2407
2408 /****************************************************************************
2409   get info about a user
2410
2411     struct user_info_11 {
2412         char                usri11_name[21];  0-20 
2413         char                usri11_pad;       21 
2414         char                *usri11_comment;  22-25 
2415         char            *usri11_usr_comment;  26-29
2416         unsigned short      usri11_priv;      30-31
2417         unsigned long       usri11_auth_flags; 32-35
2418         long                usri11_password_age; 36-39
2419         char                *usri11_homedir; 40-43
2420         char            *usri11_parms; 44-47
2421         long                usri11_last_logon; 48-51
2422         long                usri11_last_logoff; 52-55
2423         unsigned short      usri11_bad_pw_count; 56-57
2424         unsigned short      usri11_num_logons; 58-59
2425         char                *usri11_logon_server; 60-63
2426         unsigned short      usri11_country_code; 64-65
2427         char            *usri11_workstations; 66-69
2428         unsigned long       usri11_max_storage; 70-73
2429         unsigned short      usri11_units_per_week; 74-75
2430         unsigned char       *usri11_logon_hours; 76-79
2431         unsigned short      usri11_code_page; 80-81
2432     };
2433
2434 where:
2435
2436   usri11_name specifies the user name for which information is retireved
2437
2438   usri11_pad aligns the next data structure element to a word boundary
2439
2440   usri11_comment is a null terminated ASCII comment
2441
2442   usri11_user_comment is a null terminated ASCII comment about the user
2443
2444   usri11_priv specifies the level of the privilege assigned to the user.
2445        The possible values are:
2446
2447 Name             Value  Description
2448 USER_PRIV_GUEST  0      Guest privilege
2449 USER_PRIV_USER   1      User privilege
2450 USER_PRV_ADMIN   2      Administrator privilege
2451
2452   usri11_auth_flags specifies the account operator privileges. The
2453        possible values are:
2454
2455 Name            Value   Description
2456 AF_OP_PRINT     0       Print operator
2457
2458
2459 Leach, Naik                                        [Page 28]
2460 \f
2461
2462
2463 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2464
2465
2466 AF_OP_COMM      1       Communications operator
2467 AF_OP_SERVER    2       Server operator
2468 AF_OP_ACCOUNTS  3       Accounts operator
2469
2470
2471   usri11_password_age specifies how many seconds have elapsed since the
2472        password was last changed.
2473
2474   usri11_home_dir points to a null terminated ASCII string that contains
2475        the path name of the user's home directory.
2476
2477   usri11_parms points to a null terminated ASCII string that is set
2478        aside for use by applications.
2479
2480   usri11_last_logon specifies the time when the user last logged on.
2481        This value is stored as the number of seconds elapsed since
2482        00:00:00, January 1, 1970.
2483
2484   usri11_last_logoff specifies the time when the user last logged off.
2485        This value is stored as the number of seconds elapsed since
2486        00:00:00, January 1, 1970. A value of 0 means the last logoff
2487        time is unknown.
2488
2489   usri11_bad_pw_count specifies the number of incorrect passwords
2490        entered since the last successful logon.
2491
2492   usri11_log1_num_logons specifies the number of times this user has
2493        logged on. A value of -1 means the number of logons is unknown.
2494
2495   usri11_logon_server points to a null terminated ASCII string that
2496        contains the name of the server to which logon requests are sent.
2497        A null string indicates logon requests should be sent to the
2498        domain controller.
2499
2500   usri11_country_code specifies the country code for the user's language
2501        of choice.
2502
2503   usri11_workstations points to a null terminated ASCII string that
2504        contains the names of workstations the user may log on from.
2505        There may be up to 8 workstations, with the names separated by
2506        commas. A null strings indicates there are no restrictions.
2507
2508   usri11_max_storage specifies the maximum amount of disk space the user
2509        can occupy. A value of 0xffffffff indicates there are no
2510        restrictions.
2511
2512   usri11_units_per_week specifies the equal number of time units into
2513        which a week is divided. This value must be equal to 168.
2514
2515   usri11_logon_hours points to a 21 byte (168 bits) string that
2516        specifies the time during which the user can log on. Each bit
2517        represents one unique hour in a week. The first bit (bit 0, word
2518        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2519
2520
2521
2522 Leach, Naik                                        [Page 29]
2523 \f
2524
2525
2526 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2527
2528
2529        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2530        are no restrictions.
2531
2532   usri11_code_page specifies the code page for the user's language of
2533        choice
2534
2535 All of the pointers in this data structure need to be treated
2536 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2537 to be ignored. The converter word returned in the parameters section
2538 needs to be subtracted from the lower 16 bits to calculate an offset
2539 into the return buffer where this ASCII string resides.
2540
2541 There is no auxiliary data in the response.
2542
2543   ****************************************************************************/
2544
2545 #define usri11_name           0 
2546 #define usri11_pad            21
2547 #define usri11_comment        22
2548 #define usri11_usr_comment    26
2549 #define usri11_full_name      30
2550 #define usri11_priv           34
2551 #define usri11_auth_flags     36
2552 #define usri11_password_age   40
2553 #define usri11_homedir        44
2554 #define usri11_parms          48
2555 #define usri11_last_logon     52
2556 #define usri11_last_logoff    56
2557 #define usri11_bad_pw_count   60
2558 #define usri11_num_logons     62
2559 #define usri11_logon_server   64
2560 #define usri11_country_code   68
2561 #define usri11_workstations   70
2562 #define usri11_max_storage    74
2563 #define usri11_units_per_week 78
2564 #define usri11_logon_hours    80
2565 #define usri11_code_page      84
2566 #define usri11_end            86
2567
2568 #define USER_PRIV_GUEST 0
2569 #define USER_PRIV_USER 1
2570 #define USER_PRIV_ADMIN 2
2571
2572 #define AF_OP_PRINT     0 
2573 #define AF_OP_COMM      1
2574 #define AF_OP_SERVER    2
2575 #define AF_OP_ACCOUNTS  3
2576
2577
2578 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2579                                 int mdrcnt,int mprcnt,
2580                                 char **rdata,char **rparam,
2581                                 int *rdata_len,int *rparam_len)
2582 {
2583         char *str1 = param+2;
2584         char *str2 = skip_string(str1,1);
2585         char *UserName = skip_string(str2,1);
2586         char *p = skip_string(UserName,1);
2587         int uLevel = SVAL(p,0);
2588         char *p2;
2589         const char *level_string;
2590
2591     /* get NIS home of a previously validated user - simeon */
2592     /* With share level security vuid will always be zero.
2593        Don't depend on vuser being non-null !!. JRA */
2594     user_struct *vuser = get_valid_user_struct(vuid);
2595     if(vuser != NULL)
2596       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2597                vuser->user.unix_name));
2598
2599     *rparam_len = 6;
2600     *rparam = REALLOC(*rparam,*rparam_len);
2601
2602     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2603   
2604         /* check it's a supported variant */
2605         if (strcmp(str1,"zWrLh") != 0) return False;
2606         switch( uLevel )
2607         {
2608                 case 0: level_string = "B21"; break;
2609                 case 1: level_string = "B21BB16DWzzWz"; break;
2610                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2611                 case 10: level_string = "B21Bzzz"; break;
2612                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2613                 default: return False;
2614         }
2615
2616         if (strcmp(level_string,str2) != 0) return False;
2617
2618         *rdata_len = mdrcnt + 1024;
2619         *rdata = REALLOC(*rdata,*rdata_len);
2620
2621         SSVAL(*rparam,0,NERR_Success);
2622         SSVAL(*rparam,2,0);             /* converter word */
2623
2624         p = *rdata;
2625         p2 = p + usri11_end;
2626
2627         memset(p,0,21); 
2628         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2629
2630         if (uLevel > 0)
2631         {
2632                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2633                 *p2 = 0;
2634         }
2635         if (uLevel >= 10)
2636         {
2637                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2638                 pstrcpy(p2,"Comment");
2639                 p2 = skip_string(p2,1);
2640
2641                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2642                 pstrcpy(p2,"UserComment");
2643                 p2 = skip_string(p2,1);
2644
2645                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2646                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2647                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2648                 p2 = skip_string(p2,1);
2649         }
2650
2651         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2652         {         
2653                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2654                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2655                 SIVALS(p,usri11_password_age,-1);               /* password age */
2656                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2657                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
2658                 p2 = skip_string(p2,1);
2659                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2660                 pstrcpy(p2,"");
2661                 p2 = skip_string(p2,1);
2662                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2663                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2664                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2665                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2666                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2667                 pstrcpy(p2,"\\\\*");
2668                 p2 = skip_string(p2,1);
2669                 SSVAL(p,usri11_country_code,0);         /* country code */
2670
2671                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2672                 pstrcpy(p2,"");
2673                 p2 = skip_string(p2,1);
2674
2675                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2676                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2677                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2678
2679                 /* a simple way to get logon hours at all times. */
2680                 memset(p2,0xff,21);
2681                 SCVAL(p2,21,0);           /* fix zero termination */
2682                 p2 = skip_string(p2,1);
2683
2684                 SSVAL(p,usri11_code_page,0);            /* code page */
2685         }
2686         if (uLevel == 1 || uLevel == 2)
2687         {
2688                 memset(p+22,' ',16);    /* password */
2689                 SIVALS(p,38,-1);                /* password age */
2690                 SSVAL(p,42,
2691                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2692                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2693                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
2694                 p2 = skip_string(p2,1);
2695                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2696                 *p2++ = 0;
2697                 SSVAL(p,52,0);          /* flags */
2698                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2699                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
2700                 p2 = skip_string(p2,1);
2701                 if (uLevel == 2)
2702                 {
2703                         SIVAL(p,60,0);          /* auth_flags */
2704                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2705                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2706                         p2 = skip_string(p2,1);
2707                         SIVAL(p,68,0);          /* urs_comment */
2708                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2709                         pstrcpy(p2,"");
2710                         p2 = skip_string(p2,1);
2711                         SIVAL(p,76,0);          /* workstations */
2712                         SIVAL(p,80,0);          /* last_logon */
2713                         SIVAL(p,84,0);          /* last_logoff */
2714                         SIVALS(p,88,-1);                /* acct_expires */
2715                         SIVALS(p,92,-1);                /* max_storage */
2716                         SSVAL(p,96,168);        /* units_per_week */
2717                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2718                         memset(p2,-1,21);
2719                         p2 += 21;
2720                         SSVALS(p,102,-1);       /* bad_pw_count */
2721                         SSVALS(p,104,-1);       /* num_logons */
2722                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2723                         pstrcpy(p2,"\\\\%L");
2724                         standard_sub_conn(conn, p2,0);
2725                         p2 = skip_string(p2,1);
2726                         SSVAL(p,110,49);        /* country_code */
2727                         SSVAL(p,112,860);       /* code page */
2728                 }
2729         }
2730
2731         *rdata_len = PTR_DIFF(p2,*rdata);
2732
2733         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2734
2735         return(True);
2736 }
2737
2738 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2739                                 int mdrcnt,int mprcnt,
2740                                 char **rdata,char **rparam,
2741                                 int *rdata_len,int *rparam_len)
2742 {
2743   char *str1 = param+2;
2744   char *str2 = skip_string(str1,1);
2745   char *p = skip_string(str2,1);
2746   int uLevel;
2747   struct pack_desc desc;
2748   char* name;
2749     /* With share level security vuid will always be zero.
2750        Don't depend on vuser being non-null !!. JRA */
2751     user_struct *vuser = get_valid_user_struct(vuid);
2752     if(vuser != NULL)
2753       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2754                vuser->user.unix_name));
2755
2756   uLevel = SVAL(p,0);
2757   name = p + 2;
2758
2759   memset((char *)&desc,'\0',sizeof(desc));
2760
2761   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2762
2763   /* check it's a supported varient */
2764   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2765   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2766   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2767   desc.base = *rdata;
2768   desc.buflen = mdrcnt;
2769   desc.subformat = NULL;
2770   desc.format = str2;
2771   
2772   if (init_package(&desc,1,0))
2773   {
2774     PACKI(&desc,"W",0);         /* code */
2775     PACKS(&desc,"B21",name);    /* eff. name */
2776     PACKS(&desc,"B","");                /* pad */
2777     PACKI(&desc,"W",
2778           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2779     PACKI(&desc,"D",0);         /* auth flags XXX */
2780     PACKI(&desc,"W",0);         /* num logons */
2781     PACKI(&desc,"W",0);         /* bad pw count */
2782     PACKI(&desc,"D",0);         /* last logon */
2783     PACKI(&desc,"D",-1);                /* last logoff */
2784     PACKI(&desc,"D",-1);                /* logoff time */
2785     PACKI(&desc,"D",-1);                /* kickoff time */
2786     PACKI(&desc,"D",0);         /* password age */
2787     PACKI(&desc,"D",0);         /* password can change */
2788     PACKI(&desc,"D",-1);                /* password must change */
2789     {
2790       fstring mypath;
2791       fstrcpy(mypath,"\\\\");
2792       fstrcat(mypath,local_machine);
2793       strupper_m(mypath);
2794       PACKS(&desc,"z",mypath); /* computer */
2795     }
2796     PACKS(&desc,"z",lp_workgroup());/* domain */
2797
2798     PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :"");           /* script path */
2799
2800     PACKI(&desc,"D",0x00000000);                /* reserved */
2801   }
2802
2803   *rdata_len = desc.usedlen;
2804   *rparam_len = 6;
2805   *rparam = REALLOC(*rparam,*rparam_len);
2806   SSVALS(*rparam,0,desc.errcode);
2807   SSVAL(*rparam,2,0);
2808   SSVAL(*rparam,4,desc.neededlen);
2809
2810   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2811   return(True);
2812 }
2813
2814
2815 /****************************************************************************
2816   api_WAccessGetUserPerms
2817   ****************************************************************************/
2818 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2819                                     int mdrcnt,int mprcnt,
2820                                     char **rdata,char **rparam,
2821                                     int *rdata_len,int *rparam_len)
2822 {
2823   char *str1 = param+2;
2824   char *str2 = skip_string(str1,1);
2825   char *user = skip_string(str2,1);
2826   char *resource = skip_string(user,1);
2827
2828   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2829
2830   /* check it's a supported varient */
2831   if (strcmp(str1,"zzh") != 0) return False;
2832   if (strcmp(str2,"") != 0) return False;
2833
2834   *rparam_len = 6;
2835   *rparam = REALLOC(*rparam,*rparam_len);
2836   SSVALS(*rparam,0,0);          /* errorcode */
2837   SSVAL(*rparam,2,0);           /* converter word */
2838   SSVAL(*rparam,4,0x7f);        /* permission flags */
2839
2840   return(True);
2841 }
2842
2843 /****************************************************************************
2844   api_WPrintJobEnumerate
2845   ****************************************************************************/
2846 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2847                                  int mdrcnt,int mprcnt,
2848                                  char **rdata,char **rparam,
2849                                  int *rdata_len,int *rparam_len)
2850 {
2851   char *str1 = param+2;
2852   char *str2 = skip_string(str1,1);
2853   char *p = skip_string(str2,1);
2854   int uLevel;
2855   int count;
2856   int i;
2857   int snum;
2858   uint32 jobid;
2859   struct pack_desc desc;
2860   print_queue_struct *queue=NULL;
2861   print_status_struct status;
2862   char *tmpdata=NULL;
2863
2864   uLevel = SVAL(p,2);
2865
2866   memset((char *)&desc,'\0',sizeof(desc));
2867   memset((char *)&status,'\0',sizeof(status));
2868
2869   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2870
2871   /* check it's a supported varient */
2872   if (strcmp(str1,"WWrLh") != 0) return False;
2873   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2874
2875   if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid))
2876     return False;
2877
2878   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2879
2880   count = print_queue_status(snum,&queue,&status);
2881   for (i = 0; i < count; i++) {
2882     if (queue[i].job == jobid) break;
2883   }
2884
2885   if (mdrcnt > 0) {
2886     *rdata = REALLOC(*rdata,mdrcnt);
2887     desc.base = *rdata;
2888     desc.buflen = mdrcnt;
2889   } else {
2890     /*
2891      * Don't return data but need to get correct length
2892      *  init_package will return wrong size if buflen=0
2893      */
2894     desc.buflen = getlen(desc.format);
2895     desc.base = tmpdata = (char *)malloc ( desc.buflen );
2896   }
2897
2898   if (init_package(&desc,1,0)) {
2899     if (i < count) {
2900       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2901       *rdata_len = desc.usedlen;
2902     }
2903     else {
2904       desc.errcode = NERR_JobNotFound;
2905       *rdata_len = 0;
2906     }
2907   }
2908
2909   *rparam_len = 6;
2910   *rparam = REALLOC(*rparam,*rparam_len);
2911   SSVALS(*rparam,0,desc.errcode);
2912   SSVAL(*rparam,2,0);
2913   SSVAL(*rparam,4,desc.neededlen);
2914
2915   SAFE_FREE(queue);
2916   SAFE_FREE(tmpdata);
2917
2918   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2919   return(True);
2920 }
2921
2922 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2923                                    int mdrcnt,int mprcnt,
2924                                    char **rdata,char **rparam,
2925                                    int *rdata_len,int *rparam_len)
2926 {
2927   char *str1 = param+2;
2928   char *str2 = skip_string(str1,1);
2929   char *p = skip_string(str2,1);
2930   char* name = p;
2931   int uLevel;
2932   int count;
2933   int i, succnt=0;
2934   int snum;
2935   struct pack_desc desc;
2936   print_queue_struct *queue=NULL;
2937   print_status_struct status;
2938
2939   memset((char *)&desc,'\0',sizeof(desc));
2940   memset((char *)&status,'\0',sizeof(status));
2941
2942   p = skip_string(p,1);
2943   uLevel = SVAL(p,0);
2944
2945   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2946
2947   /* check it's a supported variant */
2948   if (strcmp(str1,"zWrLeh") != 0) return False;
2949   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2950   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2951
2952   snum = lp_servicenumber(name);
2953   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2954     int pnum = lp_servicenumber(PRINTERS_NAME);
2955     if (pnum >= 0) {
2956       lp_add_printer(name,pnum);
2957       snum = lp_servicenumber(name);
2958     }
2959   }
2960
2961   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2962
2963   count = print_queue_status(snum,&queue,&status);
2964   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2965   desc.base = *rdata;
2966   desc.buflen = mdrcnt;
2967
2968   if (init_package(&desc,count,0)) {
2969     succnt = 0;
2970     for (i = 0; i < count; i++) {
2971       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2972       if (desc.errcode == NERR_Success) succnt = i+1;
2973     }
2974   }
2975
2976   *rdata_len = desc.usedlen;
2977
2978   *rparam_len = 8;
2979   *rparam = REALLOC(*rparam,*rparam_len);
2980   SSVALS(*rparam,0,desc.errcode);
2981   SSVAL(*rparam,2,0);
2982   SSVAL(*rparam,4,succnt);
2983   SSVAL(*rparam,6,count);
2984
2985   SAFE_FREE(queue);
2986
2987   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2988   return(True);
2989 }
2990
2991 static int check_printdest_info(struct pack_desc* desc,
2992                                 int uLevel, char* id)
2993 {
2994   desc->subformat = NULL;
2995   switch( uLevel ) {
2996   case 0: desc->format = "B9"; break;
2997   case 1: desc->format = "B9B21WWzW"; break;
2998   case 2: desc->format = "z"; break;
2999   case 3: desc->format = "zzzWWzzzWW"; break;
3000   default: return False;
3001   }
3002   if (strcmp(desc->format,id) != 0) return False;
3003   return True;
3004 }
3005
3006 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3007                                 struct pack_desc* desc)
3008 {
3009   char buf[100];
3010   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3011   buf[sizeof(buf)-1] = 0;
3012   strupper_m(buf);
3013   if (uLevel <= 1) {
3014     PACKS(desc,"B9",buf);       /* szName */
3015     if (uLevel == 1) {
3016       PACKS(desc,"B21","");     /* szUserName */
3017       PACKI(desc,"W",0);                /* uJobId */
3018       PACKI(desc,"W",0);                /* fsStatus */
3019       PACKS(desc,"z","");       /* pszStatus */
3020       PACKI(desc,"W",0);                /* time */
3021     }
3022   }
3023   if (uLevel == 2 || uLevel == 3) {
3024     PACKS(desc,"z",buf);                /* pszPrinterName */
3025     if (uLevel == 3) {
3026       PACKS(desc,"z","");       /* pszUserName */
3027       PACKS(desc,"z","");       /* pszLogAddr */
3028       PACKI(desc,"W",0);                /* uJobId */
3029       PACKI(desc,"W",0);                /* fsStatus */
3030       PACKS(desc,"z","");       /* pszStatus */
3031       PACKS(desc,"z","");       /* pszComment */
3032       PACKS(desc,"z","NULL"); /* pszDrivers */
3033       PACKI(desc,"W",0);                /* time */
3034       PACKI(desc,"W",0);                /* pad1 */
3035     }
3036   }
3037 }
3038
3039 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3040                                   int mdrcnt,int mprcnt,
3041                                   char **rdata,char **rparam,
3042                                   int *rdata_len,int *rparam_len)
3043 {
3044   char *str1 = param+2;
3045   char *str2 = skip_string(str1,1);
3046   char *p = skip_string(str2,1);
3047   char* PrinterName = p;
3048   int uLevel;
3049   struct pack_desc desc;
3050   int snum;
3051   char *tmpdata=NULL;
3052
3053   memset((char *)&desc,'\0',sizeof(desc));
3054
3055   p = skip_string(p,1);
3056   uLevel = SVAL(p,0);
3057
3058   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3059
3060   /* check it's a supported varient */
3061   if (strcmp(str1,"zWrLh") != 0) return False;
3062   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3063
3064   snum = lp_servicenumber(PrinterName);
3065   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
3066     int pnum = lp_servicenumber(PRINTERS_NAME);
3067     if (pnum >= 0) {
3068       lp_add_printer(PrinterName,pnum);
3069       snum = lp_servicenumber(PrinterName);
3070     }
3071   }
3072
3073   if (snum < 0) {
3074     *rdata_len = 0;
3075     desc.errcode = NERR_DestNotFound;
3076     desc.neededlen = 0;
3077   }
3078   else {
3079     if (mdrcnt > 0) {
3080       *rdata = REALLOC(*rdata,mdrcnt);
3081       desc.base = *rdata;
3082       desc.buflen = mdrcnt;
3083     } else {
3084       /*
3085        * Don't return data but need to get correct length
3086        *  init_package will return wrong size if buflen=0
3087        */
3088       desc.buflen = getlen(desc.format);
3089       desc.base = tmpdata = (char *)malloc ( desc.buflen );
3090     }
3091     if (init_package(&desc,1,0)) {
3092       fill_printdest_info(conn,snum,uLevel,&desc);
3093     }
3094     *rdata_len = desc.usedlen;
3095   }
3096
3097   *rparam_len = 6;
3098   *rparam = REALLOC(*rparam,*rparam_len);
3099   SSVALS(*rparam,0,desc.errcode);
3100   SSVAL(*rparam,2,0);
3101   SSVAL(*rparam,4,desc.neededlen);
3102
3103   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3104   SAFE_FREE(tmpdata);
3105   return(True);
3106 }
3107
3108 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3109                                int mdrcnt,int mprcnt,
3110                                char **rdata,char **rparam,
3111                                int *rdata_len,int *rparam_len)
3112 {
3113   char *str1 = param+2;
3114   char *str2 = skip_string(str1,1);
3115   char *p = skip_string(str2,1);
3116   int uLevel;
3117   int queuecnt;
3118   int i, n, succnt=0;
3119   struct pack_desc desc;
3120   int services = lp_numservices();
3121
3122   memset((char *)&desc,'\0',sizeof(desc));
3123
3124   uLevel = SVAL(p,0);
3125
3126   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3127
3128   /* check it's a supported varient */
3129   if (strcmp(str1,"WrLeh") != 0) return False;
3130   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3131
3132   queuecnt = 0;
3133   for (i = 0; i < services; i++)
3134     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3135       queuecnt++;
3136
3137   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3138   desc.base = *rdata;
3139   desc.buflen = mdrcnt;
3140   if (init_package(&desc,queuecnt,0)) {    
3141     succnt = 0;
3142     n = 0;
3143     for (i = 0; i < services; i++) {
3144       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3145         fill_printdest_info(conn,i,uLevel,&desc);
3146         n++;
3147         if (desc.errcode == NERR_Success) succnt = n;
3148       }
3149     }
3150   }
3151
3152   *rdata_len = desc.usedlen;
3153
3154   *rparam_len = 8;
3155   *rparam = REALLOC(*rparam,*rparam_len);
3156   SSVALS(*rparam,0,desc.errcode);
3157   SSVAL(*rparam,2,0);
3158   SSVAL(*rparam,4,succnt);
3159   SSVAL(*rparam,6,queuecnt);
3160
3161   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3162   return(True);
3163 }
3164
3165 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3166                                  int mdrcnt,int mprcnt,
3167                                  char **rdata,char **rparam,
3168                                  int *rdata_len,int *rparam_len)
3169 {
3170   char *str1 = param+2;
3171   char *str2 = skip_string(str1,1);
3172   char *p = skip_string(str2,1);
3173   int uLevel;
3174   int succnt;
3175   struct pack_desc desc;
3176
3177   memset((char *)&desc,'\0',sizeof(desc));
3178
3179   uLevel = SVAL(p,0);
3180
3181   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3182
3183   /* check it's a supported varient */
3184   if (strcmp(str1,"WrLeh") != 0) return False;
3185   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3186
3187   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3188   desc.base = *rdata;
3189   desc.buflen = mdrcnt;
3190   if (init_package(&desc,1,0)) {
3191     PACKS(&desc,"B41","NULL");
3192   }
3193
3194   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3195
3196   *rdata_len = desc.usedlen;
3197
3198   *rparam_len = 8;
3199   *rparam = REALLOC(*rparam,*rparam_len);
3200   SSVALS(*rparam,0,desc.errcode);
3201   SSVAL(*rparam,2,0);
3202   SSVAL(*rparam,4,succnt);
3203   SSVAL(*rparam,6,1);
3204
3205   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3206   return(True);
3207 }
3208
3209 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3210                                 int mdrcnt,int mprcnt,
3211                                 char **rdata,char **rparam,
3212                                 int *rdata_len,int *rparam_len)
3213 {
3214   char *str1 = param+2;
3215   char *str2 = skip_string(str1,1);
3216   char *p = skip_string(str2,1);
3217   int uLevel;
3218   int succnt;
3219   struct pack_desc desc;
3220
3221   memset((char *)&desc,'\0',sizeof(desc));
3222
3223   uLevel = SVAL(p,0);
3224
3225   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3226
3227   /* check it's a supported varient */
3228   if (strcmp(str1,"WrLeh") != 0) return False;
3229   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3230
3231   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3232   desc.base = *rdata;
3233   desc.buflen = mdrcnt;
3234   desc.format = str2;
3235   if (init_package(&desc,1,0)) {
3236     PACKS(&desc,"B13","lpd");
3237   }
3238
3239   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3240
3241   *rdata_len = desc.usedlen;
3242
3243   *rparam_len = 8;
3244   *rparam = REALLOC(*rparam,*rparam_len);
3245   SSVALS(*rparam,0,desc.errcode);
3246   SSVAL(*rparam,2,0);
3247   SSVAL(*rparam,4,succnt);
3248   SSVAL(*rparam,6,1);
3249
3250   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3251   return(True);
3252 }
3253
3254 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3255                                int mdrcnt,int mprcnt,
3256                                char **rdata,char **rparam,
3257                                int *rdata_len,int *rparam_len)
3258 {
3259   char *str1 = param+2;
3260   char *str2 = skip_string(str1,1);
3261   char *p = skip_string(str2,1);
3262   int uLevel;
3263   int succnt;
3264   struct pack_desc desc;
3265
3266   memset((char *)&desc,'\0',sizeof(desc));
3267
3268   uLevel = SVAL(p,0);
3269
3270   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3271
3272   /* check it's a supported varient */
3273   if (strcmp(str1,"WrLeh") != 0) return False;
3274   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3275
3276   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3277   memset((char *)&desc,'\0',sizeof(desc));
3278   desc.base = *rdata;
3279   desc.buflen = mdrcnt;
3280   desc.format = str2;
3281   if (init_package(&desc,1,0)) {
3282     PACKS(&desc,"B13","lp0");
3283   }
3284
3285   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3286
3287   *rdata_len = desc.usedlen;
3288
3289   *rparam_len = 8;
3290   *rparam = REALLOC(*rparam,*rparam_len);
3291   SSVALS(*rparam,0,desc.errcode);
3292   SSVAL(*rparam,2,0);
3293   SSVAL(*rparam,4,succnt);
3294   SSVAL(*rparam,6,1);
3295
3296   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3297   return(True);
3298 }
3299
3300
3301 /****************************************************************************
3302  List open sessions
3303  ****************************************************************************/
3304 static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
3305                                int mdrcnt,int mprcnt,
3306                                char **rdata,char **rparam,
3307                                int *rdata_len,int *rparam_len)
3308
3309 {
3310   char *str1 = param+2;
3311   char *str2 = skip_string(str1,1);
3312   char *p = skip_string(str2,1);
3313   int uLevel;
3314   struct pack_desc desc;
3315   struct sessionid *session_list;
3316   int i, num_sessions;
3317
3318   memset((char *)&desc,'\0',sizeof(desc));
3319
3320   uLevel = SVAL(p,0);
3321
3322   DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
3323   DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
3324   DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
3325
3326   /* check it's a supported varient */
3327   if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False;
3328   if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False;
3329
3330   num_sessions = list_sessions(&session_list);
3331
3332   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3333   memset((char *)&desc,'\0',sizeof(desc));
3334   desc.base = *rdata;
3335   desc.buflen = mdrcnt;
3336   desc.format = str2;
3337   if (!init_package(&desc,num_sessions,0)) {
3338     return False;
3339   }
3340
3341   for(i=0; i<num_sessions; i++) {
3342     PACKS(&desc, "z", session_list[i].remote_machine);
3343     PACKS(&desc, "z", session_list[i].username);
3344     PACKI(&desc, "W", 1); /* num conns */
3345     PACKI(&desc, "W", 0); /* num opens */
3346     PACKI(&desc, "W", 1); /* num users */
3347     PACKI(&desc, "D", 0); /* session time */
3348     PACKI(&desc, "D", 0); /* idle time */
3349     PACKI(&desc, "D", 0); /* flags */
3350     PACKS(&desc, "z", "Unknown Client"); /* client type string */
3351   }
3352
3353   *rdata_len = desc.usedlen;
3354
3355   *rparam_len = 8;
3356   *rparam = REALLOC(*rparam,*rparam_len);
3357   SSVALS(*rparam,0,desc.errcode);
3358   SSVAL(*rparam,2,0); /* converter */
3359   SSVAL(*rparam,4,num_sessions); /* count */
3360
3361   DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
3362   return True;
3363 }
3364
3365
3366 /****************************************************************************
3367  The buffer was too small
3368  ****************************************************************************/
3369
3370 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3371                          int mdrcnt,int mprcnt,
3372                          char **rdata,char **rparam,
3373                          int *rdata_len,int *rparam_len)
3374 {
3375   *rparam_len = MIN(*rparam_len,mprcnt);
3376   *rparam = REALLOC(*rparam,*rparam_len);
3377
3378   *rdata_len = 0;
3379
3380   SSVAL(*rparam,0,NERR_BufTooSmall);
3381
3382   DEBUG(3,("Supplied buffer too small in API command\n"));
3383
3384   return(True);
3385 }
3386
3387
3388 /****************************************************************************
3389  The request is not supported
3390  ****************************************************************************/
3391
3392 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3393                             int mdrcnt,int mprcnt,
3394                             char **rdata,char **rparam,
3395                             int *rdata_len,int *rparam_len)
3396 {
3397   *rparam_len = 4;
3398   *rparam = REALLOC(*rparam,*rparam_len);
3399
3400   *rdata_len = 0;
3401
3402   SSVAL(*rparam,0,NERR_notsupported);
3403   SSVAL(*rparam,2,0);           /* converter word */
3404
3405   DEBUG(3,("Unsupported API command\n"));
3406
3407   return(True);
3408 }
3409
3410
3411
3412
3413 static const struct
3414 {
3415   const char *name;
3416   int id;
3417   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3418              int,int,char **,char **,int *,int *);
3419   BOOL auth_user;               /* Deny anonymous access? */
3420 } api_commands[] = {
3421   {"RNetShareEnum",     RAP_WshareEnum,         api_RNetShareEnum, True},
3422   {"RNetShareGetInfo",  RAP_WshareGetInfo,      api_RNetShareGetInfo},
3423   {"RNetShareAdd",      RAP_WshareAdd,          api_RNetShareAdd},
3424   {"RNetSessionEnum",   RAP_WsessionEnum,       api_RNetSessionEnum, True},
3425   {"RNetServerGetInfo", RAP_WserverGetInfo,     api_RNetServerGetInfo},
3426   {"RNetGroupEnum",     RAP_WGroupEnum,         api_RNetGroupEnum, True},
3427   {"RNetGroupGetUsers", RAP_WGroupGetUsers,     api_RNetGroupGetUsers, True},
3428   {"RNetUserEnum",      RAP_WUserEnum,          api_RNetUserEnum, True},
3429   {"RNetUserGetInfo",   RAP_WUserGetInfo,       api_RNetUserGetInfo},
3430   {"NetUserGetGroups",  RAP_WUserGetGroups,     api_NetUserGetGroups},
3431   {"NetWkstaGetInfo",   RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
3432   {"DosPrintQEnum",     RAP_WPrintQEnum,        api_DosPrintQEnum, True},
3433   {"DosPrintQGetInfo",  RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
3434   {"WPrintQueuePause",  RAP_WPrintQPause,       api_WPrintQueueCtrl},
3435   {"WPrintQueueResume", RAP_WPrintQContinue,    api_WPrintQueueCtrl},
3436   {"WPrintJobEnumerate",RAP_WPrintJobEnum,      api_WPrintJobEnumerate},
3437   {"WPrintJobGetInfo",  RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
3438   {"RDosPrintJobDel",   RAP_WPrintJobDel,       api_RDosPrintJobDel},
3439   {"RDosPrintJobPause", RAP_WPrintJobPause,     api_RDosPrintJobDel},
3440   {"RDosPrintJobResume",RAP_WPrintJobContinue,  api_RDosPrintJobDel},
3441   {"WPrintDestEnum",    RAP_WPrintDestEnum,     api_WPrintDestEnum},
3442   {"WPrintDestGetInfo", RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
3443   {"NetRemoteTOD",      RAP_NetRemoteTOD,       api_NetRemoteTOD},
3444   {"WPrintQueuePurge",  RAP_WPrintQPurge,       api_WPrintQueueCtrl},
3445   {"NetServerEnum",     RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
3446   {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
3447   {"SetUserPassword",   RAP_WUserPasswordSet2,  api_SetUserPassword},
3448   {"WWkstaUserLogon",   RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
3449   {"PrintJobInfo",      RAP_WPrintJobSetInfo,   api_PrintJobInfo},
3450   {"WPrintDriverEnum",  RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
3451   {"WPrintQProcEnum",   RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
3452   {"WPrintPortEnum",    RAP_WPrintPortEnum,     api_WPrintPortEnum},
3453   {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
3454   {NULL,                -1,     api_Unsupported}};
3455
3456 /*  The following RAP calls are not implemented by Samba:
3457
3458         RAP_WFileEnum2 - anon not OK 
3459 */
3460
3461 /****************************************************************************
3462  Handle remote api calls
3463  ****************************************************************************/
3464
3465 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3466                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3467 {
3468   int api_command;
3469   char *rdata = NULL;
3470   char *rparam = NULL;
3471   int rdata_len = 0;
3472   int rparam_len = 0;
3473   BOOL reply=False;
3474   int i;
3475
3476   if (!params) {
3477           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3478           return 0;
3479   }
3480
3481   api_command = SVAL(params,0);
3482
3483   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3484            api_command,
3485            params+2,
3486            skip_string(params+2,1),
3487            tdscnt,tpscnt,mdrcnt,mprcnt));
3488
3489   for (i=0;api_commands[i].name;i++) {
3490     if (api_commands[i].id == api_command && api_commands[i].fn) {
3491         DEBUG(3,("Doing %s\n",api_commands[i].name));
3492         break;
3493     }
3494   }
3495
3496   /* Check whether this api call can be done anonymously */
3497
3498   if (api_commands[i].auth_user && lp_restrict_anonymous()) {
3499           user_struct *user = get_valid_user_struct(vuid);
3500
3501           if (!user || user->guest)
3502                   return ERROR_NT(NT_STATUS_ACCESS_DENIED);
3503   }
3504
3505   rdata = (char *)malloc(1024);
3506   if (rdata)
3507     memset(rdata,'\0',1024);
3508
3509   rparam = (char *)malloc(1024);
3510   if (rparam)
3511     memset(rparam,'\0',1024);
3512
3513   if(!rdata || !rparam) {
3514     DEBUG(0,("api_reply: malloc fail !\n"));
3515     return -1;
3516   }
3517
3518   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3519                              &rdata,&rparam,&rdata_len,&rparam_len);
3520
3521
3522   if (rdata_len > mdrcnt ||
3523       rparam_len > mprcnt) {
3524       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3525                            &rdata,&rparam,&rdata_len,&rparam_len);
3526   }
3527
3528   /* if we get False back then it's actually unsupported */
3529   if (!reply)
3530     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3531                     &rdata,&rparam,&rdata_len,&rparam_len);
3532
3533   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3534
3535   SAFE_FREE(rdata);
3536   SAFE_FREE(rparam);
3537   
3538   return -1;
3539 }