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