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