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