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