ee2aec8c220c8a7557ed7aa135eaf49d07041f3d
[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, s_len;
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, s_len;
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   StrnCpy(pass1,p,16);
1536   StrnCpy(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   if (password_ok(user,pass1,strlen(pass1),NULL) &&
1549       chgpasswd(user,pass1,pass2))
1550   {
1551     SSVAL(*rparam,0,NERR_Success);
1552   }
1553
1554   bzero(pass1,sizeof(fstring));
1555   bzero(pass2,sizeof(fstring));  
1556          
1557   return(True);
1558 }
1559
1560 /****************************************************************************
1561   delete a print job
1562   Form: <W> <> 
1563   ****************************************************************************/
1564 static BOOL api_RDosPrintJobDel(int cnum,uint16 vuid, char *param,char *data,
1565                                 int mdrcnt,int mprcnt,
1566                                 char **rdata,char **rparam,
1567                                 int *rdata_len,int *rparam_len)
1568 {
1569   int function = SVAL(param,0);
1570   char *str1 = param+2;
1571   char *str2 = skip_string(str1,1);
1572   char *p = skip_string(str2,1);
1573   int jobid, snum;
1574   int i, count;
1575
1576   printjob_decode(SVAL(p,0), &snum, &jobid);
1577
1578   /* check it's a supported varient */
1579   if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1580     return(False);
1581
1582   *rparam_len = 4;
1583   *rparam = REALLOC(*rparam,*rparam_len);
1584
1585   *rdata_len = 0;
1586
1587   SSVAL(*rparam,0,NERR_Success);
1588
1589   if (snum >= 0 && VALID_SNUM(snum))
1590     {
1591       print_queue_struct *queue=NULL;
1592       lpq_reset(snum);
1593       count = get_printqueue(snum,cnum,&queue,NULL);
1594   
1595       for (i=0;i<count;i++)
1596         if ((queue[i].job&0xFF) == jobid)
1597           {
1598             switch (function) {
1599             case 81:            /* delete */ 
1600               DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
1601               del_printqueue(cnum,snum,queue[i].job);
1602               break;
1603             case 82:            /* pause */
1604             case 83:            /* resume */
1605               DEBUG(3,("%s queue entry %d\n",
1606                        (function==82?"pausing":"resuming"),queue[i].job));
1607               status_printjob(cnum,snum,queue[i].job,
1608                               (function==82?LPQ_PAUSED:LPQ_QUEUED));
1609               break;
1610             }
1611             break;
1612           }
1613   
1614       if (i==count)
1615         SSVAL(*rparam,0,NERR_JobNotFound);
1616
1617       if (queue) free(queue);
1618     }
1619
1620   SSVAL(*rparam,2,0);           /* converter word */
1621
1622   return(True);
1623 }
1624
1625 static BOOL api_WPrintQueuePurge(int cnum,uint16 vuid, char *param,char *data,
1626                                  int mdrcnt,int mprcnt,
1627                                  char **rdata,char **rparam,
1628                                  int *rdata_len,int *rparam_len)
1629 {
1630   char *str1 = param+2;
1631   char *str2 = skip_string(str1,1);
1632   char *QueueName = skip_string(str2,1);
1633   int snum;
1634
1635   /* check it's a supported varient */
1636   if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1637     return(False);
1638
1639   *rparam_len = 4;
1640   *rparam = REALLOC(*rparam,*rparam_len);
1641
1642   *rdata_len = 0;
1643
1644   SSVAL(*rparam,0,NERR_Success);
1645   SSVAL(*rparam,2,0);           /* converter word */
1646
1647   snum = lp_servicenumber(QueueName);
1648   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
1649     int pnum = lp_servicenumber(PRINTERS_NAME);
1650     if (pnum >= 0) {
1651       lp_add_printer(QueueName,pnum);
1652       snum = lp_servicenumber(QueueName);
1653     }
1654   }
1655
1656   if (snum >= 0 && VALID_SNUM(snum)) {
1657     print_queue_struct *queue=NULL;
1658     int i, count;
1659     lpq_reset(snum);
1660     
1661     count = get_printqueue(snum,cnum,&queue,NULL);
1662     for (i = 0; i < count; i++)
1663       del_printqueue(cnum,snum,queue[i].job);
1664     
1665     if (queue) free(queue);
1666   }
1667
1668   DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
1669
1670   return(True);
1671 }
1672
1673
1674 /****************************************************************************
1675   set the property of a print job (undocumented?)
1676   ? function = 0xb -> set name of print job
1677   ? function = 0x6 -> move print job up/down
1678   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1679   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1680 ****************************************************************************/
1681 static int check_printjob_info(struct pack_desc* desc,
1682                                int uLevel, char* id)
1683 {
1684   desc->subformat = NULL;
1685   switch( uLevel ) {
1686   case 0: desc->format = "W"; break;
1687   case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1688   case 2: desc->format = "WWzWWDDzz"; break;
1689   case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1690   default: return False;
1691   }
1692   if (strcmp(desc->format,id) != 0) return False;
1693   return True;
1694 }
1695
1696 static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data,
1697                              int mdrcnt,int mprcnt,
1698                              char **rdata,char **rparam,
1699                              int *rdata_len,int *rparam_len)
1700 {
1701   struct pack_desc desc;
1702   char *str1 = param+2;
1703   char *str2 = skip_string(str1,1);
1704   char *p = skip_string(str2,1);
1705   int jobid, snum;
1706   int uLevel = SVAL(p,2);
1707   int function = SVAL(p,4);     /* what is this ?? */
1708   int i;
1709   char *s = data;
1710
1711   printjob_decode(SVAL(p,0), &snum, &jobid);
1712    
1713   *rparam_len = 4;
1714   *rparam = REALLOC(*rparam,*rparam_len);
1715   
1716   *rdata_len = 0;
1717   
1718   /* check it's a supported varient */
1719   if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
1720     return(False);
1721    
1722   switch (function) {
1723   case 0x6:     /* change job place in the queue, data gives the new place */
1724     if (snum >= 0 && VALID_SNUM(snum))
1725       {
1726         print_queue_struct *queue=NULL;
1727         int count;
1728   
1729         lpq_reset(snum);
1730         count = get_printqueue(snum,cnum,&queue,NULL);
1731         for (i=0;i<count;i++)   /* find job */
1732           if ((queue[i].job&0xFF) == jobid) break;
1733             
1734         if (i==count) {
1735           desc.errcode=NERR_JobNotFound;
1736           if (queue) free(queue);
1737         }
1738         else {
1739           desc.errcode=NERR_Success;
1740           i++;
1741 #if 0   
1742           {
1743             int place= SVAL(data,0);
1744             /* we currently have no way of doing this. Can any unix do it? */
1745             if (i < place)      /* move down */;
1746             else if (i > place )        /* move up */;
1747           }
1748 #endif
1749           desc.errcode=NERR_notsupported; /* not yet supported */
1750           if (queue) free(queue);
1751         }
1752       }
1753     else desc.errcode=NERR_JobNotFound;
1754     break;
1755   case 0xb:   /* change print job name, data gives the name */
1756     /* jobid, snum should be zero */
1757     if (isalpha(*s))
1758       {
1759         pstring name;
1760         int l = 0;
1761         while (l<64 && *s)
1762           {
1763             if (issafe(*s)) name[l++] = *s;
1764             s++;
1765           }      
1766         name[l] = 0;
1767         
1768         DEBUG(3,("Setting print name to %s\n",name));
1769         
1770         become_root(True);
1771
1772         for (i=0;i<MAX_OPEN_FILES;i++)
1773           if (Files[i].open && Files[i].print_file)
1774             {
1775               pstring wd;
1776           int fcnum = Files[i].cnum;
1777               GetWd(wd);
1778               unbecome_user();
1779               
1780               if (!become_user(&Connections[fcnum], fcnum,vuid) || 
1781                   !become_service(fcnum,True))
1782                 break;
1783               
1784               if (sys_rename(Files[i].name,name) == 0)
1785                 string_set(&Files[i].name,name);
1786               break;
1787             }
1788
1789          unbecome_root(True);
1790       }
1791     desc.errcode=NERR_Success;
1792   
1793     break;
1794   default:                      /* not implemented */
1795     return False;
1796   }
1797  
1798   SSVALS(*rparam,0,desc.errcode);
1799   SSVAL(*rparam,2,0);           /* converter word */
1800   
1801   return(True);
1802 }
1803
1804
1805 /****************************************************************************
1806   get info about the server
1807   ****************************************************************************/
1808 static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data,
1809                                   int mdrcnt,int mprcnt,
1810                                   char **rdata,char **rparam,
1811                                   int *rdata_len,int *rparam_len)
1812 {
1813   char *str1 = param+2;
1814   char *str2 = skip_string(str1,1);
1815   char *p = skip_string(str2,1);
1816   int uLevel = SVAL(p,0);
1817   char *p2;
1818   int struct_len;
1819
1820   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
1821
1822   /* check it's a supported varient */
1823   if (!prefix_ok(str1,"WrLh")) return False;
1824   switch( uLevel ) {
1825   case 0:
1826     if (strcmp(str2,"B16") != 0) return False;
1827     struct_len = 16;
1828     break;
1829   case 1:
1830     if (strcmp(str2,"B16BBDz") != 0) return False;
1831     struct_len = 26;
1832     break;
1833   case 2:
1834     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
1835         != 0) return False;
1836     struct_len = 134;
1837     break;
1838   case 3:
1839     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
1840         != 0) return False;
1841     struct_len = 144;
1842     break;
1843   case 20:
1844     if (strcmp(str2,"DN") != 0) return False;
1845     struct_len = 6;
1846     break;
1847   case 50:
1848     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
1849     struct_len = 42;
1850     break;
1851   default: return False;
1852   }
1853
1854   *rdata_len = mdrcnt;
1855   *rdata = REALLOC(*rdata,*rdata_len);
1856
1857   p = *rdata;
1858   p2 = p + struct_len;
1859   if (uLevel != 20) {
1860     StrnCpy(p,local_machine,16);
1861     strupper(p);
1862   }
1863   p += 16;
1864   if (uLevel > 0)
1865     {
1866       struct srv_info_struct *servers=NULL;
1867       int i,count;
1868       pstring comment;
1869       uint32 servertype= lp_default_server_announce();
1870
1871       pstrcpy(comment,lp_serverstring());
1872
1873       if ((count=get_server_info(SV_TYPE_ALL,&servers,myworkgroup))>0) {
1874         for (i=0;i<count;i++)
1875           if (strequal(servers[i].name,local_machine))
1876       {
1877             servertype = servers[i].type;
1878             pstrcpy(comment,servers[i].comment);            
1879           }
1880       }
1881       if (servers) free(servers);
1882
1883       SCVAL(p,0,lp_major_announce_version());
1884       SCVAL(p,1,lp_minor_announce_version());
1885       SIVAL(p,2,servertype);
1886
1887       if (mdrcnt == struct_len) {
1888         SIVAL(p,6,0);
1889       } else {
1890         SIVAL(p,6,PTR_DIFF(p2,*rdata));
1891         standard_sub(cnum,comment);
1892         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
1893         p2 = skip_string(p2,1);
1894       }
1895     }
1896   if (uLevel > 1)
1897     {
1898       return False;             /* not yet implemented */
1899     }
1900
1901   *rdata_len = PTR_DIFF(p2,*rdata);
1902
1903   *rparam_len = 6;
1904   *rparam = REALLOC(*rparam,*rparam_len);
1905   SSVAL(*rparam,0,NERR_Success);
1906   SSVAL(*rparam,2,0);           /* converter word */
1907   SSVAL(*rparam,4,*rdata_len);
1908
1909   return(True);
1910 }
1911
1912
1913 /****************************************************************************
1914   get info about the server
1915   ****************************************************************************/
1916 static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
1917                                 int mdrcnt,int mprcnt,
1918                                 char **rdata,char **rparam,
1919                                 int *rdata_len,int *rparam_len)
1920 {
1921   char *str1 = param+2;
1922   char *str2 = skip_string(str1,1);
1923   char *p = skip_string(str2,1);
1924   char *p2;
1925   extern pstring sesssetup_user;
1926   int level = SVAL(p,0);
1927
1928   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
1929
1930   *rparam_len = 6;
1931   *rparam = REALLOC(*rparam,*rparam_len);
1932
1933   /* check it's a supported varient */
1934   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
1935     return(False);
1936
1937   *rdata_len = mdrcnt + 1024;
1938   *rdata = REALLOC(*rdata,*rdata_len);
1939
1940   SSVAL(*rparam,0,NERR_Success);
1941   SSVAL(*rparam,2,0);           /* converter word */
1942
1943   p = *rdata;
1944   p2 = p + 22;
1945
1946
1947   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
1948   strcpy(p2,local_machine);
1949   strupper(p2);
1950   p2 = skip_string(p2,1);
1951   p += 4;
1952
1953   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1954   strcpy(p2,sesssetup_user);
1955   p2 = skip_string(p2,1);
1956   p += 4;
1957
1958   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
1959   strcpy(p2,myworkgroup);
1960   strupper(p2);
1961   p2 = skip_string(p2,1);
1962   p += 4;
1963
1964   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
1965   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
1966   p += 2;
1967
1968   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1969   strcpy(p2,myworkgroup);       /* don't know.  login domain?? */
1970   p2 = skip_string(p2,1);
1971   p += 4;
1972
1973   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
1974   strcpy(p2,"");
1975   p2 = skip_string(p2,1);
1976   p += 4;
1977
1978   *rdata_len = PTR_DIFF(p2,*rdata);
1979
1980   SSVAL(*rparam,4,*rdata_len);
1981
1982   return(True);
1983 }
1984
1985 /****************************************************************************
1986   get info about a user
1987
1988     struct user_info_11 {
1989         char                usri11_name[21];  0-20 
1990         char                usri11_pad;       21 
1991         char                *usri11_comment;  22-25 
1992         char            *usri11_usr_comment;  26-29
1993         unsigned short      usri11_priv;      30-31
1994         unsigned long       usri11_auth_flags; 32-35
1995         long                usri11_password_age; 36-39
1996         char                *usri11_homedir; 40-43
1997         char            *usri11_parms; 44-47
1998         long                usri11_last_logon; 48-51
1999         long                usri11_last_logoff; 52-55
2000         unsigned short      usri11_bad_pw_count; 56-57
2001         unsigned short      usri11_num_logons; 58-59
2002         char                *usri11_logon_server; 60-63
2003         unsigned short      usri11_country_code; 64-65
2004         char            *usri11_workstations; 66-69
2005         unsigned long       usri11_max_storage; 70-73
2006         unsigned short      usri11_units_per_week; 74-75
2007         unsigned char       *usri11_logon_hours; 76-79
2008         unsigned short      usri11_code_page; 80-81
2009     };
2010
2011 where:
2012
2013   usri11_name specifies the user name for which information is retireved
2014
2015   usri11_pad aligns the next data structure element to a word boundary
2016
2017   usri11_comment is a null terminated ASCII comment
2018
2019   usri11_user_comment is a null terminated ASCII comment about the user
2020
2021   usri11_priv specifies the level of the privilege assigned to the user.
2022        The possible values are:
2023
2024 Name             Value  Description
2025 USER_PRIV_GUEST  0      Guest privilege
2026 USER_PRIV_USER   1      User privilege
2027 USER_PRV_ADMIN   2      Administrator privilege
2028
2029   usri11_auth_flags specifies the account operator privileges. The
2030        possible values are:
2031
2032 Name            Value   Description
2033 AF_OP_PRINT     0       Print operator
2034
2035
2036 Leach, Naik                                        [Page 28]\r\f
2037
2038
2039 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2040
2041
2042 AF_OP_COMM      1       Communications operator
2043 AF_OP_SERVER    2       Server operator
2044 AF_OP_ACCOUNTS  3       Accounts operator
2045
2046
2047   usri11_password_age specifies how many seconds have elapsed since the
2048        password was last changed.
2049
2050   usri11_home_dir points to a null terminated ASCII string that contains
2051        the path name of the user's home directory.
2052
2053   usri11_parms points to a null terminated ASCII string that is set
2054        aside for use by applications.
2055
2056   usri11_last_logon specifies the time when the user last logged on.
2057        This value is stored as the number of seconds elapsed since
2058        00:00:00, January 1, 1970.
2059
2060   usri11_last_logoff specifies the time when the user last logged off.
2061        This value is stored as the number of seconds elapsed since
2062        00:00:00, January 1, 1970. A value of 0 means the last logoff
2063        time is unknown.
2064
2065   usri11_bad_pw_count specifies the number of incorrect passwords
2066        entered since the last successful logon.
2067
2068   usri11_log1_num_logons specifies the number of times this user has
2069        logged on. A value of -1 means the number of logons is unknown.
2070
2071   usri11_logon_server points to a null terminated ASCII string that
2072        contains the name of the server to which logon requests are sent.
2073        A null string indicates logon requests should be sent to the
2074        domain controller.
2075
2076   usri11_country_code specifies the country code for the user's language
2077        of choice.
2078
2079   usri11_workstations points to a null terminated ASCII string that
2080        contains the names of workstations the user may log on from.
2081        There may be up to 8 workstations, with the names separated by
2082        commas. A null strings indicates there are no restrictions.
2083
2084   usri11_max_storage specifies the maximum amount of disk space the user
2085        can occupy. A value of 0xffffffff indicates there are no
2086        restrictions.
2087
2088   usri11_units_per_week specifies the equal number of time units into
2089        which a week is divided. This value must be equal to 168.
2090
2091   usri11_logon_hours points to a 21 byte (168 bits) string that
2092        specifies the time during which the user can log on. Each bit
2093        represents one unique hour in a week. The first bit (bit 0, word
2094        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2095
2096
2097
2098 Leach, Naik                                        [Page 29]\r\f
2099
2100
2101 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2102
2103
2104        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2105        are no restrictions.
2106
2107   usri11_code_page specifies the code page for the user's language of
2108        choice
2109
2110 All of the pointers in this data structure need to be treated
2111 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2112 to be ignored. The converter word returned in the parameters section
2113 needs to be subtracted from the lower 16 bits to calculate an offset
2114 into the return buffer where this ASCII string resides.
2115
2116 There is no auxiliary data in the response.
2117
2118   ****************************************************************************/
2119
2120 #define usri11_name           0 
2121 #define usri11_pad            21
2122 #define usri11_comment        22
2123 #define usri11_usr_comment    26
2124 #define usri11_full_name      30
2125 #define usri11_priv           34
2126 #define usri11_auth_flags     36
2127 #define usri11_password_age   40
2128 #define usri11_homedir        44
2129 #define usri11_parms          48
2130 #define usri11_last_logon     52
2131 #define usri11_last_logoff    56
2132 #define usri11_bad_pw_count   60
2133 #define usri11_num_logons     62
2134 #define usri11_logon_server   64
2135 #define usri11_country_code   68
2136 #define usri11_workstations   70
2137 #define usri11_max_storage    74
2138 #define usri11_units_per_week 78
2139 #define usri11_logon_hours    80
2140 #define usri11_code_page      84
2141 #define usri11_end            86
2142
2143 #define USER_PRIV_GUEST 0
2144 #define USER_PRIV_USER 1
2145 #define USER_PRIV_ADMIN 2
2146
2147 #define AF_OP_PRINT     0 
2148 #define AF_OP_COMM      1
2149 #define AF_OP_SERVER    2
2150 #define AF_OP_ACCOUNTS  3
2151
2152
2153 static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
2154                                 int mdrcnt,int mprcnt,
2155                                 char **rdata,char **rparam,
2156                                 int *rdata_len,int *rparam_len)
2157 {
2158         char *str1 = param+2;
2159         char *str2 = skip_string(str1,1);
2160         char *UserName = skip_string(str2,1);
2161         char *p = skip_string(UserName,1);
2162         int uLevel = SVAL(p,0);
2163         char *p2;
2164
2165     /* get NIS home of a previously validated user - simeon */
2166     user_struct *vuser = get_valid_user_struct(vuid);
2167     DEBUG(3,("  Username of UID %d is %s\n", vuser->uid, vuser->name));
2168
2169     *rparam_len = 6;
2170     *rparam = REALLOC(*rparam,*rparam_len);
2171
2172     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2173   
2174         /* check it's a supported variant */
2175         if (strcmp(str1,"zWrLh") != 0) return False;
2176         switch( uLevel )
2177         {
2178                 case 0: p2 = "B21"; break;
2179                 case 1: p2 = "B21BB16DWzzWz"; break;
2180                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2181                 case 10: p2 = "B21Bzzz"; break;
2182                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2183                 default: return False;
2184         }
2185
2186         if (strcmp(p2,str2) != 0) return False;
2187
2188         *rdata_len = mdrcnt + 1024;
2189         *rdata = REALLOC(*rdata,*rdata_len);
2190
2191         SSVAL(*rparam,0,NERR_Success);
2192         SSVAL(*rparam,2,0);             /* converter word */
2193
2194         p = *rdata;
2195         p2 = p + usri11_end;
2196
2197         memset(p,0,21); 
2198         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2199
2200         if (uLevel > 0)
2201         {
2202                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2203                 *p2 = 0;
2204         }
2205         if (uLevel >= 10)
2206         {
2207                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2208                 strcpy(p2,"Comment");
2209                 p2 = skip_string(p2,1);
2210
2211                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2212                 strcpy(p2,"UserComment");
2213                 p2 = skip_string(p2,1);
2214
2215                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2216                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2217                 strcpy(p2,vuser->real_name);    /* simeon */
2218                 p2 = skip_string(p2,1);
2219         }
2220
2221         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2222         {         
2223                 SSVAL(p,usri11_priv,Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2224                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2225                 SIVALS(p,usri11_password_age,-1);               /* password age */
2226                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2227                 strcpy(p2, lp_logon_path());
2228                 p2 = skip_string(p2,1);
2229                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2230                 strcpy(p2,"");
2231                 p2 = skip_string(p2,1);
2232                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2233                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2234                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2235                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2236                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2237                 strcpy(p2,"\\\\*");
2238                 p2 = skip_string(p2,1);
2239                 SSVAL(p,usri11_country_code,0);         /* country code */
2240
2241                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2242                 strcpy(p2,"");
2243                 p2 = skip_string(p2,1);
2244
2245                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2246                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2247                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2248
2249                 /* a simple way to get logon hours at all times. */
2250                 memset(p2,0xff,21);
2251                 SCVAL(p2,21,0);           /* fix zero termination */
2252                 p2 = skip_string(p2,1);
2253
2254                 SSVAL(p,usri11_code_page,0);            /* code page */
2255         }
2256         if (uLevel == 1 || uLevel == 2)
2257         {
2258                 memset(p+22,' ',16);    /* password */
2259                 SIVALS(p,38,-1);                /* password age */
2260                 SSVAL(p,42,
2261                 Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2262                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2263                 strcpy(p2,lp_logon_path());
2264                 p2 = skip_string(p2,1);
2265                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2266                 *p2++ = 0;
2267                 SSVAL(p,52,0);          /* flags */
2268                 SIVAL(p,54,0);          /* script_path */
2269                 if (uLevel == 2)
2270                 {
2271                         SIVAL(p,60,0);          /* auth_flags */
2272                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2273                         strcpy(p2,vuser->real_name);    /* simeon */
2274                         p2 = skip_string(p2,1);
2275                         SIVAL(p,68,0);          /* urs_comment */
2276                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2277                         strcpy(p2,"");
2278                         p2 = skip_string(p2,1);
2279                         SIVAL(p,76,0);          /* workstations */
2280                         SIVAL(p,80,0);          /* last_logon */
2281                         SIVAL(p,84,0);          /* last_logoff */
2282                         SIVALS(p,88,-1);                /* acct_expires */
2283                         SIVALS(p,92,-1);                /* max_storage */
2284                         SSVAL(p,96,168);        /* units_per_week */
2285                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2286                         memset(p2,-1,21);
2287                         p2 += 21;
2288                         SSVALS(p,102,-1);       /* bad_pw_count */
2289                         SSVALS(p,104,-1);       /* num_logons */
2290                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2291                         strcpy(p2,"\\\\%L");
2292                         standard_sub_basic(p2);
2293                         p2 = skip_string(p2,1);
2294                         SSVAL(p,110,49);        /* country_code */
2295                         SSVAL(p,112,860);       /* code page */
2296                 }
2297         }
2298
2299         *rdata_len = PTR_DIFF(p2,*rdata);
2300
2301         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2302
2303         return(True);
2304 }
2305
2306 /*******************************************************************
2307   get groups that a user is a member of
2308   ******************************************************************/
2309 static BOOL api_NetUserGetGroups(int cnum,uint16 vuid, char *param,char *data,
2310                                  int mdrcnt,int mprcnt,
2311                                  char **rdata,char **rparam,
2312                                  int *rdata_len,int *rparam_len)
2313 {
2314   char *str1 = param+2;
2315   char *str2 = skip_string(str1,1);
2316   char *UserName = skip_string(str2,1);
2317   char *p = skip_string(UserName,1);
2318   int uLevel = SVAL(p,0);
2319   char *p2;
2320   int count=0;
2321
2322   *rparam_len = 8;
2323   *rparam = REALLOC(*rparam,*rparam_len);
2324
2325   /* check it's a supported varient */
2326   if (strcmp(str1,"zWrLeh") != 0) return False;
2327   switch( uLevel ) {
2328   case 0: p2 = "B21"; break;
2329   default: return False;
2330   }
2331   if (strcmp(p2,str2) != 0) return False;
2332
2333   *rdata_len = mdrcnt + 1024;
2334   *rdata = REALLOC(*rdata,*rdata_len);
2335
2336   SSVAL(*rparam,0,NERR_Success);
2337   SSVAL(*rparam,2,0);           /* converter word */
2338
2339   p = *rdata;
2340
2341   /* XXXX we need a real SAM database some day */
2342   strcpy(p,"Users"); p += 21; count++;
2343   strcpy(p,"Domain Users"); p += 21; count++;
2344   strcpy(p,"Guests"); p += 21; count++;
2345   strcpy(p,"Domain Guests"); p += 21; count++;
2346
2347   *rdata_len = PTR_DIFF(p,*rdata);
2348
2349   SSVAL(*rparam,4,count);       /* is this right?? */
2350   SSVAL(*rparam,6,count);       /* is this right?? */
2351
2352   return(True);
2353 }
2354
2355
2356 static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data,
2357                                 int mdrcnt,int mprcnt,
2358                                 char **rdata,char **rparam,
2359                                 int *rdata_len,int *rparam_len)
2360 {
2361   char *str1 = param+2;
2362   char *str2 = skip_string(str1,1);
2363   char *p = skip_string(str2,1);
2364   int uLevel;
2365   struct pack_desc desc;
2366   char* name;
2367   char* logon_script;
2368
2369   uLevel = SVAL(p,0);
2370   name = p + 2;
2371
2372   bzero(&desc,sizeof(desc));
2373
2374   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2375
2376   /* check it's a supported varient */
2377   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2378   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2379   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2380   desc.base = *rdata;
2381   desc.buflen = mdrcnt;
2382   desc.subformat = NULL;
2383   desc.format = str2;
2384   
2385   if (init_package(&desc,1,0))
2386   {
2387     PACKI(&desc,"W",0);         /* code */
2388     PACKS(&desc,"B21",name);    /* eff. name */
2389     PACKS(&desc,"B","");                /* pad */
2390     PACKI(&desc,"W",
2391           Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2392     PACKI(&desc,"D",0);         /* auth flags XXX */
2393     PACKI(&desc,"W",0);         /* num logons */
2394     PACKI(&desc,"W",0);         /* bad pw count */
2395     PACKI(&desc,"D",0);         /* last logon */
2396     PACKI(&desc,"D",-1);                /* last logoff */
2397     PACKI(&desc,"D",-1);                /* logoff time */
2398     PACKI(&desc,"D",-1);                /* kickoff time */
2399     PACKI(&desc,"D",0);         /* password age */
2400     PACKI(&desc,"D",0);         /* password can change */
2401     PACKI(&desc,"D",-1);                /* password must change */
2402     {
2403       fstring mypath;
2404       strcpy(mypath,"\\\\");
2405       strcat(mypath,local_machine);
2406       strupper(mypath);
2407       PACKS(&desc,"z",mypath); /* computer */
2408     }
2409     PACKS(&desc,"z",myworkgroup);/* domain */
2410
2411 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2412 /* made sure all macros are fully substituted and available */
2413     logon_script = lp_logon_script();
2414     standard_sub( cnum, logon_script );
2415     PACKS(&desc,"z", logon_script);             /* script path */
2416 /* End of JHT mods */
2417
2418     PACKI(&desc,"D",0x00000000);                /* reserved */
2419   }
2420
2421   *rdata_len = desc.usedlen;
2422   *rparam_len = 6;
2423   *rparam = REALLOC(*rparam,*rparam_len);
2424   SSVALS(*rparam,0,desc.errcode);
2425   SSVAL(*rparam,2,0);
2426   SSVAL(*rparam,4,desc.neededlen);
2427
2428   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2429   return(True);
2430 }
2431
2432
2433 /****************************************************************************
2434   api_WAccessGetUserPerms
2435   ****************************************************************************/
2436 static BOOL api_WAccessGetUserPerms(int cnum,uint16 vuid, char *param,char *data,
2437                                     int mdrcnt,int mprcnt,
2438                                     char **rdata,char **rparam,
2439                                     int *rdata_len,int *rparam_len)
2440 {
2441   char *str1 = param+2;
2442   char *str2 = skip_string(str1,1);
2443   char *user = skip_string(str2,1);
2444   char *resource = skip_string(user,1);
2445
2446   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2447
2448   /* check it's a supported varient */
2449   if (strcmp(str1,"zzh") != 0) return False;
2450   if (strcmp(str2,"") != 0) return False;
2451
2452   *rparam_len = 6;
2453   *rparam = REALLOC(*rparam,*rparam_len);
2454   SSVALS(*rparam,0,0);          /* errorcode */
2455   SSVAL(*rparam,2,0);           /* converter word */
2456   SSVAL(*rparam,4,0x7f);        /* permission flags */
2457
2458   return(True);
2459 }
2460
2461 /****************************************************************************
2462   api_WPrintJobEnumerate
2463   ****************************************************************************/
2464 static BOOL api_WPrintJobGetInfo(int cnum,uint16 vuid, char *param,char *data,
2465                                  int mdrcnt,int mprcnt,
2466                                  char **rdata,char **rparam,
2467                                  int *rdata_len,int *rparam_len)
2468 {
2469   char *str1 = param+2;
2470   char *str2 = skip_string(str1,1);
2471   char *p = skip_string(str2,1);
2472   int uLevel,cbBuf;
2473   int count;
2474   int i;
2475   int snum;
2476   int job;
2477   struct pack_desc desc;
2478   print_queue_struct *queue=NULL;
2479   print_status_struct status;
2480
2481   uLevel = SVAL(p,2);
2482   cbBuf = SVAL(p,4);
2483
2484   bzero(&desc,sizeof(desc));
2485   bzero(&status,sizeof(status));
2486
2487   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2488
2489   /* check it's a supported varient */
2490   if (strcmp(str1,"WWrLh") != 0) return False;
2491   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2492
2493   printjob_decode(SVAL(p,0), &snum, &job);
2494
2495   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2496
2497   count = get_printqueue(snum,cnum,&queue,&status);
2498   for (i = 0; i < count; i++) {
2499     if ((queue[i].job & 0xFF) == job) break;
2500   }
2501   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2502   desc.base = *rdata;
2503   desc.buflen = mdrcnt;
2504
2505   if (init_package(&desc,1,0)) {
2506     if (i < count) {
2507       fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
2508       *rdata_len = desc.usedlen;
2509     }
2510     else {
2511       desc.errcode = NERR_JobNotFound;
2512       *rdata_len = 0;
2513     }
2514   }
2515
2516   *rparam_len = 6;
2517   *rparam = REALLOC(*rparam,*rparam_len);
2518   SSVALS(*rparam,0,desc.errcode);
2519   SSVAL(*rparam,2,0);
2520   SSVAL(*rparam,4,desc.neededlen);
2521
2522   if (queue) free(queue);
2523
2524   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2525   return(True);
2526 }
2527
2528 static BOOL api_WPrintJobEnumerate(int cnum,uint16 vuid, char *param,char *data,
2529                                    int mdrcnt,int mprcnt,
2530                                    char **rdata,char **rparam,
2531                                    int *rdata_len,int *rparam_len)
2532 {
2533   char *str1 = param+2;
2534   char *str2 = skip_string(str1,1);
2535   char *p = skip_string(str2,1);
2536   char* name = p;
2537   int uLevel,cbBuf;
2538   int count;
2539   int i, succnt=0;
2540   int snum;
2541   struct pack_desc desc;
2542   print_queue_struct *queue=NULL;
2543   print_status_struct status;
2544
2545   bzero(&desc,sizeof(desc));
2546   bzero(&status,sizeof(status));
2547
2548   p = skip_string(p,1);
2549   uLevel = SVAL(p,0);
2550   cbBuf = SVAL(p,2);
2551
2552   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2553
2554   /* check it's a supported varient */
2555   if (strcmp(str1,"zWrLeh") != 0) return False;
2556   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2557   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2558
2559   snum = lp_servicenumber(name);
2560   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2561     int pnum = lp_servicenumber(PRINTERS_NAME);
2562     if (pnum >= 0) {
2563       lp_add_printer(name,pnum);
2564       snum = lp_servicenumber(name);
2565     }
2566   }
2567
2568   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2569
2570   count = get_printqueue(snum,cnum,&queue,&status);
2571   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2572   desc.base = *rdata;
2573   desc.buflen = mdrcnt;
2574
2575   if (init_package(&desc,count,0)) {
2576     succnt = 0;
2577     for (i = 0; i < count; i++) {
2578       fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
2579       if (desc.errcode == NERR_Success) succnt = i+1;
2580     }
2581   }
2582
2583   *rdata_len = desc.usedlen;
2584
2585   *rparam_len = 8;
2586   *rparam = REALLOC(*rparam,*rparam_len);
2587   SSVALS(*rparam,0,desc.errcode);
2588   SSVAL(*rparam,2,0);
2589   SSVAL(*rparam,4,succnt);
2590   SSVAL(*rparam,6,count);
2591
2592   if (queue) free(queue);
2593
2594   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2595   return(True);
2596 }
2597
2598 static int check_printdest_info(struct pack_desc* desc,
2599                                 int uLevel, char* id)
2600 {
2601   desc->subformat = NULL;
2602   switch( uLevel ) {
2603   case 0: desc->format = "B9"; break;
2604   case 1: desc->format = "B9B21WWzW"; break;
2605   case 2: desc->format = "z"; break;
2606   case 3: desc->format = "zzzWWzzzWW"; break;
2607   default: return False;
2608   }
2609   if (strcmp(desc->format,id) != 0) return False;
2610   return True;
2611 }
2612
2613 static void fill_printdest_info(int cnum, int snum, int uLevel,
2614                                 struct pack_desc* desc)
2615 {
2616   char buf[100];
2617   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2618   buf[sizeof(buf)-1] = 0;
2619   strupper(buf);
2620   if (uLevel <= 1) {
2621     PACKS(desc,"B9",buf);       /* szName */
2622     if (uLevel == 1) {
2623       PACKS(desc,"B21","");     /* szUserName */
2624       PACKI(desc,"W",0);                /* uJobId */
2625       PACKI(desc,"W",0);                /* fsStatus */
2626       PACKS(desc,"z","");       /* pszStatus */
2627       PACKI(desc,"W",0);                /* time */
2628     }
2629   }
2630   if (uLevel == 2 || uLevel == 3) {
2631     PACKS(desc,"z",buf);                /* pszPrinterName */
2632     if (uLevel == 3) {
2633       PACKS(desc,"z","");       /* pszUserName */
2634       PACKS(desc,"z","");       /* pszLogAddr */
2635       PACKI(desc,"W",0);                /* uJobId */
2636       PACKI(desc,"W",0);                /* fsStatus */
2637       PACKS(desc,"z","");       /* pszStatus */
2638       PACKS(desc,"z","");       /* pszComment */
2639       PACKS(desc,"z","NULL"); /* pszDrivers */
2640       PACKI(desc,"W",0);                /* time */
2641       PACKI(desc,"W",0);                /* pad1 */
2642     }
2643   }
2644 }
2645
2646 static BOOL api_WPrintDestGetInfo(int cnum,uint16 vuid, char *param,char *data,
2647                                   int mdrcnt,int mprcnt,
2648                                   char **rdata,char **rparam,
2649                                   int *rdata_len,int *rparam_len)
2650 {
2651   char *str1 = param+2;
2652   char *str2 = skip_string(str1,1);
2653   char *p = skip_string(str2,1);
2654   char* PrinterName = p;
2655   int uLevel,cbBuf;
2656   struct pack_desc desc;
2657   int snum;
2658
2659   bzero(&desc,sizeof(desc));
2660
2661   p = skip_string(p,1);
2662   uLevel = SVAL(p,0);
2663   cbBuf = SVAL(p,2);
2664
2665   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2666
2667   /* check it's a supported varient */
2668   if (strcmp(str1,"zWrLh") != 0) return False;
2669   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2670
2671   snum = lp_servicenumber(PrinterName);
2672   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2673     int pnum = lp_servicenumber(PRINTERS_NAME);
2674     if (pnum >= 0) {
2675       lp_add_printer(PrinterName,pnum);
2676       snum = lp_servicenumber(PrinterName);
2677     }
2678   }
2679
2680   if (snum < 0) {
2681     *rdata_len = 0;
2682     desc.errcode = NERR_DestNotFound;
2683     desc.neededlen = 0;
2684   }
2685   else {
2686     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2687     desc.base = *rdata;
2688     desc.buflen = mdrcnt;
2689     if (init_package(&desc,1,0)) {
2690       fill_printdest_info(cnum,snum,uLevel,&desc);
2691     }
2692     *rdata_len = desc.usedlen;
2693   }
2694
2695   *rparam_len = 6;
2696   *rparam = REALLOC(*rparam,*rparam_len);
2697   SSVALS(*rparam,0,desc.errcode);
2698   SSVAL(*rparam,2,0);
2699   SSVAL(*rparam,4,desc.neededlen);
2700
2701   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2702   return(True);
2703 }
2704
2705 static BOOL api_WPrintDestEnum(int cnum,uint16 vuid, char *param,char *data,
2706                                int mdrcnt,int mprcnt,
2707                                char **rdata,char **rparam,
2708                                int *rdata_len,int *rparam_len)
2709 {
2710   char *str1 = param+2;
2711   char *str2 = skip_string(str1,1);
2712   char *p = skip_string(str2,1);
2713   int uLevel,cbBuf;
2714   int queuecnt;
2715   int i, n, succnt=0;
2716   struct pack_desc desc;
2717   int services = lp_numservices();
2718
2719   bzero(&desc,sizeof(desc));
2720
2721   uLevel = SVAL(p,0);
2722   cbBuf = SVAL(p,2);
2723
2724   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2725
2726   /* check it's a supported varient */
2727   if (strcmp(str1,"WrLeh") != 0) return False;
2728   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2729
2730   queuecnt = 0;
2731   for (i = 0; i < services; i++)
2732     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2733       queuecnt++;
2734
2735   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2736   desc.base = *rdata;
2737   desc.buflen = mdrcnt;
2738   if (init_package(&desc,queuecnt,0)) {    
2739     succnt = 0;
2740     n = 0;
2741     for (i = 0; i < services; i++) {
2742       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2743         fill_printdest_info(cnum,i,uLevel,&desc);
2744         n++;
2745         if (desc.errcode == NERR_Success) succnt = n;
2746       }
2747     }
2748   }
2749
2750   *rdata_len = desc.usedlen;
2751
2752   *rparam_len = 8;
2753   *rparam = REALLOC(*rparam,*rparam_len);
2754   SSVALS(*rparam,0,desc.errcode);
2755   SSVAL(*rparam,2,0);
2756   SSVAL(*rparam,4,succnt);
2757   SSVAL(*rparam,6,queuecnt);
2758
2759   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2760   return(True);
2761 }
2762
2763 static BOOL api_WPrintDriverEnum(int cnum,uint16 vuid, char *param,char *data,
2764                                  int mdrcnt,int mprcnt,
2765                                  char **rdata,char **rparam,
2766                                  int *rdata_len,int *rparam_len)
2767 {
2768   char *str1 = param+2;
2769   char *str2 = skip_string(str1,1);
2770   char *p = skip_string(str2,1);
2771   int uLevel,cbBuf;
2772   int succnt;
2773   struct pack_desc desc;
2774
2775   bzero(&desc,sizeof(desc));
2776
2777   uLevel = SVAL(p,0);
2778   cbBuf = SVAL(p,2);
2779
2780   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2781
2782   /* check it's a supported varient */
2783   if (strcmp(str1,"WrLeh") != 0) return False;
2784   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2785
2786   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2787   desc.base = *rdata;
2788   desc.buflen = mdrcnt;
2789   if (init_package(&desc,1,0)) {
2790     PACKS(&desc,"B41","NULL");
2791   }
2792
2793   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2794
2795   *rdata_len = desc.usedlen;
2796
2797   *rparam_len = 8;
2798   *rparam = REALLOC(*rparam,*rparam_len);
2799   SSVALS(*rparam,0,desc.errcode);
2800   SSVAL(*rparam,2,0);
2801   SSVAL(*rparam,4,succnt);
2802   SSVAL(*rparam,6,1);
2803
2804   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2805   return(True);
2806 }
2807
2808 static BOOL api_WPrintQProcEnum(int cnum,uint16 vuid, char *param,char *data,
2809                                 int mdrcnt,int mprcnt,
2810                                 char **rdata,char **rparam,
2811                                 int *rdata_len,int *rparam_len)
2812 {
2813   char *str1 = param+2;
2814   char *str2 = skip_string(str1,1);
2815   char *p = skip_string(str2,1);
2816   int uLevel,cbBuf;
2817   int succnt;
2818   struct pack_desc desc;
2819
2820   bzero(&desc,sizeof(desc));
2821
2822   uLevel = SVAL(p,0);
2823   cbBuf = SVAL(p,2);
2824
2825   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
2826
2827   /* check it's a supported varient */
2828   if (strcmp(str1,"WrLeh") != 0) return False;
2829   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
2830
2831   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2832   desc.base = *rdata;
2833   desc.buflen = mdrcnt;
2834   desc.format = str2;
2835   if (init_package(&desc,1,0)) {
2836     PACKS(&desc,"B13","lpd");
2837   }
2838
2839   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2840
2841   *rdata_len = desc.usedlen;
2842
2843   *rparam_len = 8;
2844   *rparam = REALLOC(*rparam,*rparam_len);
2845   SSVALS(*rparam,0,desc.errcode);
2846   SSVAL(*rparam,2,0);
2847   SSVAL(*rparam,4,succnt);
2848   SSVAL(*rparam,6,1);
2849
2850   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
2851   return(True);
2852 }
2853
2854 static BOOL api_WPrintPortEnum(int cnum,uint16 vuid, char *param,char *data,
2855                                int mdrcnt,int mprcnt,
2856                                char **rdata,char **rparam,
2857                                int *rdata_len,int *rparam_len)
2858 {
2859   char *str1 = param+2;
2860   char *str2 = skip_string(str1,1);
2861   char *p = skip_string(str2,1);
2862   int uLevel,cbBuf;
2863   int succnt;
2864   struct pack_desc desc;
2865
2866   bzero(&desc,sizeof(desc));
2867
2868   uLevel = SVAL(p,0);
2869   cbBuf = SVAL(p,2);
2870
2871   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
2872
2873   /* check it's a supported varient */
2874   if (strcmp(str1,"WrLeh") != 0) return False;
2875   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
2876
2877   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2878   bzero(&desc,sizeof(desc));
2879   desc.base = *rdata;
2880   desc.buflen = mdrcnt;
2881   desc.format = str2;
2882   if (init_package(&desc,1,0)) {
2883     PACKS(&desc,"B13","lp0");
2884   }
2885
2886   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2887
2888   *rdata_len = desc.usedlen;
2889
2890   *rparam_len = 8;
2891   *rparam = REALLOC(*rparam,*rparam_len);
2892   SSVALS(*rparam,0,desc.errcode);
2893   SSVAL(*rparam,2,0);
2894   SSVAL(*rparam,4,succnt);
2895   SSVAL(*rparam,6,1);
2896
2897   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
2898   return(True);
2899 }
2900
2901
2902 struct
2903 {
2904   char * name;
2905   char * pipe_clnt_name;
2906 #ifdef NTDOMAIN
2907   char * pipe_srv_name;
2908 #endif
2909   int subcommand;
2910   BOOL (*fn) ();
2911 } api_fd_commands [] =
2912   {
2913 #ifdef NTDOMAIN
2914     { "TransactNmPipe",     "lsarpc",   "lsass",        0x26,   api_ntLsarpcTNP },
2915     { "TransactNmPipe",     "samr",     "lsass",        0x26,   api_samrTNP },
2916     { "TransactNmPipe",     "srvsvc",   "lsass",        0x26,   api_srvsvcTNP },
2917     { "TransactNmPipe",     "wkssvc",   "ntsvcs",       0x26,   api_wkssvcTNP },
2918     { "TransactNmPipe",     "NETLOGON", "NETLOGON",     0x26,   api_netlogrpcTNP },
2919     { NULL,                         NULL,       NULL,   -1,     (BOOL (*)())api_Unsupported }
2920 #else
2921     { "TransactNmPipe"  ,       "lsarpc",       0x26,   api_LsarpcTNP },
2922     { NULL,             NULL,           -1,     (BOOL (*)())api_Unsupported }
2923 #endif
2924   };
2925
2926 /****************************************************************************
2927   handle remote api calls delivered to a named pipe already opened.
2928   ****************************************************************************/
2929 static int api_fd_reply(int cnum,uint16 vuid,char *outbuf,
2930                         uint16 *setup,char *data,char *params,
2931                         int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
2932 {
2933   char *rdata = NULL;
2934   char *rparam = NULL;
2935   int rdata_len = 0;
2936   int rparam_len = 0;
2937
2938   BOOL reply    = False;
2939   BOOL bind_req = False;
2940   BOOL set_nphs = False;
2941
2942   int i;
2943   int fd;
2944   int subcommand;
2945   char *pipe_name;
2946   
2947   DEBUG(5,("api_fd_reply\n"));
2948   /* First find out the name of this file. */
2949   if (suwcnt != 2)
2950     {
2951       DEBUG(0,("Unexpected named pipe transaction.\n"));
2952       return(-1);
2953     }
2954   
2955   /* Get the file handle and hence the file name. */
2956   fd = setup[1];
2957   subcommand = setup[0];
2958   pipe_name = get_rpc_pipe_hnd_name(fd);
2959
2960   if (pipe_name == NULL)
2961   {
2962     DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", fd));
2963   }
2964
2965   DEBUG(3,("Got API command %d on pipe %s (fd %x)",
2966             subcommand, pipe_name, fd));
2967   DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d,cnum=%d,vuid=%d)\n",
2968            tdscnt,tpscnt,mdrcnt,mprcnt,cnum,vuid));
2969   
2970   for (i = 0; api_fd_commands[i].name; i++)
2971   {
2972     if (strequal(api_fd_commands[i].pipe_clnt_name, pipe_name) &&
2973             api_fd_commands[i].subcommand == subcommand &&
2974             api_fd_commands[i].fn)
2975     {
2976           DEBUG(3,("Doing %s\n", api_fd_commands[i].name));
2977           break;
2978     }
2979   }
2980   
2981   rdata  = (char *)malloc(1024); if (rdata ) bzero(rdata ,1024);
2982   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
2983   
2984 #ifdef NTDOMAIN
2985   /* RPC Pipe command 0x26. */
2986   if (data != NULL && api_fd_commands[i].subcommand == 0x26)
2987   {
2988     RPC_HDR hdr;
2989
2990     /* process the rpc header */
2991     char *q = smb_io_rpc_hdr(True, &hdr, data, data, 4, 0);
2992     
2993         /* bind request received */
2994     if ((bind_req = ((q != NULL) && (hdr.pkt_type == RPC_BIND))))
2995     {
2996       RPC_HDR_RB hdr_rb;
2997
2998       /* decode the bind request */
2999       char *p = smb_io_rpc_hdr_rb(True, &hdr_rb, q, data, 4, 0);
3000
3001       if ((bind_req = (p != NULL)))
3002       {
3003         RPC_HDR_BA hdr_ba;
3004         fstring ack_pipe_name;
3005
3006         /* name has to be \PIPE\xxxxx */
3007         strcpy(ack_pipe_name, "\\PIPE\\");
3008         strcat(ack_pipe_name, api_fd_commands[i].pipe_srv_name);
3009
3010         /* make a bind acknowledgement */
3011         make_rpc_hdr_ba(&hdr_ba,
3012                hdr_rb.bba.max_tsize, hdr_rb.bba.max_rsize, hdr_rb.bba.assoc_gid,
3013                ack_pipe_name,
3014                0x1, 0x0, 0x0,
3015                &(hdr_rb.transfer));
3016
3017         p = smb_io_rpc_hdr_ba(False, &hdr_ba, rdata + 0x10, rdata, 4, 0);
3018
3019                 rdata_len = PTR_DIFF(p, rdata);
3020
3021         make_rpc_hdr(&hdr, RPC_BINDACK, 0x0, hdr.call_id, rdata_len);
3022
3023         p = smb_io_rpc_hdr(False, &hdr, rdata, rdata, 4, 0);
3024         
3025         reply = (p != NULL);
3026       }
3027     }
3028   }
3029 #endif
3030
3031   /* Set Named Pipe Handle state */
3032   if (subcommand == 0x1)
3033   {
3034     set_nphs = True;
3035     reply = api_LsarpcSNPHS(fd, cnum, params);
3036   }
3037
3038   if (!bind_req && !set_nphs)
3039   {
3040     DEBUG(10,("calling api_fd_command\n"));
3041
3042     reply = api_fd_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
3043                                 &rdata,&rparam,&rdata_len,&rparam_len);
3044     DEBUG(10,("called api_fd_command\n"));
3045   }
3046
3047   if (rdata_len > mdrcnt || rparam_len > mprcnt)
3048   {
3049     reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
3050                            &rdata,&rparam,&rdata_len,&rparam_len);
3051   }
3052   
3053   /* if we get False back then it's actually unsupported */
3054   if (!reply)
3055   {
3056     api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
3057                     &rdata,&rparam,&rdata_len,&rparam_len);
3058   }
3059   
3060   /* now send the reply */
3061   send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
3062   
3063   if (rdata ) free(rdata );
3064   if (rparam) free(rparam);
3065   
3066   return(-1);
3067 }
3068
3069
3070
3071 /****************************************************************************
3072   the buffer was too small
3073   ****************************************************************************/
3074 static BOOL api_TooSmall(int cnum,uint16 vuid, char *param,char *data,
3075                          int mdrcnt,int mprcnt,
3076                          char **rdata,char **rparam,
3077                          int *rdata_len,int *rparam_len)
3078 {
3079   *rparam_len = MIN(*rparam_len,mprcnt);
3080   *rparam = REALLOC(*rparam,*rparam_len);
3081
3082   *rdata_len = 0;
3083
3084   SSVAL(*rparam,0,NERR_BufTooSmall);
3085
3086   DEBUG(3,("Supplied buffer too small in API command\n"));
3087
3088   return(True);
3089 }
3090
3091
3092 /****************************************************************************
3093   the request is not supported
3094   ****************************************************************************/
3095 static BOOL api_Unsupported(int cnum,uint16 vuid, char *param,char *data,
3096                             int mdrcnt,int mprcnt,
3097                             char **rdata,char **rparam,
3098                             int *rdata_len,int *rparam_len)
3099 {
3100   *rparam_len = 4;
3101   *rparam = REALLOC(*rparam,*rparam_len);
3102
3103   *rdata_len = 0;
3104
3105   SSVAL(*rparam,0,NERR_notsupported);
3106   SSVAL(*rparam,2,0);           /* converter word */
3107
3108   DEBUG(3,("Unsupported API command\n"));
3109
3110   return(True);
3111 }
3112
3113
3114
3115
3116 struct
3117 {
3118   char *name;
3119   int id;
3120   BOOL (*fn)();
3121   int flags;
3122 } api_commands[] = {
3123   {"RNetShareEnum",     0,      (BOOL (*)())api_RNetShareEnum,0},
3124   {"RNetShareGetInfo",  1,      (BOOL (*)())api_RNetShareGetInfo,0},
3125   {"RNetServerGetInfo", 13,     (BOOL (*)())api_RNetServerGetInfo,0},
3126   {"RNetUserGetInfo",   56,     (BOOL (*)())api_RNetUserGetInfo,0},
3127   {"NetUserGetGroups",  59,     (BOOL (*)())api_NetUserGetGroups,0},
3128   {"NetWkstaGetInfo",   63,     (BOOL (*)())api_NetWkstaGetInfo,0},
3129   {"DosPrintQEnum",     69,     (BOOL (*)())api_DosPrintQEnum,0},
3130   {"DosPrintQGetInfo",  70,     (BOOL (*)())api_DosPrintQGetInfo,0},
3131   {"WPrintJobEnumerate",76,     (BOOL (*)())api_WPrintJobEnumerate,0},
3132   {"WPrintJobGetInfo",  77,     (BOOL (*)())api_WPrintJobGetInfo,0},
3133   {"RDosPrintJobDel",   81,     (BOOL (*)())api_RDosPrintJobDel,0},
3134   {"RDosPrintJobPause", 82,     (BOOL (*)())api_RDosPrintJobDel,0},
3135   {"RDosPrintJobResume",83,     (BOOL (*)())api_RDosPrintJobDel,0},
3136   {"WPrintDestEnum",    84,     (BOOL (*)())api_WPrintDestEnum,0},
3137   {"WPrintDestGetInfo", 85,     (BOOL (*)())api_WPrintDestGetInfo,0},
3138   {"NetRemoteTOD",      91,     (BOOL (*)())api_NetRemoteTOD,0},
3139   {"WPrintQueuePurge",  103,    (BOOL (*)())api_WPrintQueuePurge,0},
3140   {"NetServerEnum",     104,    (BOOL (*)())api_RNetServerEnum,0},
3141   {"WAccessGetUserPerms",105,   (BOOL (*)())api_WAccessGetUserPerms,0},
3142   {"SetUserPassword",   115,    (BOOL (*)())api_SetUserPassword,0},
3143   {"WWkstaUserLogon",   132,    (BOOL (*)())api_WWkstaUserLogon,0},
3144   {"PrintJobInfo",      147,    (BOOL (*)())api_PrintJobInfo,0},
3145   {"WPrintDriverEnum",  205,    (BOOL (*)())api_WPrintDriverEnum,0},
3146   {"WPrintQProcEnum",   206,    (BOOL (*)())api_WPrintQProcEnum,0},
3147   {"WPrintPortEnum",    207,    (BOOL (*)())api_WPrintPortEnum,0},
3148   {NULL,                -1,     (BOOL (*)())api_Unsupported,0}};
3149
3150
3151 /****************************************************************************
3152   handle remote api calls
3153   ****************************************************************************/
3154 static int api_reply(int cnum,uint16 vuid,char *outbuf,char *data,char *params,
3155                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3156 {
3157   int api_command = SVAL(params,0);
3158   char *rdata = NULL;
3159   char *rparam = NULL;
3160   int rdata_len = 0;
3161   int rparam_len = 0;
3162   BOOL reply=False;
3163   int i;
3164
3165   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3166            api_command,params+2,skip_string(params+2,1),
3167            tdscnt,tpscnt,mdrcnt,mprcnt));
3168
3169   for (i=0;api_commands[i].name;i++)
3170     if (api_commands[i].id == api_command && api_commands[i].fn)
3171       {
3172         DEBUG(3,("Doing %s\n",api_commands[i].name));
3173         break;
3174       }
3175
3176   rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
3177   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
3178
3179   reply = api_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
3180                              &rdata,&rparam,&rdata_len,&rparam_len);
3181
3182
3183   if (rdata_len > mdrcnt ||
3184       rparam_len > mprcnt)
3185     {
3186       reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
3187                            &rdata,&rparam,&rdata_len,&rparam_len);
3188     }
3189             
3190
3191   /* if we get False back then it's actually unsupported */
3192   if (!reply)
3193     api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
3194                     &rdata,&rparam,&rdata_len,&rparam_len);
3195
3196       
3197
3198   /* now send the reply */
3199   send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
3200
3201   if (rdata)
3202     free(rdata);
3203   if (rparam)
3204     free(rparam);
3205   
3206   return(-1);
3207 }
3208
3209 /****************************************************************************
3210   handle named pipe commands
3211   ****************************************************************************/
3212 static int named_pipe(int cnum,uint16 vuid, char *outbuf,char *name,
3213                       uint16 *setup,char *data,char *params,
3214                       int suwcnt,int tdscnt,int tpscnt,
3215                       int msrcnt,int mdrcnt,int mprcnt)
3216 {
3217         DEBUG(3,("named pipe command on <%s> name\n", name));
3218
3219         if (strequal(name,"LANMAN"))
3220         {
3221                 return api_reply(cnum,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
3222         }
3223
3224         if (strlen(name) < 1)
3225         {
3226                 return api_fd_reply(cnum,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
3227         }
3228
3229         if (setup)
3230         {
3231                 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
3232         }
3233
3234         return 0;
3235 }
3236
3237
3238 /****************************************************************************
3239   reply to a SMBtrans
3240   ****************************************************************************/
3241 int reply_trans(char *inbuf,char *outbuf, int size, int bufsize)
3242 {
3243   fstring name;
3244
3245   char *data=NULL,*params=NULL;
3246   uint16 *setup=NULL;
3247
3248   int outsize = 0;
3249   int cnum = SVAL(inbuf,smb_tid);
3250   uint16 vuid = SVAL(inbuf,smb_uid);
3251
3252   int tpscnt = SVAL(inbuf,smb_vwv0);
3253   int tdscnt = SVAL(inbuf,smb_vwv1);
3254   int mprcnt = SVAL(inbuf,smb_vwv2);
3255   int mdrcnt = SVAL(inbuf,smb_vwv3);
3256   int msrcnt = CVAL(inbuf,smb_vwv4);
3257   BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
3258   BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
3259   int pscnt = SVAL(inbuf,smb_vwv9);
3260   int psoff = SVAL(inbuf,smb_vwv10);
3261   int dscnt = SVAL(inbuf,smb_vwv11);
3262   int dsoff = SVAL(inbuf,smb_vwv12);
3263   int suwcnt = CVAL(inbuf,smb_vwv13);
3264
3265   bzero(name, sizeof(name));
3266   fstrcpy(name,smb_buf(inbuf));
3267
3268   if (dscnt > tdscnt || pscnt > tpscnt) {
3269           exit_server("invalid trans parameters\n");
3270   }
3271   
3272   if (tdscnt)
3273     {
3274       data = (char *)malloc(tdscnt);
3275       memcpy(data,smb_base(inbuf)+dsoff,dscnt);
3276     }
3277   if (tpscnt)
3278     {
3279       params = (char *)malloc(tpscnt);
3280       memcpy(params,smb_base(inbuf)+psoff,pscnt);
3281     }
3282
3283   if (suwcnt)
3284     {
3285       int i;
3286       setup = (uint16 *)malloc(suwcnt*sizeof(setup[0]));
3287       for (i=0;i<suwcnt;i++)
3288         setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
3289     }
3290
3291
3292   if (pscnt < tpscnt || dscnt < tdscnt)
3293     {
3294       /* We need to send an interim response then receive the rest
3295          of the parameter/data bytes */
3296       outsize = set_message(outbuf,0,0,True);
3297       show_msg(outbuf);
3298       send_smb(Client,outbuf);
3299     }
3300
3301   /* receive the rest of the trans packet */
3302   while (pscnt < tpscnt || dscnt < tdscnt)
3303     {
3304       BOOL ret;
3305       int pcnt,poff,dcnt,doff,pdisp,ddisp;
3306       
3307       ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,SMB_SECONDARY_WAIT);
3308
3309       if ((ret && (CVAL(inbuf, smb_com) != SMBtrans)) || !ret)
3310         {
3311           if(ret)
3312             DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
3313           else
3314             DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
3315               (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
3316           if (params) free(params);
3317           if (data) free(data);
3318           if (setup) free(setup);
3319           return(ERROR(ERRSRV,ERRerror));
3320         }
3321
3322       show_msg(inbuf);
3323       
3324       tpscnt = SVAL(inbuf,smb_vwv0);
3325       tdscnt = SVAL(inbuf,smb_vwv1);
3326
3327       pcnt = SVAL(inbuf,smb_vwv2);
3328       poff = SVAL(inbuf,smb_vwv3);
3329       pdisp = SVAL(inbuf,smb_vwv4);
3330       
3331       dcnt = SVAL(inbuf,smb_vwv5);
3332       doff = SVAL(inbuf,smb_vwv6);
3333       ddisp = SVAL(inbuf,smb_vwv7);
3334       
3335       pscnt += pcnt;
3336       dscnt += dcnt;
3337
3338       if (dscnt > tdscnt || pscnt > tpscnt) {
3339               exit_server("invalid trans parameters\n");
3340       }
3341
3342       if (pcnt)
3343         memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
3344       if (dcnt)
3345         memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);      
3346     }
3347
3348
3349   DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt));
3350
3351   if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0)
3352   {
3353     DEBUG(5,("calling named_pipe\n"));
3354     outsize = named_pipe(cnum,vuid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
3355                          suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
3356   }
3357   else
3358   {
3359     DEBUG(3,("invalid pipe name\n"));
3360     outsize = 0;
3361   }
3362
3363
3364   if (data) free(data);
3365   if (params) free(params);
3366   if (setup) free(setup);
3367
3368   if (close_on_completion)
3369     close_cnum(cnum,vuid);
3370
3371   if (one_way)
3372     return(-1);
3373   
3374   if (outsize == 0)
3375     return(ERROR(ERRSRV,ERRnosupport));
3376
3377   return(outsize);
3378 }