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