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