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