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