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