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