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