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