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