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