RIP BOOL. Convert BOOL -> bool. I found a few interesting
[ira/wip.git] / source3 / smbd / lanman.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Inter-process communication and named pipe handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 2007.
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 3 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, see <http://www.gnu.org/licenses/>.
22    */
23 /*
24    This file handles the named pipe and mailslot calls
25    in the SMBtrans protocol
26    */
27
28 #include "includes.h"
29
30 extern struct current_user current_user;
31 extern userdom_struct current_user_info;
32
33 #ifdef CHECK_TYPES
34 #undef CHECK_TYPES
35 #endif
36 #define CHECK_TYPES 0
37
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
41
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
46
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
50
51 #define SHPWLEN 8               /* share password length */
52
53 /* Limit size of ipc replies */
54
55 static char *smb_realloc_limit(void *ptr, size_t size)
56 {
57         char *val;
58
59         size = MAX((size),4*1024);
60         val = (char *)SMB_REALLOC(ptr,size);
61         if (val) {
62                 memset(val,'\0',size);
63         }
64         return val;
65 }
66
67 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
68                                 char *param, int tpscnt,
69                                 char *data, int tdscnt,
70                                 int mdrcnt, int mprcnt,
71                                 char **rdata, char **rparam,
72                                 int *rdata_len, int *rparam_len);
73
74 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
75                          int mdrcnt, int mprcnt,
76                          char **rdata, char **rparam,
77                          int *rdata_len, int *rparam_len);
78
79
80 static int CopyExpanded(connection_struct *conn, 
81                         int snum, char **dst, char *src, int *n)
82 {
83         pstring buf;
84         int l;
85
86         if (!src || !dst || !n || !(*dst)) {
87                 return 0;
88         }
89
90         StrnCpy(buf,src,sizeof(buf)/2);
91         pstring_sub(buf,"%S",lp_servicename(snum));
92         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
93                               conn->connectpath, conn->gid,
94                               get_current_username(),
95                               current_user_info.domain,
96                               buf, sizeof(buf));
97         l = push_ascii(*dst,buf,*n, STR_TERMINATE);
98         (*dst) += l;
99         (*n) -= l;
100         return l;
101 }
102
103 static int CopyAndAdvance(char **dst, char *src, int *n)
104 {
105         int l;
106         if (!src || !dst || !n || !(*dst)) {
107                 return 0;
108         }
109         l = push_ascii(*dst,src,*n, STR_TERMINATE);
110         (*dst) += l;
111         (*n) -= l;
112         return l;
113 }
114
115 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
116 {
117         pstring buf;
118         if (!s) {
119                 return 0;
120         }
121         StrnCpy(buf,s,sizeof(buf)/2);
122         pstring_sub(buf,"%S",lp_servicename(snum));
123         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
124                               conn->connectpath, conn->gid,
125                               get_current_username(),
126                               current_user_info.domain,
127                               buf, sizeof(buf));
128         return strlen(buf) + 1;
129 }
130
131 static char *Expand(connection_struct *conn, int snum, char *s)
132 {
133         pstring buf;
134         if (!s) {
135                 return NULL;
136         }
137         StrnCpy(buf,s,sizeof(buf)/2);
138         pstring_sub(buf,"%S",lp_servicename(snum));
139         return talloc_sub_advanced(talloc_tos(), lp_servicename(SNUM(conn)),
140                                    conn->user, conn->connectpath, conn->gid,
141                                    get_current_username(),
142                                    current_user_info.domain, buf);
143 }
144
145 /*******************************************************************
146  Check a API string for validity when we only need to check the prefix.
147 ******************************************************************/
148
149 static bool prefix_ok(const char *str, const char *prefix)
150 {
151         return(strncmp(str,prefix,strlen(prefix)) == 0);
152 }
153
154 struct pack_desc {
155         const char *format;         /* formatstring for structure */
156         const char *subformat;  /* subformat for structure */
157         char *base;         /* baseaddress of buffer */
158         int buflen;        /* remaining size for fixed part; on init: length of base */
159         int subcount;       /* count of substructures */
160         char *structbuf;  /* pointer into buffer for remaining fixed part */
161         int stringlen;    /* remaining size for variable part */                
162         char *stringbuf;  /* pointer into buffer for remaining variable part */
163         int neededlen;    /* total needed size */
164         int usedlen;        /* total used size (usedlen <= neededlen and usedlen <= buflen) */
165         const char *curpos;         /* current position; pointer into format or subformat */
166         int errcode;
167 };
168
169 static int get_counter(const char **p)
170 {
171         int i, n;
172         if (!p || !(*p)) {
173                 return 1;
174         }
175         if (!isdigit((int)**p)) {
176                 return 1;
177         }
178         for (n = 0;;) {
179                 i = **p;
180                 if (isdigit(i)) {
181                         n = 10 * n + (i - '0');
182                 } else {
183                         return n;
184                 }
185                 (*p)++;
186         }
187 }
188
189 static int getlen(const char *p)
190 {
191         int n = 0;
192         if (!p) {
193                 return 0;
194         }
195
196         while (*p) {
197                 switch( *p++ ) {
198                 case 'W':                       /* word (2 byte) */
199                         n += 2;
200                         break;
201                 case 'K':                       /* status word? (2 byte) */
202                         n += 2;
203                         break;
204                 case 'N':                       /* count of substructures (word) at end */
205                         n += 2;
206                         break;
207                 case 'D':                       /* double word (4 byte) */
208                 case 'z':                       /* offset to zero terminated string (4 byte) */
209                 case 'l':                       /* offset to user data (4 byte) */
210                         n += 4;
211                         break;
212                 case 'b':                       /* offset to data (with counter) (4 byte) */
213                         n += 4;
214                         get_counter(&p);
215                         break;
216                 case 'B':                       /* byte (with optional counter) */
217                         n += get_counter(&p);
218                         break;
219                 }
220         }
221         return n;
222 }
223
224 static bool init_package(struct pack_desc *p, int count, int subcount)
225 {
226         int n = p->buflen;
227         int i;
228
229         if (!p->format || !p->base) {
230                 return False;
231         }
232
233         i = count * getlen(p->format);
234         if (p->subformat) {
235                 i += subcount * getlen(p->subformat);
236         }
237         p->structbuf = p->base;
238         p->neededlen = 0;
239         p->usedlen = 0;
240         p->subcount = 0;
241         p->curpos = p->format;
242         if (i > n) {
243                 p->neededlen = i;
244                 i = n = 0;
245 #if 0
246                 /*
247                  * This is the old error code we used. Aparently
248                  * WinNT/2k systems return ERRbuftoosmall (2123) and
249                  * OS/2 needs this. I'm leaving this here so we can revert
250                  * if needed. JRA.
251                  */
252                 p->errcode = ERRmoredata;
253 #else
254                 p->errcode = ERRbuftoosmall;
255 #endif
256         } else {
257                 p->errcode = NERR_Success;
258         }
259         p->buflen = i;
260         n -= i;
261         p->stringbuf = p->base + i;
262         p->stringlen = n;
263         return (p->errcode == NERR_Success);
264 }
265
266 static int package(struct pack_desc *p, ...)
267 {
268         va_list args;
269         int needed=0, stringneeded;
270         const char *str=NULL;
271         int is_string=0, stringused;
272         int32 temp;
273
274         va_start(args,p);
275
276         if (!*p->curpos) {
277                 if (!p->subcount) {
278                         p->curpos = p->format;
279                 } else {
280                         p->curpos = p->subformat;
281                         p->subcount--;
282                 }
283         }
284 #if CHECK_TYPES
285         str = va_arg(args,char*);
286         SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
287 #endif
288         stringneeded = -1;
289
290         if (!p->curpos) {
291                 va_end(args);
292                 return 0;
293         }
294
295         switch( *p->curpos++ ) {
296                 case 'W':                       /* word (2 byte) */
297                         needed = 2;
298                         temp = va_arg(args,int);
299                         if (p->buflen >= needed) {
300                                 SSVAL(p->structbuf,0,temp);
301                         }
302                         break;
303                 case 'K':                       /* status word? (2 byte) */
304                         needed = 2;
305                         temp = va_arg(args,int);
306                         if (p->buflen >= needed) {
307                                 SSVAL(p->structbuf,0,temp);
308                         }
309                         break;
310                 case 'N':                       /* count of substructures (word) at end */
311                         needed = 2;
312                         p->subcount = va_arg(args,int);
313                         if (p->buflen >= needed) {
314                                 SSVAL(p->structbuf,0,p->subcount);
315                         }
316                         break;
317                 case 'D':                       /* double word (4 byte) */
318                         needed = 4;
319                         temp = va_arg(args,int);
320                         if (p->buflen >= needed) {
321                                 SIVAL(p->structbuf,0,temp);
322                         }
323                         break;
324                 case 'B':                       /* byte (with optional counter) */
325                         needed = get_counter(&p->curpos);
326                         {
327                                 char *s = va_arg(args,char*);
328                                 if (p->buflen >= needed) {
329                                         StrnCpy(p->structbuf,s?s:"",needed-1);
330                                 }
331                         }
332                         break;
333                 case 'z':                       /* offset to zero terminated string (4 byte) */
334                         str = va_arg(args,char*);
335                         stringneeded = (str ? strlen(str)+1 : 0);
336                         is_string = 1;
337                         break;
338                 case 'l':                       /* offset to user data (4 byte) */
339                         str = va_arg(args,char*);
340                         stringneeded = va_arg(args,int);
341                         is_string = 0;
342                         break;
343                 case 'b':                       /* offset to data (with counter) (4 byte) */
344                         str = va_arg(args,char*);
345                         stringneeded = get_counter(&p->curpos);
346                         is_string = 0;
347                         break;
348         }
349
350         va_end(args);
351         if (stringneeded >= 0) {
352                 needed = 4;
353                 if (p->buflen >= needed) {
354                         stringused = stringneeded;
355                         if (stringused > p->stringlen) {
356                                 stringused = (is_string ? p->stringlen : 0);
357                                 if (p->errcode == NERR_Success) {
358                                         p->errcode = ERRmoredata;
359                                 }
360                         }
361                         if (!stringused) {
362                                 SIVAL(p->structbuf,0,0);
363                         } else {
364                                 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
365                                 memcpy(p->stringbuf,str?str:"",stringused);
366                                 if (is_string) {
367                                         p->stringbuf[stringused-1] = '\0';
368                                 }
369                                 p->stringbuf += stringused;
370                                 p->stringlen -= stringused;
371                                 p->usedlen += stringused;
372                         }
373                 }
374                 p->neededlen += stringneeded;
375         }
376
377         p->neededlen += needed;
378         if (p->buflen >= needed) {
379                 p->structbuf += needed;
380                 p->buflen -= needed;
381                 p->usedlen += needed;
382         } else {
383                 if (p->errcode == NERR_Success) {
384                         p->errcode = ERRmoredata;
385                 }
386         }
387         return 1;
388 }
389
390 #if CHECK_TYPES
391 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
392 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
393 #else
394 #define PACK(desc,t,v) package(desc,v)
395 #define PACKl(desc,t,v,l) package(desc,v,l)
396 #endif
397
398 static void PACKI(struct pack_desc* desc, const char *t,int v)
399 {
400         PACK(desc,t,v);
401 }
402
403 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
404 {
405         PACK(desc,t,v);
406 }
407
408 /****************************************************************************
409  Get a print queue.
410 ****************************************************************************/
411
412 static void PackDriverData(struct pack_desc* desc)
413 {
414         char drivdata[4+4+32];
415         SIVAL(drivdata,0,sizeof drivdata); /* cb */
416         SIVAL(drivdata,4,1000); /* lVersion */
417         memset(drivdata+8,0,32);        /* szDeviceName */
418         push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
419         PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
420 }
421
422 static int check_printq_info(struct pack_desc* desc,
423                                 unsigned int uLevel, char *id1, char *id2)
424 {
425         desc->subformat = NULL;
426         switch( uLevel ) {
427                 case 0:
428                         desc->format = "B13";
429                         break;
430                 case 1:
431                         desc->format = "B13BWWWzzzzzWW";
432                         break;
433                 case 2:
434                         desc->format = "B13BWWWzzzzzWN";
435                         desc->subformat = "WB21BB16B10zWWzDDz";
436                         break;
437                 case 3:
438                         desc->format = "zWWWWzzzzWWzzl";
439                         break;
440                 case 4:
441                         desc->format = "zWWWWzzzzWNzzl";
442                         desc->subformat = "WWzWWDDzz";
443                         break;
444                 case 5:
445                         desc->format = "z";
446                         break;
447                 case 51:
448                         desc->format = "K";
449                         break;
450                 case 52:
451                         desc->format = "WzzzzzzzzN";
452                         desc->subformat = "z";
453                         break;
454                 default:
455                         DEBUG(0,("check_printq_info: invalid level %d\n",
456                                 uLevel ));
457                         return False;
458         }
459         if (id1 == NULL || strcmp(desc->format,id1) != 0) {
460                 DEBUG(0,("check_printq_info: invalid format %s\n",
461                         id1 ? id1 : "<NULL>" ));
462                 return False;
463         }
464         if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
465                 DEBUG(0,("check_printq_info: invalid subformat %s\n",
466                         id2 ? id2 : "<NULL>" ));
467                 return False;
468         }
469         return True;
470 }
471
472
473 #define RAP_JOB_STATUS_QUEUED 0
474 #define RAP_JOB_STATUS_PAUSED 1
475 #define RAP_JOB_STATUS_SPOOLING 2
476 #define RAP_JOB_STATUS_PRINTING 3
477 #define RAP_JOB_STATUS_PRINTED 4
478
479 #define RAP_QUEUE_STATUS_PAUSED 1
480 #define RAP_QUEUE_STATUS_ERROR 2
481
482 /* turn a print job status into a on the wire status 
483 */
484 static int printj_status(int v)
485 {
486         switch (v) {
487         case LPQ_QUEUED:
488                 return RAP_JOB_STATUS_QUEUED;
489         case LPQ_PAUSED:
490                 return RAP_JOB_STATUS_PAUSED;
491         case LPQ_SPOOLING:
492                 return RAP_JOB_STATUS_SPOOLING;
493         case LPQ_PRINTING:
494                 return RAP_JOB_STATUS_PRINTING;
495         }
496         return 0;
497 }
498
499 /* turn a print queue status into a on the wire status 
500 */
501 static int printq_status(int v)
502 {
503         switch (v) {
504         case LPQ_QUEUED:
505                 return 0;
506         case LPQ_PAUSED:
507                 return RAP_QUEUE_STATUS_PAUSED;
508         }
509         return RAP_QUEUE_STATUS_ERROR;
510 }
511
512 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
513                                struct pack_desc *desc,
514                                print_queue_struct *queue, int n)
515 {
516         time_t t = queue->time;
517
518         /* the client expects localtime */
519         t -= get_time_zone(t);
520
521         PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
522         if (uLevel == 1) {
523                 PACKS(desc,"B21",queue->fs_user); /* szUserName */
524                 PACKS(desc,"B","");             /* pad */
525                 PACKS(desc,"B16","");   /* szNotifyName */
526                 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
527                 PACKS(desc,"z","");             /* pszParms */
528                 PACKI(desc,"W",n+1);            /* uPosition */
529                 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
530                 PACKS(desc,"z","");             /* pszStatus */
531                 PACKI(desc,"D",t); /* ulSubmitted */
532                 PACKI(desc,"D",queue->size); /* ulSize */
533                 PACKS(desc,"z",queue->fs_file); /* pszComment */
534         }
535         if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
536                 PACKI(desc,"W",queue->priority);                /* uPriority */
537                 PACKS(desc,"z",queue->fs_user); /* pszUserName */
538                 PACKI(desc,"W",n+1);            /* uPosition */
539                 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
540                 PACKI(desc,"D",t); /* ulSubmitted */
541                 PACKI(desc,"D",queue->size); /* ulSize */
542                 PACKS(desc,"z","Samba");        /* pszComment */
543                 PACKS(desc,"z",queue->fs_file); /* pszDocument */
544                 if (uLevel == 3) {
545                         PACKS(desc,"z","");     /* pszNotifyName */
546                         PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
547                         PACKS(desc,"z","");     /* pszParms */
548                         PACKS(desc,"z","");     /* pszStatus */
549                         PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
550                         PACKS(desc,"z","lpd");  /* pszQProcName */
551                         PACKS(desc,"z","");     /* pszQProcParms */
552                         PACKS(desc,"z","NULL"); /* pszDriverName */
553                         PackDriverData(desc);   /* pDriverData */
554                         PACKS(desc,"z","");     /* pszPrinterName */
555                 } else if (uLevel == 4) {   /* OS2 */
556                         PACKS(desc,"z","");       /* pszSpoolFileName  */
557                         PACKS(desc,"z","");       /* pszPortName       */
558                         PACKS(desc,"z","");       /* pszStatus         */
559                         PACKI(desc,"D",0);        /* ulPagesSpooled    */
560                         PACKI(desc,"D",0);        /* ulPagesSent       */
561                         PACKI(desc,"D",0);        /* ulPagesPrinted    */
562                         PACKI(desc,"D",0);        /* ulTimePrinted     */
563                         PACKI(desc,"D",0);        /* ulExtendJobStatus */
564                         PACKI(desc,"D",0);        /* ulStartPage       */
565                         PACKI(desc,"D",0);        /* ulEndPage         */
566                 }
567         }
568 }
569
570 /********************************************************************
571  Return a driver name given an snum.
572  Returns True if from tdb, False otherwise.
573  ********************************************************************/
574
575 static bool get_driver_name(int snum, pstring drivername)
576 {
577         NT_PRINTER_INFO_LEVEL *info = NULL;
578         bool in_tdb = False;
579
580         get_a_printer (NULL, &info, 2, lp_servicename(snum));
581         if (info != NULL) {
582                 pstrcpy( drivername, info->info_2->drivername);
583                 in_tdb = True;
584                 free_a_printer(&info, 2);
585         }
586
587         return in_tdb;
588 }
589
590 /********************************************************************
591  Respond to the DosPrintQInfo command with a level of 52
592  This is used to get printer driver information for Win9x clients
593  ********************************************************************/
594 static void fill_printq_info_52(connection_struct *conn, int snum, 
595                                 struct pack_desc* desc, int count )
596 {
597         int                             i;
598         fstring                         location;
599         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
600         NT_PRINTER_INFO_LEVEL           *printer = NULL;
601
602         ZERO_STRUCT(driver);
603
604         if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
605                 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", 
606                         lp_servicename(snum)));
607                 goto err;
608         }
609
610         if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
611                 "Windows 4.0", 0)) )
612         {
613                 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", 
614                         printer->info_2->drivername));
615                 goto err;
616         }
617
618         trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
619         trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
620         trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
621
622         PACKI(desc, "W", 0x0400);                     /* don't know */
623         PACKS(desc, "z", driver.info_3->name);        /* long printer name */
624         PACKS(desc, "z", driver.info_3->driverpath);  /* Driverfile Name */
625         PACKS(desc, "z", driver.info_3->datafile);    /* Datafile name */
626         PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
627
628         fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
629         standard_sub_basic( "", "", location, sizeof(location)-1 );
630         PACKS(desc,"z", location);                          /* share to retrieve files */
631
632         PACKS(desc,"z", driver.info_3->defaultdatatype);    /* default data type */
633         PACKS(desc,"z", driver.info_3->helpfile);           /* helpfile name */
634         PACKS(desc,"z", driver.info_3->driverpath);               /* driver name */
635
636         DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
637         DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
638         DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
639         DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
640         DEBUG(3,("Driver Location: %s:\n",location));
641         DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
642         DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
643         PACKI(desc,"N",count);                     /* number of files to copy */
644
645         for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++) 
646         {
647                 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
648                 PACKS(desc,"z",driver.info_3->dependentfiles[i]);         /* driver files to copy */
649                 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
650         }
651
652         /* sanity check */
653         if ( i != count )
654                 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
655                         count, i));
656
657         DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
658
659         desc->errcode=NERR_Success;
660         goto done;
661
662 err:
663         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
664         desc->errcode=NERR_notsupported;
665
666 done:
667         if ( printer )
668                 free_a_printer( &printer, 2 );
669
670         if ( driver.info_3 )
671                 free_a_printer_driver( driver, 3 );
672 }
673
674
675 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
676                              struct pack_desc* desc,
677                              int count, print_queue_struct* queue,
678                              print_status_struct* status)
679 {
680         switch (uLevel) {
681         case 1:
682         case 2:
683                 PACKS(desc,"B13",SERVICE(snum));
684                 break;
685         case 3:
686         case 4:
687         case 5:
688                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
689                 break;
690         case 51:
691                 PACKI(desc,"K",printq_status(status->status));
692                 break;
693         }
694
695         if (uLevel == 1 || uLevel == 2) {
696                 PACKS(desc,"B","");             /* alignment */
697                 PACKI(desc,"W",5);              /* priority */
698                 PACKI(desc,"W",0);              /* start time */
699                 PACKI(desc,"W",0);              /* until time */
700                 PACKS(desc,"z","");             /* pSepFile */
701                 PACKS(desc,"z","lpd");  /* pPrProc */
702                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
703                 PACKS(desc,"z","");             /* pParms */
704                 if (snum < 0) {
705                         PACKS(desc,"z","UNKNOWN PRINTER");
706                         PACKI(desc,"W",LPSTAT_ERROR);
707                 }
708                 else if (!status || !status->message[0]) {
709                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
710                         PACKI(desc,"W",LPSTAT_OK); /* status */
711                 } else {
712                         PACKS(desc,"z",status->message);
713                         PACKI(desc,"W",printq_status(status->status)); /* status */
714                 }
715                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
716         }
717
718         if (uLevel == 3 || uLevel == 4) {
719                 pstring drivername;
720
721                 PACKI(desc,"W",5);              /* uPriority */
722                 PACKI(desc,"W",0);              /* uStarttime */
723                 PACKI(desc,"W",0);              /* uUntiltime */
724                 PACKI(desc,"W",5);              /* pad1 */
725                 PACKS(desc,"z","");             /* pszSepFile */
726                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
727                 PACKS(desc,"z",NULL);           /* pszParms */
728                 PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
729                 /* "don't ask" that it's done this way to fix corrupted 
730                    Win9X/ME printer comments. */
731                 if (!status) {
732                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
733                 } else {
734                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
735                 }
736                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
737                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
738                 get_driver_name(snum,drivername);
739                 PACKS(desc,"z",drivername);             /* pszDriverName */
740                 PackDriverData(desc);   /* pDriverData */
741         }
742
743         if (uLevel == 2 || uLevel == 4) {
744                 int i;
745                 for (i=0;i<count;i++)
746                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
747         }
748
749         if (uLevel==52)
750                 fill_printq_info_52( conn, snum, desc, count );
751 }
752
753 /* This function returns the number of files for a given driver */
754 static int get_printerdrivernumber(int snum)
755 {
756         int                             result = 0;
757         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
758         NT_PRINTER_INFO_LEVEL           *printer = NULL;
759
760         ZERO_STRUCT(driver);
761
762         if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
763                 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n", 
764                         lp_servicename(snum)));
765                 goto done;
766         }
767
768         if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
769                 "Windows 4.0", 0)) )
770         {
771                 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", 
772                         printer->info_2->drivername));
773                 goto done;
774         }
775
776         /* count the number of files */
777         while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
778                         result++;
779                         \
780  done:
781         if ( printer )
782                 free_a_printer( &printer, 2 );
783
784         if ( driver.info_3 )
785                 free_a_printer_driver( driver, 3 );
786
787         return result;
788 }
789
790 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
791                                 char *param, int tpscnt,
792                                 char *data, int tdscnt,
793                                 int mdrcnt,int mprcnt,
794                                 char **rdata,char **rparam,
795                                 int *rdata_len,int *rparam_len)
796 {
797         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
798         char *str2 = skip_string(param,tpscnt,str1);
799         char *p = skip_string(param,tpscnt,str2);
800         char *QueueName = p;
801         unsigned int uLevel;
802         int count=0;
803         int snum;
804         char *str3;
805         struct pack_desc desc;
806         print_queue_struct *queue=NULL;
807         print_status_struct status;
808         char* tmpdata=NULL;
809
810         if (!str1 || !str2 || !p) {
811                 return False;
812         }
813         memset((char *)&status,'\0',sizeof(status));
814         memset((char *)&desc,'\0',sizeof(desc));
815
816         p = skip_string(param,tpscnt,p);
817         if (!p) {
818                 return False;
819         }
820         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
821         str3 = get_safe_str_ptr(param,tpscnt,p,4);
822         /* str3 may be null here and is checked in check_printq_info(). */
823
824         /* remove any trailing username */
825         if ((p = strchr_m(QueueName,'%')))
826                 *p = 0;
827  
828         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
829  
830         /* check it's a supported varient */
831         if (!prefix_ok(str1,"zWrLh"))
832                 return False;
833         if (!check_printq_info(&desc,uLevel,str2,str3)) {
834                 /*
835                  * Patch from Scott Moomaw <scott@bridgewater.edu>
836                  * to return the 'invalid info level' error if an
837                  * unknown level was requested.
838                  */
839                 *rdata_len = 0;
840                 *rparam_len = 6;
841                 *rparam = smb_realloc_limit(*rparam,*rparam_len);
842                 if (!*rparam) {
843                         return False;
844                 }
845                 SSVALS(*rparam,0,ERRunknownlevel);
846                 SSVAL(*rparam,2,0);
847                 SSVAL(*rparam,4,0);
848                 return(True);
849         }
850  
851         snum = find_service(QueueName);
852         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
853                 return False;
854                 
855         if (uLevel==52) {
856                 count = get_printerdrivernumber(snum);
857                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
858         } else {
859                 count = print_queue_status(snum, &queue,&status);
860         }
861
862         if (mdrcnt > 0) {
863                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
864                 if (!*rdata) {
865                         SAFE_FREE(queue);
866                         return False;
867                 }
868                 desc.base = *rdata;
869                 desc.buflen = mdrcnt;
870         } else {
871                 /*
872                  * Don't return data but need to get correct length
873                  * init_package will return wrong size if buflen=0
874                  */
875                 desc.buflen = getlen(desc.format);
876                 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
877         }
878
879         if (init_package(&desc,1,count)) {
880                 desc.subcount = count;
881                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
882         }
883
884         *rdata_len = desc.usedlen;
885   
886         /*
887          * We must set the return code to ERRbuftoosmall
888          * in order to support lanman style printing with Win NT/2k
889          * clients       --jerry
890          */
891         if (!mdrcnt && lp_disable_spoolss())
892                 desc.errcode = ERRbuftoosmall;
893  
894         *rdata_len = desc.usedlen;
895         *rparam_len = 6;
896         *rparam = smb_realloc_limit(*rparam,*rparam_len);
897         if (!*rparam) {
898                 SAFE_FREE(queue);
899                 SAFE_FREE(tmpdata);
900                 return False;
901         }
902         SSVALS(*rparam,0,desc.errcode);
903         SSVAL(*rparam,2,0);
904         SSVAL(*rparam,4,desc.neededlen);
905   
906         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
907
908         SAFE_FREE(queue);
909         SAFE_FREE(tmpdata);
910
911         return(True);
912 }
913
914 /****************************************************************************
915  View list of all print jobs on all queues.
916 ****************************************************************************/
917
918 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
919                                 char *param, int tpscnt,
920                                 char *data, int tdscnt,
921                                 int mdrcnt, int mprcnt,
922                                 char **rdata, char** rparam,
923                                 int *rdata_len, int *rparam_len)
924 {
925         char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
926         char *output_format1 = skip_string(param,tpscnt,param_format);
927         char *p = skip_string(param,tpscnt,output_format1);
928         unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
929         char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
930         int services = lp_numservices();
931         int i, n;
932         struct pack_desc desc;
933         print_queue_struct **queue = NULL;
934         print_status_struct *status = NULL;
935         int *subcntarr = NULL;
936         int queuecnt = 0, subcnt = 0, succnt = 0;
937  
938         if (!param_format || !output_format1 || !p) {
939                 return False;
940         }
941
942         memset((char *)&desc,'\0',sizeof(desc));
943
944         DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
945  
946         if (!prefix_ok(param_format,"WrLeh")) {
947                 return False;
948         }
949         if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
950                 /*
951                  * Patch from Scott Moomaw <scott@bridgewater.edu>
952                  * to return the 'invalid info level' error if an
953                  * unknown level was requested.
954                  */
955                 *rdata_len = 0;
956                 *rparam_len = 6;
957                 *rparam = smb_realloc_limit(*rparam,*rparam_len);
958                 if (!*rparam) {
959                         return False;
960                 }
961                 SSVALS(*rparam,0,ERRunknownlevel);
962                 SSVAL(*rparam,2,0);
963                 SSVAL(*rparam,4,0);
964                 return(True);
965         }
966
967         for (i = 0; i < services; i++) {
968                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
969                         queuecnt++;
970                 }
971         }
972
973         if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
974                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
975                 goto err;
976         }
977         memset(queue,0,queuecnt*sizeof(print_queue_struct*));
978         if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
979                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
980                 goto err;
981         }
982         memset(status,0,queuecnt*sizeof(print_status_struct));
983         if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
984                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
985                 goto err;
986         }
987
988         subcnt = 0;
989         n = 0;
990         for (i = 0; i < services; i++) {
991                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
992                         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
993                         subcnt += subcntarr[n];
994                         n++;
995                 }
996         }
997
998         if (mdrcnt > 0) {
999                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1000                 if (!*rdata) {
1001                         goto err;
1002                 }
1003         }
1004         desc.base = *rdata;
1005         desc.buflen = mdrcnt;
1006
1007         if (init_package(&desc,queuecnt,subcnt)) {
1008                 n = 0;
1009                 succnt = 0;
1010                 for (i = 0; i < services; i++) {
1011                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1012                                 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1013                                 n++;
1014                                 if (desc.errcode == NERR_Success) {
1015                                         succnt = n;
1016                                 }
1017                         }
1018                 }
1019         }
1020
1021         SAFE_FREE(subcntarr);
1022  
1023         *rdata_len = desc.usedlen;
1024         *rparam_len = 8;
1025         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1026         if (!*rparam) {
1027                 goto err;
1028         }
1029         SSVALS(*rparam,0,desc.errcode);
1030         SSVAL(*rparam,2,0);
1031         SSVAL(*rparam,4,succnt);
1032         SSVAL(*rparam,6,queuecnt);
1033   
1034         for (i = 0; i < queuecnt; i++) {
1035                 if (queue) {
1036                         SAFE_FREE(queue[i]);
1037                 }
1038         }
1039
1040         SAFE_FREE(queue);
1041         SAFE_FREE(status);
1042   
1043         return True;
1044
1045   err:
1046
1047         SAFE_FREE(subcntarr);
1048         for (i = 0; i < queuecnt; i++) {
1049                 if (queue) {
1050                         SAFE_FREE(queue[i]);
1051                 }
1052         }
1053         SAFE_FREE(queue);
1054         SAFE_FREE(status);
1055
1056         return False;
1057 }
1058
1059 /****************************************************************************
1060  Get info level for a server list query.
1061 ****************************************************************************/
1062
1063 static bool check_server_info(int uLevel, char* id)
1064 {
1065         switch( uLevel ) {
1066                 case 0:
1067                         if (strcmp(id,"B16") != 0) {
1068                                 return False;
1069                         }
1070                         break;
1071                 case 1:
1072                         if (strcmp(id,"B16BBDz") != 0) {
1073                                 return False;
1074                         }
1075                         break;
1076                 default: 
1077                         return False;
1078         }
1079         return True;
1080 }
1081
1082 struct srv_info_struct {
1083         fstring name;
1084         uint32 type;
1085         fstring comment;
1086         fstring domain;
1087         bool server_added;
1088 };
1089
1090 /*******************************************************************
1091  Get server info lists from the files saved by nmbd. Return the
1092  number of entries.
1093 ******************************************************************/
1094
1095 static int get_server_info(uint32 servertype, 
1096                            struct srv_info_struct **servers,
1097                            const char *domain)
1098 {
1099         int count=0;
1100         int alloced=0;
1101         char **lines;
1102         bool local_list_only;
1103         int i;
1104
1105         lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1106         if (!lines) {
1107                 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1108                 return 0;
1109         }
1110
1111         /* request for everything is code for request all servers */
1112         if (servertype == SV_TYPE_ALL) {
1113                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1114         }
1115
1116         local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1117
1118         DEBUG(4,("Servertype search: %8x\n",servertype));
1119
1120         for (i=0;lines[i];i++) {
1121                 fstring stype;
1122                 struct srv_info_struct *s;
1123                 const char *ptr = lines[i];
1124                 bool ok = True;
1125
1126                 if (!*ptr) {
1127                         continue;
1128                 }
1129     
1130                 if (count == alloced) {
1131                         alloced += 10;
1132                         *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1133                         if (!*servers) {
1134                                 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1135                                 file_lines_free(lines);
1136                                 return 0;
1137                         }
1138                         memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1139                 }
1140                 s = &(*servers)[count];
1141     
1142                 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1143                         continue;
1144                 }
1145                 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1146                         continue;
1147                 }
1148                 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1149                         continue;
1150                 }
1151                 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1152                         /* this allows us to cope with an old nmbd */
1153                         fstrcpy(s->domain,lp_workgroup()); 
1154                 }
1155     
1156                 if (sscanf(stype,"%X",&s->type) != 1) { 
1157                         DEBUG(4,("r:host file ")); 
1158                         ok = False; 
1159                 }
1160     
1161                 /* Filter the servers/domains we return based on what was asked for. */
1162
1163                 /* Check to see if we are being asked for a local list only. */
1164                 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1165                         DEBUG(4,("r: local list only"));
1166                         ok = False;
1167                 }
1168
1169                 /* doesn't match up: don't want it */
1170                 if (!(servertype & s->type)) { 
1171                         DEBUG(4,("r:serv type ")); 
1172                         ok = False; 
1173                 }
1174     
1175                 if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1176                                 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1177                         DEBUG(4,("s: dom mismatch "));
1178                         ok = False;
1179                 }
1180     
1181                 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1182                         ok = False;
1183                 }
1184     
1185                 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1186                 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1187
1188                 if (ok) {
1189                         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1190                                 s->name, s->type, s->comment, s->domain));
1191                         s->server_added = True;
1192                         count++;
1193                 } else {
1194                         DEBUG(4,("%20s %8x %25s %15s\n",
1195                                 s->name, s->type, s->comment, s->domain));
1196                 }
1197         }
1198   
1199         file_lines_free(lines);
1200         return count;
1201 }
1202
1203 /*******************************************************************
1204  Fill in a server info structure.
1205 ******************************************************************/
1206
1207 static int fill_srv_info(struct srv_info_struct *service, 
1208                          int uLevel, char **buf, int *buflen, 
1209                          char **stringbuf, int *stringspace, char *baseaddr)
1210 {
1211         int struct_len;
1212         char* p;
1213         char* p2;
1214         int l2;
1215         int len;
1216  
1217         switch (uLevel) {
1218                 case 0:
1219                         struct_len = 16;
1220                         break;
1221                 case 1:
1222                         struct_len = 26;
1223                         break;
1224                 default:
1225                         return -1;
1226         }
1227  
1228         if (!buf) {
1229                 len = 0;
1230                 switch (uLevel) {
1231                         case 1:
1232                                 len = strlen(service->comment)+1;
1233                                 break;
1234                 }
1235
1236                 *buflen = struct_len;
1237                 *stringspace = len;
1238                 return struct_len + len;
1239         }
1240   
1241         len = struct_len;
1242         p = *buf;
1243         if (*buflen < struct_len) {
1244                 return -1;
1245         }
1246         if (stringbuf) {
1247                 p2 = *stringbuf;
1248                 l2 = *stringspace;
1249         } else {
1250                 p2 = p + struct_len;
1251                 l2 = *buflen - struct_len;
1252         }
1253         if (!baseaddr) {
1254                 baseaddr = p;
1255         }
1256   
1257         switch (uLevel) {
1258                 case 0:
1259                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1260                         break;
1261
1262                 case 1:
1263                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1264                         SIVAL(p,18,service->type);
1265                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1266                         len += CopyAndAdvance(&p2,service->comment,&l2);
1267                         break;
1268         }
1269
1270         if (stringbuf) {
1271                 *buf = p + struct_len;
1272                 *buflen -= struct_len;
1273                 *stringbuf = p2;
1274                 *stringspace = l2;
1275         } else {
1276                 *buf = p2;
1277                 *buflen -= len;
1278         }
1279         return len;
1280 }
1281
1282
1283 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1284 {
1285         return(strcmp(s1->name,s2->name));
1286 }
1287
1288 /****************************************************************************
1289  View list of servers available (or possibly domains). The info is
1290  extracted from lists saved by nmbd on the local host.
1291 ****************************************************************************/
1292
1293 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1294                                 char *param, int tpscnt,
1295                                 char *data, int tdscnt,
1296                                 int mdrcnt, int mprcnt, char **rdata, 
1297                                 char **rparam, int *rdata_len, int *rparam_len)
1298 {
1299         char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1300         char *str2 = skip_string(param,tpscnt,str1);
1301         char *p = skip_string(param,tpscnt,str2);
1302         int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1303         int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1304         uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1305         char *p2;
1306         int data_len, fixed_len, string_len;
1307         int f_len = 0, s_len = 0;
1308         struct srv_info_struct *servers=NULL;
1309         int counted=0,total=0;
1310         int i,missed;
1311         fstring domain;
1312         bool domain_request;
1313         bool local_request;
1314
1315         if (!str1 || !str2 || !p) {
1316                 return False;
1317         }
1318
1319         /* If someone sets all the bits they don't really mean to set
1320            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1321            known servers. */
1322
1323         if (servertype == SV_TYPE_ALL) {
1324                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1325         }
1326
1327         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1328            any other bit (they may just set this bit on it's own) they 
1329            want all the locally seen servers. However this bit can be 
1330            set on its own so set the requested servers to be 
1331            ALL - DOMAIN_ENUM. */
1332
1333         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1334                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1335         }
1336
1337         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1338         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1339
1340         p += 8;
1341
1342         if (!prefix_ok(str1,"WrLehD")) {
1343                 return False;
1344         }
1345         if (!check_server_info(uLevel,str2)) {
1346                 return False;
1347         }
1348   
1349         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1350         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1351         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1352
1353         if (strcmp(str1, "WrLehDz") == 0) {
1354                 if (skip_string(param,tpscnt,p) == NULL) {
1355                         return False;
1356                 }
1357                 pull_ascii_fstring(domain, p);
1358         } else {
1359                 fstrcpy(domain, lp_workgroup());
1360         }
1361
1362         if (lp_browse_list()) {
1363                 total = get_server_info(servertype,&servers,domain);
1364         }
1365
1366         data_len = fixed_len = string_len = 0;
1367         missed = 0;
1368
1369         if (total > 0) {
1370                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1371         }
1372
1373         {
1374                 char *lastname=NULL;
1375
1376                 for (i=0;i<total;i++) {
1377                         struct srv_info_struct *s = &servers[i];
1378
1379                         if (lastname && strequal(lastname,s->name)) {
1380                                 continue;
1381                         }
1382                         lastname = s->name;
1383                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1384                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1385                                 s->name, s->type, s->comment, s->domain));
1386       
1387                         if (data_len <= buf_len) {
1388                                 counted++;
1389                                 fixed_len += f_len;
1390                                 string_len += s_len;
1391                         } else {
1392                                 missed++;
1393                         }
1394                 }
1395         }
1396
1397         *rdata_len = fixed_len + string_len;
1398         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1399         if (!*rdata) {
1400                 return False;
1401         }
1402   
1403         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1404         p = *rdata;
1405         f_len = fixed_len;
1406         s_len = string_len;
1407
1408         {
1409                 char *lastname=NULL;
1410                 int count2 = counted;
1411
1412                 for (i = 0; i < total && count2;i++) {
1413                         struct srv_info_struct *s = &servers[i];
1414
1415                         if (lastname && strequal(lastname,s->name)) {
1416                                 continue;
1417                         }
1418                         lastname = s->name;
1419                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1420                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1421                                 s->name, s->type, s->comment, s->domain));
1422                         count2--;
1423                 }
1424         }
1425   
1426         *rparam_len = 8;
1427         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1428         if (!*rparam) {
1429                 return False;
1430         }
1431         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1432         SSVAL(*rparam,2,0);
1433         SSVAL(*rparam,4,counted);
1434         SSVAL(*rparam,6,counted+missed);
1435
1436         SAFE_FREE(servers);
1437
1438         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1439                 domain,uLevel,counted,counted+missed));
1440
1441         return True;
1442 }
1443
1444 /****************************************************************************
1445   command 0x34 - suspected of being a "Lookup Names" stub api
1446   ****************************************************************************/
1447
1448 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1449                                 char *param, int tpscnt,
1450                                 char *data, int tdscnt,
1451                                 int mdrcnt, int mprcnt, char **rdata, 
1452                                 char **rparam, int *rdata_len, int *rparam_len)
1453 {
1454         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1455         char *str2 = skip_string(param,tpscnt,str1);
1456         char *p = skip_string(param,tpscnt,str2);
1457         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1458         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1459         int counted=0;
1460         int missed=0;
1461
1462         if (!str1 || !str2 || !p) {
1463                 return False;
1464         }
1465
1466         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1467                 str1, str2, p, uLevel, buf_len));
1468
1469         if (!prefix_ok(str1,"zWrLeh")) {
1470                 return False;
1471         }
1472   
1473         *rdata_len = 0;
1474   
1475         *rparam_len = 8;
1476         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1477         if (!*rparam) {
1478                 return False;
1479         }
1480
1481         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1482         SSVAL(*rparam,2,0);
1483         SSVAL(*rparam,4,counted);
1484         SSVAL(*rparam,6,counted+missed);
1485
1486         return True;
1487 }
1488
1489 /****************************************************************************
1490   get info about a share
1491   ****************************************************************************/
1492
1493 static bool check_share_info(int uLevel, char* id)
1494 {
1495         switch( uLevel ) {
1496                 case 0:
1497                         if (strcmp(id,"B13") != 0) {
1498                                 return False;
1499                         }
1500                         break;
1501                 case 1:
1502                         if (strcmp(id,"B13BWz") != 0) {
1503                                 return False;
1504                         }
1505                         break;
1506                 case 2:
1507                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1508                                 return False;
1509                         }
1510                         break;
1511                 case 91:
1512                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1513                                 return False;
1514                         }
1515                         break;
1516                 default:
1517                         return False;
1518         }
1519         return True;
1520 }
1521
1522 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1523                            char** buf, int* buflen,
1524                            char** stringbuf, int* stringspace, char* baseaddr)
1525 {
1526         int struct_len;
1527         char* p;
1528         char* p2;
1529         int l2;
1530         int len;
1531  
1532         switch( uLevel ) {
1533                 case 0:
1534                         struct_len = 13;
1535                         break;
1536                 case 1:
1537                         struct_len = 20;
1538                         break;
1539                 case 2:
1540                         struct_len = 40;
1541                         break;
1542                 case 91:
1543                         struct_len = 68;
1544                         break;
1545                 default:
1546                         return -1;
1547         }
1548   
1549  
1550         if (!buf) {
1551                 len = 0;
1552
1553                 if (uLevel > 0) {
1554                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1555                 }
1556                 if (uLevel > 1) {
1557                         len += strlen(lp_pathname(snum)) + 1;
1558                 }
1559                 if (buflen) {
1560                         *buflen = struct_len;
1561                 }
1562                 if (stringspace) {
1563                         *stringspace = len;
1564                 }
1565                 return struct_len + len;
1566         }
1567   
1568         len = struct_len;
1569         p = *buf;
1570         if ((*buflen) < struct_len) {
1571                 return -1;
1572         }
1573
1574         if (stringbuf) {
1575                 p2 = *stringbuf;
1576                 l2 = *stringspace;
1577         } else {
1578                 p2 = p + struct_len;
1579                 l2 = (*buflen) - struct_len;
1580         }
1581
1582         if (!baseaddr) {
1583                 baseaddr = p;
1584         }
1585   
1586         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1587   
1588         if (uLevel > 0) {
1589                 int type;
1590
1591                 SCVAL(p,13,0);
1592                 type = STYPE_DISKTREE;
1593                 if (lp_print_ok(snum)) {
1594                         type = STYPE_PRINTQ;
1595                 }
1596                 if (strequal("IPC",lp_fstype(snum))) {
1597                         type = STYPE_IPC;
1598                 }
1599                 SSVAL(p,14,type);               /* device type */
1600                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1601                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1602         }
1603   
1604         if (uLevel > 1) {
1605                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1606                 SSVALS(p,22,-1);                /* max uses */
1607                 SSVAL(p,24,1); /* current uses */
1608                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1609                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1610                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1611         }
1612   
1613         if (uLevel > 2) {
1614                 memset(p+40,0,SHPWLEN+2);
1615                 SSVAL(p,50,0);
1616                 SIVAL(p,52,0);
1617                 SSVAL(p,56,0);
1618                 SSVAL(p,58,0);
1619                 SIVAL(p,60,0);
1620                 SSVAL(p,64,0);
1621                 SSVAL(p,66,0);
1622         }
1623        
1624         if (stringbuf) {
1625                 (*buf) = p + struct_len;
1626                 (*buflen) -= struct_len;
1627                 (*stringbuf) = p2;
1628                 (*stringspace) = l2;
1629         } else {
1630                 (*buf) = p2;
1631                 (*buflen) -= len;
1632         }
1633
1634         return len;
1635 }
1636
1637 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1638                                 char *param, int tpscnt,
1639                                 char *data, int tdscnt,
1640                                 int mdrcnt,int mprcnt,
1641                                 char **rdata,char **rparam,
1642                                 int *rdata_len,int *rparam_len)
1643 {
1644         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1645         char *str2 = skip_string(param,tpscnt,str1);
1646         char *netname = skip_string(param,tpscnt,str2);
1647         char *p = skip_string(param,tpscnt,netname);
1648         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1649         int snum;
1650   
1651         if (!str1 || !str2 || !netname || !p) {
1652                 return False;
1653         }
1654
1655         snum = find_service(netname);
1656         if (snum < 0) {
1657                 return False;
1658         }
1659   
1660         /* check it's a supported varient */
1661         if (!prefix_ok(str1,"zWrLh")) {
1662                 return False;
1663         }
1664         if (!check_share_info(uLevel,str2)) {
1665                 return False;
1666         }
1667  
1668         *rdata = smb_realloc_limit(*rdata,mdrcnt);
1669         if (!*rdata) {
1670                 return False;
1671         }
1672         p = *rdata;
1673         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1674         if (*rdata_len < 0) {
1675                 return False;
1676         }
1677  
1678         *rparam_len = 6;
1679         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1680         if (!*rparam) {
1681                 return False;
1682         }
1683         SSVAL(*rparam,0,NERR_Success);
1684         SSVAL(*rparam,2,0);             /* converter word */
1685         SSVAL(*rparam,4,*rdata_len);
1686  
1687         return True;
1688 }
1689
1690 /****************************************************************************
1691   View the list of available shares.
1692
1693   This function is the server side of the NetShareEnum() RAP call.
1694   It fills the return buffer with share names and share comments.
1695   Note that the return buffer normally (in all known cases) allows only
1696   twelve byte strings for share names (plus one for a nul terminator).
1697   Share names longer than 12 bytes must be skipped.
1698  ****************************************************************************/
1699
1700 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1701                                 char *param, int tpscnt,
1702                                 char *data, int tdscnt,
1703                                 int                mdrcnt,
1704                                 int                mprcnt,
1705                                 char             **rdata,
1706                                 char             **rparam,
1707                                 int               *rdata_len,
1708                                 int               *rparam_len )
1709 {
1710         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1711         char *str2 = skip_string(param,tpscnt,str1);
1712         char *p = skip_string(param,tpscnt,str2);
1713         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1714         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1715         char *p2;
1716         int count = 0;
1717         int total=0,counted=0;
1718         bool missed = False;
1719         int i;
1720         int data_len, fixed_len, string_len;
1721         int f_len = 0, s_len = 0;
1722  
1723         if (!str1 || !str2 || !p) {
1724                 return False;
1725         }
1726
1727         if (!prefix_ok(str1,"WrLeh")) {
1728                 return False;
1729         }
1730         if (!check_share_info(uLevel,str2)) {
1731                 return False;
1732         }
1733   
1734         /* Ensure all the usershares are loaded. */
1735         become_root();
1736         load_registry_shares();
1737         count = load_usershare_shares();
1738         unbecome_root();
1739
1740         data_len = fixed_len = string_len = 0;
1741         for (i=0;i<count;i++) {
1742                 fstring servicename_dos;
1743                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1744                         continue;
1745                 }
1746                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1747                 /* Maximum name length = 13. */
1748                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1749                         total++;
1750                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1751                         if (data_len <= buf_len) {
1752                                 counted++;
1753                                 fixed_len += f_len;
1754                                 string_len += s_len;
1755                         } else {
1756                                 missed = True;
1757                         }
1758                 }
1759         }
1760
1761         *rdata_len = fixed_len + string_len;
1762         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1763         if (!*rdata) {
1764                 return False;
1765         }
1766  
1767         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1768         p = *rdata;
1769         f_len = fixed_len;
1770         s_len = string_len;
1771
1772         for( i = 0; i < count; i++ ) {
1773                 fstring servicename_dos;
1774                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1775                         continue;
1776                 }
1777
1778                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1779                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1780                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1781                                 break;
1782                         }
1783                 }
1784         }
1785   
1786         *rparam_len = 8;
1787         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1788         if (!*rparam) {
1789                 return False;
1790         }
1791         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1792         SSVAL(*rparam,2,0);
1793         SSVAL(*rparam,4,counted);
1794         SSVAL(*rparam,6,total);
1795   
1796         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1797                 counted,total,uLevel,
1798                 buf_len,*rdata_len,mdrcnt));
1799
1800         return True;
1801 }
1802
1803 /****************************************************************************
1804   Add a share
1805   ****************************************************************************/
1806
1807 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1808                                 char *param, int tpscnt,
1809                                 char *data, int tdscnt,
1810                                 int mdrcnt,int mprcnt,
1811                                 char **rdata,char **rparam,
1812                                 int *rdata_len,int *rparam_len)
1813 {
1814         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1815         char *str2 = skip_string(param,tpscnt,str1);
1816         char *p = skip_string(param,tpscnt,str2);
1817         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1818         fstring sharename;
1819         fstring comment;
1820         pstring pathname;
1821         char *command, *cmdname;
1822         unsigned int offset;
1823         int snum;
1824         int res = ERRunsup;
1825   
1826         if (!str1 || !str2 || !p) {
1827                 return False;
1828         }
1829
1830         /* check it's a supported varient */
1831         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1832                 return False;
1833         }
1834         if (!check_share_info(uLevel,str2)) {
1835                 return False;
1836         }
1837         if (uLevel != 2) {
1838                 return False;
1839         }
1840
1841         /* Do we have a string ? */
1842         if (skip_string(data,mdrcnt,data) == NULL) {
1843                 return False;
1844         }
1845         pull_ascii_fstring(sharename,data);
1846         snum = find_service(sharename);
1847         if (snum >= 0) { /* already exists */
1848                 res = ERRfilexists;
1849                 goto error_exit;
1850         }
1851
1852         if (mdrcnt < 28) {
1853                 return False;
1854         }
1855
1856         /* only support disk share adds */
1857         if (SVAL(data,14)!=STYPE_DISKTREE) {
1858                 return False;
1859         }
1860
1861         offset = IVAL(data, 16);
1862         if (offset >= mdrcnt) {
1863                 res = ERRinvalidparam;
1864                 goto error_exit;
1865         }
1866
1867         /* Do we have a string ? */
1868         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1869                 return False;
1870         }
1871         pull_ascii_fstring(comment, offset? (data+offset) : "");
1872
1873         offset = IVAL(data, 26);
1874
1875         if (offset >= mdrcnt) {
1876                 res = ERRinvalidparam;
1877                 goto error_exit;
1878         }
1879
1880         /* Do we have a string ? */
1881         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1882                 return False;
1883         }
1884         pull_ascii_pstring(pathname, offset? (data+offset) : "");
1885
1886         string_replace(sharename, '"', ' ');
1887         string_replace(pathname, '"', ' ');
1888         string_replace(comment, '"', ' ');
1889
1890         cmdname = lp_add_share_cmd();
1891
1892         if (!cmdname || *cmdname == '\0') {
1893                 return False;
1894         }
1895
1896         asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1897                 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1898
1899         if (command) {
1900                 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1901
1902                 if ((res = smbrun(command, NULL)) != 0) {
1903                         DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1904                         SAFE_FREE(command);
1905                         res = ERRnoaccess;
1906                         goto error_exit;
1907                 } else {
1908                         SAFE_FREE(command);
1909                         message_send_all(smbd_messaging_context(),
1910                                          MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1911                 }
1912         } else {
1913                 return False;
1914         }
1915
1916         *rparam_len = 6;
1917         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1918         if (!*rparam) {
1919                 return False;
1920         }
1921         SSVAL(*rparam,0,NERR_Success);
1922         SSVAL(*rparam,2,0);             /* converter word */
1923         SSVAL(*rparam,4,*rdata_len);
1924         *rdata_len = 0;
1925   
1926         return True;
1927
1928   error_exit:
1929
1930         *rparam_len = 4;
1931         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1932         if (!*rparam) {
1933                 return False;
1934         }
1935         *rdata_len = 0;
1936         SSVAL(*rparam,0,res);
1937         SSVAL(*rparam,2,0);
1938         return True;
1939 }
1940
1941 /****************************************************************************
1942   view list of groups available
1943   ****************************************************************************/
1944
1945 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1946                                 char *param, int tpscnt,
1947                                 char *data, int tdscnt,
1948                                 int mdrcnt,int mprcnt,
1949                                 char **rdata,char **rparam,
1950                                 int *rdata_len,int *rparam_len)
1951 {
1952         int i;
1953         int errflags=0;
1954         int resume_context, cli_buf_size;
1955         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1956         char *str2 = skip_string(param,tpscnt,str1);
1957         char *p = skip_string(param,tpscnt,str2);
1958
1959         struct pdb_search *search;
1960         struct samr_displayentry *entries;
1961
1962         int num_entries;
1963  
1964         if (!str1 || !str2 || !p) {
1965                 return False;
1966         }
1967
1968         if (strcmp(str1,"WrLeh") != 0) {
1969                 return False;
1970         }
1971
1972         /* parameters  
1973          * W-> resume context (number of users to skip)
1974          * r -> return parameter pointer to receive buffer 
1975          * L -> length of receive buffer
1976          * e -> return parameter number of entries
1977          * h -> return parameter total number of users
1978          */
1979
1980         if (strcmp("B21",str2) != 0) {
1981                 return False;
1982         }
1983
1984         /* get list of domain groups SID_DOMAIN_GRP=2 */
1985         become_root();
1986         search = pdb_search_groups();
1987         unbecome_root();
1988
1989         if (search == NULL) {
1990                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1991                 return False;
1992         }
1993
1994         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1995         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1996         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1997                   "%d\n", resume_context, cli_buf_size));
1998
1999         become_root();
2000         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2001                                          &entries);
2002         unbecome_root();
2003
2004         *rdata_len = cli_buf_size;
2005         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2006         if (!*rdata) {
2007                 return False;
2008         }
2009
2010         p = *rdata;
2011
2012         for(i=0; i<num_entries; i++) {
2013                 fstring name;
2014                 fstrcpy(name, entries[i].account_name);
2015                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2016                         /* truncate the name at 21 chars. */
2017                         memcpy(p, name, 21); 
2018                         DEBUG(10,("adding entry %d group %s\n", i, p));
2019                         p += 21;
2020                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
2021                                    No idea why... */
2022                 } else {
2023                         /* set overflow error */
2024                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
2025                         errflags=234;
2026                         break;
2027                 }
2028         }
2029
2030         pdb_search_destroy(search);
2031
2032         *rdata_len = PTR_DIFF(p,*rdata);
2033
2034         *rparam_len = 8;
2035         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2036         if (!*rparam) {
2037                 return False;
2038         }
2039         SSVAL(*rparam, 0, errflags);
2040         SSVAL(*rparam, 2, 0);           /* converter word */
2041         SSVAL(*rparam, 4, i);   /* is this right?? */
2042         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
2043
2044         return(True);
2045 }
2046
2047 /*******************************************************************
2048  Get groups that a user is a member of.
2049 ******************************************************************/
2050
2051 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2052                                 char *param, int tpscnt,
2053                                 char *data, int tdscnt,
2054                                 int mdrcnt,int mprcnt,
2055                                 char **rdata,char **rparam,
2056                                 int *rdata_len,int *rparam_len)
2057 {
2058         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2059         char *str2 = skip_string(param,tpscnt,str1);
2060         char *UserName = skip_string(param,tpscnt,str2);
2061         char *p = skip_string(param,tpscnt,UserName);
2062         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2063         const char *level_string;
2064         int count=0;
2065         struct samu *sampw = NULL;
2066         bool ret = False;
2067         DOM_SID *sids;
2068         gid_t *gids;
2069         size_t num_groups;
2070         size_t i;
2071         NTSTATUS result;
2072         DOM_SID user_sid;
2073         enum lsa_SidType type;
2074         TALLOC_CTX *mem_ctx;
2075
2076         if (!str1 || !str2 || !UserName || !p) {
2077                 return False;
2078         }
2079
2080         *rparam_len = 8;
2081         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2082         if (!*rparam) {
2083                 return False;
2084         }
2085
2086         /* check it's a supported varient */
2087
2088         if ( strcmp(str1,"zWrLeh") != 0 )
2089                 return False;
2090
2091         switch( uLevel ) {
2092                 case 0:
2093                         level_string = "B21";
2094                         break;
2095                 default:
2096                         return False;
2097         }
2098
2099         if (strcmp(level_string,str2) != 0)
2100                 return False;
2101
2102         *rdata_len = mdrcnt + 1024;
2103         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2104         if (!*rdata) {
2105                 return False;
2106         }
2107
2108         SSVAL(*rparam,0,NERR_Success);
2109         SSVAL(*rparam,2,0);             /* converter word */
2110
2111         p = *rdata;
2112
2113         mem_ctx = talloc_new(NULL);
2114         if (mem_ctx == NULL) {
2115                 DEBUG(0, ("talloc_new failed\n"));
2116                 return False;
2117         }
2118
2119         if ( !(sampw = samu_new(mem_ctx)) ) {
2120                 DEBUG(0, ("samu_new() failed!\n"));
2121                 TALLOC_FREE(mem_ctx);
2122                 return False;
2123         }
2124
2125         /* Lookup the user information; This should only be one of 
2126            our accounts (not remote domains) */
2127
2128         become_root();                                  /* ROOT BLOCK */
2129
2130         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2131                          NULL, NULL, &user_sid, &type)) {
2132                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2133                 goto done;
2134         }
2135
2136         if (type != SID_NAME_USER) {
2137                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2138                            sid_type_lookup(type)));
2139                 goto done;
2140         }
2141
2142         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2143                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2144                            sid_string_static(&user_sid), UserName));
2145                 goto done;
2146         }
2147
2148         gids = NULL;
2149         sids = NULL;
2150         num_groups = 0;
2151
2152         result = pdb_enum_group_memberships(mem_ctx, sampw,
2153                                             &sids, &gids, &num_groups);
2154
2155         if (!NT_STATUS_IS_OK(result)) {
2156                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2157                            UserName));
2158                 goto done;
2159         }
2160
2161         for (i=0; i<num_groups; i++) {
2162
2163                 const char *grp_name;
2164         
2165                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2166                         pstrcpy(p, grp_name);
2167                         p += 21; 
2168                         count++;
2169                 }
2170         }
2171
2172         *rdata_len = PTR_DIFF(p,*rdata);
2173
2174         SSVAL(*rparam,4,count); /* is this right?? */
2175         SSVAL(*rparam,6,count); /* is this right?? */
2176
2177         ret = True;
2178
2179 done:
2180         unbecome_root();                                /* END ROOT BLOCK */
2181
2182         TALLOC_FREE(mem_ctx);
2183
2184         return ret;
2185 }
2186
2187 /*******************************************************************
2188  Get all users.
2189 ******************************************************************/
2190
2191 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2192                                 char *param, int tpscnt,
2193                                 char *data, int tdscnt,
2194                                 int mdrcnt,int mprcnt,
2195                                 char **rdata,char **rparam,
2196                                 int *rdata_len,int *rparam_len)
2197 {
2198         int count_sent=0;
2199         int num_users=0;
2200         int errflags=0;
2201         int i, resume_context, cli_buf_size;
2202         struct pdb_search *search;
2203         struct samr_displayentry *users;
2204
2205         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2206         char *str2 = skip_string(param,tpscnt,str1);
2207         char *p = skip_string(param,tpscnt,str2);
2208
2209         if (!str1 || !str2 || !p) {
2210                 return False;
2211         }
2212
2213         if (strcmp(str1,"WrLeh") != 0)
2214                 return False;
2215         /* parameters
2216           * W-> resume context (number of users to skip)
2217           * r -> return parameter pointer to receive buffer
2218           * L -> length of receive buffer
2219           * e -> return parameter number of entries
2220           * h -> return parameter total number of users
2221           */
2222   
2223         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2224         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2225         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2226                         resume_context, cli_buf_size));
2227
2228         *rparam_len = 8;
2229         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2230         if (!*rparam) {
2231                 return False;
2232         }
2233
2234         /* check it's a supported varient */
2235         if (strcmp("B21",str2) != 0)
2236                 return False;
2237
2238         *rdata_len = cli_buf_size;
2239         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2240         if (!*rdata) {
2241                 return False;
2242         }
2243
2244         p = *rdata;
2245
2246         become_root();
2247         search = pdb_search_users(ACB_NORMAL);
2248         unbecome_root();
2249         if (search == NULL) {
2250                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2251                 return False;
2252         }
2253
2254         become_root();
2255         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2256                                        &users);
2257         unbecome_root();
2258
2259         errflags=NERR_Success;
2260
2261         for (i=0; i<num_users; i++) {
2262                 const char *name = users[i].account_name;
2263                 
2264                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2265                         pstrcpy(p,name); 
2266                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2267                                   "%s\n",count_sent,p));
2268                         p += 21; 
2269                         count_sent++; 
2270                 } else {
2271                         /* set overflow error */
2272                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2273                                   "username %s\n",count_sent,name));
2274                         errflags=234;
2275                         break;
2276                 }
2277         }
2278
2279         pdb_search_destroy(search);
2280
2281         *rdata_len = PTR_DIFF(p,*rdata);
2282
2283         SSVAL(*rparam,0,errflags);
2284         SSVAL(*rparam,2,0);           /* converter word */
2285         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2286         SSVAL(*rparam,6,num_users); /* is this right?? */
2287
2288         return True;
2289 }
2290
2291 /****************************************************************************
2292  Get the time of day info.
2293 ****************************************************************************/
2294
2295 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2296                                 char *param, int tpscnt,
2297                                 char *data, int tdscnt,
2298                                 int mdrcnt,int mprcnt,
2299                                 char **rdata,char **rparam,
2300                                 int *rdata_len,int *rparam_len)
2301 {
2302         struct tm *t;
2303         time_t unixdate = time(NULL);
2304         char *p;
2305
2306         *rparam_len = 4;
2307         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2308         if (!*rparam) {
2309                 return False;
2310         }
2311
2312         *rdata_len = 21;
2313         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2314         if (!*rdata) {
2315                 return False;
2316         }
2317
2318         SSVAL(*rparam,0,NERR_Success);
2319         SSVAL(*rparam,2,0);             /* converter word */
2320
2321         p = *rdata;
2322
2323         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2324                                             by NT in a "net time" operation,
2325                                             it seems to ignore the one below */
2326
2327         /* the client expects to get localtime, not GMT, in this bit 
2328                 (I think, this needs testing) */
2329         t = localtime(&unixdate);
2330         if (!t) {
2331                 return False;
2332         }
2333
2334         SIVAL(p,4,0);           /* msecs ? */
2335         SCVAL(p,8,t->tm_hour);
2336         SCVAL(p,9,t->tm_min);
2337         SCVAL(p,10,t->tm_sec);
2338         SCVAL(p,11,0);          /* hundredths of seconds */
2339         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2340         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2341         SCVAL(p,16,t->tm_mday);
2342         SCVAL(p,17,t->tm_mon + 1);
2343         SSVAL(p,18,1900+t->tm_year);
2344         SCVAL(p,20,t->tm_wday);
2345
2346         return True;
2347 }
2348
2349 /****************************************************************************
2350  Set the user password.
2351 *****************************************************************************/
2352
2353 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2354                                 char *param, int tpscnt,
2355                                 char *data, int tdscnt,
2356                                 int mdrcnt,int mprcnt,
2357                                 char **rdata,char **rparam,
2358                                 int *rdata_len,int *rparam_len)
2359 {
2360         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2361         char *p = NULL;
2362         fstring user;
2363         fstring pass1,pass2;
2364
2365         /* Skip 2 strings. */
2366         p = skip_string(param,tpscnt,np);
2367         p = skip_string(param,tpscnt,p);
2368
2369         if (!np || !p) {
2370                 return False;
2371         }
2372
2373         /* Do we have a string ? */
2374         if (skip_string(param,tpscnt,p) == NULL) {
2375                 return False;
2376         }
2377         pull_ascii_fstring(user,p);
2378
2379         p = skip_string(param,tpscnt,p);
2380         if (!p) {
2381                 return False;
2382         }
2383
2384         memset(pass1,'\0',sizeof(pass1));
2385         memset(pass2,'\0',sizeof(pass2));
2386         /*
2387          * We use 31 here not 32 as we're checking
2388          * the last byte we want to access is safe.
2389          */
2390         if (!is_offset_safe(param,tpscnt,p,31)) {
2391                 return False;
2392         }
2393         memcpy(pass1,p,16);
2394         memcpy(pass2,p+16,16);
2395
2396         *rparam_len = 4;
2397         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2398         if (!*rparam) {
2399                 return False;
2400         }
2401
2402         *rdata_len = 0;
2403
2404         SSVAL(*rparam,0,NERR_badpass);
2405         SSVAL(*rparam,2,0);             /* converter word */
2406
2407         DEBUG(3,("Set password for <%s>\n",user));
2408
2409         /*
2410          * Attempt to verify the old password against smbpasswd entries
2411          * Win98 clients send old and new password in plaintext for this call.
2412          */
2413
2414         {
2415                 auth_serversupplied_info *server_info = NULL;
2416                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2417
2418                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2419
2420                         become_root();
2421                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2422                                 SSVAL(*rparam,0,NERR_Success);
2423                         }
2424                         unbecome_root();
2425
2426                         TALLOC_FREE(server_info);
2427                 }
2428                 data_blob_clear_free(&password);
2429         }
2430
2431         /*
2432          * If the plaintext change failed, attempt
2433          * the old encrypted method. NT will generate this
2434          * after trying the samr method. Note that this
2435          * method is done as a last resort as this
2436          * password change method loses the NT password hash
2437          * and cannot change the UNIX password as no plaintext
2438          * is received.
2439          */
2440
2441         if(SVAL(*rparam,0) != NERR_Success) {
2442                 struct samu *hnd = NULL;
2443
2444                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2445                         become_root();
2446                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2447                                 SSVAL(*rparam,0,NERR_Success);
2448                         }
2449                         unbecome_root();
2450                         TALLOC_FREE(hnd);
2451                 }
2452         }
2453
2454         memset((char *)pass1,'\0',sizeof(fstring));
2455         memset((char *)pass2,'\0',sizeof(fstring));      
2456          
2457         return(True);
2458 }
2459
2460 /****************************************************************************
2461   Set the user password (SamOEM version - gets plaintext).
2462 ****************************************************************************/
2463
2464 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2465                                 char *param, int tpscnt,
2466                                 char *data, int tdscnt,
2467                                 int mdrcnt,int mprcnt,
2468                                 char **rdata,char **rparam,
2469                                 int *rdata_len,int *rparam_len)
2470 {
2471         fstring user;
2472         char *p = get_safe_str_ptr(param,tpscnt,param,2);
2473         *rparam_len = 2;
2474         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2475         if (!*rparam) {
2476                 return False;
2477         }
2478
2479         if (!p) {
2480                 return False;
2481         }
2482         *rdata_len = 0;
2483
2484         SSVAL(*rparam,0,NERR_badpass);
2485
2486         /*
2487          * Check the parameter definition is correct.
2488          */
2489
2490         /* Do we have a string ? */
2491         if (skip_string(param,tpscnt,p) == 0) {
2492                 return False;
2493         }
2494         if(!strequal(p, "zsT")) {
2495                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2496                 return False;
2497         }
2498         p = skip_string(param, tpscnt, p);
2499         if (!p) {
2500                 return False;
2501         }
2502
2503         /* Do we have a string ? */
2504         if (skip_string(param,tpscnt,p) == 0) {
2505                 return False;
2506         }
2507         if(!strequal(p, "B516B16")) {
2508                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2509                 return False;
2510         }
2511         p = skip_string(param,tpscnt,p);
2512         if (!p) {
2513                 return False;
2514         }
2515         /* Do we have a string ? */
2516         if (skip_string(param,tpscnt,p) == 0) {
2517                 return False;
2518         }
2519         p += pull_ascii_fstring(user,p);
2520
2521         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2522
2523         /*
2524          * Pass the user through the NT -> unix user mapping
2525          * function.
2526          */
2527
2528         (void)map_username(user);
2529
2530         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2531                 SSVAL(*rparam,0,NERR_Success);
2532         }
2533
2534         return(True);
2535 }
2536
2537 /****************************************************************************
2538   delete a print job
2539   Form: <W> <> 
2540   ****************************************************************************/
2541
2542 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2543                                 char *param, int tpscnt,
2544                                 char *data, int tdscnt,
2545                                 int mdrcnt,int mprcnt,
2546                                 char **rdata,char **rparam,
2547                                 int *rdata_len,int *rparam_len)
2548 {
2549         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2550         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2551         char *str2 = skip_string(param,tpscnt,str1);
2552         char *p = skip_string(param,tpscnt,str2);
2553         uint32 jobid;
2554         int snum;
2555         fstring sharename;
2556         int errcode;
2557         WERROR werr = WERR_OK;
2558
2559         if (!str1 || !str2 || !p) {
2560                 return False;
2561         }
2562         /*
2563          * We use 1 here not 2 as we're checking
2564          * the last byte we want to access is safe.
2565          */
2566         if (!is_offset_safe(param,tpscnt,p,1)) {
2567                 return False;
2568         }
2569         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2570                 return False;
2571
2572         /* check it's a supported varient */
2573         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2574                 return(False);
2575
2576         *rparam_len = 4;
2577         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2578         if (!*rparam) {
2579                 return False;
2580         }
2581         *rdata_len = 0;
2582
2583         if (!print_job_exists(sharename, jobid)) {
2584                 errcode = NERR_JobNotFound;
2585                 goto out;
2586         }
2587
2588         snum = lp_servicenumber( sharename);
2589         if (snum == -1) {
2590                 errcode = NERR_DestNotFound;
2591                 goto out;
2592         }
2593
2594         errcode = NERR_notsupported;
2595         
2596         switch (function) {
2597         case 81:                /* delete */ 
2598                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2599                         errcode = NERR_Success;
2600                 break;
2601         case 82:                /* pause */
2602                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2603                         errcode = NERR_Success;
2604                 break;
2605         case 83:                /* resume */
2606                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2607                         errcode = NERR_Success;
2608                 break;
2609         }
2610
2611         if (!W_ERROR_IS_OK(werr))
2612                 errcode = W_ERROR_V(werr);
2613         
2614  out:
2615         SSVAL(*rparam,0,errcode);       
2616         SSVAL(*rparam,2,0);             /* converter word */
2617
2618         return(True);
2619 }
2620
2621 /****************************************************************************
2622   Purge a print queue - or pause or resume it.
2623   ****************************************************************************/
2624
2625 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2626                                 char *param, int tpscnt,
2627                                 char *data, int tdscnt,
2628                                 int mdrcnt,int mprcnt,
2629                                 char **rdata,char **rparam,
2630                                 int *rdata_len,int *rparam_len)
2631 {
2632         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2633         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2634         char *str2 = skip_string(param,tpscnt,str1);
2635         char *QueueName = skip_string(param,tpscnt,str2);
2636         int errcode = NERR_notsupported;
2637         int snum;
2638         WERROR werr = WERR_OK;
2639
2640         if (!str1 || !str2 || !QueueName) {
2641                 return False;
2642         }
2643
2644         /* check it's a supported varient */
2645         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2646                 return(False);
2647
2648         *rparam_len = 4;
2649         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2650         if (!*rparam) {
2651                 return False;
2652         }
2653         *rdata_len = 0;
2654
2655         if (skip_string(param,tpscnt,QueueName) == NULL) {
2656                 return False;
2657         }
2658         snum = print_queue_snum(QueueName);
2659
2660         if (snum == -1) {
2661                 errcode = NERR_JobNotFound;
2662                 goto out;
2663         }
2664
2665         switch (function) {
2666         case 74: /* Pause queue */
2667                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2668                 break;
2669         case 75: /* Resume queue */
2670                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2671                 break;
2672         case 103: /* Purge */
2673                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2674                 break;
2675         }
2676
2677         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2678
2679  out:
2680         SSVAL(*rparam,0,errcode);
2681         SSVAL(*rparam,2,0);             /* converter word */
2682
2683         return(True);
2684 }
2685
2686 /****************************************************************************
2687   set the property of a print job (undocumented?)
2688   ? function = 0xb -> set name of print job
2689   ? function = 0x6 -> move print job up/down
2690   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2691   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2692 ****************************************************************************/
2693
2694 static int check_printjob_info(struct pack_desc* desc,
2695                                int uLevel, char* id)
2696 {
2697         desc->subformat = NULL;
2698         switch( uLevel ) {
2699         case 0: desc->format = "W"; break;
2700         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2701         case 2: desc->format = "WWzWWDDzz"; break;
2702         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2703         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2704         default:
2705                 DEBUG(0,("check_printjob_info: invalid level %d\n",
2706                         uLevel ));
2707                 return False;
2708         }
2709         if (id == NULL || strcmp(desc->format,id) != 0) {
2710                 DEBUG(0,("check_printjob_info: invalid format %s\n",
2711                         id ? id : "<NULL>" ));
2712                 return False;
2713         }
2714         return True;
2715 }
2716
2717 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2718                                 char *param, int tpscnt,
2719                                 char *data, int tdscnt,
2720                                 int mdrcnt,int mprcnt,
2721                                 char **rdata,char **rparam,
2722                                 int *rdata_len,int *rparam_len)
2723 {
2724         struct pack_desc desc;
2725         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2726         char *str2 = skip_string(param,tpscnt,str1);
2727         char *p = skip_string(param,tpscnt,str2);
2728         uint32 jobid;
2729         fstring sharename;
2730         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2731         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2732         int place, errcode;
2733
2734         if (!str1 || !str2 || !p) {
2735                 return False;
2736         }
2737         /*
2738          * We use 1 here not 2 as we're checking
2739          * the last byte we want to access is safe.
2740          */
2741         if (!is_offset_safe(param,tpscnt,p,1)) {
2742                 return False;
2743         }
2744         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2745                 return False;
2746         *rparam_len = 4;
2747         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2748         if (!*rparam) {
2749                 return False;
2750         }
2751
2752         if (!share_defined(sharename)) {
2753                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2754                          sharename));
2755                 return False;
2756         }
2757   
2758         *rdata_len = 0;
2759         
2760         /* check it's a supported varient */
2761         if ((strcmp(str1,"WWsTP")) || 
2762             (!check_printjob_info(&desc,uLevel,str2)))
2763                 return(False);
2764
2765         if (!print_job_exists(sharename, jobid)) {
2766                 errcode=NERR_JobNotFound;
2767                 goto out;
2768         }
2769
2770         errcode = NERR_notsupported;
2771
2772         switch (function) {
2773         case 0x6:
2774                 /* change job place in the queue, 
2775                    data gives the new place */
2776                 place = SVAL(data,0);
2777                 if (print_job_set_place(sharename, jobid, place)) {
2778                         errcode=NERR_Success;
2779                 }
2780                 break;
2781
2782         case 0xb:   
2783                 /* change print job name, data gives the name */
2784                 if (print_job_set_name(sharename, jobid, data)) {
2785                         errcode=NERR_Success;
2786                 }
2787                 break;
2788
2789         default:
2790                 return False;
2791         }
2792
2793  out:
2794         SSVALS(*rparam,0,errcode);
2795         SSVAL(*rparam,2,0);             /* converter word */
2796         
2797         return(True);
2798 }
2799
2800
2801 /****************************************************************************
2802  Get info about the server.
2803 ****************************************************************************/
2804
2805 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2806                                 char *param, int tpscnt,
2807                                 char *data, int tdscnt,
2808                                 int mdrcnt,int mprcnt,
2809                                 char **rdata,char **rparam,
2810                                 int *rdata_len,int *rparam_len)
2811 {
2812         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2813         char *str2 = skip_string(param,tpscnt,str1);
2814         char *p = skip_string(param,tpscnt,str2);
2815         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2816         char *p2;
2817         int struct_len;
2818
2819         if (!str1 || !str2 || !p) {
2820                 return False;
2821         }
2822
2823         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2824
2825         /* check it's a supported varient */
2826         if (!prefix_ok(str1,"WrLh")) {
2827                 return False;
2828         }
2829
2830         switch( uLevel ) {
2831                 case 0:
2832                         if (strcmp(str2,"B16") != 0) {
2833                                 return False;
2834                         }
2835                         struct_len = 16;
2836                         break;
2837                 case 1:
2838                         if (strcmp(str2,"B16BBDz") != 0) {
2839                                 return False;
2840                         }
2841                         struct_len = 26;
2842                         break;
2843                 case 2:
2844                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2845                                 return False;
2846                         }
2847                         struct_len = 134;
2848                         break;
2849                 case 3:
2850                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2851                                 return False;
2852                         }
2853                         struct_len = 144;
2854                         break;
2855                 case 20:
2856                         if (strcmp(str2,"DN") != 0) {
2857                                 return False;
2858                         }
2859                         struct_len = 6;
2860                         break;
2861                 case 50:
2862                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2863                                 return False;
2864                         }
2865                         struct_len = 42;
2866                         break;
2867                 default:
2868                         return False;
2869         }
2870
2871         *rdata_len = mdrcnt;
2872         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2873         if (!*rdata) {
2874                 return False;
2875         }
2876
2877         p = *rdata;
2878         p2 = p + struct_len;
2879         if (uLevel != 20) {
2880                 srvstr_push(NULL, 0, p,global_myname(),16,
2881                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2882         }
2883         p += 16;
2884         if (uLevel > 0) {
2885                 struct srv_info_struct *servers=NULL;
2886                 int i,count;
2887                 pstring comment;
2888                 uint32 servertype= lp_default_server_announce();
2889
2890                 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2891
2892                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2893                         for (i=0;i<count;i++) {
2894                                 if (strequal(servers[i].name,global_myname())) {
2895                                         servertype = servers[i].type;
2896                                         push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2897                                 }
2898                         }
2899                 }
2900
2901                 SAFE_FREE(servers);
2902
2903                 SCVAL(p,0,lp_major_announce_version());
2904                 SCVAL(p,1,lp_minor_announce_version());
2905                 SIVAL(p,2,servertype);
2906
2907                 if (mdrcnt == struct_len) {
2908                         SIVAL(p,6,0);
2909                 } else {
2910                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2911                         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2912                                               conn->connectpath, conn->gid,
2913                                               get_current_username(),
2914                                               current_user_info.domain,
2915                                               comment, sizeof(comment));
2916                         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2917                         p2 = skip_string(*rdata,*rdata_len,p2);
2918                         if (!p2) {
2919                                 return False;
2920                         }
2921                 }
2922         }
2923
2924         if (uLevel > 1) {
2925                 return False;           /* not yet implemented */
2926         }
2927
2928         *rdata_len = PTR_DIFF(p2,*rdata);
2929
2930         *rparam_len = 6;
2931         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2932         if (!*rparam) {
2933                 return False;
2934         }
2935         SSVAL(*rparam,0,NERR_Success);
2936         SSVAL(*rparam,2,0);             /* converter word */
2937         SSVAL(*rparam,4,*rdata_len);
2938
2939         return True;
2940 }
2941
2942 /****************************************************************************
2943  Get info about the server.
2944 ****************************************************************************/
2945
2946 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2947                                 char *param, int tpscnt,
2948                                 char *data, int tdscnt,
2949                                 int mdrcnt,int mprcnt,
2950                                 char **rdata,char **rparam,
2951                                 int *rdata_len,int *rparam_len)
2952 {
2953         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2954         char *str2 = skip_string(param,tpscnt,str1);
2955         char *p = skip_string(param,tpscnt,str2);
2956         char *p2;
2957         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2958
2959         if (!str1 || !str2 || !p) {
2960                 return False;
2961         }
2962
2963         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2964
2965         *rparam_len = 6;
2966         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2967         if (!*rparam) {
2968                 return False;
2969         }
2970
2971         /* check it's a supported varient */
2972         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2973                 return False;
2974         }
2975
2976         *rdata_len = mdrcnt + 1024;
2977         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2978         if (!*rdata) {
2979                 return False;
2980         }
2981
2982         SSVAL(*rparam,0,NERR_Success);
2983         SSVAL(*rparam,2,0);             /* converter word */
2984
2985         p = *rdata;
2986         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2987         if (!p2) {
2988                 return False;
2989         }
2990
2991         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2992         pstrcpy(p2,get_local_machine_name());
2993         strupper_m(p2);
2994         p2 = skip_string(*rdata,*rdata_len,p2);
2995         if (!p2) {
2996                 return False;
2997         }
2998         p += 4;
2999
3000         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3001         pstrcpy(p2,current_user_info.smb_name);
3002         p2 = skip_string(*rdata,*rdata_len,p2);
3003         if (!p2) {
3004                 return False;
3005         }
3006         p += 4;
3007
3008         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3009         pstrcpy(p2,lp_workgroup());
3010         strupper_m(p2);
3011         p2 = skip_string(*rdata,*rdata_len,p2);
3012         if (!p2) {
3013                 return False;
3014         }
3015         p += 4;
3016
3017         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3018         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3019         p += 2;
3020
3021         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3022         pstrcpy(p2,lp_workgroup());     /* don't know.  login domain?? */
3023         p2 = skip_string(*rdata,*rdata_len,p2);
3024         if (!p2) {
3025                 return False;
3026         }
3027         p += 4;
3028
3029         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3030         pstrcpy(p2,"");
3031         p2 = skip_string(*rdata,*rdata_len,p2);
3032         if (!p2) {
3033                 return False;
3034         }
3035         p += 4;
3036
3037         *rdata_len = PTR_DIFF(p2,*rdata);
3038
3039         SSVAL(*rparam,4,*rdata_len);
3040
3041         return True;
3042 }
3043
3044 /****************************************************************************
3045   get info about a user
3046
3047     struct user_info_11 {
3048         char                usri11_name[21];  0-20 
3049         char                usri11_pad;       21 
3050         char                *usri11_comment;  22-25 
3051         char            *usri11_usr_comment;  26-29
3052         unsigned short      usri11_priv;      30-31
3053         unsigned long       usri11_auth_flags; 32-35
3054         long                usri11_password_age; 36-39
3055         char                *usri11_homedir; 40-43
3056         char            *usri11_parms; 44-47
3057         long                usri11_last_logon; 48-51
3058         long                usri11_last_logoff; 52-55
3059         unsigned short      usri11_bad_pw_count; 56-57
3060         unsigned short      usri11_num_logons; 58-59
3061         char                *usri11_logon_server; 60-63
3062         unsigned short      usri11_country_code; 64-65
3063         char            *usri11_workstations; 66-69
3064         unsigned long       usri11_max_storage; 70-73
3065         unsigned short      usri11_units_per_week; 74-75
3066         unsigned char       *usri11_logon_hours; 76-79
3067         unsigned short      usri11_code_page; 80-81
3068     };
3069
3070 where:
3071
3072   usri11_name specifies the user name for which information is retireved
3073
3074   usri11_pad aligns the next data structure element to a word boundary
3075
3076   usri11_comment is a null terminated ASCII comment
3077
3078   usri11_user_comment is a null terminated ASCII comment about the user
3079
3080   usri11_priv specifies the level of the privilege assigned to the user.
3081        The possible values are:
3082
3083 Name             Value  Description
3084 USER_PRIV_GUEST  0      Guest privilege
3085 USER_PRIV_USER   1      User privilege
3086 USER_PRV_ADMIN   2      Administrator privilege
3087
3088   usri11_auth_flags specifies the account operator privileges. The
3089        possible values are:
3090
3091 Name            Value   Description
3092 AF_OP_PRINT     0       Print operator
3093
3094
3095 Leach, Naik                                        [Page 28]
3096 \f
3097
3098
3099 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3100
3101
3102 AF_OP_COMM      1       Communications operator
3103 AF_OP_SERVER    2       Server operator
3104 AF_OP_ACCOUNTS  3       Accounts operator
3105
3106
3107   usri11_password_age specifies how many seconds have elapsed since the
3108        password was last changed.
3109
3110   usri11_home_dir points to a null terminated ASCII string that contains
3111        the path name of the user's home directory.
3112
3113   usri11_parms points to a null terminated ASCII string that is set
3114        aside for use by applications.
3115
3116   usri11_last_logon specifies the time when the user last logged on.
3117        This value is stored as the number of seconds elapsed since
3118        00:00:00, January 1, 1970.
3119
3120   usri11_last_logoff specifies the time when the user last logged off.
3121        This value is stored as the number of seconds elapsed since
3122        00:00:00, January 1, 1970. A value of 0 means the last logoff
3123        time is unknown.
3124
3125   usri11_bad_pw_count specifies the number of incorrect passwords
3126        entered since the last successful logon.
3127
3128   usri11_log1_num_logons specifies the number of times this user has
3129        logged on. A value of -1 means the number of logons is unknown.
3130
3131   usri11_logon_server points to a null terminated ASCII string that
3132        contains the name of the server to which logon requests are sent.
3133        A null string indicates logon requests should be sent to the
3134        domain controller.
3135
3136   usri11_country_code specifies the country code for the user's language
3137        of choice.
3138
3139   usri11_workstations points to a null terminated ASCII string that
3140        contains the names of workstations the user may log on from.
3141        There may be up to 8 workstations, with the names separated by
3142        commas. A null strings indicates there are no restrictions.
3143
3144   usri11_max_storage specifies the maximum amount of disk space the user
3145        can occupy. A value of 0xffffffff indicates there are no
3146        restrictions.
3147
3148   usri11_units_per_week specifies the equal number of time units into
3149        which a week is divided. This value must be equal to 168.
3150
3151   usri11_logon_hours points to a 21 byte (168 bits) string that
3152        specifies the time during which the user can log on. Each bit
3153        represents one unique hour in a week. The first bit (bit 0, word
3154        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3155
3156
3157
3158 Leach, Naik                                        [Page 29]
3159 \f
3160
3161
3162 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3163
3164
3165        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3166        are no restrictions.
3167
3168   usri11_code_page specifies the code page for the user's language of
3169        choice
3170
3171 All of the pointers in this data structure need to be treated
3172 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
3173 to be ignored. The converter word returned in the parameters section
3174 needs to be subtracted from the lower 16 bits to calculate an offset
3175 into the return buffer where this ASCII string resides.
3176
3177 There is no auxiliary data in the response.
3178
3179   ****************************************************************************/
3180
3181 #define usri11_name           0 
3182 #define usri11_pad            21
3183 #define usri11_comment        22
3184 #define usri11_usr_comment    26
3185 #define usri11_full_name      30
3186 #define usri11_priv           34
3187 #define usri11_auth_flags     36
3188 #define usri11_password_age   40
3189 #define usri11_homedir        44
3190 #define usri11_parms          48
3191 #define usri11_last_logon     52
3192 #define usri11_last_logoff    56
3193 #define usri11_bad_pw_count   60
3194 #define usri11_num_logons     62
3195 #define usri11_logon_server   64
3196 #define usri11_country_code   68
3197 #define usri11_workstations   70
3198 #define usri11_max_storage    74
3199 #define usri11_units_per_week 78
3200 #define usri11_logon_hours    80
3201 #define usri11_code_page      84
3202 #define usri11_end            86
3203
3204 #define USER_PRIV_GUEST 0
3205 #define USER_PRIV_USER 1
3206 #define USER_PRIV_ADMIN 2
3207
3208 #define AF_OP_PRINT     0 
3209 #define AF_OP_COMM      1
3210 #define AF_OP_SERVER    2
3211 #define AF_OP_ACCOUNTS  3
3212
3213
3214 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3215                                 char *param, int tpscnt,
3216                                 char *data, int tdscnt,
3217                                 int mdrcnt,int mprcnt,
3218                                 char **rdata,char **rparam,
3219                                 int *rdata_len,int *rparam_len)
3220 {
3221         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3222         char *str2 = skip_string(param,tpscnt,str1);
3223         char *UserName = skip_string(param,tpscnt,str2);
3224         char *p = skip_string(param,tpscnt,UserName);
3225         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3226         char *p2;
3227         const char *level_string;
3228
3229         /* get NIS home of a previously validated user - simeon */
3230         /* With share level security vuid will always be zero.
3231            Don't depend on vuser being non-null !!. JRA */
3232         user_struct *vuser = get_valid_user_struct(vuid);
3233         if(vuser != NULL) {
3234                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3235                         vuser->user.unix_name));
3236         }
3237
3238         if (!str1 || !str2 || !UserName || !p) {
3239                 return False;
3240         }
3241
3242         *rparam_len = 6;
3243         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3244         if (!*rparam) {
3245                 return False;
3246         }
3247
3248         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3249   
3250         /* check it's a supported variant */
3251         if (strcmp(str1,"zWrLh") != 0) {
3252                 return False;
3253         }
3254         switch( uLevel ) {
3255                 case 0: level_string = "B21"; break;
3256                 case 1: level_string = "B21BB16DWzzWz"; break;
3257                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3258                 case 10: level_string = "B21Bzzz"; break;
3259                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3260                 default: return False;
3261         }
3262
3263         if (strcmp(level_string,str2) != 0) {
3264                 return False;
3265         }
3266
3267         *rdata_len = mdrcnt + 1024;
3268         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3269         if (!*rdata) {
3270                 return False;
3271         }
3272
3273         SSVAL(*rparam,0,NERR_Success);
3274         SSVAL(*rparam,2,0);             /* converter word */
3275
3276         p = *rdata;
3277         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3278         if (!p2) {
3279                 return False;
3280         }
3281
3282         memset(p,0,21); 
3283         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3284
3285         if (uLevel > 0) {
3286                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3287                 *p2 = 0;
3288         }
3289
3290         if (uLevel >= 10) {
3291                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3292                 pstrcpy(p2,"Comment");
3293                 p2 = skip_string(*rdata,*rdata_len,p2);
3294                 if (!p2) {
3295                         return False;
3296                 }
3297
3298                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3299                 pstrcpy(p2,"UserComment");
3300                 p2 = skip_string(*rdata,*rdata_len,p2);
3301                 if (!p2) {
3302                         return False;
3303                 }
3304
3305                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3306                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3307                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3308                 p2 = skip_string(*rdata,*rdata_len,p2);
3309                 if (!p2) {
3310                         return False;
3311                 }
3312         }
3313
3314         if (uLevel == 11) {
3315                 /* modelled after NTAS 3.51 reply */
3316                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3317                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3318                 SIVALS(p,usri11_password_age,-1);               /* password age */
3319                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3320                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3321                 p2 = skip_string(*rdata,*rdata_len,p2);
3322                 if (!p2) {
3323                         return False;
3324                 }
3325                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3326                 pstrcpy(p2,"");
3327                 p2 = skip_string(*rdata,*rdata_len,p2);
3328                 if (!p2) {
3329                         return False;
3330                 }
3331                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3332                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3333                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3334                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3335                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3336                 pstrcpy(p2,"\\\\*");
3337                 p2 = skip_string(*rdata,*rdata_len,p2);
3338                 if (!p2) {
3339                         return False;
3340                 }
3341                 SSVAL(p,usri11_country_code,0);         /* country code */
3342
3343                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3344                 pstrcpy(p2,"");
3345                 p2 = skip_string(*rdata,*rdata_len,p2);
3346                 if (!p2) {
3347                         return False;
3348                 }
3349
3350                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3351                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3352                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3353
3354                 /* a simple way to get logon hours at all times. */
3355                 memset(p2,0xff,21);
3356                 SCVAL(p2,21,0);           /* fix zero termination */
3357                 p2 = skip_string(*rdata,*rdata_len,p2);
3358                 if (!p2) {
3359                         return False;
3360                 }
3361
3362                 SSVAL(p,usri11_code_page,0);            /* code page */
3363         }
3364
3365         if (uLevel == 1 || uLevel == 2) {
3366                 memset(p+22,' ',16);    /* password */
3367                 SIVALS(p,38,-1);                /* password age */
3368                 SSVAL(p,42,
3369                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3370                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3371                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3372                 p2 = skip_string(*rdata,*rdata_len,p2);
3373                 if (!p2) {
3374                         return False;
3375                 }
3376                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3377                 *p2++ = 0;
3378                 SSVAL(p,52,0);          /* flags */
3379                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3380                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3381                 p2 = skip_string(*rdata,*rdata_len,p2);
3382                 if (!p2) {
3383                         return False;
3384                 }
3385                 if (uLevel == 2) {
3386                         SIVAL(p,60,0);          /* auth_flags */
3387                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3388                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3389                         p2 = skip_string(*rdata,*rdata_len,p2);
3390                         if (!p2) {
3391                                 return False;
3392                         }
3393                         SIVAL(p,68,0);          /* urs_comment */
3394                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3395                         pstrcpy(p2,"");
3396                         p2 = skip_string(*rdata,*rdata_len,p2);
3397                         if (!p2) {
3398                                 return False;
3399                         }
3400                         SIVAL(p,76,0);          /* workstations */
3401                         SIVAL(p,80,0);          /* last_logon */
3402                         SIVAL(p,84,0);          /* last_logoff */
3403                         SIVALS(p,88,-1);                /* acct_expires */
3404                         SIVALS(p,92,-1);                /* max_storage */
3405                         SSVAL(p,96,168);        /* units_per_week */
3406                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3407                         memset(p2,-1,21);
3408                         p2 += 21;
3409                         SSVALS(p,102,-1);       /* bad_pw_count */
3410                         SSVALS(p,104,-1);       /* num_logons */
3411                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3412                         {
3413                                 pstring tmp;
3414                                 pstrcpy(tmp, "\\\\%L");
3415                                 standard_sub_basic("", "", tmp, sizeof(tmp));
3416                                 pstrcpy(p2, tmp);
3417                         }
3418                         p2 = skip_string(*rdata,*rdata_len,p2);
3419                         if (!p2) {
3420                                 return False;
3421                         }
3422                         SSVAL(p,110,49);        /* country_code */
3423                         SSVAL(p,112,860);       /* code page */
3424                 }
3425         }
3426
3427         *rdata_len = PTR_DIFF(p2,*rdata);
3428
3429         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3430
3431         return(True);
3432 }
3433
3434 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3435                                 char *param, int tpscnt,
3436                                 char *data, int tdscnt,
3437                                 int mdrcnt,int mprcnt,
3438                                 char **rdata,char **rparam,
3439                                 int *rdata_len,int *rparam_len)
3440 {
3441         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3442         char *str2 = skip_string(param,tpscnt,str1);
3443         char *p = skip_string(param,tpscnt,str2);
3444         int uLevel;
3445         struct pack_desc desc;
3446         char* name;
3447                 /* With share level security vuid will always be zero.
3448                    Don't depend on vuser being non-null !!. JRA */
3449         user_struct *vuser = get_valid_user_struct(vuid);
3450
3451         if (!str1 || !str2 || !p) {
3452                 return False;
3453         }
3454
3455         if(vuser != NULL) {
3456                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3457                         vuser->user.unix_name));
3458         }
3459
3460         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3461         name = get_safe_str_ptr(param,tpscnt,p,2);
3462         if (!name) {
3463                 return False;
3464         }
3465
3466         memset((char *)&desc,'\0',sizeof(desc));
3467
3468         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3469
3470         /* check it's a supported varient */
3471         if (strcmp(str1,"OOWb54WrLh") != 0) {
3472                 return False;
3473         }
3474         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3475                 return False;
3476         }
3477         if (mdrcnt > 0) {
3478                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3479                 if (!*rdata) {
3480                         return False;
3481                 }
3482         }
3483
3484         desc.base = *rdata;
3485         desc.buflen = mdrcnt;
3486         desc.subformat = NULL;
3487         desc.format = str2;
3488   
3489         if (init_package(&desc,1,0)) {
3490                 PACKI(&desc,"W",0);             /* code */
3491                 PACKS(&desc,"B21",name);        /* eff. name */
3492                 PACKS(&desc,"B","");            /* pad */
3493                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3494                 PACKI(&desc,"D",0);             /* auth flags XXX */
3495                 PACKI(&desc,"W",0);             /* num logons */
3496                 PACKI(&desc,"W",0);             /* bad pw count */
3497                 PACKI(&desc,"D",0);             /* last logon */
3498                 PACKI(&desc,"D",-1);            /* last logoff */
3499                 PACKI(&desc,"D",-1);            /* logoff time */
3500                 PACKI(&desc,"D",-1);            /* kickoff time */
3501                 PACKI(&desc,"D",0);             /* password age */
3502                 PACKI(&desc,"D",0);             /* password can change */
3503                 PACKI(&desc,"D",-1);            /* password must change */
3504
3505                 {
3506                         fstring mypath;
3507                         fstrcpy(mypath,"\\\\");
3508                         fstrcat(mypath,get_local_machine_name());
3509                         strupper_m(mypath);
3510                         PACKS(&desc,"z",mypath); /* computer */
3511                 }
3512
3513                 PACKS(&desc,"z",lp_workgroup());/* domain */
3514                 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3515                 PACKI(&desc,"D",0x00000000);            /* reserved */
3516         }
3517
3518         *rdata_len = desc.usedlen;
3519         *rparam_len = 6;
3520         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3521         if (!*rparam) {
3522                 return False;
3523         }
3524         SSVALS(*rparam,0,desc.errcode);
3525         SSVAL(*rparam,2,0);
3526         SSVAL(*rparam,4,desc.neededlen);
3527
3528         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3529
3530         return True;
3531 }
3532
3533 /****************************************************************************
3534  api_WAccessGetUserPerms
3535 ****************************************************************************/
3536
3537 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3538                                 char *param, int tpscnt,
3539                                 char *data, int tdscnt,
3540                                 int mdrcnt,int mprcnt,
3541                                 char **rdata,char **rparam,
3542                                 int *rdata_len,int *rparam_len)
3543 {
3544         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3545         char *str2 = skip_string(param,tpscnt,str1);
3546         char *user = skip_string(param,tpscnt,str2);
3547         char *resource = skip_string(param,tpscnt,user);
3548
3549         if (!str1 || !str2 || !user || !resource) {
3550                 return False;
3551         }
3552
3553         if (skip_string(param,tpscnt,resource) == NULL) {
3554                 return False;
3555         }
3556         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3557
3558         /* check it's a supported varient */
3559         if (strcmp(str1,"zzh") != 0) {
3560                 return False;
3561         }
3562         if (strcmp(str2,"") != 0) {
3563                 return False;
3564         }
3565
3566         *rparam_len = 6;
3567         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3568         if (!*rparam) {
3569                 return False;
3570         }
3571         SSVALS(*rparam,0,0);            /* errorcode */
3572         SSVAL(*rparam,2,0);             /* converter word */
3573         SSVAL(*rparam,4,0x7f);  /* permission flags */
3574
3575         return True;
3576 }
3577
3578 /****************************************************************************
3579   api_WPrintJobEnumerate
3580   ****************************************************************************/
3581
3582 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3583                                 char *param, int tpscnt,
3584                                 char *data, int tdscnt,
3585                                 int mdrcnt,int mprcnt,
3586                                 char **rdata,char **rparam,
3587                                 int *rdata_len,int *rparam_len)
3588 {
3589         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3590         char *str2 = skip_string(param,tpscnt,str1);
3591         char *p = skip_string(param,tpscnt,str2);
3592         int uLevel;
3593         int count;
3594         int i;
3595         int snum;
3596         fstring sharename;
3597         uint32 jobid;
3598         struct pack_desc desc;
3599         print_queue_struct *queue=NULL;
3600         print_status_struct status;
3601         char *tmpdata=NULL;
3602
3603         if (!str1 || !str2 || !p) {
3604                 return False;
3605         }
3606
3607         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3608
3609         memset((char *)&desc,'\0',sizeof(desc));
3610         memset((char *)&status,'\0',sizeof(status));
3611
3612         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3613
3614         /* check it's a supported varient */
3615         if (strcmp(str1,"WWrLh") != 0) {
3616                 return False;
3617         }
3618         if (!check_printjob_info(&desc,uLevel,str2)) {
3619                 return False;
3620         }
3621
3622         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3623                 return False;
3624         }
3625
3626         snum = lp_servicenumber( sharename);
3627         if (snum < 0 || !VALID_SNUM(snum)) {
3628                 return(False);
3629         }
3630
3631         count = print_queue_status(snum,&queue,&status);
3632         for (i = 0; i < count; i++) {
3633                 if (queue[i].job == jobid) {
3634                         break;
3635                 }
3636         }
3637
3638         if (mdrcnt > 0) {
3639                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3640                 if (!*rdata) {
3641                         return False;
3642                 }
3643                 desc.base = *rdata;
3644                 desc.buflen = mdrcnt;
3645         } else {
3646                 /*
3647                  * Don't return data but need to get correct length
3648                  *  init_package will return wrong size if buflen=0
3649                  */
3650                 desc.buflen = getlen(desc.format);
3651                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3652         }
3653
3654         if (init_package(&desc,1,0)) {
3655                 if (i < count) {
3656                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3657                         *rdata_len = desc.usedlen;
3658                 } else {
3659                         desc.errcode = NERR_JobNotFound;
3660                         *rdata_len = 0;
3661                 }
3662         }
3663
3664         *rparam_len = 6;
3665         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3666         if (!*rparam) {
3667                 return False;
3668         }
3669         SSVALS(*rparam,0,desc.errcode);
3670         SSVAL(*rparam,2,0);
3671         SSVAL(*rparam,4,desc.neededlen);
3672
3673         SAFE_FREE(queue);
3674         SAFE_FREE(tmpdata);
3675
3676         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3677
3678         return True;
3679 }
3680
3681 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3682                                 char *param, int tpscnt,
3683                                 char *data, int tdscnt,
3684                                 int mdrcnt,int mprcnt,
3685                                 char **rdata,char **rparam,
3686                                 int *rdata_len,int *rparam_len)
3687 {
3688         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3689         char *str2 = skip_string(param,tpscnt,str1);
3690         char *p = skip_string(param,tpscnt,str2);
3691         char *name = p;
3692         int uLevel;
3693         int count;
3694         int i, succnt=0;
3695         int snum;
3696         struct pack_desc desc;
3697         print_queue_struct *queue=NULL;
3698         print_status_struct status;
3699
3700         if (!str1 || !str2 || !p) {
3701                 return False;
3702         }
3703
3704         memset((char *)&desc,'\0',sizeof(desc));
3705         memset((char *)&status,'\0',sizeof(status));
3706
3707         p = skip_string(param,tpscnt,p);
3708         if (!p) {
3709                 return False;
3710         }
3711         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3712
3713         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3714
3715         /* check it's a supported variant */
3716         if (strcmp(str1,"zWrLeh") != 0) {
3717                 return False;
3718         }
3719     
3720         if (uLevel > 2) {
3721                 return False;   /* defined only for uLevel 0,1,2 */
3722         }
3723     
3724         if (!check_printjob_info(&desc,uLevel,str2)) { 
3725                 return False;
3726         }
3727
3728         snum = find_service(name);
3729         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3730                 return False;
3731         }
3732
3733         count = print_queue_status(snum,&queue,&status);
3734         if (mdrcnt > 0) {
3735                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3736                 if (!*rdata) {
3737                         return False;
3738                 }
3739         }
3740         desc.base = *rdata;
3741         desc.buflen = mdrcnt;
3742
3743         if (init_package(&desc,count,0)) {
3744                 succnt = 0;
3745                 for (i = 0; i < count; i++) {
3746                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3747                         if (desc.errcode == NERR_Success) {
3748                                 succnt = i+1;
3749                         }
3750                 }
3751         }
3752
3753         *rdata_len = desc.usedlen;
3754
3755         *rparam_len = 8;
3756         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3757         if (!*rparam) {
3758                 return False;
3759         }
3760         SSVALS(*rparam,0,desc.errcode);
3761         SSVAL(*rparam,2,0);
3762         SSVAL(*rparam,4,succnt);
3763         SSVAL(*rparam,6,count);
3764
3765         SAFE_FREE(queue);
3766
3767         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3768
3769         return True;
3770 }
3771
3772 static int check_printdest_info(struct pack_desc* desc,
3773                                 int uLevel, char* id)
3774 {
3775         desc->subformat = NULL;
3776         switch( uLevel ) {
3777                 case 0:
3778                         desc->format = "B9";
3779                         break;
3780                 case 1:
3781                         desc->format = "B9B21WWzW";
3782                         break;
3783                 case 2:
3784                         desc->format = "z";
3785                         break;
3786                 case 3:
3787                         desc->format = "zzzWWzzzWW";
3788                         break;
3789                 default:
3790                         DEBUG(0,("check_printdest_info: invalid level %d\n",
3791                                 uLevel));
3792                         return False;
3793         }
3794         if (id == NULL || strcmp(desc->format,id) != 0) {
3795                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
3796                         id ? id : "<NULL>" ));
3797                 return False;
3798         }
3799         return True;
3800 }
3801
3802 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3803                                 struct pack_desc* desc)
3804 {
3805         char buf[100];
3806
3807         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3808         buf[sizeof(buf)-1] = 0;
3809         strupper_m(buf);
3810
3811         if (uLevel <= 1) {
3812                 PACKS(desc,"B9",buf);   /* szName */
3813                 if (uLevel == 1) {
3814                         PACKS(desc,"B21","");   /* szUserName */
3815                         PACKI(desc,"W",0);              /* uJobId */
3816                         PACKI(desc,"W",0);              /* fsStatus */
3817                         PACKS(desc,"z","");     /* pszStatus */
3818                         PACKI(desc,"W",0);              /* time */
3819                 }
3820         }
3821
3822         if (uLevel == 2 || uLevel == 3) {
3823                 PACKS(desc,"z",buf);            /* pszPrinterName */
3824                 if (uLevel == 3) {
3825                         PACKS(desc,"z","");     /* pszUserName */
3826                         PACKS(desc,"z","");     /* pszLogAddr */
3827                         PACKI(desc,"W",0);              /* uJobId */
3828                         PACKI(desc,"W",0);              /* fsStatus */
3829                         PACKS(desc,"z","");     /* pszStatus */
3830                         PACKS(desc,"z","");     /* pszComment */
3831                         PACKS(desc,"z","NULL"); /* pszDrivers */
3832                         PACKI(desc,"W",0);              /* time */
3833                         PACKI(desc,"W",0);              /* pad1 */
3834                 }
3835         }
3836 }
3837
3838 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3839                                 char *param, int tpscnt,
3840                                 char *data, int tdscnt,
3841                                 int mdrcnt,int mprcnt,
3842                                 char **rdata,char **rparam,
3843                                 int *rdata_len,int *rparam_len)
3844 {
3845         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3846         char *str2 = skip_string(param,tpscnt,str1);
3847         char *p = skip_string(param,tpscnt,str2);
3848         char* PrinterName = p;
3849         int uLevel;
3850         struct pack_desc desc;
3851         int snum;
3852         char *tmpdata=NULL;
3853
3854         if (!str1 || !str2 || !p) {
3855                 return False;
3856         }
3857
3858         memset((char *)&desc,'\0',sizeof(desc));
3859
3860         p = skip_string(param,tpscnt,p);
3861         if (!p) {
3862                 return False;
3863         }
3864         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3865
3866         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3867
3868         /* check it's a supported varient */
3869         if (strcmp(str1,"zWrLh") != 0) {
3870                 return False;
3871         }
3872         if (!check_printdest_info(&desc,uLevel,str2)) {
3873                 return False;
3874         }
3875
3876         snum = find_service(PrinterName);
3877         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3878                 *rdata_len = 0;
3879                 desc.errcode = NERR_DestNotFound;
3880                 desc.neededlen = 0;
3881         } else {
3882                 if (mdrcnt > 0) {
3883                         *rdata = smb_realloc_limit(*rdata,mdrcnt);
3884                         if (!*rdata) {
3885                                 return False;
3886                         }
3887                         desc.base = *rdata;
3888                         desc.buflen = mdrcnt;
3889                 } else {
3890                         /*
3891                          * Don't return data but need to get correct length
3892                          * init_package will return wrong size if buflen=0
3893                          */
3894                         desc.buflen = getlen(desc.format);
3895                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3896                 }
3897                 if (init_package(&desc,1,0)) {
3898                         fill_printdest_info(conn,snum,uLevel,&desc);
3899                 }
3900                 *rdata_len = desc.usedlen;
3901         }
3902
3903         *rparam_len = 6;
3904         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3905         if (!*rparam) {
3906                 return False;
3907         }
3908         SSVALS(*rparam,0,desc.errcode);
3909         SSVAL(*rparam,2,0);
3910         SSVAL(*rparam,4,desc.neededlen);
3911
3912         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3913         SAFE_FREE(tmpdata);
3914
3915         return True;
3916 }
3917
3918 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3919                                 char *param, int tpscnt,
3920                                 char *data, int tdscnt,
3921                                 int mdrcnt,int mprcnt,
3922                                 char **rdata,char **rparam,
3923                                 int *rdata_len,int *rparam_len)
3924 {
3925         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3926         char *str2 = skip_string(param,tpscnt,str1);
3927         char *p = skip_string(param,tpscnt,str2);
3928         int uLevel;
3929         int queuecnt;
3930         int i, n, succnt=0;
3931         struct pack_desc desc;
3932         int services = lp_numservices();
3933
3934         if (!str1 || !str2 || !p) {
3935                 return False;
3936         }
3937
3938         memset((char *)&desc,'\0',sizeof(desc));
3939
3940         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3941
3942         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3943
3944         /* check it's a supported varient */
3945         if (strcmp(str1,"WrLeh") != 0) {
3946                 return False;
3947         }
3948         if (!check_printdest_info(&desc,uLevel,str2)) {
3949                 return False;
3950         }
3951
3952         queuecnt = 0;
3953         for (i = 0; i < services; i++) {
3954                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3955                         queuecnt++;
3956                 }
3957         }
3958
3959         if (mdrcnt > 0) {
3960                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3961                 if (!*rdata) {
3962                         return False;
3963                 }
3964         }
3965
3966         desc.base = *rdata;
3967         desc.buflen = mdrcnt;
3968         if (init_package(&desc,queuecnt,0)) {    
3969                 succnt = 0;
3970                 n = 0;
3971                 for (i = 0; i < services; i++) {
3972                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3973                                 fill_printdest_info(conn,i,uLevel,&desc);
3974                                 n++;
3975                                 if (desc.errcode == NERR_Success) {
3976                                         succnt = n;
3977                                 }
3978                         }
3979                 }
3980         }
3981
3982         *rdata_len = desc.usedlen;
3983
3984         *rparam_len = 8;
3985         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3986         if (!*rparam) {
3987                 return False;
3988         }
3989         SSVALS(*rparam,0,desc.errcode);
3990         SSVAL(*rparam,2,0);
3991         SSVAL(*rparam,4,succnt);
3992         SSVAL(*rparam,6,queuecnt);
3993
3994         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3995
3996         return True;
3997 }
3998
3999 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4000                                 char *param, int tpscnt,
4001                                 char *data, int tdscnt,
4002                                 int mdrcnt,int mprcnt,
4003                                 char **rdata,char **rparam,
4004                                 int *rdata_len,int *rparam_len)
4005 {
4006         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4007         char *str2 = skip_string(param,tpscnt,str1);
4008         char *p = skip_string(param,tpscnt,str2);
4009         int uLevel;
4010         int succnt;
4011         struct pack_desc desc;
4012
4013         if (!str1 || !str2 || !p) {
4014                 return False;
4015         }
4016
4017         memset((char *)&desc,'\0',sizeof(desc));
4018
4019         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4020
4021         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4022
4023         /* check it's a supported varient */
4024         if (strcmp(str1,"WrLeh") != 0) {
4025                 return False;
4026         }
4027         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4028                 return False;
4029         }
4030
4031         if (mdrcnt > 0) {
4032                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4033                 if (!*rdata) {
4034                         return False;
4035                 }
4036         }
4037         desc.base = *rdata;
4038         desc.buflen = mdrcnt;
4039         if (init_package(&desc,1,0)) {
4040                 PACKS(&desc,"B41","NULL");
4041         }
4042
4043         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4044
4045         *rdata_len = desc.usedlen;
4046
4047         *rparam_len = 8;
4048         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4049         if (!*rparam) {
4050                 return False;
4051         }
4052         SSVALS(*rparam,0,desc.errcode);
4053         SSVAL(*rparam,2,0);
4054         SSVAL(*rparam,4,succnt);
4055         SSVAL(*rparam,6,1);
4056
4057         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4058
4059         return True;
4060 }
4061
4062 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4063                                 char *param, int tpscnt,
4064                                 char *data, int tdscnt,
4065                                 int mdrcnt,int mprcnt,
4066                                 char **rdata,char **rparam,
4067                                 int *rdata_len,int *rparam_len)
4068 {
4069         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4070         char *str2 = skip_string(param,tpscnt,str1);
4071         char *p = skip_string(param,tpscnt,str2);
4072         int uLevel;
4073         int succnt;
4074         struct pack_desc desc;
4075
4076         if (!str1 || !str2 || !p) {
4077                 return False;
4078         }
4079         memset((char *)&desc,'\0',sizeof(desc));
4080
4081         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4082
4083         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4084
4085         /* check it's a supported varient */
4086         if (strcmp(str1,"WrLeh") != 0) {
4087                 return False;
4088         }
4089         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4090                 return False;
4091         }
4092
4093         if (mdrcnt > 0) {
4094                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4095                 if (!*rdata) {
4096                         return False;
4097                 }
4098         }
4099         desc.base = *rdata;
4100         desc.buflen = mdrcnt;
4101         desc.format = str2;
4102         if (init_package(&desc,1,0)) {
4103                 PACKS(&desc,"B13","lpd");
4104         }
4105
4106         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4107
4108         *rdata_len = desc.usedlen;
4109
4110         *rparam_len = 8;
4111         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4112         if (!*rparam) {
4113                 return False;
4114         }
4115         SSVALS(*rparam,0,desc.errcode);
4116         SSVAL(*rparam,2,0);
4117         SSVAL(*rparam,4,succnt);
4118         SSVAL(*rparam,6,1);
4119
4120         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4121
4122         return True;
4123 }
4124
4125 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4126                                 char *param, int tpscnt,
4127                                 char *data, int tdscnt,
4128                                 int mdrcnt,int mprcnt,
4129                                 char **rdata,char **rparam,
4130                                 int *rdata_len,int *rparam_len)
4131 {
4132         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4133         char *str2 = skip_string(param,tpscnt,str1);
4134         char *p = skip_string(param,tpscnt,str2);
4135         int uLevel;
4136         int succnt;
4137         struct pack_desc desc;
4138
4139         if (!str1 || !str2 || !p) {
4140                 return False;
4141         }
4142
4143         memset((char *)&desc,'\0',sizeof(desc));
4144
4145         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4146
4147         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4148
4149         /* check it's a supported varient */
4150         if (strcmp(str1,"WrLeh") != 0) {
4151                 return False;
4152         }
4153         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4154                 return False;
4155         }
4156
4157         if (mdrcnt > 0) {
4158                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4159                 if (!*rdata) {
4160                         return False;
4161                 }
4162         }
4163         memset((char *)&desc,'\0',sizeof(desc));
4164         desc.base = *rdata;
4165         desc.buflen = mdrcnt;
4166         desc.format = str2;
4167         if (init_package(&desc,1,0)) {
4168                 PACKS(&desc,"B13","lp0");
4169         }
4170
4171         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4172
4173         *rdata_len = desc.usedlen;
4174
4175         *rparam_len = 8;
4176         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4177         if (!*rparam) {
4178                 return False;
4179         }
4180         SSVALS(*rparam,0,desc.errcode);
4181         SSVAL(*rparam,2,0);
4182         SSVAL(*rparam,4,succnt);
4183         SSVAL(*rparam,6,1);
4184
4185         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4186
4187         return True;
4188 }
4189
4190 /****************************************************************************
4191  List open sessions
4192  ****************************************************************************/
4193
4194 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4195                                 char *param, int tpscnt,
4196                                 char *data, int tdscnt,
4197                                 int mdrcnt,int mprcnt,
4198                                 char **rdata,char **rparam,
4199                                 int *rdata_len,int *rparam_len)
4200
4201 {
4202         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4203         char *str2 = skip_string(param,tpscnt,str1);
4204         char *p = skip_string(param,tpscnt,str2);
4205         int uLevel;
4206         struct pack_desc desc;
4207         struct sessionid *session_list;
4208         int i, num_sessions;
4209
4210         if (!str1 || !str2 || !p) {
4211                 return False;
4212         }
4213
4214         memset((char *)&desc,'\0',sizeof(desc));
4215
4216         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4217
4218         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4219         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4220         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4221
4222         /* check it's a supported varient */
4223         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4224                 return False;
4225         }
4226         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4227                 return False;
4228         }
4229
4230         num_sessions = list_sessions(talloc_tos(), &session_list);
4231
4232         if (mdrcnt > 0) {
4233                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4234                 if (!*rdata) {
4235                         return False;
4236                 }
4237         }
4238         memset((char *)&desc,'\0',sizeof(desc));
4239         desc.base = *rdata;
4240         desc.buflen = mdrcnt;
4241         desc.format = str2;
4242         if (!init_package(&desc,num_sessions,0)) {
4243                 return False;
4244         }
4245
4246         for(i=0; i<num_sessions; i++) {
4247                 PACKS(&desc, "z", session_list[i].remote_machine);
4248                 PACKS(&desc, "z", session_list[i].username);
4249                 PACKI(&desc, "W", 1); /* num conns */
4250                 PACKI(&desc, "W", 0); /* num opens */
4251                 PACKI(&desc, "W", 1); /* num users */
4252                 PACKI(&desc, "D", 0); /* session time */
4253                 PACKI(&desc, "D", 0); /* idle time */
4254                 PACKI(&desc, "D", 0); /* flags */
4255                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4256         }
4257
4258         *rdata_len = desc.usedlen;
4259
4260         *rparam_len = 8;
4261         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4262         if (!*rparam) {
4263                 return False;
4264         }
4265         SSVALS(*rparam,0,desc.errcode);
4266         SSVAL(*rparam,2,0); /* converter */
4267         SSVAL(*rparam,4,num_sessions); /* count */
4268
4269         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4270
4271         return True;
4272 }
4273
4274
4275 /****************************************************************************
4276  The buffer was too small.
4277  ****************************************************************************/
4278
4279 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4280                          int mdrcnt, int mprcnt,
4281                          char **rdata, char **rparam,
4282                          int *rdata_len, int *rparam_len)
4283 {
4284         *rparam_len = MIN(*rparam_len,mprcnt);
4285         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4286         if (!*rparam) {
4287                 return False;
4288         }
4289
4290         *rdata_len = 0;
4291
4292         SSVAL(*rparam,0,NERR_BufTooSmall);
4293
4294         DEBUG(3,("Supplied buffer too small in API command\n"));
4295
4296         return True;
4297 }
4298
4299 /****************************************************************************
4300  The request is not supported.
4301  ****************************************************************************/
4302
4303 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4304                                 char *param, int tpscnt,
4305                                 char *data, int tdscnt,
4306                                 int mdrcnt, int mprcnt,
4307                                 char **rdata, char **rparam,
4308                                 int *rdata_len, int *rparam_len)
4309 {
4310         *rparam_len = 4;
4311         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4312         if (!*rparam) {
4313                 return False;
4314         }
4315
4316         *rdata_len = 0;
4317
4318         SSVAL(*rparam,0,NERR_notsupported);
4319         SSVAL(*rparam,2,0);             /* converter word */
4320
4321         DEBUG(3,("Unsupported API command\n"));
4322
4323         return True;
4324 }
4325
4326 static const struct {
4327         const char *name;
4328         int id;
4329         bool (*fn)(connection_struct *, uint16,
4330                         char *, int,
4331                         char *, int,
4332                         int,int,char **,char **,int *,int *);
4333         bool auth_user;         /* Deny anonymous access? */
4334 } api_commands[] = {
4335         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
4336         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
4337         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
4338         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
4339         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
4340         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
4341         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
4342         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
4343         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
4344         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
4345         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
4346         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
4347         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
4348         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
4349         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4350         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4351         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4352         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4353         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4354         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4355         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4356         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4357         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4358         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4359         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4360         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4361         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4362         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4363         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4364         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4365         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4366         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4367         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4368         {NULL,          -1,     api_Unsupported}
4369         /*  The following RAP calls are not implemented by Samba:
4370
4371         RAP_WFileEnum2 - anon not OK 
4372         */
4373 };
4374
4375
4376 /****************************************************************************
4377  Handle remote api calls.
4378 ****************************************************************************/
4379
4380 void api_reply(connection_struct *conn, uint16 vuid,
4381                struct smb_request *req,
4382                char *data, char *params,
4383                int tdscnt, int tpscnt,
4384                int mdrcnt, int mprcnt)
4385 {
4386         int api_command;
4387         char *rdata = NULL;
4388         char *rparam = NULL;
4389         const char *name1 = NULL;
4390         const char *name2 = NULL;
4391         int rdata_len = 0;
4392         int rparam_len = 0;
4393         bool reply=False;
4394         int i;
4395
4396         if (!params) {
4397                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4398                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4399                 return;
4400         }
4401
4402         if (tpscnt < 2) {
4403                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4404                 return;
4405         }
4406         api_command = SVAL(params,0);
4407         /* Is there a string at position params+2 ? */
4408         if (skip_string(params,tpscnt,params+2)) {
4409                 name1 = params + 2;
4410         } else {
4411                 name1 = "";
4412         }
4413         name2 = skip_string(params,tpscnt,params+2);
4414         if (!name2) {
4415                 name2 = "";
4416         }
4417
4418         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4419                 api_command,
4420                 name1,
4421                 name2,
4422                 tdscnt,tpscnt,mdrcnt,mprcnt));
4423
4424         for (i=0;api_commands[i].name;i++) {
4425                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4426                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4427                         break;
4428                 }
4429         }
4430
4431         /* Check whether this api call can be done anonymously */
4432
4433         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4434                 user_struct *user = get_valid_user_struct(vuid);
4435
4436                 if (!user || user->guest) {
4437                         reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4438                         return;
4439                 }
4440         }
4441
4442         rdata = (char *)SMB_MALLOC(1024);
4443         if (rdata) {
4444                 memset(rdata,'\0',1024);
4445         }
4446
4447         rparam = (char *)SMB_MALLOC(1024);
4448         if (rparam) {
4449                 memset(rparam,'\0',1024);
4450         }
4451
4452         if(!rdata || !rparam) {
4453                 DEBUG(0,("api_reply: malloc fail !\n"));
4454                 SAFE_FREE(rdata);
4455                 SAFE_FREE(rparam);
4456                 reply_nterror(req, NT_STATUS_NO_MEMORY);
4457                 return;
4458         }
4459
4460         reply = api_commands[i].fn(conn,
4461                                 vuid,
4462                                 params,tpscnt,  /* params + length */
4463                                 data,tdscnt,    /* data + length */
4464                                 mdrcnt,mprcnt,
4465                                 &rdata,&rparam,&rdata_len,&rparam_len);
4466
4467
4468         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4469                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4470                                         &rdata,&rparam,&rdata_len,&rparam_len);
4471         }
4472
4473         /* if we get False back then it's actually unsupported */
4474         if (!reply) {
4475                 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4476                         &rdata,&rparam,&rdata_len,&rparam_len);
4477         }
4478
4479         /* If api_Unsupported returns false we can't return anything. */
4480         if (reply) {
4481                 send_trans_reply(req, rparam, rparam_len,
4482                                  rdata, rdata_len, False);
4483         }
4484
4485         SAFE_FREE(rdata);
4486         SAFE_FREE(rparam);
4487         return;
4488 }