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