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