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