Large commit which restructures the local password storage API.
[ira/wip.git] / source3 / smbd / lanman.c
1 #define OLD_NTDOMAIN 1
2 /* 
3    Unix SMB/Netbios implementation.
4    Version 1.9.
5    Inter-process communication and named pipe handling
6    Copyright (C) Andrew Tridgell 1992-1998
7
8    SMB Version handling
9    Copyright (C) John H Terpstra 1995-1998
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24    */
25 /*
26    This file handles the named pipe and mailslot calls
27    in the SMBtrans protocol
28    */
29
30 #include "includes.h"
31
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
36
37 extern int DEBUGLEVEL;
38
39 extern fstring local_machine;
40 extern pstring global_myname;
41 extern fstring global_myworkgroup;
42
43 #define NERR_Success 0
44 #define NERR_badpass 86
45 #define NERR_notsupported 50
46
47 #define NERR_BASE (2100)
48 #define NERR_BufTooSmall (NERR_BASE+23)
49 #define NERR_JobNotFound (NERR_BASE+51)
50 #define NERR_DestNotFound (NERR_BASE+52)
51
52 #define ACCESS_READ 0x01
53 #define ACCESS_WRITE 0x02
54 #define ACCESS_CREATE 0x04
55
56 #define SHPWLEN 8               /* share password length */
57
58 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
59                             int mdrcnt,int mprcnt,
60                             char **rdata,char **rparam,
61                             int *rdata_len,int *rparam_len);
62 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
63                          int mdrcnt,int mprcnt,
64                          char **rdata,char **rparam,
65                          int *rdata_len,int *rparam_len);
66
67
68 static int CopyExpanded(connection_struct *conn, 
69                         int snum, char** dst, char* src, int* n)
70 {
71         pstring buf;
72         int l;
73
74         if (!src || !dst || !n || !(*dst)) return(0);
75
76         StrnCpy(buf,src,sizeof(buf)/2);
77         pstring_sub(buf,"%S",lp_servicename(snum));
78         standard_sub_conn(conn,buf);
79         StrnCpy(*dst,buf,*n);
80         l = strlen(*dst) + 1;
81         (*dst) += l;
82         (*n) -= l;
83         return l;
84 }
85
86 static int CopyAndAdvance(char** dst, char* src, int* n)
87 {
88   int l;
89   if (!src || !dst || !n || !(*dst)) return(0);
90   StrnCpy(*dst,src,*n-1);
91   l = strlen(*dst) + 1;
92   (*dst) += l;
93   (*n) -= l;
94   return l;
95 }
96
97 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
98 {
99         pstring buf;
100         if (!s) return(0);
101         StrnCpy(buf,s,sizeof(buf)/2);
102         pstring_sub(buf,"%S",lp_servicename(snum));
103         standard_sub_conn(conn,buf);
104         return strlen(buf) + 1;
105 }
106
107 static char* Expand(connection_struct *conn, int snum, char* s)
108 {
109         static pstring buf;
110         if (!s) return(NULL);
111         StrnCpy(buf,s,sizeof(buf)/2);
112         pstring_sub(buf,"%S",lp_servicename(snum));
113         standard_sub_conn(conn,buf);
114         return &buf[0];
115 }
116
117 /*******************************************************************
118   check a API string for validity when we only need to check the prefix
119   ******************************************************************/
120 static BOOL prefix_ok(char *str,char *prefix)
121 {
122   return(strncmp(str,prefix,strlen(prefix)) == 0);
123 }
124
125 struct pack_desc {
126   char* format;     /* formatstring for structure */
127   char* subformat;  /* subformat for structure */
128   char* base;       /* baseaddress of buffer */
129   int buflen;      /* remaining size for fixed part; on init: length of base */
130   int subcount;     /* count of substructures */
131   char* structbuf;  /* pointer into buffer for remaining fixed part */
132   int stringlen;    /* remaining size for variable part */              
133   char* stringbuf;  /* pointer into buffer for remaining variable part */
134   int neededlen;    /* total needed size */
135   int usedlen;      /* total used size (usedlen <= neededlen and usedlen <= buflen) */
136   char* curpos;     /* current position; pointer into format or subformat */
137   int errcode;
138 };
139
140 static int get_counter(char** p)
141 {
142   int i, n;
143   if (!p || !(*p)) return(1);
144   if (!isdigit((int)**p)) return 1;
145   for (n = 0;;) {
146     i = **p;
147     if (isdigit(i))
148       n = 10 * n + (i - '0');
149     else
150       return n;
151     (*p)++;
152   }
153 }
154
155 static int getlen(char* p)
156 {
157   int n = 0;
158   if (!p) return(0);
159   while (*p) {
160     switch( *p++ ) {
161     case 'W':                   /* word (2 byte) */
162       n += 2;
163       break;
164     case 'K':                   /* status word? (2 byte) */
165       n += 2;
166       break;
167     case 'N':                   /* count of substructures (word) at end */
168       n += 2;
169       break;
170     case 'D':                   /* double word (4 byte) */
171     case 'z':                   /* offset to zero terminated string (4 byte) */
172     case 'l':                   /* offset to user data (4 byte) */
173       n += 4;
174       break;
175     case 'b':                   /* offset to data (with counter) (4 byte) */
176       n += 4;
177       get_counter(&p);
178       break;
179     case 'B':                   /* byte (with optional counter) */
180       n += get_counter(&p);
181       break;
182     }
183   }
184   return n;
185 }
186
187 static BOOL init_package(struct pack_desc* p, int count, int subcount)
188 {
189   int n = p->buflen;
190   int i;
191
192   if (!p->format || !p->base) return(False);
193
194   i = count * getlen(p->format);
195   if (p->subformat) i += subcount * getlen(p->subformat);
196   p->structbuf = p->base;
197   p->neededlen = 0;
198   p->usedlen = 0;
199   p->subcount = 0;
200   p->curpos = p->format;
201   if (i > n) {
202     p->neededlen = i;
203     i = n = 0;
204     p->errcode = ERRmoredata;
205   }
206   else
207     p->errcode = NERR_Success;
208   p->buflen = i;
209   n -= i;
210   p->stringbuf = p->base + i;
211   p->stringlen = n;
212   return(p->errcode == NERR_Success);
213 }
214
215 #ifdef HAVE_STDARG_H
216 static int package(struct pack_desc* p, ...)
217 {
218 #else
219 static int package(va_alist)
220 va_dcl
221 {
222   struct pack_desc* p;
223 #endif
224   va_list args;
225   int needed=0, stringneeded;
226   char* str=NULL;
227   int is_string=0, stringused;
228   int32 temp;
229
230 #ifdef HAVE_STDARG_H
231   va_start(args,p);
232 #else
233   va_start(args);
234   p = va_arg(args,struct pack_desc *);
235 #endif
236
237   if (!*p->curpos) {
238     if (!p->subcount)
239       p->curpos = p->format;
240     else {
241       p->curpos = p->subformat;
242       p->subcount--;
243     }
244   }
245 #if CHECK_TYPES
246   str = va_arg(args,char*);
247   SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
248 #endif
249   stringneeded = -1;
250
251   if (!p->curpos) {
252     va_end(args);
253     return(0);
254   }
255
256   switch( *p->curpos++ ) {
257   case 'W':                     /* word (2 byte) */
258     needed = 2;
259     temp = va_arg(args,int);
260     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
261     break;
262   case 'K':                     /* status word? (2 byte) */
263     needed = 2;
264     temp = va_arg(args,int);
265     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
266     break;
267   case 'N':                     /* count of substructures (word) at end */
268     needed = 2;
269     p->subcount = va_arg(args,int);
270     if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
271     break;
272   case 'D':                     /* double word (4 byte) */
273     needed = 4;
274     temp = va_arg(args,int);
275     if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
276     break;
277   case 'B':                     /* byte (with optional counter) */
278     needed = get_counter(&p->curpos);
279     {
280       char *s = va_arg(args,char*);
281       if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
282     }
283     break;
284   case 'z':                     /* offset to zero terminated string (4 byte) */
285     str = va_arg(args,char*);
286     stringneeded = (str ? strlen(str)+1 : 0);
287     is_string = 1;
288     break;
289   case 'l':                     /* offset to user data (4 byte) */
290     str = va_arg(args,char*);
291     stringneeded = va_arg(args,int);
292     is_string = 0;
293     break;
294   case 'b':                     /* offset to data (with counter) (4 byte) */
295     str = va_arg(args,char*);
296     stringneeded = get_counter(&p->curpos);
297     is_string = 0;
298     break;
299   }
300   va_end(args);
301   if (stringneeded >= 0) {
302     needed = 4;
303     if (p->buflen >= needed) {
304       stringused = stringneeded;
305       if (stringused > p->stringlen) {
306         stringused = (is_string ? p->stringlen : 0);
307         if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
308       }
309       if (!stringused)
310         SIVAL(p->structbuf,0,0);
311       else {
312         SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
313         memcpy(p->stringbuf,str?str:"",stringused);
314         if (is_string) p->stringbuf[stringused-1] = '\0';
315         p->stringbuf += stringused;
316         p->stringlen -= stringused;
317         p->usedlen += stringused;
318       }
319     }
320     p->neededlen += stringneeded;
321   }
322   p->neededlen += needed;
323   if (p->buflen >= needed) {
324     p->structbuf += needed;
325     p->buflen -= needed;
326     p->usedlen += needed;
327   }
328   else {
329     if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
330   }
331   return 1;
332 }
333
334 #if CHECK_TYPES
335 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
336 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
337 #else
338 #define PACK(desc,t,v) package(desc,v)
339 #define PACKl(desc,t,v,l) package(desc,v,l)
340 #endif
341
342 static void PACKI(struct pack_desc* desc,char *t,int v)
343 {
344   PACK(desc,t,v);
345 }
346
347 static void PACKS(struct pack_desc* desc,char *t,char *v)
348 {
349   PACK(desc,t,v);
350 }
351
352
353 /****************************************************************************
354   get a print queue
355   ****************************************************************************/
356 static void PackDriverData(struct pack_desc* desc)
357 {
358   char drivdata[4+4+32];
359   SIVAL(drivdata,0,sizeof drivdata); /* cb */
360   SIVAL(drivdata,4,1000);       /* lVersion */
361   memset(drivdata+8,0,32);      /* szDeviceName */
362   pstrcpy(drivdata+8,"NULL");
363   PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
364 }
365
366 static int check_printq_info(struct pack_desc* desc,
367                              int uLevel, char *id1, char *id2)
368 {
369   desc->subformat = NULL;
370   switch( uLevel ) {
371   case 0:
372     desc->format = "B13";
373     break;
374   case 1:
375     desc->format = "B13BWWWzzzzzWW";
376     break;
377   case 2:
378     desc->format = "B13BWWWzzzzzWN";
379     desc->subformat = "WB21BB16B10zWWzDDz";
380     break;
381   case 3:
382     desc->format = "zWWWWzzzzWWzzl";
383     break;
384   case 4:
385     desc->format = "zWWWWzzzzWNzzl";
386     desc->subformat = "WWzWWDDzz";
387     break;
388   case 5:
389     desc->format = "z";
390     break;
391   case 51:
392     desc->format = "K";
393     break;
394   case 52:
395     desc->format = "WzzzzzzzzN";
396     desc->subformat = "z";
397     break;
398   default: return False;
399   }
400   if (strcmp(desc->format,id1) != 0) return False;
401   if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
402   return True;
403 }
404
405
406 #define JOB_STATUS_QUEUED 0
407 #define JOB_STATUS_PAUSED 1
408 #define JOB_STATUS_SPOOLING 2
409 #define JOB_STATUS_PRINTING 3
410 #define JOB_STATUS_PRINTED 4
411
412 #define QUEUE_STATUS_PAUSED 1
413 #define QUEUE_STATUS_ERROR 2
414
415 /* turn a print job status into a on the wire status 
416 */
417 static int printj_status(int v)
418 {
419         switch (v) {
420         case LPQ_QUEUED:
421                 return JOB_STATUS_QUEUED;
422         case LPQ_PAUSED:
423                 return JOB_STATUS_PAUSED;
424         case LPQ_SPOOLING:
425                 return JOB_STATUS_SPOOLING;
426         case LPQ_PRINTING:
427                 return JOB_STATUS_PRINTING;
428         }
429         return 0;
430 }
431
432 /* turn a print queue status into a on the wire status 
433 */
434 static int printq_status(int v)
435 {
436         switch (v) {
437         case LPQ_QUEUED:
438                 return 0;
439         case LPQ_PAUSED:
440                 return QUEUE_STATUS_PAUSED;
441         }
442         return QUEUE_STATUS_ERROR;
443 }
444
445 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
446                                struct pack_desc* desc,
447                                print_queue_struct* queue, int n)
448 {
449   time_t t = queue->time;
450
451   /* the client expects localtime */
452   t -= TimeDiff(t);
453
454   PACKI(desc,"W",queue->job); /* uJobId */
455   if (uLevel == 1) {
456     PACKS(desc,"B21",queue->user); /* szUserName */
457     PACKS(desc,"B","");         /* pad */
458     PACKS(desc,"B16","");       /* szNotifyName */
459     PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
460     PACKS(desc,"z","");         /* pszParms */
461     PACKI(desc,"W",n+1);                /* uPosition */
462     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
463     PACKS(desc,"z","");         /* pszStatus */
464     PACKI(desc,"D",t); /* ulSubmitted */
465     PACKI(desc,"D",queue->size); /* ulSize */
466     PACKS(desc,"z",queue->file); /* pszComment */
467   }
468   if (uLevel == 2 || uLevel == 3) {
469     PACKI(desc,"W",queue->priority);            /* uPriority */
470     PACKS(desc,"z",queue->user); /* pszUserName */
471     PACKI(desc,"W",n+1);                /* uPosition */
472     PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
473     PACKI(desc,"D",t); /* ulSubmitted */
474     PACKI(desc,"D",queue->size); /* ulSize */
475     PACKS(desc,"z","Samba");    /* pszComment */
476     PACKS(desc,"z",queue->file); /* pszDocument */
477     if (uLevel == 3) {
478       PACKS(desc,"z","");       /* pszNotifyName */
479       PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
480       PACKS(desc,"z","");       /* pszParms */
481       PACKS(desc,"z","");       /* pszStatus */
482       PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
483       PACKS(desc,"z","lpd");    /* pszQProcName */
484       PACKS(desc,"z","");       /* pszQProcParms */
485       PACKS(desc,"z","NULL"); /* pszDriverName */
486       PackDriverData(desc);     /* pDriverData */
487       PACKS(desc,"z","");       /* pszPrinterName */
488     }
489   }
490 }
491
492 /********************************************************************
493  Respond to the DosPrintQInfo command with a level of 52
494  This is used to get printer driver information for Win9x clients
495  ********************************************************************/
496 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
497                                 struct pack_desc* desc,
498                                 int count, print_queue_struct* queue,
499                                 print_status_struct* status)
500 {
501         int i;
502         BOOL ok = False;
503         pstring tok,driver,datafile,langmon,helpfile,datatype;
504         char *p;
505         char **lines = NULL;
506         pstring gen_line;
507         NT_PRINTER_INFO_LEVEL *info = NULL;
508         BOOL in_tdb = False;
509         fstring location;
510         
511         /*
512          * Check in the tdb *first* before checking the legacy
513          * files. This allows an NT upload to take precedence over
514          * the existing fileset. JRA.
515          * 
516          * we need to lookup the driver name prior to making the call
517          * to get_a_printer_driver_9x_compatible() and not rely on the
518          * 'print driver' parameter --jerry
519          */
520
521         get_a_printer (&info, 2, lp_servicename(snum));
522         if ((info != NULL) && 
523             ((ok = get_a_printer_driver_9x_compatible(gen_line, info->info_2->drivername)) == True))
524         {
525                 in_tdb = True;
526                 p = gen_line;
527                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", 
528                           info->info_2->drivername, gen_line));
529         } 
530         else 
531         {
532                 /* didn't find driver in tdb */
533
534                 DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
535                            snum, lp_printerdriver(snum), lp_driverfile(snum)));
536
537                 lines = file_lines_load(lp_driverfile(snum),NULL);
538                 if (!lines) 
539                 {
540                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
541                                   strerror(errno)));
542                         desc->errcode=NERR_notsupported;
543                         goto done;
544                 } 
545
546                 /* lookup the long printer driver name in the file description */
547                 for (i=0;lines[i] && !ok;i++) 
548                 {
549                         p = lines[i];
550                         if (next_token(&p,tok,":",sizeof(tok)) &&
551                            (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
552                            (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
553                         {
554                                 ok = True;
555                         }
556                 }
557         }
558
559         if (ok)
560         {
561                 /* driver file name */
562                 if (!next_token(&p,driver,":",sizeof(driver)))
563                         goto err;
564
565                 /* data file name */
566                 if (!next_token(&p,datafile,":",sizeof(datafile)))
567                         goto err;
568
569                 /*
570                  * for the next tokens - which may be empty - I have
571                  * to check for empty tokens first because the
572                  * next_token function will skip all empty token
573                  * fields */
574
575                 /* help file */
576                 if (*p == ':') 
577                 {
578                         *helpfile = '\0';
579                         p++;
580                 } 
581                 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
582                         goto err;
583         
584                 /* language monitor */
585                 if (*p == ':') 
586                 {
587                         *langmon = '\0';
588                         p++;
589                 } 
590                 else if (!next_token(&p,langmon,":",sizeof(langmon)))
591                         goto err;
592         
593                 /* default data type */
594                 if (!next_token(&p,datatype,":",sizeof(datatype))) 
595                         goto err;
596         
597                 PACKI(desc,"W",0x0400);               /* don't know */
598                 if (in_tdb)
599                 {
600                         PACKS(desc,"z",info->info_2->drivername);    /* long printer name */
601                 }
602                 else
603                 {
604                         PACKS(desc,"z",lp_printerdriver(snum));    /* long printer name */
605                 }
606                 PACKS(desc,"z",driver);                    /* Driverfile Name */
607                 PACKS(desc,"z",datafile);                  /* Datafile name */
608                 PACKS(desc,"z",langmon);                         /* language monitor */
609                 if (in_tdb)
610                 {
611                         fstrcpy(location, "\\\\");
612                         fstrcat(location, global_myname);
613                         fstrcat(location, "\\print$\\WIN40\\0");
614                         PACKS(desc,"z",location);   /* share to retrieve files */
615                 }
616                 else
617                 {
618                         PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
619                 }
620                 PACKS(desc,"z",datatype);                        /* default data type */
621                 PACKS(desc,"z",helpfile);                  /* helpfile name */
622                 PACKS(desc,"z",driver);                    /* driver name */
623
624                 if (in_tdb)
625                         DEBUG(3,("lp_printerdriver:%s:\n",info->info_2->drivername));
626                 else
627                         DEBUG(3,("lp_printerdriver:%s:\n",lp_printerdriver(snum)));
628                         
629                 DEBUG(3,("Driver:%s:\n",driver));
630                 DEBUG(3,("Data File:%s:\n",datafile));
631                 DEBUG(3,("Language Monitor:%s:\n",langmon));
632                 if (in_tdb)
633                         DEBUG(3,("lp_driverlocation:%s:\n",location));
634                 else
635                         DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
636                 DEBUG(3,("Data Type:%s:\n",datatype));
637                 DEBUG(3,("Help File:%s:\n",helpfile));
638                 PACKI(desc,"N",count);                     /* number of files to copy */
639
640                 for (i=0;i<count;i++) 
641                 {
642                         /* no need to check return value here
643                          * - it was already tested in
644                          * get_printerdrivernumber */
645                         next_token(&p,tok,",",sizeof(tok));
646                         PACKS(desc,"z",tok);         /* driver files to copy */
647                         DEBUG(3,("file:%s:\n",tok));
648                 }
649                 
650                 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
651                           SERVICE(snum),count));
652
653                 desc->errcode=NERR_Success;
654                 goto done;
655         }
656
657   err:
658
659         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
660         desc->errcode=NERR_notsupported;
661
662  done:
663         safe_free(info);
664         file_lines_free(lines); 
665 }
666
667
668 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
669                              struct pack_desc* desc,
670                              int count, print_queue_struct* queue,
671                              print_status_struct* status)
672 {
673         switch (uLevel) {
674         case 1:
675         case 2:
676                 PACKS(desc,"B13",SERVICE(snum));
677                 break;
678         case 3:
679         case 4:
680         case 5:
681                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
682                 break;
683         case 51:
684                 PACKI(desc,"K",printq_status(status->status));
685                 break;
686         }
687
688         if (uLevel == 1 || uLevel == 2) {
689                 PACKS(desc,"B","");             /* alignment */
690                 PACKI(desc,"W",5);              /* priority */
691                 PACKI(desc,"W",0);              /* start time */
692                 PACKI(desc,"W",0);              /* until time */
693                 PACKS(desc,"z","");             /* pSepFile */
694                 PACKS(desc,"z","lpd");  /* pPrProc */
695                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
696                 PACKS(desc,"z","");             /* pParms */
697                 if (snum < 0) {
698                         PACKS(desc,"z","UNKNOWN PRINTER");
699                         PACKI(desc,"W",LPSTAT_ERROR);
700                 }
701                 else if (!status || !status->message[0]) {
702                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
703                         PACKI(desc,"W",LPSTAT_OK); /* status */
704                 } else {
705                         PACKS(desc,"z",status->message);
706                         PACKI(desc,"W",printq_status(status->status)); /* status */
707                 }
708                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
709         }
710
711         if (uLevel == 3 || uLevel == 4) {
712                 PACKI(desc,"W",5);              /* uPriority */
713                 PACKI(desc,"W",0);              /* uStarttime */
714                 PACKI(desc,"W",0);              /* uUntiltime */
715                 PACKI(desc,"W",5);              /* pad1 */
716                 PACKS(desc,"z","");             /* pszSepFile */
717                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
718                 PACKS(desc,"z","");             /* pszParms */
719                 if (!status || !status->message[0]) {
720                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
721                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
722                 } else {
723                         PACKS(desc,"z",status->message); /* pszComment */
724                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
725                 }
726                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
727                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
728                 PACKS(desc,"z",lp_printerdriver(snum));         /* pszDriverName */
729                 PackDriverData(desc);   /* pDriverData */
730         }
731
732         if (uLevel == 2 || uLevel == 4) {
733                 int i;
734                 for (i=0;i<count;i++)
735                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
736         }
737
738         if (uLevel==52) {
739                 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
740         }
741 }
742
743 /* This function returns the number of files for a given driver */
744 static int get_printerdrivernumber(int snum)
745 {
746         int i, result = 0;
747         BOOL ok = False;
748         pstring tok;
749         char *p;
750         char **lines = NULL;
751         pstring gen_line;
752         NT_PRINTER_INFO_LEVEL *info = NULL;
753         
754         /*
755          * Check in the tdb *first* before checking the legacy
756          * files. This allows an NT upload to take precedence over
757          * the existing fileset. JRA.
758          *
759          * we need to lookup the driver name prior to making the call
760          * to get_a_printer_driver_9x_compatible() and not rely on the
761          * 'print driver' parameter --jerry
762          */
763         
764         get_a_printer (&info, 2, lp_servicename(snum));
765         if ((info != NULL) && 
766             (ok = get_a_printer_driver_9x_compatible(gen_line, info->info_2->drivername) == True)) 
767         {
768                 p = gen_line;
769                 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", lp_printerdriver(snum), gen_line));
770         } 
771         else 
772         {
773                 /* didn't find driver in tdb */
774         
775                 DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
776                           snum, lp_printerdriver(snum), lp_driverfile(snum)));
777                 
778                 lines = file_lines_load(lp_driverfile(snum), NULL);
779                 if (!lines) 
780                 {
781                         DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
782                         goto done;
783                 } 
784
785                 /* lookup the long printer driver name in the file description */
786                 for (i=0;lines[i] && !ok;i++) 
787                 {
788                         p = lines[i];
789                         if (next_token(&p,tok,":",sizeof(tok)) &&
790                            (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
791                            (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum))))) 
792                         {
793                                 ok = True;
794                         }
795                 }
796         }
797         
798         if( ok ) 
799         {
800                 /* skip 5 fields */
801                 i = 5;
802                 while (*p && i) {
803                         if (*p++ == ':') i--;
804                 }
805                 if (!*p || i) {
806                         DEBUG(3,("Can't determine number of printer driver files\n"));
807                         goto done;
808                 }
809                 
810                 /* count the number of files */
811                 while (next_token(&p,tok,",",sizeof(tok)))
812                         i++;
813         
814                 result = i;
815         }
816
817  done:
818
819         safe_free(info);
820         file_lines_free(lines);
821
822         return result;
823 }
824
825 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
826                                  uint16 vuid, char *param,char *data,
827                                  int mdrcnt,int mprcnt,
828                                  char **rdata,char **rparam,
829                                  int *rdata_len,int *rparam_len)
830 {
831   char *str1 = param+2;
832   char *str2 = skip_string(str1,1);
833   char *p = skip_string(str2,1);
834   char *QueueName = p;
835   int uLevel;
836   int count=0;
837   int snum;
838   char* str3;
839   struct pack_desc desc;
840   print_queue_struct *queue=NULL;
841   print_status_struct status;
842   
843   memset((char *)&status,'\0',sizeof(status));
844   memset((char *)&desc,'\0',sizeof(desc));
845  
846   p = skip_string(p,1);
847   uLevel = SVAL(p,0);
848   str3 = p + 4;
849  
850   /* remove any trailing username */
851   if ((p = strchr(QueueName,'%'))) *p = 0;
852  
853   DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
854  
855   /* check it's a supported varient */
856   if (!prefix_ok(str1,"zWrLh")) return False;
857   if (!check_printq_info(&desc,uLevel,str2,str3)) {
858     /*
859      * Patch from Scott Moomaw <scott@bridgewater.edu>
860      * to return the 'invalid info level' error if an
861      * unknown level was requested.
862      */
863     *rdata_len = 0;
864     *rparam_len = 6;
865     *rparam = REALLOC(*rparam,*rparam_len);
866     SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
867     SSVAL(*rparam,2,0);
868     SSVAL(*rparam,4,0);
869     return(True);
870   }
871  
872   snum = lp_servicenumber(QueueName);
873   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
874     int pnum = lp_servicenumber(PRINTERS_NAME);
875     if (pnum >= 0) {
876       lp_add_printer(QueueName,pnum);
877       snum = lp_servicenumber(QueueName);
878     }
879   }
880   
881   if (snum < 0 || !VALID_SNUM(snum)) return(False);
882
883   if (uLevel==52) {
884           count = get_printerdrivernumber(snum);
885           DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
886   } else {
887           count = print_queue_status(snum, &queue,&status);
888   }
889
890   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
891   desc.base = *rdata;
892   desc.buflen = mdrcnt;
893   if (init_package(&desc,1,count)) {
894           desc.subcount = count;
895           fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
896   } else if(uLevel == 0) {
897 #if 0
898         /*
899          * This is a *disgusting* hack.
900          * This is *so* bad that even I'm embarrassed (and I
901          * have no shame). Here's the deal :
902          * Until we get the correct SPOOLSS code into smbd
903          * then when we're running with NT SMB support then
904          * NT makes this call with a level of zero, and then
905          * immediately follows it with an open request to
906          * the \\SRVSVC pipe. If we allow that open to
907          * succeed then NT barfs when it cannot open the
908          * \\SPOOLSS pipe immediately after and continually
909          * whines saying "Printer name is invalid" forever
910          * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
911          * to fail, then NT downgrades to using the downlevel code
912          * and everything works as well as before. I hate
913          * myself for adding this code.... JRA.
914          */
915
916         fail_next_srvsvc_open();
917 #endif
918   }
919
920   *rdata_len = desc.usedlen;
921   
922   *rparam_len = 6;
923   *rparam = REALLOC(*rparam,*rparam_len);
924   SSVALS(*rparam,0,desc.errcode);
925   SSVAL(*rparam,2,0);
926   SSVAL(*rparam,4,desc.neededlen);
927   
928   DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
929
930   if (queue) free(queue);
931   
932   return(True);
933 }
934
935 /****************************************************************************
936  View list of all print jobs on all queues.
937 ****************************************************************************/
938
939 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
940                               int mdrcnt, int mprcnt,
941                               char **rdata, char** rparam,
942                               int *rdata_len, int *rparam_len)
943 {
944   char *param_format = param+2;
945   char *output_format1 = skip_string(param_format,1);
946   char *p = skip_string(output_format1,1);
947   int uLevel = SVAL(p,0);
948   char *output_format2 = p + 4;
949   int services = lp_numservices();
950   int i, n;
951   struct pack_desc desc;
952   print_queue_struct **queue = NULL;
953   print_status_struct *status = NULL;
954   int* subcntarr = NULL;
955   int queuecnt, subcnt=0, succnt=0;
956  
957   memset((char *)&desc,'\0',sizeof(desc));
958
959   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
960  
961   if (!prefix_ok(param_format,"WrLeh")) return False;
962   if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
963     /*
964      * Patch from Scott Moomaw <scott@bridgewater.edu>
965      * to return the 'invalid info level' error if an
966      * unknown level was requested.
967      */
968     *rdata_len = 0;
969     *rparam_len = 6;
970     *rparam = REALLOC(*rparam,*rparam_len);
971     SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
972     SSVAL(*rparam,2,0);
973     SSVAL(*rparam,4,0);
974     return(True);
975   }
976
977   queuecnt = 0;
978   for (i = 0; i < services; i++)
979     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
980       queuecnt++;
981   if (uLevel > 0) {
982     if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
983       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
984       return False;
985     }
986     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
987     if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
988       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
989       return False;
990     }
991     memset(status,0,queuecnt*sizeof(print_status_struct));
992     if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
993       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
994       return False;
995     }
996     subcnt = 0;
997     n = 0;
998     for (i = 0; i < services; i++)
999       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1000         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1001         subcnt += subcntarr[n];
1002         n++;
1003       }
1004   }
1005   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1006   desc.base = *rdata;
1007   desc.buflen = mdrcnt;
1008
1009   if (init_package(&desc,queuecnt,subcnt)) {
1010     n = 0;
1011     succnt = 0;
1012     for (i = 0; i < services; i++)
1013       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1014         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1015         n++;
1016         if (desc.errcode == NERR_Success) succnt = n;
1017       }
1018   }
1019
1020   if (subcntarr) free(subcntarr);
1021  
1022   *rdata_len = desc.usedlen;
1023   *rparam_len = 8;
1024   *rparam = REALLOC(*rparam,*rparam_len);
1025   SSVALS(*rparam,0,desc.errcode);
1026   SSVAL(*rparam,2,0);
1027   SSVAL(*rparam,4,succnt);
1028   SSVAL(*rparam,6,queuecnt);
1029   
1030   for (i = 0; i < queuecnt; i++) {
1031     if (queue && queue[i]) free(queue[i]);
1032   }
1033
1034   if (queue) free(queue);
1035   if (status) free(status);
1036   
1037   return True;
1038 }
1039
1040 /****************************************************************************
1041   get info level for a server list query
1042   ****************************************************************************/
1043 static BOOL check_server_info(int uLevel, char* id)
1044 {
1045   switch( uLevel ) {
1046   case 0:
1047     if (strcmp(id,"B16") != 0) return False;
1048     break;
1049   case 1:
1050     if (strcmp(id,"B16BBDz") != 0) return False;
1051     break;
1052   default: 
1053     return False;
1054   }
1055   return True;
1056 }
1057
1058 struct srv_info_struct
1059 {
1060   fstring name;
1061   uint32 type;
1062   fstring comment;
1063   fstring domain;
1064   BOOL server_added;
1065 };
1066
1067
1068 /*******************************************************************
1069   get server info lists from the files saved by nmbd. Return the
1070   number of entries
1071   ******************************************************************/
1072 static int get_server_info(uint32 servertype, 
1073                            struct srv_info_struct **servers,
1074                            char *domain)
1075 {
1076   int count=0;
1077   int alloced=0;
1078   char **lines;
1079   BOOL local_list_only;
1080   int i;
1081
1082   lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1083   if (!lines) {
1084     DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1085     return(0);
1086   }
1087
1088   /* request for everything is code for request all servers */
1089   if (servertype == SV_TYPE_ALL) 
1090         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1091
1092   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1093
1094   DEBUG(4,("Servertype search: %8x\n",servertype));
1095
1096   for (i=0;lines[i];i++) {
1097     fstring stype;
1098     struct srv_info_struct *s;
1099     char *ptr = lines[i];
1100     BOOL ok = True;
1101
1102     if (!*ptr) continue;
1103     
1104     if (count == alloced) {
1105       alloced += 10;
1106       (*servers) = (struct srv_info_struct *)
1107         Realloc(*servers,sizeof(**servers)*alloced);
1108       if (!(*servers)) return(0);
1109       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1110     }
1111     s = &(*servers)[count];
1112     
1113     if (!next_token(&ptr,s->name   , NULL, sizeof(s->name))) continue;
1114     if (!next_token(&ptr,stype     , NULL, sizeof(stype))) continue;
1115     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1116     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1117       /* this allows us to cope with an old nmbd */
1118       pstrcpy(s->domain,global_myworkgroup); 
1119     }
1120     
1121     if (sscanf(stype,"%X",&s->type) != 1) { 
1122       DEBUG(4,("r:host file ")); 
1123       ok = False; 
1124     }
1125     
1126         /* Filter the servers/domains we return based on what was asked for. */
1127
1128         /* Check to see if we are being asked for a local list only. */
1129         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1130           DEBUG(4,("r: local list only"));
1131           ok = False;
1132         }
1133
1134     /* doesn't match up: don't want it */
1135     if (!(servertype & s->type)) { 
1136       DEBUG(4,("r:serv type ")); 
1137       ok = False; 
1138     }
1139     
1140     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1141         (s->type & SV_TYPE_DOMAIN_ENUM))
1142       {
1143         DEBUG(4,("s: dom mismatch "));
1144         ok = False;
1145       }
1146     
1147     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1148       {
1149         ok = False;
1150       }
1151     
1152         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1153         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1154
1155     if (ok)
1156       {
1157         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1158                  s->name, s->type, s->comment, s->domain));
1159         
1160         s->server_added = True;
1161         count++;
1162       }
1163     else
1164       {
1165         DEBUG(4,("%20s %8x %25s %15s\n",
1166                  s->name, s->type, s->comment, s->domain));
1167       }
1168   }
1169   
1170   file_lines_free(lines);
1171   return(count);
1172 }
1173
1174
1175 /*******************************************************************
1176   fill in a server info structure
1177   ******************************************************************/
1178 static int fill_srv_info(struct srv_info_struct *service, 
1179                          int uLevel, char **buf, int *buflen, 
1180                          char **stringbuf, int *stringspace, char *baseaddr)
1181 {
1182   int struct_len;
1183   char* p;
1184   char* p2;
1185   int l2;
1186   int len;
1187  
1188   switch (uLevel) {
1189   case 0: struct_len = 16; break;
1190   case 1: struct_len = 26; break;
1191   default: return -1;
1192   }  
1193  
1194   if (!buf)
1195     {
1196       len = 0;
1197       switch (uLevel) 
1198         {
1199         case 1:
1200           len = strlen(service->comment)+1;
1201           break;
1202         }
1203
1204       if (buflen) *buflen = struct_len;
1205       if (stringspace) *stringspace = len;
1206       return struct_len + len;
1207     }
1208   
1209   len = struct_len;
1210   p = *buf;
1211   if (*buflen < struct_len) return -1;
1212   if (stringbuf)
1213     {
1214       p2 = *stringbuf;
1215       l2 = *stringspace;
1216     }
1217   else
1218     {
1219       p2 = p + struct_len;
1220       l2 = *buflen - struct_len;
1221     }
1222   if (!baseaddr) baseaddr = p;
1223   
1224   switch (uLevel)
1225     {
1226     case 0:
1227       StrnCpy(p,service->name,15);
1228       break;
1229
1230     case 1:
1231       StrnCpy(p,service->name,15);
1232       SIVAL(p,18,service->type);
1233       SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1234       len += CopyAndAdvance(&p2,service->comment,&l2);
1235       break;
1236     }
1237
1238   if (stringbuf)
1239     {
1240       *buf = p + struct_len;
1241       *buflen -= struct_len;
1242       *stringbuf = p2;
1243       *stringspace = l2;
1244     }
1245   else
1246     {
1247       *buf = p2;
1248       *buflen -= len;
1249     }
1250   return len;
1251 }
1252
1253
1254 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1255 {
1256   return(strcmp(s1->name,s2->name));
1257 }
1258
1259 /****************************************************************************
1260   view list of servers available (or possibly domains). The info is
1261   extracted from lists saved by nmbd on the local host
1262   ****************************************************************************/
1263 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1264                                int mdrcnt, int mprcnt, char **rdata, 
1265                                char **rparam, int *rdata_len, int *rparam_len)
1266 {
1267   char *str1 = param+2;
1268   char *str2 = skip_string(str1,1);
1269   char *p = skip_string(str2,1);
1270   int uLevel = SVAL(p,0);
1271   int buf_len = SVAL(p,2);
1272   uint32 servertype = IVAL(p,4);
1273   char *p2;
1274   int data_len, fixed_len, string_len;
1275   int f_len = 0, s_len = 0;
1276   struct srv_info_struct *servers=NULL;
1277   int counted=0,total=0;
1278   int i,missed;
1279   fstring domain;
1280   BOOL domain_request;
1281   BOOL local_request;
1282
1283   /* If someone sets all the bits they don't really mean to set
1284      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1285      known servers. */
1286
1287   if (servertype == SV_TYPE_ALL) 
1288     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1289
1290   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1291      any other bit (they may just set this bit on it's own) they 
1292      want all the locally seen servers. However this bit can be 
1293      set on its own so set the requested servers to be 
1294      ALL - DOMAIN_ENUM. */
1295
1296   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1297     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1298
1299   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1300   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1301
1302   p += 8;
1303
1304   if (!prefix_ok(str1,"WrLehD")) return False;
1305   if (!check_server_info(uLevel,str2)) return False;
1306   
1307   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1308   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1309   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1310
1311   if (strcmp(str1, "WrLehDz") == 0) {
1312     StrnCpy(domain, p, sizeof(fstring)-1);
1313   } else {
1314     StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);    
1315   }
1316
1317   if (lp_browse_list())
1318     total = get_server_info(servertype,&servers,domain);
1319
1320   data_len = fixed_len = string_len = 0;
1321   missed = 0;
1322
1323   qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1324
1325   {
1326     char *lastname=NULL;
1327
1328     for (i=0;i<total;i++)
1329     {
1330       struct srv_info_struct *s = &servers[i];
1331       if (lastname && strequal(lastname,s->name)) continue;
1332       lastname = s->name;
1333       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1334       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1335                s->name, s->type, s->comment, s->domain));
1336       
1337       if (data_len <= buf_len) {
1338           counted++;
1339           fixed_len += f_len;
1340           string_len += s_len;
1341       } else {
1342         missed++;
1343       }
1344     }
1345   }
1346
1347   *rdata_len = fixed_len + string_len;
1348   *rdata = REALLOC(*rdata,*rdata_len);
1349   memset(*rdata,'\0',*rdata_len);
1350   
1351   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1352   p = *rdata;
1353   f_len = fixed_len;
1354   s_len = string_len;
1355
1356   {
1357     char *lastname=NULL;
1358     int count2 = counted;
1359     for (i = 0; i < total && count2;i++)
1360       {
1361         struct srv_info_struct *s = &servers[i];
1362         if (lastname && strequal(lastname,s->name)) continue;
1363         lastname = s->name;
1364         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1365         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1366                  s->name, s->type, s->comment, s->domain));
1367         count2--;
1368       }
1369   }
1370   
1371   *rparam_len = 8;
1372   *rparam = REALLOC(*rparam,*rparam_len);
1373   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1374   SSVAL(*rparam,2,0);
1375   SSVAL(*rparam,4,counted);
1376   SSVAL(*rparam,6,counted+missed);
1377
1378   if (servers) free(servers);
1379
1380   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1381            domain,uLevel,counted,counted+missed));
1382
1383   return(True);
1384 }
1385
1386 /****************************************************************************
1387   command 0x34 - suspected of being a "Lookup Names" stub api
1388   ****************************************************************************/
1389 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1390                                int mdrcnt, int mprcnt, char **rdata, 
1391                                char **rparam, int *rdata_len, int *rparam_len)
1392 {
1393   char *str1 = param+2;
1394   char *str2 = skip_string(str1,1);
1395   char *p = skip_string(str2,1);
1396   int uLevel = SVAL(p,0);
1397   int buf_len = SVAL(p,2);
1398   int counted=0;
1399   int missed=0;
1400
1401         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1402                 str1, str2, p, uLevel, buf_len));
1403
1404   if (!prefix_ok(str1,"zWrLeh")) return False;
1405   
1406   *rdata_len = 0;
1407   
1408   *rparam_len = 8;
1409   *rparam = REALLOC(*rparam,*rparam_len);
1410
1411   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1412   SSVAL(*rparam,2,0);
1413   SSVAL(*rparam,4,counted);
1414   SSVAL(*rparam,6,counted+missed);
1415
1416   return(True);
1417 }
1418
1419 /****************************************************************************
1420   get info about a share
1421   ****************************************************************************/
1422 static BOOL check_share_info(int uLevel, char* id)
1423 {
1424   switch( uLevel ) {
1425   case 0:
1426     if (strcmp(id,"B13") != 0) return False;
1427     break;
1428   case 1:
1429     if (strcmp(id,"B13BWz") != 0) return False;
1430     break;
1431   case 2:
1432     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1433     break;
1434   case 91:
1435     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1436     break;
1437   default: return False;
1438   }
1439   return True;
1440 }
1441
1442 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1443                            char** buf, int* buflen,
1444                            char** stringbuf, int* stringspace, char* baseaddr)
1445 {
1446   int struct_len;
1447   char* p;
1448   char* p2;
1449   int l2;
1450   int len;
1451  
1452   switch( uLevel ) {
1453   case 0: struct_len = 13; break;
1454   case 1: struct_len = 20; break;
1455   case 2: struct_len = 40; break;
1456   case 91: struct_len = 68; break;
1457   default: return -1;
1458   }
1459   
1460  
1461   if (!buf)
1462     {
1463       len = 0;
1464       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1465       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1466       if (buflen) *buflen = struct_len;
1467       if (stringspace) *stringspace = len;
1468       return struct_len + len;
1469     }
1470   
1471   len = struct_len;
1472   p = *buf;
1473   if ((*buflen) < struct_len) return -1;
1474   if (stringbuf)
1475     {
1476       p2 = *stringbuf;
1477       l2 = *stringspace;
1478     }
1479   else
1480     {
1481       p2 = p + struct_len;
1482       l2 = (*buflen) - struct_len;
1483     }
1484   if (!baseaddr) baseaddr = p;
1485   
1486   StrnCpy(p,lp_servicename(snum),13);
1487   
1488   if (uLevel > 0)
1489     {
1490       int type;
1491       CVAL(p,13) = 0;
1492       type = STYPE_DISKTREE;
1493       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1494       if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1495       SSVAL(p,14,type);         /* device type */
1496       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1497       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1498     }
1499   
1500   if (uLevel > 1)
1501     {
1502       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1503       SSVALS(p,22,-1);          /* max uses */
1504       SSVAL(p,24,1); /* current uses */
1505       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1506       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1507       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1508     }
1509   
1510   if (uLevel > 2)
1511     {
1512       memset(p+40,0,SHPWLEN+2);
1513       SSVAL(p,50,0);
1514       SIVAL(p,52,0);
1515       SSVAL(p,56,0);
1516       SSVAL(p,58,0);
1517       SIVAL(p,60,0);
1518       SSVAL(p,64,0);
1519       SSVAL(p,66,0);
1520     }
1521        
1522   if (stringbuf)
1523     {
1524       (*buf) = p + struct_len;
1525       (*buflen) -= struct_len;
1526       (*stringbuf) = p2;
1527       (*stringspace) = l2;
1528     }
1529   else
1530     {
1531       (*buf) = p2;
1532       (*buflen) -= len;
1533     }
1534   return len;
1535 }
1536
1537 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1538                                  int mdrcnt,int mprcnt,
1539                                  char **rdata,char **rparam,
1540                                  int *rdata_len,int *rparam_len)
1541 {
1542   char *str1 = param+2;
1543   char *str2 = skip_string(str1,1);
1544   char *netname = skip_string(str2,1);
1545   char *p = skip_string(netname,1);
1546   int uLevel = SVAL(p,0);
1547   int snum = find_service(netname);
1548   
1549   if (snum < 0) return False;
1550   
1551   /* check it's a supported varient */
1552   if (!prefix_ok(str1,"zWrLh")) return False;
1553   if (!check_share_info(uLevel,str2)) return False;
1554  
1555   *rdata = REALLOC(*rdata,mdrcnt);
1556   p = *rdata;
1557   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1558   if (*rdata_len < 0) return False;
1559  
1560   *rparam_len = 6;
1561   *rparam = REALLOC(*rparam,*rparam_len);
1562   SSVAL(*rparam,0,NERR_Success);
1563   SSVAL(*rparam,2,0);           /* converter word */
1564   SSVAL(*rparam,4,*rdata_len);
1565  
1566   return(True);
1567 }
1568
1569 /****************************************************************************
1570   view list of shares available
1571   ****************************************************************************/
1572 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1573                               int mdrcnt,int mprcnt,
1574                               char **rdata,char **rparam,
1575                               int *rdata_len,int *rparam_len)
1576 {
1577   char *str1 = param+2;
1578   char *str2 = skip_string(str1,1);
1579   char *p = skip_string(str2,1);
1580   int uLevel = SVAL(p,0);
1581   int buf_len = SVAL(p,2);
1582   char *p2;
1583   int count=lp_numservices();
1584   int total=0,counted=0;
1585   BOOL missed = False;
1586   int i;
1587   int data_len, fixed_len, string_len;
1588   int f_len = 0, s_len = 0;
1589  
1590   if (!prefix_ok(str1,"WrLeh")) return False;
1591   if (!check_share_info(uLevel,str2)) return False;
1592   
1593   data_len = fixed_len = string_len = 0;
1594   for (i=0;i<count;i++)
1595     if (lp_browseable(i) && lp_snum_ok(i))
1596     {
1597       total++;
1598       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1599       if (data_len <= buf_len)
1600       {
1601         counted++;
1602         fixed_len += f_len;
1603         string_len += s_len;
1604       }
1605       else
1606         missed = True;
1607     }
1608   *rdata_len = fixed_len + string_len;
1609   *rdata = REALLOC(*rdata,*rdata_len);
1610   memset(*rdata,0,*rdata_len);
1611   
1612   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1613   p = *rdata;
1614   f_len = fixed_len;
1615   s_len = string_len;
1616   for (i = 0; i < count;i++)
1617     if (lp_browseable(i) && lp_snum_ok(i))
1618       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1619         break;
1620   
1621   *rparam_len = 8;
1622   *rparam = REALLOC(*rparam,*rparam_len);
1623   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1624   SSVAL(*rparam,2,0);
1625   SSVAL(*rparam,4,counted);
1626   SSVAL(*rparam,6,total);
1627   
1628   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1629            counted,total,uLevel,
1630            buf_len,*rdata_len,mdrcnt));
1631   return(True);
1632 }
1633
1634
1635
1636 /****************************************************************************
1637   get the time of day info
1638   ****************************************************************************/
1639 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1640                              int mdrcnt,int mprcnt,
1641                              char **rdata,char **rparam,
1642                              int *rdata_len,int *rparam_len)
1643 {
1644   char *p;
1645   *rparam_len = 4;
1646   *rparam = REALLOC(*rparam,*rparam_len);
1647
1648   *rdata_len = 21;
1649   *rdata = REALLOC(*rdata,*rdata_len);
1650
1651   SSVAL(*rparam,0,NERR_Success);
1652   SSVAL(*rparam,2,0);           /* converter word */
1653
1654   p = *rdata;
1655
1656   {
1657     struct tm *t;
1658     time_t unixdate = time(NULL);
1659
1660     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1661                                     by NT in a "net time" operation,
1662                                     it seems to ignore the one below */
1663
1664     /* the client expects to get localtime, not GMT, in this bit 
1665        (I think, this needs testing) */
1666     t = LocalTime(&unixdate);
1667
1668     SIVAL(p,4,0);               /* msecs ? */
1669     CVAL(p,8) = t->tm_hour;
1670     CVAL(p,9) = t->tm_min;
1671     CVAL(p,10) = t->tm_sec;
1672     CVAL(p,11) = 0;             /* hundredths of seconds */
1673     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1674     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1675     CVAL(p,16) = t->tm_mday;
1676     CVAL(p,17) = t->tm_mon + 1;
1677     SSVAL(p,18,1900+t->tm_year);
1678     CVAL(p,20) = t->tm_wday;
1679   }
1680
1681
1682   return(True);
1683 }
1684
1685 /****************************************************************************
1686  Set the user password.
1687 *****************************************************************************/
1688
1689 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1690                                 int mdrcnt,int mprcnt,
1691                                 char **rdata,char **rparam,
1692                                 int *rdata_len,int *rparam_len)
1693 {
1694   char *p = skip_string(param+2,2);
1695   fstring user;
1696   fstring pass1,pass2;
1697
1698   fstrcpy(user,p);
1699
1700   p = skip_string(p,1);
1701
1702   memset(pass1,'\0',sizeof(pass1));
1703   memset(pass2,'\0',sizeof(pass2));
1704   memcpy(pass1,p,16);
1705   memcpy(pass2,p+16,16);
1706
1707   *rparam_len = 4;
1708   *rparam = REALLOC(*rparam,*rparam_len);
1709
1710   *rdata_len = 0;
1711
1712   SSVAL(*rparam,0,NERR_badpass);
1713   SSVAL(*rparam,2,0);           /* converter word */
1714
1715   DEBUG(3,("Set password for <%s>\n",user));
1716
1717   /*
1718    * Pass the user through the NT -> unix user mapping
1719    * function.
1720    */
1721
1722   (void)map_username(user);
1723
1724   /*
1725    * Do any UNIX username case mangling.
1726    */
1727   (void)Get_Pwnam( user, True);
1728
1729   /*
1730    * Attempt to verify the old password against smbpasswd entries
1731    * Win98 clients send old and new password in plaintext for this call.
1732    */
1733
1734   {
1735     fstring saved_pass2;
1736     SAM_ACCOUNT *sampass;
1737
1738     /*
1739      * Save the new password as change_oem_password overwrites it
1740      * with zeros.
1741      */
1742
1743     fstrcpy(saved_pass2, pass2);
1744
1745     if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1746         change_oem_password(sampass,pass2,False))
1747     {
1748       SSVAL(*rparam,0,NERR_Success);
1749
1750       /*
1751        * If unix password sync was requested, attempt to change
1752        * the /etc/passwd database also. Return failure if this cannot
1753        * be done.
1754        */
1755
1756       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1757         SSVAL(*rparam,0,NERR_badpass);
1758     }
1759   }
1760
1761   /*
1762    * If the above failed, attempt the plaintext password change.
1763    * This tests against the /etc/passwd database only.
1764    */
1765
1766   if(SVAL(*rparam,0) != NERR_Success)
1767   {
1768     if (password_ok(user, pass1,strlen(pass1),NULL) &&
1769         chgpasswd(user,pass1,pass2,False))
1770     {
1771       SSVAL(*rparam,0,NERR_Success);
1772     }
1773   }
1774
1775   /*
1776    * If the plaintext change failed, attempt
1777    * the old encrypted method. NT will generate this
1778    * after trying the samr method. Note that this
1779    * method is done as a last resort as this
1780    * password change method loses the NT password hash
1781    * and cannot change the UNIX password as no plaintext
1782    * is received.
1783    */
1784
1785   if(SVAL(*rparam,0) != NERR_Success)
1786   {
1787     SAM_ACCOUNT *hnd = NULL;
1788
1789     if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
1790        change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1791     {
1792       SSVAL(*rparam,0,NERR_Success);
1793     }
1794   }
1795
1796   memset((char *)pass1,'\0',sizeof(fstring));
1797   memset((char *)pass2,'\0',sizeof(fstring));    
1798          
1799   return(True);
1800 }
1801
1802 /****************************************************************************
1803   Set the user password (SamOEM version - gets plaintext).
1804 ****************************************************************************/
1805
1806 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1807                                 int mdrcnt,int mprcnt,
1808                                 char **rdata,char **rparam,
1809                                 int *rdata_len,int *rparam_len)
1810 {
1811   fstring user;
1812   char *p = param + 2;
1813   *rparam_len = 2;
1814   *rparam = REALLOC(*rparam,*rparam_len);
1815
1816   *rdata_len = 0;
1817
1818   SSVAL(*rparam,0,NERR_badpass);
1819
1820   /*
1821    * Check the parameter definition is correct.
1822    */
1823   if(!strequal(param + 2, "zsT")) {
1824     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1825     return False;
1826   }
1827   p = skip_string(p, 1);
1828
1829   if(!strequal(p, "B516B16")) {
1830     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1831     return False;
1832   }
1833   p = skip_string(p,1);
1834
1835   fstrcpy(user,p);
1836   p = skip_string(p,1);
1837
1838   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1839
1840   /*
1841    * Pass the user through the NT -> unix user mapping
1842    * function.
1843    */
1844
1845   (void)map_username(user);
1846
1847   /*
1848    * Do any UNIX username case mangling.
1849    */
1850   (void)Get_Pwnam( user, True);
1851
1852   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1853   {
1854     SSVAL(*rparam,0,NERR_Success);
1855   }
1856
1857   return(True);
1858 }
1859
1860 /****************************************************************************
1861   delete a print job
1862   Form: <W> <> 
1863   ****************************************************************************/
1864 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1865                                 int mdrcnt,int mprcnt,
1866                                 char **rdata,char **rparam,
1867                                 int *rdata_len,int *rparam_len)
1868 {
1869         int function = SVAL(param,0);
1870         char *str1 = param+2;
1871         char *str2 = skip_string(str1,1);
1872         char *p = skip_string(str2,1);
1873         int jobid, errcode;
1874         extern struct current_user current_user;
1875
1876         jobid = SVAL(p,0);
1877
1878         /* check it's a supported varient */
1879         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1880                 return(False);
1881
1882         *rparam_len = 4;
1883         *rparam = REALLOC(*rparam,*rparam_len); 
1884         *rdata_len = 0;
1885
1886         if (!print_job_exists(jobid)) {
1887                 errcode = NERR_JobNotFound;
1888                 goto out;
1889         }
1890
1891         errcode = NERR_notsupported;
1892         
1893         switch (function) {
1894         case 81:                /* delete */ 
1895                 if (print_job_delete(&current_user, jobid, &errcode)) 
1896                         errcode = NERR_Success;
1897                 break;
1898         case 82:                /* pause */
1899                 if (print_job_pause(&current_user, jobid, &errcode)) 
1900                         errcode = NERR_Success;
1901                 break;
1902         case 83:                /* resume */
1903                 if (print_job_resume(&current_user, jobid, &errcode)) 
1904                         errcode = NERR_Success;
1905                 break;
1906         }
1907         
1908  out:
1909         SSVAL(*rparam,0,errcode);       
1910         SSVAL(*rparam,2,0);             /* converter word */
1911
1912         return(True);
1913 }
1914
1915 /****************************************************************************
1916   Purge a print queue - or pause or resume it.
1917   ****************************************************************************/
1918 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1919                                  int mdrcnt,int mprcnt,
1920                                  char **rdata,char **rparam,
1921                                  int *rdata_len,int *rparam_len)
1922 {
1923         int function = SVAL(param,0);
1924         char *str1 = param+2;
1925         char *str2 = skip_string(str1,1);
1926         char *QueueName = skip_string(str2,1);
1927         int errcode = NERR_notsupported;
1928         int snum;
1929
1930         /* check it's a supported varient */
1931         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1932                 return(False);
1933
1934         *rparam_len = 4;
1935         *rparam = REALLOC(*rparam,*rparam_len);
1936         *rdata_len = 0;
1937
1938         snum = print_queue_snum(QueueName);
1939
1940         if (snum == -1) {
1941                 errcode = NERR_JobNotFound;
1942                 goto out;
1943         }
1944
1945         switch (function) {
1946         case 74: /* Pause queue */
1947                 if (print_queue_pause(NULL, snum, &errcode)) errcode = NERR_Success;
1948                 break;
1949         case 75: /* Resume queue */
1950                 if (print_queue_resume(NULL, snum, &errcode)) errcode = NERR_Success;
1951                 break;
1952         case 103: /* Purge */
1953                 if (print_queue_purge(NULL, snum, &errcode)) errcode = NERR_Success;
1954                 break;
1955         }
1956
1957  out:
1958         SSVAL(*rparam,0,errcode);
1959         SSVAL(*rparam,2,0);             /* converter word */
1960
1961         return(True);
1962 }
1963
1964
1965 /****************************************************************************
1966   set the property of a print job (undocumented?)
1967   ? function = 0xb -> set name of print job
1968   ? function = 0x6 -> move print job up/down
1969   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1970   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1971 ****************************************************************************/
1972 static int check_printjob_info(struct pack_desc* desc,
1973                                int uLevel, char* id)
1974 {
1975         desc->subformat = NULL;
1976         switch( uLevel ) {
1977         case 0: desc->format = "W"; break;
1978         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1979         case 2: desc->format = "WWzWWDDzz"; break;
1980         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1981         default: return False;
1982         }
1983         if (strcmp(desc->format,id) != 0) return False;
1984         return True;
1985 }
1986
1987 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1988                              int mdrcnt,int mprcnt,
1989                              char **rdata,char **rparam,
1990                              int *rdata_len,int *rparam_len)
1991 {
1992         struct pack_desc desc;
1993         char *str1 = param+2;
1994         char *str2 = skip_string(str1,1);
1995         char *p = skip_string(str2,1);
1996         int jobid;
1997         int uLevel = SVAL(p,2);
1998         int function = SVAL(p,4);
1999         int place, errcode;
2000
2001         jobid = SVAL(p,0);
2002         *rparam_len = 4;
2003         *rparam = REALLOC(*rparam,*rparam_len);
2004   
2005         *rdata_len = 0;
2006         
2007         /* check it's a supported varient */
2008         if ((strcmp(str1,"WWsTP")) || 
2009             (!check_printjob_info(&desc,uLevel,str2)))
2010                 return(False);
2011
2012         if (!print_job_exists(jobid)) {
2013                 errcode=NERR_JobNotFound;
2014                 goto out;
2015         }
2016
2017         errcode = NERR_notsupported;
2018
2019         switch (function) {
2020         case 0x6:
2021                 /* change job place in the queue, 
2022                    data gives the new place */
2023                 place = SVAL(data,0);
2024                 if (print_job_set_place(jobid, place)) {
2025                         errcode=NERR_Success;
2026                 }
2027                 break;
2028
2029         case 0xb:   
2030                 /* change print job name, data gives the name */
2031                 if (print_job_set_name(jobid, data)) {
2032                         errcode=NERR_Success;
2033                 }
2034                 break;
2035
2036         default:
2037                 return False;
2038         }
2039
2040  out:
2041         SSVALS(*rparam,0,errcode);
2042         SSVAL(*rparam,2,0);             /* converter word */
2043         
2044         return(True);
2045 }
2046
2047
2048 /****************************************************************************
2049   get info about the server
2050   ****************************************************************************/
2051 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2052                                   int mdrcnt,int mprcnt,
2053                                   char **rdata,char **rparam,
2054                                   int *rdata_len,int *rparam_len)
2055 {
2056   char *str1 = param+2;
2057   char *str2 = skip_string(str1,1);
2058   char *p = skip_string(str2,1);
2059   int uLevel = SVAL(p,0);
2060   char *p2;
2061   int struct_len;
2062
2063   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2064
2065   /* check it's a supported varient */
2066   if (!prefix_ok(str1,"WrLh")) return False;
2067   switch( uLevel ) {
2068   case 0:
2069     if (strcmp(str2,"B16") != 0) return False;
2070     struct_len = 16;
2071     break;
2072   case 1:
2073     if (strcmp(str2,"B16BBDz") != 0) return False;
2074     struct_len = 26;
2075     break;
2076   case 2:
2077     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2078         != 0) return False;
2079     struct_len = 134;
2080     break;
2081   case 3:
2082     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2083         != 0) return False;
2084     struct_len = 144;
2085     break;
2086   case 20:
2087     if (strcmp(str2,"DN") != 0) return False;
2088     struct_len = 6;
2089     break;
2090   case 50:
2091     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2092     struct_len = 42;
2093     break;
2094   default: return False;
2095   }
2096
2097   *rdata_len = mdrcnt;
2098   *rdata = REALLOC(*rdata,*rdata_len);
2099
2100   p = *rdata;
2101   p2 = p + struct_len;
2102   if (uLevel != 20) {
2103     StrnCpy(p,local_machine,16);
2104     strupper(p);
2105   }
2106   p += 16;
2107   if (uLevel > 0)
2108     {
2109       struct srv_info_struct *servers=NULL;
2110       int i,count;
2111       pstring comment;
2112       uint32 servertype= lp_default_server_announce();
2113
2114       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2115
2116       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2117         for (i=0;i<count;i++)
2118           if (strequal(servers[i].name,local_machine))
2119       {
2120             servertype = servers[i].type;
2121             pstrcpy(comment,servers[i].comment);            
2122           }
2123       }
2124       if (servers) free(servers);
2125
2126       SCVAL(p,0,lp_major_announce_version());
2127       SCVAL(p,1,lp_minor_announce_version());
2128       SIVAL(p,2,servertype);
2129
2130       if (mdrcnt == struct_len) {
2131         SIVAL(p,6,0);
2132       } else {
2133         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2134         standard_sub_conn(conn,comment);
2135         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2136         p2 = skip_string(p2,1);
2137       }
2138     }
2139   if (uLevel > 1)
2140     {
2141       return False;             /* not yet implemented */
2142     }
2143
2144   *rdata_len = PTR_DIFF(p2,*rdata);
2145
2146   *rparam_len = 6;
2147   *rparam = REALLOC(*rparam,*rparam_len);
2148   SSVAL(*rparam,0,NERR_Success);
2149   SSVAL(*rparam,2,0);           /* converter word */
2150   SSVAL(*rparam,4,*rdata_len);
2151
2152   return(True);
2153 }
2154
2155
2156 /****************************************************************************
2157   get info about the server
2158   ****************************************************************************/
2159 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2160                                 int mdrcnt,int mprcnt,
2161                                 char **rdata,char **rparam,
2162                                 int *rdata_len,int *rparam_len)
2163 {
2164   char *str1 = param+2;
2165   char *str2 = skip_string(str1,1);
2166   char *p = skip_string(str2,1);
2167   char *p2;
2168   extern pstring sesssetup_user;
2169   int level = SVAL(p,0);
2170
2171   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2172
2173   *rparam_len = 6;
2174   *rparam = REALLOC(*rparam,*rparam_len);
2175
2176   /* check it's a supported varient */
2177   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2178     return(False);
2179
2180   *rdata_len = mdrcnt + 1024;
2181   *rdata = REALLOC(*rdata,*rdata_len);
2182
2183   SSVAL(*rparam,0,NERR_Success);
2184   SSVAL(*rparam,2,0);           /* converter word */
2185
2186   p = *rdata;
2187   p2 = p + 22;
2188
2189
2190   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2191   pstrcpy(p2,local_machine);
2192   strupper(p2);
2193   p2 = skip_string(p2,1);
2194   p += 4;
2195
2196   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2197   pstrcpy(p2,sesssetup_user);
2198   p2 = skip_string(p2,1);
2199   p += 4;
2200
2201   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2202   pstrcpy(p2,global_myworkgroup);
2203   strupper(p2);
2204   p2 = skip_string(p2,1);
2205   p += 4;
2206
2207   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2208   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2209   p += 2;
2210
2211   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2212   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2213   p2 = skip_string(p2,1);
2214   p += 4;
2215
2216   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2217   pstrcpy(p2,"");
2218   p2 = skip_string(p2,1);
2219   p += 4;
2220
2221   *rdata_len = PTR_DIFF(p2,*rdata);
2222
2223   SSVAL(*rparam,4,*rdata_len);
2224
2225   return(True);
2226 }
2227
2228 /****************************************************************************
2229   get info about a user
2230
2231     struct user_info_11 {
2232         char                usri11_name[21];  0-20 
2233         char                usri11_pad;       21 
2234         char                *usri11_comment;  22-25 
2235         char            *usri11_usr_comment;  26-29
2236         unsigned short      usri11_priv;      30-31
2237         unsigned long       usri11_auth_flags; 32-35
2238         long                usri11_password_age; 36-39
2239         char                *usri11_homedir; 40-43
2240         char            *usri11_parms; 44-47
2241         long                usri11_last_logon; 48-51
2242         long                usri11_last_logoff; 52-55
2243         unsigned short      usri11_bad_pw_count; 56-57
2244         unsigned short      usri11_num_logons; 58-59
2245         char                *usri11_logon_server; 60-63
2246         unsigned short      usri11_country_code; 64-65
2247         char            *usri11_workstations; 66-69
2248         unsigned long       usri11_max_storage; 70-73
2249         unsigned short      usri11_units_per_week; 74-75
2250         unsigned char       *usri11_logon_hours; 76-79
2251         unsigned short      usri11_code_page; 80-81
2252     };
2253
2254 where:
2255
2256   usri11_name specifies the user name for which information is retireved
2257
2258   usri11_pad aligns the next data structure element to a word boundary
2259
2260   usri11_comment is a null terminated ASCII comment
2261
2262   usri11_user_comment is a null terminated ASCII comment about the user
2263
2264   usri11_priv specifies the level of the privilege assigned to the user.
2265        The possible values are:
2266
2267 Name             Value  Description
2268 USER_PRIV_GUEST  0      Guest privilege
2269 USER_PRIV_USER   1      User privilege
2270 USER_PRV_ADMIN   2      Administrator privilege
2271
2272   usri11_auth_flags specifies the account operator privileges. The
2273        possible values are:
2274
2275 Name            Value   Description
2276 AF_OP_PRINT     0       Print operator
2277
2278
2279 Leach, Naik                                        [Page 28]
2280 \f
2281
2282
2283 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2284
2285
2286 AF_OP_COMM      1       Communications operator
2287 AF_OP_SERVER    2       Server operator
2288 AF_OP_ACCOUNTS  3       Accounts operator
2289
2290
2291   usri11_password_age specifies how many seconds have elapsed since the
2292        password was last changed.
2293
2294   usri11_home_dir points to a null terminated ASCII string that contains
2295        the path name of the user's home directory.
2296
2297   usri11_parms points to a null terminated ASCII string that is set
2298        aside for use by applications.
2299
2300   usri11_last_logon specifies the time when the user last logged on.
2301        This value is stored as the number of seconds elapsed since
2302        00:00:00, January 1, 1970.
2303
2304   usri11_last_logoff specifies the time when the user last logged off.
2305        This value is stored as the number of seconds elapsed since
2306        00:00:00, January 1, 1970. A value of 0 means the last logoff
2307        time is unknown.
2308
2309   usri11_bad_pw_count specifies the number of incorrect passwords
2310        entered since the last successful logon.
2311
2312   usri11_log1_num_logons specifies the number of times this user has
2313        logged on. A value of -1 means the number of logons is unknown.
2314
2315   usri11_logon_server points to a null terminated ASCII string that
2316        contains the name of the server to which logon requests are sent.
2317        A null string indicates logon requests should be sent to the
2318        domain controller.
2319
2320   usri11_country_code specifies the country code for the user's language
2321        of choice.
2322
2323   usri11_workstations points to a null terminated ASCII string that
2324        contains the names of workstations the user may log on from.
2325        There may be up to 8 workstations, with the names separated by
2326        commas. A null strings indicates there are no restrictions.
2327
2328   usri11_max_storage specifies the maximum amount of disk space the user
2329        can occupy. A value of 0xffffffff indicates there are no
2330        restrictions.
2331
2332   usri11_units_per_week specifies the equal number of time units into
2333        which a week is divided. This value must be equal to 168.
2334
2335   usri11_logon_hours points to a 21 byte (168 bits) string that
2336        specifies the time during which the user can log on. Each bit
2337        represents one unique hour in a week. The first bit (bit 0, word
2338        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2339
2340
2341
2342 Leach, Naik                                        [Page 29]
2343 \f
2344
2345
2346 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2347
2348
2349        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2350        are no restrictions.
2351
2352   usri11_code_page specifies the code page for the user's language of
2353        choice
2354
2355 All of the pointers in this data structure need to be treated
2356 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2357 to be ignored. The converter word returned in the parameters section
2358 needs to be subtracted from the lower 16 bits to calculate an offset
2359 into the return buffer where this ASCII string resides.
2360
2361 There is no auxiliary data in the response.
2362
2363   ****************************************************************************/
2364
2365 #define usri11_name           0 
2366 #define usri11_pad            21
2367 #define usri11_comment        22
2368 #define usri11_usr_comment    26
2369 #define usri11_full_name      30
2370 #define usri11_priv           34
2371 #define usri11_auth_flags     36
2372 #define usri11_password_age   40
2373 #define usri11_homedir        44
2374 #define usri11_parms          48
2375 #define usri11_last_logon     52
2376 #define usri11_last_logoff    56
2377 #define usri11_bad_pw_count   60
2378 #define usri11_num_logons     62
2379 #define usri11_logon_server   64
2380 #define usri11_country_code   68
2381 #define usri11_workstations   70
2382 #define usri11_max_storage    74
2383 #define usri11_units_per_week 78
2384 #define usri11_logon_hours    80
2385 #define usri11_code_page      84
2386 #define usri11_end            86
2387
2388 #define USER_PRIV_GUEST 0
2389 #define USER_PRIV_USER 1
2390 #define USER_PRIV_ADMIN 2
2391
2392 #define AF_OP_PRINT     0 
2393 #define AF_OP_COMM      1
2394 #define AF_OP_SERVER    2
2395 #define AF_OP_ACCOUNTS  3
2396
2397
2398 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2399                                 int mdrcnt,int mprcnt,
2400                                 char **rdata,char **rparam,
2401                                 int *rdata_len,int *rparam_len)
2402 {
2403         char *str1 = param+2;
2404         char *str2 = skip_string(str1,1);
2405         char *UserName = skip_string(str2,1);
2406         char *p = skip_string(UserName,1);
2407         int uLevel = SVAL(p,0);
2408         char *p2;
2409
2410     /* get NIS home of a previously validated user - simeon */
2411     /* With share level security vuid will always be zero.
2412        Don't depend on vuser being non-null !!. JRA */
2413     user_struct *vuser = get_valid_user_struct(vuid);
2414     if(vuser != NULL)
2415       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2416                vuser->user.unix_name));
2417
2418     *rparam_len = 6;
2419     *rparam = REALLOC(*rparam,*rparam_len);
2420
2421     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2422   
2423         /* check it's a supported variant */
2424         if (strcmp(str1,"zWrLh") != 0) return False;
2425         switch( uLevel )
2426         {
2427                 case 0: p2 = "B21"; break;
2428                 case 1: p2 = "B21BB16DWzzWz"; break;
2429                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2430                 case 10: p2 = "B21Bzzz"; break;
2431                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2432                 default: return False;
2433         }
2434
2435         if (strcmp(p2,str2) != 0) return False;
2436
2437         *rdata_len = mdrcnt + 1024;
2438         *rdata = REALLOC(*rdata,*rdata_len);
2439
2440         SSVAL(*rparam,0,NERR_Success);
2441         SSVAL(*rparam,2,0);             /* converter word */
2442
2443         p = *rdata;
2444         p2 = p + usri11_end;
2445
2446         memset(p,0,21); 
2447         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2448
2449         if (uLevel > 0)
2450         {
2451                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2452                 *p2 = 0;
2453         }
2454         if (uLevel >= 10)
2455         {
2456                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2457                 pstrcpy(p2,"Comment");
2458                 p2 = skip_string(p2,1);
2459
2460                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2461                 pstrcpy(p2,"UserComment");
2462                 p2 = skip_string(p2,1);
2463
2464                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2465                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2466                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2467                 p2 = skip_string(p2,1);
2468         }
2469
2470         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2471         {         
2472                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2473                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2474                 SIVALS(p,usri11_password_age,-1);               /* password age */
2475                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2476                 pstrcpy(p2, lp_logon_home());
2477                 standard_sub_conn(conn, p2);
2478                 p2 = skip_string(p2,1);
2479                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2480                 pstrcpy(p2,"");
2481                 p2 = skip_string(p2,1);
2482                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2483                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2484                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2485                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2486                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2487                 pstrcpy(p2,"\\\\*");
2488                 p2 = skip_string(p2,1);
2489                 SSVAL(p,usri11_country_code,0);         /* country code */
2490
2491                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2492                 pstrcpy(p2,"");
2493                 p2 = skip_string(p2,1);
2494
2495                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2496                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2497                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2498
2499                 /* a simple way to get logon hours at all times. */
2500                 memset(p2,0xff,21);
2501                 SCVAL(p2,21,0);           /* fix zero termination */
2502                 p2 = skip_string(p2,1);
2503
2504                 SSVAL(p,usri11_code_page,0);            /* code page */
2505         }
2506         if (uLevel == 1 || uLevel == 2)
2507         {
2508                 memset(p+22,' ',16);    /* password */
2509                 SIVALS(p,38,-1);                /* password age */
2510                 SSVAL(p,42,
2511                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2512                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2513                 pstrcpy(p2,lp_logon_home());
2514                 standard_sub_conn(conn, p2);
2515                 p2 = skip_string(p2,1);
2516                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2517                 *p2++ = 0;
2518                 SSVAL(p,52,0);          /* flags */
2519                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2520                 pstrcpy(p2,lp_logon_script());
2521                 standard_sub_conn( conn, p2 );             
2522                 p2 = skip_string(p2,1);
2523                 if (uLevel == 2)
2524                 {
2525                         SIVAL(p,60,0);          /* auth_flags */
2526                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2527                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2528                         p2 = skip_string(p2,1);
2529                         SIVAL(p,68,0);          /* urs_comment */
2530                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2531                         pstrcpy(p2,"");
2532                         p2 = skip_string(p2,1);
2533                         SIVAL(p,76,0);          /* workstations */
2534                         SIVAL(p,80,0);          /* last_logon */
2535                         SIVAL(p,84,0);          /* last_logoff */
2536                         SIVALS(p,88,-1);                /* acct_expires */
2537                         SIVALS(p,92,-1);                /* max_storage */
2538                         SSVAL(p,96,168);        /* units_per_week */
2539                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2540                         memset(p2,-1,21);
2541                         p2 += 21;
2542                         SSVALS(p,102,-1);       /* bad_pw_count */
2543                         SSVALS(p,104,-1);       /* num_logons */
2544                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2545                         pstrcpy(p2,"\\\\%L");
2546                         standard_sub_conn(conn, p2);
2547                         p2 = skip_string(p2,1);
2548                         SSVAL(p,110,49);        /* country_code */
2549                         SSVAL(p,112,860);       /* code page */
2550                 }
2551         }
2552
2553         *rdata_len = PTR_DIFF(p2,*rdata);
2554
2555         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2556
2557         return(True);
2558 }
2559
2560 /*******************************************************************
2561   get groups that a user is a member of
2562   ******************************************************************/
2563 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2564                                  int mdrcnt,int mprcnt,
2565                                  char **rdata,char **rparam,
2566                                  int *rdata_len,int *rparam_len)
2567 {
2568   char *str1 = param+2;
2569   char *str2 = skip_string(str1,1);
2570   char *UserName = skip_string(str2,1);
2571   char *p = skip_string(UserName,1);
2572   int uLevel = SVAL(p,0);
2573   char *p2;
2574   int count=0;
2575
2576   *rparam_len = 8;
2577   *rparam = REALLOC(*rparam,*rparam_len);
2578
2579   /* check it's a supported varient */
2580   if (strcmp(str1,"zWrLeh") != 0) return False;
2581   switch( uLevel ) {
2582   case 0: p2 = "B21"; break;
2583   default: return False;
2584   }
2585   if (strcmp(p2,str2) != 0) return False;
2586
2587   *rdata_len = mdrcnt + 1024;
2588   *rdata = REALLOC(*rdata,*rdata_len);
2589
2590   SSVAL(*rparam,0,NERR_Success);
2591   SSVAL(*rparam,2,0);           /* converter word */
2592
2593   p = *rdata;
2594
2595   /* XXXX we need a real SAM database some day */
2596   pstrcpy(p,"Users"); p += 21; count++;
2597   pstrcpy(p,"Domain Users"); p += 21; count++;
2598   pstrcpy(p,"Guests"); p += 21; count++;
2599   pstrcpy(p,"Domain Guests"); p += 21; count++;
2600
2601   *rdata_len = PTR_DIFF(p,*rdata);
2602
2603   SSVAL(*rparam,4,count);       /* is this right?? */
2604   SSVAL(*rparam,6,count);       /* is this right?? */
2605
2606   return(True);
2607 }
2608
2609
2610 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2611                                 int mdrcnt,int mprcnt,
2612                                 char **rdata,char **rparam,
2613                                 int *rdata_len,int *rparam_len)
2614 {
2615   char *str1 = param+2;
2616   char *str2 = skip_string(str1,1);
2617   char *p = skip_string(str2,1);
2618   int uLevel;
2619   struct pack_desc desc;
2620   char* name;
2621
2622   uLevel = SVAL(p,0);
2623   name = p + 2;
2624
2625   memset((char *)&desc,'\0',sizeof(desc));
2626
2627   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2628
2629   /* check it's a supported varient */
2630   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2631   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2632   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2633   desc.base = *rdata;
2634   desc.buflen = mdrcnt;
2635   desc.subformat = NULL;
2636   desc.format = str2;
2637   
2638   if (init_package(&desc,1,0))
2639   {
2640     PACKI(&desc,"W",0);         /* code */
2641     PACKS(&desc,"B21",name);    /* eff. name */
2642     PACKS(&desc,"B","");                /* pad */
2643     PACKI(&desc,"W",
2644           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2645     PACKI(&desc,"D",0);         /* auth flags XXX */
2646     PACKI(&desc,"W",0);         /* num logons */
2647     PACKI(&desc,"W",0);         /* bad pw count */
2648     PACKI(&desc,"D",0);         /* last logon */
2649     PACKI(&desc,"D",-1);                /* last logoff */
2650     PACKI(&desc,"D",-1);                /* logoff time */
2651     PACKI(&desc,"D",-1);                /* kickoff time */
2652     PACKI(&desc,"D",0);         /* password age */
2653     PACKI(&desc,"D",0);         /* password can change */
2654     PACKI(&desc,"D",-1);                /* password must change */
2655     {
2656       fstring mypath;
2657       fstrcpy(mypath,"\\\\");
2658       fstrcat(mypath,local_machine);
2659       strupper(mypath);
2660       PACKS(&desc,"z",mypath); /* computer */
2661     }
2662     PACKS(&desc,"z",global_myworkgroup);/* domain */
2663
2664 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2665 /* made sure all macros are fully substituted and available */
2666     {
2667       pstring logon_script;
2668       pstrcpy(logon_script,lp_logon_script());
2669       standard_sub_conn( conn, logon_script );
2670       PACKS(&desc,"z", logon_script);           /* script path */
2671     }
2672 /* End of JHT mods */
2673
2674     PACKI(&desc,"D",0x00000000);                /* reserved */
2675   }
2676
2677   *rdata_len = desc.usedlen;
2678   *rparam_len = 6;
2679   *rparam = REALLOC(*rparam,*rparam_len);
2680   SSVALS(*rparam,0,desc.errcode);
2681   SSVAL(*rparam,2,0);
2682   SSVAL(*rparam,4,desc.neededlen);
2683
2684   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2685   return(True);
2686 }
2687
2688
2689 /****************************************************************************
2690   api_WAccessGetUserPerms
2691   ****************************************************************************/
2692 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2693                                     int mdrcnt,int mprcnt,
2694                                     char **rdata,char **rparam,
2695                                     int *rdata_len,int *rparam_len)
2696 {
2697   char *str1 = param+2;
2698   char *str2 = skip_string(str1,1);
2699   char *user = skip_string(str2,1);
2700   char *resource = skip_string(user,1);
2701
2702   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2703
2704   /* check it's a supported varient */
2705   if (strcmp(str1,"zzh") != 0) return False;
2706   if (strcmp(str2,"") != 0) return False;
2707
2708   *rparam_len = 6;
2709   *rparam = REALLOC(*rparam,*rparam_len);
2710   SSVALS(*rparam,0,0);          /* errorcode */
2711   SSVAL(*rparam,2,0);           /* converter word */
2712   SSVAL(*rparam,4,0x7f);        /* permission flags */
2713
2714   return(True);
2715 }
2716
2717 /****************************************************************************
2718   api_WPrintJobEnumerate
2719   ****************************************************************************/
2720 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2721                                  int mdrcnt,int mprcnt,
2722                                  char **rdata,char **rparam,
2723                                  int *rdata_len,int *rparam_len)
2724 {
2725   char *str1 = param+2;
2726   char *str2 = skip_string(str1,1);
2727   char *p = skip_string(str2,1);
2728   int uLevel;
2729   int count;
2730   int i;
2731   int snum;
2732   int job;
2733   struct pack_desc desc;
2734   print_queue_struct *queue=NULL;
2735   print_status_struct status;
2736
2737   uLevel = SVAL(p,2);
2738
2739   memset((char *)&desc,'\0',sizeof(desc));
2740   memset((char *)&status,'\0',sizeof(status));
2741
2742   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2743
2744   /* check it's a supported varient */
2745   if (strcmp(str1,"WWrLh") != 0) return False;
2746   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2747
2748   job = SVAL(p,0);
2749   snum = print_job_snum(job);
2750
2751   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2752
2753   count = print_queue_status(snum,&queue,&status);
2754   for (i = 0; i < count; i++) {
2755     if (queue[i].job == job) break;
2756   }
2757   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2758   desc.base = *rdata;
2759   desc.buflen = mdrcnt;
2760
2761   if (init_package(&desc,1,0)) {
2762     if (i < count) {
2763       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2764       *rdata_len = desc.usedlen;
2765     }
2766     else {
2767       desc.errcode = NERR_JobNotFound;
2768       *rdata_len = 0;
2769     }
2770   }
2771
2772   *rparam_len = 6;
2773   *rparam = REALLOC(*rparam,*rparam_len);
2774   SSVALS(*rparam,0,desc.errcode);
2775   SSVAL(*rparam,2,0);
2776   SSVAL(*rparam,4,desc.neededlen);
2777
2778   if (queue) free(queue);
2779
2780   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2781   return(True);
2782 }
2783
2784 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2785                                    int mdrcnt,int mprcnt,
2786                                    char **rdata,char **rparam,
2787                                    int *rdata_len,int *rparam_len)
2788 {
2789   char *str1 = param+2;
2790   char *str2 = skip_string(str1,1);
2791   char *p = skip_string(str2,1);
2792   char* name = p;
2793   int uLevel;
2794   int count;
2795   int i, succnt=0;
2796   int snum;
2797   struct pack_desc desc;
2798   print_queue_struct *queue=NULL;
2799   print_status_struct status;
2800
2801   memset((char *)&desc,'\0',sizeof(desc));
2802   memset((char *)&status,'\0',sizeof(status));
2803
2804   p = skip_string(p,1);
2805   uLevel = SVAL(p,0);
2806
2807   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2808
2809   /* check it's a supported varient */
2810   if (strcmp(str1,"zWrLeh") != 0) return False;
2811   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2812   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2813
2814   snum = lp_servicenumber(name);
2815   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2816     int pnum = lp_servicenumber(PRINTERS_NAME);
2817     if (pnum >= 0) {
2818       lp_add_printer(name,pnum);
2819       snum = lp_servicenumber(name);
2820     }
2821   }
2822
2823   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2824
2825   count = print_queue_status(snum,&queue,&status);
2826   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2827   desc.base = *rdata;
2828   desc.buflen = mdrcnt;
2829
2830   if (init_package(&desc,count,0)) {
2831     succnt = 0;
2832     for (i = 0; i < count; i++) {
2833       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2834       if (desc.errcode == NERR_Success) succnt = i+1;
2835     }
2836   }
2837
2838   *rdata_len = desc.usedlen;
2839
2840   *rparam_len = 8;
2841   *rparam = REALLOC(*rparam,*rparam_len);
2842   SSVALS(*rparam,0,desc.errcode);
2843   SSVAL(*rparam,2,0);
2844   SSVAL(*rparam,4,succnt);
2845   SSVAL(*rparam,6,count);
2846
2847   if (queue) free(queue);
2848
2849   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2850   return(True);
2851 }
2852
2853 static int check_printdest_info(struct pack_desc* desc,
2854                                 int uLevel, char* id)
2855 {
2856   desc->subformat = NULL;
2857   switch( uLevel ) {
2858   case 0: desc->format = "B9"; break;
2859   case 1: desc->format = "B9B21WWzW"; break;
2860   case 2: desc->format = "z"; break;
2861   case 3: desc->format = "zzzWWzzzWW"; break;
2862   default: return False;
2863   }
2864   if (strcmp(desc->format,id) != 0) return False;
2865   return True;
2866 }
2867
2868 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2869                                 struct pack_desc* desc)
2870 {
2871   char buf[100];
2872   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2873   buf[sizeof(buf)-1] = 0;
2874   strupper(buf);
2875   if (uLevel <= 1) {
2876     PACKS(desc,"B9",buf);       /* szName */
2877     if (uLevel == 1) {
2878       PACKS(desc,"B21","");     /* szUserName */
2879       PACKI(desc,"W",0);                /* uJobId */
2880       PACKI(desc,"W",0);                /* fsStatus */
2881       PACKS(desc,"z","");       /* pszStatus */
2882       PACKI(desc,"W",0);                /* time */
2883     }
2884   }
2885   if (uLevel == 2 || uLevel == 3) {
2886     PACKS(desc,"z",buf);                /* pszPrinterName */
2887     if (uLevel == 3) {
2888       PACKS(desc,"z","");       /* pszUserName */
2889       PACKS(desc,"z","");       /* pszLogAddr */
2890       PACKI(desc,"W",0);                /* uJobId */
2891       PACKI(desc,"W",0);                /* fsStatus */
2892       PACKS(desc,"z","");       /* pszStatus */
2893       PACKS(desc,"z","");       /* pszComment */
2894       PACKS(desc,"z","NULL"); /* pszDrivers */
2895       PACKI(desc,"W",0);                /* time */
2896       PACKI(desc,"W",0);                /* pad1 */
2897     }
2898   }
2899 }
2900
2901 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2902                                   int mdrcnt,int mprcnt,
2903                                   char **rdata,char **rparam,
2904                                   int *rdata_len,int *rparam_len)
2905 {
2906   char *str1 = param+2;
2907   char *str2 = skip_string(str1,1);
2908   char *p = skip_string(str2,1);
2909   char* PrinterName = p;
2910   int uLevel;
2911   struct pack_desc desc;
2912   int snum;
2913
2914   memset((char *)&desc,'\0',sizeof(desc));
2915
2916   p = skip_string(p,1);
2917   uLevel = SVAL(p,0);
2918
2919   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2920
2921   /* check it's a supported varient */
2922   if (strcmp(str1,"zWrLh") != 0) return False;
2923   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2924
2925   snum = lp_servicenumber(PrinterName);
2926   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2927     int pnum = lp_servicenumber(PRINTERS_NAME);
2928     if (pnum >= 0) {
2929       lp_add_printer(PrinterName,pnum);
2930       snum = lp_servicenumber(PrinterName);
2931     }
2932   }
2933
2934   if (snum < 0) {
2935     *rdata_len = 0;
2936     desc.errcode = NERR_DestNotFound;
2937     desc.neededlen = 0;
2938   }
2939   else {
2940     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2941     desc.base = *rdata;
2942     desc.buflen = mdrcnt;
2943     if (init_package(&desc,1,0)) {
2944       fill_printdest_info(conn,snum,uLevel,&desc);
2945     }
2946     *rdata_len = desc.usedlen;
2947   }
2948
2949   *rparam_len = 6;
2950   *rparam = REALLOC(*rparam,*rparam_len);
2951   SSVALS(*rparam,0,desc.errcode);
2952   SSVAL(*rparam,2,0);
2953   SSVAL(*rparam,4,desc.neededlen);
2954
2955   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2956   return(True);
2957 }
2958
2959 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2960                                int mdrcnt,int mprcnt,
2961                                char **rdata,char **rparam,
2962                                int *rdata_len,int *rparam_len)
2963 {
2964   char *str1 = param+2;
2965   char *str2 = skip_string(str1,1);
2966   char *p = skip_string(str2,1);
2967   int uLevel;
2968   int queuecnt;
2969   int i, n, succnt=0;
2970   struct pack_desc desc;
2971   int services = lp_numservices();
2972
2973   memset((char *)&desc,'\0',sizeof(desc));
2974
2975   uLevel = SVAL(p,0);
2976
2977   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2978
2979   /* check it's a supported varient */
2980   if (strcmp(str1,"WrLeh") != 0) return False;
2981   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2982
2983   queuecnt = 0;
2984   for (i = 0; i < services; i++)
2985     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2986       queuecnt++;
2987
2988   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2989   desc.base = *rdata;
2990   desc.buflen = mdrcnt;
2991   if (init_package(&desc,queuecnt,0)) {    
2992     succnt = 0;
2993     n = 0;
2994     for (i = 0; i < services; i++) {
2995       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2996         fill_printdest_info(conn,i,uLevel,&desc);
2997         n++;
2998         if (desc.errcode == NERR_Success) succnt = n;
2999       }
3000     }
3001   }
3002
3003   *rdata_len = desc.usedlen;
3004
3005   *rparam_len = 8;
3006   *rparam = REALLOC(*rparam,*rparam_len);
3007   SSVALS(*rparam,0,desc.errcode);
3008   SSVAL(*rparam,2,0);
3009   SSVAL(*rparam,4,succnt);
3010   SSVAL(*rparam,6,queuecnt);
3011
3012   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3013   return(True);
3014 }
3015
3016 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3017                                  int mdrcnt,int mprcnt,
3018                                  char **rdata,char **rparam,
3019                                  int *rdata_len,int *rparam_len)
3020 {
3021   char *str1 = param+2;
3022   char *str2 = skip_string(str1,1);
3023   char *p = skip_string(str2,1);
3024   int uLevel;
3025   int succnt;
3026   struct pack_desc desc;
3027
3028   memset((char *)&desc,'\0',sizeof(desc));
3029
3030   uLevel = SVAL(p,0);
3031
3032   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3033
3034   /* check it's a supported varient */
3035   if (strcmp(str1,"WrLeh") != 0) return False;
3036   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3037
3038   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3039   desc.base = *rdata;
3040   desc.buflen = mdrcnt;
3041   if (init_package(&desc,1,0)) {
3042     PACKS(&desc,"B41","NULL");
3043   }
3044
3045   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3046
3047   *rdata_len = desc.usedlen;
3048
3049   *rparam_len = 8;
3050   *rparam = REALLOC(*rparam,*rparam_len);
3051   SSVALS(*rparam,0,desc.errcode);
3052   SSVAL(*rparam,2,0);
3053   SSVAL(*rparam,4,succnt);
3054   SSVAL(*rparam,6,1);
3055
3056   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3057   return(True);
3058 }
3059
3060 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3061                                 int mdrcnt,int mprcnt,
3062                                 char **rdata,char **rparam,
3063                                 int *rdata_len,int *rparam_len)
3064 {
3065   char *str1 = param+2;
3066   char *str2 = skip_string(str1,1);
3067   char *p = skip_string(str2,1);
3068   int uLevel;
3069   int succnt;
3070   struct pack_desc desc;
3071
3072   memset((char *)&desc,'\0',sizeof(desc));
3073
3074   uLevel = SVAL(p,0);
3075
3076   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3077
3078   /* check it's a supported varient */
3079   if (strcmp(str1,"WrLeh") != 0) return False;
3080   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3081
3082   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3083   desc.base = *rdata;
3084   desc.buflen = mdrcnt;
3085   desc.format = str2;
3086   if (init_package(&desc,1,0)) {
3087     PACKS(&desc,"B13","lpd");
3088   }
3089
3090   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3091
3092   *rdata_len = desc.usedlen;
3093
3094   *rparam_len = 8;
3095   *rparam = REALLOC(*rparam,*rparam_len);
3096   SSVALS(*rparam,0,desc.errcode);
3097   SSVAL(*rparam,2,0);
3098   SSVAL(*rparam,4,succnt);
3099   SSVAL(*rparam,6,1);
3100
3101   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3102   return(True);
3103 }
3104
3105 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3106                                int mdrcnt,int mprcnt,
3107                                char **rdata,char **rparam,
3108                                int *rdata_len,int *rparam_len)
3109 {
3110   char *str1 = param+2;
3111   char *str2 = skip_string(str1,1);
3112   char *p = skip_string(str2,1);
3113   int uLevel;
3114   int succnt;
3115   struct pack_desc desc;
3116
3117   memset((char *)&desc,'\0',sizeof(desc));
3118
3119   uLevel = SVAL(p,0);
3120
3121   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3122
3123   /* check it's a supported varient */
3124   if (strcmp(str1,"WrLeh") != 0) return False;
3125   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3126
3127   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3128   memset((char *)&desc,'\0',sizeof(desc));
3129   desc.base = *rdata;
3130   desc.buflen = mdrcnt;
3131   desc.format = str2;
3132   if (init_package(&desc,1,0)) {
3133     PACKS(&desc,"B13","lp0");
3134   }
3135
3136   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3137
3138   *rdata_len = desc.usedlen;
3139
3140   *rparam_len = 8;
3141   *rparam = REALLOC(*rparam,*rparam_len);
3142   SSVALS(*rparam,0,desc.errcode);
3143   SSVAL(*rparam,2,0);
3144   SSVAL(*rparam,4,succnt);
3145   SSVAL(*rparam,6,1);
3146
3147   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3148   return(True);
3149 }
3150
3151 /****************************************************************************
3152  The buffer was too small
3153  ****************************************************************************/
3154
3155 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3156                          int mdrcnt,int mprcnt,
3157                          char **rdata,char **rparam,
3158                          int *rdata_len,int *rparam_len)
3159 {
3160   *rparam_len = MIN(*rparam_len,mprcnt);
3161   *rparam = REALLOC(*rparam,*rparam_len);
3162
3163   *rdata_len = 0;
3164
3165   SSVAL(*rparam,0,NERR_BufTooSmall);
3166
3167   DEBUG(3,("Supplied buffer too small in API command\n"));
3168
3169   return(True);
3170 }
3171
3172
3173 /****************************************************************************
3174  The request is not supported
3175  ****************************************************************************/
3176
3177 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3178                             int mdrcnt,int mprcnt,
3179                             char **rdata,char **rparam,
3180                             int *rdata_len,int *rparam_len)
3181 {
3182   *rparam_len = 4;
3183   *rparam = REALLOC(*rparam,*rparam_len);
3184
3185   *rdata_len = 0;
3186
3187   SSVAL(*rparam,0,NERR_notsupported);
3188   SSVAL(*rparam,2,0);           /* converter word */
3189
3190   DEBUG(3,("Unsupported API command\n"));
3191
3192   return(True);
3193 }
3194
3195
3196
3197
3198 struct
3199 {
3200   char *name;
3201   int id;
3202   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3203              int,int,char **,char **,int *,int *);
3204   int flags;
3205 } api_commands[] = {
3206   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3207   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3208   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3209   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3210   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3211   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3212   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3213   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3214   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3215   {"WPrintQueuePause",  74, api_WPrintQueueCtrl,0},
3216   {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3217   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3218   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3219   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3220   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3221   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3222   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3223   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3224   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3225   {"WPrintQueuePurge",  103,    api_WPrintQueueCtrl,0},
3226   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3227   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3228   {"SetUserPassword",   115,    api_SetUserPassword,0},
3229   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3230   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3231   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3232   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3233   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3234   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3235   {NULL,                -1,     api_Unsupported,0}};
3236
3237
3238 /****************************************************************************
3239  Handle remote api calls
3240  ****************************************************************************/
3241
3242 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3243                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3244 {
3245   int api_command;
3246   char *rdata = NULL;
3247   char *rparam = NULL;
3248   int rdata_len = 0;
3249   int rparam_len = 0;
3250   BOOL reply=False;
3251   int i;
3252
3253   if (!params) {
3254           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3255           return 0;
3256   }
3257
3258   api_command = SVAL(params,0);
3259
3260   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3261            api_command,
3262            params+2,
3263            skip_string(params+2,1),
3264            tdscnt,tpscnt,mdrcnt,mprcnt));
3265
3266   for (i=0;api_commands[i].name;i++) {
3267     if (api_commands[i].id == api_command && api_commands[i].fn) {
3268         DEBUG(3,("Doing %s\n",api_commands[i].name));
3269         break;
3270     }
3271   }
3272
3273   rdata = (char *)malloc(1024);
3274   if (rdata)
3275     memset(rdata,'\0',1024);
3276
3277   rparam = (char *)malloc(1024);
3278   if (rparam)
3279     memset(rparam,'\0',1024);
3280
3281   if(!rdata || !rparam) {
3282     DEBUG(0,("api_reply: malloc fail !\n"));
3283     return -1;
3284   }
3285
3286   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3287                              &rdata,&rparam,&rdata_len,&rparam_len);
3288
3289
3290   if (rdata_len > mdrcnt ||
3291       rparam_len > mprcnt) {
3292       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3293                            &rdata,&rparam,&rdata_len,&rparam_len);
3294   }
3295
3296   /* if we get False back then it's actually unsupported */
3297   if (!reply)
3298     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3299                     &rdata,&rparam,&rdata_len,&rparam_len);
3300
3301   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3302
3303   if (rdata )
3304     free(rdata);
3305   if (rparam)
3306     free(rparam);
3307   
3308   return -1;
3309 }
3310
3311
3312 #undef OLD_NTDOMAIN