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