r22391: Looks bigger than it is. Make "inbuf" available
[samba.git] / source3 / smbd / lanman.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Inter-process communication and named pipe handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 2007.
6
7    SMB Version handling
8    Copyright (C) John H Terpstra 1995-1998
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 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(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1898                 }
1899         } else {
1900                 return False;
1901         }
1902
1903         *rparam_len = 6;
1904         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1905         if (!*rparam) {
1906                 return False;
1907         }
1908         SSVAL(*rparam,0,NERR_Success);
1909         SSVAL(*rparam,2,0);             /* converter word */
1910         SSVAL(*rparam,4,*rdata_len);
1911         *rdata_len = 0;
1912   
1913         return True;
1914
1915   error_exit:
1916
1917         *rparam_len = 4;
1918         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1919         if (!*rparam) {
1920                 return False;
1921         }
1922         *rdata_len = 0;
1923         SSVAL(*rparam,0,res);
1924         SSVAL(*rparam,2,0);
1925         return True;
1926 }
1927
1928 /****************************************************************************
1929   view list of groups available
1930   ****************************************************************************/
1931
1932 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1933                                 char *param, int tpscnt,
1934                                 char *data, int tdscnt,
1935                                 int mdrcnt,int mprcnt,
1936                                 char **rdata,char **rparam,
1937                                 int *rdata_len,int *rparam_len)
1938 {
1939         int i;
1940         int errflags=0;
1941         int resume_context, cli_buf_size;
1942         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1943         char *str2 = skip_string(param,tpscnt,str1);
1944         char *p = skip_string(param,tpscnt,str2);
1945
1946         struct pdb_search *search;
1947         struct samr_displayentry *entries;
1948
1949         int num_entries;
1950  
1951         if (!str1 || !str2 || !p) {
1952                 return False;
1953         }
1954
1955         if (strcmp(str1,"WrLeh") != 0) {
1956                 return False;
1957         }
1958
1959         /* parameters  
1960          * W-> resume context (number of users to skip)
1961          * r -> return parameter pointer to receive buffer 
1962          * L -> length of receive buffer
1963          * e -> return parameter number of entries
1964          * h -> return parameter total number of users
1965          */
1966
1967         if (strcmp("B21",str2) != 0) {
1968                 return False;
1969         }
1970
1971         /* get list of domain groups SID_DOMAIN_GRP=2 */
1972         become_root();
1973         search = pdb_search_groups();
1974         unbecome_root();
1975
1976         if (search == NULL) {
1977                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1978                 return False;
1979         }
1980
1981         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1982         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1983         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1984                   "%d\n", resume_context, cli_buf_size));
1985
1986         become_root();
1987         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1988                                          &entries);
1989         unbecome_root();
1990
1991         *rdata_len = cli_buf_size;
1992         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1993         if (!*rdata) {
1994                 return False;
1995         }
1996
1997         p = *rdata;
1998
1999         for(i=0; i<num_entries; i++) {
2000                 fstring name;
2001                 fstrcpy(name, entries[i].account_name);
2002                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2003                         /* truncate the name at 21 chars. */
2004                         memcpy(p, name, 21); 
2005                         DEBUG(10,("adding entry %d group %s\n", i, p));
2006                         p += 21;
2007                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
2008                                    No idea why... */
2009                 } else {
2010                         /* set overflow error */
2011                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
2012                         errflags=234;
2013                         break;
2014                 }
2015         }
2016
2017         pdb_search_destroy(search);
2018
2019         *rdata_len = PTR_DIFF(p,*rdata);
2020
2021         *rparam_len = 8;
2022         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2023         if (!*rparam) {
2024                 return False;
2025         }
2026         SSVAL(*rparam, 0, errflags);
2027         SSVAL(*rparam, 2, 0);           /* converter word */
2028         SSVAL(*rparam, 4, i);   /* is this right?? */
2029         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
2030
2031         return(True);
2032 }
2033
2034 /*******************************************************************
2035  Get groups that a user is a member of.
2036 ******************************************************************/
2037
2038 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2039                                 char *param, int tpscnt,
2040                                 char *data, int tdscnt,
2041                                 int mdrcnt,int mprcnt,
2042                                 char **rdata,char **rparam,
2043                                 int *rdata_len,int *rparam_len)
2044 {
2045         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2046         char *str2 = skip_string(param,tpscnt,str1);
2047         char *UserName = skip_string(param,tpscnt,str2);
2048         char *p = skip_string(param,tpscnt,UserName);
2049         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2050         const char *level_string;
2051         int count=0;
2052         struct samu *sampw = NULL;
2053         BOOL ret = False;
2054         DOM_SID *sids;
2055         gid_t *gids;
2056         size_t num_groups;
2057         size_t i;
2058         NTSTATUS result;
2059         DOM_SID user_sid;
2060         enum lsa_SidType type;
2061         TALLOC_CTX *mem_ctx;
2062
2063         if (!str1 || !str2 || !UserName || !p) {
2064                 return False;
2065         }
2066
2067         *rparam_len = 8;
2068         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2069         if (!*rparam) {
2070                 return False;
2071         }
2072   
2073         /* check it's a supported varient */
2074         
2075         if ( strcmp(str1,"zWrLeh") != 0 )
2076                 return False;
2077                 
2078         switch( uLevel ) {
2079                 case 0:
2080                         level_string = "B21";
2081                         break;
2082                 default:
2083                         return False;
2084         }
2085
2086         if (strcmp(level_string,str2) != 0)
2087                 return False;
2088
2089         *rdata_len = mdrcnt + 1024;
2090         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2091         if (!*rdata) {
2092                 return False;
2093         }
2094         SSVAL(*rparam,0,NERR_Success);
2095         SSVAL(*rparam,2,0);             /* converter word */
2096
2097         p = *rdata;
2098
2099         mem_ctx = talloc_new(NULL);
2100         if (mem_ctx == NULL) {
2101                 DEBUG(0, ("talloc_new failed\n"));
2102                 return False;
2103         }
2104
2105         if ( !(sampw = samu_new(mem_ctx)) ) {
2106                 DEBUG(0, ("samu_new() failed!\n"));
2107                 TALLOC_FREE(mem_ctx);
2108                 return False;
2109         }
2110
2111         /* Lookup the user information; This should only be one of 
2112            our accounts (not remote domains) */
2113
2114         become_root();                                  /* ROOT BLOCK */
2115
2116         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2117                          NULL, NULL, &user_sid, &type)) {
2118                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2119                 goto done;
2120         }
2121
2122         if (type != SID_NAME_USER) {
2123                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2124                            sid_type_lookup(type)));
2125                 goto done;
2126         }
2127
2128         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2129                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2130                            sid_string_static(&user_sid), UserName));
2131                 goto done;
2132         }
2133
2134         gids = NULL;
2135         sids = NULL;
2136         num_groups = 0;
2137
2138         result = pdb_enum_group_memberships(mem_ctx, sampw,
2139                                             &sids, &gids, &num_groups);
2140
2141         if (!NT_STATUS_IS_OK(result)) {
2142                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2143                            UserName));
2144                 goto done;
2145         }
2146
2147         for (i=0; i<num_groups; i++) {
2148
2149                 const char *grp_name;
2150         
2151                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2152                         pstrcpy(p, grp_name);
2153                         p += 21; 
2154                         count++;
2155                 }
2156         }
2157
2158         *rdata_len = PTR_DIFF(p,*rdata);
2159
2160         SSVAL(*rparam,4,count); /* is this right?? */
2161         SSVAL(*rparam,6,count); /* is this right?? */
2162
2163         ret = True;
2164
2165 done:
2166         unbecome_root();                                /* END ROOT BLOCK */
2167
2168         TALLOC_FREE(mem_ctx);
2169
2170         return ret;
2171 }
2172
2173 /*******************************************************************
2174  Get all users.
2175 ******************************************************************/
2176
2177 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2178                                 char *param, int tpscnt,
2179                                 char *data, int tdscnt,
2180                                 int mdrcnt,int mprcnt,
2181                                 char **rdata,char **rparam,
2182                                 int *rdata_len,int *rparam_len)
2183 {
2184         int count_sent=0;
2185         int num_users=0;
2186         int errflags=0;
2187         int i, resume_context, cli_buf_size;
2188         struct pdb_search *search;
2189         struct samr_displayentry *users;
2190
2191         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2192         char *str2 = skip_string(param,tpscnt,str1);
2193         char *p = skip_string(param,tpscnt,str2);
2194
2195         if (!str1 || !str2 || !p) {
2196                 return False;
2197         }
2198
2199         if (strcmp(str1,"WrLeh") != 0)
2200                 return False;
2201         /* parameters
2202           * W-> resume context (number of users to skip)
2203           * r -> return parameter pointer to receive buffer
2204           * L -> length of receive buffer
2205           * e -> return parameter number of entries
2206           * h -> return parameter total number of users
2207           */
2208   
2209         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2210         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2211         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2212                         resume_context, cli_buf_size));
2213
2214         *rparam_len = 8;
2215         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2216         if (!*rparam) {
2217                 return False;
2218         }
2219
2220         /* check it's a supported varient */
2221         if (strcmp("B21",str2) != 0)
2222                 return False;
2223
2224         *rdata_len = cli_buf_size;
2225         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2226         if (!*rdata) {
2227                 return False;
2228         }
2229
2230         p = *rdata;
2231
2232         become_root();
2233         search = pdb_search_users(ACB_NORMAL);
2234         unbecome_root();
2235         if (search == NULL) {
2236                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2237                 return False;
2238         }
2239
2240         become_root();
2241         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2242                                        &users);
2243         unbecome_root();
2244
2245         errflags=NERR_Success;
2246
2247         for (i=0; i<num_users; i++) {
2248                 const char *name = users[i].account_name;
2249                 
2250                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2251                         pstrcpy(p,name); 
2252                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2253                                   "%s\n",count_sent,p));
2254                         p += 21; 
2255                         count_sent++; 
2256                 } else {
2257                         /* set overflow error */
2258                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2259                                   "username %s\n",count_sent,name));
2260                         errflags=234;
2261                         break;
2262                 }
2263         }
2264
2265         pdb_search_destroy(search);
2266
2267         *rdata_len = PTR_DIFF(p,*rdata);
2268
2269         SSVAL(*rparam,0,errflags);
2270         SSVAL(*rparam,2,0);           /* converter word */
2271         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2272         SSVAL(*rparam,6,num_users); /* is this right?? */
2273
2274         return True;
2275 }
2276
2277 /****************************************************************************
2278  Get the time of day info.
2279 ****************************************************************************/
2280
2281 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2282                                 char *param, int tpscnt,
2283                                 char *data, int tdscnt,
2284                                 int mdrcnt,int mprcnt,
2285                                 char **rdata,char **rparam,
2286                                 int *rdata_len,int *rparam_len)
2287 {
2288         struct tm *t;
2289         time_t unixdate = time(NULL);
2290         char *p;
2291
2292         *rparam_len = 4;
2293         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2294         if (!*rparam) {
2295                 return False;
2296         }
2297
2298         *rdata_len = 21;
2299         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2300         if (!*rdata) {
2301                 return False;
2302         }
2303
2304         SSVAL(*rparam,0,NERR_Success);
2305         SSVAL(*rparam,2,0);             /* converter word */
2306
2307         p = *rdata;
2308
2309         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2310                                             by NT in a "net time" operation,
2311                                             it seems to ignore the one below */
2312
2313         /* the client expects to get localtime, not GMT, in this bit 
2314                 (I think, this needs testing) */
2315         t = localtime(&unixdate);
2316         if (!t) {
2317                 return False;
2318         }
2319
2320         SIVAL(p,4,0);           /* msecs ? */
2321         SCVAL(p,8,t->tm_hour);
2322         SCVAL(p,9,t->tm_min);
2323         SCVAL(p,10,t->tm_sec);
2324         SCVAL(p,11,0);          /* hundredths of seconds */
2325         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2326         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2327         SCVAL(p,16,t->tm_mday);
2328         SCVAL(p,17,t->tm_mon + 1);
2329         SSVAL(p,18,1900+t->tm_year);
2330         SCVAL(p,20,t->tm_wday);
2331
2332         return True;
2333 }
2334
2335 /****************************************************************************
2336  Set the user password.
2337 *****************************************************************************/
2338
2339 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2340                                 char *param, int tpscnt,
2341                                 char *data, int tdscnt,
2342                                 int mdrcnt,int mprcnt,
2343                                 char **rdata,char **rparam,
2344                                 int *rdata_len,int *rparam_len)
2345 {
2346         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2347         char *p = NULL;
2348         fstring user;
2349         fstring pass1,pass2;
2350
2351         /* Skip 2 strings. */
2352         p = skip_string(param,tpscnt,np);
2353         p = skip_string(param,tpscnt,p);
2354
2355         if (!np || !p) {
2356                 return False;
2357         }
2358
2359         /* Do we have a string ? */
2360         if (skip_string(param,tpscnt,p) == NULL) {
2361                 return False;
2362         }
2363         pull_ascii_fstring(user,p);
2364
2365         p = skip_string(param,tpscnt,p);
2366         if (!p) {
2367                 return False;
2368         }
2369
2370         memset(pass1,'\0',sizeof(pass1));
2371         memset(pass2,'\0',sizeof(pass2));
2372         /*
2373          * We use 31 here not 32 as we're checking
2374          * the last byte we want to access is safe.
2375          */
2376         if (!is_offset_safe(param,tpscnt,p,31)) {
2377                 return False;
2378         }
2379         memcpy(pass1,p,16);
2380         memcpy(pass2,p+16,16);
2381
2382         *rparam_len = 4;
2383         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2384         if (!*rparam) {
2385                 return False;
2386         }
2387
2388         *rdata_len = 0;
2389
2390         SSVAL(*rparam,0,NERR_badpass);
2391         SSVAL(*rparam,2,0);             /* converter word */
2392
2393         DEBUG(3,("Set password for <%s>\n",user));
2394
2395         /*
2396          * Attempt to verify the old password against smbpasswd entries
2397          * Win98 clients send old and new password in plaintext for this call.
2398          */
2399
2400         {
2401                 auth_serversupplied_info *server_info = NULL;
2402                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2403
2404                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2405
2406                         become_root();
2407                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2408                                 SSVAL(*rparam,0,NERR_Success);
2409                         }
2410                         unbecome_root();
2411
2412                         TALLOC_FREE(server_info);
2413                 }
2414                 data_blob_clear_free(&password);
2415         }
2416
2417         /*
2418          * If the plaintext change failed, attempt
2419          * the old encrypted method. NT will generate this
2420          * after trying the samr method. Note that this
2421          * method is done as a last resort as this
2422          * password change method loses the NT password hash
2423          * and cannot change the UNIX password as no plaintext
2424          * is received.
2425          */
2426
2427         if(SVAL(*rparam,0) != NERR_Success) {
2428                 struct samu *hnd = NULL;
2429
2430                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2431                         become_root();
2432                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2433                                 SSVAL(*rparam,0,NERR_Success);
2434                         }
2435                         unbecome_root();
2436                         TALLOC_FREE(hnd);
2437                 }
2438         }
2439
2440         memset((char *)pass1,'\0',sizeof(fstring));
2441         memset((char *)pass2,'\0',sizeof(fstring));      
2442          
2443         return(True);
2444 }
2445
2446 /****************************************************************************
2447   Set the user password (SamOEM version - gets plaintext).
2448 ****************************************************************************/
2449
2450 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2451                                 char *param, int tpscnt,
2452                                 char *data, int tdscnt,
2453                                 int mdrcnt,int mprcnt,
2454                                 char **rdata,char **rparam,
2455                                 int *rdata_len,int *rparam_len)
2456 {
2457         fstring user;
2458         char *p = get_safe_str_ptr(param,tpscnt,param,2);
2459         *rparam_len = 2;
2460         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2461         if (!*rparam) {
2462                 return False;
2463         }
2464
2465         if (!p) {
2466                 return False;
2467         }
2468         *rdata_len = 0;
2469
2470         SSVAL(*rparam,0,NERR_badpass);
2471
2472         /*
2473          * Check the parameter definition is correct.
2474          */
2475
2476         /* Do we have a string ? */
2477         if (skip_string(param,tpscnt,p) == 0) {
2478                 return False;
2479         }
2480         if(!strequal(p, "zsT")) {
2481                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2482                 return False;
2483         }
2484         p = skip_string(param, tpscnt, p);
2485         if (!p) {
2486                 return False;
2487         }
2488
2489         /* Do we have a string ? */
2490         if (skip_string(param,tpscnt,p) == 0) {
2491                 return False;
2492         }
2493         if(!strequal(p, "B516B16")) {
2494                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2495                 return False;
2496         }
2497         p = skip_string(param,tpscnt,p);
2498         if (!p) {
2499                 return False;
2500         }
2501         /* Do we have a string ? */
2502         if (skip_string(param,tpscnt,p) == 0) {
2503                 return False;
2504         }
2505         p += pull_ascii_fstring(user,p);
2506
2507         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2508
2509         /*
2510          * Pass the user through the NT -> unix user mapping
2511          * function.
2512          */
2513
2514         (void)map_username(user);
2515
2516         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2517                 SSVAL(*rparam,0,NERR_Success);
2518         }
2519
2520         return(True);
2521 }
2522
2523 /****************************************************************************
2524   delete a print job
2525   Form: <W> <> 
2526   ****************************************************************************/
2527
2528 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2529                                 char *param, int tpscnt,
2530                                 char *data, int tdscnt,
2531                                 int mdrcnt,int mprcnt,
2532                                 char **rdata,char **rparam,
2533                                 int *rdata_len,int *rparam_len)
2534 {
2535         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2536         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2537         char *str2 = skip_string(param,tpscnt,str1);
2538         char *p = skip_string(param,tpscnt,str2);
2539         uint32 jobid;
2540         int snum;
2541         fstring sharename;
2542         int errcode;
2543         WERROR werr = WERR_OK;
2544
2545         if (!str1 || !str2 || !p) {
2546                 return False;
2547         }
2548         /*
2549          * We use 1 here not 2 as we're checking
2550          * the last byte we want to access is safe.
2551          */
2552         if (!is_offset_safe(param,tpscnt,p,1)) {
2553                 return False;
2554         }
2555         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2556                 return False;
2557
2558         /* check it's a supported varient */
2559         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2560                 return(False);
2561
2562         *rparam_len = 4;
2563         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);       
2564         if (!*rparam) {
2565                 return False;
2566         }
2567         *rdata_len = 0;
2568
2569         if (!print_job_exists(sharename, jobid)) {
2570                 errcode = NERR_JobNotFound;
2571                 goto out;
2572         }
2573
2574         snum = lp_servicenumber( sharename);
2575         if (snum == -1) {
2576                 errcode = NERR_DestNotFound;
2577                 goto out;
2578         }
2579
2580         errcode = NERR_notsupported;
2581         
2582         switch (function) {
2583         case 81:                /* delete */ 
2584                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2585                         errcode = NERR_Success;
2586                 break;
2587         case 82:                /* pause */
2588                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2589                         errcode = NERR_Success;
2590                 break;
2591         case 83:                /* resume */
2592                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2593                         errcode = NERR_Success;
2594                 break;
2595         }
2596
2597         if (!W_ERROR_IS_OK(werr))
2598                 errcode = W_ERROR_V(werr);
2599         
2600  out:
2601         SSVAL(*rparam,0,errcode);       
2602         SSVAL(*rparam,2,0);             /* converter word */
2603
2604         return(True);
2605 }
2606
2607 /****************************************************************************
2608   Purge a print queue - or pause or resume it.
2609   ****************************************************************************/
2610
2611 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2612                                 char *param, int tpscnt,
2613                                 char *data, int tdscnt,
2614                                 int mdrcnt,int mprcnt,
2615                                 char **rdata,char **rparam,
2616                                 int *rdata_len,int *rparam_len)
2617 {
2618         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2619         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2620         char *str2 = skip_string(param,tpscnt,str1);
2621         char *QueueName = skip_string(param,tpscnt,str2);
2622         int errcode = NERR_notsupported;
2623         int snum;
2624         WERROR werr = WERR_OK;
2625
2626         if (!str1 || !str2 || !QueueName) {
2627                 return False;
2628         }
2629
2630         /* check it's a supported varient */
2631         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2632                 return(False);
2633
2634         *rparam_len = 4;
2635         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2636         if (!*rparam) {
2637                 return False;
2638         }
2639         *rdata_len = 0;
2640
2641         if (skip_string(param,tpscnt,QueueName) == NULL) {
2642                 return False;
2643         }
2644         snum = print_queue_snum(QueueName);
2645
2646         if (snum == -1) {
2647                 errcode = NERR_JobNotFound;
2648                 goto out;
2649         }
2650
2651         switch (function) {
2652         case 74: /* Pause queue */
2653                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2654                 break;
2655         case 75: /* Resume queue */
2656                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2657                 break;
2658         case 103: /* Purge */
2659                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2660                 break;
2661         }
2662
2663         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2664
2665  out:
2666         SSVAL(*rparam,0,errcode);
2667         SSVAL(*rparam,2,0);             /* converter word */
2668
2669         return(True);
2670 }
2671
2672 /****************************************************************************
2673   set the property of a print job (undocumented?)
2674   ? function = 0xb -> set name of print job
2675   ? function = 0x6 -> move print job up/down
2676   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2677   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2678 ****************************************************************************/
2679
2680 static int check_printjob_info(struct pack_desc* desc,
2681                                int uLevel, char* id)
2682 {
2683         desc->subformat = NULL;
2684         switch( uLevel ) {
2685         case 0: desc->format = "W"; break;
2686         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2687         case 2: desc->format = "WWzWWDDzz"; break;
2688         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2689         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2690         default:
2691                 DEBUG(0,("check_printjob_info: invalid level %d\n",
2692                         uLevel ));
2693                 return False;
2694         }
2695         if (id == NULL || strcmp(desc->format,id) != 0) {
2696                 DEBUG(0,("check_printjob_info: invalid format %s\n",
2697                         id ? id : "<NULL>" ));
2698                 return False;
2699         }
2700         return True;
2701 }
2702
2703 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2704                                 char *param, int tpscnt,
2705                                 char *data, int tdscnt,
2706                                 int mdrcnt,int mprcnt,
2707                                 char **rdata,char **rparam,
2708                                 int *rdata_len,int *rparam_len)
2709 {
2710         struct pack_desc desc;
2711         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2712         char *str2 = skip_string(param,tpscnt,str1);
2713         char *p = skip_string(param,tpscnt,str2);
2714         uint32 jobid;
2715         fstring sharename;
2716         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2717         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2718         int place, errcode;
2719
2720         if (!str1 || !str2 || !p) {
2721                 return False;
2722         }
2723         /*
2724          * We use 1 here not 2 as we're checking
2725          * the last byte we want to access is safe.
2726          */
2727         if (!is_offset_safe(param,tpscnt,p,1)) {
2728                 return False;
2729         }
2730         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2731                 return False;
2732         *rparam_len = 4;
2733         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2734         if (!*rparam) {
2735                 return False;
2736         }
2737
2738         if (!share_defined(sharename)) {
2739                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2740                          sharename));
2741                 return False;
2742         }
2743   
2744         *rdata_len = 0;
2745         
2746         /* check it's a supported varient */
2747         if ((strcmp(str1,"WWsTP")) || 
2748             (!check_printjob_info(&desc,uLevel,str2)))
2749                 return(False);
2750
2751         if (!print_job_exists(sharename, jobid)) {
2752                 errcode=NERR_JobNotFound;
2753                 goto out;
2754         }
2755
2756         errcode = NERR_notsupported;
2757
2758         switch (function) {
2759         case 0x6:
2760                 /* change job place in the queue, 
2761                    data gives the new place */
2762                 place = SVAL(data,0);
2763                 if (print_job_set_place(sharename, jobid, place)) {
2764                         errcode=NERR_Success;
2765                 }
2766                 break;
2767
2768         case 0xb:   
2769                 /* change print job name, data gives the name */
2770                 if (print_job_set_name(sharename, jobid, data)) {
2771                         errcode=NERR_Success;
2772                 }
2773                 break;
2774
2775         default:
2776                 return False;
2777         }
2778
2779  out:
2780         SSVALS(*rparam,0,errcode);
2781         SSVAL(*rparam,2,0);             /* converter word */
2782         
2783         return(True);
2784 }
2785
2786
2787 /****************************************************************************
2788  Get info about the server.
2789 ****************************************************************************/
2790
2791 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2792                                 char *param, int tpscnt,
2793                                 char *data, int tdscnt,
2794                                 int mdrcnt,int mprcnt,
2795                                 char **rdata,char **rparam,
2796                                 int *rdata_len,int *rparam_len)
2797 {
2798         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2799         char *str2 = skip_string(param,tpscnt,str1);
2800         char *p = skip_string(param,tpscnt,str2);
2801         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2802         char *p2;
2803         int struct_len;
2804
2805         if (!str1 || !str2 || !p) {
2806                 return False;
2807         }
2808
2809         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2810
2811         /* check it's a supported varient */
2812         if (!prefix_ok(str1,"WrLh")) {
2813                 return False;
2814         }
2815
2816         switch( uLevel ) {
2817                 case 0:
2818                         if (strcmp(str2,"B16") != 0) {
2819                                 return False;
2820                         }
2821                         struct_len = 16;
2822                         break;
2823                 case 1:
2824                         if (strcmp(str2,"B16BBDz") != 0) {
2825                                 return False;
2826                         }
2827                         struct_len = 26;
2828                         break;
2829                 case 2:
2830                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2831                                 return False;
2832                         }
2833                         struct_len = 134;
2834                         break;
2835                 case 3:
2836                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2837                                 return False;
2838                         }
2839                         struct_len = 144;
2840                         break;
2841                 case 20:
2842                         if (strcmp(str2,"DN") != 0) {
2843                                 return False;
2844                         }
2845                         struct_len = 6;
2846                         break;
2847                 case 50:
2848                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2849                                 return False;
2850                         }
2851                         struct_len = 42;
2852                         break;
2853                 default:
2854                         return False;
2855         }
2856
2857         *rdata_len = mdrcnt;
2858         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2859         if (!*rdata) {
2860                 return False;
2861         }
2862
2863         p = *rdata;
2864         p2 = p + struct_len;
2865         if (uLevel != 20) {
2866                 srvstr_push(NULL, p,global_myname(),16, 
2867                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2868         }
2869         p += 16;
2870         if (uLevel > 0) {
2871                 struct srv_info_struct *servers=NULL;
2872                 int i,count;
2873                 pstring comment;
2874                 uint32 servertype= lp_default_server_announce();
2875
2876                 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2877
2878                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2879                         for (i=0;i<count;i++) {
2880                                 if (strequal(servers[i].name,global_myname())) {
2881                                         servertype = servers[i].type;
2882                                         push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2883                                 }
2884                         }
2885                 }
2886
2887                 SAFE_FREE(servers);
2888
2889                 SCVAL(p,0,lp_major_announce_version());
2890                 SCVAL(p,1,lp_minor_announce_version());
2891                 SIVAL(p,2,servertype);
2892
2893                 if (mdrcnt == struct_len) {
2894                         SIVAL(p,6,0);
2895                 } else {
2896                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2897                         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2898                                               conn->connectpath, conn->gid,
2899                                               get_current_username(),
2900                                               current_user_info.domain,
2901                                               comment, sizeof(comment));
2902                         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2903                         p2 = skip_string(*rdata,*rdata_len,p2);
2904                         if (!p2) {
2905                                 return False;
2906                         }
2907                 }
2908         }
2909
2910         if (uLevel > 1) {
2911                 return False;           /* not yet implemented */
2912         }
2913
2914         *rdata_len = PTR_DIFF(p2,*rdata);
2915
2916         *rparam_len = 6;
2917         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2918         if (!*rparam) {
2919                 return False;
2920         }
2921         SSVAL(*rparam,0,NERR_Success);
2922         SSVAL(*rparam,2,0);             /* converter word */
2923         SSVAL(*rparam,4,*rdata_len);
2924
2925         return True;
2926 }
2927
2928 /****************************************************************************
2929  Get info about the server.
2930 ****************************************************************************/
2931
2932 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2933                                 char *param, int tpscnt,
2934                                 char *data, int tdscnt,
2935                                 int mdrcnt,int mprcnt,
2936                                 char **rdata,char **rparam,
2937                                 int *rdata_len,int *rparam_len)
2938 {
2939         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2940         char *str2 = skip_string(param,tpscnt,str1);
2941         char *p = skip_string(param,tpscnt,str2);
2942         char *p2;
2943         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2944
2945         if (!str1 || !str2 || !p) {
2946                 return False;
2947         }
2948
2949         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2950
2951         *rparam_len = 6;
2952         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2953         if (!*rparam) {
2954                 return False;
2955         }
2956
2957         /* check it's a supported varient */
2958         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2959                 return False;
2960         }
2961
2962         *rdata_len = mdrcnt + 1024;
2963         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2964         if (!*rdata) {
2965                 return False;
2966         }
2967
2968         SSVAL(*rparam,0,NERR_Success);
2969         SSVAL(*rparam,2,0);             /* converter word */
2970
2971         p = *rdata;
2972         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2973         if (!p2) {
2974                 return False;
2975         }
2976
2977         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2978         pstrcpy(p2,get_local_machine_name());
2979         strupper_m(p2);
2980         p2 = skip_string(*rdata,*rdata_len,p2);
2981         if (!p2) {
2982                 return False;
2983         }
2984         p += 4;
2985
2986         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2987         pstrcpy(p2,current_user_info.smb_name);
2988         p2 = skip_string(*rdata,*rdata_len,p2);
2989         if (!p2) {
2990                 return False;
2991         }
2992         p += 4;
2993
2994         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2995         pstrcpy(p2,lp_workgroup());
2996         strupper_m(p2);
2997         p2 = skip_string(*rdata,*rdata_len,p2);
2998         if (!p2) {
2999                 return False;
3000         }
3001         p += 4;
3002
3003         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3004         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3005         p += 2;
3006
3007         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3008         pstrcpy(p2,lp_workgroup());     /* don't know.  login domain?? */
3009         p2 = skip_string(*rdata,*rdata_len,p2);
3010         if (!p2) {
3011                 return False;
3012         }
3013         p += 4;
3014
3015         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3016         pstrcpy(p2,"");
3017         p2 = skip_string(*rdata,*rdata_len,p2);
3018         if (!p2) {
3019                 return False;
3020         }
3021         p += 4;
3022
3023         *rdata_len = PTR_DIFF(p2,*rdata);
3024
3025         SSVAL(*rparam,4,*rdata_len);
3026
3027         return True;
3028 }
3029
3030 /****************************************************************************
3031   get info about a user
3032
3033     struct user_info_11 {
3034         char                usri11_name[21];  0-20 
3035         char                usri11_pad;       21 
3036         char                *usri11_comment;  22-25 
3037         char            *usri11_usr_comment;  26-29
3038         unsigned short      usri11_priv;      30-31
3039         unsigned long       usri11_auth_flags; 32-35
3040         long                usri11_password_age; 36-39
3041         char                *usri11_homedir; 40-43
3042         char            *usri11_parms; 44-47
3043         long                usri11_last_logon; 48-51
3044         long                usri11_last_logoff; 52-55
3045         unsigned short      usri11_bad_pw_count; 56-57
3046         unsigned short      usri11_num_logons; 58-59
3047         char                *usri11_logon_server; 60-63
3048         unsigned short      usri11_country_code; 64-65
3049         char            *usri11_workstations; 66-69
3050         unsigned long       usri11_max_storage; 70-73
3051         unsigned short      usri11_units_per_week; 74-75
3052         unsigned char       *usri11_logon_hours; 76-79
3053         unsigned short      usri11_code_page; 80-81
3054     };
3055
3056 where:
3057
3058   usri11_name specifies the user name for which information is retireved
3059
3060   usri11_pad aligns the next data structure element to a word boundary
3061
3062   usri11_comment is a null terminated ASCII comment
3063
3064   usri11_user_comment is a null terminated ASCII comment about the user
3065
3066   usri11_priv specifies the level of the privilege assigned to the user.
3067        The possible values are:
3068
3069 Name             Value  Description
3070 USER_PRIV_GUEST  0      Guest privilege
3071 USER_PRIV_USER   1      User privilege
3072 USER_PRV_ADMIN   2      Administrator privilege
3073
3074   usri11_auth_flags specifies the account operator privileges. The
3075        possible values are:
3076
3077 Name            Value   Description
3078 AF_OP_PRINT     0       Print operator
3079
3080
3081 Leach, Naik                                        [Page 28]
3082 \f
3083
3084
3085 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3086
3087
3088 AF_OP_COMM      1       Communications operator
3089 AF_OP_SERVER    2       Server operator
3090 AF_OP_ACCOUNTS  3       Accounts operator
3091
3092
3093   usri11_password_age specifies how many seconds have elapsed since the
3094        password was last changed.
3095
3096   usri11_home_dir points to a null terminated ASCII string that contains
3097        the path name of the user's home directory.
3098
3099   usri11_parms points to a null terminated ASCII string that is set
3100        aside for use by applications.
3101
3102   usri11_last_logon specifies the time when the user last logged on.
3103        This value is stored as the number of seconds elapsed since
3104        00:00:00, January 1, 1970.
3105
3106   usri11_last_logoff specifies the time when the user last logged off.
3107        This value is stored as the number of seconds elapsed since
3108        00:00:00, January 1, 1970. A value of 0 means the last logoff
3109        time is unknown.
3110
3111   usri11_bad_pw_count specifies the number of incorrect passwords
3112        entered since the last successful logon.
3113
3114   usri11_log1_num_logons specifies the number of times this user has
3115        logged on. A value of -1 means the number of logons is unknown.
3116
3117   usri11_logon_server points to a null terminated ASCII string that
3118        contains the name of the server to which logon requests are sent.
3119        A null string indicates logon requests should be sent to the
3120        domain controller.
3121
3122   usri11_country_code specifies the country code for the user's language
3123        of choice.
3124
3125   usri11_workstations points to a null terminated ASCII string that
3126        contains the names of workstations the user may log on from.
3127        There may be up to 8 workstations, with the names separated by
3128        commas. A null strings indicates there are no restrictions.
3129
3130   usri11_max_storage specifies the maximum amount of disk space the user
3131        can occupy. A value of 0xffffffff indicates there are no
3132        restrictions.
3133
3134   usri11_units_per_week specifies the equal number of time units into
3135        which a week is divided. This value must be equal to 168.
3136
3137   usri11_logon_hours points to a 21 byte (168 bits) string that
3138        specifies the time during which the user can log on. Each bit
3139        represents one unique hour in a week. The first bit (bit 0, word
3140        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3141
3142
3143
3144 Leach, Naik                                        [Page 29]
3145 \f
3146
3147
3148 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3149
3150
3151        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3152        are no restrictions.
3153
3154   usri11_code_page specifies the code page for the user's language of
3155        choice
3156
3157 All of the pointers in this data structure need to be treated
3158 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
3159 to be ignored. The converter word returned in the parameters section
3160 needs to be subtracted from the lower 16 bits to calculate an offset
3161 into the return buffer where this ASCII string resides.
3162
3163 There is no auxiliary data in the response.
3164
3165   ****************************************************************************/
3166
3167 #define usri11_name           0 
3168 #define usri11_pad            21
3169 #define usri11_comment        22
3170 #define usri11_usr_comment    26
3171 #define usri11_full_name      30
3172 #define usri11_priv           34
3173 #define usri11_auth_flags     36
3174 #define usri11_password_age   40
3175 #define usri11_homedir        44
3176 #define usri11_parms          48
3177 #define usri11_last_logon     52
3178 #define usri11_last_logoff    56
3179 #define usri11_bad_pw_count   60
3180 #define usri11_num_logons     62
3181 #define usri11_logon_server   64
3182 #define usri11_country_code   68
3183 #define usri11_workstations   70
3184 #define usri11_max_storage    74
3185 #define usri11_units_per_week 78
3186 #define usri11_logon_hours    80
3187 #define usri11_code_page      84
3188 #define usri11_end            86
3189
3190 #define USER_PRIV_GUEST 0
3191 #define USER_PRIV_USER 1
3192 #define USER_PRIV_ADMIN 2
3193
3194 #define AF_OP_PRINT     0 
3195 #define AF_OP_COMM      1
3196 #define AF_OP_SERVER    2
3197 #define AF_OP_ACCOUNTS  3
3198
3199
3200 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3201                                 char *param, int tpscnt,
3202                                 char *data, int tdscnt,
3203                                 int mdrcnt,int mprcnt,
3204                                 char **rdata,char **rparam,
3205                                 int *rdata_len,int *rparam_len)
3206 {
3207         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3208         char *str2 = skip_string(param,tpscnt,str1);
3209         char *UserName = skip_string(param,tpscnt,str2);
3210         char *p = skip_string(param,tpscnt,UserName);
3211         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3212         char *p2;
3213         const char *level_string;
3214
3215         /* get NIS home of a previously validated user - simeon */
3216         /* With share level security vuid will always be zero.
3217            Don't depend on vuser being non-null !!. JRA */
3218         user_struct *vuser = get_valid_user_struct(vuid);
3219         if(vuser != NULL) {
3220                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3221                         vuser->user.unix_name));
3222         }
3223
3224         if (!str1 || !str2 || !UserName || !p) {
3225                 return False;
3226         }
3227
3228         *rparam_len = 6;
3229         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3230         if (!*rparam) {
3231                 return False;
3232         }
3233
3234         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3235   
3236         /* check it's a supported variant */
3237         if (strcmp(str1,"zWrLh") != 0) {
3238                 return False;
3239         }
3240         switch( uLevel ) {
3241                 case 0: level_string = "B21"; break;
3242                 case 1: level_string = "B21BB16DWzzWz"; break;
3243                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3244                 case 10: level_string = "B21Bzzz"; break;
3245                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3246                 default: return False;
3247         }
3248
3249         if (strcmp(level_string,str2) != 0) {
3250                 return False;
3251         }
3252
3253         *rdata_len = mdrcnt + 1024;
3254         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3255         if (!*rdata) {
3256                 return False;
3257         }
3258
3259         SSVAL(*rparam,0,NERR_Success);
3260         SSVAL(*rparam,2,0);             /* converter word */
3261
3262         p = *rdata;
3263         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3264         if (!p2) {
3265                 return False;
3266         }
3267
3268         memset(p,0,21); 
3269         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3270
3271         if (uLevel > 0) {
3272                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3273                 *p2 = 0;
3274         }
3275
3276         if (uLevel >= 10) {
3277                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3278                 pstrcpy(p2,"Comment");
3279                 p2 = skip_string(*rdata,*rdata_len,p2);
3280                 if (!p2) {
3281                         return False;
3282                 }
3283
3284                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3285                 pstrcpy(p2,"UserComment");
3286                 p2 = skip_string(*rdata,*rdata_len,p2);
3287                 if (!p2) {
3288                         return False;
3289                 }
3290
3291                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3292                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3293                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3294                 p2 = skip_string(*rdata,*rdata_len,p2);
3295                 if (!p2) {
3296                         return False;
3297                 }
3298         }
3299
3300         if (uLevel == 11) {
3301                 /* modelled after NTAS 3.51 reply */
3302                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3303                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3304                 SIVALS(p,usri11_password_age,-1);               /* password age */
3305                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3306                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3307                 p2 = skip_string(*rdata,*rdata_len,p2);
3308                 if (!p2) {
3309                         return False;
3310                 }
3311                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3312                 pstrcpy(p2,"");
3313                 p2 = skip_string(*rdata,*rdata_len,p2);
3314                 if (!p2) {
3315                         return False;
3316                 }
3317                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3318                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3319                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3320                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3321                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3322                 pstrcpy(p2,"\\\\*");
3323                 p2 = skip_string(*rdata,*rdata_len,p2);
3324                 if (!p2) {
3325                         return False;
3326                 }
3327                 SSVAL(p,usri11_country_code,0);         /* country code */
3328
3329                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3330                 pstrcpy(p2,"");
3331                 p2 = skip_string(*rdata,*rdata_len,p2);
3332                 if (!p2) {
3333                         return False;
3334                 }
3335
3336                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3337                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3338                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3339
3340                 /* a simple way to get logon hours at all times. */
3341                 memset(p2,0xff,21);
3342                 SCVAL(p2,21,0);           /* fix zero termination */
3343                 p2 = skip_string(*rdata,*rdata_len,p2);
3344                 if (!p2) {
3345                         return False;
3346                 }
3347
3348                 SSVAL(p,usri11_code_page,0);            /* code page */
3349         }
3350
3351         if (uLevel == 1 || uLevel == 2) {
3352                 memset(p+22,' ',16);    /* password */
3353                 SIVALS(p,38,-1);                /* password age */
3354                 SSVAL(p,42,
3355                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3356                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3357                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3358                 p2 = skip_string(*rdata,*rdata_len,p2);
3359                 if (!p2) {
3360                         return False;
3361                 }
3362                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3363                 *p2++ = 0;
3364                 SSVAL(p,52,0);          /* flags */
3365                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3366                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3367                 p2 = skip_string(*rdata,*rdata_len,p2);
3368                 if (!p2) {
3369                         return False;
3370                 }
3371                 if (uLevel == 2) {
3372                         SIVAL(p,60,0);          /* auth_flags */
3373                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3374                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3375                         p2 = skip_string(*rdata,*rdata_len,p2);
3376                         if (!p2) {
3377                                 return False;
3378                         }
3379                         SIVAL(p,68,0);          /* urs_comment */
3380                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3381                         pstrcpy(p2,"");
3382                         p2 = skip_string(*rdata,*rdata_len,p2);
3383                         if (!p2) {
3384                                 return False;
3385                         }
3386                         SIVAL(p,76,0);          /* workstations */
3387                         SIVAL(p,80,0);          /* last_logon */
3388                         SIVAL(p,84,0);          /* last_logoff */
3389                         SIVALS(p,88,-1);                /* acct_expires */
3390                         SIVALS(p,92,-1);                /* max_storage */
3391                         SSVAL(p,96,168);        /* units_per_week */
3392                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3393                         memset(p2,-1,21);
3394                         p2 += 21;
3395                         SSVALS(p,102,-1);       /* bad_pw_count */
3396                         SSVALS(p,104,-1);       /* num_logons */
3397                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3398                         {
3399                                 pstring tmp;
3400                                 pstrcpy(tmp, "\\\\%L");
3401                                 standard_sub_basic("", "", tmp, sizeof(tmp));
3402                                 pstrcpy(p2, tmp);
3403                         }
3404                         p2 = skip_string(*rdata,*rdata_len,p2);
3405                         if (!p2) {
3406                                 return False;
3407                         }
3408                         SSVAL(p,110,49);        /* country_code */
3409                         SSVAL(p,112,860);       /* code page */
3410                 }
3411         }
3412
3413         *rdata_len = PTR_DIFF(p2,*rdata);
3414
3415         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3416
3417         return(True);
3418 }
3419
3420 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3421                                 char *param, int tpscnt,
3422                                 char *data, int tdscnt,
3423                                 int mdrcnt,int mprcnt,
3424                                 char **rdata,char **rparam,
3425                                 int *rdata_len,int *rparam_len)
3426 {
3427         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3428         char *str2 = skip_string(param,tpscnt,str1);
3429         char *p = skip_string(param,tpscnt,str2);
3430         int uLevel;
3431         struct pack_desc desc;
3432         char* name;
3433                 /* With share level security vuid will always be zero.
3434                    Don't depend on vuser being non-null !!. JRA */
3435         user_struct *vuser = get_valid_user_struct(vuid);
3436
3437         if (!str1 || !str2 || !p) {
3438                 return False;
3439         }
3440
3441         if(vuser != NULL) {
3442                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3443                         vuser->user.unix_name));
3444         }
3445
3446         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3447         name = get_safe_str_ptr(param,tpscnt,p,2);
3448         if (!name) {
3449                 return False;
3450         }
3451
3452         memset((char *)&desc,'\0',sizeof(desc));
3453
3454         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3455
3456         /* check it's a supported varient */
3457         if (strcmp(str1,"OOWb54WrLh") != 0) {
3458                 return False;
3459         }
3460         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3461                 return False;
3462         }
3463         if (mdrcnt > 0) {
3464                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3465                 if (!*rdata) {
3466                         return False;
3467                 }
3468         }
3469
3470         desc.base = *rdata;
3471         desc.buflen = mdrcnt;
3472         desc.subformat = NULL;
3473         desc.format = str2;
3474   
3475         if (init_package(&desc,1,0)) {
3476                 PACKI(&desc,"W",0);             /* code */
3477                 PACKS(&desc,"B21",name);        /* eff. name */
3478                 PACKS(&desc,"B","");            /* pad */
3479                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3480                 PACKI(&desc,"D",0);             /* auth flags XXX */
3481                 PACKI(&desc,"W",0);             /* num logons */
3482                 PACKI(&desc,"W",0);             /* bad pw count */
3483                 PACKI(&desc,"D",0);             /* last logon */
3484                 PACKI(&desc,"D",-1);            /* last logoff */
3485                 PACKI(&desc,"D",-1);            /* logoff time */
3486                 PACKI(&desc,"D",-1);            /* kickoff time */
3487                 PACKI(&desc,"D",0);             /* password age */
3488                 PACKI(&desc,"D",0);             /* password can change */
3489                 PACKI(&desc,"D",-1);            /* password must change */
3490
3491                 {
3492                         fstring mypath;
3493                         fstrcpy(mypath,"\\\\");
3494                         fstrcat(mypath,get_local_machine_name());
3495                         strupper_m(mypath);
3496                         PACKS(&desc,"z",mypath); /* computer */
3497                 }
3498
3499                 PACKS(&desc,"z",lp_workgroup());/* domain */
3500                 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3501                 PACKI(&desc,"D",0x00000000);            /* reserved */
3502         }
3503
3504         *rdata_len = desc.usedlen;
3505         *rparam_len = 6;
3506         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3507         if (!*rparam) {
3508                 return False;
3509         }
3510         SSVALS(*rparam,0,desc.errcode);
3511         SSVAL(*rparam,2,0);
3512         SSVAL(*rparam,4,desc.neededlen);
3513
3514         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3515
3516         return True;
3517 }
3518
3519 /****************************************************************************
3520  api_WAccessGetUserPerms
3521 ****************************************************************************/
3522
3523 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3524                                 char *param, int tpscnt,
3525                                 char *data, int tdscnt,
3526                                 int mdrcnt,int mprcnt,
3527                                 char **rdata,char **rparam,
3528                                 int *rdata_len,int *rparam_len)
3529 {
3530         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3531         char *str2 = skip_string(param,tpscnt,str1);
3532         char *user = skip_string(param,tpscnt,str2);
3533         char *resource = skip_string(param,tpscnt,user);
3534
3535         if (!str1 || !str2 || !user || !resource) {
3536                 return False;
3537         }
3538
3539         if (skip_string(param,tpscnt,resource) == NULL) {
3540                 return False;
3541         }
3542         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3543
3544         /* check it's a supported varient */
3545         if (strcmp(str1,"zzh") != 0) {
3546                 return False;
3547         }
3548         if (strcmp(str2,"") != 0) {
3549                 return False;
3550         }
3551
3552         *rparam_len = 6;
3553         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3554         if (!*rparam) {
3555                 return False;
3556         }
3557         SSVALS(*rparam,0,0);            /* errorcode */
3558         SSVAL(*rparam,2,0);             /* converter word */
3559         SSVAL(*rparam,4,0x7f);  /* permission flags */
3560
3561         return True;
3562 }
3563
3564 /****************************************************************************
3565   api_WPrintJobEnumerate
3566   ****************************************************************************/
3567
3568 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3569                                 char *param, int tpscnt,
3570                                 char *data, int tdscnt,
3571                                 int mdrcnt,int mprcnt,
3572                                 char **rdata,char **rparam,
3573                                 int *rdata_len,int *rparam_len)
3574 {
3575         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3576         char *str2 = skip_string(param,tpscnt,str1);
3577         char *p = skip_string(param,tpscnt,str2);
3578         int uLevel;
3579         int count;
3580         int i;
3581         int snum;
3582         fstring sharename;
3583         uint32 jobid;
3584         struct pack_desc desc;
3585         print_queue_struct *queue=NULL;
3586         print_status_struct status;
3587         char *tmpdata=NULL;
3588
3589         if (!str1 || !str2 || !p) {
3590                 return False;
3591         }
3592
3593         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3594
3595         memset((char *)&desc,'\0',sizeof(desc));
3596         memset((char *)&status,'\0',sizeof(status));
3597
3598         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3599
3600         /* check it's a supported varient */
3601         if (strcmp(str1,"WWrLh") != 0) {
3602                 return False;
3603         }
3604         if (!check_printjob_info(&desc,uLevel,str2)) {
3605                 return False;
3606         }
3607
3608         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3609                 return False;
3610         }
3611
3612         snum = lp_servicenumber( sharename);
3613         if (snum < 0 || !VALID_SNUM(snum)) {
3614                 return(False);
3615         }
3616
3617         count = print_queue_status(snum,&queue,&status);
3618         for (i = 0; i < count; i++) {
3619                 if (queue[i].job == jobid) {
3620                         break;
3621                 }
3622         }
3623
3624         if (mdrcnt > 0) {
3625                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3626                 if (!*rdata) {
3627                         return False;
3628                 }
3629                 desc.base = *rdata;
3630                 desc.buflen = mdrcnt;
3631         } else {
3632                 /*
3633                  * Don't return data but need to get correct length
3634                  *  init_package will return wrong size if buflen=0
3635                  */
3636                 desc.buflen = getlen(desc.format);
3637                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3638         }
3639
3640         if (init_package(&desc,1,0)) {
3641                 if (i < count) {
3642                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3643                         *rdata_len = desc.usedlen;
3644                 } else {
3645                         desc.errcode = NERR_JobNotFound;
3646                         *rdata_len = 0;
3647                 }
3648         }
3649
3650         *rparam_len = 6;
3651         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3652         if (!*rparam) {
3653                 return False;
3654         }
3655         SSVALS(*rparam,0,desc.errcode);
3656         SSVAL(*rparam,2,0);
3657         SSVAL(*rparam,4,desc.neededlen);
3658
3659         SAFE_FREE(queue);
3660         SAFE_FREE(tmpdata);
3661
3662         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3663
3664         return True;
3665 }
3666
3667 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3668                                 char *param, int tpscnt,
3669                                 char *data, int tdscnt,
3670                                 int mdrcnt,int mprcnt,
3671                                 char **rdata,char **rparam,
3672                                 int *rdata_len,int *rparam_len)
3673 {
3674         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3675         char *str2 = skip_string(param,tpscnt,str1);
3676         char *p = skip_string(param,tpscnt,str2);
3677         char *name = p;
3678         int uLevel;
3679         int count;
3680         int i, succnt=0;
3681         int snum;
3682         struct pack_desc desc;
3683         print_queue_struct *queue=NULL;
3684         print_status_struct status;
3685
3686         if (!str1 || !str2 || !p) {
3687                 return False;
3688         }
3689
3690         memset((char *)&desc,'\0',sizeof(desc));
3691         memset((char *)&status,'\0',sizeof(status));
3692
3693         p = skip_string(param,tpscnt,p);
3694         if (!p) {
3695                 return False;
3696         }
3697         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3698
3699         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3700
3701         /* check it's a supported variant */
3702         if (strcmp(str1,"zWrLeh") != 0) {
3703                 return False;
3704         }
3705     
3706         if (uLevel > 2) {
3707                 return False;   /* defined only for uLevel 0,1,2 */
3708         }
3709     
3710         if (!check_printjob_info(&desc,uLevel,str2)) { 
3711                 return False;
3712         }
3713
3714         snum = find_service(name);
3715         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3716                 return False;
3717         }
3718
3719         count = print_queue_status(snum,&queue,&status);
3720         if (mdrcnt > 0) {
3721                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3722                 if (!*rdata) {
3723                         return False;
3724                 }
3725         }
3726         desc.base = *rdata;
3727         desc.buflen = mdrcnt;
3728
3729         if (init_package(&desc,count,0)) {
3730                 succnt = 0;
3731                 for (i = 0; i < count; i++) {
3732                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3733                         if (desc.errcode == NERR_Success) {
3734                                 succnt = i+1;
3735                         }
3736                 }
3737         }
3738
3739         *rdata_len = desc.usedlen;
3740
3741         *rparam_len = 8;
3742         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3743         if (!*rparam) {
3744                 return False;
3745         }
3746         SSVALS(*rparam,0,desc.errcode);
3747         SSVAL(*rparam,2,0);
3748         SSVAL(*rparam,4,succnt);
3749         SSVAL(*rparam,6,count);
3750
3751         SAFE_FREE(queue);
3752
3753         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3754
3755         return True;
3756 }
3757
3758 static int check_printdest_info(struct pack_desc* desc,
3759                                 int uLevel, char* id)
3760 {
3761         desc->subformat = NULL;
3762         switch( uLevel ) {
3763                 case 0:
3764                         desc->format = "B9";
3765                         break;
3766                 case 1:
3767                         desc->format = "B9B21WWzW";
3768                         break;
3769                 case 2:
3770                         desc->format = "z";
3771                         break;
3772                 case 3:
3773                         desc->format = "zzzWWzzzWW";
3774                         break;
3775                 default:
3776                         DEBUG(0,("check_printdest_info: invalid level %d\n",
3777                                 uLevel));
3778                         return False;
3779         }
3780         if (id == NULL || strcmp(desc->format,id) != 0) {
3781                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
3782                         id ? id : "<NULL>" ));
3783                 return False;
3784         }
3785         return True;
3786 }
3787
3788 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3789                                 struct pack_desc* desc)
3790 {
3791         char buf[100];
3792
3793         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3794         buf[sizeof(buf)-1] = 0;
3795         strupper_m(buf);
3796
3797         if (uLevel <= 1) {
3798                 PACKS(desc,"B9",buf);   /* szName */
3799                 if (uLevel == 1) {
3800                         PACKS(desc,"B21","");   /* szUserName */
3801                         PACKI(desc,"W",0);              /* uJobId */
3802                         PACKI(desc,"W",0);              /* fsStatus */
3803                         PACKS(desc,"z","");     /* pszStatus */
3804                         PACKI(desc,"W",0);              /* time */
3805                 }
3806         }
3807
3808         if (uLevel == 2 || uLevel == 3) {
3809                 PACKS(desc,"z",buf);            /* pszPrinterName */
3810                 if (uLevel == 3) {
3811                         PACKS(desc,"z","");     /* pszUserName */
3812                         PACKS(desc,"z","");     /* pszLogAddr */
3813                         PACKI(desc,"W",0);              /* uJobId */
3814                         PACKI(desc,"W",0);              /* fsStatus */
3815                         PACKS(desc,"z","");     /* pszStatus */
3816                         PACKS(desc,"z","");     /* pszComment */
3817                         PACKS(desc,"z","NULL"); /* pszDrivers */
3818                         PACKI(desc,"W",0);              /* time */
3819                         PACKI(desc,"W",0);              /* pad1 */
3820                 }
3821         }
3822 }
3823
3824 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3825                                 char *param, int tpscnt,
3826                                 char *data, int tdscnt,
3827                                 int mdrcnt,int mprcnt,
3828                                 char **rdata,char **rparam,
3829                                 int *rdata_len,int *rparam_len)
3830 {
3831         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3832         char *str2 = skip_string(param,tpscnt,str1);
3833         char *p = skip_string(param,tpscnt,str2);
3834         char* PrinterName = p;
3835         int uLevel;
3836         struct pack_desc desc;
3837         int snum;
3838         char *tmpdata=NULL;
3839
3840         if (!str1 || !str2 || !p) {
3841                 return False;
3842         }
3843
3844         memset((char *)&desc,'\0',sizeof(desc));
3845
3846         p = skip_string(param,tpscnt,p);
3847         if (!p) {
3848                 return False;
3849         }
3850         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3851
3852         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3853
3854         /* check it's a supported varient */
3855         if (strcmp(str1,"zWrLh") != 0) {
3856                 return False;
3857         }
3858         if (!check_printdest_info(&desc,uLevel,str2)) {
3859                 return False;
3860         }
3861
3862         snum = find_service(PrinterName);
3863         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3864                 *rdata_len = 0;
3865                 desc.errcode = NERR_DestNotFound;
3866                 desc.neededlen = 0;
3867         } else {
3868                 if (mdrcnt > 0) {
3869                         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3870                         if (!*rdata) {
3871                                 return False;
3872                         }
3873                         desc.base = *rdata;
3874                         desc.buflen = mdrcnt;
3875                 } else {
3876                         /*
3877                          * Don't return data but need to get correct length
3878                          * init_package will return wrong size if buflen=0
3879                          */
3880                         desc.buflen = getlen(desc.format);
3881                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3882                 }
3883                 if (init_package(&desc,1,0)) {
3884                         fill_printdest_info(conn,snum,uLevel,&desc);
3885                 }
3886                 *rdata_len = desc.usedlen;
3887         }
3888
3889         *rparam_len = 6;
3890         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3891         if (!*rparam) {
3892                 return False;
3893         }
3894         SSVALS(*rparam,0,desc.errcode);
3895         SSVAL(*rparam,2,0);
3896         SSVAL(*rparam,4,desc.neededlen);
3897
3898         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3899         SAFE_FREE(tmpdata);
3900
3901         return True;
3902 }
3903
3904 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3905                                 char *param, int tpscnt,
3906                                 char *data, int tdscnt,
3907                                 int mdrcnt,int mprcnt,
3908                                 char **rdata,char **rparam,
3909                                 int *rdata_len,int *rparam_len)
3910 {
3911         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3912         char *str2 = skip_string(param,tpscnt,str1);
3913         char *p = skip_string(param,tpscnt,str2);
3914         int uLevel;
3915         int queuecnt;
3916         int i, n, succnt=0;
3917         struct pack_desc desc;
3918         int services = lp_numservices();
3919
3920         if (!str1 || !str2 || !p) {
3921                 return False;
3922         }
3923
3924         memset((char *)&desc,'\0',sizeof(desc));
3925
3926         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3927
3928         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3929
3930         /* check it's a supported varient */
3931         if (strcmp(str1,"WrLeh") != 0) {
3932                 return False;
3933         }
3934         if (!check_printdest_info(&desc,uLevel,str2)) {
3935                 return False;
3936         }
3937
3938         queuecnt = 0;
3939         for (i = 0; i < services; i++) {
3940                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3941                         queuecnt++;
3942                 }
3943         }
3944
3945         if (mdrcnt > 0) {
3946                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3947                 if (!*rdata) {
3948                         return False;
3949                 }
3950         }
3951
3952         desc.base = *rdata;
3953         desc.buflen = mdrcnt;
3954         if (init_package(&desc,queuecnt,0)) {    
3955                 succnt = 0;
3956                 n = 0;
3957                 for (i = 0; i < services; i++) {
3958                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3959                                 fill_printdest_info(conn,i,uLevel,&desc);
3960                                 n++;
3961                                 if (desc.errcode == NERR_Success) {
3962                                         succnt = n;
3963                                 }
3964                         }
3965                 }
3966         }
3967
3968         *rdata_len = desc.usedlen;
3969
3970         *rparam_len = 8;
3971         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3972         if (!*rparam) {
3973                 return False;
3974         }
3975         SSVALS(*rparam,0,desc.errcode);
3976         SSVAL(*rparam,2,0);
3977         SSVAL(*rparam,4,succnt);
3978         SSVAL(*rparam,6,queuecnt);
3979
3980         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3981
3982         return True;
3983 }
3984
3985 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3986                                 char *param, int tpscnt,
3987                                 char *data, int tdscnt,
3988                                 int mdrcnt,int mprcnt,
3989                                 char **rdata,char **rparam,
3990                                 int *rdata_len,int *rparam_len)
3991 {
3992         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3993         char *str2 = skip_string(param,tpscnt,str1);
3994         char *p = skip_string(param,tpscnt,str2);
3995         int uLevel;
3996         int succnt;
3997         struct pack_desc desc;
3998
3999         if (!str1 || !str2 || !p) {
4000                 return False;
4001         }
4002
4003         memset((char *)&desc,'\0',sizeof(desc));
4004
4005         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4006
4007         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4008
4009         /* check it's a supported varient */
4010         if (strcmp(str1,"WrLeh") != 0) {
4011                 return False;
4012         }
4013         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4014                 return False;
4015         }
4016
4017         if (mdrcnt > 0) {
4018                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4019                 if (!*rdata) {
4020                         return False;
4021                 }
4022         }
4023         desc.base = *rdata;
4024         desc.buflen = mdrcnt;
4025         if (init_package(&desc,1,0)) {
4026                 PACKS(&desc,"B41","NULL");
4027         }
4028
4029         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4030
4031         *rdata_len = desc.usedlen;
4032
4033         *rparam_len = 8;
4034         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4035         if (!*rparam) {
4036                 return False;
4037         }
4038         SSVALS(*rparam,0,desc.errcode);
4039         SSVAL(*rparam,2,0);
4040         SSVAL(*rparam,4,succnt);
4041         SSVAL(*rparam,6,1);
4042
4043         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4044
4045         return True;
4046 }
4047
4048 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4049                                 char *param, int tpscnt,
4050                                 char *data, int tdscnt,
4051                                 int mdrcnt,int mprcnt,
4052                                 char **rdata,char **rparam,
4053                                 int *rdata_len,int *rparam_len)
4054 {
4055         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4056         char *str2 = skip_string(param,tpscnt,str1);
4057         char *p = skip_string(param,tpscnt,str2);
4058         int uLevel;
4059         int succnt;
4060         struct pack_desc desc;
4061
4062         if (!str1 || !str2 || !p) {
4063                 return False;
4064         }
4065         memset((char *)&desc,'\0',sizeof(desc));
4066
4067         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4068
4069         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4070
4071         /* check it's a supported varient */
4072         if (strcmp(str1,"WrLeh") != 0) {
4073                 return False;
4074         }
4075         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4076                 return False;
4077         }
4078
4079         if (mdrcnt > 0) {
4080                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4081                 if (!*rdata) {
4082                         return False;
4083                 }
4084         }
4085         desc.base = *rdata;
4086         desc.buflen = mdrcnt;
4087         desc.format = str2;
4088         if (init_package(&desc,1,0)) {
4089                 PACKS(&desc,"B13","lpd");
4090         }
4091
4092         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4093
4094         *rdata_len = desc.usedlen;
4095
4096         *rparam_len = 8;
4097         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4098         if (!*rparam) {
4099                 return False;
4100         }
4101         SSVALS(*rparam,0,desc.errcode);
4102         SSVAL(*rparam,2,0);
4103         SSVAL(*rparam,4,succnt);
4104         SSVAL(*rparam,6,1);
4105
4106         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4107
4108         return True;
4109 }
4110
4111 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4112                                 char *param, int tpscnt,
4113                                 char *data, int tdscnt,
4114                                 int mdrcnt,int mprcnt,
4115                                 char **rdata,char **rparam,
4116                                 int *rdata_len,int *rparam_len)
4117 {
4118         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4119         char *str2 = skip_string(param,tpscnt,str1);
4120         char *p = skip_string(param,tpscnt,str2);
4121         int uLevel;
4122         int succnt;
4123         struct pack_desc desc;
4124
4125         if (!str1 || !str2 || !p) {
4126                 return False;
4127         }
4128
4129         memset((char *)&desc,'\0',sizeof(desc));
4130
4131         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4132
4133         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4134
4135         /* check it's a supported varient */
4136         if (strcmp(str1,"WrLeh") != 0) {
4137                 return False;
4138         }
4139         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4140                 return False;
4141         }
4142
4143         if (mdrcnt > 0) {
4144                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4145                 if (!*rdata) {
4146                         return False;
4147                 }
4148         }
4149         memset((char *)&desc,'\0',sizeof(desc));
4150         desc.base = *rdata;
4151         desc.buflen = mdrcnt;
4152         desc.format = str2;
4153         if (init_package(&desc,1,0)) {
4154                 PACKS(&desc,"B13","lp0");
4155         }
4156
4157         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4158
4159         *rdata_len = desc.usedlen;
4160
4161         *rparam_len = 8;
4162         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4163         if (!*rparam) {
4164                 return False;
4165         }
4166         SSVALS(*rparam,0,desc.errcode);
4167         SSVAL(*rparam,2,0);
4168         SSVAL(*rparam,4,succnt);
4169         SSVAL(*rparam,6,1);
4170
4171         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4172
4173         return True;
4174 }
4175
4176 /****************************************************************************
4177  List open sessions
4178  ****************************************************************************/
4179
4180 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4181                                 char *param, int tpscnt,
4182                                 char *data, int tdscnt,
4183                                 int mdrcnt,int mprcnt,
4184                                 char **rdata,char **rparam,
4185                                 int *rdata_len,int *rparam_len)
4186
4187 {
4188         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4189         char *str2 = skip_string(param,tpscnt,str1);
4190         char *p = skip_string(param,tpscnt,str2);
4191         int uLevel;
4192         struct pack_desc desc;
4193         struct sessionid *session_list;
4194         int i, num_sessions;
4195
4196         if (!str1 || !str2 || !p) {
4197                 return False;
4198         }
4199
4200         memset((char *)&desc,'\0',sizeof(desc));
4201
4202         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4203
4204         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4205         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4206         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4207
4208         /* check it's a supported varient */
4209         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4210                 return False;
4211         }
4212         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4213                 return False;
4214         }
4215
4216         num_sessions = list_sessions(&session_list);
4217
4218         if (mdrcnt > 0) {
4219                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4220                 if (!*rdata) {
4221                         return False;
4222                 }
4223         }
4224         memset((char *)&desc,'\0',sizeof(desc));
4225         desc.base = *rdata;
4226         desc.buflen = mdrcnt;
4227         desc.format = str2;
4228         if (!init_package(&desc,num_sessions,0)) {
4229                 return False;
4230         }
4231
4232         for(i=0; i<num_sessions; i++) {
4233                 PACKS(&desc, "z", session_list[i].remote_machine);
4234                 PACKS(&desc, "z", session_list[i].username);
4235                 PACKI(&desc, "W", 1); /* num conns */
4236                 PACKI(&desc, "W", 0); /* num opens */
4237                 PACKI(&desc, "W", 1); /* num users */
4238                 PACKI(&desc, "D", 0); /* session time */
4239                 PACKI(&desc, "D", 0); /* idle time */
4240                 PACKI(&desc, "D", 0); /* flags */
4241                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4242         }
4243
4244         *rdata_len = desc.usedlen;
4245
4246         *rparam_len = 8;
4247         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4248         if (!*rparam) {
4249                 return False;
4250         }
4251         SSVALS(*rparam,0,desc.errcode);
4252         SSVAL(*rparam,2,0); /* converter */
4253         SSVAL(*rparam,4,num_sessions); /* count */
4254
4255         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4256
4257         return True;
4258 }
4259
4260
4261 /****************************************************************************
4262  The buffer was too small.
4263  ****************************************************************************/
4264
4265 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4266                          int mdrcnt, int mprcnt,
4267                          char **rdata, char **rparam,
4268                          int *rdata_len, int *rparam_len)
4269 {
4270         *rparam_len = MIN(*rparam_len,mprcnt);
4271         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4272         if (!*rparam) {
4273                 return False;
4274         }
4275
4276         *rdata_len = 0;
4277
4278         SSVAL(*rparam,0,NERR_BufTooSmall);
4279
4280         DEBUG(3,("Supplied buffer too small in API command\n"));
4281
4282         return True;
4283 }
4284
4285 /****************************************************************************
4286  The request is not supported.
4287  ****************************************************************************/
4288
4289 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4290                                 char *param, int tpscnt,
4291                                 char *data, int tdscnt,
4292                                 int mdrcnt, int mprcnt,
4293                                 char **rdata, char **rparam,
4294                                 int *rdata_len, int *rparam_len)
4295 {
4296         *rparam_len = 4;
4297         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4298         if (!*rparam) {
4299                 return False;
4300         }
4301
4302         *rdata_len = 0;
4303
4304         SSVAL(*rparam,0,NERR_notsupported);
4305         SSVAL(*rparam,2,0);             /* converter word */
4306
4307         DEBUG(3,("Unsupported API command\n"));
4308
4309         return True;
4310 }
4311
4312 static const struct {
4313         const char *name;
4314         int id;
4315         BOOL (*fn)(connection_struct *, uint16,
4316                         char *, int,
4317                         char *, int,
4318                         int,int,char **,char **,int *,int *);
4319         BOOL auth_user;         /* Deny anonymous access? */
4320 } api_commands[] = {
4321         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
4322         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
4323         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
4324         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
4325         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
4326         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
4327         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
4328         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
4329         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
4330         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
4331         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
4332         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
4333         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
4334         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
4335         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4336         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4337         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4338         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4339         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4340         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4341         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4342         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4343         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4344         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4345         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4346         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4347         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4348         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4349         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4350         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4351         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4352         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4353         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4354         {NULL,          -1,     api_Unsupported}
4355         /*  The following RAP calls are not implemented by Samba:
4356
4357         RAP_WFileEnum2 - anon not OK 
4358         */
4359 };
4360
4361
4362 /****************************************************************************
4363  Handle remote api calls.
4364 ****************************************************************************/
4365
4366 int api_reply(connection_struct *conn,
4367                 uint16 vuid,
4368                 const char *inbuf,
4369                 char *outbuf,
4370                 char *data,
4371                 char *params,
4372                 int tdscnt,
4373                 int tpscnt,
4374                 int mdrcnt,
4375                 int mprcnt)
4376 {
4377         int api_command;
4378         char *rdata = NULL;
4379         char *rparam = NULL;
4380         const char *name1 = NULL;
4381         const char *name2 = NULL;
4382         int rdata_len = 0;
4383         int rparam_len = 0;
4384         BOOL reply=False;
4385         int i;
4386
4387         if (!params) {
4388                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4389                 return 0;
4390         }
4391
4392         if (tpscnt < 2) {
4393                 return 0;
4394         }
4395         api_command = SVAL(params,0);
4396         /* Is there a string at position params+2 ? */
4397         if (skip_string(params,tpscnt,params+2)) {
4398                 name1 = params + 2;
4399         } else {
4400                 name1 = "";
4401         }
4402         name2 = skip_string(params,tpscnt,params+2);
4403         if (!name2) {
4404                 name2 = "";
4405         }
4406
4407         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4408                 api_command,
4409                 name1,
4410                 name2,
4411                 tdscnt,tpscnt,mdrcnt,mprcnt));
4412
4413         for (i=0;api_commands[i].name;i++) {
4414                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4415                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4416                         break;
4417                 }
4418         }
4419
4420         /* Check whether this api call can be done anonymously */
4421
4422         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4423                 user_struct *user = get_valid_user_struct(vuid);
4424
4425                 if (!user || user->guest) {
4426                         return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4427                 }
4428         }
4429
4430         rdata = (char *)SMB_MALLOC(1024);
4431         if (rdata) {
4432                 memset(rdata,'\0',1024);
4433         }
4434
4435         rparam = (char *)SMB_MALLOC(1024);
4436         if (rparam) {
4437                 memset(rparam,'\0',1024);
4438         }
4439
4440         if(!rdata || !rparam) {
4441                 DEBUG(0,("api_reply: malloc fail !\n"));
4442                 SAFE_FREE(rdata);
4443                 SAFE_FREE(rparam);
4444                 return -1;
4445         }
4446
4447         reply = api_commands[i].fn(conn,
4448                                 vuid,
4449                                 params,tpscnt,  /* params + length */
4450                                 data,tdscnt,    /* data + length */
4451                                 mdrcnt,mprcnt,
4452                                 &rdata,&rparam,&rdata_len,&rparam_len);
4453
4454
4455         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4456                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4457                                         &rdata,&rparam,&rdata_len,&rparam_len);
4458         }
4459
4460         /* if we get False back then it's actually unsupported */
4461         if (!reply) {
4462                 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4463                         &rdata,&rparam,&rdata_len,&rparam_len);
4464         }
4465
4466         /* If api_Unsupported returns false we can't return anything. */
4467         if (reply) {
4468                 send_trans_reply(inbuf,
4469                                 outbuf,
4470                                 rparam,
4471                                 rparam_len,
4472                                 rdata,
4473                                 rdata_len,
4474                                 False);
4475         }
4476
4477         SAFE_FREE(rdata);
4478         SAFE_FREE(rparam);
4479         return -1;
4480 }