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