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