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