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