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