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