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