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