1) updated ipc.c NetUserGetInfo - load \\%L\%U instead of \\%L\HOMES
[samba.git] / source3 / smbd / ipc.c
1
2 /* 
3    Unix SMB/Netbios implementation.
4    Version 1.9.
5    Inter-process communication and named pipe handling
6    Copyright (C) Andrew Tridgell 1992-1995
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    */
22 /*
23    This file handles the named pipe and mailslot calls
24    in the SMBtrans protocol
25    */
26
27 #include "includes.h"
28
29 #ifdef CHECK_TYPES
30 #undef CHECK_TYPES
31 #endif
32 #define CHECK_TYPES 0
33
34 extern int DEBUGLEVEL;
35 extern int max_send;
36 extern files_struct Files[];
37 extern connection_struct Connections[];
38
39 extern fstring local_machine;
40
41 #define NERR_Success 0
42 #define NERR_badpass 86
43 #define NERR_notsupported 50
44
45 #define NERR_BASE (2100)
46 #define NERR_BufTooSmall (NERR_BASE+23)
47 #define NERR_JobNotFound (NERR_BASE+51)
48 #define NERR_DestNotFound (NERR_BASE+52)
49 #define ERROR_INVALID_LEVEL 124
50 #define ERROR_MORE_DATA 234
51
52 #define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
53
54 #define ACCESS_READ 0x01
55 #define ACCESS_WRITE 0x02
56 #define ACCESS_CREATE 0x04
57
58 #define SHPWLEN 8               /* share password length */
59 #define NNLEN 12                /* 8.3 net name length */
60 #define SNLEN 15                /* service name length */
61 #define QNLEN 12                /* queue name maximum length */
62
63 #define MAJOR_VERSION 4
64 #define MINOR_VERSION 1
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, const 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",((snum%0xFF)<<8) | (queue->job%0xFF)); /* 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
776   strcpy(fname,lp_lockdir());
777   trim_string(fname,NULL,"/");
778   strcat(fname,"/");
779   strcat(fname,SERVER_LIST);
780
781   f = fopen(fname,"r");
782
783   if (!f) {
784     DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
785     return(0);
786   }
787
788   /* request for everything is code for request all servers */
789   if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
790
791   DEBUG(4,("Servertype search: %8x\n",servertype));
792
793   while (!feof(f))
794   {
795     fstring stype;
796     struct srv_info_struct *s;
797     char *ptr = line;
798     BOOL ok = True;
799     *ptr = 0;
800
801     fgets(line,sizeof(line)-1,f);
802     if (!*line) continue;
803     
804     if (count == alloced) {
805       alloced += 10;
806       (*servers) = (struct srv_info_struct *)
807         Realloc(*servers,sizeof(**servers)*alloced);
808       if (!(*servers)) return(0);
809       bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
810     }
811     s = &(*servers)[count];
812     
813     if (!next_token(&ptr,s->name   , NULL)) continue;
814     if (!next_token(&ptr,stype     , NULL)) continue;
815     if (!next_token(&ptr,s->comment, NULL)) continue;
816     if (!next_token(&ptr,s->domain , NULL)) {
817       /* this allows us to cope with an old nmbd */
818       strcpy(s->domain,lp_workgroup()); 
819     }
820     
821     if (sscanf(stype,"%X",&s->type) != 1) { 
822       DEBUG(4,("r:host file ")); 
823       ok = False; 
824     }
825     
826     /* doesn't match up: don't want it */
827     if (!(servertype & s->type)) { 
828       DEBUG(4,("r:serv type ")); 
829       ok = False; 
830     }
831     
832     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
833         (s->type & SV_TYPE_DOMAIN_ENUM))
834       {
835         DEBUG(4,("s: dom mismatch "));
836         ok = False;
837       }
838     
839     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
840       {
841         ok = False;
842       }
843     
844     if (ok)
845       {
846         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
847                  s->name, s->type, s->comment, s->domain));
848         
849         s->server_added = True;
850         count++;
851       }
852     else
853       {
854         DEBUG(4,("%20s %8x %25s %15s\n",
855                  s->name, s->type, s->comment, s->domain));
856       }
857   }
858   
859   fclose(f);
860   return(count);
861 }
862
863
864 /*******************************************************************
865   fill in a server info structure
866   ******************************************************************/
867 static int fill_srv_info(struct srv_info_struct *service, 
868                          int uLevel, char **buf, int *buflen, 
869                          char **stringbuf, int *stringspace, char *baseaddr)
870 {
871   int struct_len;
872   char* p;
873   char* p2;
874   int l2;
875   int len;
876  
877   switch (uLevel) {
878   case 0: struct_len = 16; break;
879   case 1: struct_len = 26; break;
880   default: return -1;
881   }  
882  
883   if (!buf)
884     {
885       len = 0;
886       switch (uLevel) 
887         {
888         case 1:
889           len = strlen(service->comment)+1;
890           break;
891         }
892
893       if (buflen) *buflen = struct_len;
894       if (stringspace) *stringspace = len;
895       return struct_len + len;
896     }
897   
898   len = struct_len;
899   p = *buf;
900   if (*buflen < struct_len) return -1;
901   if (stringbuf)
902     {
903       p2 = *stringbuf;
904       l2 = *stringspace;
905     }
906   else
907     {
908       p2 = p + struct_len;
909       l2 = *buflen - struct_len;
910     }
911   if (!baseaddr) baseaddr = p;
912   
913   switch (uLevel)
914     {
915     case 0:
916       StrnCpy(p,service->name,15);
917       break;
918
919     case 1:
920       StrnCpy(p,service->name,15);
921       SIVAL(p,18,service->type);
922       SIVAL(p,22,PTR_DIFF(p2,baseaddr));
923       len += CopyAndAdvance(&p2,service->comment,&l2);
924       break;
925     }
926
927   if (stringbuf)
928     {
929       *buf = p + struct_len;
930       *buflen -= struct_len;
931       *stringbuf = p2;
932       *stringspace = l2;
933     }
934   else
935     {
936       *buf = p2;
937       *buflen -= len;
938     }
939   return len;
940 }
941
942
943 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
944 {
945   return(strcmp(s1->name,s2->name));
946 }
947
948 /****************************************************************************
949   view list of servers available (or possibly domains). The info is
950   extracted from lists saved by nmbd on the local host
951   ****************************************************************************/
952 static BOOL api_RNetServerEnum(int cnum, uint16 vuid, char *param, char *data,
953                                int mdrcnt, int mprcnt, char **rdata, 
954                                char **rparam, int *rdata_len, int *rparam_len)
955 {
956   char *str1 = param+2;
957   char *str2 = skip_string(str1,1);
958   char *p = skip_string(str2,1);
959   int uLevel = SVAL(p,0);
960   int buf_len = SVAL(p,2);
961   uint32 servertype = IVAL(p,4);
962   char *p2;
963   int data_len, fixed_len, string_len;
964   int f_len, s_len;
965   struct srv_info_struct *servers=NULL;
966   int counted=0,total=0;
967   int i,missed;
968   fstring domain;
969   BOOL domain_request;
970   BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY;
971
972   if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
973
974   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
975
976   p += 8;
977
978   if (!prefix_ok(str1,"WrLehD")) return False;
979   if (!check_server_info(uLevel,str2)) return False;
980   
981   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
982   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
983   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
984
985   if (strcmp(str1, "WrLehDz") == 0) {
986     StrnCpy(domain, p, sizeof(fstring)-1);
987   } else {
988     StrnCpy(domain, lp_workgroup(), sizeof(fstring)-1);    
989   }
990
991   if (lp_browse_list())
992     total = get_server_info(servertype,&servers,domain);
993
994   data_len = fixed_len = string_len = 0;
995   missed = 0;
996
997   qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
998
999   {
1000     char *lastname=NULL;
1001
1002     for (i=0;i<total;i++)
1003     {
1004       struct srv_info_struct *s = &servers[i];
1005       if (lastname && strequal(lastname,s->name)) continue;
1006       lastname = s->name;
1007       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1008       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1009                s->name, s->type, s->comment, s->domain));
1010       
1011       if (data_len <= buf_len) {
1012           counted++;
1013           fixed_len += f_len;
1014           string_len += s_len;
1015       } else {
1016         missed++;
1017       }
1018     }
1019   }
1020
1021   *rdata_len = fixed_len + string_len;
1022   *rdata = REALLOC(*rdata,*rdata_len);
1023   bzero(*rdata,*rdata_len);
1024   
1025   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1026   p = *rdata;
1027   f_len = fixed_len;
1028   s_len = string_len;
1029
1030   {
1031     char *lastname=NULL;
1032     int count2 = counted;
1033     for (i = 0; i < total && count2;i++)
1034       {
1035         struct srv_info_struct *s = &servers[i];
1036         if (lastname && strequal(lastname,s->name)) continue;
1037         lastname = s->name;
1038         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1039         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1040                  s->name, s->type, s->comment, s->domain));
1041         count2--;
1042       }
1043   }
1044   
1045   *rparam_len = 8;
1046   *rparam = REALLOC(*rparam,*rparam_len);
1047   SSVAL(*rparam,0,NERR_Success);
1048   SSVAL(*rparam,2,0);
1049   SSVAL(*rparam,4,counted);
1050   SSVAL(*rparam,6,counted+missed);
1051
1052   if (servers) free(servers);
1053
1054   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1055            domain,uLevel,counted,counted+missed));
1056
1057   return(True);
1058 }
1059
1060
1061 /****************************************************************************
1062   get info about a share
1063   ****************************************************************************/
1064 static BOOL check_share_info(int uLevel, char* id)
1065 {
1066   switch( uLevel ) {
1067   case 0:
1068     if (strcmp(id,"B13") != 0) return False;
1069     break;
1070   case 1:
1071     if (strcmp(id,"B13BWz") != 0) return False;
1072     break;
1073   case 2:
1074     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1075     break;
1076   case 91:
1077     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1078     break;
1079   default: return False;
1080   }
1081   return True;
1082 }
1083
1084 static int fill_share_info(int cnum, int snum, int uLevel,
1085                            char** buf, int* buflen,
1086                            char** stringbuf, int* stringspace, char* baseaddr)
1087 {
1088   int struct_len;
1089   char* p;
1090   char* p2;
1091   int l2;
1092   int len;
1093  
1094   switch( uLevel ) {
1095   case 0: struct_len = 13; break;
1096   case 1: struct_len = 20; break;
1097   case 2: struct_len = 40; break;
1098   case 91: struct_len = 68; break;
1099   default: return -1;
1100   }
1101   
1102  
1103   if (!buf)
1104     {
1105       len = 0;
1106       if (uLevel > 0) len += StrlenExpanded(cnum,snum,lp_comment(snum));
1107       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1108       if (buflen) *buflen = struct_len;
1109       if (stringspace) *stringspace = len;
1110       return struct_len + len;
1111     }
1112   
1113   len = struct_len;
1114   p = *buf;
1115   if ((*buflen) < struct_len) return -1;
1116   if (stringbuf)
1117     {
1118       p2 = *stringbuf;
1119       l2 = *stringspace;
1120     }
1121   else
1122     {
1123       p2 = p + struct_len;
1124       l2 = (*buflen) - struct_len;
1125     }
1126   if (!baseaddr) baseaddr = p;
1127   
1128   StrnCpy(p,lp_servicename(snum),13);
1129   
1130   if (uLevel > 0)
1131     {
1132       int type;
1133       CVAL(p,13) = 0;
1134       type = STYPE_DISKTREE;
1135       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1136       if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1137       SSVAL(p,14,type);         /* device type */
1138       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1139       len += CopyExpanded(cnum,snum,&p2,lp_comment(snum),&l2);
1140     }
1141   
1142   if (uLevel > 1)
1143     {
1144       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1145       SSVALS(p,22,-1);          /* max uses */
1146       SSVAL(p,24,1); /* current uses */
1147       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1148       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1149       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1150     }
1151   
1152   if (uLevel > 2)
1153     {
1154       memset(p+40,0,SHPWLEN+2);
1155       SSVAL(p,50,0);
1156       SIVAL(p,52,0);
1157       SSVAL(p,56,0);
1158       SSVAL(p,58,0);
1159       SIVAL(p,60,0);
1160       SSVAL(p,64,0);
1161       SSVAL(p,66,0);
1162     }
1163        
1164   if (stringbuf)
1165     {
1166       (*buf) = p + struct_len;
1167       (*buflen) -= struct_len;
1168       (*stringbuf) = p2;
1169       (*stringspace) = l2;
1170     }
1171   else
1172     {
1173       (*buf) = p2;
1174       (*buflen) -= len;
1175     }
1176   return len;
1177 }
1178
1179 static BOOL api_RNetShareGetInfo(int cnum,uint16 vuid, char *param,char *data,
1180                                  int mdrcnt,int mprcnt,
1181                                  char **rdata,char **rparam,
1182                                  int *rdata_len,int *rparam_len)
1183 {
1184   char *str1 = param+2;
1185   char *str2 = skip_string(str1,1);
1186   char *netname = skip_string(str2,1);
1187   char *p = skip_string(netname,1);
1188   int uLevel = SVAL(p,0);
1189   int snum = find_service(netname);
1190   
1191   if (snum < 0) return False;
1192   
1193   /* check it's a supported varient */
1194   if (!prefix_ok(str1,"zWrLh")) return False;
1195   if (!check_share_info(uLevel,str2)) return False;
1196  
1197   *rdata = REALLOC(*rdata,mdrcnt);
1198   p = *rdata;
1199   *rdata_len = fill_share_info(cnum,snum,uLevel,&p,&mdrcnt,0,0,0);
1200   if (*rdata_len < 0) return False;
1201  
1202   *rparam_len = 6;
1203   *rparam = REALLOC(*rparam,*rparam_len);
1204   SSVAL(*rparam,0,NERR_Success);
1205   SSVAL(*rparam,2,0);           /* converter word */
1206   SSVAL(*rparam,4,*rdata_len);
1207  
1208   return(True);
1209 }
1210
1211 /****************************************************************************
1212   view list of shares available
1213   ****************************************************************************/
1214 static BOOL api_RNetShareEnum(int cnum,uint16 vuid, char *param,char *data,
1215                               int mdrcnt,int mprcnt,
1216                               char **rdata,char **rparam,
1217                               int *rdata_len,int *rparam_len)
1218 {
1219   char *str1 = param+2;
1220   char *str2 = skip_string(str1,1);
1221   char *p = skip_string(str2,1);
1222   int uLevel = SVAL(p,0);
1223   int buf_len = SVAL(p,2);
1224   char *p2;
1225   int count=lp_numservices();
1226   int total=0,counted=0;
1227   int i;
1228   int data_len, fixed_len, string_len;
1229   int f_len, s_len;
1230  
1231   if (!prefix_ok(str1,"WrLeh")) return False;
1232   if (!check_share_info(uLevel,str2)) return False;
1233   
1234   data_len = fixed_len = string_len = 0;
1235   for (i=0;i<count;i++)
1236     if (lp_browseable(i) && lp_snum_ok(i))
1237       {
1238         total++;
1239         data_len += fill_share_info(cnum,i,uLevel,0,&f_len,0,&s_len,0);
1240         if (data_len <= buf_len)
1241           {
1242             counted++;
1243             fixed_len += f_len;
1244             string_len += s_len;
1245           }
1246       }
1247   *rdata_len = fixed_len + string_len;
1248   *rdata = REALLOC(*rdata,*rdata_len);
1249   memset(*rdata,0,*rdata_len);
1250   
1251   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1252   p = *rdata;
1253   f_len = fixed_len;
1254   s_len = string_len;
1255   for (i = 0; i < count;i++)
1256     if (lp_browseable(i) && lp_snum_ok(i))
1257       if (fill_share_info(cnum,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1258         break;
1259   
1260   *rparam_len = 8;
1261   *rparam = REALLOC(*rparam,*rparam_len);
1262   SSVAL(*rparam,0,NERR_Success);
1263   SSVAL(*rparam,2,0);
1264   SSVAL(*rparam,4,counted);
1265   SSVAL(*rparam,6,total);
1266   
1267   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1268            counted,total,uLevel,
1269            buf_len,*rdata_len,mdrcnt));
1270   return(True);
1271 }
1272
1273
1274
1275 /****************************************************************************
1276   get the time of day info
1277   ****************************************************************************/
1278 static BOOL api_NetRemoteTOD(int cnum,uint16 vuid, char *param,char *data,
1279                              int mdrcnt,int mprcnt,
1280                              char **rdata,char **rparam,
1281                              int *rdata_len,int *rparam_len)
1282 {
1283   char *p;
1284   *rparam_len = 4;
1285   *rparam = REALLOC(*rparam,*rparam_len);
1286
1287   *rdata_len = 21;
1288   *rdata = REALLOC(*rdata,*rdata_len);
1289
1290   SSVAL(*rparam,0,NERR_Success);
1291   SSVAL(*rparam,2,0);           /* converter word */
1292
1293   p = *rdata;
1294
1295   {
1296     struct tm *t;
1297     time_t unixdate = time(NULL);
1298
1299     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1300                                     by NT in a "net time" operation,
1301                                     it seems to ignore the one below */
1302
1303     /* the client expects to get localtime, not GMT, in this bit 
1304        (I think, this needs testing) */
1305     t = LocalTime(&unixdate);
1306
1307     SIVAL(p,4,0);               /* msecs ? */
1308     CVAL(p,8) = t->tm_hour;
1309     CVAL(p,9) = t->tm_min;
1310     CVAL(p,10) = t->tm_sec;
1311     CVAL(p,11) = 0;             /* hundredths of seconds */
1312     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1313     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1314     CVAL(p,16) = t->tm_mday;
1315     CVAL(p,17) = t->tm_mon + 1;
1316     SSVAL(p,18,1900+t->tm_year);
1317     CVAL(p,20) = t->tm_wday;
1318   }
1319
1320
1321   return(True);
1322 }
1323
1324 /****************************************************************************
1325   set the user password
1326   ****************************************************************************/
1327 static BOOL api_SetUserPassword(int cnum,uint16 vuid, char *param,char *data,
1328                                 int mdrcnt,int mprcnt,
1329                                 char **rdata,char **rparam,
1330                                 int *rdata_len,int *rparam_len)
1331 {
1332   char *p = skip_string(param+2,2);
1333   fstring user;
1334   fstring pass1,pass2;
1335
1336   strcpy(user,p);
1337
1338   p = skip_string(p,1);
1339
1340   StrnCpy(pass1,p,16);
1341   StrnCpy(pass2,p+16,16);
1342
1343   *rparam_len = 4;
1344   *rparam = REALLOC(*rparam,*rparam_len);
1345
1346   *rdata_len = 0;
1347
1348   SSVAL(*rparam,0,NERR_badpass);
1349   SSVAL(*rparam,2,0);           /* converter word */
1350
1351   DEBUG(3,("Set password for <%s>\n",user));
1352
1353   if (password_ok(user,pass1,strlen(pass1),NULL) &&
1354       chgpasswd(user,pass1,pass2))
1355   {
1356     SSVAL(*rparam,0,NERR_Success);
1357   }
1358
1359   bzero(pass1,sizeof(fstring));
1360   bzero(pass2,sizeof(fstring));  
1361          
1362   return(True);
1363 }
1364
1365 /****************************************************************************
1366   delete a print job
1367   Form: <W> <> 
1368   ****************************************************************************/
1369 static BOOL api_RDosPrintJobDel(int cnum,uint16 vuid, char *param,char *data,
1370                                 int mdrcnt,int mprcnt,
1371                                 char **rdata,char **rparam,
1372                                 int *rdata_len,int *rparam_len)
1373 {
1374   int function = SVAL(param,0);
1375   char *str1 = param+2;
1376   char *str2 = skip_string(str1,1);
1377   char *p = skip_string(str2,1);
1378   int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
1379                                    by the print queue api */
1380   int snum = (SVAL(p,0)>>8);  
1381   int i, count;
1382
1383
1384   /* check it's a supported varient */
1385   if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1386     return(False);
1387
1388   *rparam_len = 4;
1389   *rparam = REALLOC(*rparam,*rparam_len);
1390
1391   *rdata_len = 0;
1392
1393   SSVAL(*rparam,0,NERR_Success);
1394
1395   if (snum >= 0 && VALID_SNUM(snum))
1396     {
1397       print_queue_struct *queue=NULL;
1398       lpq_reset(snum);
1399       count = get_printqueue(snum,cnum,&queue,NULL);
1400   
1401       for (i=0;i<count;i++)
1402         if ((queue[i].job%0xFF) == jobid)
1403           {
1404             switch (function) {
1405             case 81:            /* delete */ 
1406               DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
1407               del_printqueue(cnum,snum,queue[i].job);
1408               break;
1409             case 82:            /* pause */
1410             case 83:            /* resume */
1411               DEBUG(3,("%s queue entry %d\n",
1412                        (function==82?"pausing":"resuming"),queue[i].job));
1413               status_printjob(cnum,snum,queue[i].job,
1414                               (function==82?LPQ_PAUSED:LPQ_QUEUED));
1415               break;
1416             }
1417             break;
1418           }
1419   
1420       if (i==count)
1421         SSVAL(*rparam,0,NERR_JobNotFound);
1422
1423       if (queue) free(queue);
1424     }
1425
1426   SSVAL(*rparam,2,0);           /* converter word */
1427
1428   return(True);
1429 }
1430
1431 static BOOL api_WPrintQueuePurge(int cnum,uint16 vuid, char *param,char *data,
1432                                  int mdrcnt,int mprcnt,
1433                                  char **rdata,char **rparam,
1434                                  int *rdata_len,int *rparam_len)
1435 {
1436   char *str1 = param+2;
1437   char *str2 = skip_string(str1,1);
1438   char *QueueName = skip_string(str2,1);
1439   int snum;
1440
1441   /* check it's a supported varient */
1442   if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1443     return(False);
1444
1445   *rparam_len = 4;
1446   *rparam = REALLOC(*rparam,*rparam_len);
1447
1448   *rdata_len = 0;
1449
1450   SSVAL(*rparam,0,NERR_Success);
1451   SSVAL(*rparam,2,0);           /* converter word */
1452
1453   snum = lp_servicenumber(QueueName);
1454   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
1455     int pnum = lp_servicenumber(PRINTERS_NAME);
1456     if (pnum >= 0) {
1457       lp_add_printer(QueueName,pnum);
1458       snum = lp_servicenumber(QueueName);
1459     }
1460   }
1461
1462   if (snum >= 0 && VALID_SNUM(snum)) {
1463     print_queue_struct *queue=NULL;
1464     int i, count;
1465     lpq_reset(snum);
1466     
1467     count = get_printqueue(snum,cnum,&queue,NULL);
1468     for (i = 0; i < count; i++)
1469       del_printqueue(cnum,snum,queue[i].job);
1470     
1471     if (queue) free(queue);
1472   }
1473
1474   DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
1475
1476   return(True);
1477 }
1478
1479
1480 /****************************************************************************
1481   set the property of a print job (undocumented?)
1482   ? function = 0xb -> set name of print job
1483   ? function = 0x6 -> move print job up/down
1484   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1485   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1486 ****************************************************************************/
1487 static int check_printjob_info(struct pack_desc* desc,
1488                                int uLevel, char* id)
1489 {
1490   desc->subformat = NULL;
1491   switch( uLevel ) {
1492   case 0: desc->format = "W"; break;
1493   case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1494   case 2: desc->format = "WWzWWDDzz"; break;
1495   case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1496   default: return False;
1497   }
1498   if (strcmp(desc->format,id) != 0) return False;
1499   return True;
1500 }
1501
1502 static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data,
1503                              int mdrcnt,int mprcnt,
1504                              char **rdata,char **rparam,
1505                              int *rdata_len,int *rparam_len)
1506 {
1507   struct pack_desc desc;
1508   char *str1 = param+2;
1509   char *str2 = skip_string(str1,1);
1510   char *p = skip_string(str2,1);
1511   int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
1512                                    by the print queue api */
1513   int snum = (SVAL(p,0)>>8);
1514   int uLevel = SVAL(p,2);
1515   int function = SVAL(p,4);     /* what is this ?? */
1516   int i;
1517   char *s = data;
1518    
1519   *rparam_len = 4;
1520   *rparam = REALLOC(*rparam,*rparam_len);
1521   
1522   *rdata_len = 0;
1523   
1524   /* check it's a supported varient */
1525   if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
1526     return(False);
1527    
1528   switch (function) {
1529   case 0x6:     /* change job place in the queue, data gives the new place */
1530     if (snum >= 0 && VALID_SNUM(snum))
1531       {
1532         print_queue_struct *queue=NULL;
1533         int count;
1534   
1535         lpq_reset(snum);
1536         count = get_printqueue(snum,cnum,&queue,NULL);
1537         for (i=0;i<count;i++)   /* find job */
1538           if ((queue[i].job%0xFF) == jobid) break;
1539             
1540         if (i==count) {
1541           desc.errcode=NERR_JobNotFound;
1542           if (queue) free(queue);
1543         }
1544         else {
1545           desc.errcode=NERR_Success;
1546           i++;
1547 #if 0   
1548           {
1549             int place= SVAL(data,0);
1550             /* we currently have no way of doing this. Can any unix do it? */
1551             if (i < place)      /* move down */;
1552             else if (i > place )        /* move up */;
1553           }
1554 #endif
1555           desc.errcode=NERR_notsupported; /* not yet supported */
1556           if (queue) free(queue);
1557         }
1558       }
1559     else desc.errcode=NERR_JobNotFound;
1560     break;
1561   case 0xb:   /* change print job name, data gives the name */
1562     /* jobid, snum should be zero */
1563     if (isalpha(*s))
1564       {
1565         pstring name;
1566         int l = 0;
1567         while (l<64 && *s)
1568           {
1569             if (issafe(*s)) name[l++] = *s;
1570             s++;
1571           }      
1572         name[l] = 0;
1573         
1574         DEBUG(3,("Setting print name to %s\n",name));
1575         
1576         for (i=0;i<MAX_OPEN_FILES;i++)
1577           if (Files[i].open && Files[i].print_file)
1578             {
1579               pstring wd;
1580               GetWd(wd);
1581               unbecome_user();
1582               
1583               if (!become_user(Files[i].cnum,vuid) || 
1584                   !become_service(Files[i].cnum,True))
1585                 break;
1586               
1587               if (sys_rename(Files[i].name,name) == 0)
1588                 string_set(&Files[i].name,name);
1589               break;
1590             }
1591       }
1592     desc.errcode=NERR_Success;
1593   
1594     break;
1595   default:                      /* not implemented */
1596     return False;
1597   }
1598  
1599   SSVALS(*rparam,0,desc.errcode);
1600   SSVAL(*rparam,2,0);           /* converter word */
1601   
1602   return(True);
1603 }
1604
1605
1606 /****************************************************************************
1607   get info about the server
1608   ****************************************************************************/
1609 static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data,
1610                                   int mdrcnt,int mprcnt,
1611                                   char **rdata,char **rparam,
1612                                   int *rdata_len,int *rparam_len)
1613 {
1614   char *str1 = param+2;
1615   char *str2 = skip_string(str1,1);
1616   char *p = skip_string(str2,1);
1617   int uLevel = SVAL(p,0);
1618   char *p2;
1619   int struct_len;
1620
1621   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
1622
1623   /* check it's a supported varient */
1624   if (!prefix_ok(str1,"WrLh")) return False;
1625   switch( uLevel ) {
1626   case 0:
1627     if (strcmp(str2,"B16") != 0) return False;
1628     struct_len = 16;
1629     break;
1630   case 1:
1631     if (strcmp(str2,"B16BBDz") != 0) return False;
1632     struct_len = 26;
1633     break;
1634   case 2:
1635     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
1636         != 0) return False;
1637     struct_len = 134;
1638     break;
1639   case 3:
1640     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
1641         != 0) return False;
1642     struct_len = 144;
1643     break;
1644   case 20:
1645     if (strcmp(str2,"DN") != 0) return False;
1646     struct_len = 6;
1647     break;
1648   case 50:
1649     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
1650     struct_len = 42;
1651     break;
1652   default: return False;
1653   }
1654
1655   *rdata_len = mdrcnt;
1656   *rdata = REALLOC(*rdata,*rdata_len);
1657
1658   p = *rdata;
1659   p2 = p + struct_len;
1660   if (uLevel != 20) {
1661     StrnCpy(p,local_machine,16);
1662     strupper(p);
1663   }
1664   p += 16;
1665   if (uLevel > 0)
1666     {
1667       struct srv_info_struct *servers=NULL;
1668       int i,count;
1669       pstring comment;
1670       uint32 servertype=DFLT_SERVER_TYPE;
1671
1672       strcpy(comment,lp_serverstring());
1673
1674       if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
1675         for (i=0;i<count;i++)
1676           if (strequal(servers[i].name,local_machine))
1677       {
1678             servertype = servers[i].type;
1679             strcpy(comment,servers[i].comment);     
1680           }
1681       }
1682       if (servers) free(servers);
1683
1684       SCVAL(p,0,MAJOR_VERSION);
1685       SCVAL(p,1,MINOR_VERSION);
1686       SIVAL(p,2,servertype);
1687
1688       if (mdrcnt == struct_len) {
1689         SIVAL(p,6,0);
1690       } else {
1691         SIVAL(p,6,PTR_DIFF(p2,*rdata));
1692         standard_sub(cnum,comment);
1693         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
1694         p2 = skip_string(p2,1);
1695       }
1696     }
1697   if (uLevel > 1)
1698     {
1699       return False;             /* not yet implemented */
1700     }
1701
1702   *rdata_len = PTR_DIFF(p2,*rdata);
1703
1704   *rparam_len = 6;
1705   *rparam = REALLOC(*rparam,*rparam_len);
1706   SSVAL(*rparam,0,NERR_Success);
1707   SSVAL(*rparam,2,0);           /* converter word */
1708   SSVAL(*rparam,4,*rdata_len);
1709
1710   return(True);
1711 }
1712
1713
1714 /****************************************************************************
1715   get info about the server
1716   ****************************************************************************/
1717 static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
1718                                 int mdrcnt,int mprcnt,
1719                                 char **rdata,char **rparam,
1720                                 int *rdata_len,int *rparam_len)
1721 {
1722   char *str1 = param+2;
1723   char *str2 = skip_string(str1,1);
1724   char *p = skip_string(str2,1);
1725   char *p2;
1726   extern pstring sesssetup_user;
1727   int level = SVAL(p,0);
1728
1729   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
1730
1731   *rparam_len = 6;
1732   *rparam = REALLOC(*rparam,*rparam_len);
1733
1734   /* check it's a supported varient */
1735   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
1736     return(False);
1737
1738   *rdata_len = mdrcnt + 1024;
1739   *rdata = REALLOC(*rdata,*rdata_len);
1740
1741   SSVAL(*rparam,0,NERR_Success);
1742   SSVAL(*rparam,2,0);           /* converter word */
1743
1744   p = *rdata;
1745   p2 = p + 22;
1746
1747
1748   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
1749   strcpy(p2,local_machine);
1750   strupper(p2);
1751   p2 = skip_string(p2,1);
1752   p += 4;
1753
1754   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1755   strcpy(p2,sesssetup_user);
1756   p2 = skip_string(p2,1);
1757   p += 4;
1758
1759   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
1760   strcpy(p2,lp_workgroup());
1761   strupper(p2);
1762   p2 = skip_string(p2,1);
1763   p += 4;
1764
1765   SCVAL(p,0,MAJOR_VERSION); /* system version - e.g 4 in 4.1 */
1766   SCVAL(p,1,MINOR_VERSION); /* system version - e.g .1 in 4.1 */
1767   p += 2;
1768
1769   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1770   strcpy(p2,lp_workgroup());    /* don't know.  login domain?? */
1771   p2 = skip_string(p2,1);
1772   p += 4;
1773
1774   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
1775   strcpy(p2,"");
1776   p2 = skip_string(p2,1);
1777   p += 4;
1778
1779   *rdata_len = PTR_DIFF(p2,*rdata);
1780
1781   SSVAL(*rparam,4,*rdata_len);
1782
1783   return(True);
1784 }
1785
1786 /****************************************************************************
1787   get info about a user
1788
1789     struct user_info_11 {
1790         char                usri11_name[21];  0-20 
1791         char                usri11_pad;       21 
1792         char                *usri11_comment;  22-25 
1793         char            *usri11_usr_comment;  26-29
1794         unsigned short      usri11_priv;      30-31
1795         unsigned long       usri11_auth_flags; 32-35
1796         long                usri11_password_age; 36-39
1797         char                *usri11_homedir; 40-43
1798         char            *usri11_parms; 44-47
1799         long                usri11_last_logon; 48-51
1800         long                usri11_last_logoff; 52-55
1801         unsigned short      usri11_bad_pw_count; 56-57
1802         unsigned short      usri11_num_logons; 58-59
1803         char                *usri11_logon_server; 60-63
1804         unsigned short      usri11_country_code; 64-65
1805         char            *usri11_workstations; 66-69
1806         unsigned long       usri11_max_storage; 70-73
1807         unsigned short      usri11_units_per_week; 74-75
1808         unsigned char       *usri11_logon_hours; 76-79
1809         unsigned short      usri11_code_page; 80-81
1810     };
1811
1812 where:
1813
1814   usri11_name specifies the user name for which information is retireved
1815
1816   usri11_pad aligns the next data structure element to a word boundary
1817
1818   usri11_comment is a null terminated ASCII comment
1819
1820   usri11_user_comment is a null terminated ASCII comment about the user
1821
1822   usri11_priv specifies the level of the privilege assigned to the user.
1823        The possible values are:
1824
1825 Name             Value  Description
1826 USER_PRIV_GUEST  0      Guest privilege
1827 USER_PRIV_USER   1      User privilege
1828 USER_PRV_ADMIN   2      Administrator privilege
1829
1830   usri11_auth_flags specifies the account operator privileges. The
1831        possible values are:
1832
1833 Name            Value   Description
1834 AF_OP_PRINT     0       Print operator
1835
1836
1837 Leach, Naik                                        [Page 28]\r\f
1838
1839
1840 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
1841
1842
1843 AF_OP_COMM      1       Communications operator
1844 AF_OP_SERVER    2       Server operator
1845 AF_OP_ACCOUNTS  3       Accounts operator
1846
1847
1848   usri11_password_age specifies how many seconds have elapsed since the
1849        password was last changed.
1850
1851   usri11_home_dir points to a null terminated ASCII string that contains
1852        the path name of the user's home directory.
1853
1854   usri11_parms points to a null terminated ASCII string that is set
1855        aside for use by applications.
1856
1857   usri11_last_logon specifies the time when the user last logged on.
1858        This value is stored as the number of seconds elapsed since
1859        00:00:00, January 1, 1970.
1860
1861   usri11_last_logoff specifies the time when the user last logged off.
1862        This value is stored as the number of seconds elapsed since
1863        00:00:00, January 1, 1970. A value of 0 means the last logoff
1864        time is unknown.
1865
1866   usri11_bad_pw_count specifies the number of incorrect passwords
1867        entered since the last successful logon.
1868
1869   usri11_log1_num_logons specifies the number of times this user has
1870        logged on. A value of -1 means the number of logons is unknown.
1871
1872   usri11_logon_server points to a null terminated ASCII string that
1873        contains the name of the server to which logon requests are sent.
1874        A null string indicates logon requests should be sent to the
1875        domain controller.
1876
1877   usri11_country_code specifies the country code for the user's language
1878        of choice.
1879
1880   usri11_workstations points to a null terminated ASCII string that
1881        contains the names of workstations the user may log on from.
1882        There may be up to 8 workstations, with the names separated by
1883        commas. A null strings indicates there are no restrictions.
1884
1885   usri11_max_storage specifies the maximum amount of disk space the user
1886        can occupy. A value of 0xffffffff indicates there are no
1887        restrictions.
1888
1889   usri11_units_per_week specifies the equal number of time units into
1890        which a week is divided. This value must be equal to 168.
1891
1892   usri11_logon_hours points to a 21 byte (168 bits) string that
1893        specifies the time during which the user can log on. Each bit
1894        represents one unique hour in a week. The first bit (bit 0, word
1895        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
1896
1897
1898
1899 Leach, Naik                                        [Page 29]\r\f
1900
1901
1902 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
1903
1904
1905        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
1906        are no restrictions.
1907
1908   usri11_code_page specifies the code page for the user's language of
1909        choice
1910
1911 All of the pointers in this data structure need to be treated
1912 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
1913 to be ignored. The converter word returned in the parameters section
1914 needs to be subtracted from the lower 16 bits to calculate an offset
1915 into the return buffer where this ASCII string resides.
1916
1917 There is no auxiliary data in the response.
1918
1919   ****************************************************************************/
1920
1921 #define usri11_name           0 
1922 #define usri11_pad            21
1923 #define usri11_comment        22
1924 #define usri11_usr_comment    26
1925 #define usri11_full_name      30
1926 #define usri11_priv           34
1927 #define usri11_auth_flags     36
1928 #define usri11_password_age   40
1929 #define usri11_homedir        44
1930 #define usri11_parms          48
1931 #define usri11_last_logon     52
1932 #define usri11_last_logoff    56
1933 #define usri11_bad_pw_count   60
1934 #define usri11_num_logons     62
1935 #define usri11_logon_server   64
1936 #define usri11_country_code   68
1937 #define usri11_workstations   70
1938 #define usri11_max_storage    74
1939 #define usri11_units_per_week 78
1940 #define usri11_logon_hours    80
1941 #define usri11_code_page      84
1942 #define usri11_end            86
1943
1944 #define USER_PRIV_GUEST 0
1945 #define USER_PRIV_USER 1
1946 #define USER_PRIV_ADMIN 2
1947
1948 #define AF_OP_PRINT     0 
1949 #define AF_OP_COMM      1
1950 #define AF_OP_SERVER    2
1951 #define AF_OP_ACCOUNTS  3
1952
1953 static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
1954                                 int mdrcnt,int mprcnt,
1955                                 char **rdata,char **rparam,
1956                                 int *rdata_len,int *rparam_len)
1957 {
1958         char *str1 = param+2;
1959         char *str2 = skip_string(str1,1);
1960         char *UserName = skip_string(str2,1);
1961         char *p = skip_string(UserName,1);
1962         int uLevel = SVAL(p,0);
1963         char *p2;
1964
1965         *rparam_len = 6;
1966         *rparam = REALLOC(*rparam,*rparam_len);
1967
1968         /* check it's a supported varient */
1969         if (strcmp(str1,"zWrLh") != 0) return False;
1970         switch( uLevel )
1971         {
1972                 case 0: p2 = "B21"; break;
1973                 case 1: p2 = "B21BB16DWzzWz"; break;
1974                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
1975                 case 10: p2 = "B21Bzzz"; break;
1976                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
1977                 default: return False;
1978         }
1979
1980         if (strcmp(p2,str2) != 0) return False;
1981
1982         *rdata_len = mdrcnt + 1024;
1983         *rdata = REALLOC(*rdata,*rdata_len);
1984
1985         SSVAL(*rparam,0,NERR_Success);
1986         SSVAL(*rparam,2,0);             /* converter word */
1987
1988         p = *rdata;
1989         p2 = p + usri11_end;
1990
1991         memset(p,0,21); 
1992         strcpy(p+usri11_name,UserName); /* 21 bytes - user name */
1993
1994         if (uLevel > 0)
1995         {
1996                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
1997                 *p2 = 0;
1998         }
1999         if (uLevel >= 10)
2000         {
2001                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2002                 strcpy(p2,"Comment");
2003                 p2 = skip_string(p2,1);
2004
2005                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2006                 strcpy(p2,"UserComment");
2007                 p2 = skip_string(p2,1);
2008
2009         /* EEK! the cifsrap.txt doesn't have this in!!!! */
2010                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2011 #if 0
2012                 strcpy(p2,"FullName");
2013 #endif
2014                 strcpy(p2,UserName); /* suggest copying the user name, for now... */
2015                 p2 = skip_string(p2,1);
2016         }
2017         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2018         {         
2019                 SSVAL(p,usri11_priv,Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2020                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2021                 SIVALS(p,usri11_password_age,0xffffffff);               /* password age */
2022                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2023                 if (*lp_logon_path())
2024                 {
2025                         strcpy(p2,lp_logon_path());
2026                 }
2027                 else
2028                 {
2029                         strcpy(p2,"\\\\%L\\%U");
2030                 }
2031                 standard_sub_basic(p2);
2032                 p2 = skip_string(p2,1);
2033                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2034                 strcpy(p2,"");
2035                 p2 = skip_string(p2,1);
2036                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2037                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2038                 SSVALS(p,usri11_bad_pw_count,0xffffffff);               /* bad pw counts */
2039                 SSVALS(p,usri11_num_logons,0xffffffff);         /* num logons */
2040                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2041                 strcpy(p2,"\\\\*");
2042                 p2 = skip_string(p2,1);
2043                 SSVAL(p,usri11_country_code,0);         /* country code */
2044
2045                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2046                 strcpy(p2,"");
2047                 p2 = skip_string(p2,1);
2048
2049                 SIVALS(p,usri11_max_storage,0xffffffff);                /* max storage */
2050                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2051                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2052
2053                 /* a simple way to get logon hours at all times. */
2054                 memset(p2,0xff,21);
2055                 SCVAL(p2,21,0);           /* fix zero termination */
2056                 p2 = skip_string(p2,1);
2057
2058                 SSVAL(p,usri11_code_page,0);            /* code page */
2059         }
2060         if (uLevel == 1 || uLevel == 2)
2061         {
2062                 memset(p+22,' ',16);    /* password */
2063                 SIVALS(p,38,-1);                /* password age */
2064                 SSVAL(p,42,
2065                 Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2066                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2067                 if (*lp_logon_path())
2068                 {
2069                         strcpy(p2,lp_logon_path());
2070                 }
2071                 else
2072                 {
2073                         strcpy(p2,"\\\\%L\\%U");
2074                 }
2075                 standard_sub_basic(p2);
2076                 p2 = skip_string(p2,1);
2077                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2078                 *p2++ = 0;
2079                 SSVAL(p,52,0);          /* flags */
2080                 SIVAL(p,54,0);          /* script_path */
2081                 if (uLevel == 2)
2082                 {
2083                         SIVAL(p,60,0);          /* auth_flags */
2084                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2085                         strcpy(p2,"<Full Name>");
2086                         p2 = skip_string(p2,1);
2087                         SIVAL(p,68,0);          /* urs_comment */
2088                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2089                         strcpy(p2,"");
2090                         p2 = skip_string(p2,1);
2091                         SIVAL(p,76,0);          /* workstations */
2092                         SIVAL(p,80,0);          /* last_logon */
2093                         SIVAL(p,84,0);          /* last_logoff */
2094                         SIVALS(p,88,-1);                /* acct_expires */
2095                         SIVALS(p,92,-1);                /* max_storage */
2096                         SSVAL(p,96,168);        /* units_per_week */
2097                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2098                         memset(p2,-1,21);
2099                         p2 += 21;
2100                         SSVALS(p,102,-1);       /* bad_pw_count */
2101                         SSVALS(p,104,-1);       /* num_logons */
2102                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2103                         strcpy(p2,"\\\\%L");
2104                         standard_sub_basic(p2);
2105                         p2 = skip_string(p2,1);
2106                         SSVAL(p,110,49);        /* country_code */
2107                         SSVAL(p,112,860);       /* code page */
2108                 }
2109         }
2110
2111         *rdata_len = PTR_DIFF(p2,*rdata);
2112
2113         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2114
2115         return(True);
2116 }
2117
2118 /*******************************************************************
2119   get groups that a user is a member of
2120   ******************************************************************/
2121 static BOOL api_NetUserGetGroups(int cnum,uint16 vuid, char *param,char *data,
2122                                  int mdrcnt,int mprcnt,
2123                                  char **rdata,char **rparam,
2124                                  int *rdata_len,int *rparam_len)
2125 {
2126   char *str1 = param+2;
2127   char *str2 = skip_string(str1,1);
2128   char *UserName = skip_string(str2,1);
2129   char *p = skip_string(UserName,1);
2130   int uLevel = SVAL(p,0);
2131   char *p2;
2132   int count=0;
2133
2134   *rparam_len = 8;
2135   *rparam = REALLOC(*rparam,*rparam_len);
2136
2137   /* check it's a supported varient */
2138   if (strcmp(str1,"zWrLeh") != 0) return False;
2139   switch( uLevel ) {
2140   case 0: p2 = "B21"; break;
2141   default: return False;
2142   }
2143   if (strcmp(p2,str2) != 0) return False;
2144
2145   *rdata_len = mdrcnt + 1024;
2146   *rdata = REALLOC(*rdata,*rdata_len);
2147
2148   SSVAL(*rparam,0,NERR_Success);
2149   SSVAL(*rparam,2,0);           /* converter word */
2150
2151   p = *rdata;
2152
2153   /* XXXX we need a real SAM database some day */
2154   strcpy(p,"Users"); p += 21; count++;
2155   strcpy(p,"Domain Users"); p += 21; count++;
2156   strcpy(p,"Guests"); p += 21; count++;
2157   strcpy(p,"Domain Guests"); p += 21; count++;
2158
2159   *rdata_len = PTR_DIFF(p,*rdata);
2160
2161   SSVAL(*rparam,4,count);       /* is this right?? */
2162   SSVAL(*rparam,6,count);       /* is this right?? */
2163
2164   return(True);
2165 }
2166
2167
2168 static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data,
2169                                 int mdrcnt,int mprcnt,
2170                                 char **rdata,char **rparam,
2171                                 int *rdata_len,int *rparam_len)
2172 {
2173   char *str1 = param+2;
2174   char *str2 = skip_string(str1,1);
2175   char *p = skip_string(str2,1);
2176   int uLevel;
2177   struct pack_desc desc;
2178   char* name;
2179
2180   uLevel = SVAL(p,0);
2181   name = p + 2;
2182
2183   bzero(&desc,sizeof(desc));
2184
2185   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2186
2187   /* check it's a supported varient */
2188   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2189   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2190   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2191   desc.base = *rdata;
2192   desc.buflen = mdrcnt;
2193   desc.subformat = NULL;
2194   desc.format = str2;
2195   
2196   if (init_package(&desc,1,0))
2197   {
2198     PACKI(&desc,"W",0);         /* code */
2199     PACKS(&desc,"B21",name);    /* eff. name */
2200     PACKS(&desc,"B","");                /* pad */
2201     PACKI(&desc,"W",
2202           Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2203     PACKI(&desc,"D",0);         /* auth flags XXX */
2204     PACKI(&desc,"W",0);         /* num logons */
2205     PACKI(&desc,"W",0);         /* bad pw count */
2206     PACKI(&desc,"D",0);         /* last logon */
2207     PACKI(&desc,"D",-1);                /* last logoff */
2208     PACKI(&desc,"D",-1);                /* logoff time */
2209     PACKI(&desc,"D",-1);                /* kickoff time */
2210     PACKI(&desc,"D",0);         /* password age */
2211     PACKI(&desc,"D",0);         /* password can change */
2212     PACKI(&desc,"D",-1);                /* password must change */
2213     {
2214       fstring mypath;
2215       strcpy(mypath,"\\\\");
2216       strcat(mypath,local_machine);
2217       strupper(mypath);
2218       PACKS(&desc,"z",mypath); /* computer */
2219     }
2220     PACKS(&desc,"z",lp_workgroup());/* domain */
2221     PACKS(&desc,"z",lp_logon_script());         /* script path */
2222     PACKI(&desc,"D",0x00000000);                /* reserved */
2223   }
2224
2225   *rdata_len = desc.usedlen;
2226   *rparam_len = 6;
2227   *rparam = REALLOC(*rparam,*rparam_len);
2228   SSVALS(*rparam,0,desc.errcode);
2229   SSVAL(*rparam,2,0);
2230   SSVAL(*rparam,4,desc.neededlen);
2231
2232   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2233   return(True);
2234 }
2235
2236
2237 /****************************************************************************
2238   api_WAccessGetUserPerms
2239   ****************************************************************************/
2240 static BOOL api_WAccessGetUserPerms(int cnum,uint16 vuid, char *param,char *data,
2241                                     int mdrcnt,int mprcnt,
2242                                     char **rdata,char **rparam,
2243                                     int *rdata_len,int *rparam_len)
2244 {
2245   char *str1 = param+2;
2246   char *str2 = skip_string(str1,1);
2247   char *user = skip_string(str2,1);
2248   char *resource = skip_string(user,1);
2249
2250   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2251
2252   /* check it's a supported varient */
2253   if (strcmp(str1,"zzh") != 0) return False;
2254   if (strcmp(str2,"") != 0) return False;
2255
2256   *rparam_len = 6;
2257   *rparam = REALLOC(*rparam,*rparam_len);
2258   SSVALS(*rparam,0,0);          /* errorcode */
2259   SSVAL(*rparam,2,0);           /* converter word */
2260   SSVAL(*rparam,4,0x7f);        /* permission flags */
2261
2262   return(True);
2263 }
2264
2265 /****************************************************************************
2266   api_WPrintJobEnumerate
2267   ****************************************************************************/
2268 static BOOL api_WPrintJobGetInfo(int cnum,uint16 vuid, char *param,char *data,
2269                                  int mdrcnt,int mprcnt,
2270                                  char **rdata,char **rparam,
2271                                  int *rdata_len,int *rparam_len)
2272 {
2273   char *str1 = param+2;
2274   char *str2 = skip_string(str1,1);
2275   char *p = skip_string(str2,1);
2276   int uJobId = SVAL(p,0);
2277   int uLevel,cbBuf;
2278   int count;
2279   int i;
2280   int snum;
2281   int job;
2282   struct pack_desc desc;
2283   print_queue_struct *queue=NULL;
2284   print_status_struct status;
2285
2286   uLevel = SVAL(p,2);
2287   cbBuf = SVAL(p,4);
2288
2289   bzero(&desc,sizeof(desc));
2290   bzero(&status,sizeof(status));
2291
2292   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,uJobId));
2293
2294   /* check it's a supported varient */
2295   if (strcmp(str1,"WWrLh") != 0) return False;
2296   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2297
2298   snum = (unsigned int)uJobId >> 8; /*## valid serice number??*/
2299   job = uJobId & 0xFF;
2300
2301   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2302
2303   count = get_printqueue(snum,cnum,&queue,&status);
2304   for (i = 0; i < count; i++) {
2305     if ((queue[i].job % 0xFF) == job) break;
2306   }
2307   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2308   desc.base = *rdata;
2309   desc.buflen = mdrcnt;
2310
2311   if (init_package(&desc,1,0)) {
2312     if (i < count) {
2313       fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
2314       *rdata_len = desc.usedlen;
2315     }
2316     else {
2317       desc.errcode = NERR_JobNotFound;
2318       *rdata_len = 0;
2319     }
2320   }
2321
2322   *rparam_len = 6;
2323   *rparam = REALLOC(*rparam,*rparam_len);
2324   SSVALS(*rparam,0,desc.errcode);
2325   SSVAL(*rparam,2,0);
2326   SSVAL(*rparam,4,desc.neededlen);
2327
2328   if (queue) free(queue);
2329
2330   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2331   return(True);
2332 }
2333
2334 static BOOL api_WPrintJobEnumerate(int cnum,uint16 vuid, char *param,char *data,
2335                                    int mdrcnt,int mprcnt,
2336                                    char **rdata,char **rparam,
2337                                    int *rdata_len,int *rparam_len)
2338 {
2339   char *str1 = param+2;
2340   char *str2 = skip_string(str1,1);
2341   char *p = skip_string(str2,1);
2342   char* name = p;
2343   int uLevel,cbBuf;
2344   int count;
2345   int i, succnt=0;
2346   int snum;
2347   struct pack_desc desc;
2348   print_queue_struct *queue=NULL;
2349   print_status_struct status;
2350
2351   bzero(&desc,sizeof(desc));
2352   bzero(&status,sizeof(status));
2353
2354   p = skip_string(p,1);
2355   uLevel = SVAL(p,0);
2356   cbBuf = SVAL(p,2);
2357
2358   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2359
2360   /* check it's a supported varient */
2361   if (strcmp(str1,"zWrLeh") != 0) return False;
2362   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2363   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2364
2365   snum = lp_servicenumber(name);
2366   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2367     int pnum = lp_servicenumber(PRINTERS_NAME);
2368     if (pnum >= 0) {
2369       lp_add_printer(name,pnum);
2370       snum = lp_servicenumber(name);
2371     }
2372   }
2373
2374   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2375
2376   count = get_printqueue(snum,cnum,&queue,&status);
2377   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2378   desc.base = *rdata;
2379   desc.buflen = mdrcnt;
2380
2381   if (init_package(&desc,count,0)) {
2382     succnt = 0;
2383     for (i = 0; i < count; i++) {
2384       fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
2385       if (desc.errcode == NERR_Success) succnt = i+1;
2386     }
2387   }
2388
2389   *rdata_len = desc.usedlen;
2390
2391   *rparam_len = 8;
2392   *rparam = REALLOC(*rparam,*rparam_len);
2393   SSVALS(*rparam,0,desc.errcode);
2394   SSVAL(*rparam,2,0);
2395   SSVAL(*rparam,4,succnt);
2396   SSVAL(*rparam,6,count);
2397
2398   if (queue) free(queue);
2399
2400   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2401   return(True);
2402 }
2403
2404 static int check_printdest_info(struct pack_desc* desc,
2405                                 int uLevel, char* id)
2406 {
2407   desc->subformat = NULL;
2408   switch( uLevel ) {
2409   case 0: desc->format = "B9"; break;
2410   case 1: desc->format = "B9B21WWzW"; break;
2411   case 2: desc->format = "z"; break;
2412   case 3: desc->format = "zzzWWzzzWW"; break;
2413   default: return False;
2414   }
2415   if (strcmp(desc->format,id) != 0) return False;
2416   return True;
2417 }
2418
2419 static void fill_printdest_info(int cnum, int snum, int uLevel,
2420                                 struct pack_desc* desc)
2421 {
2422   char buf[100];
2423   strcpy(buf,SERVICE(snum));
2424   strupper(buf);
2425   if (uLevel <= 1) {
2426     PACKS(desc,"B9",buf);       /* szName */
2427     if (uLevel == 1) {
2428       PACKS(desc,"B21","");     /* szUserName */
2429       PACKI(desc,"W",0);                /* uJobId */
2430       PACKI(desc,"W",0);                /* fsStatus */
2431       PACKS(desc,"z","");       /* pszStatus */
2432       PACKI(desc,"W",0);                /* time */
2433     }
2434   }
2435   if (uLevel == 2 || uLevel == 3) {
2436     PACKS(desc,"z",buf);                /* pszPrinterName */
2437     if (uLevel == 3) {
2438       PACKS(desc,"z","");       /* pszUserName */
2439       PACKS(desc,"z","");       /* pszLogAddr */
2440       PACKI(desc,"W",0);                /* uJobId */
2441       PACKI(desc,"W",0);                /* fsStatus */
2442       PACKS(desc,"z","");       /* pszStatus */
2443       PACKS(desc,"z","");       /* pszComment */
2444       PACKS(desc,"z","NULL"); /* pszDrivers */
2445       PACKI(desc,"W",0);                /* time */
2446       PACKI(desc,"W",0);                /* pad1 */
2447     }
2448   }
2449 }
2450
2451 static BOOL api_WPrintDestGetInfo(int cnum,uint16 vuid, char *param,char *data,
2452                                   int mdrcnt,int mprcnt,
2453                                   char **rdata,char **rparam,
2454                                   int *rdata_len,int *rparam_len)
2455 {
2456   char *str1 = param+2;
2457   char *str2 = skip_string(str1,1);
2458   char *p = skip_string(str2,1);
2459   char* PrinterName = p;
2460   int uLevel,cbBuf;
2461   struct pack_desc desc;
2462   int snum;
2463
2464   bzero(&desc,sizeof(desc));
2465
2466   p = skip_string(p,1);
2467   uLevel = SVAL(p,0);
2468   cbBuf = SVAL(p,2);
2469
2470   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2471
2472   /* check it's a supported varient */
2473   if (strcmp(str1,"zWrLh") != 0) return False;
2474   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2475
2476   snum = lp_servicenumber(PrinterName);
2477   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2478     int pnum = lp_servicenumber(PRINTERS_NAME);
2479     if (pnum >= 0) {
2480       lp_add_printer(PrinterName,pnum);
2481       snum = lp_servicenumber(PrinterName);
2482     }
2483   }
2484
2485   if (snum < 0) {
2486     *rdata_len = 0;
2487     desc.errcode = NERR_DestNotFound;
2488     desc.neededlen = 0;
2489   }
2490   else {
2491     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2492     desc.base = *rdata;
2493     desc.buflen = mdrcnt;
2494     if (init_package(&desc,1,0)) {
2495       fill_printdest_info(cnum,snum,uLevel,&desc);
2496     }
2497     *rdata_len = desc.usedlen;
2498   }
2499
2500   *rparam_len = 6;
2501   *rparam = REALLOC(*rparam,*rparam_len);
2502   SSVALS(*rparam,0,desc.errcode);
2503   SSVAL(*rparam,2,0);
2504   SSVAL(*rparam,4,desc.neededlen);
2505
2506   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2507   return(True);
2508 }
2509
2510 static BOOL api_WPrintDestEnum(int cnum,uint16 vuid, char *param,char *data,
2511                                int mdrcnt,int mprcnt,
2512                                char **rdata,char **rparam,
2513                                int *rdata_len,int *rparam_len)
2514 {
2515   char *str1 = param+2;
2516   char *str2 = skip_string(str1,1);
2517   char *p = skip_string(str2,1);
2518   int uLevel,cbBuf;
2519   int queuecnt;
2520   int i, n, succnt=0;
2521   struct pack_desc desc;
2522   int services = lp_numservices();
2523
2524   bzero(&desc,sizeof(desc));
2525
2526   uLevel = SVAL(p,0);
2527   cbBuf = SVAL(p,2);
2528
2529   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2530
2531   /* check it's a supported varient */
2532   if (strcmp(str1,"WrLeh") != 0) return False;
2533   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2534
2535   queuecnt = 0;
2536   for (i = 0; i < services; i++)
2537     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2538       queuecnt++;
2539
2540   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2541   desc.base = *rdata;
2542   desc.buflen = mdrcnt;
2543   if (init_package(&desc,queuecnt,0)) {    
2544     succnt = 0;
2545     n = 0;
2546     for (i = 0; i < services; i++) {
2547       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2548         fill_printdest_info(cnum,i,uLevel,&desc);
2549         n++;
2550         if (desc.errcode == NERR_Success) succnt = n;
2551       }
2552     }
2553   }
2554
2555   *rdata_len = desc.usedlen;
2556
2557   *rparam_len = 8;
2558   *rparam = REALLOC(*rparam,*rparam_len);
2559   SSVALS(*rparam,0,desc.errcode);
2560   SSVAL(*rparam,2,0);
2561   SSVAL(*rparam,4,succnt);
2562   SSVAL(*rparam,6,queuecnt);
2563
2564   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2565   return(True);
2566 }
2567
2568 static BOOL api_WPrintDriverEnum(int cnum,uint16 vuid, char *param,char *data,
2569                                  int mdrcnt,int mprcnt,
2570                                  char **rdata,char **rparam,
2571                                  int *rdata_len,int *rparam_len)
2572 {
2573   char *str1 = param+2;
2574   char *str2 = skip_string(str1,1);
2575   char *p = skip_string(str2,1);
2576   int uLevel,cbBuf;
2577   int succnt;
2578   struct pack_desc desc;
2579
2580   bzero(&desc,sizeof(desc));
2581
2582   uLevel = SVAL(p,0);
2583   cbBuf = SVAL(p,2);
2584
2585   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2586
2587   /* check it's a supported varient */
2588   if (strcmp(str1,"WrLeh") != 0) return False;
2589   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2590
2591   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2592   desc.base = *rdata;
2593   desc.buflen = mdrcnt;
2594   if (init_package(&desc,1,0)) {
2595     PACKS(&desc,"B41","NULL");
2596   }
2597
2598   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2599
2600   *rdata_len = desc.usedlen;
2601
2602   *rparam_len = 8;
2603   *rparam = REALLOC(*rparam,*rparam_len);
2604   SSVALS(*rparam,0,desc.errcode);
2605   SSVAL(*rparam,2,0);
2606   SSVAL(*rparam,4,succnt);
2607   SSVAL(*rparam,6,1);
2608
2609   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2610   return(True);
2611 }
2612
2613 static BOOL api_WPrintQProcEnum(int cnum,uint16 vuid, char *param,char *data,
2614                                 int mdrcnt,int mprcnt,
2615                                 char **rdata,char **rparam,
2616                                 int *rdata_len,int *rparam_len)
2617 {
2618   char *str1 = param+2;
2619   char *str2 = skip_string(str1,1);
2620   char *p = skip_string(str2,1);
2621   int uLevel,cbBuf;
2622   int succnt;
2623   struct pack_desc desc;
2624
2625   bzero(&desc,sizeof(desc));
2626
2627   uLevel = SVAL(p,0);
2628   cbBuf = SVAL(p,2);
2629
2630   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
2631
2632   /* check it's a supported varient */
2633   if (strcmp(str1,"WrLeh") != 0) return False;
2634   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
2635
2636   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2637   desc.base = *rdata;
2638   desc.buflen = mdrcnt;
2639   desc.format = str2;
2640   if (init_package(&desc,1,0)) {
2641     PACKS(&desc,"B13","lpd");
2642   }
2643
2644   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2645
2646   *rdata_len = desc.usedlen;
2647
2648   *rparam_len = 8;
2649   *rparam = REALLOC(*rparam,*rparam_len);
2650   SSVALS(*rparam,0,desc.errcode);
2651   SSVAL(*rparam,2,0);
2652   SSVAL(*rparam,4,succnt);
2653   SSVAL(*rparam,6,1);
2654
2655   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
2656   return(True);
2657 }
2658
2659 static BOOL api_WPrintPortEnum(int cnum,uint16 vuid, char *param,char *data,
2660                                int mdrcnt,int mprcnt,
2661                                char **rdata,char **rparam,
2662                                int *rdata_len,int *rparam_len)
2663 {
2664   char *str1 = param+2;
2665   char *str2 = skip_string(str1,1);
2666   char *p = skip_string(str2,1);
2667   int uLevel,cbBuf;
2668   int succnt;
2669   struct pack_desc desc;
2670
2671   bzero(&desc,sizeof(desc));
2672
2673   uLevel = SVAL(p,0);
2674   cbBuf = SVAL(p,2);
2675
2676   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
2677
2678   /* check it's a supported varient */
2679   if (strcmp(str1,"WrLeh") != 0) return False;
2680   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
2681
2682   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2683   bzero(&desc,sizeof(desc));
2684   desc.base = *rdata;
2685   desc.buflen = mdrcnt;
2686   desc.format = str2;
2687   if (init_package(&desc,1,0)) {
2688     PACKS(&desc,"B13","lp0");
2689   }
2690
2691   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2692
2693   *rdata_len = desc.usedlen;
2694
2695   *rparam_len = 8;
2696   *rparam = REALLOC(*rparam,*rparam_len);
2697   SSVALS(*rparam,0,desc.errcode);
2698   SSVAL(*rparam,2,0);
2699   SSVAL(*rparam,4,succnt);
2700   SSVAL(*rparam,6,1);
2701
2702   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
2703   return(True);
2704 }
2705
2706
2707 struct
2708 {
2709   char * name;
2710   char * pipename;
2711   int subcommand;
2712   BOOL (*fn) ();
2713 } api_fd_commands [] =
2714   {
2715     { "SetNmdPpHndState",       "lsarpc",       1,      api_LsarpcSNPHS },
2716     { "TransactNmPipe", "lsarpc",       0x26,   api_LsarpcTNP },
2717     { NULL,             NULL,           -1,     (BOOL (*)())api_Unsupported }
2718   };
2719
2720 /****************************************************************************
2721   handle remote api calls delivered to a named pipe already opened.
2722   ****************************************************************************/
2723 static int api_fd_reply(int cnum,uint16 vuid,char *outbuf,
2724                         uint16 *setup,char *data,char *params,
2725                         int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
2726 {
2727   char *rdata = NULL;
2728   char *rparam = NULL;
2729   int rdata_len = 0;
2730   int rparam_len = 0;
2731   BOOL reply=False;
2732   int i;
2733   int fd;
2734   int subcommand;
2735   
2736   /* First find out the name of this file. */
2737   if (suwcnt != 2)
2738     {
2739       DEBUG(0,("Unexpected named pipe transaction.\n"));
2740       return(-1);
2741     }
2742   
2743   /* Get the file handle and hence the file name. */
2744   fd = setup[1];
2745   subcommand = setup[0];
2746   
2747   DEBUG(3,("Got API command %d on pipe %s ",subcommand,Files[fd].name));
2748   DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
2749            tdscnt,tpscnt,mdrcnt,mprcnt));
2750   
2751   for (i=0;api_fd_commands[i].name;i++)
2752     if (strequal(api_fd_commands[i].pipename, Files[fd].name) &&
2753         api_fd_commands[i].subcommand == subcommand &&
2754         api_fd_commands[i].fn)
2755       {
2756         DEBUG(3,("Doing %s\n",api_fd_commands[i].name));
2757         break;
2758       }
2759   
2760   rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
2761   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
2762   
2763   reply = api_fd_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
2764                                 &rdata,&rparam,&rdata_len,&rparam_len);
2765   
2766   if (rdata_len > mdrcnt ||
2767       rparam_len > mprcnt)
2768     {
2769       reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
2770                            &rdata,&rparam,&rdata_len,&rparam_len);
2771     }
2772   
2773   
2774   /* if we get False back then it's actually unsupported */
2775   if (!reply)
2776     api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
2777                     &rdata,&rparam,&rdata_len,&rparam_len);
2778   
2779   /* now send the reply */
2780   send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
2781   
2782   if (rdata)
2783     free(rdata);
2784   if (rparam)
2785     free(rparam);
2786   
2787   return(-1);
2788 }
2789
2790
2791
2792 /****************************************************************************
2793   the buffer was too small
2794   ****************************************************************************/
2795 static BOOL api_TooSmall(int cnum,uint16 vuid, char *param,char *data,
2796                          int mdrcnt,int mprcnt,
2797                          char **rdata,char **rparam,
2798                          int *rdata_len,int *rparam_len)
2799 {
2800   *rparam_len = MIN(*rparam_len,mprcnt);
2801   *rparam = REALLOC(*rparam,*rparam_len);
2802
2803   *rdata_len = 0;
2804
2805   SSVAL(*rparam,0,NERR_BufTooSmall);
2806
2807   DEBUG(3,("Supplied buffer too small in API command\n"));
2808
2809   return(True);
2810 }
2811
2812
2813 /****************************************************************************
2814   the request is not supported
2815   ****************************************************************************/
2816 static BOOL api_Unsupported(int cnum,uint16 vuid, char *param,char *data,
2817                             int mdrcnt,int mprcnt,
2818                             char **rdata,char **rparam,
2819                             int *rdata_len,int *rparam_len)
2820 {
2821   *rparam_len = 4;
2822   *rparam = REALLOC(*rparam,*rparam_len);
2823
2824   *rdata_len = 0;
2825
2826   SSVAL(*rparam,0,NERR_notsupported);
2827   SSVAL(*rparam,2,0);           /* converter word */
2828
2829   DEBUG(3,("Unsupported API command\n"));
2830
2831   return(True);
2832 }
2833
2834
2835
2836
2837 struct
2838 {
2839   char *name;
2840   int id;
2841   BOOL (*fn)();
2842   int flags;
2843 } api_commands[] = {
2844   {"RNetShareEnum",     0,      (BOOL (*)())api_RNetShareEnum,0},
2845   {"RNetShareGetInfo",  1,      (BOOL (*)())api_RNetShareGetInfo,0},
2846   {"RNetServerGetInfo", 13,     (BOOL (*)())api_RNetServerGetInfo,0},
2847   {"RNetUserGetInfo",   56,     (BOOL (*)())api_RNetUserGetInfo,0},
2848   {"NetUserGetGroups",  59,     (BOOL (*)())api_NetUserGetGroups,0},
2849   {"NetWkstaGetInfo",   63,     (BOOL (*)())api_NetWkstaGetInfo,0},
2850   {"DosPrintQEnum",     69,     (BOOL (*)())api_DosPrintQEnum,0},
2851   {"DosPrintQGetInfo",  70,     (BOOL (*)())api_DosPrintQGetInfo,0},
2852   {"WPrintJobEnumerate",76,     (BOOL (*)())api_WPrintJobEnumerate,0},
2853   {"WPrintJobGetInfo",  77,     (BOOL (*)())api_WPrintJobGetInfo,0},
2854   {"RDosPrintJobDel",   81,     (BOOL (*)())api_RDosPrintJobDel,0},
2855   {"RDosPrintJobPause", 82,     (BOOL (*)())api_RDosPrintJobDel,0},
2856   {"RDosPrintJobResume",83,     (BOOL (*)())api_RDosPrintJobDel,0},
2857   {"WPrintDestEnum",    84,     (BOOL (*)())api_WPrintDestEnum,0},
2858   {"WPrintDestGetInfo", 85,     (BOOL (*)())api_WPrintDestGetInfo,0},
2859   {"NetRemoteTOD",      91,     (BOOL (*)())api_NetRemoteTOD,0},
2860   {"WPrintQueuePurge",  103,    (BOOL (*)())api_WPrintQueuePurge,0},
2861   {"NetServerEnum",     104,    (BOOL (*)())api_RNetServerEnum,0},
2862   {"WAccessGetUserPerms",105,   (BOOL (*)())api_WAccessGetUserPerms,0},
2863   {"SetUserPassword",   115,    (BOOL (*)())api_SetUserPassword,0},
2864   {"WWkstaUserLogon",   132,    (BOOL (*)())api_WWkstaUserLogon,0},
2865   {"PrintJobInfo",      147,    (BOOL (*)())api_PrintJobInfo,0},
2866   {"WPrintDriverEnum",  205,    (BOOL (*)())api_WPrintDriverEnum,0},
2867   {"WPrintQProcEnum",   206,    (BOOL (*)())api_WPrintQProcEnum,0},
2868   {"WPrintPortEnum",    207,    (BOOL (*)())api_WPrintPortEnum,0},
2869   {NULL,                -1,     (BOOL (*)())api_Unsupported,0}};
2870
2871
2872 /****************************************************************************
2873   handle remote api calls
2874   ****************************************************************************/
2875 static int api_reply(int cnum,uint16 vuid,char *outbuf,char *data,char *params,
2876                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
2877 {
2878   int api_command = SVAL(params,0);
2879   char *rdata = NULL;
2880   char *rparam = NULL;
2881   int rdata_len = 0;
2882   int rparam_len = 0;
2883   BOOL reply=False;
2884   int i;
2885
2886   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
2887            api_command,params+2,skip_string(params+2,1),
2888            tdscnt,tpscnt,mdrcnt,mprcnt));
2889
2890   for (i=0;api_commands[i].name;i++)
2891     if (api_commands[i].id == api_command && api_commands[i].fn)
2892       {
2893         DEBUG(3,("Doing %s\n",api_commands[i].name));
2894         break;
2895       }
2896
2897   rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
2898   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
2899
2900   reply = api_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
2901                              &rdata,&rparam,&rdata_len,&rparam_len);
2902
2903
2904   if (rdata_len > mdrcnt ||
2905       rparam_len > mprcnt)
2906     {
2907       reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
2908                            &rdata,&rparam,&rdata_len,&rparam_len);
2909     }
2910             
2911
2912   /* if we get False back then it's actually unsupported */
2913   if (!reply)
2914     api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
2915                     &rdata,&rparam,&rdata_len,&rparam_len);
2916
2917       
2918
2919   /* now send the reply */
2920   send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
2921
2922   if (rdata)
2923     free(rdata);
2924   if (rparam)
2925     free(rparam);
2926   
2927   return(-1);
2928 }
2929
2930 /****************************************************************************
2931   handle named pipe commands
2932   ****************************************************************************/
2933 static int named_pipe(int cnum,uint16 vuid, char *outbuf,char *name,
2934                       uint16 *setup,char *data,char *params,
2935                       int suwcnt,int tdscnt,int tpscnt,
2936                       int msrcnt,int mdrcnt,int mprcnt)
2937 {
2938
2939   if (strequal(name,"LANMAN"))
2940     return(api_reply(cnum,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
2941
2942 if (strlen(name) < 1)
2943   return(api_fd_reply(cnum,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt));
2944
2945
2946   DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
2947            name,(int)setup[0],(int)setup[1]));
2948   
2949   return(0);
2950 }
2951
2952
2953 /****************************************************************************
2954   reply to a SMBtrans
2955   ****************************************************************************/
2956 int reply_trans(char *inbuf,char *outbuf)
2957 {
2958   fstring name;
2959
2960   char *data=NULL,*params=NULL;
2961   uint16 *setup=NULL;
2962
2963   int outsize = 0;
2964   int cnum = SVAL(inbuf,smb_tid);
2965   uint16 vuid = SVAL(inbuf,smb_uid);
2966
2967   int tpscnt = SVAL(inbuf,smb_vwv0);
2968   int tdscnt = SVAL(inbuf,smb_vwv1);
2969   int mprcnt = SVAL(inbuf,smb_vwv2);
2970   int mdrcnt = SVAL(inbuf,smb_vwv3);
2971   int msrcnt = CVAL(inbuf,smb_vwv4);
2972   BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
2973   BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
2974   int pscnt = SVAL(inbuf,smb_vwv9);
2975   int psoff = SVAL(inbuf,smb_vwv10);
2976   int dscnt = SVAL(inbuf,smb_vwv11);
2977   int dsoff = SVAL(inbuf,smb_vwv12);
2978   int suwcnt = CVAL(inbuf,smb_vwv13);
2979
2980   StrnCpy(name,smb_buf(inbuf),sizeof(name)-1);
2981   
2982   if (tdscnt)
2983     {
2984       data = (char *)malloc(tdscnt);
2985       memcpy(data,smb_base(inbuf)+dsoff,dscnt);
2986     }
2987   if (tpscnt)
2988     {
2989       params = (char *)malloc(tpscnt);
2990       memcpy(params,smb_base(inbuf)+psoff,pscnt);
2991     }
2992
2993   if (suwcnt)
2994     {
2995       int i;
2996       setup = (uint16 *)malloc(suwcnt*sizeof(setup[0]));
2997       for (i=0;i<suwcnt;i++)
2998         setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
2999     }
3000
3001
3002   if (pscnt < tpscnt || dscnt < tdscnt)
3003     {
3004       /* We need to send an interim response then receive the rest
3005          of the parameter/data bytes */
3006       outsize = set_message(outbuf,0,0,True);
3007       show_msg(outbuf);
3008       send_smb(Client,outbuf);
3009     }
3010
3011   /* receive the rest of the trans packet */
3012   while (pscnt < tpscnt || dscnt < tdscnt)
3013     {
3014       int pcnt,poff,dcnt,doff,pdisp,ddisp;
3015       
3016       if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
3017           CVAL(inbuf, smb_com) != SMBtrans)
3018         {
3019           DEBUG(2,("Invalid secondary trans2 packet\n"));
3020           if (params) free(params);
3021           if (data) free(data);
3022           if (setup) free(setup);
3023           return(ERROR(ERRSRV,ERRerror));
3024         }
3025
3026       show_msg(inbuf);
3027       
3028       tpscnt = SVAL(inbuf,smb_vwv0);
3029       tdscnt = SVAL(inbuf,smb_vwv1);
3030
3031       pcnt = SVAL(inbuf,smb_vwv2);
3032       poff = SVAL(inbuf,smb_vwv3);
3033       pdisp = SVAL(inbuf,smb_vwv4);
3034       
3035       dcnt = SVAL(inbuf,smb_vwv5);
3036       doff = SVAL(inbuf,smb_vwv6);
3037       ddisp = SVAL(inbuf,smb_vwv7);
3038       
3039       pscnt += pcnt;
3040       dscnt += dcnt;
3041
3042       if (pcnt)
3043         memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
3044       if (dcnt)
3045         memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);      
3046     }
3047
3048
3049   DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt));
3050   
3051
3052   if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0)
3053     outsize = named_pipe(cnum,vuid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
3054                          suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
3055
3056
3057   if (data) free(data);
3058   if (params) free(params);
3059   if (setup) free(setup);
3060
3061   if (close_on_completion)
3062     close_cnum(cnum,vuid);
3063
3064   if (one_way)
3065     return(-1);
3066   
3067   if (outsize == 0)
3068     return(ERROR(ERRSRV,ERRnosupport));
3069
3070   return(outsize);
3071 }
3072
3073