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