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