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