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