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