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