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