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