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