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