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