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