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