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