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