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