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