One less Get_Pwnam_Modify call!
[kai/samba.git] / source3 / smbd / lanman.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Inter-process communication and named pipe handling
5    Copyright (C) Andrew Tridgell 1992-1998
6
7    SMB Version handling
8    Copyright (C) John H Terpstra 1995-1998
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    */
24 /*
25    This file handles the named pipe and mailslot calls
26    in the SMBtrans protocol
27    */
28
29 #include "includes.h"
30
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
35
36 extern fstring local_machine;
37 extern pstring global_myname;
38 extern fstring global_myworkgroup;
39
40 #define NERR_Success 0
41 #define NERR_badpass 86
42 #define NERR_notsupported 50
43
44 #define NERR_BASE (2100)
45 #define NERR_BufTooSmall (NERR_BASE+23)
46 #define NERR_JobNotFound (NERR_BASE+51)
47 #define NERR_DestNotFound (NERR_BASE+52)
48
49 #define ACCESS_READ 0x01
50 #define ACCESS_WRITE 0x02
51 #define ACCESS_CREATE 0x04
52
53 #define SHPWLEN 8               /* share password length */
54
55 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
56                             int mdrcnt,int mprcnt,
57                             char **rdata,char **rparam,
58                             int *rdata_len,int *rparam_len);
59 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
60                          int mdrcnt,int mprcnt,
61                          char **rdata,char **rparam,
62                          int *rdata_len,int *rparam_len);
63
64
65 static int CopyExpanded(connection_struct *conn, 
66                         int snum, char** dst, char* src, int* n)
67 {
68         pstring buf;
69         int l;
70
71         if (!src || !dst || !n || !(*dst)) return(0);
72
73         StrnCpy(buf,src,sizeof(buf)/2);
74         pstring_sub(buf,"%S",lp_servicename(snum));
75         standard_sub_conn(conn,buf);
76         l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
77         (*dst) += l;
78         (*n) -= l;
79         return l;
80 }
81
82 static int CopyAndAdvance(char** dst, char* src, int* n)
83 {
84   int l;
85   if (!src || !dst || !n || !(*dst)) return(0);
86   l = push_ascii(*dst,src,*n-1, STR_TERMINATE);
87   (*dst) += l;
88   (*n) -= l;
89   return l;
90 }
91
92 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
93 {
94         pstring buf;
95         if (!s) return(0);
96         StrnCpy(buf,s,sizeof(buf)/2);
97         pstring_sub(buf,"%S",lp_servicename(snum));
98         standard_sub_conn(conn,buf);
99         return strlen(buf) + 1;
100 }
101
102 static char* Expand(connection_struct *conn, int snum, char* s)
103 {
104         static pstring buf;
105         if (!s) return(NULL);
106         StrnCpy(buf,s,sizeof(buf)/2);
107         pstring_sub(buf,"%S",lp_servicename(snum));
108         standard_sub_conn(conn,buf);
109         return &buf[0];
110 }
111
112 /*******************************************************************
113   check a API string for validity when we only need to check the prefix
114   ******************************************************************/
115 static BOOL prefix_ok(char *str,char *prefix)
116 {
117   return(strncmp(str,prefix,strlen(prefix)) == 0);
118 }
119
120 struct pack_desc {
121   char* format;     /* formatstring for structure */
122   char* subformat;  /* subformat for structure */
123   char* base;       /* baseaddress of buffer */
124   int buflen;      /* remaining size for fixed part; on init: length of base */
125   int subcount;     /* count of substructures */
126   char* structbuf;  /* pointer into buffer for remaining fixed part */
127   int stringlen;    /* remaining size for variable part */              
128   char* stringbuf;  /* pointer into buffer for remaining variable part */
129   int neededlen;    /* total needed size */
130   int usedlen;      /* total used size (usedlen <= neededlen and usedlen <= buflen) */
131   char* curpos;     /* current position; pointer into format or subformat */
132   int errcode;
133 };
134
135 static int get_counter(char** p)
136 {
137   int i, n;
138   if (!p || !(*p)) return(1);
139   if (!isdigit((int)**p)) return 1;
140   for (n = 0;;) {
141     i = **p;
142     if (isdigit(i))
143       n = 10 * n + (i - '0');
144     else
145       return n;
146     (*p)++;
147   }
148 }
149
150 static int getlen(char* p)
151 {
152   int n = 0;
153   if (!p) return(0);
154   while (*p) {
155     switch( *p++ ) {
156     case 'W':                   /* word (2 byte) */
157       n += 2;
158       break;
159     case 'K':                   /* status word? (2 byte) */
160       n += 2;
161       break;
162     case 'N':                   /* count of substructures (word) at end */
163       n += 2;
164       break;
165     case 'D':                   /* double word (4 byte) */
166     case 'z':                   /* offset to zero terminated string (4 byte) */
167     case 'l':                   /* offset to user data (4 byte) */
168       n += 4;
169       break;
170     case 'b':                   /* offset to data (with counter) (4 byte) */
171       n += 4;
172       get_counter(&p);
173       break;
174     case 'B':                   /* byte (with optional counter) */
175       n += get_counter(&p);
176       break;
177     }
178   }
179   return n;
180 }
181
182 static BOOL init_package(struct pack_desc* p, int count, int subcount)
183 {
184   int n = p->buflen;
185   int i;
186
187   if (!p->format || !p->base) return(False);
188
189   i = count * getlen(p->format);
190   if (p->subformat) i += subcount * getlen(p->subformat);
191   p->structbuf = p->base;
192   p->neededlen = 0;
193   p->usedlen = 0;
194   p->subcount = 0;
195   p->curpos = p->format;
196   if (i > n) {
197     p->neededlen = i;
198     i = n = 0;
199 #if 0
200     /*
201      * This is the old error code we used. Aparently
202      * WinNT/2k systems return ERRbuftoosmall (2123) and
203      * OS/2 needs this. I'm leaving this here so we can revert
204      * if needed. JRA.
205      */
206     p->errcode = ERRmoredata;
207 #else
208         p->errcode = ERRbuftoosmall;
209 #endif
210   }
211   else
212     p->errcode = NERR_Success;
213   p->buflen = i;
214   n -= i;
215   p->stringbuf = p->base + i;
216   p->stringlen = n;
217   return(p->errcode == NERR_Success);
218 }
219
220 static int package(struct pack_desc* p, ...)
221 {
222   va_list args;
223   int needed=0, stringneeded;
224   char* str=NULL;
225   int is_string=0, stringused;
226   int32 temp;
227
228   va_start(args,p);
229
230   if (!*p->curpos) {
231     if (!p->subcount)
232       p->curpos = p->format;
233     else {
234       p->curpos = p->subformat;
235       p->subcount--;
236     }
237   }
238 #if CHECK_TYPES
239   str = va_arg(args,char*);
240   SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
241 #endif
242   stringneeded = -1;
243
244   if (!p->curpos) {
245     va_end(args);
246     return(0);
247   }
248
249   switch( *p->curpos++ ) {
250   case 'W':                     /* word (2 byte) */
251     needed = 2;
252     temp = va_arg(args,int);
253     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
254     break;
255   case 'K':                     /* status word? (2 byte) */
256     needed = 2;
257     temp = va_arg(args,int);
258     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
259     break;
260   case 'N':                     /* count of substructures (word) at end */
261     needed = 2;
262     p->subcount = va_arg(args,int);
263     if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
264     break;
265   case 'D':                     /* double word (4 byte) */
266     needed = 4;
267     temp = va_arg(args,int);
268     if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
269     break;
270   case 'B':                     /* byte (with optional counter) */
271     needed = get_counter(&p->curpos);
272     {
273       char *s = va_arg(args,char*);
274       if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
275     }
276     break;
277   case 'z':                     /* offset to zero terminated string (4 byte) */
278     str = va_arg(args,char*);
279     stringneeded = (str ? strlen(str)+1 : 0);
280     is_string = 1;
281     break;
282   case 'l':                     /* offset to user data (4 byte) */
283     str = va_arg(args,char*);
284     stringneeded = va_arg(args,int);
285     is_string = 0;
286     break;
287   case 'b':                     /* offset to data (with counter) (4 byte) */
288     str = va_arg(args,char*);
289     stringneeded = get_counter(&p->curpos);
290     is_string = 0;
291     break;
292   }
293   va_end(args);
294   if (stringneeded >= 0) {
295     needed = 4;
296     if (p->buflen >= needed) {
297       stringused = stringneeded;
298       if (stringused > p->stringlen) {
299         stringused = (is_string ? p->stringlen : 0);
300         if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
301       }
302       if (!stringused)
303         SIVAL(p->structbuf,0,0);
304       else {
305         SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
306         memcpy(p->stringbuf,str?str:"",stringused);
307         if (is_string) p->stringbuf[stringused-1] = '\0';
308         p->stringbuf += stringused;
309         p->stringlen -= stringused;
310         p->usedlen += stringused;
311       }
312     }
313     p->neededlen += stringneeded;
314   }
315   p->neededlen += needed;
316   if (p->buflen >= needed) {
317     p->structbuf += needed;
318     p->buflen -= needed;
319     p->usedlen += needed;
320   }
321   else {
322     if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
323   }
324   return 1;
325 }
326
327 #if CHECK_TYPES
328 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
329 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
330 #else
331 #define PACK(desc,t,v) package(desc,v)
332 #define PACKl(desc,t,v,l) package(desc,v,l)
333 #endif
334
335 static void PACKI(struct pack_desc* desc,char *t,int v)
336 {
337   PACK(desc,t,v);
338 }
339
340 static void PACKS(struct pack_desc* desc,char *t,char *v)
341 {
342   PACK(desc,t,v);
343 }
344
345
346 /****************************************************************************
347   get a print queue
348   ****************************************************************************/
349 static void PackDriverData(struct pack_desc* desc)
350 {
351   char drivdata[4+4+32];
352   SIVAL(drivdata,0,sizeof drivdata); /* cb */
353   SIVAL(drivdata,4,1000);       /* lVersion */
354   memset(drivdata+8,0,32);      /* szDeviceName */
355   push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
356   PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
357 }
358
359 static int check_printq_info(struct pack_desc* desc,
360                              int uLevel, char *id1, char *id2)
361 {
362   desc->subformat = NULL;
363   switch( uLevel ) {
364   case 0:
365     desc->format = "B13";
366     break;
367   case 1:
368     desc->format = "B13BWWWzzzzzWW";
369     break;
370   case 2:
371     desc->format = "B13BWWWzzzzzWN";
372     desc->subformat = "WB21BB16B10zWWzDDz";
373     break;
374   case 3:
375     desc->format = "zWWWWzzzzWWzzl";
376     break;
377   case 4:
378     desc->format = "zWWWWzzzzWNzzl";
379     desc->subformat = "WWzWWDDzz";
380     break;
381   case 5:
382     desc->format = "z";
383     break;
384   case 51:
385     desc->format = "K";
386     break;
387   case 52:
388     desc->format = "WzzzzzzzzN";
389     desc->subformat = "z";
390     break;
391   default: return False;
392   }
393   if (strcmp(desc->format,id1) != 0) return False;
394   if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
395   return True;
396 }
397
398
399 #define RAP_JOB_STATUS_QUEUED 0
400 #define RAP_JOB_STATUS_PAUSED 1
401 #define RAP_JOB_STATUS_SPOOLING 2
402 #define RAP_JOB_STATUS_PRINTING 3
403 #define RAP_JOB_STATUS_PRINTED 4
404
405 #define RAP_QUEUE_STATUS_PAUSED 1
406 #define RAP_QUEUE_STATUS_ERROR 2
407
408 /* turn a print job status into a on the wire status 
409 */
410 static int printj_status(int v)
411 {
412         switch (v) {
413         case LPQ_QUEUED:
414                 return RAP_JOB_STATUS_QUEUED;
415         case LPQ_PAUSED:
416                 return RAP_JOB_STATUS_PAUSED;
417         case LPQ_SPOOLING:
418                 return RAP_JOB_STATUS_SPOOLING;
419         case LPQ_PRINTING:
420                 return RAP_JOB_STATUS_PRINTING;
421         }
422         return 0;
423 }
424
425 /* turn a print queue status into a on the wire status 
426 */
427 static int printq_status(int v)
428 {
429         switch (v) {
430         case LPQ_QUEUED:
431                 return 0;
432         case LPQ_PAUSED:
433                 return RAP_QUEUE_STATUS_PAUSED;
434         }
435         return RAP_QUEUE_STATUS_ERROR;
436 }
437
438 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
439                                struct pack_desc* desc,
440                                print_queue_struct* queue, int n)
441 {
442   time_t t = queue->time;
443
444   /* the client expects localtime */
445   t -= TimeDiff(t);
446
447   PACKI(desc,"W",queue->job); /* uJobId */
448   if (uLevel == 1) {
449     PACKS(desc,"B21",queue->user); /* szUserName */
450     PACKS(desc,"B","");         /* pad */
451     PACKS(desc,"B16","");       /* szNotifyName */
452     PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
453     PACKS(desc,"z","");         /* pszParms */
454     PACKI(desc,"W",n+1);                /* uPosition */
455     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
456     PACKS(desc,"z","");         /* pszStatus */
457     PACKI(desc,"D",t); /* ulSubmitted */
458     PACKI(desc,"D",queue->size); /* ulSize */
459     PACKS(desc,"z",queue->file); /* pszComment */
460   }
461   if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
462     PACKI(desc,"W",queue->priority);            /* uPriority */
463     PACKS(desc,"z",queue->user); /* pszUserName */
464     PACKI(desc,"W",n+1);                /* uPosition */
465     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
466     PACKI(desc,"D",t); /* ulSubmitted */
467     PACKI(desc,"D",queue->size); /* ulSize */
468     PACKS(desc,"z","Samba");    /* pszComment */
469     PACKS(desc,"z",queue->file); /* pszDocument */
470     if (uLevel == 3) {
471       PACKS(desc,"z","");       /* pszNotifyName */
472       PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
473       PACKS(desc,"z","");       /* pszParms */
474       PACKS(desc,"z","");       /* pszStatus */
475       PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
476       PACKS(desc,"z","lpd");    /* pszQProcName */
477       PACKS(desc,"z","");       /* pszQProcParms */
478       PACKS(desc,"z","NULL"); /* pszDriverName */
479       PackDriverData(desc);     /* pDriverData */
480       PACKS(desc,"z","");       /* pszPrinterName */
481     } else if (uLevel == 4) {   /* OS2 */
482       PACKS(desc,"z","");       /* pszSpoolFileName  */
483        PACKS(desc,"z","");       /* pszPortName       */
484        PACKS(desc,"z","");       /* pszStatus         */
485        PACKI(desc,"D",0);        /* ulPagesSpooled    */
486        PACKI(desc,"D",0);        /* ulPagesSent       */
487        PACKI(desc,"D",0);        /* ulPagesPrinted    */
488        PACKI(desc,"D",0);        /* ulTimePrinted     */
489        PACKI(desc,"D",0);        /* ulExtendJobStatus */
490        PACKI(desc,"D",0);        /* ulStartPage       */
491        PACKI(desc,"D",0);        /* ulEndPage         */
492     }
493   }
494 }
495
496 /********************************************************************
497  Return a driver name given an snum.
498  Looks in a tdb first. Returns True if from tdb, False otherwise.
499  ********************************************************************/
500
501 static BOOL get_driver_name(int snum, pstring drivername)
502 {
503         NT_PRINTER_INFO_LEVEL *info = NULL;
504         BOOL in_tdb = False;
505
506         get_a_printer (&info, 2, lp_servicename(snum));
507         if (info != NULL) {
508                 pstrcpy( drivername, info->info_2->drivername);
509                 in_tdb = True;
510                 free_a_printer(&info, 2);
511         } else {
512                 pstrcpy( drivername, lp_printerdriver(snum));
513         }
514
515         return in_tdb;
516 }
517
518 /********************************************************************
519  Respond to the DosPrintQInfo command with a level of 52
520  This is used to get printer driver information for Win9x clients
521  ********************************************************************/
522 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
523                                 struct pack_desc* desc,
524                                 int count, print_queue_struct* queue,
525                                 print_status_struct* status)
526 {
527         int i;
528         BOOL ok = False;
529         pstring tok,driver,datafile,langmon,helpfile,datatype;
530         char *p;
531         char **lines = NULL;
532         pstring gen_line;
533         BOOL in_tdb = False;
534         fstring location;
535         pstring drivername;
536
537         /*
538          * Check in the tdb *first* before checking the legacy
539          * files. This allows an NT upload to take precedence over
540          * the existing fileset. JRA.
541          * 
542          * we need to lookup the driver name prior to making the call
543          * to get_a_printer_driver_9x_compatible() and not rely on the
544          * 'print driver' parameter --jerry
545          */
546
547
548         if ((get_driver_name(snum,drivername)) && 
549             ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
550         {
551                 in_tdb = True;
552                 p = gen_line;
553                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
554         } 
555         else 
556         {
557                 /* didn't find driver in tdb */
558
559                 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
560                            snum, drivername, lp_driverfile(snum)));
561
562                 lines = file_lines_load(lp_driverfile(snum),NULL);
563                 if (!lines) 
564                 {
565                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
566                                   strerror(errno)));
567                         desc->errcode=NERR_notsupported;
568                         goto done;
569                 } 
570
571                 /* lookup the long printer driver name in the file description */
572                 for (i=0;lines[i] && !ok;i++) 
573                 {
574                         p = lines[i];
575                         if (next_token(&p,tok,":",sizeof(tok)) &&
576                            (strlen(drivername) == strlen(tok)) &&
577                            (!strncmp(tok,drivername,strlen(drivername))))
578                         {
579                                 ok = True;
580                         }
581                 }
582         }
583
584         if (ok)
585         {
586                 /* driver file name */
587                 if (!next_token(&p,driver,":",sizeof(driver)))
588                         goto err;
589
590                 /* data file name */
591                 if (!next_token(&p,datafile,":",sizeof(datafile)))
592                         goto err;
593
594                 /*
595                  * for the next tokens - which may be empty - I have
596                  * to check for empty tokens first because the
597                  * next_token function will skip all empty token
598                  * fields */
599
600                 /* help file */
601                 if (*p == ':') 
602                 {
603                         *helpfile = '\0';
604                         p++;
605                 } 
606                 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
607                         goto err;
608         
609                 /* language monitor */
610                 if (*p == ':') 
611                 {
612                         *langmon = '\0';
613                         p++;
614                 } 
615                 else if (!next_token(&p,langmon,":",sizeof(langmon)))
616                         goto err;
617         
618                 /* default data type */
619                 if (!next_token(&p,datatype,":",sizeof(datatype))) 
620                         goto err;
621         
622                 PACKI(desc,"W",0x0400);               /* don't know */
623                 PACKS(desc,"z",drivername);    /* long printer name */
624                 PACKS(desc,"z",driver);                    /* Driverfile Name */
625                 PACKS(desc,"z",datafile);                  /* Datafile name */
626                 PACKS(desc,"z",langmon);                         /* language monitor */
627                 if (in_tdb)
628                 {
629                         fstrcpy(location, "\\\\");
630                         fstrcat(location, global_myname);
631                         fstrcat(location, "\\print$\\WIN40\\0");
632                         PACKS(desc,"z",location);   /* share to retrieve files */
633                 }
634                 else
635                 {
636                         PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
637                 }
638                 PACKS(desc,"z",datatype);                        /* default data type */
639                 PACKS(desc,"z",helpfile);                  /* helpfile name */
640                 PACKS(desc,"z",driver);                    /* driver name */
641
642                 DEBUG(3,("printerdriver:%s:\n",drivername));
643                 DEBUG(3,("Driver:%s:\n",driver));
644                 DEBUG(3,("Data File:%s:\n",datafile));
645                 DEBUG(3,("Language Monitor:%s:\n",langmon));
646                 if (in_tdb)
647                         DEBUG(3,("lp_driverlocation:%s:\n",location));
648                 else
649                         DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
650                 DEBUG(3,("Data Type:%s:\n",datatype));
651                 DEBUG(3,("Help File:%s:\n",helpfile));
652                 PACKI(desc,"N",count);                     /* number of files to copy */
653
654                 for (i=0;i<count;i++) 
655                 {
656                         /* no need to check return value here
657                          * - it was already tested in
658                          * get_printerdrivernumber */
659                         next_token(&p,tok,",",sizeof(tok));
660                         PACKS(desc,"z",tok);         /* driver files to copy */
661                         DEBUG(3,("file:%s:\n",tok));
662                 }
663                 
664                 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
665                           SERVICE(snum),count));
666
667                 desc->errcode=NERR_Success;
668                 goto done;
669         }
670
671   err:
672
673         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
674         desc->errcode=NERR_notsupported;
675
676  done:
677         file_lines_free(lines); 
678 }
679
680
681 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
682                              struct pack_desc* desc,
683                              int count, print_queue_struct* queue,
684                              print_status_struct* status)
685 {
686         switch (uLevel) {
687         case 1:
688         case 2:
689                 PACKS(desc,"B13",SERVICE(snum));
690                 break;
691         case 3:
692         case 4:
693         case 5:
694                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
695                 break;
696         case 51:
697                 PACKI(desc,"K",printq_status(status->status));
698                 break;
699         }
700
701         if (uLevel == 1 || uLevel == 2) {
702                 PACKS(desc,"B","");             /* alignment */
703                 PACKI(desc,"W",5);              /* priority */
704                 PACKI(desc,"W",0);              /* start time */
705                 PACKI(desc,"W",0);              /* until time */
706                 PACKS(desc,"z","");             /* pSepFile */
707                 PACKS(desc,"z","lpd");  /* pPrProc */
708                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
709                 PACKS(desc,"z","");             /* pParms */
710                 if (snum < 0) {
711                         PACKS(desc,"z","UNKNOWN PRINTER");
712                         PACKI(desc,"W",LPSTAT_ERROR);
713                 }
714                 else if (!status || !status->message[0]) {
715                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
716                         PACKI(desc,"W",LPSTAT_OK); /* status */
717                 } else {
718                         PACKS(desc,"z",status->message);
719                         PACKI(desc,"W",printq_status(status->status)); /* status */
720                 }
721                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
722         }
723
724         if (uLevel == 3 || uLevel == 4) {
725                 pstring drivername;
726
727                 PACKI(desc,"W",5);              /* uPriority */
728                 PACKI(desc,"W",0);              /* uStarttime */
729                 PACKI(desc,"W",0);              /* uUntiltime */
730                 PACKI(desc,"W",5);              /* pad1 */
731                 PACKS(desc,"z","");             /* pszSepFile */
732                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
733                 PACKS(desc,"z",NULL);           /* pszParms */
734                 PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
735                 /* "don't ask" that it's done this way to fix corrupted 
736                    Win9X/ME printer comments. */
737                 if (!status) {
738                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
739                 } else {
740                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
741                 }
742                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
743                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
744                 get_driver_name(snum,drivername);
745                 PACKS(desc,"z",drivername);             /* pszDriverName */
746                 PackDriverData(desc);   /* pDriverData */
747         }
748
749         if (uLevel == 2 || uLevel == 4) {
750                 int i;
751                 for (i=0;i<count;i++)
752                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
753         }
754
755         if (uLevel==52) {
756                 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
757         }
758 }
759
760 /* This function returns the number of files for a given driver */
761 static int get_printerdrivernumber(int snum)
762 {
763         int i, result = 0;
764         BOOL ok = False;
765         pstring tok;
766         char *p;
767         char **lines = NULL;
768         pstring gen_line;
769         pstring drivername;
770         
771         /*
772          * Check in the tdb *first* before checking the legacy
773          * files. This allows an NT upload to take precedence over
774          * the existing fileset. JRA.
775          *
776          * we need to lookup the driver name prior to making the call
777          * to get_a_printer_driver_9x_compatible() and not rely on the
778          * 'print driver' parameter --jerry
779          */
780         
781         if ((get_driver_name(snum,drivername)) && 
782             (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True)) 
783         {
784                 p = gen_line;
785                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
786         } 
787         else 
788         {
789                 /* didn't find driver in tdb */
790         
791                 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
792                           snum, drivername, lp_driverfile(snum)));
793                 
794                 lines = file_lines_load(lp_driverfile(snum), NULL);
795                 if (!lines) 
796                 {
797                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
798                         goto done;
799                 } 
800
801                 /* lookup the long printer driver name in the file description */
802                 for (i=0;lines[i] && !ok;i++) 
803                 {
804                         p = lines[i];
805                         if (next_token(&p,tok,":",sizeof(tok)) &&
806                            (strlen(drivername) == strlen(tok)) &&
807                            (!strncmp(tok,drivername,strlen(drivername)))) 
808                         {
809                                 ok = True;
810                         }
811                 }
812         }
813         
814         if( ok ) 
815         {
816                 /* skip 5 fields */
817                 i = 5;
818                 while (*p && i) {
819                         if (*p++ == ':') i--;
820                 }
821                 if (!*p || i) {
822                         DEBUG(3,("Can't determine number of printer driver files\n"));
823                         goto done;
824                 }
825                 
826                 /* count the number of files */
827                 while (next_token(&p,tok,",",sizeof(tok)))
828                         i++;
829         
830                 result = i;
831         }
832
833  done:
834
835         file_lines_free(lines);
836
837         return result;
838 }
839
840 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
841                                  uint16 vuid, char *param,char *data,
842                                  int mdrcnt,int mprcnt,
843                                  char **rdata,char **rparam,
844                                  int *rdata_len,int *rparam_len)
845 {
846         char *str1 = param+2;
847         char *str2 = skip_string(str1,1);
848         char *p = skip_string(str2,1);
849         char *QueueName = p;
850         int uLevel;
851         int count=0;
852         int snum;
853         char* str3;
854         struct pack_desc desc;
855         print_queue_struct *queue=NULL;
856         print_status_struct status;
857         char* tmpdata=NULL;
858
859         memset((char *)&status,'\0',sizeof(status));
860         memset((char *)&desc,'\0',sizeof(desc));
861  
862         p = skip_string(p,1);
863         uLevel = SVAL(p,0);
864         str3 = p + 4;
865  
866         /* remove any trailing username */
867         if ((p = strchr_m(QueueName,'%')))
868                 *p = 0;
869  
870         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
871  
872         /* check it's a supported varient */
873         if (!prefix_ok(str1,"zWrLh"))
874                 return False;
875         if (!check_printq_info(&desc,uLevel,str2,str3)) {
876                 /*
877                  * Patch from Scott Moomaw <scott@bridgewater.edu>
878                  * to return the 'invalid info level' error if an
879                  * unknown level was requested.
880                  */
881                 *rdata_len = 0;
882                 *rparam_len = 6;
883                 *rparam = REALLOC(*rparam,*rparam_len);
884                 SSVALS(*rparam,0,ERRunknownlevel);
885                 SSVAL(*rparam,2,0);
886                 SSVAL(*rparam,4,0);
887                 return(True);
888         }
889  
890         snum = lp_servicenumber(QueueName);
891         if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
892                 int pnum = lp_servicenumber(PRINTERS_NAME);
893                 if (pnum >= 0) {
894                         lp_add_printer(QueueName,pnum);
895                         snum = lp_servicenumber(QueueName);
896                 }
897         }
898   
899         if (snum < 0 || !VALID_SNUM(snum))
900                 return(False);
901
902         if (uLevel==52) {
903                 count = get_printerdrivernumber(snum);
904                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
905         } else {
906                 count = print_queue_status(snum, &queue,&status);
907         }
908
909         if (mdrcnt > 0) {
910                 *rdata = REALLOC(*rdata,mdrcnt);
911                 desc.base = *rdata;
912                 desc.buflen = mdrcnt;
913         } else {
914                 /*
915                  * Don't return data but need to get correct length
916                  * init_package will return wrong size if buflen=0
917                  */
918                 desc.buflen = getlen(desc.format);
919                 desc.base = tmpdata = (char *) malloc (desc.buflen);
920         }
921
922         if (init_package(&desc,1,count)) {
923                 desc.subcount = count;
924                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
925         }
926
927         *rdata_len = desc.usedlen;
928   
929         /*
930          * We must set the return code to ERRbuftoosmall
931          * in order to support lanman style printing with Win NT/2k
932          * clients       --jerry
933          */
934         if (!mdrcnt && lp_disable_spoolss())
935                 desc.errcode = ERRbuftoosmall;
936  
937     *rdata_len = desc.usedlen;
938         *rparam_len = 6;
939         *rparam = REALLOC(*rparam,*rparam_len);
940         SSVALS(*rparam,0,desc.errcode);
941         SSVAL(*rparam,2,0);
942         SSVAL(*rparam,4,desc.neededlen);
943   
944         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
945
946         SAFE_FREE(queue);
947         SAFE_FREE(tmpdata);
948
949         return(True);
950 }
951
952 /****************************************************************************
953  View list of all print jobs on all queues.
954 ****************************************************************************/
955
956 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
957                               int mdrcnt, int mprcnt,
958                               char **rdata, char** rparam,
959                               int *rdata_len, int *rparam_len)
960 {
961   char *param_format = param+2;
962   char *output_format1 = skip_string(param_format,1);
963   char *p = skip_string(output_format1,1);
964   int uLevel = SVAL(p,0);
965   char *output_format2 = p + 4;
966   int services = lp_numservices();
967   int i, n;
968   struct pack_desc desc;
969   print_queue_struct **queue = NULL;
970   print_status_struct *status = NULL;
971   int* subcntarr = NULL;
972   int queuecnt, subcnt=0, succnt=0;
973  
974   memset((char *)&desc,'\0',sizeof(desc));
975
976   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
977  
978   if (!prefix_ok(param_format,"WrLeh")) return False;
979   if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
980     /*
981      * Patch from Scott Moomaw <scott@bridgewater.edu>
982      * to return the 'invalid info level' error if an
983      * unknown level was requested.
984      */
985     *rdata_len = 0;
986     *rparam_len = 6;
987     *rparam = REALLOC(*rparam,*rparam_len);
988     SSVALS(*rparam,0,ERRunknownlevel);
989     SSVAL(*rparam,2,0);
990     SSVAL(*rparam,4,0);
991     return(True);
992   }
993
994   queuecnt = 0;
995   for (i = 0; i < services; i++)
996     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
997       queuecnt++;
998   if (uLevel > 0) {
999     if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1000       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1001       return False;
1002     }
1003     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1004     if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1005       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1006       return False;
1007     }
1008     memset(status,0,queuecnt*sizeof(print_status_struct));
1009     if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1010       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1011       return False;
1012     }
1013     subcnt = 0;
1014     n = 0;
1015     for (i = 0; i < services; i++)
1016       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1017         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1018         subcnt += subcntarr[n];
1019         n++;
1020       }
1021   }
1022   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1023   desc.base = *rdata;
1024   desc.buflen = mdrcnt;
1025
1026   if (init_package(&desc,queuecnt,subcnt)) {
1027     n = 0;
1028     succnt = 0;
1029     for (i = 0; i < services; i++)
1030       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1031         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1032         n++;
1033         if (desc.errcode == NERR_Success) succnt = n;
1034       }
1035   }
1036
1037   SAFE_FREE(subcntarr);
1038  
1039   *rdata_len = desc.usedlen;
1040   *rparam_len = 8;
1041   *rparam = REALLOC(*rparam,*rparam_len);
1042   SSVALS(*rparam,0,desc.errcode);
1043   SSVAL(*rparam,2,0);
1044   SSVAL(*rparam,4,succnt);
1045   SSVAL(*rparam,6,queuecnt);
1046   
1047   for (i = 0; i < queuecnt; i++) {
1048     if (queue) SAFE_FREE(queue[i]);
1049   }
1050
1051   SAFE_FREE(queue);
1052   SAFE_FREE(status);
1053   
1054   return True;
1055 }
1056
1057 /****************************************************************************
1058   get info level for a server list query
1059   ****************************************************************************/
1060 static BOOL check_server_info(int uLevel, char* id)
1061 {
1062   switch( uLevel ) {
1063   case 0:
1064     if (strcmp(id,"B16") != 0) return False;
1065     break;
1066   case 1:
1067     if (strcmp(id,"B16BBDz") != 0) return False;
1068     break;
1069   default: 
1070     return False;
1071   }
1072   return True;
1073 }
1074
1075 struct srv_info_struct
1076 {
1077   fstring name;
1078   uint32 type;
1079   fstring comment;
1080   fstring domain;
1081   BOOL server_added;
1082 };
1083
1084
1085 /*******************************************************************
1086   get server info lists from the files saved by nmbd. Return the
1087   number of entries
1088   ******************************************************************/
1089 static int get_server_info(uint32 servertype, 
1090                            struct srv_info_struct **servers,
1091                            char *domain)
1092 {
1093   int count=0;
1094   int alloced=0;
1095   char **lines;
1096   BOOL local_list_only;
1097   int i;
1098
1099   lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1100   if (!lines) {
1101     DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1102     return(0);
1103   }
1104
1105   /* request for everything is code for request all servers */
1106   if (servertype == SV_TYPE_ALL) 
1107         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1108
1109   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1110
1111   DEBUG(4,("Servertype search: %8x\n",servertype));
1112
1113   for (i=0;lines[i];i++) {
1114     fstring stype;
1115     struct srv_info_struct *s;
1116     char *ptr = lines[i];
1117     BOOL ok = True;
1118
1119     if (!*ptr) continue;
1120     
1121     if (count == alloced) {
1122       struct srv_info_struct *ts;
1123       
1124       alloced += 10;
1125       ts = (struct srv_info_struct *)
1126         Realloc(*servers,sizeof(**servers)*alloced);
1127       if (!ts) {
1128         DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1129         return(0);
1130       }
1131       else *servers = ts;
1132       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1133     }
1134     s = &(*servers)[count];
1135     
1136     if (!next_token(&ptr,s->name   , NULL, sizeof(s->name))) continue;
1137     if (!next_token(&ptr,stype     , NULL, sizeof(stype))) continue;
1138     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1139     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1140       /* this allows us to cope with an old nmbd */
1141       pstrcpy(s->domain,global_myworkgroup); 
1142     }
1143     
1144     if (sscanf(stype,"%X",&s->type) != 1) { 
1145       DEBUG(4,("r:host file ")); 
1146       ok = False; 
1147     }
1148     
1149         /* Filter the servers/domains we return based on what was asked for. */
1150
1151         /* Check to see if we are being asked for a local list only. */
1152         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1153           DEBUG(4,("r: local list only"));
1154           ok = False;
1155         }
1156
1157     /* doesn't match up: don't want it */
1158     if (!(servertype & s->type)) { 
1159       DEBUG(4,("r:serv type ")); 
1160       ok = False; 
1161     }
1162     
1163     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1164         (s->type & SV_TYPE_DOMAIN_ENUM))
1165       {
1166         DEBUG(4,("s: dom mismatch "));
1167         ok = False;
1168       }
1169     
1170     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1171       {
1172         ok = False;
1173       }
1174     
1175         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1176         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1177
1178     if (ok)
1179       {
1180         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1181                  s->name, s->type, s->comment, s->domain));
1182         
1183         s->server_added = True;
1184         count++;
1185       }
1186     else
1187       {
1188         DEBUG(4,("%20s %8x %25s %15s\n",
1189                  s->name, s->type, s->comment, s->domain));
1190       }
1191   }
1192   
1193   file_lines_free(lines);
1194   return(count);
1195 }
1196
1197
1198 /*******************************************************************
1199   fill in a server info structure
1200   ******************************************************************/
1201 static int fill_srv_info(struct srv_info_struct *service, 
1202                          int uLevel, char **buf, int *buflen, 
1203                          char **stringbuf, int *stringspace, char *baseaddr)
1204 {
1205   int struct_len;
1206   char* p;
1207   char* p2;
1208   int l2;
1209   int len;
1210  
1211   switch (uLevel) {
1212   case 0: struct_len = 16; break;
1213   case 1: struct_len = 26; break;
1214   default: return -1;
1215   }  
1216  
1217   if (!buf)
1218     {
1219       len = 0;
1220       switch (uLevel) 
1221         {
1222         case 1:
1223           len = strlen(service->comment)+1;
1224           break;
1225         }
1226
1227       if (buflen) *buflen = struct_len;
1228       if (stringspace) *stringspace = len;
1229       return struct_len + len;
1230     }
1231   
1232   len = struct_len;
1233   p = *buf;
1234   if (*buflen < struct_len) return -1;
1235   if (stringbuf)
1236     {
1237       p2 = *stringbuf;
1238       l2 = *stringspace;
1239     }
1240   else
1241     {
1242       p2 = p + struct_len;
1243       l2 = *buflen - struct_len;
1244     }
1245   if (!baseaddr) baseaddr = p;
1246   
1247   switch (uLevel)
1248     {
1249     case 0:
1250             push_ascii(p,service->name, 15, STR_TERMINATE);
1251             break;
1252
1253     case 1:
1254             push_ascii(p,service->name,15, STR_TERMINATE);
1255             SIVAL(p,18,service->type);
1256             SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1257             len += CopyAndAdvance(&p2,service->comment,&l2);
1258             break;
1259     }
1260
1261   if (stringbuf)
1262     {
1263       *buf = p + struct_len;
1264       *buflen -= struct_len;
1265       *stringbuf = p2;
1266       *stringspace = l2;
1267     }
1268   else
1269     {
1270       *buf = p2;
1271       *buflen -= len;
1272     }
1273   return len;
1274 }
1275
1276
1277 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1278 {
1279   return(strcmp(s1->name,s2->name));
1280 }
1281
1282 /****************************************************************************
1283   view list of servers available (or possibly domains). The info is
1284   extracted from lists saved by nmbd on the local host
1285   ****************************************************************************/
1286 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1287                                int mdrcnt, int mprcnt, char **rdata, 
1288                                char **rparam, int *rdata_len, int *rparam_len)
1289 {
1290   char *str1 = param+2;
1291   char *str2 = skip_string(str1,1);
1292   char *p = skip_string(str2,1);
1293   int uLevel = SVAL(p,0);
1294   int buf_len = SVAL(p,2);
1295   uint32 servertype = IVAL(p,4);
1296   char *p2;
1297   int data_len, fixed_len, string_len;
1298   int f_len = 0, s_len = 0;
1299   struct srv_info_struct *servers=NULL;
1300   int counted=0,total=0;
1301   int i,missed;
1302   fstring domain;
1303   BOOL domain_request;
1304   BOOL local_request;
1305
1306   /* If someone sets all the bits they don't really mean to set
1307      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1308      known servers. */
1309
1310   if (servertype == SV_TYPE_ALL) 
1311     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1312
1313   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1314      any other bit (they may just set this bit on it's own) they 
1315      want all the locally seen servers. However this bit can be 
1316      set on its own so set the requested servers to be 
1317      ALL - DOMAIN_ENUM. */
1318
1319   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1320     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1321
1322   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1323   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1324
1325   p += 8;
1326
1327   if (!prefix_ok(str1,"WrLehD")) return False;
1328   if (!check_server_info(uLevel,str2)) return False;
1329   
1330   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1331   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1332   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1333
1334   if (strcmp(str1, "WrLehDz") == 0) {
1335           pull_ascii_fstring(domain, p);
1336   } else {
1337           fstrcpy(domain, global_myworkgroup);
1338   }
1339
1340   if (lp_browse_list())
1341     total = get_server_info(servertype,&servers,domain);
1342
1343   data_len = fixed_len = string_len = 0;
1344   missed = 0;
1345
1346   if (total > 0)
1347     qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1348
1349   {
1350     char *lastname=NULL;
1351
1352     for (i=0;i<total;i++)
1353     {
1354       struct srv_info_struct *s = &servers[i];
1355       if (lastname && strequal(lastname,s->name)) continue;
1356       lastname = s->name;
1357       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1358       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1359                s->name, s->type, s->comment, s->domain));
1360       
1361       if (data_len <= buf_len) {
1362           counted++;
1363           fixed_len += f_len;
1364           string_len += s_len;
1365       } else {
1366         missed++;
1367       }
1368     }
1369   }
1370
1371   *rdata_len = fixed_len + string_len;
1372   *rdata = REALLOC(*rdata,*rdata_len);
1373   memset(*rdata,'\0',*rdata_len);
1374   
1375   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1376   p = *rdata;
1377   f_len = fixed_len;
1378   s_len = string_len;
1379
1380   {
1381     char *lastname=NULL;
1382     int count2 = counted;
1383     for (i = 0; i < total && count2;i++)
1384       {
1385         struct srv_info_struct *s = &servers[i];
1386         if (lastname && strequal(lastname,s->name)) continue;
1387         lastname = s->name;
1388         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1389         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1390                  s->name, s->type, s->comment, s->domain));
1391         count2--;
1392       }
1393   }
1394   
1395   *rparam_len = 8;
1396   *rparam = REALLOC(*rparam,*rparam_len);
1397   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1398   SSVAL(*rparam,2,0);
1399   SSVAL(*rparam,4,counted);
1400   SSVAL(*rparam,6,counted+missed);
1401
1402   SAFE_FREE(servers);
1403
1404   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1405            domain,uLevel,counted,counted+missed));
1406
1407   return(True);
1408 }
1409
1410 /****************************************************************************
1411   command 0x34 - suspected of being a "Lookup Names" stub api
1412   ****************************************************************************/
1413 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1414                                int mdrcnt, int mprcnt, char **rdata, 
1415                                char **rparam, int *rdata_len, int *rparam_len)
1416 {
1417   char *str1 = param+2;
1418   char *str2 = skip_string(str1,1);
1419   char *p = skip_string(str2,1);
1420   int uLevel = SVAL(p,0);
1421   int buf_len = SVAL(p,2);
1422   int counted=0;
1423   int missed=0;
1424
1425         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1426                 str1, str2, p, uLevel, buf_len));
1427
1428   if (!prefix_ok(str1,"zWrLeh")) return False;
1429   
1430   *rdata_len = 0;
1431   
1432   *rparam_len = 8;
1433   *rparam = REALLOC(*rparam,*rparam_len);
1434
1435   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1436   SSVAL(*rparam,2,0);
1437   SSVAL(*rparam,4,counted);
1438   SSVAL(*rparam,6,counted+missed);
1439
1440   return(True);
1441 }
1442
1443 /****************************************************************************
1444   get info about a share
1445   ****************************************************************************/
1446 static BOOL check_share_info(int uLevel, char* id)
1447 {
1448   switch( uLevel ) {
1449   case 0:
1450     if (strcmp(id,"B13") != 0) return False;
1451     break;
1452   case 1:
1453     if (strcmp(id,"B13BWz") != 0) return False;
1454     break;
1455   case 2:
1456     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1457     break;
1458   case 91:
1459     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1460     break;
1461   default: return False;
1462   }
1463   return True;
1464 }
1465
1466 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1467                            char** buf, int* buflen,
1468                            char** stringbuf, int* stringspace, char* baseaddr)
1469 {
1470   int struct_len;
1471   char* p;
1472   char* p2;
1473   int l2;
1474   int len;
1475  
1476   switch( uLevel ) {
1477   case 0: struct_len = 13; break;
1478   case 1: struct_len = 20; break;
1479   case 2: struct_len = 40; break;
1480   case 91: struct_len = 68; break;
1481   default: return -1;
1482   }
1483   
1484  
1485   if (!buf)
1486     {
1487       len = 0;
1488       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1489       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1490       if (buflen) *buflen = struct_len;
1491       if (stringspace) *stringspace = len;
1492       return struct_len + len;
1493     }
1494   
1495   len = struct_len;
1496   p = *buf;
1497   if ((*buflen) < struct_len) return -1;
1498   if (stringbuf)
1499     {
1500       p2 = *stringbuf;
1501       l2 = *stringspace;
1502     }
1503   else
1504     {
1505       p2 = p + struct_len;
1506       l2 = (*buflen) - struct_len;
1507     }
1508   if (!baseaddr) baseaddr = p;
1509   
1510   push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1511   
1512   if (uLevel > 0)
1513     {
1514       int type;
1515       SCVAL(p,13,0);
1516       type = STYPE_DISKTREE;
1517       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1518       if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
1519       SSVAL(p,14,type);         /* device type */
1520       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1521       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1522     }
1523   
1524   if (uLevel > 1)
1525     {
1526       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1527       SSVALS(p,22,-1);          /* max uses */
1528       SSVAL(p,24,1); /* current uses */
1529       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1530       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1531       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1532     }
1533   
1534   if (uLevel > 2)
1535     {
1536       memset(p+40,0,SHPWLEN+2);
1537       SSVAL(p,50,0);
1538       SIVAL(p,52,0);
1539       SSVAL(p,56,0);
1540       SSVAL(p,58,0);
1541       SIVAL(p,60,0);
1542       SSVAL(p,64,0);
1543       SSVAL(p,66,0);
1544     }
1545        
1546   if (stringbuf)
1547     {
1548       (*buf) = p + struct_len;
1549       (*buflen) -= struct_len;
1550       (*stringbuf) = p2;
1551       (*stringspace) = l2;
1552     }
1553   else
1554     {
1555       (*buf) = p2;
1556       (*buflen) -= len;
1557     }
1558   return len;
1559 }
1560
1561 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1562                                  int mdrcnt,int mprcnt,
1563                                  char **rdata,char **rparam,
1564                                  int *rdata_len,int *rparam_len)
1565 {
1566   char *str1 = param+2;
1567   char *str2 = skip_string(str1,1);
1568   char *netname = skip_string(str2,1);
1569   char *p = skip_string(netname,1);
1570   int uLevel = SVAL(p,0);
1571   int snum = find_service(netname);
1572   
1573   if (snum < 0) return False;
1574   
1575   /* check it's a supported varient */
1576   if (!prefix_ok(str1,"zWrLh")) return False;
1577   if (!check_share_info(uLevel,str2)) return False;
1578  
1579   *rdata = REALLOC(*rdata,mdrcnt);
1580   p = *rdata;
1581   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1582   if (*rdata_len < 0) return False;
1583  
1584   *rparam_len = 6;
1585   *rparam = REALLOC(*rparam,*rparam_len);
1586   SSVAL(*rparam,0,NERR_Success);
1587   SSVAL(*rparam,2,0);           /* converter word */
1588   SSVAL(*rparam,4,*rdata_len);
1589  
1590   return(True);
1591 }
1592
1593 /****************************************************************************
1594   view list of shares available
1595   ****************************************************************************/
1596 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1597                               int mdrcnt,int mprcnt,
1598                               char **rdata,char **rparam,
1599                               int *rdata_len,int *rparam_len)
1600 {
1601   char *str1 = param+2;
1602   char *str2 = skip_string(str1,1);
1603   char *p = skip_string(str2,1);
1604   int uLevel = SVAL(p,0);
1605   int buf_len = SVAL(p,2);
1606   char *p2;
1607   int count=lp_numservices();
1608   int total=0,counted=0;
1609   BOOL missed = False;
1610   int i;
1611   int data_len, fixed_len, string_len;
1612   int f_len = 0, s_len = 0;
1613  
1614   if (!prefix_ok(str1,"WrLeh")) return False;
1615   if (!check_share_info(uLevel,str2)) return False;
1616   
1617   data_len = fixed_len = string_len = 0;
1618   for (i=0;i<count;i++)
1619     if (lp_browseable(i) && lp_snum_ok(i))
1620     {
1621       total++;
1622       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1623       if (data_len <= buf_len)
1624       {
1625         counted++;
1626         fixed_len += f_len;
1627         string_len += s_len;
1628       }
1629       else
1630         missed = True;
1631     }
1632   *rdata_len = fixed_len + string_len;
1633   *rdata = REALLOC(*rdata,*rdata_len);
1634   memset(*rdata,0,*rdata_len);
1635   
1636   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1637   p = *rdata;
1638   f_len = fixed_len;
1639   s_len = string_len;
1640   for (i = 0; i < count;i++)
1641     if (lp_browseable(i) && lp_snum_ok(i))
1642       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1643         break;
1644   
1645   *rparam_len = 8;
1646   *rparam = REALLOC(*rparam,*rparam_len);
1647   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1648   SSVAL(*rparam,2,0);
1649   SSVAL(*rparam,4,counted);
1650   SSVAL(*rparam,6,total);
1651   
1652   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1653            counted,total,uLevel,
1654            buf_len,*rdata_len,mdrcnt));
1655   return(True);
1656 }
1657
1658 /****************************************************************************
1659   Add a share
1660   ****************************************************************************/
1661 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
1662                                  int mdrcnt,int mprcnt,
1663                                  char **rdata,char **rparam,
1664                                  int *rdata_len,int *rparam_len)
1665 {
1666   char *str1 = param+2;
1667   char *str2 = skip_string(str1,1);
1668   char *p = skip_string(str2,1);
1669   int uLevel = SVAL(p,0);
1670   fstring sharename;
1671   fstring comment;
1672   pstring pathname;
1673   char *command, *cmdname;
1674   uint offset;
1675   int snum;
1676   int res = ERRunsup;
1677   
1678   /* check it's a supported varient */
1679   if (!prefix_ok(str1,RAP_WShareAdd_REQ)) return False;
1680   if (!check_share_info(uLevel,str2)) return False;
1681   if (uLevel != 2) return False;
1682
1683   pull_ascii_fstring(sharename,data);
1684   snum = find_service(sharename);
1685   if (snum >= 0) { /* already exists */
1686     res = ERRfilexists;
1687     goto error_exit;
1688   }
1689
1690   /* only support disk share adds */
1691   if (SVAL(data,14)!=STYPE_DISKTREE) return False;
1692
1693   offset = IVAL(data, 16);
1694   if (offset >= mdrcnt) {
1695     res = ERRinvalidparam;
1696     goto error_exit;
1697   }
1698   pull_ascii_fstring(comment, offset? (data+offset) : "");
1699
1700   offset = IVAL(data, 26);
1701   if (offset >= mdrcnt) {
1702     res = ERRinvalidparam;
1703     goto error_exit;
1704   }
1705   pull_ascii_pstring(pathname, offset? (data+offset) : "");
1706
1707   string_replace(sharename, '"', ' ');
1708   string_replace(pathname, '"', ' ');
1709   string_replace(comment, '"', ' ');
1710
1711   cmdname = lp_add_share_cmd();
1712
1713   if (!cmdname || *cmdname == '\0') return False;
1714
1715   asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1716            lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1717
1718   if (command) {
1719     DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1720     if ((res = smbrun(command, NULL)) != 0) {
1721       DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1722       SAFE_FREE(command);
1723       res = ERRnoaccess;
1724       goto error_exit;
1725     } else {
1726       SAFE_FREE(command);
1727       message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1728     }
1729   } else return False;
1730
1731   *rparam_len = 6;
1732   *rparam = REALLOC(*rparam,*rparam_len);
1733   SSVAL(*rparam,0,NERR_Success);
1734   SSVAL(*rparam,2,0);           /* converter word */
1735   SSVAL(*rparam,4,*rdata_len);
1736   *rdata_len = 0;
1737   
1738   return True;
1739
1740  error_exit:
1741   *rparam_len = 4;
1742   *rparam = REALLOC(*rparam,*rparam_len);
1743   *rdata_len = 0;
1744   SSVAL(*rparam,0,res);
1745   SSVAL(*rparam,2,0);
1746   return True;
1747
1748 }
1749
1750 /****************************************************************************
1751   view list of groups available
1752   ****************************************************************************/
1753 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1754                               int mdrcnt,int mprcnt,
1755                               char **rdata,char **rparam,
1756                               int *rdata_len,int *rparam_len)
1757 {
1758         char *str1 = param+2;
1759         char *str2 = skip_string(str1,1);
1760         char *p = skip_string(str2,1);
1761         int uLevel = SVAL(p,0);
1762         char *p2;
1763         int count=0;
1764
1765         if (!prefix_ok(str1,"WrLeh")) return False;
1766   
1767         /* check it's a supported variant */
1768         switch( uLevel )
1769         {
1770                 case 0: 
1771                         p2 = "B21"; 
1772                         break;
1773                 default: 
1774                         return False;
1775         }
1776
1777         if (strcmp(p2,str2) != 0) return False;
1778
1779         *rdata_len = mdrcnt + 1024;
1780         *rdata = REALLOC(*rdata,*rdata_len);
1781
1782         SSVAL(*rparam,0,NERR_Success);
1783         SSVAL(*rparam,2,0);             /* converter word */
1784
1785         p = *rdata;
1786
1787         /* XXXX we need a real SAM database some day */
1788         pstrcpy(p,"Users"); p += 21; count++;
1789         pstrcpy(p,"Domain Users"); p += 21; count++;
1790         pstrcpy(p,"Guests"); p += 21; count++;
1791         pstrcpy(p,"Domain Guests"); p += 21; count++;
1792
1793         *rdata_len = PTR_DIFF(p,*rdata);
1794
1795         *rparam_len = 8;
1796         *rparam = REALLOC(*rparam,*rparam_len);
1797
1798         SSVAL(*rparam,4,count); /* is this right?? */
1799         SSVAL(*rparam,6,count); /* is this right?? */
1800
1801         DEBUG(3,("api_RNetGroupEnum gave %d entries\n", count));
1802
1803         return(True);
1804 }
1805
1806 /****************************************************************************
1807   view list of groups available
1808   ****************************************************************************/
1809 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1810                               int mdrcnt,int mprcnt,
1811                               char **rdata,char **rparam,
1812                               int *rdata_len,int *rparam_len)
1813 {
1814         char *str1 = param+2;
1815         char *str2 = skip_string(str1,1);
1816         char *p = skip_string(str2,1);
1817         int uLevel = SVAL(p,0);
1818         char *p2;
1819         int count=0;
1820
1821         if (!prefix_ok(str1,"WrLeh")) return False;
1822   
1823         /* check it's a supported variant */
1824         switch( uLevel )
1825         {
1826                 case 0: 
1827                         p2 = "B21"; 
1828                         break;
1829                 default: 
1830                         return False;
1831         }
1832
1833         if (strcmp(p2,str2) != 0) return False;
1834
1835         *rdata_len = mdrcnt + 1024;
1836         *rdata = REALLOC(*rdata,*rdata_len);
1837
1838         SSVAL(*rparam,0,NERR_Success);
1839         SSVAL(*rparam,2,0);             /* converter word */
1840
1841         p = *rdata;
1842
1843         /* XXXX we need a real SAM database some day */
1844         pstrcpy(p,"Users"); p += 21; count++;
1845         pstrcpy(p,"Domain Users"); p += 21; count++;
1846         pstrcpy(p,"Guests"); p += 21; count++;
1847         pstrcpy(p,"Domain Guests"); p += 21; count++;
1848
1849         *rdata_len = PTR_DIFF(p,*rdata);
1850
1851         *rparam_len = 8;
1852         *rparam = REALLOC(*rparam,*rparam_len);
1853
1854         SSVAL(*rparam,4,count); /* is this right?? */
1855         SSVAL(*rparam,6,count); /* is this right?? */
1856
1857         DEBUG(3,("api_RNetUserEnum gave %d entries\n", count));
1858
1859         return(True);
1860 }
1861
1862
1863
1864 /****************************************************************************
1865   get the time of day info
1866   ****************************************************************************/
1867 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1868                              int mdrcnt,int mprcnt,
1869                              char **rdata,char **rparam,
1870                              int *rdata_len,int *rparam_len)
1871 {
1872   char *p;
1873   *rparam_len = 4;
1874   *rparam = REALLOC(*rparam,*rparam_len);
1875
1876   *rdata_len = 21;
1877   *rdata = REALLOC(*rdata,*rdata_len);
1878
1879   SSVAL(*rparam,0,NERR_Success);
1880   SSVAL(*rparam,2,0);           /* converter word */
1881
1882   p = *rdata;
1883
1884   {
1885     struct tm *t;
1886     time_t unixdate = time(NULL);
1887
1888     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1889                                     by NT in a "net time" operation,
1890                                     it seems to ignore the one below */
1891
1892     /* the client expects to get localtime, not GMT, in this bit 
1893        (I think, this needs testing) */
1894     t = LocalTime(&unixdate);
1895
1896     SIVAL(p,4,0);               /* msecs ? */
1897     SCVAL(p,8,t->tm_hour);
1898     SCVAL(p,9,t->tm_min);
1899     SCVAL(p,10,t->tm_sec);
1900     SCVAL(p,11,0);              /* hundredths of seconds */
1901     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1902     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1903     SCVAL(p,16,t->tm_mday);
1904     SCVAL(p,17,t->tm_mon + 1);
1905     SSVAL(p,18,1900+t->tm_year);
1906     SCVAL(p,20,t->tm_wday);
1907   }
1908
1909
1910   return(True);
1911 }
1912
1913 /****************************************************************************
1914  Set the user password.
1915 *****************************************************************************/
1916
1917 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1918                                 int mdrcnt,int mprcnt,
1919                                 char **rdata,char **rparam,
1920                                 int *rdata_len,int *rparam_len)
1921 {
1922   char *p = skip_string(param+2,2);
1923   fstring user;
1924   fstring pass1,pass2;
1925
1926   pull_ascii_fstring(user,p);
1927
1928   p = skip_string(p,1);
1929
1930   memset(pass1,'\0',sizeof(pass1));
1931   memset(pass2,'\0',sizeof(pass2));
1932   memcpy(pass1,p,16);
1933   memcpy(pass2,p+16,16);
1934
1935   *rparam_len = 4;
1936   *rparam = REALLOC(*rparam,*rparam_len);
1937
1938   *rdata_len = 0;
1939
1940   SSVAL(*rparam,0,NERR_badpass);
1941   SSVAL(*rparam,2,0);           /* converter word */
1942
1943   DEBUG(3,("Set password for <%s>\n",user));
1944
1945   /*
1946    * Attempt to verify the old password against smbpasswd entries
1947    * Win98 clients send old and new password in plaintext for this call.
1948    */
1949
1950   {
1951           auth_serversupplied_info *server_info = NULL;
1952           DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
1953           if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
1954                   if (change_oem_password(server_info->sam_account,pass2))
1955                   {
1956                           SSVAL(*rparam,0,NERR_Success);
1957                   }
1958                   
1959                   /*
1960                    * If unix password sync was requested, attempt to change
1961                    * the /etc/passwd database also. Return failure if this cannot
1962                    * be done.
1963                    *
1964                    * This occours regardless of the previous result, becouse 
1965                    * It might not have been testing the password against the SAM backend.
1966                    * (and therefore the change_oem_password would fail).
1967                    *
1968                    * Conditional on lp_unix_password_sync() becouse we don't want
1969                    * to touch the unix db unless we have admin permission.
1970                    */
1971                   
1972                   if(lp_unix_password_sync() && !chgpasswd(pdb_get_username(server_info->sam_account),
1973                                                            pass1,pass2,False)) {
1974                           SSVAL(*rparam,0,NERR_badpass);
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 }