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