removed all of lukes recent changes. I need to do a p2 release but
[nivanova/samba-autobuild/.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 1
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,missed;
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   missed = 0;
995
996   qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
997
998   {
999     char *lastname=NULL;
1000
1001     for (i=0;i<total;i++)
1002     {
1003       struct srv_info_struct *s = &servers[i];
1004       if (lastname && strequal(lastname,s->name)) continue;
1005       lastname = s->name;
1006       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1007       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1008                s->name, s->type, s->comment, s->domain));
1009       
1010       if (data_len <= buf_len) {
1011           counted++;
1012           fixed_len += f_len;
1013           string_len += s_len;
1014       } else {
1015         missed++;
1016       }
1017     }
1018   }
1019
1020   *rdata_len = fixed_len + string_len;
1021   *rdata = REALLOC(*rdata,*rdata_len);
1022   bzero(*rdata,*rdata_len);
1023   
1024   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1025   p = *rdata;
1026   f_len = fixed_len;
1027   s_len = string_len;
1028
1029   {
1030     char *lastname=NULL;
1031     int count2 = counted;
1032     for (i = 0; i < total && count2;i++)
1033       {
1034         struct srv_info_struct *s = &servers[i];
1035         if (lastname && strequal(lastname,s->name)) continue;
1036         lastname = s->name;
1037         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1038         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1039                  s->name, s->type, s->comment, s->domain));
1040         count2--;
1041       }
1042   }
1043   
1044   *rparam_len = 8;
1045   *rparam = REALLOC(*rparam,*rparam_len);
1046   SSVAL(*rparam,0,NERR_Success);
1047   SSVAL(*rparam,2,0);
1048   SSVAL(*rparam,4,counted);
1049   SSVAL(*rparam,6,counted+missed);
1050
1051   if (servers) free(servers);
1052
1053   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1054            domain,uLevel,counted,counted+missed));
1055
1056   return(True);
1057 }
1058
1059
1060 /****************************************************************************
1061   get info about a share
1062   ****************************************************************************/
1063 static BOOL check_share_info(int uLevel, char* id)
1064 {
1065   switch( uLevel ) {
1066   case 0:
1067     if (strcmp(id,"B13") != 0) return False;
1068     break;
1069   case 1:
1070     if (strcmp(id,"B13BWz") != 0) return False;
1071     break;
1072   case 2:
1073     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1074     break;
1075   case 91:
1076     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1077     break;
1078   default: return False;
1079   }
1080   return True;
1081 }
1082
1083 static int fill_share_info(int cnum, int snum, int uLevel,
1084                            char** buf, int* buflen,
1085                            char** stringbuf, int* stringspace, char* baseaddr)
1086 {
1087   int struct_len;
1088   char* p;
1089   char* p2;
1090   int l2;
1091   int len;
1092  
1093   switch( uLevel ) {
1094   case 0: struct_len = 13; break;
1095   case 1: struct_len = 20; break;
1096   case 2: struct_len = 40; break;
1097   case 91: struct_len = 68; break;
1098   default: return -1;
1099   }
1100   
1101  
1102   if (!buf)
1103     {
1104       len = 0;
1105       if (uLevel > 0) len += StrlenExpanded(cnum,snum,lp_comment(snum));
1106       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1107       if (buflen) *buflen = struct_len;
1108       if (stringspace) *stringspace = len;
1109       return struct_len + len;
1110     }
1111   
1112   len = struct_len;
1113   p = *buf;
1114   if ((*buflen) < struct_len) return -1;
1115   if (stringbuf)
1116     {
1117       p2 = *stringbuf;
1118       l2 = *stringspace;
1119     }
1120   else
1121     {
1122       p2 = p + struct_len;
1123       l2 = (*buflen) - struct_len;
1124     }
1125   if (!baseaddr) baseaddr = p;
1126   
1127   StrnCpy(p,lp_servicename(snum),13);
1128   
1129   if (uLevel > 0)
1130     {
1131       int type;
1132       CVAL(p,13) = 0;
1133       type = STYPE_DISKTREE;
1134       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1135       if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1136       SSVAL(p,14,type);         /* device type */
1137       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1138       len += CopyExpanded(cnum,snum,&p2,lp_comment(snum),&l2);
1139     }
1140   
1141   if (uLevel > 1)
1142     {
1143       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1144       SSVALS(p,22,-1);          /* max uses */
1145       SSVAL(p,24,1); /* current uses */
1146       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1147       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1148       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1149     }
1150   
1151   if (uLevel > 2)
1152     {
1153       memset(p+40,0,SHPWLEN+2);
1154       SSVAL(p,50,0);
1155       SIVAL(p,52,0);
1156       SSVAL(p,56,0);
1157       SSVAL(p,58,0);
1158       SIVAL(p,60,0);
1159       SSVAL(p,64,0);
1160       SSVAL(p,66,0);
1161     }
1162        
1163   if (stringbuf)
1164     {
1165       (*buf) = p + struct_len;
1166       (*buflen) -= struct_len;
1167       (*stringbuf) = p2;
1168       (*stringspace) = l2;
1169     }
1170   else
1171     {
1172       (*buf) = p2;
1173       (*buflen) -= len;
1174     }
1175   return len;
1176 }
1177
1178 static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
1179                                  int mdrcnt,int mprcnt,
1180                                  char **rdata,char **rparam,
1181                                  int *rdata_len,int *rparam_len)
1182 {
1183   char *str1 = param+2;
1184   char *str2 = skip_string(str1,1);
1185   char *netname = skip_string(str2,1);
1186   char *p = skip_string(netname,1);
1187   int uLevel = SVAL(p,0);
1188   int snum = find_service(netname);
1189   
1190   if (snum < 0) return False;
1191   
1192   /* check it's a supported varient */
1193   if (!prefix_ok(str1,"zWrLh")) return False;
1194   if (!check_share_info(uLevel,str2)) return False;
1195  
1196   *rdata = REALLOC(*rdata,mdrcnt);
1197   p = *rdata;
1198   *rdata_len = fill_share_info(cnum,snum,uLevel,&p,&mdrcnt,0,0,0);
1199   if (*rdata_len < 0) return False;
1200  
1201   *rparam_len = 6;
1202   *rparam = REALLOC(*rparam,*rparam_len);
1203   SSVAL(*rparam,0,NERR_Success);
1204   SSVAL(*rparam,2,0);           /* converter word */
1205   SSVAL(*rparam,4,*rdata_len);
1206  
1207   return(True);
1208 }
1209
1210 /****************************************************************************
1211   view list of shares available
1212   ****************************************************************************/
1213 static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
1214                               int mdrcnt,int mprcnt,
1215                               char **rdata,char **rparam,
1216                               int *rdata_len,int *rparam_len)
1217 {
1218   char *str1 = param+2;
1219   char *str2 = skip_string(str1,1);
1220   char *p = skip_string(str2,1);
1221   int uLevel = SVAL(p,0);
1222   int buf_len = SVAL(p,2);
1223   char *p2;
1224   int count=lp_numservices();
1225   int total=0,counted=0;
1226   int i;
1227   int data_len, fixed_len, string_len;
1228   int f_len, s_len;
1229  
1230   if (!prefix_ok(str1,"WrLeh")) return False;
1231   if (!check_share_info(uLevel,str2)) return False;
1232   
1233   data_len = fixed_len = string_len = 0;
1234   for (i=0;i<count;i++)
1235     if (lp_browseable(i) && lp_snum_ok(i))
1236       {
1237         total++;
1238         data_len += fill_share_info(cnum,i,uLevel,0,&f_len,0,&s_len,0);
1239         if (data_len <= buf_len)
1240           {
1241             counted++;
1242             fixed_len += f_len;
1243             string_len += s_len;
1244           }
1245       }
1246   *rdata_len = fixed_len + string_len;
1247   *rdata = REALLOC(*rdata,*rdata_len);
1248   memset(*rdata,0,*rdata_len);
1249   
1250   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1251   p = *rdata;
1252   f_len = fixed_len;
1253   s_len = string_len;
1254   for (i = 0; i < count;i++)
1255     if (lp_browseable(i) && lp_snum_ok(i))
1256       if (fill_share_info(cnum,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1257         break;
1258   
1259   *rparam_len = 8;
1260   *rparam = REALLOC(*rparam,*rparam_len);
1261   SSVAL(*rparam,0,NERR_Success);
1262   SSVAL(*rparam,2,0);
1263   SSVAL(*rparam,4,counted);
1264   SSVAL(*rparam,6,total);
1265   
1266   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1267            counted,total,uLevel,
1268            buf_len,*rdata_len,mdrcnt));
1269   return(True);
1270 }
1271
1272
1273
1274 /****************************************************************************
1275   get the time of day info
1276   ****************************************************************************/
1277 static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
1278                              int mdrcnt,int mprcnt,
1279                              char **rdata,char **rparam,
1280                              int *rdata_len,int *rparam_len)
1281 {
1282   char *p;
1283   *rparam_len = 4;
1284   *rparam = REALLOC(*rparam,*rparam_len);
1285
1286   *rdata_len = 21;
1287   *rdata = REALLOC(*rdata,*rdata_len);
1288
1289   SSVAL(*rparam,0,NERR_Success);
1290   SSVAL(*rparam,2,0);           /* converter word */
1291
1292   p = *rdata;
1293
1294   {
1295     struct tm *t;
1296     time_t unixdate = time(NULL);
1297
1298     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1299                                     by NT in a "net time" operation,
1300                                     it seems to ignore the one below */
1301
1302     /* the client expects to get localtime, not GMT, in this bit 
1303        (I think, this needs testing) */
1304     t = LocalTime(&unixdate);
1305
1306     SIVAL(p,4,0);               /* msecs ? */
1307     CVAL(p,8) = t->tm_hour;
1308     CVAL(p,9) = t->tm_min;
1309     CVAL(p,10) = t->tm_sec;
1310     CVAL(p,11) = 0;             /* hundredths of seconds */
1311     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1312     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1313     CVAL(p,16) = t->tm_mday;
1314     CVAL(p,17) = t->tm_mon + 1;
1315     SSVAL(p,18,1900+t->tm_year);
1316     CVAL(p,20) = t->tm_wday;
1317   }
1318
1319
1320   return(True);
1321 }
1322
1323 /****************************************************************************
1324   set the user password
1325   ****************************************************************************/
1326 static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
1327                                 int mdrcnt,int mprcnt,
1328                                 char **rdata,char **rparam,
1329                                 int *rdata_len,int *rparam_len)
1330 {
1331   char *p = skip_string(param+2,2);
1332   fstring user;
1333   fstring pass1,pass2;
1334
1335   strcpy(user,p);
1336
1337   p = skip_string(p,1);
1338
1339   StrnCpy(pass1,p,16);
1340   StrnCpy(pass2,p+16,16);
1341
1342   *rparam_len = 4;
1343   *rparam = REALLOC(*rparam,*rparam_len);
1344
1345   *rdata_len = 0;
1346
1347   SSVAL(*rparam,0,NERR_badpass);
1348   SSVAL(*rparam,2,0);           /* converter word */
1349
1350   DEBUG(3,("Set password for <%s>\n",user));
1351
1352   if (password_ok(user,pass1,strlen(pass1),NULL,False) &&
1353       chgpasswd(user,pass1,pass2))
1354   {
1355     SSVAL(*rparam,0,NERR_Success);
1356   }
1357
1358   bzero(pass1,sizeof(fstring));
1359   bzero(pass2,sizeof(fstring));  
1360          
1361   return(True);
1362 }
1363
1364 /****************************************************************************
1365   delete a print job
1366   Form: <W> <> 
1367   ****************************************************************************/
1368 static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
1369                                 int mdrcnt,int mprcnt,
1370                                 char **rdata,char **rparam,
1371                                 int *rdata_len,int *rparam_len)
1372 {
1373   int function = SVAL(param,0);
1374   char *str1 = param+2;
1375   char *str2 = skip_string(str1,1);
1376   char *p = skip_string(str2,1);
1377   int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
1378                                    by the print queue api */
1379   int snum = (SVAL(p,0)>>8);  
1380   int i, count;
1381
1382
1383   /* check it's a supported varient */
1384   if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1385     return(False);
1386
1387   *rparam_len = 4;
1388   *rparam = REALLOC(*rparam,*rparam_len);
1389
1390   *rdata_len = 0;
1391
1392   SSVAL(*rparam,0,NERR_Success);
1393
1394   if (snum >= 0 && VALID_SNUM(snum))
1395     {
1396       print_queue_struct *queue=NULL;
1397       lpq_reset(snum);
1398       count = get_printqueue(snum,cnum,&queue,NULL);
1399   
1400       for (i=0;i<count;i++)
1401         if ((queue[i].job%0xFF) == jobid)
1402           {
1403             switch (function) {
1404             case 81:            /* delete */ 
1405               DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
1406               del_printqueue(cnum,snum,queue[i].job);
1407               break;
1408             case 82:            /* pause */
1409             case 83:            /* resume */
1410               DEBUG(3,("%s queue entry %d\n",
1411                        (function==82?"pausing":"resuming"),queue[i].job));
1412               status_printjob(cnum,snum,queue[i].job,
1413                               (function==82?LPQ_PAUSED:LPQ_QUEUED));
1414               break;
1415             }
1416             break;
1417           }
1418   
1419       if (i==count)
1420         SSVAL(*rparam,0,NERR_JobNotFound);
1421
1422       if (queue) free(queue);
1423     }
1424
1425   SSVAL(*rparam,2,0);           /* converter word */
1426
1427   return(True);
1428 }
1429
1430 static BOOL api_WPrintQueuePurge(int cnum,int uid, char *param,char *data,
1431                                  int mdrcnt,int mprcnt,
1432                                  char **rdata,char **rparam,
1433                                  int *rdata_len,int *rparam_len)
1434 {
1435   char *str1 = param+2;
1436   char *str2 = skip_string(str1,1);
1437   char *QueueName = skip_string(str2,1);
1438   int snum;
1439
1440   /* check it's a supported varient */
1441   if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1442     return(False);
1443
1444   *rparam_len = 4;
1445   *rparam = REALLOC(*rparam,*rparam_len);
1446
1447   *rdata_len = 0;
1448
1449   SSVAL(*rparam,0,NERR_Success);
1450   SSVAL(*rparam,2,0);           /* converter word */
1451
1452   snum = lp_servicenumber(QueueName);
1453   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
1454     int pnum = lp_servicenumber(PRINTERS_NAME);
1455     if (pnum >= 0) {
1456       lp_add_printer(QueueName,pnum);
1457       snum = lp_servicenumber(QueueName);
1458     }
1459   }
1460
1461   if (snum >= 0 && VALID_SNUM(snum)) {
1462     print_queue_struct *queue=NULL;
1463     int i, count;
1464     lpq_reset(snum);
1465     
1466     count = get_printqueue(snum,cnum,&queue,NULL);
1467     for (i = 0; i < count; i++)
1468       del_printqueue(cnum,snum,queue[i].job);
1469     
1470     if (queue) free(queue);
1471   }
1472
1473   DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
1474
1475   return(True);
1476 }
1477
1478
1479 /****************************************************************************
1480   set the property of a print job (undocumented?)
1481   ? function = 0xb -> set name of print job
1482   ? function = 0x6 -> move print job up/down
1483   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1484   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1485 ****************************************************************************/
1486 static int check_printjob_info(struct pack_desc* desc,
1487                                int uLevel, char* id)
1488 {
1489   desc->subformat = NULL;
1490   switch( uLevel ) {
1491   case 0: desc->format = "W"; break;
1492   case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1493   case 2: desc->format = "WWzWWDDzz"; break;
1494   case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1495   default: return False;
1496   }
1497   if (strcmp(desc->format,id) != 0) return False;
1498   return True;
1499 }
1500
1501 static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
1502                              int mdrcnt,int mprcnt,
1503                              char **rdata,char **rparam,
1504                              int *rdata_len,int *rparam_len)
1505 {
1506   struct pack_desc desc;
1507   char *str1 = param+2;
1508   char *str2 = skip_string(str1,1);
1509   char *p = skip_string(str2,1);
1510   int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
1511                                    by the print queue api */
1512   int snum = (SVAL(p,0)>>8);
1513   int uLevel = SVAL(p,2);
1514   int function = SVAL(p,4);     /* what is this ?? */
1515   int i;
1516   char *s = data;
1517    
1518   *rparam_len = 4;
1519   *rparam = REALLOC(*rparam,*rparam_len);
1520   
1521   *rdata_len = 0;
1522   
1523   /* check it's a supported varient */
1524   if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
1525     return(False);
1526    
1527   switch (function) {
1528   case 0x6:     /* change job place in the queue, data gives the new place */
1529     if (snum >= 0 && VALID_SNUM(snum))
1530       {
1531         print_queue_struct *queue=NULL;
1532         int count;
1533   
1534         lpq_reset(snum);
1535         count = get_printqueue(snum,cnum,&queue,NULL);
1536         for (i=0;i<count;i++)   /* find job */
1537           if ((queue[i].job%0xFF) == jobid) break;
1538             
1539         if (i==count) {
1540           desc.errcode=NERR_JobNotFound;
1541           if (queue) free(queue);
1542         }
1543         else {
1544           desc.errcode=NERR_Success;
1545           i++;
1546 #if 0   
1547           {
1548             int place= SVAL(data,0);
1549             /* we currently have no way of doing this. Can any unix do it? */
1550             if (i < place)      /* move down */;
1551             else if (i > place )        /* move up */;
1552           }
1553 #endif
1554           desc.errcode=NERR_notsupported; /* not yet supported */
1555           if (queue) free(queue);
1556         }
1557       }
1558     else desc.errcode=NERR_JobNotFound;
1559     break;
1560   case 0xb:   /* change print job name, data gives the name */
1561     /* jobid, snum should be zero */
1562     if (isalpha(*s))
1563       {
1564         pstring name;
1565         int l = 0;
1566         while (l<64 && *s)
1567           {
1568             if (issafe(*s)) name[l++] = *s;
1569             s++;
1570           }      
1571         name[l] = 0;
1572         
1573         DEBUG(3,("Setting print name to %s\n",name));
1574         
1575         for (i=0;i<MAX_OPEN_FILES;i++)
1576           if (Files[i].open && Files[i].print_file)
1577             {
1578               pstring wd;
1579               GetWd(wd);
1580               unbecome_user();
1581               
1582               if (!become_user(Files[i].cnum,uid) || 
1583                   !become_service(Files[i].cnum,True))
1584                 break;
1585               
1586               if (sys_rename(Files[i].name,name) == 0)
1587                 string_set(&Files[i].name,name);
1588               break;
1589             }
1590       }
1591     desc.errcode=NERR_Success;
1592   
1593     break;
1594   default:                      /* not implemented */
1595     return False;
1596   }
1597  
1598   SSVALS(*rparam,0,desc.errcode);
1599   SSVAL(*rparam,2,0);           /* converter word */
1600   
1601   return(True);
1602 }
1603
1604
1605 /****************************************************************************
1606   get info about the server
1607   ****************************************************************************/
1608 static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
1609                                   int mdrcnt,int mprcnt,
1610                                   char **rdata,char **rparam,
1611                                   int *rdata_len,int *rparam_len)
1612 {
1613   char *str1 = param+2;
1614   char *str2 = skip_string(str1,1);
1615   char *p = skip_string(str2,1);
1616   int uLevel = SVAL(p,0);
1617   char *p2;
1618   int struct_len;
1619
1620   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
1621
1622   /* check it's a supported varient */
1623   if (!prefix_ok(str1,"WrLh")) return False;
1624   switch( uLevel ) {
1625   case 0:
1626     if (strcmp(str2,"B16") != 0) return False;
1627     struct_len = 16;
1628     break;
1629   case 1:
1630     if (strcmp(str2,"B16BBDz") != 0) return False;
1631     struct_len = 26;
1632     break;
1633   case 2:
1634     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
1635         != 0) return False;
1636     struct_len = 134;
1637     break;
1638   case 3:
1639     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
1640         != 0) return False;
1641     struct_len = 144;
1642     break;
1643   case 20:
1644     if (strcmp(str2,"DN") != 0) return False;
1645     struct_len = 6;
1646     break;
1647   case 50:
1648     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
1649     struct_len = 42;
1650     break;
1651   default: return False;
1652   }
1653
1654   *rdata_len = mdrcnt;
1655   *rdata = REALLOC(*rdata,*rdata_len);
1656
1657   p = *rdata;
1658   p2 = p + struct_len;
1659   if (uLevel != 20) {
1660     StrnCpy(p,local_machine,16);
1661     strupper(p);
1662   }
1663   p += 16;
1664   if (uLevel > 0)
1665     {
1666       struct srv_info_struct *servers=NULL;
1667       int i,count;
1668       pstring comment;
1669       uint32 servertype=DFLT_SERVER_TYPE;
1670
1671       strcpy(comment,lp_serverstring());
1672
1673       if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
1674         for (i=0;i<count;i++)
1675           if (strequal(servers[i].name,local_machine)) {
1676             servertype = servers[i].type;
1677             strcpy(comment,servers[i].comment);     
1678           }
1679       }
1680       if (servers) free(servers);
1681
1682       SCVAL(p,0,MAJOR_VERSION);
1683       SCVAL(p,1,MINOR_VERSION);
1684       SIVAL(p,2,servertype);
1685
1686       if (mdrcnt == struct_len) {
1687         SIVAL(p,6,0);
1688       } else {
1689         SIVAL(p,6,PTR_DIFF(p2,*rdata));
1690         standard_sub(cnum,comment);
1691         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
1692         p2 = skip_string(p2,1);
1693       }
1694     }
1695   if (uLevel > 1)
1696     {
1697       return False;             /* not yet implemented */
1698     }
1699
1700   *rdata_len = PTR_DIFF(p2,*rdata);
1701
1702   *rparam_len = 6;
1703   *rparam = REALLOC(*rparam,*rparam_len);
1704   SSVAL(*rparam,0,NERR_Success);
1705   SSVAL(*rparam,2,0);           /* converter word */
1706   SSVAL(*rparam,4,*rdata_len);
1707
1708   return(True);
1709 }
1710
1711
1712 /****************************************************************************
1713   get info about the server
1714   ****************************************************************************/
1715 static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
1716                                 int mdrcnt,int mprcnt,
1717                                 char **rdata,char **rparam,
1718                                 int *rdata_len,int *rparam_len)
1719 {
1720   char *str1 = param+2;
1721   char *str2 = skip_string(str1,1);
1722   char *p = skip_string(str2,1);
1723   char *p2;
1724   extern pstring sesssetup_user;
1725   int level = SVAL(p,0);
1726
1727   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
1728
1729   *rparam_len = 6;
1730   *rparam = REALLOC(*rparam,*rparam_len);
1731
1732   /* check it's a supported varient */
1733   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
1734     return(False);
1735
1736   *rdata_len = mdrcnt + 1024;
1737   *rdata = REALLOC(*rdata,*rdata_len);
1738
1739   SSVAL(*rparam,0,NERR_Success);
1740   SSVAL(*rparam,2,0);           /* converter word */
1741
1742   p = *rdata;
1743   p2 = p + 22;
1744
1745   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1746   strcpy(p2,local_machine);
1747   p2 = skip_string(p2,1);
1748   p += 4;
1749
1750   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1751   strcpy(p2,sesssetup_user);
1752   p2 = skip_string(p2,1);
1753   p += 4;
1754
1755   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1756   strcpy(p2,lp_workgroup());
1757   p2 = skip_string(p2,1);
1758   p += 4;
1759
1760   SCVAL(p,0,MAJOR_VERSION); 
1761   SCVAL(p,1,MINOR_VERSION); 
1762   p += 2;
1763
1764   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1765   strcpy(p2,lp_workgroup());    /* login domain?? */
1766   p2 = skip_string(p2,1);
1767   p += 4;
1768
1769   SIVAL(p,0,PTR_DIFF(p2,*rdata));
1770   strcpy(p2,"");
1771   p2 = skip_string(p2,1);
1772   p += 4;
1773
1774   *rdata_len = PTR_DIFF(p2,*rdata);
1775
1776   SSVAL(*rparam,4,*rdata_len);
1777
1778   return(True);
1779 }
1780
1781
1782 /****************************************************************************
1783   get info about a user
1784   ****************************************************************************/
1785
1786 #define USER_PRIV_GUEST 0
1787 #define USER_PRIV_USER 1
1788 #define USER_PRIV_ADMIN 2
1789
1790 static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
1791                                 int mdrcnt,int mprcnt,
1792                                 char **rdata,char **rparam,
1793                                 int *rdata_len,int *rparam_len)
1794 {
1795   char *str1 = param+2;
1796   char *str2 = skip_string(str1,1);
1797   char *UserName = skip_string(str2,1);
1798   char *p = skip_string(UserName,1);
1799   int uLevel = SVAL(p,0);
1800   char *p2;
1801
1802   *rparam_len = 6;
1803   *rparam = REALLOC(*rparam,*rparam_len);
1804
1805   /* check it's a supported varient */
1806   if (strcmp(str1,"zWrLh") != 0) return False;
1807   switch( uLevel ) {
1808   case 0: p2 = "B21"; break;
1809   case 1: p2 = "B21BB16DWzzWz"; break;
1810   case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
1811   case 10: p2 = "B21Bzzz"; break;
1812   case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
1813   default: return False;
1814   }
1815   if (strcmp(p2,str2) != 0) return False;
1816
1817   *rdata_len = mdrcnt + 1024;
1818   *rdata = REALLOC(*rdata,*rdata_len);
1819
1820   SSVAL(*rparam,0,NERR_Success);
1821   SSVAL(*rparam,2,0);           /* converter word */
1822
1823   p = *rdata;
1824   p2 = p + 86;
1825
1826   memset(p,0,21);
1827   strcpy(p,UserName);
1828   if (uLevel > 0) {
1829     SCVAL(p,21,0);
1830     *p2 = 0;
1831     if (uLevel >= 10) {
1832       SIVAL(p,22,PTR_DIFF(p2,p)); /* comment */
1833       strcpy(p2,"<Comment>");
1834       p2 = skip_string(p2,1);
1835       SIVAL(p,26,PTR_DIFF(p2,p)); /* user_comment */
1836       strcpy(p2,"<UserComment>");
1837       p2 = skip_string(p2,1);
1838       SIVAL(p,30,PTR_DIFF(p2,p)); /* full name */
1839       strcpy(p2,"<FullName>");
1840       p2 = skip_string(p2,1);
1841     }
1842     if (uLevel == 11) {         /* modelled after NTAS 3.51 reply */
1843       SSVAL(p,34,
1844             Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
1845       SIVAL(p,36,0);            /* auth flags */
1846       SIVALS(p,40,-1);          /* password age */
1847       SIVAL(p,44,PTR_DIFF(p2,p)); /* home dir */
1848       strcpy(p2,"\\\\%L\\HOMES");
1849       standard_sub_basic(p2);
1850       p2 = skip_string(p2,1);
1851       SIVAL(p,48,PTR_DIFF(p2,p)); /* parms */
1852       strcpy(p2,"");
1853       p2 = skip_string(p2,1);
1854       SIVAL(p,52,0);            /* last logon */
1855       SIVAL(p,56,0);            /* last logoff */
1856       SSVALS(p,60,-1);          /* bad pw counts */
1857       SSVALS(p,62,-1);          /* num logons */
1858       SIVAL(p,64,PTR_DIFF(p2,p)); /* logon server */
1859       strcpy(p2,"\\\\*");
1860       p2 = skip_string(p2,1);
1861       SSVAL(p,68,0);            /* country code */
1862
1863       SIVAL(p,70,PTR_DIFF(p2,p)); /* workstations */
1864       strcpy(p2,"");
1865       p2 = skip_string(p2,1);
1866
1867       SIVALS(p,74,-1);          /* max storage */
1868       SSVAL(p,78,168);          /* units per week */
1869       SIVAL(p,80,PTR_DIFF(p2,p)); /* logon hours */
1870       memset(p2,-1,21);
1871       SCVAL(p2,21,0);           /* fix zero termination */
1872       p2 = skip_string(p2,1);
1873
1874       SSVAL(p,84,0);            /* code page */
1875     }
1876     if (uLevel == 1 || uLevel == 2) {
1877       memset(p+22,' ',16);      /* password */
1878       SIVALS(p,38,-1);          /* password age */
1879       SSVAL(p,42,
1880             Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
1881       SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
1882       strcpy(p2,"\\\\%L\\HOMES");
1883       standard_sub_basic(p2);
1884       p2 = skip_string(p2,1);
1885       SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
1886       *p2++ = 0;
1887       SSVAL(p,52,0);            /* flags */
1888       SIVAL(p,54,0);            /* script_path */
1889       if (uLevel == 2) {
1890         SIVAL(p,60,0);          /* auth_flags */
1891         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
1892         strcpy(p2,"<Full Name>");
1893         p2 = skip_string(p2,1);
1894         SIVAL(p,68,0);          /* urs_comment */
1895         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
1896         strcpy(p2,"");
1897         p2 = skip_string(p2,1);
1898         SIVAL(p,76,0);          /* workstations */
1899         SIVAL(p,80,0);          /* last_logon */
1900         SIVAL(p,84,0);          /* last_logoff */
1901         SIVALS(p,88,-1);                /* acct_expires */
1902         SIVALS(p,92,-1);                /* max_storage */
1903         SSVAL(p,96,168);        /* units_per_week */
1904         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
1905         memset(p2,-1,21);
1906         p2 += 21;
1907         SSVALS(p,102,-1);       /* bad_pw_count */
1908         SSVALS(p,104,-1);       /* num_logons */
1909         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
1910         strcpy(p2,"\\\\%L");
1911         standard_sub_basic(p2);
1912         p2 = skip_string(p2,1);
1913         SSVAL(p,110,49);        /* country_code */
1914         SSVAL(p,112,860);       /* code page */
1915       }
1916     }
1917   }
1918
1919   *rdata_len = PTR_DIFF(p2,*rdata);
1920
1921   SSVAL(*rparam,4,*rdata_len);  /* is this right?? */
1922
1923   return(True);
1924 }
1925
1926
1927 /*******************************************************************
1928   get groups that a user is a member of
1929   ******************************************************************/
1930 static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
1931                                  int mdrcnt,int mprcnt,
1932                                  char **rdata,char **rparam,
1933                                  int *rdata_len,int *rparam_len)
1934 {
1935   char *str1 = param+2;
1936   char *str2 = skip_string(str1,1);
1937   char *UserName = skip_string(str2,1);
1938   char *p = skip_string(UserName,1);
1939   int uLevel = SVAL(p,0);
1940   char *p2;
1941   int count=0;
1942
1943   *rparam_len = 8;
1944   *rparam = REALLOC(*rparam,*rparam_len);
1945
1946   /* check it's a supported varient */
1947   if (strcmp(str1,"zWrLeh") != 0) return False;
1948   switch( uLevel ) {
1949   case 0: p2 = "B21"; break;
1950   default: return False;
1951   }
1952   if (strcmp(p2,str2) != 0) return False;
1953
1954   *rdata_len = mdrcnt + 1024;
1955   *rdata = REALLOC(*rdata,*rdata_len);
1956
1957   SSVAL(*rparam,0,NERR_Success);
1958   SSVAL(*rparam,2,0);           /* converter word */
1959
1960   p = *rdata;
1961
1962   /* XXXX we need a real SAM database some day */
1963   strcpy(p,"Users"); p += 21; count++;
1964   strcpy(p,"Domain Users"); p += 21; count++;
1965   strcpy(p,"Guests"); p += 21; count++;
1966   strcpy(p,"Domain Guests"); p += 21; count++;
1967
1968   *rdata_len = PTR_DIFF(p,*rdata);
1969
1970   SSVAL(*rparam,4,count);       /* is this right?? */
1971   SSVAL(*rparam,6,count);       /* is this right?? */
1972
1973   return(True);
1974 }
1975
1976
1977 static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
1978                                 int mdrcnt,int mprcnt,
1979                                 char **rdata,char **rparam,
1980                                 int *rdata_len,int *rparam_len)
1981 {
1982   char *str1 = param+2;
1983   char *str2 = skip_string(str1,1);
1984   char *p = skip_string(str2,1);
1985   int uLevel;
1986   struct pack_desc desc;
1987   char* name;
1988
1989   uLevel = SVAL(p,0);
1990   name = p + 2;
1991
1992   bzero(&desc,sizeof(desc));
1993
1994   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
1995
1996   /* check it's a supported varient */
1997   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
1998   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
1999   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2000   desc.base = *rdata;
2001   desc.buflen = mdrcnt;
2002   desc.subformat = NULL;
2003   desc.format = str2;
2004   
2005   
2006
2007   if (init_package(&desc,1,0)) {
2008     PACKI(&desc,"W",0);         /* code */
2009     PACKS(&desc,"B21",name);    /* eff. name */
2010     PACKS(&desc,"B","");                /* pad */
2011     PACKI(&desc,"W",
2012           Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2013     PACKI(&desc,"D",0);         /* auth flags XXX */
2014     PACKI(&desc,"W",0);         /* num logons */
2015     PACKI(&desc,"W",0);         /* bad pw count */
2016     PACKI(&desc,"D",-1);                /* last logon */
2017     PACKI(&desc,"D",-1);                /* last logoff */
2018     PACKI(&desc,"D",-1);                /* logoff time */
2019     PACKI(&desc,"D",-1);                /* kickoff time */
2020     PACKI(&desc,"D",0);         /* password age */
2021     PACKI(&desc,"D",0);         /* password can change */
2022     PACKI(&desc,"D",-1);                /* password must change */
2023     {
2024       fstring mypath;
2025       strcpy(mypath,"\\\\");
2026       strcat(mypath,local_machine);
2027       strupper(mypath);
2028       PACKS(&desc,"z",mypath); /* computer */
2029     }
2030     PACKS(&desc,"z",lp_workgroup());/* domain */
2031     PACKS(&desc,"z",lp_logon_script());         /* script path */
2032     PACKI(&desc,"D",0);         /* reserved */
2033   }
2034
2035   *rdata_len = desc.usedlen;
2036   *rparam_len = 6;
2037   *rparam = REALLOC(*rparam,*rparam_len);
2038   SSVALS(*rparam,0,desc.errcode);
2039   SSVAL(*rparam,2,0);
2040   SSVAL(*rparam,4,desc.neededlen);
2041
2042   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2043   return(True);
2044 }
2045
2046
2047 /****************************************************************************
2048   api_WAccessGetUserPerms
2049   ****************************************************************************/
2050 static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
2051                                     int mdrcnt,int mprcnt,
2052                                     char **rdata,char **rparam,
2053                                     int *rdata_len,int *rparam_len)
2054 {
2055   char *str1 = param+2;
2056   char *str2 = skip_string(str1,1);
2057   char *user = skip_string(str2,1);
2058   char *resource = skip_string(user,1);
2059
2060   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2061
2062   /* check it's a supported varient */
2063   if (strcmp(str1,"zzh") != 0) return False;
2064   if (strcmp(str2,"") != 0) return False;
2065
2066   *rparam_len = 6;
2067   *rparam = REALLOC(*rparam,*rparam_len);
2068   SSVALS(*rparam,0,0);          /* errorcode */
2069   SSVAL(*rparam,2,0);           /* converter word */
2070   SSVAL(*rparam,4,0x7f);        /* permission flags */
2071
2072   return(True);
2073 }
2074
2075 /****************************************************************************
2076   api_WPrintJobEnumerate
2077   ****************************************************************************/
2078 static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
2079                                  int mdrcnt,int mprcnt,
2080                                  char **rdata,char **rparam,
2081                                  int *rdata_len,int *rparam_len)
2082 {
2083   char *str1 = param+2;
2084   char *str2 = skip_string(str1,1);
2085   char *p = skip_string(str2,1);
2086   int uJobId = SVAL(p,0);
2087   int uLevel,cbBuf;
2088   int count;
2089   int i;
2090   int snum;
2091   int job;
2092   struct pack_desc desc;
2093   print_queue_struct *queue=NULL;
2094   print_status_struct status;
2095
2096   uLevel = SVAL(p,2);
2097   cbBuf = SVAL(p,4);
2098
2099   bzero(&desc,sizeof(desc));
2100   bzero(&status,sizeof(status));
2101
2102   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,uJobId));
2103
2104   /* check it's a supported varient */
2105   if (strcmp(str1,"WWrLh") != 0) return False;
2106   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2107
2108   snum = (unsigned int)uJobId >> 8; /*## valid serice number??*/
2109   job = uJobId & 0xFF;
2110
2111   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2112
2113   count = get_printqueue(snum,cnum,&queue,&status);
2114   for (i = 0; i < count; i++) {
2115     if ((queue[i].job % 0xFF) == job) break;
2116   }
2117   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2118   desc.base = *rdata;
2119   desc.buflen = mdrcnt;
2120
2121   if (init_package(&desc,1,0)) {
2122     if (i < count) {
2123       fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
2124       *rdata_len = desc.usedlen;
2125     }
2126     else {
2127       desc.errcode = NERR_JobNotFound;
2128       *rdata_len = 0;
2129     }
2130   }
2131
2132   *rparam_len = 6;
2133   *rparam = REALLOC(*rparam,*rparam_len);
2134   SSVALS(*rparam,0,desc.errcode);
2135   SSVAL(*rparam,2,0);
2136   SSVAL(*rparam,4,desc.neededlen);
2137
2138   if (queue) free(queue);
2139
2140   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2141   return(True);
2142 }
2143
2144 static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
2145                                    int mdrcnt,int mprcnt,
2146                                    char **rdata,char **rparam,
2147                                    int *rdata_len,int *rparam_len)
2148 {
2149   char *str1 = param+2;
2150   char *str2 = skip_string(str1,1);
2151   char *p = skip_string(str2,1);
2152   char* name = p;
2153   int uLevel,cbBuf;
2154   int count;
2155   int i, succnt=0;
2156   int snum;
2157   struct pack_desc desc;
2158   print_queue_struct *queue=NULL;
2159   print_status_struct status;
2160
2161   bzero(&desc,sizeof(desc));
2162   bzero(&status,sizeof(status));
2163
2164   p = skip_string(p,1);
2165   uLevel = SVAL(p,0);
2166   cbBuf = SVAL(p,2);
2167
2168   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2169
2170   /* check it's a supported varient */
2171   if (strcmp(str1,"zWrLeh") != 0) return False;
2172   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2173   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2174
2175   snum = lp_servicenumber(name);
2176   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2177     int pnum = lp_servicenumber(PRINTERS_NAME);
2178     if (pnum >= 0) {
2179       lp_add_printer(name,pnum);
2180       snum = lp_servicenumber(name);
2181     }
2182   }
2183
2184   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2185
2186   count = get_printqueue(snum,cnum,&queue,&status);
2187   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2188   desc.base = *rdata;
2189   desc.buflen = mdrcnt;
2190
2191   if (init_package(&desc,count,0)) {
2192     succnt = 0;
2193     for (i = 0; i < count; i++) {
2194       fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
2195       if (desc.errcode == NERR_Success) succnt = i+1;
2196     }
2197   }
2198
2199   *rdata_len = desc.usedlen;
2200
2201   *rparam_len = 8;
2202   *rparam = REALLOC(*rparam,*rparam_len);
2203   SSVALS(*rparam,0,desc.errcode);
2204   SSVAL(*rparam,2,0);
2205   SSVAL(*rparam,4,succnt);
2206   SSVAL(*rparam,6,count);
2207
2208   if (queue) free(queue);
2209
2210   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2211   return(True);
2212 }
2213
2214 static int check_printdest_info(struct pack_desc* desc,
2215                                 int uLevel, char* id)
2216 {
2217   desc->subformat = NULL;
2218   switch( uLevel ) {
2219   case 0: desc->format = "B9"; break;
2220   case 1: desc->format = "B9B21WWzW"; break;
2221   case 2: desc->format = "z"; break;
2222   case 3: desc->format = "zzzWWzzzWW"; break;
2223   default: return False;
2224   }
2225   if (strcmp(desc->format,id) != 0) return False;
2226   return True;
2227 }
2228
2229 static void fill_printdest_info(int cnum, int snum, int uLevel,
2230                                 struct pack_desc* desc)
2231 {
2232   char buf[100];
2233   strcpy(buf,SERVICE(snum));
2234   strupper(buf);
2235   if (uLevel <= 1) {
2236     PACKS(desc,"B9",buf);       /* szName */
2237     if (uLevel == 1) {
2238       PACKS(desc,"B21","");     /* szUserName */
2239       PACKI(desc,"W",0);                /* uJobId */
2240       PACKI(desc,"W",0);                /* fsStatus */
2241       PACKS(desc,"z","");       /* pszStatus */
2242       PACKI(desc,"W",0);                /* time */
2243     }
2244   }
2245   if (uLevel == 2 || uLevel == 3) {
2246     PACKS(desc,"z",buf);                /* pszPrinterName */
2247     if (uLevel == 3) {
2248       PACKS(desc,"z","");       /* pszUserName */
2249       PACKS(desc,"z","");       /* pszLogAddr */
2250       PACKI(desc,"W",0);                /* uJobId */
2251       PACKI(desc,"W",0);                /* fsStatus */
2252       PACKS(desc,"z","");       /* pszStatus */
2253       PACKS(desc,"z","");       /* pszComment */
2254       PACKS(desc,"z","NULL"); /* pszDrivers */
2255       PACKI(desc,"W",0);                /* time */
2256       PACKI(desc,"W",0);                /* pad1 */
2257     }
2258   }
2259 }
2260
2261 static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
2262                                   int mdrcnt,int mprcnt,
2263                                   char **rdata,char **rparam,
2264                                   int *rdata_len,int *rparam_len)
2265 {
2266   char *str1 = param+2;
2267   char *str2 = skip_string(str1,1);
2268   char *p = skip_string(str2,1);
2269   char* PrinterName = p;
2270   int uLevel,cbBuf;
2271   struct pack_desc desc;
2272   int snum;
2273
2274   bzero(&desc,sizeof(desc));
2275
2276   p = skip_string(p,1);
2277   uLevel = SVAL(p,0);
2278   cbBuf = SVAL(p,2);
2279
2280   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2281
2282   /* check it's a supported varient */
2283   if (strcmp(str1,"zWrLh") != 0) return False;
2284   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2285
2286   snum = lp_servicenumber(PrinterName);
2287   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2288     int pnum = lp_servicenumber(PRINTERS_NAME);
2289     if (pnum >= 0) {
2290       lp_add_printer(PrinterName,pnum);
2291       snum = lp_servicenumber(PrinterName);
2292     }
2293   }
2294
2295   if (snum < 0) {
2296     *rdata_len = 0;
2297     desc.errcode = NERR_DestNotFound;
2298     desc.neededlen = 0;
2299   }
2300   else {
2301     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2302     desc.base = *rdata;
2303     desc.buflen = mdrcnt;
2304     if (init_package(&desc,1,0)) {
2305       fill_printdest_info(cnum,snum,uLevel,&desc);
2306     }
2307     *rdata_len = desc.usedlen;
2308   }
2309
2310   *rparam_len = 6;
2311   *rparam = REALLOC(*rparam,*rparam_len);
2312   SSVALS(*rparam,0,desc.errcode);
2313   SSVAL(*rparam,2,0);
2314   SSVAL(*rparam,4,desc.neededlen);
2315
2316   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2317   return(True);
2318 }
2319
2320 static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
2321                                int mdrcnt,int mprcnt,
2322                                char **rdata,char **rparam,
2323                                int *rdata_len,int *rparam_len)
2324 {
2325   char *str1 = param+2;
2326   char *str2 = skip_string(str1,1);
2327   char *p = skip_string(str2,1);
2328   int uLevel,cbBuf;
2329   int queuecnt;
2330   int i, n, succnt=0;
2331   struct pack_desc desc;
2332   int services = lp_numservices();
2333
2334   bzero(&desc,sizeof(desc));
2335
2336   uLevel = SVAL(p,0);
2337   cbBuf = SVAL(p,2);
2338
2339   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2340
2341   /* check it's a supported varient */
2342   if (strcmp(str1,"WrLeh") != 0) return False;
2343   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2344
2345   queuecnt = 0;
2346   for (i = 0; i < services; i++)
2347     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2348       queuecnt++;
2349
2350   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2351   desc.base = *rdata;
2352   desc.buflen = mdrcnt;
2353   if (init_package(&desc,queuecnt,0)) {    
2354     succnt = 0;
2355     n = 0;
2356     for (i = 0; i < services; i++) {
2357       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2358         fill_printdest_info(cnum,i,uLevel,&desc);
2359         n++;
2360         if (desc.errcode == NERR_Success) succnt = n;
2361       }
2362     }
2363   }
2364
2365   *rdata_len = desc.usedlen;
2366
2367   *rparam_len = 8;
2368   *rparam = REALLOC(*rparam,*rparam_len);
2369   SSVALS(*rparam,0,desc.errcode);
2370   SSVAL(*rparam,2,0);
2371   SSVAL(*rparam,4,succnt);
2372   SSVAL(*rparam,6,queuecnt);
2373
2374   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2375   return(True);
2376 }
2377
2378 static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
2379                                  int mdrcnt,int mprcnt,
2380                                  char **rdata,char **rparam,
2381                                  int *rdata_len,int *rparam_len)
2382 {
2383   char *str1 = param+2;
2384   char *str2 = skip_string(str1,1);
2385   char *p = skip_string(str2,1);
2386   int uLevel,cbBuf;
2387   int succnt;
2388   struct pack_desc desc;
2389
2390   bzero(&desc,sizeof(desc));
2391
2392   uLevel = SVAL(p,0);
2393   cbBuf = SVAL(p,2);
2394
2395   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2396
2397   /* check it's a supported varient */
2398   if (strcmp(str1,"WrLeh") != 0) return False;
2399   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2400
2401   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2402   desc.base = *rdata;
2403   desc.buflen = mdrcnt;
2404   if (init_package(&desc,1,0)) {
2405     PACKS(&desc,"B41","NULL");
2406   }
2407
2408   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2409
2410   *rdata_len = desc.usedlen;
2411
2412   *rparam_len = 8;
2413   *rparam = REALLOC(*rparam,*rparam_len);
2414   SSVALS(*rparam,0,desc.errcode);
2415   SSVAL(*rparam,2,0);
2416   SSVAL(*rparam,4,succnt);
2417   SSVAL(*rparam,6,1);
2418
2419   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2420   return(True);
2421 }
2422
2423 static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
2424                                 int mdrcnt,int mprcnt,
2425                                 char **rdata,char **rparam,
2426                                 int *rdata_len,int *rparam_len)
2427 {
2428   char *str1 = param+2;
2429   char *str2 = skip_string(str1,1);
2430   char *p = skip_string(str2,1);
2431   int uLevel,cbBuf;
2432   int succnt;
2433   struct pack_desc desc;
2434
2435   bzero(&desc,sizeof(desc));
2436
2437   uLevel = SVAL(p,0);
2438   cbBuf = SVAL(p,2);
2439
2440   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
2441
2442   /* check it's a supported varient */
2443   if (strcmp(str1,"WrLeh") != 0) return False;
2444   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
2445
2446   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2447   desc.base = *rdata;
2448   desc.buflen = mdrcnt;
2449   desc.format = str2;
2450   if (init_package(&desc,1,0)) {
2451     PACKS(&desc,"B13","lpd");
2452   }
2453
2454   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2455
2456   *rdata_len = desc.usedlen;
2457
2458   *rparam_len = 8;
2459   *rparam = REALLOC(*rparam,*rparam_len);
2460   SSVALS(*rparam,0,desc.errcode);
2461   SSVAL(*rparam,2,0);
2462   SSVAL(*rparam,4,succnt);
2463   SSVAL(*rparam,6,1);
2464
2465   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
2466   return(True);
2467 }
2468
2469 static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
2470                                int mdrcnt,int mprcnt,
2471                                char **rdata,char **rparam,
2472                                int *rdata_len,int *rparam_len)
2473 {
2474   char *str1 = param+2;
2475   char *str2 = skip_string(str1,1);
2476   char *p = skip_string(str2,1);
2477   int uLevel,cbBuf;
2478   int succnt;
2479   struct pack_desc desc;
2480
2481   bzero(&desc,sizeof(desc));
2482
2483   uLevel = SVAL(p,0);
2484   cbBuf = SVAL(p,2);
2485
2486   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
2487
2488   /* check it's a supported varient */
2489   if (strcmp(str1,"WrLeh") != 0) return False;
2490   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
2491
2492   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2493   bzero(&desc,sizeof(desc));
2494   desc.base = *rdata;
2495   desc.buflen = mdrcnt;
2496   desc.format = str2;
2497   if (init_package(&desc,1,0)) {
2498     PACKS(&desc,"B13","lp0");
2499   }
2500
2501   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2502
2503   *rdata_len = desc.usedlen;
2504
2505   *rparam_len = 8;
2506   *rparam = REALLOC(*rparam,*rparam_len);
2507   SSVALS(*rparam,0,desc.errcode);
2508   SSVAL(*rparam,2,0);
2509   SSVAL(*rparam,4,succnt);
2510   SSVAL(*rparam,6,1);
2511
2512   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
2513   return(True);
2514 }
2515
2516
2517 struct
2518 {
2519   char * name;
2520   char * pipename;
2521   int subcommand;
2522   BOOL (*fn) ();
2523 } api_fd_commands [] =
2524   {
2525     { "SetNmdPpHndState",       "lsarpc",       1,      api_LsarpcSNPHS },
2526     { "TransactNmPipe", "lsarpc",       0x26,   api_LsarpcTNP },
2527     { NULL,             NULL,           -1,     api_Unsupported }
2528   };
2529
2530 /****************************************************************************
2531   handle remote api calls delivered to a named pipe already opened.
2532   ****************************************************************************/
2533 static int api_fd_reply(int cnum,int uid,char *outbuf,
2534                         uint16 *setup,char *data,char *params,
2535                         int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
2536 {
2537   char *rdata = NULL;
2538   char *rparam = NULL;
2539   int rdata_len = 0;
2540   int rparam_len = 0;
2541   BOOL reply=False;
2542   int i;
2543   int fd;
2544   int subcommand;
2545   
2546   /* First find out the name of this file. */
2547   if (suwcnt != 2)
2548     {
2549       DEBUG(0,("Unexpected named pipe transaction.\n"));
2550       return(-1);
2551     }
2552   
2553   /* Get the file handle and hence the file name. */
2554   fd = setup[1];
2555   subcommand = setup[0];
2556   
2557   DEBUG(3,("Got API command %d on pipe %s ",subcommand,Files[fd].name));
2558   DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
2559            tdscnt,tpscnt,mdrcnt,mprcnt));
2560   
2561   for (i=0;api_fd_commands[i].name;i++)
2562     if (strequal(api_fd_commands[i].pipename, Files[fd].name) &&
2563         api_fd_commands[i].subcommand == subcommand &&
2564         api_fd_commands[i].fn)
2565       {
2566         DEBUG(3,("Doing %s\n",api_fd_commands[i].name));
2567         break;
2568       }
2569   
2570   rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
2571   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
2572   
2573   reply = api_fd_commands[i].fn(cnum,uid,params,data,mdrcnt,mprcnt,
2574                                 &rdata,&rparam,&rdata_len,&rparam_len);
2575   
2576   if (rdata_len > mdrcnt ||
2577       rparam_len > mprcnt)
2578     {
2579       reply = api_TooSmall(cnum,uid,params,data,mdrcnt,mprcnt,
2580                            &rdata,&rparam,&rdata_len,&rparam_len);
2581     }
2582   
2583   
2584   /* if we get False back then it's actually unsupported */
2585   if (!reply)
2586     api_Unsupported(cnum,uid,params,data,mdrcnt,mprcnt,
2587                     &rdata,&rparam,&rdata_len,&rparam_len);
2588   
2589   /* now send the reply */
2590   send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
2591   
2592   if (rdata)
2593     free(rdata);
2594   if (rparam)
2595     free(rparam);
2596   
2597   return(-1);
2598 }
2599
2600
2601
2602 /****************************************************************************
2603   the buffer was too small
2604   ****************************************************************************/
2605 static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
2606                          int mdrcnt,int mprcnt,
2607                          char **rdata,char **rparam,
2608                          int *rdata_len,int *rparam_len)
2609 {
2610   *rparam_len = MIN(*rparam_len,mprcnt);
2611   *rparam = REALLOC(*rparam,*rparam_len);
2612
2613   *rdata_len = 0;
2614
2615   SSVAL(*rparam,0,NERR_BufTooSmall);
2616
2617   DEBUG(3,("Supplied buffer too small in API command\n"));
2618
2619   return(True);
2620 }
2621
2622
2623 /****************************************************************************
2624   the request is not supported
2625   ****************************************************************************/
2626 static BOOL api_Unsupported(int cnum,int uid, char *param,char *data,
2627                             int mdrcnt,int mprcnt,
2628                             char **rdata,char **rparam,
2629                             int *rdata_len,int *rparam_len)
2630 {
2631   *rparam_len = 4;
2632   *rparam = REALLOC(*rparam,*rparam_len);
2633
2634   *rdata_len = 0;
2635
2636   SSVAL(*rparam,0,NERR_notsupported);
2637   SSVAL(*rparam,2,0);           /* converter word */
2638
2639   DEBUG(3,("Unsupported API command\n"));
2640
2641   return(True);
2642 }
2643
2644
2645
2646
2647 struct
2648 {
2649   char *name;
2650   int id;
2651   BOOL (*fn)();
2652   int flags;
2653 } api_commands[] = {
2654   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
2655   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
2656   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
2657   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
2658   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
2659   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
2660   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
2661   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
2662   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
2663   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
2664   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
2665   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
2666   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
2667   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
2668   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
2669   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
2670   {"WPrintQueuePurge",  103,    api_WPrintQueuePurge,0},
2671   {"NetServerEnum",     104,    api_RNetServerEnum,0},
2672   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
2673   {"SetUserPassword",   115,    api_SetUserPassword,0},
2674   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
2675   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
2676   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
2677   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
2678   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
2679   {NULL,                -1,     api_Unsupported,0}};
2680
2681
2682 /****************************************************************************
2683   handle remote api calls
2684   ****************************************************************************/
2685 static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
2686                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
2687 {
2688   int api_command = SVAL(params,0);
2689   char *rdata = NULL;
2690   char *rparam = NULL;
2691   int rdata_len = 0;
2692   int rparam_len = 0;
2693   BOOL reply=False;
2694   int i;
2695
2696   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
2697            api_command,params+2,skip_string(params+2,1),
2698            tdscnt,tpscnt,mdrcnt,mprcnt));
2699
2700   for (i=0;api_commands[i].name;i++)
2701     if (api_commands[i].id == api_command && api_commands[i].fn)
2702       {
2703         DEBUG(3,("Doing %s\n",api_commands[i].name));
2704         break;
2705       }
2706
2707   rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
2708   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
2709
2710   reply = api_commands[i].fn(cnum,uid,params,data,mdrcnt,mprcnt,
2711                              &rdata,&rparam,&rdata_len,&rparam_len);
2712
2713
2714   if (rdata_len > mdrcnt ||
2715       rparam_len > mprcnt)
2716     {
2717       reply = api_TooSmall(cnum,uid,params,data,mdrcnt,mprcnt,
2718                            &rdata,&rparam,&rdata_len,&rparam_len);
2719     }
2720             
2721
2722   /* if we get False back then it's actually unsupported */
2723   if (!reply)
2724     api_Unsupported(cnum,uid,params,data,mdrcnt,mprcnt,
2725                     &rdata,&rparam,&rdata_len,&rparam_len);
2726
2727       
2728
2729   /* now send the reply */
2730   send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
2731
2732   if (rdata)
2733     free(rdata);
2734   if (rparam)
2735     free(rparam);
2736   
2737   return(-1);
2738 }
2739
2740 /****************************************************************************
2741   handle named pipe commands
2742   ****************************************************************************/
2743 static int named_pipe(int cnum,int uid, char *outbuf,char *name,
2744                       uint16 *setup,char *data,char *params,
2745                       int suwcnt,int tdscnt,int tpscnt,
2746                       int msrcnt,int mdrcnt,int mprcnt)
2747 {
2748
2749   if (strequal(name,"LANMAN"))
2750     return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
2751
2752 if (strlen(name) < 1)
2753   return(api_fd_reply(cnum,uid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt));
2754
2755
2756   DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
2757            name,(int)setup[0],(int)setup[1]));
2758   
2759   return(0);
2760 }
2761
2762
2763 /****************************************************************************
2764   reply to a SMBtrans
2765   ****************************************************************************/
2766 int reply_trans(char *inbuf,char *outbuf)
2767 {
2768   fstring name;
2769
2770   char *data=NULL,*params=NULL;
2771   uint16 *setup=NULL;
2772
2773   int outsize = 0;
2774   int cnum = SVAL(inbuf,smb_tid);
2775   int uid = SVAL(inbuf,smb_uid);
2776
2777   int tpscnt = SVAL(inbuf,smb_vwv0);
2778   int tdscnt = SVAL(inbuf,smb_vwv1);
2779   int mprcnt = SVAL(inbuf,smb_vwv2);
2780   int mdrcnt = SVAL(inbuf,smb_vwv3);
2781   int msrcnt = CVAL(inbuf,smb_vwv4);
2782   BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
2783   BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
2784   int pscnt = SVAL(inbuf,smb_vwv9);
2785   int psoff = SVAL(inbuf,smb_vwv10);
2786   int dscnt = SVAL(inbuf,smb_vwv11);
2787   int dsoff = SVAL(inbuf,smb_vwv12);
2788   int suwcnt = CVAL(inbuf,smb_vwv13);
2789
2790   StrnCpy(name,smb_buf(inbuf),sizeof(name)-1);
2791   
2792   if (tdscnt)
2793     {
2794       data = (char *)malloc(tdscnt);
2795       memcpy(data,smb_base(inbuf)+dsoff,dscnt);
2796     }
2797   if (tpscnt)
2798     {
2799       params = (char *)malloc(tpscnt);
2800       memcpy(params,smb_base(inbuf)+psoff,pscnt);
2801     }
2802
2803   if (suwcnt)
2804     {
2805       int i;
2806       setup = (uint16 *)malloc(suwcnt*sizeof(setup[0]));
2807       for (i=0;i<suwcnt;i++)
2808         setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
2809     }
2810
2811
2812   if (pscnt < tpscnt || dscnt < tdscnt)
2813     {
2814       /* We need to send an interim response then receive the rest
2815          of the parameter/data bytes */
2816       outsize = set_message(outbuf,0,0,True);
2817       show_msg(outbuf);
2818       send_smb(Client,outbuf);
2819     }
2820
2821   /* receive the rest of the trans packet */
2822   while (pscnt < tpscnt || dscnt < tdscnt)
2823     {
2824       int pcnt,poff,dcnt,doff,pdisp,ddisp;
2825       
2826       if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
2827           CVAL(inbuf, smb_com) != SMBtrans)
2828         {
2829           DEBUG(2,("Invalid secondary trans2 packet\n"));
2830           if (params) free(params);
2831           if (data) free(data);
2832           if (setup) free(setup);
2833           return(ERROR(ERRSRV,ERRerror));
2834         }
2835
2836       show_msg(inbuf);
2837       
2838       tpscnt = SVAL(inbuf,smb_vwv0);
2839       tdscnt = SVAL(inbuf,smb_vwv1);
2840
2841       pcnt = SVAL(inbuf,smb_vwv2);
2842       poff = SVAL(inbuf,smb_vwv3);
2843       pdisp = SVAL(inbuf,smb_vwv4);
2844       
2845       dcnt = SVAL(inbuf,smb_vwv5);
2846       doff = SVAL(inbuf,smb_vwv6);
2847       ddisp = SVAL(inbuf,smb_vwv7);
2848       
2849       pscnt += pcnt;
2850       dscnt += dcnt;
2851
2852       if (pcnt)
2853         memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
2854       if (dcnt)
2855         memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);      
2856     }
2857
2858
2859   DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt));
2860   
2861
2862   if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0)
2863     outsize = named_pipe(cnum,uid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
2864                          suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
2865
2866
2867   if (data) free(data);
2868   if (params) free(params);
2869   if (setup) free(setup);
2870
2871   if (close_on_completion)
2872     close_cnum(cnum,uid);
2873
2874   if (one_way)
2875     return(-1);
2876   
2877   if (outsize == 0)
2878     return(ERROR(ERRSRV,ERRnosupport));
2879
2880   return(outsize);
2881 }
2882
2883