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