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