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