include/vfs.h:
[nivanova/samba-autobuild/.git] / source3 / smbd / lanman.c
1 #define OLD_NTDOMAIN 1
2 /* 
3    Unix SMB/Netbios implementation.
4    Version 1.9.
5    Inter-process communication and named pipe handling
6    Copyright (C) Andrew Tridgell 1992-1998
7
8    SMB Version handling
9    Copyright (C) John H Terpstra 1995-1998
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24    */
25 /*
26    This file handles the named pipe and mailslot calls
27    in the SMBtrans protocol
28    */
29
30 #include "includes.h"
31
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
36
37 extern int DEBUGLEVEL;
38
39 extern fstring local_machine;
40 extern pstring global_myname;
41 extern fstring global_myworkgroup;
42
43 #define NERR_Success 0
44 #define NERR_badpass 86
45 #define NERR_notsupported 50
46
47 #define NERR_BASE (2100)
48 #define NERR_BufTooSmall (NERR_BASE+23)
49 #define NERR_JobNotFound (NERR_BASE+51)
50 #define NERR_DestNotFound (NERR_BASE+52)
51
52 #define ACCESS_READ 0x01
53 #define ACCESS_WRITE 0x02
54 #define ACCESS_CREATE 0x04
55
56 #define SHPWLEN 8               /* share password length */
57
58 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
59                             int mdrcnt,int mprcnt,
60                             char **rdata,char **rparam,
61                             int *rdata_len,int *rparam_len);
62 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
63                          int mdrcnt,int mprcnt,
64                          char **rdata,char **rparam,
65                          int *rdata_len,int *rparam_len);
66
67
68 static int CopyExpanded(connection_struct *conn, 
69                         int snum, char** dst, char* src, int* n)
70 {
71         pstring buf;
72         int l;
73
74         if (!src || !dst || !n || !(*dst)) return(0);
75
76         StrnCpy(buf,src,sizeof(buf)/2);
77         pstring_sub(buf,"%S",lp_servicename(snum));
78         standard_sub_conn(conn,buf);
79         StrnCpy(*dst,buf,*n-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   qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1345
1346   {
1347     char *lastname=NULL;
1348
1349     for (i=0;i<total;i++)
1350     {
1351       struct srv_info_struct *s = &servers[i];
1352       if (lastname && strequal(lastname,s->name)) continue;
1353       lastname = s->name;
1354       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1355       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1356                s->name, s->type, s->comment, s->domain));
1357       
1358       if (data_len <= buf_len) {
1359           counted++;
1360           fixed_len += f_len;
1361           string_len += s_len;
1362       } else {
1363         missed++;
1364       }
1365     }
1366   }
1367
1368   *rdata_len = fixed_len + string_len;
1369   *rdata = REALLOC(*rdata,*rdata_len);
1370   memset(*rdata,'\0',*rdata_len);
1371   
1372   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1373   p = *rdata;
1374   f_len = fixed_len;
1375   s_len = string_len;
1376
1377   {
1378     char *lastname=NULL;
1379     int count2 = counted;
1380     for (i = 0; i < total && count2;i++)
1381       {
1382         struct srv_info_struct *s = &servers[i];
1383         if (lastname && strequal(lastname,s->name)) continue;
1384         lastname = s->name;
1385         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1386         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1387                  s->name, s->type, s->comment, s->domain));
1388         count2--;
1389       }
1390   }
1391   
1392   *rparam_len = 8;
1393   *rparam = REALLOC(*rparam,*rparam_len);
1394   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1395   SSVAL(*rparam,2,0);
1396   SSVAL(*rparam,4,counted);
1397   SSVAL(*rparam,6,counted+missed);
1398
1399   if (servers) free(servers);
1400
1401   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1402            domain,uLevel,counted,counted+missed));
1403
1404   return(True);
1405 }
1406
1407 /****************************************************************************
1408   command 0x34 - suspected of being a "Lookup Names" stub api
1409   ****************************************************************************/
1410 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1411                                int mdrcnt, int mprcnt, char **rdata, 
1412                                char **rparam, int *rdata_len, int *rparam_len)
1413 {
1414   char *str1 = param+2;
1415   char *str2 = skip_string(str1,1);
1416   char *p = skip_string(str2,1);
1417   int uLevel = SVAL(p,0);
1418   int buf_len = SVAL(p,2);
1419   int counted=0;
1420   int missed=0;
1421
1422         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1423                 str1, str2, p, uLevel, buf_len));
1424
1425   if (!prefix_ok(str1,"zWrLeh")) return False;
1426   
1427   *rdata_len = 0;
1428   
1429   *rparam_len = 8;
1430   *rparam = REALLOC(*rparam,*rparam_len);
1431
1432   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1433   SSVAL(*rparam,2,0);
1434   SSVAL(*rparam,4,counted);
1435   SSVAL(*rparam,6,counted+missed);
1436
1437   return(True);
1438 }
1439
1440 /****************************************************************************
1441   get info about a share
1442   ****************************************************************************/
1443 static BOOL check_share_info(int uLevel, char* id)
1444 {
1445   switch( uLevel ) {
1446   case 0:
1447     if (strcmp(id,"B13") != 0) return False;
1448     break;
1449   case 1:
1450     if (strcmp(id,"B13BWz") != 0) return False;
1451     break;
1452   case 2:
1453     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1454     break;
1455   case 91:
1456     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1457     break;
1458   default: return False;
1459   }
1460   return True;
1461 }
1462
1463 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1464                            char** buf, int* buflen,
1465                            char** stringbuf, int* stringspace, char* baseaddr)
1466 {
1467   int struct_len;
1468   char* p;
1469   char* p2;
1470   int l2;
1471   int len;
1472  
1473   switch( uLevel ) {
1474   case 0: struct_len = 13; break;
1475   case 1: struct_len = 20; break;
1476   case 2: struct_len = 40; break;
1477   case 91: struct_len = 68; break;
1478   default: return -1;
1479   }
1480   
1481  
1482   if (!buf)
1483     {
1484       len = 0;
1485       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1486       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1487       if (buflen) *buflen = struct_len;
1488       if (stringspace) *stringspace = len;
1489       return struct_len + len;
1490     }
1491   
1492   len = struct_len;
1493   p = *buf;
1494   if ((*buflen) < struct_len) return -1;
1495   if (stringbuf)
1496     {
1497       p2 = *stringbuf;
1498       l2 = *stringspace;
1499     }
1500   else
1501     {
1502       p2 = p + struct_len;
1503       l2 = (*buflen) - struct_len;
1504     }
1505   if (!baseaddr) baseaddr = p;
1506   
1507   StrnCpy(p,lp_servicename(snum),13);
1508   
1509   if (uLevel > 0)
1510     {
1511       int type;
1512       CVAL(p,13) = 0;
1513       type = STYPE_DISKTREE;
1514       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1515       if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1516       SSVAL(p,14,type);         /* device type */
1517       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1518       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1519     }
1520   
1521   if (uLevel > 1)
1522     {
1523       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1524       SSVALS(p,22,-1);          /* max uses */
1525       SSVAL(p,24,1); /* current uses */
1526       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1527       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1528       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1529     }
1530   
1531   if (uLevel > 2)
1532     {
1533       memset(p+40,0,SHPWLEN+2);
1534       SSVAL(p,50,0);
1535       SIVAL(p,52,0);
1536       SSVAL(p,56,0);
1537       SSVAL(p,58,0);
1538       SIVAL(p,60,0);
1539       SSVAL(p,64,0);
1540       SSVAL(p,66,0);
1541     }
1542        
1543   if (stringbuf)
1544     {
1545       (*buf) = p + struct_len;
1546       (*buflen) -= struct_len;
1547       (*stringbuf) = p2;
1548       (*stringspace) = l2;
1549     }
1550   else
1551     {
1552       (*buf) = p2;
1553       (*buflen) -= len;
1554     }
1555   return len;
1556 }
1557
1558 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1559                                  int mdrcnt,int mprcnt,
1560                                  char **rdata,char **rparam,
1561                                  int *rdata_len,int *rparam_len)
1562 {
1563   char *str1 = param+2;
1564   char *str2 = skip_string(str1,1);
1565   char *netname = skip_string(str2,1);
1566   char *p = skip_string(netname,1);
1567   int uLevel = SVAL(p,0);
1568   int snum = find_service(netname);
1569   
1570   if (snum < 0) return False;
1571   
1572   /* check it's a supported varient */
1573   if (!prefix_ok(str1,"zWrLh")) return False;
1574   if (!check_share_info(uLevel,str2)) return False;
1575  
1576   *rdata = REALLOC(*rdata,mdrcnt);
1577   p = *rdata;
1578   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1579   if (*rdata_len < 0) return False;
1580  
1581   *rparam_len = 6;
1582   *rparam = REALLOC(*rparam,*rparam_len);
1583   SSVAL(*rparam,0,NERR_Success);
1584   SSVAL(*rparam,2,0);           /* converter word */
1585   SSVAL(*rparam,4,*rdata_len);
1586  
1587   return(True);
1588 }
1589
1590 /****************************************************************************
1591   view list of shares available
1592   ****************************************************************************/
1593 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1594                               int mdrcnt,int mprcnt,
1595                               char **rdata,char **rparam,
1596                               int *rdata_len,int *rparam_len)
1597 {
1598   char *str1 = param+2;
1599   char *str2 = skip_string(str1,1);
1600   char *p = skip_string(str2,1);
1601   int uLevel = SVAL(p,0);
1602   int buf_len = SVAL(p,2);
1603   char *p2;
1604   int count=lp_numservices();
1605   int total=0,counted=0;
1606   BOOL missed = False;
1607   int i;
1608   int data_len, fixed_len, string_len;
1609   int f_len = 0, s_len = 0;
1610  
1611   if (!prefix_ok(str1,"WrLeh")) return False;
1612   if (!check_share_info(uLevel,str2)) return False;
1613   
1614   data_len = fixed_len = string_len = 0;
1615   for (i=0;i<count;i++)
1616     if (lp_browseable(i) && lp_snum_ok(i))
1617     {
1618       total++;
1619       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1620       if (data_len <= buf_len)
1621       {
1622         counted++;
1623         fixed_len += f_len;
1624         string_len += s_len;
1625       }
1626       else
1627         missed = True;
1628     }
1629   *rdata_len = fixed_len + string_len;
1630   *rdata = REALLOC(*rdata,*rdata_len);
1631   memset(*rdata,0,*rdata_len);
1632   
1633   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1634   p = *rdata;
1635   f_len = fixed_len;
1636   s_len = string_len;
1637   for (i = 0; i < count;i++)
1638     if (lp_browseable(i) && lp_snum_ok(i))
1639       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1640         break;
1641   
1642   *rparam_len = 8;
1643   *rparam = REALLOC(*rparam,*rparam_len);
1644   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1645   SSVAL(*rparam,2,0);
1646   SSVAL(*rparam,4,counted);
1647   SSVAL(*rparam,6,total);
1648   
1649   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1650            counted,total,uLevel,
1651            buf_len,*rdata_len,mdrcnt));
1652   return(True);
1653 }
1654
1655
1656
1657 /****************************************************************************
1658   get the time of day info
1659   ****************************************************************************/
1660 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1661                              int mdrcnt,int mprcnt,
1662                              char **rdata,char **rparam,
1663                              int *rdata_len,int *rparam_len)
1664 {
1665   char *p;
1666   *rparam_len = 4;
1667   *rparam = REALLOC(*rparam,*rparam_len);
1668
1669   *rdata_len = 21;
1670   *rdata = REALLOC(*rdata,*rdata_len);
1671
1672   SSVAL(*rparam,0,NERR_Success);
1673   SSVAL(*rparam,2,0);           /* converter word */
1674
1675   p = *rdata;
1676
1677   {
1678     struct tm *t;
1679     time_t unixdate = time(NULL);
1680
1681     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1682                                     by NT in a "net time" operation,
1683                                     it seems to ignore the one below */
1684
1685     /* the client expects to get localtime, not GMT, in this bit 
1686        (I think, this needs testing) */
1687     t = LocalTime(&unixdate);
1688
1689     SIVAL(p,4,0);               /* msecs ? */
1690     CVAL(p,8) = t->tm_hour;
1691     CVAL(p,9) = t->tm_min;
1692     CVAL(p,10) = t->tm_sec;
1693     CVAL(p,11) = 0;             /* hundredths of seconds */
1694     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1695     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1696     CVAL(p,16) = t->tm_mday;
1697     CVAL(p,17) = t->tm_mon + 1;
1698     SSVAL(p,18,1900+t->tm_year);
1699     CVAL(p,20) = t->tm_wday;
1700   }
1701
1702
1703   return(True);
1704 }
1705
1706 /****************************************************************************
1707  Set the user password.
1708 *****************************************************************************/
1709
1710 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1711                                 int mdrcnt,int mprcnt,
1712                                 char **rdata,char **rparam,
1713                                 int *rdata_len,int *rparam_len)
1714 {
1715   char *p = skip_string(param+2,2);
1716   fstring user;
1717   fstring pass1,pass2;
1718
1719   fstrcpy(user,p);
1720
1721   p = skip_string(p,1);
1722
1723   memset(pass1,'\0',sizeof(pass1));
1724   memset(pass2,'\0',sizeof(pass2));
1725   memcpy(pass1,p,16);
1726   memcpy(pass2,p+16,16);
1727
1728   *rparam_len = 4;
1729   *rparam = REALLOC(*rparam,*rparam_len);
1730
1731   *rdata_len = 0;
1732
1733   SSVAL(*rparam,0,NERR_badpass);
1734   SSVAL(*rparam,2,0);           /* converter word */
1735
1736   DEBUG(3,("Set password for <%s>\n",user));
1737
1738   /*
1739    * Pass the user through the NT -> unix user mapping
1740    * function.
1741    */
1742
1743   (void)map_username(user);
1744
1745   /*
1746    * Do any UNIX username case mangling.
1747    */
1748   (void)Get_Pwnam( user, True);
1749
1750   /*
1751    * Attempt to verify the old password against smbpasswd entries
1752    * Win98 clients send old and new password in plaintext for this call.
1753    */
1754
1755   {
1756     fstring saved_pass2;
1757     SAM_ACCOUNT *sampass;
1758
1759     /*
1760      * Save the new password as change_oem_password overwrites it
1761      * with zeros.
1762      */
1763
1764     fstrcpy(saved_pass2, pass2);
1765
1766     if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1767         change_oem_password(sampass,pass2,False))
1768     {
1769       SSVAL(*rparam,0,NERR_Success);
1770
1771       /*
1772        * If unix password sync was requested, attempt to change
1773        * the /etc/passwd database also. Return failure if this cannot
1774        * be done.
1775        */
1776
1777       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1778         SSVAL(*rparam,0,NERR_badpass);
1779     }
1780   }
1781
1782   /*
1783    * If the above failed, attempt the plaintext password change.
1784    * This tests against the /etc/passwd database only.
1785    */
1786
1787   if(SVAL(*rparam,0) != NERR_Success)
1788   {
1789     if (password_ok(user, pass1,strlen(pass1),NULL) &&
1790         chgpasswd(user,pass1,pass2,False))
1791     {
1792       SSVAL(*rparam,0,NERR_Success);
1793     }
1794   }
1795
1796   /*
1797    * If the plaintext change failed, attempt
1798    * the old encrypted method. NT will generate this
1799    * after trying the samr method. Note that this
1800    * method is done as a last resort as this
1801    * password change method loses the NT password hash
1802    * and cannot change the UNIX password as no plaintext
1803    * is received.
1804    */
1805
1806   if(SVAL(*rparam,0) != NERR_Success)
1807   {
1808     SAM_ACCOUNT *hnd = NULL;
1809
1810     if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
1811        change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1812     {
1813       SSVAL(*rparam,0,NERR_Success);
1814     }
1815   }
1816
1817   memset((char *)pass1,'\0',sizeof(fstring));
1818   memset((char *)pass2,'\0',sizeof(fstring));    
1819          
1820   return(True);
1821 }
1822
1823 /****************************************************************************
1824   Set the user password (SamOEM version - gets plaintext).
1825 ****************************************************************************/
1826
1827 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1828                                 int mdrcnt,int mprcnt,
1829                                 char **rdata,char **rparam,
1830                                 int *rdata_len,int *rparam_len)
1831 {
1832   fstring user;
1833   char *p = param + 2;
1834   *rparam_len = 2;
1835   *rparam = REALLOC(*rparam,*rparam_len);
1836
1837   *rdata_len = 0;
1838
1839   SSVAL(*rparam,0,NERR_badpass);
1840
1841   /*
1842    * Check the parameter definition is correct.
1843    */
1844   if(!strequal(param + 2, "zsT")) {
1845     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1846     return False;
1847   }
1848   p = skip_string(p, 1);
1849
1850   if(!strequal(p, "B516B16")) {
1851     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1852     return False;
1853   }
1854   p = skip_string(p,1);
1855
1856   fstrcpy(user,p);
1857   p = skip_string(p,1);
1858
1859   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1860
1861   /*
1862    * Pass the user through the NT -> unix user mapping
1863    * function.
1864    */
1865
1866   (void)map_username(user);
1867
1868   /*
1869    * Do any UNIX username case mangling.
1870    */
1871   (void)Get_Pwnam( user, True);
1872
1873   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1874   {
1875     SSVAL(*rparam,0,NERR_Success);
1876   }
1877
1878   return(True);
1879 }
1880
1881 /****************************************************************************
1882   delete a print job
1883   Form: <W> <> 
1884   ****************************************************************************/
1885 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1886                                 int mdrcnt,int mprcnt,
1887                                 char **rdata,char **rparam,
1888                                 int *rdata_len,int *rparam_len)
1889 {
1890         int function = SVAL(param,0);
1891         char *str1 = param+2;
1892         char *str2 = skip_string(str1,1);
1893         char *p = skip_string(str2,1);
1894         int jobid, errcode;
1895         extern struct current_user current_user;
1896
1897         jobid = SVAL(p,0);
1898
1899         /* check it's a supported varient */
1900         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1901                 return(False);
1902
1903         *rparam_len = 4;
1904         *rparam = REALLOC(*rparam,*rparam_len); 
1905         *rdata_len = 0;
1906
1907         if (!print_job_exists(jobid)) {
1908                 errcode = NERR_JobNotFound;
1909                 goto out;
1910         }
1911
1912         errcode = NERR_notsupported;
1913         
1914         switch (function) {
1915         case 81:                /* delete */ 
1916                 if (print_job_delete(&current_user, jobid, &errcode)) 
1917                         errcode = NERR_Success;
1918                 break;
1919         case 82:                /* pause */
1920                 if (print_job_pause(&current_user, jobid, &errcode)) 
1921                         errcode = NERR_Success;
1922                 break;
1923         case 83:                /* resume */
1924                 if (print_job_resume(&current_user, jobid, &errcode)) 
1925                         errcode = NERR_Success;
1926                 break;
1927         }
1928         
1929  out:
1930         SSVAL(*rparam,0,errcode);       
1931         SSVAL(*rparam,2,0);             /* converter word */
1932
1933         return(True);
1934 }
1935
1936 /****************************************************************************
1937   Purge a print queue - or pause or resume it.
1938   ****************************************************************************/
1939 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1940                                  int mdrcnt,int mprcnt,
1941                                  char **rdata,char **rparam,
1942                                  int *rdata_len,int *rparam_len)
1943 {
1944         int function = SVAL(param,0);
1945         char *str1 = param+2;
1946         char *str2 = skip_string(str1,1);
1947         char *QueueName = skip_string(str2,1);
1948         int errcode = NERR_notsupported;
1949         int snum;
1950         extern struct current_user current_user;
1951
1952         /* check it's a supported varient */
1953         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1954                 return(False);
1955
1956         *rparam_len = 4;
1957         *rparam = REALLOC(*rparam,*rparam_len);
1958         *rdata_len = 0;
1959
1960         snum = print_queue_snum(QueueName);
1961
1962         if (snum == -1) {
1963                 errcode = NERR_JobNotFound;
1964                 goto out;
1965         }
1966
1967         switch (function) {
1968         case 74: /* Pause queue */
1969                 if (print_queue_pause(&current_user, snum, &errcode)) errcode = NERR_Success;
1970                 break;
1971         case 75: /* Resume queue */
1972                 if (print_queue_resume(&current_user, snum, &errcode)) errcode = NERR_Success;
1973                 break;
1974         case 103: /* Purge */
1975                 if (print_queue_purge(&current_user, snum, &errcode)) errcode = NERR_Success;
1976                 break;
1977         }
1978
1979  out:
1980         SSVAL(*rparam,0,errcode);
1981         SSVAL(*rparam,2,0);             /* converter word */
1982
1983         return(True);
1984 }
1985
1986
1987 /****************************************************************************
1988   set the property of a print job (undocumented?)
1989   ? function = 0xb -> set name of print job
1990   ? function = 0x6 -> move print job up/down
1991   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1992   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1993 ****************************************************************************/
1994 static int check_printjob_info(struct pack_desc* desc,
1995                                int uLevel, char* id)
1996 {
1997         desc->subformat = NULL;
1998         switch( uLevel ) {
1999         case 0: desc->format = "W"; break;
2000         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2001         case 2: desc->format = "WWzWWDDzz"; break;
2002         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2003         default: return False;
2004         }
2005         if (strcmp(desc->format,id) != 0) return False;
2006         return True;
2007 }
2008
2009 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2010                              int mdrcnt,int mprcnt,
2011                              char **rdata,char **rparam,
2012                              int *rdata_len,int *rparam_len)
2013 {
2014         struct pack_desc desc;
2015         char *str1 = param+2;
2016         char *str2 = skip_string(str1,1);
2017         char *p = skip_string(str2,1);
2018         int jobid;
2019         int uLevel = SVAL(p,2);
2020         int function = SVAL(p,4);
2021         int place, errcode;
2022
2023         jobid = SVAL(p,0);
2024         *rparam_len = 4;
2025         *rparam = REALLOC(*rparam,*rparam_len);
2026   
2027         *rdata_len = 0;
2028         
2029         /* check it's a supported varient */
2030         if ((strcmp(str1,"WWsTP")) || 
2031             (!check_printjob_info(&desc,uLevel,str2)))
2032                 return(False);
2033
2034         if (!print_job_exists(jobid)) {
2035                 errcode=NERR_JobNotFound;
2036                 goto out;
2037         }
2038
2039         errcode = NERR_notsupported;
2040
2041         switch (function) {
2042         case 0x6:
2043                 /* change job place in the queue, 
2044                    data gives the new place */
2045                 place = SVAL(data,0);
2046                 if (print_job_set_place(jobid, place)) {
2047                         errcode=NERR_Success;
2048                 }
2049                 break;
2050
2051         case 0xb:   
2052                 /* change print job name, data gives the name */
2053                 if (print_job_set_name(jobid, data)) {
2054                         errcode=NERR_Success;
2055                 }
2056                 break;
2057
2058         default:
2059                 return False;
2060         }
2061
2062  out:
2063         SSVALS(*rparam,0,errcode);
2064         SSVAL(*rparam,2,0);             /* converter word */
2065         
2066         return(True);
2067 }
2068
2069
2070 /****************************************************************************
2071   get info about the server
2072   ****************************************************************************/
2073 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2074                                   int mdrcnt,int mprcnt,
2075                                   char **rdata,char **rparam,
2076                                   int *rdata_len,int *rparam_len)
2077 {
2078   char *str1 = param+2;
2079   char *str2 = skip_string(str1,1);
2080   char *p = skip_string(str2,1);
2081   int uLevel = SVAL(p,0);
2082   char *p2;
2083   int struct_len;
2084
2085   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2086
2087   /* check it's a supported varient */
2088   if (!prefix_ok(str1,"WrLh")) return False;
2089   switch( uLevel ) {
2090   case 0:
2091     if (strcmp(str2,"B16") != 0) return False;
2092     struct_len = 16;
2093     break;
2094   case 1:
2095     if (strcmp(str2,"B16BBDz") != 0) return False;
2096     struct_len = 26;
2097     break;
2098   case 2:
2099     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2100         != 0) return False;
2101     struct_len = 134;
2102     break;
2103   case 3:
2104     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2105         != 0) return False;
2106     struct_len = 144;
2107     break;
2108   case 20:
2109     if (strcmp(str2,"DN") != 0) return False;
2110     struct_len = 6;
2111     break;
2112   case 50:
2113     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2114     struct_len = 42;
2115     break;
2116   default: return False;
2117   }
2118
2119   *rdata_len = mdrcnt;
2120   *rdata = REALLOC(*rdata,*rdata_len);
2121
2122   p = *rdata;
2123   p2 = p + struct_len;
2124   if (uLevel != 20) {
2125     StrnCpy(p,local_machine,16);
2126     strupper(p);
2127   }
2128   p += 16;
2129   if (uLevel > 0)
2130     {
2131       struct srv_info_struct *servers=NULL;
2132       int i,count;
2133       pstring comment;
2134       uint32 servertype= lp_default_server_announce();
2135
2136       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2137
2138       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2139         for (i=0;i<count;i++)
2140           if (strequal(servers[i].name,local_machine))
2141       {
2142             servertype = servers[i].type;
2143             pstrcpy(comment,servers[i].comment);            
2144           }
2145       }
2146       if (servers) free(servers);
2147
2148       SCVAL(p,0,lp_major_announce_version());
2149       SCVAL(p,1,lp_minor_announce_version());
2150       SIVAL(p,2,servertype);
2151
2152       if (mdrcnt == struct_len) {
2153         SIVAL(p,6,0);
2154       } else {
2155         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2156         standard_sub_conn(conn,comment);
2157         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2158         p2 = skip_string(p2,1);
2159       }
2160     }
2161   if (uLevel > 1)
2162     {
2163       return False;             /* not yet implemented */
2164     }
2165
2166   *rdata_len = PTR_DIFF(p2,*rdata);
2167
2168   *rparam_len = 6;
2169   *rparam = REALLOC(*rparam,*rparam_len);
2170   SSVAL(*rparam,0,NERR_Success);
2171   SSVAL(*rparam,2,0);           /* converter word */
2172   SSVAL(*rparam,4,*rdata_len);
2173
2174   return(True);
2175 }
2176
2177
2178 /****************************************************************************
2179   get info about the server
2180   ****************************************************************************/
2181 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2182                                 int mdrcnt,int mprcnt,
2183                                 char **rdata,char **rparam,
2184                                 int *rdata_len,int *rparam_len)
2185 {
2186   char *str1 = param+2;
2187   char *str2 = skip_string(str1,1);
2188   char *p = skip_string(str2,1);
2189   char *p2;
2190   extern userdom_struct current_user_info;
2191   int level = SVAL(p,0);
2192
2193   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2194
2195   *rparam_len = 6;
2196   *rparam = REALLOC(*rparam,*rparam_len);
2197
2198   /* check it's a supported varient */
2199   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2200     return(False);
2201
2202   *rdata_len = mdrcnt + 1024;
2203   *rdata = REALLOC(*rdata,*rdata_len);
2204
2205   SSVAL(*rparam,0,NERR_Success);
2206   SSVAL(*rparam,2,0);           /* converter word */
2207
2208   p = *rdata;
2209   p2 = p + 22;
2210
2211
2212   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2213   pstrcpy(p2,local_machine);
2214   strupper(p2);
2215   p2 = skip_string(p2,1);
2216   p += 4;
2217
2218   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2219   pstrcpy(p2,current_user_info.smb_name);
2220   p2 = skip_string(p2,1);
2221   p += 4;
2222
2223   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2224   pstrcpy(p2,global_myworkgroup);
2225   strupper(p2);
2226   p2 = skip_string(p2,1);
2227   p += 4;
2228
2229   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2230   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2231   p += 2;
2232
2233   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2234   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2235   p2 = skip_string(p2,1);
2236   p += 4;
2237
2238   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2239   pstrcpy(p2,"");
2240   p2 = skip_string(p2,1);
2241   p += 4;
2242
2243   *rdata_len = PTR_DIFF(p2,*rdata);
2244
2245   SSVAL(*rparam,4,*rdata_len);
2246
2247   return(True);
2248 }
2249
2250 /****************************************************************************
2251   get info about a user
2252
2253     struct user_info_11 {
2254         char                usri11_name[21];  0-20 
2255         char                usri11_pad;       21 
2256         char                *usri11_comment;  22-25 
2257         char            *usri11_usr_comment;  26-29
2258         unsigned short      usri11_priv;      30-31
2259         unsigned long       usri11_auth_flags; 32-35
2260         long                usri11_password_age; 36-39
2261         char                *usri11_homedir; 40-43
2262         char            *usri11_parms; 44-47
2263         long                usri11_last_logon; 48-51
2264         long                usri11_last_logoff; 52-55
2265         unsigned short      usri11_bad_pw_count; 56-57
2266         unsigned short      usri11_num_logons; 58-59
2267         char                *usri11_logon_server; 60-63
2268         unsigned short      usri11_country_code; 64-65
2269         char            *usri11_workstations; 66-69
2270         unsigned long       usri11_max_storage; 70-73
2271         unsigned short      usri11_units_per_week; 74-75
2272         unsigned char       *usri11_logon_hours; 76-79
2273         unsigned short      usri11_code_page; 80-81
2274     };
2275
2276 where:
2277
2278   usri11_name specifies the user name for which information is retireved
2279
2280   usri11_pad aligns the next data structure element to a word boundary
2281
2282   usri11_comment is a null terminated ASCII comment
2283
2284   usri11_user_comment is a null terminated ASCII comment about the user
2285
2286   usri11_priv specifies the level of the privilege assigned to the user.
2287        The possible values are:
2288
2289 Name             Value  Description
2290 USER_PRIV_GUEST  0      Guest privilege
2291 USER_PRIV_USER   1      User privilege
2292 USER_PRV_ADMIN   2      Administrator privilege
2293
2294   usri11_auth_flags specifies the account operator privileges. The
2295        possible values are:
2296
2297 Name            Value   Description
2298 AF_OP_PRINT     0       Print operator
2299
2300
2301 Leach, Naik                                        [Page 28]
2302 \f
2303
2304
2305 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2306
2307
2308 AF_OP_COMM      1       Communications operator
2309 AF_OP_SERVER    2       Server operator
2310 AF_OP_ACCOUNTS  3       Accounts operator
2311
2312
2313   usri11_password_age specifies how many seconds have elapsed since the
2314        password was last changed.
2315
2316   usri11_home_dir points to a null terminated ASCII string that contains
2317        the path name of the user's home directory.
2318
2319   usri11_parms points to a null terminated ASCII string that is set
2320        aside for use by applications.
2321
2322   usri11_last_logon specifies the time when the user last logged on.
2323        This value is stored as the number of seconds elapsed since
2324        00:00:00, January 1, 1970.
2325
2326   usri11_last_logoff specifies the time when the user last logged off.
2327        This value is stored as the number of seconds elapsed since
2328        00:00:00, January 1, 1970. A value of 0 means the last logoff
2329        time is unknown.
2330
2331   usri11_bad_pw_count specifies the number of incorrect passwords
2332        entered since the last successful logon.
2333
2334   usri11_log1_num_logons specifies the number of times this user has
2335        logged on. A value of -1 means the number of logons is unknown.
2336
2337   usri11_logon_server points to a null terminated ASCII string that
2338        contains the name of the server to which logon requests are sent.
2339        A null string indicates logon requests should be sent to the
2340        domain controller.
2341
2342   usri11_country_code specifies the country code for the user's language
2343        of choice.
2344
2345   usri11_workstations points to a null terminated ASCII string that
2346        contains the names of workstations the user may log on from.
2347        There may be up to 8 workstations, with the names separated by
2348        commas. A null strings indicates there are no restrictions.
2349
2350   usri11_max_storage specifies the maximum amount of disk space the user
2351        can occupy. A value of 0xffffffff indicates there are no
2352        restrictions.
2353
2354   usri11_units_per_week specifies the equal number of time units into
2355        which a week is divided. This value must be equal to 168.
2356
2357   usri11_logon_hours points to a 21 byte (168 bits) string that
2358        specifies the time during which the user can log on. Each bit
2359        represents one unique hour in a week. The first bit (bit 0, word
2360        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2361
2362
2363
2364 Leach, Naik                                        [Page 29]
2365 \f
2366
2367
2368 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2369
2370
2371        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2372        are no restrictions.
2373
2374   usri11_code_page specifies the code page for the user's language of
2375        choice
2376
2377 All of the pointers in this data structure need to be treated
2378 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2379 to be ignored. The converter word returned in the parameters section
2380 needs to be subtracted from the lower 16 bits to calculate an offset
2381 into the return buffer where this ASCII string resides.
2382
2383 There is no auxiliary data in the response.
2384
2385   ****************************************************************************/
2386
2387 #define usri11_name           0 
2388 #define usri11_pad            21
2389 #define usri11_comment        22
2390 #define usri11_usr_comment    26
2391 #define usri11_full_name      30
2392 #define usri11_priv           34
2393 #define usri11_auth_flags     36
2394 #define usri11_password_age   40
2395 #define usri11_homedir        44
2396 #define usri11_parms          48
2397 #define usri11_last_logon     52
2398 #define usri11_last_logoff    56
2399 #define usri11_bad_pw_count   60
2400 #define usri11_num_logons     62
2401 #define usri11_logon_server   64
2402 #define usri11_country_code   68
2403 #define usri11_workstations   70
2404 #define usri11_max_storage    74
2405 #define usri11_units_per_week 78
2406 #define usri11_logon_hours    80
2407 #define usri11_code_page      84
2408 #define usri11_end            86
2409
2410 #define USER_PRIV_GUEST 0
2411 #define USER_PRIV_USER 1
2412 #define USER_PRIV_ADMIN 2
2413
2414 #define AF_OP_PRINT     0 
2415 #define AF_OP_COMM      1
2416 #define AF_OP_SERVER    2
2417 #define AF_OP_ACCOUNTS  3
2418
2419
2420 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2421                                 int mdrcnt,int mprcnt,
2422                                 char **rdata,char **rparam,
2423                                 int *rdata_len,int *rparam_len)
2424 {
2425         char *str1 = param+2;
2426         char *str2 = skip_string(str1,1);
2427         char *UserName = skip_string(str2,1);
2428         char *p = skip_string(UserName,1);
2429         int uLevel = SVAL(p,0);
2430         char *p2;
2431
2432     /* get NIS home of a previously validated user - simeon */
2433     /* With share level security vuid will always be zero.
2434        Don't depend on vuser being non-null !!. JRA */
2435     user_struct *vuser = get_valid_user_struct(vuid);
2436     if(vuser != NULL)
2437       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2438                vuser->user.unix_name));
2439
2440     *rparam_len = 6;
2441     *rparam = REALLOC(*rparam,*rparam_len);
2442
2443     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2444   
2445         /* check it's a supported variant */
2446         if (strcmp(str1,"zWrLh") != 0) return False;
2447         switch( uLevel )
2448         {
2449                 case 0: p2 = "B21"; break;
2450                 case 1: p2 = "B21BB16DWzzWz"; break;
2451                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2452                 case 10: p2 = "B21Bzzz"; break;
2453                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2454                 default: return False;
2455         }
2456
2457         if (strcmp(p2,str2) != 0) return False;
2458
2459         *rdata_len = mdrcnt + 1024;
2460         *rdata = REALLOC(*rdata,*rdata_len);
2461
2462         SSVAL(*rparam,0,NERR_Success);
2463         SSVAL(*rparam,2,0);             /* converter word */
2464
2465         p = *rdata;
2466         p2 = p + usri11_end;
2467
2468         memset(p,0,21); 
2469         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2470
2471         if (uLevel > 0)
2472         {
2473                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2474                 *p2 = 0;
2475         }
2476         if (uLevel >= 10)
2477         {
2478                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2479                 pstrcpy(p2,"Comment");
2480                 p2 = skip_string(p2,1);
2481
2482                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2483                 pstrcpy(p2,"UserComment");
2484                 p2 = skip_string(p2,1);
2485
2486                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2487                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2488                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2489                 p2 = skip_string(p2,1);
2490         }
2491
2492         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2493         {         
2494                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2495                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2496                 SIVALS(p,usri11_password_age,-1);               /* password age */
2497                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2498                 pstrcpy(p2, lp_logon_home());
2499                 standard_sub_conn(conn, p2);
2500                 p2 = skip_string(p2,1);
2501                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2502                 pstrcpy(p2,"");
2503                 p2 = skip_string(p2,1);
2504                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2505                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2506                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2507                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2508                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2509                 pstrcpy(p2,"\\\\*");
2510                 p2 = skip_string(p2,1);
2511                 SSVAL(p,usri11_country_code,0);         /* country code */
2512
2513                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2514                 pstrcpy(p2,"");
2515                 p2 = skip_string(p2,1);
2516
2517                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2518                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2519                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2520
2521                 /* a simple way to get logon hours at all times. */
2522                 memset(p2,0xff,21);
2523                 SCVAL(p2,21,0);           /* fix zero termination */
2524                 p2 = skip_string(p2,1);
2525
2526                 SSVAL(p,usri11_code_page,0);            /* code page */
2527         }
2528         if (uLevel == 1 || uLevel == 2)
2529         {
2530                 memset(p+22,' ',16);    /* password */
2531                 SIVALS(p,38,-1);                /* password age */
2532                 SSVAL(p,42,
2533                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2534                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2535                 pstrcpy(p2,lp_logon_home());
2536                 standard_sub_conn(conn, p2);
2537                 p2 = skip_string(p2,1);
2538                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2539                 *p2++ = 0;
2540                 SSVAL(p,52,0);          /* flags */
2541                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2542                 pstrcpy(p2,lp_logon_script());
2543                 standard_sub_conn( conn, p2 );             
2544                 p2 = skip_string(p2,1);
2545                 if (uLevel == 2)
2546                 {
2547                         SIVAL(p,60,0);          /* auth_flags */
2548                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2549                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2550                         p2 = skip_string(p2,1);
2551                         SIVAL(p,68,0);          /* urs_comment */
2552                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2553                         pstrcpy(p2,"");
2554                         p2 = skip_string(p2,1);
2555                         SIVAL(p,76,0);          /* workstations */
2556                         SIVAL(p,80,0);          /* last_logon */
2557                         SIVAL(p,84,0);          /* last_logoff */
2558                         SIVALS(p,88,-1);                /* acct_expires */
2559                         SIVALS(p,92,-1);                /* max_storage */
2560                         SSVAL(p,96,168);        /* units_per_week */
2561                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2562                         memset(p2,-1,21);
2563                         p2 += 21;
2564                         SSVALS(p,102,-1);       /* bad_pw_count */
2565                         SSVALS(p,104,-1);       /* num_logons */
2566                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2567                         pstrcpy(p2,"\\\\%L");
2568                         standard_sub_conn(conn, p2);
2569                         p2 = skip_string(p2,1);
2570                         SSVAL(p,110,49);        /* country_code */
2571                         SSVAL(p,112,860);       /* code page */
2572                 }
2573         }
2574
2575         *rdata_len = PTR_DIFF(p2,*rdata);
2576
2577         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2578
2579         return(True);
2580 }
2581
2582 /*******************************************************************
2583   get groups that a user is a member of
2584   ******************************************************************/
2585 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2586                                  int mdrcnt,int mprcnt,
2587                                  char **rdata,char **rparam,
2588                                  int *rdata_len,int *rparam_len)
2589 {
2590   char *str1 = param+2;
2591   char *str2 = skip_string(str1,1);
2592   char *UserName = skip_string(str2,1);
2593   char *p = skip_string(UserName,1);
2594   int uLevel = SVAL(p,0);
2595   char *p2;
2596   int count=0;
2597
2598   *rparam_len = 8;
2599   *rparam = REALLOC(*rparam,*rparam_len);
2600
2601   /* check it's a supported varient */
2602   if (strcmp(str1,"zWrLeh") != 0) return False;
2603   switch( uLevel ) {
2604   case 0: p2 = "B21"; break;
2605   default: return False;
2606   }
2607   if (strcmp(p2,str2) != 0) return False;
2608
2609   *rdata_len = mdrcnt + 1024;
2610   *rdata = REALLOC(*rdata,*rdata_len);
2611
2612   SSVAL(*rparam,0,NERR_Success);
2613   SSVAL(*rparam,2,0);           /* converter word */
2614
2615   p = *rdata;
2616
2617   /* XXXX we need a real SAM database some day */
2618   pstrcpy(p,"Users"); p += 21; count++;
2619   pstrcpy(p,"Domain Users"); p += 21; count++;
2620   pstrcpy(p,"Guests"); p += 21; count++;
2621   pstrcpy(p,"Domain Guests"); p += 21; count++;
2622
2623   *rdata_len = PTR_DIFF(p,*rdata);
2624
2625   SSVAL(*rparam,4,count);       /* is this right?? */
2626   SSVAL(*rparam,6,count);       /* is this right?? */
2627
2628   return(True);
2629 }
2630
2631
2632 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2633                                 int mdrcnt,int mprcnt,
2634                                 char **rdata,char **rparam,
2635                                 int *rdata_len,int *rparam_len)
2636 {
2637   char *str1 = param+2;
2638   char *str2 = skip_string(str1,1);
2639   char *p = skip_string(str2,1);
2640   int uLevel;
2641   struct pack_desc desc;
2642   char* name;
2643
2644   uLevel = SVAL(p,0);
2645   name = p + 2;
2646
2647   memset((char *)&desc,'\0',sizeof(desc));
2648
2649   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2650
2651   /* check it's a supported varient */
2652   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2653   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2654   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2655   desc.base = *rdata;
2656   desc.buflen = mdrcnt;
2657   desc.subformat = NULL;
2658   desc.format = str2;
2659   
2660   if (init_package(&desc,1,0))
2661   {
2662     PACKI(&desc,"W",0);         /* code */
2663     PACKS(&desc,"B21",name);    /* eff. name */
2664     PACKS(&desc,"B","");                /* pad */
2665     PACKI(&desc,"W",
2666           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2667     PACKI(&desc,"D",0);         /* auth flags XXX */
2668     PACKI(&desc,"W",0);         /* num logons */
2669     PACKI(&desc,"W",0);         /* bad pw count */
2670     PACKI(&desc,"D",0);         /* last logon */
2671     PACKI(&desc,"D",-1);                /* last logoff */
2672     PACKI(&desc,"D",-1);                /* logoff time */
2673     PACKI(&desc,"D",-1);                /* kickoff time */
2674     PACKI(&desc,"D",0);         /* password age */
2675     PACKI(&desc,"D",0);         /* password can change */
2676     PACKI(&desc,"D",-1);                /* password must change */
2677     {
2678       fstring mypath;
2679       fstrcpy(mypath,"\\\\");
2680       fstrcat(mypath,local_machine);
2681       strupper(mypath);
2682       PACKS(&desc,"z",mypath); /* computer */
2683     }
2684     PACKS(&desc,"z",global_myworkgroup);/* domain */
2685
2686 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2687 /* made sure all macros are fully substituted and available */
2688     {
2689       pstring logon_script;
2690       pstrcpy(logon_script,lp_logon_script());
2691       standard_sub_conn( conn, logon_script );
2692       PACKS(&desc,"z", logon_script);           /* script path */
2693     }
2694 /* End of JHT mods */
2695
2696     PACKI(&desc,"D",0x00000000);                /* reserved */
2697   }
2698
2699   *rdata_len = desc.usedlen;
2700   *rparam_len = 6;
2701   *rparam = REALLOC(*rparam,*rparam_len);
2702   SSVALS(*rparam,0,desc.errcode);
2703   SSVAL(*rparam,2,0);
2704   SSVAL(*rparam,4,desc.neededlen);
2705
2706   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2707   return(True);
2708 }
2709
2710
2711 /****************************************************************************
2712   api_WAccessGetUserPerms
2713   ****************************************************************************/
2714 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2715                                     int mdrcnt,int mprcnt,
2716                                     char **rdata,char **rparam,
2717                                     int *rdata_len,int *rparam_len)
2718 {
2719   char *str1 = param+2;
2720   char *str2 = skip_string(str1,1);
2721   char *user = skip_string(str2,1);
2722   char *resource = skip_string(user,1);
2723
2724   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2725
2726   /* check it's a supported varient */
2727   if (strcmp(str1,"zzh") != 0) return False;
2728   if (strcmp(str2,"") != 0) return False;
2729
2730   *rparam_len = 6;
2731   *rparam = REALLOC(*rparam,*rparam_len);
2732   SSVALS(*rparam,0,0);          /* errorcode */
2733   SSVAL(*rparam,2,0);           /* converter word */
2734   SSVAL(*rparam,4,0x7f);        /* permission flags */
2735
2736   return(True);
2737 }
2738
2739 /****************************************************************************
2740   api_WPrintJobEnumerate
2741   ****************************************************************************/
2742 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2743                                  int mdrcnt,int mprcnt,
2744                                  char **rdata,char **rparam,
2745                                  int *rdata_len,int *rparam_len)
2746 {
2747   char *str1 = param+2;
2748   char *str2 = skip_string(str1,1);
2749   char *p = skip_string(str2,1);
2750   int uLevel;
2751   int count;
2752   int i;
2753   int snum;
2754   int job;
2755   struct pack_desc desc;
2756   print_queue_struct *queue=NULL;
2757   print_status_struct status;
2758
2759   uLevel = SVAL(p,2);
2760
2761   memset((char *)&desc,'\0',sizeof(desc));
2762   memset((char *)&status,'\0',sizeof(status));
2763
2764   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2765
2766   /* check it's a supported varient */
2767   if (strcmp(str1,"WWrLh") != 0) return False;
2768   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2769
2770   job = SVAL(p,0);
2771   snum = print_job_snum(job);
2772
2773   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2774
2775   count = print_queue_status(snum,&queue,&status);
2776   for (i = 0; i < count; i++) {
2777     if (queue[i].job == job) break;
2778   }
2779   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2780   desc.base = *rdata;
2781   desc.buflen = mdrcnt;
2782
2783   if (init_package(&desc,1,0)) {
2784     if (i < count) {
2785       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2786       *rdata_len = desc.usedlen;
2787     }
2788     else {
2789       desc.errcode = NERR_JobNotFound;
2790       *rdata_len = 0;
2791     }
2792   }
2793
2794   *rparam_len = 6;
2795   *rparam = REALLOC(*rparam,*rparam_len);
2796   SSVALS(*rparam,0,desc.errcode);
2797   SSVAL(*rparam,2,0);
2798   SSVAL(*rparam,4,desc.neededlen);
2799
2800   if (queue) free(queue);
2801
2802   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2803   return(True);
2804 }
2805
2806 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2807                                    int mdrcnt,int mprcnt,
2808                                    char **rdata,char **rparam,
2809                                    int *rdata_len,int *rparam_len)
2810 {
2811   char *str1 = param+2;
2812   char *str2 = skip_string(str1,1);
2813   char *p = skip_string(str2,1);
2814   char* name = p;
2815   int uLevel;
2816   int count;
2817   int i, succnt=0;
2818   int snum;
2819   struct pack_desc desc;
2820   print_queue_struct *queue=NULL;
2821   print_status_struct status;
2822
2823   memset((char *)&desc,'\0',sizeof(desc));
2824   memset((char *)&status,'\0',sizeof(status));
2825
2826   p = skip_string(p,1);
2827   uLevel = SVAL(p,0);
2828
2829   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2830
2831   /* check it's a supported varient */
2832   if (strcmp(str1,"zWrLeh") != 0) return False;
2833   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2834   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2835
2836   snum = lp_servicenumber(name);
2837   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2838     int pnum = lp_servicenumber(PRINTERS_NAME);
2839     if (pnum >= 0) {
2840       lp_add_printer(name,pnum);
2841       snum = lp_servicenumber(name);
2842     }
2843   }
2844
2845   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2846
2847   count = print_queue_status(snum,&queue,&status);
2848   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2849   desc.base = *rdata;
2850   desc.buflen = mdrcnt;
2851
2852   if (init_package(&desc,count,0)) {
2853     succnt = 0;
2854     for (i = 0; i < count; i++) {
2855       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2856       if (desc.errcode == NERR_Success) succnt = i+1;
2857     }
2858   }
2859
2860   *rdata_len = desc.usedlen;
2861
2862   *rparam_len = 8;
2863   *rparam = REALLOC(*rparam,*rparam_len);
2864   SSVALS(*rparam,0,desc.errcode);
2865   SSVAL(*rparam,2,0);
2866   SSVAL(*rparam,4,succnt);
2867   SSVAL(*rparam,6,count);
2868
2869   if (queue) free(queue);
2870
2871   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2872   return(True);
2873 }
2874
2875 static int check_printdest_info(struct pack_desc* desc,
2876                                 int uLevel, char* id)
2877 {
2878   desc->subformat = NULL;
2879   switch( uLevel ) {
2880   case 0: desc->format = "B9"; break;
2881   case 1: desc->format = "B9B21WWzW"; break;
2882   case 2: desc->format = "z"; break;
2883   case 3: desc->format = "zzzWWzzzWW"; break;
2884   default: return False;
2885   }
2886   if (strcmp(desc->format,id) != 0) return False;
2887   return True;
2888 }
2889
2890 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2891                                 struct pack_desc* desc)
2892 {
2893   char buf[100];
2894   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2895   buf[sizeof(buf)-1] = 0;
2896   strupper(buf);
2897   if (uLevel <= 1) {
2898     PACKS(desc,"B9",buf);       /* szName */
2899     if (uLevel == 1) {
2900       PACKS(desc,"B21","");     /* szUserName */
2901       PACKI(desc,"W",0);                /* uJobId */
2902       PACKI(desc,"W",0);                /* fsStatus */
2903       PACKS(desc,"z","");       /* pszStatus */
2904       PACKI(desc,"W",0);                /* time */
2905     }
2906   }
2907   if (uLevel == 2 || uLevel == 3) {
2908     PACKS(desc,"z",buf);                /* pszPrinterName */
2909     if (uLevel == 3) {
2910       PACKS(desc,"z","");       /* pszUserName */
2911       PACKS(desc,"z","");       /* pszLogAddr */
2912       PACKI(desc,"W",0);                /* uJobId */
2913       PACKI(desc,"W",0);                /* fsStatus */
2914       PACKS(desc,"z","");       /* pszStatus */
2915       PACKS(desc,"z","");       /* pszComment */
2916       PACKS(desc,"z","NULL"); /* pszDrivers */
2917       PACKI(desc,"W",0);                /* time */
2918       PACKI(desc,"W",0);                /* pad1 */
2919     }
2920   }
2921 }
2922
2923 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2924                                   int mdrcnt,int mprcnt,
2925                                   char **rdata,char **rparam,
2926                                   int *rdata_len,int *rparam_len)
2927 {
2928   char *str1 = param+2;
2929   char *str2 = skip_string(str1,1);
2930   char *p = skip_string(str2,1);
2931   char* PrinterName = p;
2932   int uLevel;
2933   struct pack_desc desc;
2934   int snum;
2935
2936   memset((char *)&desc,'\0',sizeof(desc));
2937
2938   p = skip_string(p,1);
2939   uLevel = SVAL(p,0);
2940
2941   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2942
2943   /* check it's a supported varient */
2944   if (strcmp(str1,"zWrLh") != 0) return False;
2945   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2946
2947   snum = lp_servicenumber(PrinterName);
2948   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2949     int pnum = lp_servicenumber(PRINTERS_NAME);
2950     if (pnum >= 0) {
2951       lp_add_printer(PrinterName,pnum);
2952       snum = lp_servicenumber(PrinterName);
2953     }
2954   }
2955
2956   if (snum < 0) {
2957     *rdata_len = 0;
2958     desc.errcode = NERR_DestNotFound;
2959     desc.neededlen = 0;
2960   }
2961   else {
2962     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2963     desc.base = *rdata;
2964     desc.buflen = mdrcnt;
2965     if (init_package(&desc,1,0)) {
2966       fill_printdest_info(conn,snum,uLevel,&desc);
2967     }
2968     *rdata_len = desc.usedlen;
2969   }
2970
2971   *rparam_len = 6;
2972   *rparam = REALLOC(*rparam,*rparam_len);
2973   SSVALS(*rparam,0,desc.errcode);
2974   SSVAL(*rparam,2,0);
2975   SSVAL(*rparam,4,desc.neededlen);
2976
2977   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2978   return(True);
2979 }
2980
2981 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2982                                int mdrcnt,int mprcnt,
2983                                char **rdata,char **rparam,
2984                                int *rdata_len,int *rparam_len)
2985 {
2986   char *str1 = param+2;
2987   char *str2 = skip_string(str1,1);
2988   char *p = skip_string(str2,1);
2989   int uLevel;
2990   int queuecnt;
2991   int i, n, succnt=0;
2992   struct pack_desc desc;
2993   int services = lp_numservices();
2994
2995   memset((char *)&desc,'\0',sizeof(desc));
2996
2997   uLevel = SVAL(p,0);
2998
2999   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3000
3001   /* check it's a supported varient */
3002   if (strcmp(str1,"WrLeh") != 0) return False;
3003   if (!check_printdest_info(&desc,uLevel,str2)) return False;
3004
3005   queuecnt = 0;
3006   for (i = 0; i < services; i++)
3007     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3008       queuecnt++;
3009
3010   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3011   desc.base = *rdata;
3012   desc.buflen = mdrcnt;
3013   if (init_package(&desc,queuecnt,0)) {    
3014     succnt = 0;
3015     n = 0;
3016     for (i = 0; i < services; i++) {
3017       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3018         fill_printdest_info(conn,i,uLevel,&desc);
3019         n++;
3020         if (desc.errcode == NERR_Success) succnt = n;
3021       }
3022     }
3023   }
3024
3025   *rdata_len = desc.usedlen;
3026
3027   *rparam_len = 8;
3028   *rparam = REALLOC(*rparam,*rparam_len);
3029   SSVALS(*rparam,0,desc.errcode);
3030   SSVAL(*rparam,2,0);
3031   SSVAL(*rparam,4,succnt);
3032   SSVAL(*rparam,6,queuecnt);
3033
3034   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3035   return(True);
3036 }
3037
3038 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3039                                  int mdrcnt,int mprcnt,
3040                                  char **rdata,char **rparam,
3041                                  int *rdata_len,int *rparam_len)
3042 {
3043   char *str1 = param+2;
3044   char *str2 = skip_string(str1,1);
3045   char *p = skip_string(str2,1);
3046   int uLevel;
3047   int succnt;
3048   struct pack_desc desc;
3049
3050   memset((char *)&desc,'\0',sizeof(desc));
3051
3052   uLevel = SVAL(p,0);
3053
3054   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3055
3056   /* check it's a supported varient */
3057   if (strcmp(str1,"WrLeh") != 0) return False;
3058   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3059
3060   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3061   desc.base = *rdata;
3062   desc.buflen = mdrcnt;
3063   if (init_package(&desc,1,0)) {
3064     PACKS(&desc,"B41","NULL");
3065   }
3066
3067   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3068
3069   *rdata_len = desc.usedlen;
3070
3071   *rparam_len = 8;
3072   *rparam = REALLOC(*rparam,*rparam_len);
3073   SSVALS(*rparam,0,desc.errcode);
3074   SSVAL(*rparam,2,0);
3075   SSVAL(*rparam,4,succnt);
3076   SSVAL(*rparam,6,1);
3077
3078   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3079   return(True);
3080 }
3081
3082 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3083                                 int mdrcnt,int mprcnt,
3084                                 char **rdata,char **rparam,
3085                                 int *rdata_len,int *rparam_len)
3086 {
3087   char *str1 = param+2;
3088   char *str2 = skip_string(str1,1);
3089   char *p = skip_string(str2,1);
3090   int uLevel;
3091   int succnt;
3092   struct pack_desc desc;
3093
3094   memset((char *)&desc,'\0',sizeof(desc));
3095
3096   uLevel = SVAL(p,0);
3097
3098   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3099
3100   /* check it's a supported varient */
3101   if (strcmp(str1,"WrLeh") != 0) return False;
3102   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3103
3104   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3105   desc.base = *rdata;
3106   desc.buflen = mdrcnt;
3107   desc.format = str2;
3108   if (init_package(&desc,1,0)) {
3109     PACKS(&desc,"B13","lpd");
3110   }
3111
3112   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3113
3114   *rdata_len = desc.usedlen;
3115
3116   *rparam_len = 8;
3117   *rparam = REALLOC(*rparam,*rparam_len);
3118   SSVALS(*rparam,0,desc.errcode);
3119   SSVAL(*rparam,2,0);
3120   SSVAL(*rparam,4,succnt);
3121   SSVAL(*rparam,6,1);
3122
3123   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3124   return(True);
3125 }
3126
3127 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3128                                int mdrcnt,int mprcnt,
3129                                char **rdata,char **rparam,
3130                                int *rdata_len,int *rparam_len)
3131 {
3132   char *str1 = param+2;
3133   char *str2 = skip_string(str1,1);
3134   char *p = skip_string(str2,1);
3135   int uLevel;
3136   int succnt;
3137   struct pack_desc desc;
3138
3139   memset((char *)&desc,'\0',sizeof(desc));
3140
3141   uLevel = SVAL(p,0);
3142
3143   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3144
3145   /* check it's a supported varient */
3146   if (strcmp(str1,"WrLeh") != 0) return False;
3147   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3148
3149   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3150   memset((char *)&desc,'\0',sizeof(desc));
3151   desc.base = *rdata;
3152   desc.buflen = mdrcnt;
3153   desc.format = str2;
3154   if (init_package(&desc,1,0)) {
3155     PACKS(&desc,"B13","lp0");
3156   }
3157
3158   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3159
3160   *rdata_len = desc.usedlen;
3161
3162   *rparam_len = 8;
3163   *rparam = REALLOC(*rparam,*rparam_len);
3164   SSVALS(*rparam,0,desc.errcode);
3165   SSVAL(*rparam,2,0);
3166   SSVAL(*rparam,4,succnt);
3167   SSVAL(*rparam,6,1);
3168
3169   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3170   return(True);
3171 }
3172
3173 /****************************************************************************
3174  The buffer was too small
3175  ****************************************************************************/
3176
3177 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3178                          int mdrcnt,int mprcnt,
3179                          char **rdata,char **rparam,
3180                          int *rdata_len,int *rparam_len)
3181 {
3182   *rparam_len = MIN(*rparam_len,mprcnt);
3183   *rparam = REALLOC(*rparam,*rparam_len);
3184
3185   *rdata_len = 0;
3186
3187   SSVAL(*rparam,0,NERR_BufTooSmall);
3188
3189   DEBUG(3,("Supplied buffer too small in API command\n"));
3190
3191   return(True);
3192 }
3193
3194
3195 /****************************************************************************
3196  The request is not supported
3197  ****************************************************************************/
3198
3199 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3200                             int mdrcnt,int mprcnt,
3201                             char **rdata,char **rparam,
3202                             int *rdata_len,int *rparam_len)
3203 {
3204   *rparam_len = 4;
3205   *rparam = REALLOC(*rparam,*rparam_len);
3206
3207   *rdata_len = 0;
3208
3209   SSVAL(*rparam,0,NERR_notsupported);
3210   SSVAL(*rparam,2,0);           /* converter word */
3211
3212   DEBUG(3,("Unsupported API command\n"));
3213
3214   return(True);
3215 }
3216
3217
3218
3219
3220 struct
3221 {
3222   char *name;
3223   int id;
3224   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3225              int,int,char **,char **,int *,int *);
3226   int flags;
3227 } api_commands[] = {
3228   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3229   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3230   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3231   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3232   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3233   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3234   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3235   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3236   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3237   {"WPrintQueuePause",  74, api_WPrintQueueCtrl,0},
3238   {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3239   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3240   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3241   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3242   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3243   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3244   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3245   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3246   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3247   {"WPrintQueuePurge",  103,    api_WPrintQueueCtrl,0},
3248   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3249   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3250   {"SetUserPassword",   115,    api_SetUserPassword,0},
3251   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3252   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3253   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3254   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3255   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3256   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3257   {NULL,                -1,     api_Unsupported,0}};
3258
3259
3260 /****************************************************************************
3261  Handle remote api calls
3262  ****************************************************************************/
3263
3264 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3265                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3266 {
3267   int api_command;
3268   char *rdata = NULL;
3269   char *rparam = NULL;
3270   int rdata_len = 0;
3271   int rparam_len = 0;
3272   BOOL reply=False;
3273   int i;
3274
3275   if (!params) {
3276           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3277           return 0;
3278   }
3279
3280   api_command = SVAL(params,0);
3281
3282   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3283            api_command,
3284            params+2,
3285            skip_string(params+2,1),
3286            tdscnt,tpscnt,mdrcnt,mprcnt));
3287
3288   for (i=0;api_commands[i].name;i++) {
3289     if (api_commands[i].id == api_command && api_commands[i].fn) {
3290         DEBUG(3,("Doing %s\n",api_commands[i].name));
3291         break;
3292     }
3293   }
3294
3295   rdata = (char *)malloc(1024);
3296   if (rdata)
3297     memset(rdata,'\0',1024);
3298
3299   rparam = (char *)malloc(1024);
3300   if (rparam)
3301     memset(rparam,'\0',1024);
3302
3303   if(!rdata || !rparam) {
3304     DEBUG(0,("api_reply: malloc fail !\n"));
3305     return -1;
3306   }
3307
3308   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3309                              &rdata,&rparam,&rdata_len,&rparam_len);
3310
3311
3312   if (rdata_len > mdrcnt ||
3313       rparam_len > mprcnt) {
3314       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3315                            &rdata,&rparam,&rdata_len,&rparam_len);
3316   }
3317
3318   /* if we get False back then it's actually unsupported */
3319   if (!reply)
3320     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3321                     &rdata,&rparam,&rdata_len,&rparam_len);
3322
3323   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3324
3325   if (rdata )
3326     free(rdata);
3327   if (rparam)
3328     free(rparam);
3329   
3330   return -1;
3331 }
3332
3333
3334 #undef OLD_NTDOMAIN