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