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