Use asprintf, do bounds check, better rc logic
[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       CVAL(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(), 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);
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     CVAL(p,8) = t->tm_hour;
1898     CVAL(p,9) = t->tm_min;
1899     CVAL(p,10) = t->tm_sec;
1900     CVAL(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     CVAL(p,16) = t->tm_mday;
1904     CVAL(p,17) = t->tm_mon + 1;
1905     SSVAL(p,18,1900+t->tm_year);
1906     CVAL(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   struct passwd *passwd;
1927
1928   pull_ascii_fstring(user,p);
1929
1930   p = skip_string(p,1);
1931
1932   memset(pass1,'\0',sizeof(pass1));
1933   memset(pass2,'\0',sizeof(pass2));
1934   memcpy(pass1,p,16);
1935   memcpy(pass2,p+16,16);
1936
1937   *rparam_len = 4;
1938   *rparam = REALLOC(*rparam,*rparam_len);
1939
1940   *rdata_len = 0;
1941
1942   SSVAL(*rparam,0,NERR_badpass);
1943   SSVAL(*rparam,2,0);           /* converter word */
1944
1945   DEBUG(3,("Set password for <%s>\n",user));
1946
1947   /*
1948    * Pass the user through the NT -> unix user mapping
1949    * function.
1950    */
1951
1952   (void)map_username(user);
1953
1954   /*
1955    * Do any UNIX username case mangling.
1956    */
1957   passwd = Get_Pwnam( user, True);
1958
1959   /*
1960    * Attempt to verify the old password against smbpasswd entries
1961    * Win98 clients send old and new password in plaintext for this call.
1962    */
1963
1964   {
1965     fstring saved_pass2;
1966     SAM_ACCOUNT *sampass=NULL;
1967
1968     /*
1969      * Save the new password as change_oem_password overwrites it
1970      * with zeros.
1971      */
1972
1973     fstrcpy(saved_pass2, pass2);
1974
1975     if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1976         change_oem_password(sampass,pass2))
1977     {
1978       SSVAL(*rparam,0,NERR_Success);
1979
1980       /*
1981        * If unix password sync was requested, attempt to change
1982        * the /etc/passwd database also. Return failure if this cannot
1983        * be done.
1984        */
1985
1986       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1987         SSVAL(*rparam,0,NERR_badpass);
1988     }
1989         pdb_free_sam(&sampass);
1990  }
1991   
1992
1993   /*
1994    * If the above failed, attempt the plaintext password change.
1995    * This tests against the /etc/passwd database only.
1996    */
1997
1998   if(SVAL(*rparam,0) != NERR_Success)
1999   {
2000           if NT_STATUS_IS_OK(pass_check(passwd, user, pass1, 
2001                                         strlen(pass1), NULL, False)) 
2002                   {
2003                           if (chgpasswd(user,pass1,pass2,False)) {
2004                                   SSVAL(*rparam,0,NERR_Success);
2005                           }
2006                   }
2007   }
2008   
2009   /*
2010    * If the plaintext change failed, attempt
2011    * the old encrypted method. NT will generate this
2012    * after trying the samr method. Note that this
2013    * method is done as a last resort as this
2014    * password change method loses the NT password hash
2015    * and cannot change the UNIX password as no plaintext
2016    * is received.
2017    */
2018
2019   if(SVAL(*rparam,0) != NERR_Success)
2020   {
2021     SAM_ACCOUNT *hnd = NULL;
2022
2023     if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
2024        change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
2025     {
2026       SSVAL(*rparam,0,NERR_Success);
2027     }
2028         pdb_free_sam(&hnd);
2029   }
2030
2031
2032   memset((char *)pass1,'\0',sizeof(fstring));
2033   memset((char *)pass2,'\0',sizeof(fstring));    
2034          
2035   return(True);
2036 }
2037
2038 /****************************************************************************
2039   Set the user password (SamOEM version - gets plaintext).
2040 ****************************************************************************/
2041
2042 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2043                                 int mdrcnt,int mprcnt,
2044                                 char **rdata,char **rparam,
2045                                 int *rdata_len,int *rparam_len)
2046 {
2047   fstring user;
2048   char *p = param + 2;
2049   *rparam_len = 2;
2050   *rparam = REALLOC(*rparam,*rparam_len);
2051
2052   *rdata_len = 0;
2053
2054   SSVAL(*rparam,0,NERR_badpass);
2055
2056   /*
2057    * Check the parameter definition is correct.
2058    */
2059   if(!strequal(param + 2, "zsT")) {
2060     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
2061     return False;
2062   }
2063   p = skip_string(p, 1);
2064
2065   if(!strequal(p, "B516B16")) {
2066     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2067     return False;
2068   }
2069   p = skip_string(p,1);
2070
2071   p += pull_ascii_fstring(user,p);
2072
2073   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2074
2075   /*
2076    * Pass the user through the NT -> unix user mapping
2077    * function.
2078    */
2079
2080   (void)map_username(user);
2081
2082   /*
2083    * Do any UNIX username case mangling.
2084    */
2085   (void)Get_Pwnam( user, True);
2086
2087   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
2088   {
2089     SSVAL(*rparam,0,NERR_Success);
2090   }
2091
2092   return(True);
2093 }
2094
2095 /****************************************************************************
2096   delete a print job
2097   Form: <W> <> 
2098   ****************************************************************************/
2099 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2100                                 int mdrcnt,int mprcnt,
2101                                 char **rdata,char **rparam,
2102                                 int *rdata_len,int *rparam_len)
2103 {
2104         int function = SVAL(param,0);
2105         char *str1 = param+2;
2106         char *str2 = skip_string(str1,1);
2107         char *p = skip_string(str2,1);
2108         int jobid, errcode;
2109         extern struct current_user current_user;
2110         WERROR werr = WERR_OK;
2111
2112         jobid = SVAL(p,0);
2113
2114         /* check it's a supported varient */
2115         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2116                 return(False);
2117
2118         *rparam_len = 4;
2119         *rparam = REALLOC(*rparam,*rparam_len); 
2120         *rdata_len = 0;
2121
2122         if (!print_job_exists(jobid)) {
2123                 errcode = NERR_JobNotFound;
2124                 goto out;
2125         }
2126
2127         errcode = NERR_notsupported;
2128         
2129         switch (function) {
2130         case 81:                /* delete */ 
2131                 if (print_job_delete(&current_user, jobid, &werr)) 
2132                         errcode = NERR_Success;
2133                 break;
2134         case 82:                /* pause */
2135                 if (print_job_pause(&current_user, jobid, &werr)) 
2136                         errcode = NERR_Success;
2137                 break;
2138         case 83:                /* resume */
2139                 if (print_job_resume(&current_user, jobid, &werr)) 
2140                         errcode = NERR_Success;
2141                 break;
2142         }
2143
2144         if (!W_ERROR_IS_OK(werr))
2145                 errcode = W_ERROR_V(werr);
2146         
2147  out:
2148         SSVAL(*rparam,0,errcode);       
2149         SSVAL(*rparam,2,0);             /* converter word */
2150
2151         return(True);
2152 }
2153
2154 /****************************************************************************
2155   Purge a print queue - or pause or resume it.
2156   ****************************************************************************/
2157 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2158                                  int mdrcnt,int mprcnt,
2159                                  char **rdata,char **rparam,
2160                                  int *rdata_len,int *rparam_len)
2161 {
2162         int function = SVAL(param,0);
2163         char *str1 = param+2;
2164         char *str2 = skip_string(str1,1);
2165         char *QueueName = skip_string(str2,1);
2166         int errcode = NERR_notsupported;
2167         int snum;
2168         WERROR werr = WERR_OK;
2169         extern struct current_user current_user;
2170
2171         /* check it's a supported varient */
2172         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2173                 return(False);
2174
2175         *rparam_len = 4;
2176         *rparam = REALLOC(*rparam,*rparam_len);
2177         *rdata_len = 0;
2178
2179         snum = print_queue_snum(QueueName);
2180
2181         if (snum == -1) {
2182                 errcode = NERR_JobNotFound;
2183                 goto out;
2184         }
2185
2186         switch (function) {
2187         case 74: /* Pause queue */
2188                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2189                 break;
2190         case 75: /* Resume queue */
2191                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2192                 break;
2193         case 103: /* Purge */
2194                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2195                 break;
2196         }
2197
2198         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2199
2200  out:
2201         SSVAL(*rparam,0,errcode);
2202         SSVAL(*rparam,2,0);             /* converter word */
2203
2204         return(True);
2205 }
2206
2207
2208 /****************************************************************************
2209   set the property of a print job (undocumented?)
2210   ? function = 0xb -> set name of print job
2211   ? function = 0x6 -> move print job up/down
2212   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2213   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2214 ****************************************************************************/
2215 static int check_printjob_info(struct pack_desc* desc,
2216                                int uLevel, char* id)
2217 {
2218         desc->subformat = NULL;
2219         switch( uLevel ) {
2220         case 0: desc->format = "W"; break;
2221         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2222         case 2: desc->format = "WWzWWDDzz"; break;
2223         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2224         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2225         default: return False;
2226         }
2227         if (strcmp(desc->format,id) != 0) return False;
2228         return True;
2229 }
2230
2231 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2232                              int mdrcnt,int mprcnt,
2233                              char **rdata,char **rparam,
2234                              int *rdata_len,int *rparam_len)
2235 {
2236         struct pack_desc desc;
2237         char *str1 = param+2;
2238         char *str2 = skip_string(str1,1);
2239         char *p = skip_string(str2,1);
2240         int jobid;
2241         int uLevel = SVAL(p,2);
2242         int function = SVAL(p,4);
2243         int place, errcode;
2244
2245         jobid = SVAL(p,0);
2246         *rparam_len = 4;
2247         *rparam = REALLOC(*rparam,*rparam_len);
2248   
2249         *rdata_len = 0;
2250         
2251         /* check it's a supported varient */
2252         if ((strcmp(str1,"WWsTP")) || 
2253             (!check_printjob_info(&desc,uLevel,str2)))
2254                 return(False);
2255
2256         if (!print_job_exists(jobid)) {
2257                 errcode=NERR_JobNotFound;
2258                 goto out;
2259         }
2260
2261         errcode = NERR_notsupported;
2262
2263         switch (function) {
2264         case 0x6:
2265                 /* change job place in the queue, 
2266                    data gives the new place */
2267                 place = SVAL(data,0);
2268                 if (print_job_set_place(jobid, place)) {
2269                         errcode=NERR_Success;
2270                 }
2271                 break;
2272
2273         case 0xb:   
2274                 /* change print job name, data gives the name */
2275                 if (print_job_set_name(jobid, data)) {
2276                         errcode=NERR_Success;
2277                 }
2278                 break;
2279
2280         default:
2281                 return False;
2282         }
2283
2284  out:
2285         SSVALS(*rparam,0,errcode);
2286         SSVAL(*rparam,2,0);             /* converter word */
2287         
2288         return(True);
2289 }
2290
2291
2292 /****************************************************************************
2293   get info about the server
2294   ****************************************************************************/
2295 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2296                                   int mdrcnt,int mprcnt,
2297                                   char **rdata,char **rparam,
2298                                   int *rdata_len,int *rparam_len)
2299 {
2300   char *str1 = param+2;
2301   char *str2 = skip_string(str1,1);
2302   char *p = skip_string(str2,1);
2303   int uLevel = SVAL(p,0);
2304   char *p2;
2305   int struct_len;
2306
2307   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2308
2309   /* check it's a supported varient */
2310   if (!prefix_ok(str1,"WrLh")) return False;
2311   switch( uLevel ) {
2312   case 0:
2313     if (strcmp(str2,"B16") != 0) return False;
2314     struct_len = 16;
2315     break;
2316   case 1:
2317     if (strcmp(str2,"B16BBDz") != 0) return False;
2318     struct_len = 26;
2319     break;
2320   case 2:
2321     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2322         != 0) return False;
2323     struct_len = 134;
2324     break;
2325   case 3:
2326     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2327         != 0) return False;
2328     struct_len = 144;
2329     break;
2330   case 20:
2331     if (strcmp(str2,"DN") != 0) return False;
2332     struct_len = 6;
2333     break;
2334   case 50:
2335     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2336     struct_len = 42;
2337     break;
2338   default: return False;
2339   }
2340
2341   *rdata_len = mdrcnt;
2342   *rdata = REALLOC(*rdata,*rdata_len);
2343
2344   p = *rdata;
2345   p2 = p + struct_len;
2346   if (uLevel != 20) {
2347     srvstr_push(NULL, p,local_machine,16, 
2348                 STR_ASCII|STR_UPPER|STR_TERMINATE);
2349   }
2350   p += 16;
2351   if (uLevel > 0)
2352     {
2353       struct srv_info_struct *servers=NULL;
2354       int i,count;
2355       pstring comment;
2356       uint32 servertype= lp_default_server_announce();
2357
2358       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2359
2360       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2361         for (i=0;i<count;i++)
2362           if (strequal(servers[i].name,local_machine))
2363       {
2364             servertype = servers[i].type;
2365             pstrcpy(comment,servers[i].comment);            
2366           }
2367       }
2368       SAFE_FREE(servers);
2369
2370       SCVAL(p,0,lp_major_announce_version());
2371       SCVAL(p,1,lp_minor_announce_version());
2372       SIVAL(p,2,servertype);
2373
2374       if (mdrcnt == struct_len) {
2375         SIVAL(p,6,0);
2376       } else {
2377         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2378         standard_sub_conn(conn,comment);
2379         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2380         p2 = skip_string(p2,1);
2381       }
2382     }
2383   if (uLevel > 1)
2384     {
2385       return False;             /* not yet implemented */
2386     }
2387
2388   *rdata_len = PTR_DIFF(p2,*rdata);
2389
2390   *rparam_len = 6;
2391   *rparam = REALLOC(*rparam,*rparam_len);
2392   SSVAL(*rparam,0,NERR_Success);
2393   SSVAL(*rparam,2,0);           /* converter word */
2394   SSVAL(*rparam,4,*rdata_len);
2395
2396   return(True);
2397 }
2398
2399
2400 /****************************************************************************
2401   get info about the server
2402   ****************************************************************************/
2403 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2404                                 int mdrcnt,int mprcnt,
2405                                 char **rdata,char **rparam,
2406                                 int *rdata_len,int *rparam_len)
2407 {
2408   char *str1 = param+2;
2409   char *str2 = skip_string(str1,1);
2410   char *p = skip_string(str2,1);
2411   char *p2;
2412   extern userdom_struct current_user_info;
2413   int level = SVAL(p,0);
2414
2415   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2416
2417   *rparam_len = 6;
2418   *rparam = REALLOC(*rparam,*rparam_len);
2419
2420   /* check it's a supported varient */
2421   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2422     return(False);
2423
2424   *rdata_len = mdrcnt + 1024;
2425   *rdata = REALLOC(*rdata,*rdata_len);
2426
2427   SSVAL(*rparam,0,NERR_Success);
2428   SSVAL(*rparam,2,0);           /* converter word */
2429
2430   p = *rdata;
2431   p2 = p + 22;
2432
2433
2434   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2435   pstrcpy(p2,local_machine);
2436   strupper(p2);
2437   p2 = skip_string(p2,1);
2438   p += 4;
2439
2440   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2441   pstrcpy(p2,current_user_info.smb_name);
2442   p2 = skip_string(p2,1);
2443   p += 4;
2444
2445   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2446   pstrcpy(p2,global_myworkgroup);
2447   strupper(p2);
2448   p2 = skip_string(p2,1);
2449   p += 4;
2450
2451   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2452   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2453   p += 2;
2454
2455   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2456   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2457   p2 = skip_string(p2,1);
2458   p += 4;
2459
2460   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2461   pstrcpy(p2,"");
2462   p2 = skip_string(p2,1);
2463   p += 4;
2464
2465   *rdata_len = PTR_DIFF(p2,*rdata);
2466
2467   SSVAL(*rparam,4,*rdata_len);
2468
2469   return(True);
2470 }
2471
2472 /****************************************************************************
2473   get info about a user
2474
2475     struct user_info_11 {
2476         char                usri11_name[21];  0-20 
2477         char                usri11_pad;       21 
2478         char                *usri11_comment;  22-25 
2479         char            *usri11_usr_comment;  26-29
2480         unsigned short      usri11_priv;      30-31
2481         unsigned long       usri11_auth_flags; 32-35
2482         long                usri11_password_age; 36-39
2483         char                *usri11_homedir; 40-43
2484         char            *usri11_parms; 44-47
2485         long                usri11_last_logon; 48-51
2486         long                usri11_last_logoff; 52-55
2487         unsigned short      usri11_bad_pw_count; 56-57
2488         unsigned short      usri11_num_logons; 58-59
2489         char                *usri11_logon_server; 60-63
2490         unsigned short      usri11_country_code; 64-65
2491         char            *usri11_workstations; 66-69
2492         unsigned long       usri11_max_storage; 70-73
2493         unsigned short      usri11_units_per_week; 74-75
2494         unsigned char       *usri11_logon_hours; 76-79
2495         unsigned short      usri11_code_page; 80-81
2496     };
2497
2498 where:
2499
2500   usri11_name specifies the user name for which information is retireved
2501
2502   usri11_pad aligns the next data structure element to a word boundary
2503
2504   usri11_comment is a null terminated ASCII comment
2505
2506   usri11_user_comment is a null terminated ASCII comment about the user
2507
2508   usri11_priv specifies the level of the privilege assigned to the user.
2509        The possible values are:
2510
2511 Name             Value  Description
2512 USER_PRIV_GUEST  0      Guest privilege
2513 USER_PRIV_USER   1      User privilege
2514 USER_PRV_ADMIN   2      Administrator privilege
2515
2516   usri11_auth_flags specifies the account operator privileges. The
2517        possible values are:
2518
2519 Name            Value   Description
2520 AF_OP_PRINT     0       Print operator
2521
2522
2523 Leach, Naik                                        [Page 28]
2524 \f
2525
2526
2527 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2528
2529
2530 AF_OP_COMM      1       Communications operator
2531 AF_OP_SERVER    2       Server operator
2532 AF_OP_ACCOUNTS  3       Accounts operator
2533
2534
2535   usri11_password_age specifies how many seconds have elapsed since the
2536        password was last changed.
2537
2538   usri11_home_dir points to a null terminated ASCII string that contains
2539        the path name of the user's home directory.
2540
2541   usri11_parms points to a null terminated ASCII string that is set
2542        aside for use by applications.
2543
2544   usri11_last_logon specifies the time when the user last logged on.
2545        This value is stored as the number of seconds elapsed since
2546        00:00:00, January 1, 1970.
2547
2548   usri11_last_logoff specifies the time when the user last logged off.
2549        This value is stored as the number of seconds elapsed since
2550        00:00:00, January 1, 1970. A value of 0 means the last logoff
2551        time is unknown.
2552
2553   usri11_bad_pw_count specifies the number of incorrect passwords
2554        entered since the last successful logon.
2555
2556   usri11_log1_num_logons specifies the number of times this user has
2557        logged on. A value of -1 means the number of logons is unknown.
2558
2559   usri11_logon_server points to a null terminated ASCII string that
2560        contains the name of the server to which logon requests are sent.
2561        A null string indicates logon requests should be sent to the
2562        domain controller.
2563
2564   usri11_country_code specifies the country code for the user's language
2565        of choice.
2566
2567   usri11_workstations points to a null terminated ASCII string that
2568        contains the names of workstations the user may log on from.
2569        There may be up to 8 workstations, with the names separated by
2570        commas. A null strings indicates there are no restrictions.
2571
2572   usri11_max_storage specifies the maximum amount of disk space the user
2573        can occupy. A value of 0xffffffff indicates there are no
2574        restrictions.
2575
2576   usri11_units_per_week specifies the equal number of time units into
2577        which a week is divided. This value must be equal to 168.
2578
2579   usri11_logon_hours points to a 21 byte (168 bits) string that
2580        specifies the time during which the user can log on. Each bit
2581        represents one unique hour in a week. The first bit (bit 0, word
2582        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2583
2584
2585
2586 Leach, Naik                                        [Page 29]
2587 \f
2588
2589
2590 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2591
2592
2593        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2594        are no restrictions.
2595
2596   usri11_code_page specifies the code page for the user's language of
2597        choice
2598
2599 All of the pointers in this data structure need to be treated
2600 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2601 to be ignored. The converter word returned in the parameters section
2602 needs to be subtracted from the lower 16 bits to calculate an offset
2603 into the return buffer where this ASCII string resides.
2604
2605 There is no auxiliary data in the response.
2606
2607   ****************************************************************************/
2608
2609 #define usri11_name           0 
2610 #define usri11_pad            21
2611 #define usri11_comment        22
2612 #define usri11_usr_comment    26
2613 #define usri11_full_name      30
2614 #define usri11_priv           34
2615 #define usri11_auth_flags     36
2616 #define usri11_password_age   40
2617 #define usri11_homedir        44
2618 #define usri11_parms          48
2619 #define usri11_last_logon     52
2620 #define usri11_last_logoff    56
2621 #define usri11_bad_pw_count   60
2622 #define usri11_num_logons     62
2623 #define usri11_logon_server   64
2624 #define usri11_country_code   68
2625 #define usri11_workstations   70
2626 #define usri11_max_storage    74
2627 #define usri11_units_per_week 78
2628 #define usri11_logon_hours    80
2629 #define usri11_code_page      84
2630 #define usri11_end            86
2631
2632 #define USER_PRIV_GUEST 0
2633 #define USER_PRIV_USER 1
2634 #define USER_PRIV_ADMIN 2
2635
2636 #define AF_OP_PRINT     0 
2637 #define AF_OP_COMM      1
2638 #define AF_OP_SERVER    2
2639 #define AF_OP_ACCOUNTS  3
2640
2641
2642 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2643                                 int mdrcnt,int mprcnt,
2644                                 char **rdata,char **rparam,
2645                                 int *rdata_len,int *rparam_len)
2646 {
2647         char *str1 = param+2;
2648         char *str2 = skip_string(str1,1);
2649         char *UserName = skip_string(str2,1);
2650         char *p = skip_string(UserName,1);
2651         int uLevel = SVAL(p,0);
2652         char *p2;
2653
2654     /* get NIS home of a previously validated user - simeon */
2655     /* With share level security vuid will always be zero.
2656        Don't depend on vuser being non-null !!. JRA */
2657     user_struct *vuser = get_valid_user_struct(vuid);
2658     if(vuser != NULL)
2659       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2660                vuser->user.unix_name));
2661
2662     *rparam_len = 6;
2663     *rparam = REALLOC(*rparam,*rparam_len);
2664
2665     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2666   
2667         /* check it's a supported variant */
2668         if (strcmp(str1,"zWrLh") != 0) return False;
2669         switch( uLevel )
2670         {
2671                 case 0: p2 = "B21"; break;
2672                 case 1: p2 = "B21BB16DWzzWz"; break;
2673                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2674                 case 10: p2 = "B21Bzzz"; break;
2675                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2676                 default: return False;
2677         }
2678
2679         if (strcmp(p2,str2) != 0) return False;
2680
2681         *rdata_len = mdrcnt + 1024;
2682         *rdata = REALLOC(*rdata,*rdata_len);
2683
2684         SSVAL(*rparam,0,NERR_Success);
2685         SSVAL(*rparam,2,0);             /* converter word */
2686
2687         p = *rdata;
2688         p2 = p + usri11_end;
2689
2690         memset(p,0,21); 
2691         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2692
2693         if (uLevel > 0)
2694         {
2695                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2696                 *p2 = 0;
2697         }
2698         if (uLevel >= 10)
2699         {
2700                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2701                 pstrcpy(p2,"Comment");
2702                 p2 = skip_string(p2,1);
2703
2704                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2705                 pstrcpy(p2,"UserComment");
2706                 p2 = skip_string(p2,1);
2707
2708                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2709                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2710                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2711                 p2 = skip_string(p2,1);
2712         }
2713
2714         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2715         {         
2716                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2717                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2718                 SIVALS(p,usri11_password_age,-1);               /* password age */
2719                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2720                 pstrcpy(p2, lp_logon_home());
2721                 standard_sub_conn(conn, p2);
2722                 p2 = skip_string(p2,1);
2723                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2724                 pstrcpy(p2,"");
2725                 p2 = skip_string(p2,1);
2726                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2727                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2728                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2729                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2730                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2731                 pstrcpy(p2,"\\\\*");
2732                 p2 = skip_string(p2,1);
2733                 SSVAL(p,usri11_country_code,0);         /* country code */
2734
2735                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2736                 pstrcpy(p2,"");
2737                 p2 = skip_string(p2,1);
2738
2739                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2740                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2741                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2742
2743                 /* a simple way to get logon hours at all times. */
2744                 memset(p2,0xff,21);
2745                 SCVAL(p2,21,0);           /* fix zero termination */
2746                 p2 = skip_string(p2,1);
2747
2748                 SSVAL(p,usri11_code_page,0);            /* code page */
2749         }
2750         if (uLevel == 1 || uLevel == 2)
2751         {
2752                 memset(p+22,' ',16);    /* password */
2753                 SIVALS(p,38,-1);                /* password age */
2754                 SSVAL(p,42,
2755                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2756                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2757                 pstrcpy(p2,lp_logon_home());
2758                 standard_sub_conn(conn, p2);
2759                 p2 = skip_string(p2,1);
2760                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2761                 *p2++ = 0;
2762                 SSVAL(p,52,0);          /* flags */
2763                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2764                 pstrcpy(p2,lp_logon_script());
2765                 standard_sub_conn( conn, p2 );             
2766                 p2 = skip_string(p2,1);
2767                 if (uLevel == 2)
2768                 {
2769                         SIVAL(p,60,0);          /* auth_flags */
2770                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2771                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2772                         p2 = skip_string(p2,1);
2773                         SIVAL(p,68,0);          /* urs_comment */
2774                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2775                         pstrcpy(p2,"");
2776                         p2 = skip_string(p2,1);
2777                         SIVAL(p,76,0);          /* workstations */
2778                         SIVAL(p,80,0);          /* last_logon */
2779                         SIVAL(p,84,0);          /* last_logoff */
2780                         SIVALS(p,88,-1);                /* acct_expires */
2781                         SIVALS(p,92,-1);                /* max_storage */
2782                         SSVAL(p,96,168);        /* units_per_week */
2783                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2784                         memset(p2,-1,21);
2785                         p2 += 21;
2786                         SSVALS(p,102,-1);       /* bad_pw_count */
2787                         SSVALS(p,104,-1);       /* num_logons */
2788                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2789                         pstrcpy(p2,"\\\\%L");
2790                         standard_sub_conn(conn, p2);
2791                         p2 = skip_string(p2,1);
2792                         SSVAL(p,110,49);        /* country_code */
2793                         SSVAL(p,112,860);       /* code page */
2794                 }
2795         }
2796
2797         *rdata_len = PTR_DIFF(p2,*rdata);
2798
2799         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2800
2801         return(True);
2802 }
2803
2804 /*******************************************************************
2805   get groups that a user is a member of
2806   ******************************************************************/
2807 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2808                                  int mdrcnt,int mprcnt,
2809                                  char **rdata,char **rparam,
2810                                  int *rdata_len,int *rparam_len)
2811 {
2812   char *str1 = param+2;
2813   char *str2 = skip_string(str1,1);
2814   char *UserName = skip_string(str2,1);
2815   char *p = skip_string(UserName,1);
2816   int uLevel = SVAL(p,0);
2817   char *p2;
2818   int count=0;
2819
2820   *rparam_len = 8;
2821   *rparam = REALLOC(*rparam,*rparam_len);
2822
2823   /* check it's a supported varient */
2824   if (strcmp(str1,"zWrLeh") != 0) return False;
2825   switch( uLevel ) {
2826   case 0: p2 = "B21"; break;
2827   default: return False;
2828   }
2829   if (strcmp(p2,str2) != 0) return False;
2830
2831   *rdata_len = mdrcnt + 1024;
2832   *rdata = REALLOC(*rdata,*rdata_len);
2833
2834   SSVAL(*rparam,0,NERR_Success);
2835   SSVAL(*rparam,2,0);           /* converter word */
2836
2837   p = *rdata;
2838
2839   /* XXXX we need a real SAM database some day */
2840   pstrcpy(p,"Users"); p += 21; count++;
2841   pstrcpy(p,"Domain Users"); p += 21; count++;
2842   pstrcpy(p,"Guests"); p += 21; count++;
2843   pstrcpy(p,"Domain Guests"); p += 21; count++;
2844
2845   *rdata_len = PTR_DIFF(p,*rdata);
2846
2847   SSVAL(*rparam,4,count);       /* is this right?? */
2848   SSVAL(*rparam,6,count);       /* is this right?? */
2849
2850   return(True);
2851 }
2852
2853
2854 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2855                                 int mdrcnt,int mprcnt,
2856                                 char **rdata,char **rparam,
2857                                 int *rdata_len,int *rparam_len)
2858 {
2859   char *str1 = param+2;
2860   char *str2 = skip_string(str1,1);
2861   char *p = skip_string(str2,1);
2862   int uLevel;
2863   struct pack_desc desc;
2864   char* name;
2865
2866   uLevel = SVAL(p,0);
2867   name = p + 2;
2868
2869   memset((char *)&desc,'\0',sizeof(desc));
2870
2871   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2872
2873   /* check it's a supported varient */
2874   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2875   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2876   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2877   desc.base = *rdata;
2878   desc.buflen = mdrcnt;
2879   desc.subformat = NULL;
2880   desc.format = str2;
2881   
2882   if (init_package(&desc,1,0))
2883   {
2884     PACKI(&desc,"W",0);         /* code */
2885     PACKS(&desc,"B21",name);    /* eff. name */
2886     PACKS(&desc,"B","");                /* pad */
2887     PACKI(&desc,"W",
2888           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2889     PACKI(&desc,"D",0);         /* auth flags XXX */
2890     PACKI(&desc,"W",0);         /* num logons */
2891     PACKI(&desc,"W",0);         /* bad pw count */
2892     PACKI(&desc,"D",0);         /* last logon */
2893     PACKI(&desc,"D",-1);                /* last logoff */
2894     PACKI(&desc,"D",-1);                /* logoff time */
2895     PACKI(&desc,"D",-1);                /* kickoff time */
2896     PACKI(&desc,"D",0);         /* password age */
2897     PACKI(&desc,"D",0);         /* password can change */
2898     PACKI(&desc,"D",-1);                /* password must change */
2899     {
2900       fstring mypath;
2901       fstrcpy(mypath,"\\\\");
2902       fstrcat(mypath,local_machine);
2903       strupper(mypath);
2904       PACKS(&desc,"z",mypath); /* computer */
2905     }
2906     PACKS(&desc,"z",global_myworkgroup);/* domain */
2907
2908 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2909 /* made sure all macros are fully substituted and available */
2910     {
2911       pstring logon_script;
2912       pstrcpy(logon_script,lp_logon_script());
2913       standard_sub_conn( conn, logon_script );
2914       PACKS(&desc,"z", logon_script);           /* script path */
2915     }
2916 /* End of JHT mods */
2917
2918     PACKI(&desc,"D",0x00000000);                /* reserved */
2919   }
2920
2921   *rdata_len = desc.usedlen;
2922   *rparam_len = 6;
2923   *rparam = REALLOC(*rparam,*rparam_len);
2924   SSVALS(*rparam,0,desc.errcode);
2925   SSVAL(*rparam,2,0);
2926   SSVAL(*rparam,4,desc.neededlen);
2927
2928   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2929   return(True);
2930 }
2931
2932
2933 /****************************************************************************
2934   api_WAccessGetUserPerms
2935   ****************************************************************************/
2936 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2937                                     int mdrcnt,int mprcnt,
2938                                     char **rdata,char **rparam,
2939                                     int *rdata_len,int *rparam_len)
2940 {
2941   char *str1 = param+2;
2942   char *str2 = skip_string(str1,1);
2943   char *user = skip_string(str2,1);
2944   char *resource = skip_string(user,1);
2945
2946   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2947
2948   /* check it's a supported varient */
2949   if (strcmp(str1,"zzh") != 0) return False;
2950   if (strcmp(str2,"") != 0) return False;
2951
2952   *rparam_len = 6;
2953   *rparam = REALLOC(*rparam,*rparam_len);
2954   SSVALS(*rparam,0,0);          /* errorcode */
2955   SSVAL(*rparam,2,0);           /* converter word */
2956   SSVAL(*rparam,4,0x7f);        /* permission flags */
2957
2958   return(True);
2959 }
2960
2961 /****************************************************************************
2962   api_WPrintJobEnumerate
2963   ****************************************************************************/
2964 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2965                                  int mdrcnt,int mprcnt,
2966                                  char **rdata,char **rparam,
2967                                  int *rdata_len,int *rparam_len)
2968 {
2969   char *str1 = param+2;
2970   char *str2 = skip_string(str1,1);
2971   char *p = skip_string(str2,1);
2972   int uLevel;
2973   int count;
2974   int i;
2975   int snum;
2976   int job;
2977   struct pack_desc desc;
2978   print_queue_struct *queue=NULL;
2979   print_status_struct status;
2980   char *tmpdata=NULL;
2981
2982   uLevel = SVAL(p,2);
2983
2984   memset((char *)&desc,'\0',sizeof(desc));
2985   memset((char *)&status,'\0',sizeof(status));
2986
2987   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2988
2989   /* check it's a supported varient */
2990   if (strcmp(str1,"WWrLh") != 0) return False;
2991   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2992
2993   job = SVAL(p,0);
2994   snum = print_job_snum(job);
2995
2996   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2997
2998   count = print_queue_status(snum,&queue,&status);
2999   for (i = 0; i < count; i++) {
3000     if (queue[i].job == job) break;
3001   }
3002
3003   if (mdrcnt > 0) {
3004     *rdata = REALLOC(*rdata,mdrcnt);
3005     desc.base = *rdata;
3006     desc.buflen = mdrcnt;
3007   } else {
3008     /*
3009      * Don't return data but need to get correct length
3010      *  init_package will return wrong size if buflen=0
3011      */
3012     desc.buflen = getlen(desc.format);
3013     desc.base = tmpdata = (char *)malloc ( desc.buflen );
3014   }
3015
3016   if (init_package(&desc,1,0)) {
3017     if (i < count) {
3018       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3019       *rdata_len = desc.usedlen;
3020     }
3021     else {
3022       desc.errcode = NERR_JobNotFound;
3023       *rdata_len = 0;
3024     }
3025   }
3026
3027   *rparam_len = 6;
3028   *rparam = REALLOC(*rparam,*rparam_len);
3029   SSVALS(*rparam,0,desc.errcode);
3030   SSVAL(*rparam,2,0);
3031   SSVAL(*rparam,4,desc.neededlen);
3032
3033   SAFE_FREE(queue);
3034   SAFE_FREE(tmpdata);
3035
3036   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3037   return(True);
3038 }
3039
3040 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
3041                                    int mdrcnt,int mprcnt,
3042                                    char **rdata,char **rparam,
3043                                    int *rdata_len,int *rparam_len)
3044 {
3045   char *str1 = param+2;
3046   char *str2 = skip_string(str1,1);
3047   char *p = skip_string(str2,1);
3048   char* name = p;
3049   int uLevel;
3050   int count;
3051   int i, succnt=0;
3052   int snum;
3053   struct pack_desc desc;
3054   print_queue_struct *queue=NULL;
3055   print_status_struct status;
3056
3057   memset((char *)&desc,'\0',sizeof(desc));
3058   memset((char *)&status,'\0',sizeof(status));
3059
3060   p = skip_string(p,1);
3061   uLevel = SVAL(p,0);
3062
3063   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3064
3065   /* check it's a supported varient */
3066   if (strcmp(str1,"zWrLeh") != 0) return False;
3067   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
3068   if (!check_printjob_info(&desc,uLevel,str2)) return False;
3069
3070   snum = lp_servicenumber(name);
3071   if (snum < 0 && pcap_printername_ok(name,NULL)) {
3072     int pnum = lp_servicenumber(PRINTERS_NAME);
3073     if (pnum >= 0) {
3074       lp_add_printer(name,pnum);
3075       snum = lp_servicenumber(name);
3076     }
3077   }
3078
3079   if (snum < 0 || !VALID_SNUM(snum)) return(False);
3080
3081   count = print_queue_status(snum,&queue,&status);
3082   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3083   desc.base = *rdata;
3084   desc.buflen = mdrcnt;
3085
3086   if (init_package(&desc,count,0)) {
3087     succnt = 0;
3088     for (i = 0; i < count; i++) {
3089       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3090       if (desc.errcode == NERR_Success) succnt = i+1;
3091     }
3092   }
3093
3094   *rdata_len = desc.usedlen;
3095
3096   *rparam_len = 8;
3097   *rparam = REALLOC(*rparam,*rparam_len);
3098   SSVALS(*rparam,0,desc.errcode);
3099   SSVAL(*rparam,2,0);
3100   SSVAL(*rparam,4,succnt);
3101   SSVAL(*rparam,6,count);
3102
3103   SAFE_FREE(queue);
3104
3105   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3106   return(True);
3107 }
3108
3109 static int check_printdest_info(struct pack_desc* desc,
3110                                 int uLevel, char* id)
3111 {
3112   desc->subformat = NULL;
3113   switch( uLevel ) {
3114   case 0: desc->format = "B9"; break;
3115   case 1: desc->format = "B9B21WWzW"; break;
3116   case 2: desc->format = "z"; break;
3117   case 3: desc->format = "zzzWWzzzWW"; break;
3118   default: return False;
3119   }
3120   if (strcmp(desc->format,id) != 0) return False;
3121   return True;
3122 }
3123
3124 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3125                                 struct pack_desc* desc)
3126 {
3127   char buf[100];
3128   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3129   buf[sizeof(buf)-1] = 0;
3130   strupper(buf);
3131   if (uLevel <= 1) {
3132     PACKS(desc,"B9",buf);       /* szName */
3133     if (uLevel == 1) {
3134       PACKS(desc,"B21","");     /* szUserName */
3135       PACKI(desc,"W",0);                /* uJobId */
3136       PACKI(desc,"W",0);                /* fsStatus */
3137       PACKS(desc,"z","");       /* pszStatus */
3138       PACKI(desc,"W",0);                /* time */
3139     }
3140   }
3141   if (uLevel == 2 || uLevel == 3) {
3142     PACKS(desc,"z",buf);                /* pszPrinterName */
3143     if (uLevel == 3) {
3144       PACKS(desc,"z","");       /* pszUserName */
3145       PACKS(desc,"z","");       /* pszLogAddr */
3146       PACKI(desc,"W",0);                /* uJobId */
3147       PACKI(desc,"W",0);                /* fsStatus */
3148       PACKS(desc,"z","");       /* pszStatus */
3149       PACKS(desc,"z","");       /* pszComment */
3150       PACKS(desc,"z","NULL"); /* pszDrivers */
3151       PACKI(desc,"W",0);                /* time */
3152       PACKI(desc,"W",0);                /* pad1 */
3153     }
3154   }
3155 }
3156
3157 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3158                                   int mdrcnt,int mprcnt,
3159                                   char **rdata,char **rparam,
3160                                   int *rdata_len,int *rparam_len)
3161 {
3162   char *str1 = param+2;
3163   char *str2 = skip_string(str1,1);
3164   char *p = skip_string(str2,1);
3165   char* PrinterName = p;
3166   int uLevel;
3167   struct pack_desc desc;
3168   int snum;
3169   char *tmpdata=NULL;
3170
3171   memset((char *)&desc,'\0',sizeof(desc));
3172
3173   p = skip_string(p,1);
3174   uLevel = SVAL(p,0);
3175
3176   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3177
3178   /* check it's a supported varient */
3179   if (strcmp(str1,"zWrLh") != 0) return False;
3180   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3181
3182   snum = lp_servicenumber(PrinterName);
3183   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
3184     int pnum = lp_servicenumber(PRINTERS_NAME);
3185     if (pnum >= 0) {
3186       lp_add_printer(PrinterName,pnum);
3187       snum = lp_servicenumber(PrinterName);
3188     }
3189   }
3190
3191   if (snum < 0) {
3192     *rdata_len = 0;
3193     desc.errcode = NERR_DestNotFound;
3194     desc.neededlen = 0;
3195   }
3196   else {
3197     if (mdrcnt > 0) {
3198       *rdata = REALLOC(*rdata,mdrcnt);
3199       desc.base = *rdata;
3200       desc.buflen = mdrcnt;
3201     } else {
3202       /*
3203        * Don't return data but need to get correct length
3204        *  init_package will return wrong size if buflen=0
3205        */
3206       desc.buflen = getlen(desc.format);
3207       desc.base = tmpdata = (char *)malloc ( desc.buflen );
3208     }
3209     if (init_package(&desc,1,0)) {
3210       fill_printdest_info(conn,snum,uLevel,&desc);
3211     }
3212     *rdata_len = desc.usedlen;
3213   }
3214
3215   *rparam_len = 6;
3216   *rparam = REALLOC(*rparam,*rparam_len);
3217   SSVALS(*rparam,0,desc.errcode);
3218   SSVAL(*rparam,2,0);
3219   SSVAL(*rparam,4,desc.neededlen);
3220
3221   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3222   SAFE_FREE(tmpdata);
3223   return(True);
3224 }
3225
3226 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3227                                int mdrcnt,int mprcnt,
3228                                char **rdata,char **rparam,
3229                                int *rdata_len,int *rparam_len)
3230 {
3231   char *str1 = param+2;
3232   char *str2 = skip_string(str1,1);
3233   char *p = skip_string(str2,1);
3234   int uLevel;
3235   int queuecnt;
3236   int i, n, succnt=0;
3237   struct pack_desc desc;
3238   int services = lp_numservices();
3239
3240   memset((char *)&desc,'\0',sizeof(desc));
3241
3242   uLevel = SVAL(p,0);
3243
3244   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3245
3246   /* check it's a supported varient */
3247   if (strcmp(str1,"WrLeh") != 0) return False;
3248   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3249
3250   queuecnt = 0;
3251   for (i = 0; i < services; i++)
3252     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3253       queuecnt++;
3254
3255   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3256   desc.base = *rdata;
3257   desc.buflen = mdrcnt;
3258   if (init_package(&desc,queuecnt,0)) {    
3259     succnt = 0;
3260     n = 0;
3261     for (i = 0; i < services; i++) {
3262       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3263         fill_printdest_info(conn,i,uLevel,&desc);
3264         n++;
3265         if (desc.errcode == NERR_Success) succnt = n;
3266       }
3267     }
3268   }
3269
3270   *rdata_len = desc.usedlen;
3271
3272   *rparam_len = 8;
3273   *rparam = REALLOC(*rparam,*rparam_len);
3274   SSVALS(*rparam,0,desc.errcode);
3275   SSVAL(*rparam,2,0);
3276   SSVAL(*rparam,4,succnt);
3277   SSVAL(*rparam,6,queuecnt);
3278
3279   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3280   return(True);
3281 }
3282
3283 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3284                                  int mdrcnt,int mprcnt,
3285                                  char **rdata,char **rparam,
3286                                  int *rdata_len,int *rparam_len)
3287 {
3288   char *str1 = param+2;
3289   char *str2 = skip_string(str1,1);
3290   char *p = skip_string(str2,1);
3291   int uLevel;
3292   int succnt;
3293   struct pack_desc desc;
3294
3295   memset((char *)&desc,'\0',sizeof(desc));
3296
3297   uLevel = SVAL(p,0);
3298
3299   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3300
3301   /* check it's a supported varient */
3302   if (strcmp(str1,"WrLeh") != 0) return False;
3303   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3304
3305   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3306   desc.base = *rdata;
3307   desc.buflen = mdrcnt;
3308   if (init_package(&desc,1,0)) {
3309     PACKS(&desc,"B41","NULL");
3310   }
3311
3312   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3313
3314   *rdata_len = desc.usedlen;
3315
3316   *rparam_len = 8;
3317   *rparam = REALLOC(*rparam,*rparam_len);
3318   SSVALS(*rparam,0,desc.errcode);
3319   SSVAL(*rparam,2,0);
3320   SSVAL(*rparam,4,succnt);
3321   SSVAL(*rparam,6,1);
3322
3323   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3324   return(True);
3325 }
3326
3327 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3328                                 int mdrcnt,int mprcnt,
3329                                 char **rdata,char **rparam,
3330                                 int *rdata_len,int *rparam_len)
3331 {
3332   char *str1 = param+2;
3333   char *str2 = skip_string(str1,1);
3334   char *p = skip_string(str2,1);
3335   int uLevel;
3336   int succnt;
3337   struct pack_desc desc;
3338
3339   memset((char *)&desc,'\0',sizeof(desc));
3340
3341   uLevel = SVAL(p,0);
3342
3343   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3344
3345   /* check it's a supported varient */
3346   if (strcmp(str1,"WrLeh") != 0) return False;
3347   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3348
3349   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3350   desc.base = *rdata;
3351   desc.buflen = mdrcnt;
3352   desc.format = str2;
3353   if (init_package(&desc,1,0)) {
3354     PACKS(&desc,"B13","lpd");
3355   }
3356
3357   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3358
3359   *rdata_len = desc.usedlen;
3360
3361   *rparam_len = 8;
3362   *rparam = REALLOC(*rparam,*rparam_len);
3363   SSVALS(*rparam,0,desc.errcode);
3364   SSVAL(*rparam,2,0);
3365   SSVAL(*rparam,4,succnt);
3366   SSVAL(*rparam,6,1);
3367
3368   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3369   return(True);
3370 }
3371
3372 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3373                                int mdrcnt,int mprcnt,
3374                                char **rdata,char **rparam,
3375                                int *rdata_len,int *rparam_len)
3376 {
3377   char *str1 = param+2;
3378   char *str2 = skip_string(str1,1);
3379   char *p = skip_string(str2,1);
3380   int uLevel;
3381   int succnt;
3382   struct pack_desc desc;
3383
3384   memset((char *)&desc,'\0',sizeof(desc));
3385
3386   uLevel = SVAL(p,0);
3387
3388   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3389
3390   /* check it's a supported varient */
3391   if (strcmp(str1,"WrLeh") != 0) return False;
3392   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3393
3394   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3395   memset((char *)&desc,'\0',sizeof(desc));
3396   desc.base = *rdata;
3397   desc.buflen = mdrcnt;
3398   desc.format = str2;
3399   if (init_package(&desc,1,0)) {
3400     PACKS(&desc,"B13","lp0");
3401   }
3402
3403   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3404
3405   *rdata_len = desc.usedlen;
3406
3407   *rparam_len = 8;
3408   *rparam = REALLOC(*rparam,*rparam_len);
3409   SSVALS(*rparam,0,desc.errcode);
3410   SSVAL(*rparam,2,0);
3411   SSVAL(*rparam,4,succnt);
3412   SSVAL(*rparam,6,1);
3413
3414   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3415   return(True);
3416 }
3417
3418 /****************************************************************************
3419  The buffer was too small
3420  ****************************************************************************/
3421
3422 static BOOL api_TooSmall(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   *rparam_len = MIN(*rparam_len,mprcnt);
3428   *rparam = REALLOC(*rparam,*rparam_len);
3429
3430   *rdata_len = 0;
3431
3432   SSVAL(*rparam,0,NERR_BufTooSmall);
3433
3434   DEBUG(3,("Supplied buffer too small in API command\n"));
3435
3436   return(True);
3437 }
3438
3439
3440 /****************************************************************************
3441  The request is not supported
3442  ****************************************************************************/
3443
3444 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3445                             int mdrcnt,int mprcnt,
3446                             char **rdata,char **rparam,
3447                             int *rdata_len,int *rparam_len)
3448 {
3449   *rparam_len = 4;
3450   *rparam = REALLOC(*rparam,*rparam_len);
3451
3452   *rdata_len = 0;
3453
3454   SSVAL(*rparam,0,NERR_notsupported);
3455   SSVAL(*rparam,2,0);           /* converter word */
3456
3457   DEBUG(3,("Unsupported API command\n"));
3458
3459   return(True);
3460 }
3461
3462
3463
3464
3465 struct
3466 {
3467   char *name;
3468   int id;
3469   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3470              int,int,char **,char **,int *,int *);
3471   int flags;
3472 } api_commands[] = {
3473   {"RNetShareEnum",     RAP_WshareEnum,         api_RNetShareEnum,0},
3474   {"RNetShareGetInfo",  RAP_WshareGetInfo,      api_RNetShareGetInfo,0},
3475   {"RNetShareAdd",      RAP_WshareAdd,          api_RNetShareAdd,0},
3476   {"RNetServerGetInfo", RAP_WserverGetInfo,     api_RNetServerGetInfo,0},
3477   {"RNetGroupEnum",     RAP_WGroupEnum,         api_RNetGroupEnum,0},
3478   {"RNetGroupGetUsers", RAP_WGroupGetUsers,     api_RNetGroupGetUsers,0},
3479   {"RNetUserEnum",      RAP_WUserEnum,          api_RNetUserEnum,0},
3480   {"RNetUserGetInfo",   RAP_WUserGetInfo,       api_RNetUserGetInfo,0},
3481   {"NetUserGetGroups",  RAP_WUserGetGroups,     api_NetUserGetGroups,0},
3482   {"NetWkstaGetInfo",   RAP_WWkstaGetInfo,      api_NetWkstaGetInfo,0},
3483   {"DosPrintQEnum",     RAP_WPrintQEnum,        api_DosPrintQEnum,0},
3484   {"DosPrintQGetInfo",  RAP_WPrintQGetInfo,     api_DosPrintQGetInfo,0},
3485   {"WPrintQueuePause",  RAP_WPrintQPause,       api_WPrintQueueCtrl,0},
3486   {"WPrintQueueResume", RAP_WPrintQContinue,    api_WPrintQueueCtrl,0},
3487   {"WPrintJobEnumerate",RAP_WPrintJobEnum,      api_WPrintJobEnumerate,0},
3488   {"WPrintJobGetInfo",  RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo,0},
3489   {"RDosPrintJobDel",   RAP_WPrintJobDel,       api_RDosPrintJobDel,0},
3490   {"RDosPrintJobPause", RAP_WPrintJobPause,     api_RDosPrintJobDel,0},
3491   {"RDosPrintJobResume",RAP_WPrintJobContinue,  api_RDosPrintJobDel,0},
3492   {"WPrintDestEnum",    RAP_WPrintDestEnum,     api_WPrintDestEnum,0},
3493   {"WPrintDestGetInfo", RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo,0},
3494   {"NetRemoteTOD",      RAP_NetRemoteTOD,       api_NetRemoteTOD,0},
3495   {"WPrintQueuePurge",  RAP_WPrintQPurge,       api_WPrintQueueCtrl,0},
3496   {"NetServerEnum",     RAP_NetServerEnum2,     api_RNetServerEnum,0},
3497   {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0},
3498   {"SetUserPassword",   RAP_WUserPasswordSet2,  api_SetUserPassword,0},
3499   {"WWkstaUserLogon",   RAP_WWkstaUserLogon,    api_WWkstaUserLogon,0},
3500   {"PrintJobInfo",      RAP_WPrintJobSetInfo,   api_PrintJobInfo,0},
3501   {"WPrintDriverEnum",  RAP_WPrintDriverEnum,   api_WPrintDriverEnum,0},
3502   {"WPrintQProcEnum",   RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0},
3503   {"WPrintPortEnum",    RAP_WPrintPortEnum,     api_WPrintPortEnum,0},
3504   {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0},
3505   {NULL,                -1,     api_Unsupported,0}};
3506
3507
3508 /****************************************************************************
3509  Handle remote api calls
3510  ****************************************************************************/
3511
3512 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3513                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3514 {
3515   int api_command;
3516   char *rdata = NULL;
3517   char *rparam = NULL;
3518   int rdata_len = 0;
3519   int rparam_len = 0;
3520   BOOL reply=False;
3521   int i;
3522
3523   if (!params) {
3524           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3525           return 0;
3526   }
3527
3528   api_command = SVAL(params,0);
3529
3530   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3531            api_command,
3532            params+2,
3533            skip_string(params+2,1),
3534            tdscnt,tpscnt,mdrcnt,mprcnt));
3535
3536   for (i=0;api_commands[i].name;i++) {
3537     if (api_commands[i].id == api_command && api_commands[i].fn) {
3538         DEBUG(3,("Doing %s\n",api_commands[i].name));
3539         break;
3540     }
3541   }
3542
3543   rdata = (char *)malloc(1024);
3544   if (rdata)
3545     memset(rdata,'\0',1024);
3546
3547   rparam = (char *)malloc(1024);
3548   if (rparam)
3549     memset(rparam,'\0',1024);
3550
3551   if(!rdata || !rparam) {
3552     DEBUG(0,("api_reply: malloc fail !\n"));
3553     return -1;
3554   }
3555
3556   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3557                              &rdata,&rparam,&rdata_len,&rparam_len);
3558
3559
3560   if (rdata_len > mdrcnt ||
3561       rparam_len > mprcnt) {
3562       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3563                            &rdata,&rparam,&rdata_len,&rparam_len);
3564   }
3565
3566   /* if we get False back then it's actually unsupported */
3567   if (!reply)
3568     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3569                     &rdata,&rparam,&rdata_len,&rparam_len);
3570
3571   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3572
3573   SAFE_FREE(rdata);
3574   SAFE_FREE(rparam);
3575   
3576   return -1;
3577 }