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