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