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