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