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