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