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