r22042: Try and clean up my own mess using the API Volker
[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_str_ptr(param,tpscnt,param,2);
781         char *str2 = skip_string(param,tpscnt,str1,1);
782         char *p = skip_string(param,tpscnt,str2,1);
783         char *QueueName = p;
784         unsigned int uLevel;
785         int count=0;
786         int snum;
787         char *str3;
788         struct pack_desc desc;
789         print_queue_struct *queue=NULL;
790         print_status_struct status;
791         char* tmpdata=NULL;
792
793         if (!str1 || !str2 || !p) {
794                 return False;
795         }
796         memset((char *)&status,'\0',sizeof(status));
797         memset((char *)&desc,'\0',sizeof(desc));
798
799         p = skip_string(param,tpscnt,p,1);
800         if (!p) {
801                 return False;
802         }
803         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
804         str3 = get_safe_str_ptr(param,tpscnt,p,4);
805         if (!str3) {
806                 return False;
807         }
808
809         /* remove any trailing username */
810         if ((p = strchr_m(QueueName,'%')))
811                 *p = 0;
812  
813         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
814  
815         /* check it's a supported varient */
816         if (!prefix_ok(str1,"zWrLh"))
817                 return False;
818         if (!check_printq_info(&desc,uLevel,str2,str3)) {
819                 /*
820                  * Patch from Scott Moomaw <scott@bridgewater.edu>
821                  * to return the 'invalid info level' error if an
822                  * unknown level was requested.
823                  */
824                 *rdata_len = 0;
825                 *rparam_len = 6;
826                 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
827                 if (!*rparam) {
828                         return False;
829                 }
830                 SSVALS(*rparam,0,ERRunknownlevel);
831                 SSVAL(*rparam,2,0);
832                 SSVAL(*rparam,4,0);
833                 return(True);
834         }
835  
836         snum = find_service(QueueName);
837         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
838                 return False;
839                 
840         if (uLevel==52) {
841                 count = get_printerdrivernumber(snum);
842                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
843         } else {
844                 count = print_queue_status(snum, &queue,&status);
845         }
846
847         if (mdrcnt > 0) {
848                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
849                 if (!*rdata) {
850                         return False;
851                 }
852                 desc.base = *rdata;
853                 desc.buflen = mdrcnt;
854         } else {
855                 /*
856                  * Don't return data but need to get correct length
857                  * init_package will return wrong size if buflen=0
858                  */
859                 desc.buflen = getlen(desc.format);
860                 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
861         }
862
863         if (init_package(&desc,1,count)) {
864                 desc.subcount = count;
865                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
866         }
867
868         *rdata_len = desc.usedlen;
869   
870         /*
871          * We must set the return code to ERRbuftoosmall
872          * in order to support lanman style printing with Win NT/2k
873          * clients       --jerry
874          */
875         if (!mdrcnt && lp_disable_spoolss())
876                 desc.errcode = ERRbuftoosmall;
877  
878         *rdata_len = desc.usedlen;
879         *rparam_len = 6;
880         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
881         if (!*rparam) {
882                 return False;
883         }
884         SSVALS(*rparam,0,desc.errcode);
885         SSVAL(*rparam,2,0);
886         SSVAL(*rparam,4,desc.neededlen);
887   
888         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
889
890         SAFE_FREE(queue);
891         SAFE_FREE(tmpdata);
892
893         return(True);
894 }
895
896 /****************************************************************************
897  View list of all print jobs on all queues.
898 ****************************************************************************/
899
900 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
901                                 char *param, int tpscnt,
902                                 char *data, int tdscnt,
903                                 int mdrcnt, int mprcnt,
904                                 char **rdata, char** rparam,
905                                 int *rdata_len, int *rparam_len)
906 {
907         char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
908         char *output_format1 = skip_string(param,tpscnt,param_format,1);
909         char *p = skip_string(param,tpscnt,output_format1,1);
910         unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
911         char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
912         int services = lp_numservices();
913         int i, n;
914         struct pack_desc desc;
915         print_queue_struct **queue = NULL;
916         print_status_struct *status = NULL;
917         int *subcntarr = NULL;
918         int queuecnt = 0, subcnt = 0, succnt = 0;
919  
920         if (!param_format || !output_format1 || !p || !output_format2) {
921                 return False;
922         }
923
924         uLevel = SVAL(p,0);
925         output_format2 = p + 4;
926
927         memset((char *)&desc,'\0',sizeof(desc));
928
929         DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
930  
931         if (!prefix_ok(param_format,"WrLeh")) {
932                 return False;
933         }
934         if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
935                 /*
936                  * Patch from Scott Moomaw <scott@bridgewater.edu>
937                  * to return the 'invalid info level' error if an
938                  * unknown level was requested.
939                  */
940                 *rdata_len = 0;
941                 *rparam_len = 6;
942                 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
943                 if (!*rparam) {
944                         return False;
945                 }
946                 SSVALS(*rparam,0,ERRunknownlevel);
947                 SSVAL(*rparam,2,0);
948                 SSVAL(*rparam,4,0);
949                 return(True);
950         }
951
952         for (i = 0; i < services; i++) {
953                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
954                         queuecnt++;
955                 }
956         }
957
958         if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
959                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
960                 goto err;
961         }
962         memset(queue,0,queuecnt*sizeof(print_queue_struct*));
963         if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
964                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
965                 goto err;
966         }
967         memset(status,0,queuecnt*sizeof(print_status_struct));
968         if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
969                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
970                 goto err;
971         }
972
973         subcnt = 0;
974         n = 0;
975         for (i = 0; i < services; i++) {
976                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
977                         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
978                         subcnt += subcntarr[n];
979                         n++;
980                 }
981         }
982
983         if (mdrcnt > 0) {
984                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
985                 if (!*rdata) {
986                         goto err;
987                 }
988         }
989         desc.base = *rdata;
990         desc.buflen = mdrcnt;
991
992         if (init_package(&desc,queuecnt,subcnt)) {
993                 n = 0;
994                 succnt = 0;
995                 for (i = 0; i < services; i++) {
996                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
997                                 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
998                                 n++;
999                                 if (desc.errcode == NERR_Success) {
1000                                         succnt = n;
1001                                 }
1002                         }
1003                 }
1004         }
1005
1006         SAFE_FREE(subcntarr);
1007  
1008         *rdata_len = desc.usedlen;
1009         *rparam_len = 8;
1010         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1011         if (!*rparam) {
1012                 goto err;
1013         }
1014         SSVALS(*rparam,0,desc.errcode);
1015         SSVAL(*rparam,2,0);
1016         SSVAL(*rparam,4,succnt);
1017         SSVAL(*rparam,6,queuecnt);
1018   
1019         for (i = 0; i < queuecnt; i++) {
1020                 if (queue) {
1021                         SAFE_FREE(queue[i]);
1022                 }
1023         }
1024
1025         SAFE_FREE(queue);
1026         SAFE_FREE(status);
1027   
1028         return True;
1029
1030   err:
1031
1032         SAFE_FREE(subcntarr);
1033         for (i = 0; i < queuecnt; i++) {
1034                 if (queue) {
1035                         SAFE_FREE(queue[i]);
1036                 }
1037         }
1038         SAFE_FREE(queue);
1039         SAFE_FREE(status);
1040
1041         return False;
1042 }
1043
1044 /****************************************************************************
1045  Get info level for a server list query.
1046 ****************************************************************************/
1047
1048 static BOOL check_server_info(int uLevel, char* id)
1049 {
1050         switch( uLevel ) {
1051                 case 0:
1052                         if (strcmp(id,"B16") != 0) {
1053                                 return False;
1054                         }
1055                         break;
1056                 case 1:
1057                         if (strcmp(id,"B16BBDz") != 0) {
1058                                 return False;
1059                         }
1060                         break;
1061                 default: 
1062                         return False;
1063         }
1064         return True;
1065 }
1066
1067 struct srv_info_struct {
1068         fstring name;
1069         uint32 type;
1070         fstring comment;
1071         fstring domain;
1072         BOOL server_added;
1073 };
1074
1075 /*******************************************************************
1076  Get server info lists from the files saved by nmbd. Return the
1077  number of entries.
1078 ******************************************************************/
1079
1080 static int get_server_info(uint32 servertype, 
1081                            struct srv_info_struct **servers,
1082                            const char *domain)
1083 {
1084         int count=0;
1085         int alloced=0;
1086         char **lines;
1087         BOOL local_list_only;
1088         int i;
1089
1090         lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1091         if (!lines) {
1092                 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1093                 return 0;
1094         }
1095
1096         /* request for everything is code for request all servers */
1097         if (servertype == SV_TYPE_ALL) {
1098                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1099         }
1100
1101         local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1102
1103         DEBUG(4,("Servertype search: %8x\n",servertype));
1104
1105         for (i=0;lines[i];i++) {
1106                 fstring stype;
1107                 struct srv_info_struct *s;
1108                 const char *ptr = lines[i];
1109                 BOOL ok = True;
1110
1111                 if (!*ptr) {
1112                         continue;
1113                 }
1114     
1115                 if (count == alloced) {
1116                         alloced += 10;
1117                         *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1118                         if (!*servers) {
1119                                 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1120                                 file_lines_free(lines);
1121                                 return 0;
1122                         }
1123                         memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1124                 }
1125                 s = &(*servers)[count];
1126     
1127                 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1128                         continue;
1129                 }
1130                 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1131                         continue;
1132                 }
1133                 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1134                         continue;
1135                 }
1136                 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1137                         /* this allows us to cope with an old nmbd */
1138                         fstrcpy(s->domain,lp_workgroup()); 
1139                 }
1140     
1141                 if (sscanf(stype,"%X",&s->type) != 1) { 
1142                         DEBUG(4,("r:host file ")); 
1143                         ok = False; 
1144                 }
1145     
1146                 /* Filter the servers/domains we return based on what was asked for. */
1147
1148                 /* Check to see if we are being asked for a local list only. */
1149                 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1150                         DEBUG(4,("r: local list only"));
1151                         ok = False;
1152                 }
1153
1154                 /* doesn't match up: don't want it */
1155                 if (!(servertype & s->type)) { 
1156                         DEBUG(4,("r:serv type ")); 
1157                         ok = False; 
1158                 }
1159     
1160                 if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1161                                 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1162                         DEBUG(4,("s: dom mismatch "));
1163                         ok = False;
1164                 }
1165     
1166                 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1167                         ok = False;
1168                 }
1169     
1170                 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1171                 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1172
1173                 if (ok) {
1174                         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1175                                 s->name, s->type, s->comment, s->domain));
1176                         s->server_added = True;
1177                         count++;
1178                 } else {
1179                         DEBUG(4,("%20s %8x %25s %15s\n",
1180                                 s->name, s->type, s->comment, s->domain));
1181                 }
1182         }
1183   
1184         file_lines_free(lines);
1185         return count;
1186 }
1187
1188 /*******************************************************************
1189  Fill in a server info structure.
1190 ******************************************************************/
1191
1192 static int fill_srv_info(struct srv_info_struct *service, 
1193                          int uLevel, char **buf, int *buflen, 
1194                          char **stringbuf, int *stringspace, char *baseaddr)
1195 {
1196         int struct_len;
1197         char* p;
1198         char* p2;
1199         int l2;
1200         int len;
1201  
1202         switch (uLevel) {
1203                 case 0:
1204                         struct_len = 16;
1205                         break;
1206                 case 1:
1207                         struct_len = 26;
1208                         break;
1209                 default:
1210                         return -1;
1211         }
1212  
1213         if (!buf) {
1214                 len = 0;
1215                 switch (uLevel) {
1216                         case 1:
1217                                 len = strlen(service->comment)+1;
1218                                 break;
1219                 }
1220
1221                 *buflen = struct_len;
1222                 *stringspace = len;
1223                 return struct_len + len;
1224         }
1225   
1226         len = struct_len;
1227         p = *buf;
1228         if (*buflen < struct_len) {
1229                 return -1;
1230         }
1231         if (stringbuf) {
1232                 p2 = *stringbuf;
1233                 l2 = *stringspace;
1234         } else {
1235                 p2 = p + struct_len;
1236                 l2 = *buflen - struct_len;
1237         }
1238         if (!baseaddr) {
1239                 baseaddr = p;
1240         }
1241   
1242         switch (uLevel) {
1243                 case 0:
1244                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1245                         break;
1246
1247                 case 1:
1248                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1249                         SIVAL(p,18,service->type);
1250                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1251                         len += CopyAndAdvance(&p2,service->comment,&l2);
1252                         break;
1253         }
1254
1255         if (stringbuf) {
1256                 *buf = p + struct_len;
1257                 *buflen -= struct_len;
1258                 *stringbuf = p2;
1259                 *stringspace = l2;
1260         } else {
1261                 *buf = p2;
1262                 *buflen -= len;
1263         }
1264         return len;
1265 }
1266
1267
1268 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1269 {
1270         return(strcmp(s1->name,s2->name));
1271 }
1272
1273 /****************************************************************************
1274  View list of servers available (or possibly domains). The info is
1275  extracted from lists saved by nmbd on the local host.
1276 ****************************************************************************/
1277
1278 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1279                                 char *param, int tpscnt,
1280                                 char *data, int tdscnt,
1281                                 int mdrcnt, int mprcnt, char **rdata, 
1282                                 char **rparam, int *rdata_len, int *rparam_len)
1283 {
1284         char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1285         char *str2 = skip_string(param,tpscnt,str1,1);
1286         char *p = skip_string(param,tpscnt,str2,1);
1287         int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1288         int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1289         uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1290         char *p2;
1291         int data_len, fixed_len, string_len;
1292         int f_len = 0, s_len = 0;
1293         struct srv_info_struct *servers=NULL;
1294         int counted=0,total=0;
1295         int i,missed;
1296         fstring domain;
1297         BOOL domain_request;
1298         BOOL local_request;
1299
1300         if (!str1 || !str2 || !p) {
1301                 return False;
1302         }
1303
1304         /* If someone sets all the bits they don't really mean to set
1305            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1306            known servers. */
1307
1308         if (servertype == SV_TYPE_ALL) {
1309                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1310         }
1311
1312         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1313            any other bit (they may just set this bit on it's own) they 
1314            want all the locally seen servers. However this bit can be 
1315            set on its own so set the requested servers to be 
1316            ALL - DOMAIN_ENUM. */
1317
1318         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1319                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1320         }
1321
1322         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1323         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1324
1325         p += 8;
1326
1327         if (!prefix_ok(str1,"WrLehD")) {
1328                 return False;
1329         }
1330         if (!check_server_info(uLevel,str2)) {
1331                 return False;
1332         }
1333   
1334         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1335         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1336         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1337
1338         if (strcmp(str1, "WrLehDz") == 0) {
1339                 if (skip_string(param,tpscnt,p,1) == NULL) {
1340                         return False;
1341                 }
1342                 pull_ascii_fstring(domain, p);
1343         } else {
1344                 fstrcpy(domain, lp_workgroup());
1345         }
1346
1347         if (lp_browse_list()) {
1348                 total = get_server_info(servertype,&servers,domain);
1349         }
1350
1351         data_len = fixed_len = string_len = 0;
1352         missed = 0;
1353
1354         if (total > 0) {
1355                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1356         }
1357
1358         {
1359                 char *lastname=NULL;
1360
1361                 for (i=0;i<total;i++) {
1362                         struct srv_info_struct *s = &servers[i];
1363
1364                         if (lastname && strequal(lastname,s->name)) {
1365                                 continue;
1366                         }
1367                         lastname = s->name;
1368                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1369                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1370                                 s->name, s->type, s->comment, s->domain));
1371       
1372                         if (data_len <= buf_len) {
1373                                 counted++;
1374                                 fixed_len += f_len;
1375                                 string_len += s_len;
1376                         } else {
1377                                 missed++;
1378                         }
1379                 }
1380         }
1381
1382         *rdata_len = fixed_len + string_len;
1383         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1384         if (!*rdata) {
1385                 return False;
1386         }
1387         memset(*rdata,'\0',*rdata_len);
1388   
1389         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1390         p = *rdata;
1391         f_len = fixed_len;
1392         s_len = string_len;
1393
1394         {
1395                 char *lastname=NULL;
1396                 int count2 = counted;
1397
1398                 for (i = 0; i < total && count2;i++) {
1399                         struct srv_info_struct *s = &servers[i];
1400
1401                         if (lastname && strequal(lastname,s->name)) {
1402                                 continue;
1403                         }
1404                         lastname = s->name;
1405                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1406                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1407                                 s->name, s->type, s->comment, s->domain));
1408                         count2--;
1409                 }
1410         }
1411   
1412         *rparam_len = 8;
1413         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1414         if (!*rparam) {
1415                 return False;
1416         }
1417         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1418         SSVAL(*rparam,2,0);
1419         SSVAL(*rparam,4,counted);
1420         SSVAL(*rparam,6,counted+missed);
1421
1422         SAFE_FREE(servers);
1423
1424         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1425                 domain,uLevel,counted,counted+missed));
1426
1427         return True;
1428 }
1429
1430 /****************************************************************************
1431   command 0x34 - suspected of being a "Lookup Names" stub api
1432   ****************************************************************************/
1433
1434 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1435                                 char *param, int tpscnt,
1436                                 char *data, int tdscnt,
1437                                 int mdrcnt, int mprcnt, char **rdata, 
1438                                 char **rparam, int *rdata_len, int *rparam_len)
1439 {
1440         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1441         char *str2 = skip_string(param,tpscnt,str1,1);
1442         char *p = skip_string(param,tpscnt,str2,1);
1443         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1444         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1445         int counted=0;
1446         int missed=0;
1447
1448         if (!str1 || !str2 || !p) {
1449                 return False;
1450         }
1451
1452         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1453                 str1, str2, p, uLevel, buf_len));
1454
1455         if (!prefix_ok(str1,"zWrLeh")) {
1456                 return False;
1457         }
1458   
1459         *rdata_len = 0;
1460   
1461         *rparam_len = 8;
1462         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1463         if (!*rparam) {
1464                 return False;
1465         }
1466
1467         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1468         SSVAL(*rparam,2,0);
1469         SSVAL(*rparam,4,counted);
1470         SSVAL(*rparam,6,counted+missed);
1471
1472         return True;
1473 }
1474
1475 /****************************************************************************
1476   get info about a share
1477   ****************************************************************************/
1478
1479 static BOOL check_share_info(int uLevel, char* id)
1480 {
1481         switch( uLevel ) {
1482                 case 0:
1483                         if (strcmp(id,"B13") != 0) {
1484                                 return False;
1485                         }
1486                         break;
1487                 case 1:
1488                         if (strcmp(id,"B13BWz") != 0) {
1489                                 return False;
1490                         }
1491                         break;
1492                 case 2:
1493                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1494                                 return False;
1495                         }
1496                         break;
1497                 case 91:
1498                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1499                                 return False;
1500                         }
1501                         break;
1502                 default:
1503                         return False;
1504         }
1505         return True;
1506 }
1507
1508 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1509                            char** buf, int* buflen,
1510                            char** stringbuf, int* stringspace, char* baseaddr)
1511 {
1512         int struct_len;
1513         char* p;
1514         char* p2;
1515         int l2;
1516         int len;
1517  
1518         switch( uLevel ) {
1519                 case 0:
1520                         struct_len = 13;
1521                         break;
1522                 case 1:
1523                         struct_len = 20;
1524                         break;
1525                 case 2:
1526                         struct_len = 40;
1527                         break;
1528                 case 91:
1529                         struct_len = 68;
1530                         break;
1531                 default:
1532                         return -1;
1533         }
1534   
1535  
1536         if (!buf) {
1537                 len = 0;
1538
1539                 if (uLevel > 0) {
1540                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1541                 }
1542                 if (uLevel > 1) {
1543                         len += strlen(lp_pathname(snum)) + 1;
1544                 }
1545                 if (buflen) {
1546                         *buflen = struct_len;
1547                 }
1548                 if (stringspace) {
1549                         *stringspace = len;
1550                 }
1551                 return struct_len + len;
1552         }
1553   
1554         len = struct_len;
1555         p = *buf;
1556         if ((*buflen) < struct_len) {
1557                 return -1;
1558         }
1559
1560         if (stringbuf) {
1561                 p2 = *stringbuf;
1562                 l2 = *stringspace;
1563         } else {
1564                 p2 = p + struct_len;
1565                 l2 = (*buflen) - struct_len;
1566         }
1567
1568         if (!baseaddr) {
1569                 baseaddr = p;
1570         }
1571   
1572         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1573   
1574         if (uLevel > 0) {
1575                 int type;
1576
1577                 SCVAL(p,13,0);
1578                 type = STYPE_DISKTREE;
1579                 if (lp_print_ok(snum)) {
1580                         type = STYPE_PRINTQ;
1581                 }
1582                 if (strequal("IPC",lp_fstype(snum))) {
1583                         type = STYPE_IPC;
1584                 }
1585                 SSVAL(p,14,type);               /* device type */
1586                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1587                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1588         }
1589   
1590         if (uLevel > 1) {
1591                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1592                 SSVALS(p,22,-1);                /* max uses */
1593                 SSVAL(p,24,1); /* current uses */
1594                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1595                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1596                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1597         }
1598   
1599         if (uLevel > 2) {
1600                 memset(p+40,0,SHPWLEN+2);
1601                 SSVAL(p,50,0);
1602                 SIVAL(p,52,0);
1603                 SSVAL(p,56,0);
1604                 SSVAL(p,58,0);
1605                 SIVAL(p,60,0);
1606                 SSVAL(p,64,0);
1607                 SSVAL(p,66,0);
1608         }
1609        
1610         if (stringbuf) {
1611                 (*buf) = p + struct_len;
1612                 (*buflen) -= struct_len;
1613                 (*stringbuf) = p2;
1614                 (*stringspace) = l2;
1615         } else {
1616                 (*buf) = p2;
1617                 (*buflen) -= len;
1618         }
1619
1620         return len;
1621 }
1622
1623 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1624                                 char *param, int tpscnt,
1625                                 char *data, int tdscnt,
1626                                 int mdrcnt,int mprcnt,
1627                                 char **rdata,char **rparam,
1628                                 int *rdata_len,int *rparam_len)
1629 {
1630         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1631         char *str2 = skip_string(param,tpscnt,str1,1);
1632         char *netname = skip_string(param,tpscnt,str2,1);
1633         char *p = skip_string(param,tpscnt,netname,1);
1634         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1635         int snum;
1636   
1637         if (!str1 || !str2 || !netname || !p) {
1638                 return False;
1639         }
1640
1641         snum = find_service(netname);
1642         if (snum < 0) {
1643                 return False;
1644         }
1645   
1646         /* check it's a supported varient */
1647         if (!prefix_ok(str1,"zWrLh")) {
1648                 return False;
1649         }
1650         if (!check_share_info(uLevel,str2)) {
1651                 return False;
1652         }
1653  
1654         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1655         if (!*rdata) {
1656                 return False;
1657         }
1658         p = *rdata;
1659         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1660         if (*rdata_len < 0) {
1661                 return False;
1662         }
1663  
1664         *rparam_len = 6;
1665         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1666         if (!*rparam) {
1667                 return False;
1668         }
1669         SSVAL(*rparam,0,NERR_Success);
1670         SSVAL(*rparam,2,0);             /* converter word */
1671         SSVAL(*rparam,4,*rdata_len);
1672  
1673         return True;
1674 }
1675
1676 /****************************************************************************
1677   View the list of available shares.
1678
1679   This function is the server side of the NetShareEnum() RAP call.
1680   It fills the return buffer with share names and share comments.
1681   Note that the return buffer normally (in all known cases) allows only
1682   twelve byte strings for share names (plus one for a nul terminator).
1683   Share names longer than 12 bytes must be skipped.
1684  ****************************************************************************/
1685
1686 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1687                                 char *param, int tpscnt,
1688                                 char *data, int tdscnt,
1689                                 int                mdrcnt,
1690                                 int                mprcnt,
1691                                 char             **rdata,
1692                                 char             **rparam,
1693                                 int               *rdata_len,
1694                                 int               *rparam_len )
1695 {
1696         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1697         char *str2 = skip_string(param,tpscnt,str1,1);
1698         char *p = skip_string(param,tpscnt,str2,1);
1699         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1700         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1701         char *p2;
1702         int count = 0;
1703         int total=0,counted=0;
1704         BOOL missed = False;
1705         int i;
1706         int data_len, fixed_len, string_len;
1707         int f_len = 0, s_len = 0;
1708  
1709         if (!str1 || !str2 || !p) {
1710                 return False;
1711         }
1712
1713         if (!prefix_ok(str1,"WrLeh")) {
1714                 return False;
1715         }
1716         if (!check_share_info(uLevel,str2)) {
1717                 return False;
1718         }
1719   
1720         /* Ensure all the usershares are loaded. */
1721         become_root();
1722         load_registry_shares();
1723         count = load_usershare_shares();
1724         unbecome_root();
1725
1726         data_len = fixed_len = string_len = 0;
1727         for (i=0;i<count;i++) {
1728                 fstring servicename_dos;
1729                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1730                         continue;
1731                 }
1732                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1733                 /* Maximum name length = 13. */
1734                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1735                         total++;
1736                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1737                         if (data_len <= buf_len) {
1738                                 counted++;
1739                                 fixed_len += f_len;
1740                                 string_len += s_len;
1741                         } else {
1742                                 missed = True;
1743                         }
1744                 }
1745         }
1746
1747         *rdata_len = fixed_len + string_len;
1748         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1749         if (!*rdata) {
1750                 return False;
1751         }
1752         memset(*rdata,0,*rdata_len);
1753   
1754         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1755         p = *rdata;
1756         f_len = fixed_len;
1757         s_len = string_len;
1758
1759         for( i = 0; i < count; i++ ) {
1760                 fstring servicename_dos;
1761                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1762                         continue;
1763                 }
1764
1765                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1766                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1767                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1768                                 break;
1769                         }
1770                 }
1771         }
1772   
1773         *rparam_len = 8;
1774         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1775         if (!*rparam) {
1776                 return False;
1777         }
1778         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1779         SSVAL(*rparam,2,0);
1780         SSVAL(*rparam,4,counted);
1781         SSVAL(*rparam,6,total);
1782   
1783         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1784                 counted,total,uLevel,
1785                 buf_len,*rdata_len,mdrcnt));
1786
1787         return True;
1788 }
1789
1790 /****************************************************************************
1791   Add a share
1792   ****************************************************************************/
1793
1794 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1795                                 char *param, int tpscnt,
1796                                 char *data, int tdscnt,
1797                                 int mdrcnt,int mprcnt,
1798                                 char **rdata,char **rparam,
1799                                 int *rdata_len,int *rparam_len)
1800 {
1801         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1802         char *str2 = skip_string(param,tpscnt,str1,1);
1803         char *p = skip_string(param,tpscnt,str2,1);
1804         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1805         fstring sharename;
1806         fstring comment;
1807         pstring pathname;
1808         char *command, *cmdname;
1809         unsigned int offset;
1810         int snum;
1811         int res = ERRunsup;
1812   
1813         if (!str1 || !str2 || !p) {
1814                 return False;
1815         }
1816
1817         /* check it's a supported varient */
1818         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1819                 return False;
1820         }
1821         if (!check_share_info(uLevel,str2)) {
1822                 return False;
1823         }
1824         if (uLevel != 2) {
1825                 return False;
1826         }
1827
1828         /* Do we have a string ? */
1829         if (skip_string(data,mdrcnt,data,1) == NULL) {
1830                 return False;
1831         }
1832         pull_ascii_fstring(sharename,data);
1833         snum = find_service(sharename);
1834         if (snum >= 0) { /* already exists */
1835                 res = ERRfilexists;
1836                 goto error_exit;
1837         }
1838
1839         if (mdrcnt < 28) {
1840                 return False;
1841         }
1842
1843         /* only support disk share adds */
1844         if (SVAL(data,14)!=STYPE_DISKTREE) {
1845                 return False;
1846         }
1847
1848         offset = IVAL(data, 16);
1849         if (offset >= mdrcnt) {
1850                 res = ERRinvalidparam;
1851                 goto error_exit;
1852         }
1853
1854         /* Do we have a string ? */
1855         if (skip_string(data,mdrcnt,data+offset,1) == NULL) {
1856                 return False;
1857         }
1858         pull_ascii_fstring(comment, offset? (data+offset) : "");
1859
1860         offset = IVAL(data, 26);
1861
1862         if (offset >= mdrcnt) {
1863                 res = ERRinvalidparam;
1864                 goto error_exit;
1865         }
1866
1867         /* Do we have a string ? */
1868         if (skip_string(data,mdrcnt,data+offset,1) == NULL) {
1869                 return False;
1870         }
1871         pull_ascii_pstring(pathname, offset? (data+offset) : "");
1872
1873         string_replace(sharename, '"', ' ');
1874         string_replace(pathname, '"', ' ');
1875         string_replace(comment, '"', ' ');
1876
1877         cmdname = lp_add_share_cmd();
1878
1879         if (!cmdname || *cmdname == '\0') {
1880                 return False;
1881         }
1882
1883         asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1884                 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1885
1886         if (command) {
1887                 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1888
1889                 if ((res = smbrun(command, NULL)) != 0) {
1890                         DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1891                         SAFE_FREE(command);
1892                         res = ERRnoaccess;
1893                         goto error_exit;
1894                 } else {
1895                         SAFE_FREE(command);
1896                         message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1897                 }
1898         } else {
1899                 return False;
1900         }
1901
1902         *rparam_len = 6;
1903         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1904         if (!*rparam) {
1905                 return False;
1906         }
1907         SSVAL(*rparam,0,NERR_Success);
1908         SSVAL(*rparam,2,0);             /* converter word */
1909         SSVAL(*rparam,4,*rdata_len);
1910         *rdata_len = 0;
1911   
1912         return True;
1913
1914   error_exit:
1915
1916         *rparam_len = 4;
1917         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1918         if (!*rparam) {
1919                 return False;
1920         }
1921         *rdata_len = 0;
1922         SSVAL(*rparam,0,res);
1923         SSVAL(*rparam,2,0);
1924         return True;
1925 }
1926
1927 /****************************************************************************
1928   view list of groups available
1929   ****************************************************************************/
1930
1931 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1932                                 char *param, int tpscnt,
1933                                 char *data, int tdscnt,
1934                                 int mdrcnt,int mprcnt,
1935                                 char **rdata,char **rparam,
1936                                 int *rdata_len,int *rparam_len)
1937 {
1938         int i;
1939         int errflags=0;
1940         int resume_context, cli_buf_size;
1941         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1942         char *str2 = skip_string(param,tpscnt,str1,1);
1943         char *p = skip_string(param,tpscnt,str2,1);
1944
1945         struct pdb_search *search;
1946         struct samr_displayentry *entries;
1947
1948         int num_entries;
1949  
1950         if (!str1 || !str2 || !p) {
1951                 return False;
1952         }
1953
1954         if (strcmp(str1,"WrLeh") != 0) {
1955                 return False;
1956         }
1957
1958         /* parameters  
1959          * W-> resume context (number of users to skip)
1960          * r -> return parameter pointer to receive buffer 
1961          * L -> length of receive buffer
1962          * e -> return parameter number of entries
1963          * h -> return parameter total number of users
1964          */
1965
1966         if (strcmp("B21",str2) != 0) {
1967                 return False;
1968         }
1969
1970         /* get list of domain groups SID_DOMAIN_GRP=2 */
1971         become_root();
1972         search = pdb_search_groups();
1973         unbecome_root();
1974
1975         if (search == NULL) {
1976                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1977                 return False;
1978         }
1979
1980         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1981         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1982         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1983                   "%d\n", resume_context, cli_buf_size));
1984
1985         become_root();
1986         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1987                                          &entries);
1988         unbecome_root();
1989
1990         *rdata_len = cli_buf_size;
1991         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1992         if (!*rdata) {
1993                 return False;
1994         }
1995
1996         p = *rdata;
1997
1998         for(i=0; i<num_entries; i++) {
1999                 fstring name;
2000                 fstrcpy(name, entries[i].account_name);
2001                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2002                         /* truncate the name at 21 chars. */
2003                         memcpy(p, name, 21); 
2004                         DEBUG(10,("adding entry %d group %s\n", i, p));
2005                         p += 21;
2006                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
2007                                    No idea why... */
2008                 } else {
2009                         /* set overflow error */
2010                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
2011                         errflags=234;
2012                         break;
2013                 }
2014         }
2015
2016         pdb_search_destroy(search);
2017
2018         *rdata_len = PTR_DIFF(p,*rdata);
2019
2020         *rparam_len = 8;
2021         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2022         if (!*rparam) {
2023                 return False;
2024         }
2025         SSVAL(*rparam, 0, errflags);
2026         SSVAL(*rparam, 2, 0);           /* converter word */
2027         SSVAL(*rparam, 4, i);   /* is this right?? */
2028         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
2029
2030         return(True);
2031 }
2032
2033 /*******************************************************************
2034  Get groups that a user is a member of.
2035 ******************************************************************/
2036
2037 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2038                                 char *param, int tpscnt,
2039                                 char *data, int tdscnt,
2040                                 int mdrcnt,int mprcnt,
2041                                 char **rdata,char **rparam,
2042                                 int *rdata_len,int *rparam_len)
2043 {
2044         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2045         char *str2 = skip_string(param,tpscnt,str1,1);
2046         char *UserName = skip_string(param,tpscnt,str2,1);
2047         char *p = skip_string(param,tpscnt,UserName,1);
2048         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2049         const char *level_string;
2050         int count=0;
2051         struct samu *sampw = NULL;
2052         BOOL ret = False;
2053         DOM_SID *sids;
2054         gid_t *gids;
2055         size_t num_groups;
2056         size_t i;
2057         NTSTATUS result;
2058         DOM_SID user_sid;
2059         enum lsa_SidType type;
2060         TALLOC_CTX *mem_ctx;
2061
2062         if (!str1 || !str2 || !UserName || !p) {
2063                 return False;
2064         }
2065
2066         *rparam_len = 8;
2067         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2068         if (!*rparam) {
2069                 return False;
2070         }
2071   
2072         /* check it's a supported varient */
2073         
2074         if ( strcmp(str1,"zWrLeh") != 0 )
2075                 return False;
2076                 
2077         switch( uLevel ) {
2078                 case 0:
2079                         level_string = "B21";
2080                         break;
2081                 default:
2082                         return False;
2083         }
2084
2085         if (strcmp(level_string,str2) != 0)
2086                 return False;
2087
2088         *rdata_len = mdrcnt + 1024;
2089         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2090         if (!*rdata) {
2091                 return False;
2092         }
2093         SSVAL(*rparam,0,NERR_Success);
2094         SSVAL(*rparam,2,0);             /* converter word */
2095
2096         p = *rdata;
2097
2098         mem_ctx = talloc_new(NULL);
2099         if (mem_ctx == NULL) {
2100                 DEBUG(0, ("talloc_new failed\n"));
2101                 return False;
2102         }
2103
2104         if ( !(sampw = samu_new(mem_ctx)) ) {
2105                 DEBUG(0, ("samu_new() failed!\n"));
2106                 TALLOC_FREE(mem_ctx);
2107                 return False;
2108         }
2109
2110         /* Lookup the user information; This should only be one of 
2111            our accounts (not remote domains) */
2112
2113         become_root();                                  /* ROOT BLOCK */
2114
2115         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2116                          NULL, NULL, &user_sid, &type)) {
2117                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2118                 goto done;
2119         }
2120
2121         if (type != SID_NAME_USER) {
2122                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2123                            sid_type_lookup(type)));
2124                 goto done;
2125         }
2126
2127         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2128                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2129                            sid_string_static(&user_sid), UserName));
2130                 goto done;
2131         }
2132
2133         gids = NULL;
2134         sids = NULL;
2135         num_groups = 0;
2136
2137         result = pdb_enum_group_memberships(mem_ctx, sampw,
2138                                             &sids, &gids, &num_groups);
2139
2140         if (!NT_STATUS_IS_OK(result)) {
2141                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2142                            UserName));
2143                 goto done;
2144         }
2145
2146         for (i=0; i<num_groups; i++) {
2147
2148                 const char *grp_name;
2149         
2150                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2151                         pstrcpy(p, grp_name);
2152                         p += 21; 
2153                         count++;
2154                 }
2155         }
2156
2157         *rdata_len = PTR_DIFF(p,*rdata);
2158
2159         SSVAL(*rparam,4,count); /* is this right?? */
2160         SSVAL(*rparam,6,count); /* is this right?? */
2161
2162         ret = True;
2163
2164 done:
2165         unbecome_root();                                /* END ROOT BLOCK */
2166
2167         TALLOC_FREE(mem_ctx);
2168
2169         return ret;
2170 }
2171
2172 /*******************************************************************
2173  Get all users.
2174 ******************************************************************/
2175
2176 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2177                                 char *param, int tpscnt,
2178                                 char *data, int tdscnt,
2179                                 int mdrcnt,int mprcnt,
2180                                 char **rdata,char **rparam,
2181                                 int *rdata_len,int *rparam_len)
2182 {
2183         int count_sent=0;
2184         int num_users=0;
2185         int errflags=0;
2186         int i, resume_context, cli_buf_size;
2187         struct pdb_search *search;
2188         struct samr_displayentry *users;
2189
2190         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2191         char *str2 = skip_string(param,tpscnt,str1,1);
2192         char *p = skip_string(param,tpscnt,str2,1);
2193
2194         if (!str1 || !str2 || !p) {
2195                 return False;
2196         }
2197
2198         if (strcmp(str1,"WrLeh") != 0)
2199                 return False;
2200         /* parameters
2201           * W-> resume context (number of users to skip)
2202           * r -> return parameter pointer to receive buffer
2203           * L -> length of receive buffer
2204           * e -> return parameter number of entries
2205           * h -> return parameter total number of users
2206           */
2207   
2208         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2209         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2210         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2211                         resume_context, cli_buf_size));
2212
2213         *rparam_len = 8;
2214         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2215         if (!*rparam) {
2216                 return False;
2217         }
2218
2219         /* check it's a supported varient */
2220         if (strcmp("B21",str2) != 0)
2221                 return False;
2222
2223         *rdata_len = cli_buf_size;
2224         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2225         if (!*rdata) {
2226                 return False;
2227         }
2228
2229         p = *rdata;
2230
2231         become_root();
2232         search = pdb_search_users(ACB_NORMAL);
2233         unbecome_root();
2234         if (search == NULL) {
2235                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2236                 return False;
2237         }
2238
2239         become_root();
2240         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2241                                        &users);
2242         unbecome_root();
2243
2244         errflags=NERR_Success;
2245
2246         for (i=0; i<num_users; i++) {
2247                 const char *name = users[i].account_name;
2248                 
2249                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2250                         pstrcpy(p,name); 
2251                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2252                                   "%s\n",count_sent,p));
2253                         p += 21; 
2254                         count_sent++; 
2255                 } else {
2256                         /* set overflow error */
2257                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2258                                   "username %s\n",count_sent,name));
2259                         errflags=234;
2260                         break;
2261                 }
2262         }
2263
2264         pdb_search_destroy(search);
2265
2266         *rdata_len = PTR_DIFF(p,*rdata);
2267
2268         SSVAL(*rparam,0,errflags);
2269         SSVAL(*rparam,2,0);           /* converter word */
2270         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2271         SSVAL(*rparam,6,num_users); /* is this right?? */
2272
2273         return True;
2274 }
2275
2276 /****************************************************************************
2277  Get the time of day info.
2278 ****************************************************************************/
2279
2280 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2281                                 char *param, int tpscnt,
2282                                 char *data, int tdscnt,
2283                                 int mdrcnt,int mprcnt,
2284                                 char **rdata,char **rparam,
2285                                 int *rdata_len,int *rparam_len)
2286 {
2287         struct tm *t;
2288         time_t unixdate = time(NULL);
2289         char *p;
2290
2291         *rparam_len = 4;
2292         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2293         if (!*rparam) {
2294                 return False;
2295         }
2296
2297         *rdata_len = 21;
2298         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2299         if (!*rdata) {
2300                 return False;
2301         }
2302
2303         SSVAL(*rparam,0,NERR_Success);
2304         SSVAL(*rparam,2,0);             /* converter word */
2305
2306         p = *rdata;
2307
2308         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2309                                             by NT in a "net time" operation,
2310                                             it seems to ignore the one below */
2311
2312         /* the client expects to get localtime, not GMT, in this bit 
2313                 (I think, this needs testing) */
2314         t = localtime(&unixdate);
2315         if (!t) {
2316                 return False;
2317         }
2318
2319         SIVAL(p,4,0);           /* msecs ? */
2320         SCVAL(p,8,t->tm_hour);
2321         SCVAL(p,9,t->tm_min);
2322         SCVAL(p,10,t->tm_sec);
2323         SCVAL(p,11,0);          /* hundredths of seconds */
2324         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2325         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2326         SCVAL(p,16,t->tm_mday);
2327         SCVAL(p,17,t->tm_mon + 1);
2328         SSVAL(p,18,1900+t->tm_year);
2329         SCVAL(p,20,t->tm_wday);
2330
2331         return True;
2332 }
2333
2334 /****************************************************************************
2335  Set the user password.
2336 *****************************************************************************/
2337
2338 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2339                                 char *param, int tpscnt,
2340                                 char *data, int tdscnt,
2341                                 int mdrcnt,int mprcnt,
2342                                 char **rdata,char **rparam,
2343                                 int *rdata_len,int *rparam_len)
2344 {
2345         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2346         char *p = skip_string(param,tpscnt,np,2);
2347         fstring user;
2348         fstring pass1,pass2;
2349
2350         if (!np || !p) {
2351                 return False;
2352         }
2353
2354         /* Do we have a string ? */
2355         if (skip_string(param,tpscnt,p,1) == NULL) {
2356                 return False;
2357         }
2358         pull_ascii_fstring(user,p);
2359
2360         p = skip_string(param,tpscnt,p,1);
2361         if (!p) {
2362                 return False;
2363         }
2364
2365         memset(pass1,'\0',sizeof(pass1));
2366         memset(pass2,'\0',sizeof(pass2));
2367         if (!is_offset_safe(param,tpscnt,p,32)) {
2368                 return False;
2369         }
2370         memcpy(pass1,p,16);
2371         memcpy(pass2,p+16,16);
2372
2373         *rparam_len = 4;
2374         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2375         if (!*rparam) {
2376                 return False;
2377         }
2378
2379         *rdata_len = 0;
2380
2381         SSVAL(*rparam,0,NERR_badpass);
2382         SSVAL(*rparam,2,0);             /* converter word */
2383
2384         DEBUG(3,("Set password for <%s>\n",user));
2385
2386         /*
2387          * Attempt to verify the old password against smbpasswd entries
2388          * Win98 clients send old and new password in plaintext for this call.
2389          */
2390
2391         {
2392                 auth_serversupplied_info *server_info = NULL;
2393                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2394
2395                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2396
2397                         become_root();
2398                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2399                                 SSVAL(*rparam,0,NERR_Success);
2400                         }
2401                         unbecome_root();
2402
2403                         TALLOC_FREE(server_info);
2404                 }
2405                 data_blob_clear_free(&password);
2406         }
2407
2408         /*
2409          * If the plaintext change failed, attempt
2410          * the old encrypted method. NT will generate this
2411          * after trying the samr method. Note that this
2412          * method is done as a last resort as this
2413          * password change method loses the NT password hash
2414          * and cannot change the UNIX password as no plaintext
2415          * is received.
2416          */
2417
2418         if(SVAL(*rparam,0) != NERR_Success) {
2419                 struct samu *hnd = NULL;
2420
2421                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2422                         become_root();
2423                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2424                                 SSVAL(*rparam,0,NERR_Success);
2425                         }
2426                         unbecome_root();
2427                         TALLOC_FREE(hnd);
2428                 }
2429         }
2430
2431         memset((char *)pass1,'\0',sizeof(fstring));
2432         memset((char *)pass2,'\0',sizeof(fstring));      
2433          
2434         return(True);
2435 }
2436
2437 /****************************************************************************
2438   Set the user password (SamOEM version - gets plaintext).
2439 ****************************************************************************/
2440
2441 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2442                                 char *param, int tpscnt,
2443                                 char *data, int tdscnt,
2444                                 int mdrcnt,int mprcnt,
2445                                 char **rdata,char **rparam,
2446                                 int *rdata_len,int *rparam_len)
2447 {
2448         fstring user;
2449         char *p = get_safe_str_ptr(param,tpscnt,param,2);
2450         *rparam_len = 2;
2451         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2452         if (!*rparam) {
2453                 return False;
2454         }
2455
2456         if (!p) {
2457                 return False;
2458         }
2459         *rdata_len = 0;
2460
2461         SSVAL(*rparam,0,NERR_badpass);
2462
2463         /*
2464          * Check the parameter definition is correct.
2465          */
2466
2467         /* Do we have a string ? */
2468         if (skip_string(param,tpscnt,p,1) == 0) {
2469                 return False;
2470         }
2471         if(!strequal(p, "zsT")) {
2472                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2473                 return False;
2474         }
2475         p = skip_string(param, tpscnt, p, 1);
2476         if (!p) {
2477                 return False;
2478         }
2479
2480         /* Do we have a string ? */
2481         if (skip_string(param,tpscnt,p,1) == 0) {
2482                 return False;
2483         }
2484         if(!strequal(p, "B516B16")) {
2485                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2486                 return False;
2487         }
2488         p = skip_string(param,tpscnt,p,1);
2489         if (!p) {
2490                 return False;
2491         }
2492         /* Do we have a string ? */
2493         if (skip_string(param,tpscnt,p,1) == 0) {
2494                 return False;
2495         }
2496         p += pull_ascii_fstring(user,p);
2497
2498         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2499
2500         /*
2501          * Pass the user through the NT -> unix user mapping
2502          * function.
2503          */
2504
2505         (void)map_username(user);
2506
2507         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2508                 SSVAL(*rparam,0,NERR_Success);
2509         }
2510
2511         return(True);
2512 }
2513
2514 /****************************************************************************
2515   delete a print job
2516   Form: <W> <> 
2517   ****************************************************************************/
2518
2519 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2520                                 char *param, int tpscnt,
2521                                 char *data, int tdscnt,
2522                                 int mdrcnt,int mprcnt,
2523                                 char **rdata,char **rparam,
2524                                 int *rdata_len,int *rparam_len)
2525 {
2526         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2527         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2528         char *str2 = skip_string(param,tpscnt,str1,1);
2529         char *p = skip_string(param,tpscnt,str2,1);
2530         uint32 jobid;
2531         int snum;
2532         fstring sharename;
2533         int errcode;
2534         WERROR werr = WERR_OK;
2535
2536         if (!str1 || !str2 || !p) {
2537                 return False;
2538         }
2539         if (!is_offset_safe(param,tpscnt,p,2)) {
2540                 return False;
2541         }
2542         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2543                 return False;
2544
2545         /* check it's a supported varient */
2546         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2547                 return(False);
2548
2549         *rparam_len = 4;
2550         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);       
2551         if (!*rparam) {
2552                 return False;
2553         }
2554         *rdata_len = 0;
2555
2556         if (!print_job_exists(sharename, jobid)) {
2557                 errcode = NERR_JobNotFound;
2558                 goto out;
2559         }
2560
2561         snum = lp_servicenumber( sharename);
2562         if (snum == -1) {
2563                 errcode = NERR_DestNotFound;
2564                 goto out;
2565         }
2566
2567         errcode = NERR_notsupported;
2568         
2569         switch (function) {
2570         case 81:                /* delete */ 
2571                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2572                         errcode = NERR_Success;
2573                 break;
2574         case 82:                /* pause */
2575                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2576                         errcode = NERR_Success;
2577                 break;
2578         case 83:                /* resume */
2579                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2580                         errcode = NERR_Success;
2581                 break;
2582         }
2583
2584         if (!W_ERROR_IS_OK(werr))
2585                 errcode = W_ERROR_V(werr);
2586         
2587  out:
2588         SSVAL(*rparam,0,errcode);       
2589         SSVAL(*rparam,2,0);             /* converter word */
2590
2591         return(True);
2592 }
2593
2594 /****************************************************************************
2595   Purge a print queue - or pause or resume it.
2596   ****************************************************************************/
2597
2598 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2599                                 char *param, int tpscnt,
2600                                 char *data, int tdscnt,
2601                                 int mdrcnt,int mprcnt,
2602                                 char **rdata,char **rparam,
2603                                 int *rdata_len,int *rparam_len)
2604 {
2605         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2606         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2607         char *str2 = skip_string(param,tpscnt,str1,1);
2608         char *QueueName = skip_string(param,tpscnt,str2,1);
2609         int errcode = NERR_notsupported;
2610         int snum;
2611         WERROR werr = WERR_OK;
2612
2613         if (!str1 || !str2 || !QueueName) {
2614                 return False;
2615         }
2616
2617         /* check it's a supported varient */
2618         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2619                 return(False);
2620
2621         *rparam_len = 4;
2622         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2623         if (!*rparam) {
2624                 return False;
2625         }
2626         *rdata_len = 0;
2627
2628         if (skip_string(param,tpscnt,QueueName,1) == NULL) {
2629                 return False;
2630         }
2631         snum = print_queue_snum(QueueName);
2632
2633         if (snum == -1) {
2634                 errcode = NERR_JobNotFound;
2635                 goto out;
2636         }
2637
2638         switch (function) {
2639         case 74: /* Pause queue */
2640                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2641                 break;
2642         case 75: /* Resume queue */
2643                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2644                 break;
2645         case 103: /* Purge */
2646                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2647                 break;
2648         }
2649
2650         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2651
2652  out:
2653         SSVAL(*rparam,0,errcode);
2654         SSVAL(*rparam,2,0);             /* converter word */
2655
2656         return(True);
2657 }
2658
2659 /****************************************************************************
2660   set the property of a print job (undocumented?)
2661   ? function = 0xb -> set name of print job
2662   ? function = 0x6 -> move print job up/down
2663   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2664   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2665 ****************************************************************************/
2666
2667 static int check_printjob_info(struct pack_desc* desc,
2668                                int uLevel, char* id)
2669 {
2670         desc->subformat = NULL;
2671         switch( uLevel ) {
2672         case 0: desc->format = "W"; break;
2673         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2674         case 2: desc->format = "WWzWWDDzz"; break;
2675         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2676         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2677         default: return False;
2678         }
2679         if (strcmp(desc->format,id) != 0) return False;
2680         return True;
2681 }
2682
2683 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2684                                 char *param, int tpscnt,
2685                                 char *data, int tdscnt,
2686                                 int mdrcnt,int mprcnt,
2687                                 char **rdata,char **rparam,
2688                                 int *rdata_len,int *rparam_len)
2689 {
2690         struct pack_desc desc;
2691         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2692         char *str2 = skip_string(param,tpscnt,str1,1);
2693         char *p = skip_string(param,tpscnt,str2,1);
2694         uint32 jobid;
2695         fstring sharename;
2696         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2697         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2698         int place, errcode;
2699
2700         if (!str1 || !str2 || !p) {
2701                 return False;
2702         }
2703         if (!is_offset_safe(param,tpscnt,p,2)) {
2704                 return False;
2705         }
2706         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2707                 return False;
2708         *rparam_len = 4;
2709         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2710         if (!*rparam) {
2711                 return False;
2712         }
2713
2714         if (!share_defined(sharename)) {
2715                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2716                          sharename));
2717                 return False;
2718         }
2719   
2720         *rdata_len = 0;
2721         
2722         /* check it's a supported varient */
2723         if ((strcmp(str1,"WWsTP")) || 
2724             (!check_printjob_info(&desc,uLevel,str2)))
2725                 return(False);
2726
2727         if (!print_job_exists(sharename, jobid)) {
2728                 errcode=NERR_JobNotFound;
2729                 goto out;
2730         }
2731
2732         errcode = NERR_notsupported;
2733
2734         switch (function) {
2735         case 0x6:
2736                 /* change job place in the queue, 
2737                    data gives the new place */
2738                 place = SVAL(data,0);
2739                 if (print_job_set_place(sharename, jobid, place)) {
2740                         errcode=NERR_Success;
2741                 }
2742                 break;
2743
2744         case 0xb:   
2745                 /* change print job name, data gives the name */
2746                 if (print_job_set_name(sharename, jobid, data)) {
2747                         errcode=NERR_Success;
2748                 }
2749                 break;
2750
2751         default:
2752                 return False;
2753         }
2754
2755  out:
2756         SSVALS(*rparam,0,errcode);
2757         SSVAL(*rparam,2,0);             /* converter word */
2758         
2759         return(True);
2760 }
2761
2762
2763 /****************************************************************************
2764  Get info about the server.
2765 ****************************************************************************/
2766
2767 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2768                                 char *param, int tpscnt,
2769                                 char *data, int tdscnt,
2770                                 int mdrcnt,int mprcnt,
2771                                 char **rdata,char **rparam,
2772                                 int *rdata_len,int *rparam_len)
2773 {
2774         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2775         char *str2 = skip_string(param,tpscnt,str1,1);
2776         char *p = skip_string(param,tpscnt,str2,1);
2777         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2778         char *p2;
2779         int struct_len;
2780
2781         if (!str1 || !str2 || !p) {
2782                 return False;
2783         }
2784
2785         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2786
2787         /* check it's a supported varient */
2788         if (!prefix_ok(str1,"WrLh")) {
2789                 return False;
2790         }
2791
2792         switch( uLevel ) {
2793                 case 0:
2794                         if (strcmp(str2,"B16") != 0) {
2795                                 return False;
2796                         }
2797                         struct_len = 16;
2798                         break;
2799                 case 1:
2800                         if (strcmp(str2,"B16BBDz") != 0) {
2801                                 return False;
2802                         }
2803                         struct_len = 26;
2804                         break;
2805                 case 2:
2806                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2807                                 return False;
2808                         }
2809                         struct_len = 134;
2810                         break;
2811                 case 3:
2812                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2813                                 return False;
2814                         }
2815                         struct_len = 144;
2816                         break;
2817                 case 20:
2818                         if (strcmp(str2,"DN") != 0) {
2819                                 return False;
2820                         }
2821                         struct_len = 6;
2822                         break;
2823                 case 50:
2824                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2825                                 return False;
2826                         }
2827                         struct_len = 42;
2828                         break;
2829                 default:
2830                         return False;
2831         }
2832
2833         *rdata_len = mdrcnt;
2834         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2835         if (!*rdata) {
2836                 return False;
2837         }
2838
2839         p = *rdata;
2840         p2 = p + struct_len;
2841         if (uLevel != 20) {
2842                 srvstr_push(NULL, p,global_myname(),16, 
2843                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2844         }
2845         p += 16;
2846         if (uLevel > 0) {
2847                 struct srv_info_struct *servers=NULL;
2848                 int i,count;
2849                 pstring comment;
2850                 uint32 servertype= lp_default_server_announce();
2851
2852                 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2853
2854                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2855                         for (i=0;i<count;i++) {
2856                                 if (strequal(servers[i].name,global_myname())) {
2857                                         servertype = servers[i].type;
2858                                         push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2859                                 }
2860                         }
2861                 }
2862
2863                 SAFE_FREE(servers);
2864
2865                 SCVAL(p,0,lp_major_announce_version());
2866                 SCVAL(p,1,lp_minor_announce_version());
2867                 SIVAL(p,2,servertype);
2868
2869                 if (mdrcnt == struct_len) {
2870                         SIVAL(p,6,0);
2871                 } else {
2872                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2873                         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2874                                               conn->connectpath, conn->gid,
2875                                               get_current_username(),
2876                                               current_user_info.domain,
2877                                               comment, sizeof(comment));
2878                         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2879                         p2 = skip_string(*rdata,*rdata_len,p2,1);
2880                         if (!p2) {
2881                                 return False;
2882                         }
2883                 }
2884         }
2885
2886         if (uLevel > 1) {
2887                 return False;           /* not yet implemented */
2888         }
2889
2890         *rdata_len = PTR_DIFF(p2,*rdata);
2891
2892         *rparam_len = 6;
2893         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2894         if (!*rparam) {
2895                 return False;
2896         }
2897         SSVAL(*rparam,0,NERR_Success);
2898         SSVAL(*rparam,2,0);             /* converter word */
2899         SSVAL(*rparam,4,*rdata_len);
2900
2901         return True;
2902 }
2903
2904 /****************************************************************************
2905  Get info about the server.
2906 ****************************************************************************/
2907
2908 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2909                                 char *param, int tpscnt,
2910                                 char *data, int tdscnt,
2911                                 int mdrcnt,int mprcnt,
2912                                 char **rdata,char **rparam,
2913                                 int *rdata_len,int *rparam_len)
2914 {
2915         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2916         char *str2 = skip_string(param,tpscnt,str1,1);
2917         char *p = skip_string(param,tpscnt,str2,1);
2918         char *p2;
2919         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2920
2921         if (!str1 || !str2 || !p) {
2922                 return False;
2923         }
2924
2925         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2926
2927         *rparam_len = 6;
2928         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2929         if (!*rparam) {
2930                 return False;
2931         }
2932
2933         /* check it's a supported varient */
2934         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2935                 return False;
2936         }
2937
2938         *rdata_len = mdrcnt + 1024;
2939         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2940         if (!*rdata) {
2941                 return False;
2942         }
2943
2944         SSVAL(*rparam,0,NERR_Success);
2945         SSVAL(*rparam,2,0);             /* converter word */
2946
2947         p = *rdata;
2948         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2949         if (!p2) {
2950                 return False;
2951         }
2952
2953         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2954         pstrcpy(p2,get_local_machine_name());
2955         strupper_m(p2);
2956         p2 = skip_string(*rdata,*rdata_len,p2,1);
2957         if (!p2) {
2958                 return False;
2959         }
2960         p += 4;
2961
2962         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2963         pstrcpy(p2,current_user_info.smb_name);
2964         p2 = skip_string(*rdata,*rdata_len,p2,1);
2965         if (!p2) {
2966                 return False;
2967         }
2968         p += 4;
2969
2970         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2971         pstrcpy(p2,lp_workgroup());
2972         strupper_m(p2);
2973         p2 = skip_string(*rdata,*rdata_len,p2,1);
2974         if (!p2) {
2975                 return False;
2976         }
2977         p += 4;
2978
2979         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2980         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2981         p += 2;
2982
2983         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2984         pstrcpy(p2,lp_workgroup());     /* don't know.  login domain?? */
2985         p2 = skip_string(*rdata,*rdata_len,p2,1);
2986         if (!p2) {
2987                 return False;
2988         }
2989         p += 4;
2990
2991         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2992         pstrcpy(p2,"");
2993         p2 = skip_string(*rdata,*rdata_len,p2,1);
2994         if (!p2) {
2995                 return False;
2996         }
2997         p += 4;
2998
2999         *rdata_len = PTR_DIFF(p2,*rdata);
3000
3001         SSVAL(*rparam,4,*rdata_len);
3002
3003         return True;
3004 }
3005
3006 /****************************************************************************
3007   get info about a user
3008
3009     struct user_info_11 {
3010         char                usri11_name[21];  0-20 
3011         char                usri11_pad;       21 
3012         char                *usri11_comment;  22-25 
3013         char            *usri11_usr_comment;  26-29
3014         unsigned short      usri11_priv;      30-31
3015         unsigned long       usri11_auth_flags; 32-35
3016         long                usri11_password_age; 36-39
3017         char                *usri11_homedir; 40-43
3018         char            *usri11_parms; 44-47
3019         long                usri11_last_logon; 48-51
3020         long                usri11_last_logoff; 52-55
3021         unsigned short      usri11_bad_pw_count; 56-57
3022         unsigned short      usri11_num_logons; 58-59
3023         char                *usri11_logon_server; 60-63
3024         unsigned short      usri11_country_code; 64-65
3025         char            *usri11_workstations; 66-69
3026         unsigned long       usri11_max_storage; 70-73
3027         unsigned short      usri11_units_per_week; 74-75
3028         unsigned char       *usri11_logon_hours; 76-79
3029         unsigned short      usri11_code_page; 80-81
3030     };
3031
3032 where:
3033
3034   usri11_name specifies the user name for which information is retireved
3035
3036   usri11_pad aligns the next data structure element to a word boundary
3037
3038   usri11_comment is a null terminated ASCII comment
3039
3040   usri11_user_comment is a null terminated ASCII comment about the user
3041
3042   usri11_priv specifies the level of the privilege assigned to the user.
3043        The possible values are:
3044
3045 Name             Value  Description
3046 USER_PRIV_GUEST  0      Guest privilege
3047 USER_PRIV_USER   1      User privilege
3048 USER_PRV_ADMIN   2      Administrator privilege
3049
3050   usri11_auth_flags specifies the account operator privileges. The
3051        possible values are:
3052
3053 Name            Value   Description
3054 AF_OP_PRINT     0       Print operator
3055
3056
3057 Leach, Naik                                        [Page 28]
3058 \f
3059
3060
3061 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3062
3063
3064 AF_OP_COMM      1       Communications operator
3065 AF_OP_SERVER    2       Server operator
3066 AF_OP_ACCOUNTS  3       Accounts operator
3067
3068
3069   usri11_password_age specifies how many seconds have elapsed since the
3070        password was last changed.
3071
3072   usri11_home_dir points to a null terminated ASCII string that contains
3073        the path name of the user's home directory.
3074
3075   usri11_parms points to a null terminated ASCII string that is set
3076        aside for use by applications.
3077
3078   usri11_last_logon specifies the time when the user last logged on.
3079        This value is stored as the number of seconds elapsed since
3080        00:00:00, January 1, 1970.
3081
3082   usri11_last_logoff specifies the time when the user last logged off.
3083        This value is stored as the number of seconds elapsed since
3084        00:00:00, January 1, 1970. A value of 0 means the last logoff
3085        time is unknown.
3086
3087   usri11_bad_pw_count specifies the number of incorrect passwords
3088        entered since the last successful logon.
3089
3090   usri11_log1_num_logons specifies the number of times this user has
3091        logged on. A value of -1 means the number of logons is unknown.
3092
3093   usri11_logon_server points to a null terminated ASCII string that
3094        contains the name of the server to which logon requests are sent.
3095        A null string indicates logon requests should be sent to the
3096        domain controller.
3097
3098   usri11_country_code specifies the country code for the user's language
3099        of choice.
3100
3101   usri11_workstations points to a null terminated ASCII string that
3102        contains the names of workstations the user may log on from.
3103        There may be up to 8 workstations, with the names separated by
3104        commas. A null strings indicates there are no restrictions.
3105
3106   usri11_max_storage specifies the maximum amount of disk space the user
3107        can occupy. A value of 0xffffffff indicates there are no
3108        restrictions.
3109
3110   usri11_units_per_week specifies the equal number of time units into
3111        which a week is divided. This value must be equal to 168.
3112
3113   usri11_logon_hours points to a 21 byte (168 bits) string that
3114        specifies the time during which the user can log on. Each bit
3115        represents one unique hour in a week. The first bit (bit 0, word
3116        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3117
3118
3119
3120 Leach, Naik                                        [Page 29]
3121 \f
3122
3123
3124 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3125
3126
3127        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3128        are no restrictions.
3129
3130   usri11_code_page specifies the code page for the user's language of
3131        choice
3132
3133 All of the pointers in this data structure need to be treated
3134 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
3135 to be ignored. The converter word returned in the parameters section
3136 needs to be subtracted from the lower 16 bits to calculate an offset
3137 into the return buffer where this ASCII string resides.
3138
3139 There is no auxiliary data in the response.
3140
3141   ****************************************************************************/
3142
3143 #define usri11_name           0 
3144 #define usri11_pad            21
3145 #define usri11_comment        22
3146 #define usri11_usr_comment    26
3147 #define usri11_full_name      30
3148 #define usri11_priv           34
3149 #define usri11_auth_flags     36
3150 #define usri11_password_age   40
3151 #define usri11_homedir        44
3152 #define usri11_parms          48
3153 #define usri11_last_logon     52
3154 #define usri11_last_logoff    56
3155 #define usri11_bad_pw_count   60
3156 #define usri11_num_logons     62
3157 #define usri11_logon_server   64
3158 #define usri11_country_code   68
3159 #define usri11_workstations   70
3160 #define usri11_max_storage    74
3161 #define usri11_units_per_week 78
3162 #define usri11_logon_hours    80
3163 #define usri11_code_page      84
3164 #define usri11_end            86
3165
3166 #define USER_PRIV_GUEST 0
3167 #define USER_PRIV_USER 1
3168 #define USER_PRIV_ADMIN 2
3169
3170 #define AF_OP_PRINT     0 
3171 #define AF_OP_COMM      1
3172 #define AF_OP_SERVER    2
3173 #define AF_OP_ACCOUNTS  3
3174
3175
3176 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3177                                 char *param, int tpscnt,
3178                                 char *data, int tdscnt,
3179                                 int mdrcnt,int mprcnt,
3180                                 char **rdata,char **rparam,
3181                                 int *rdata_len,int *rparam_len)
3182 {
3183         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3184         char *str2 = skip_string(param,tpscnt,str1,1);
3185         char *UserName = skip_string(param,tpscnt,str2,1);
3186         char *p = skip_string(param,tpscnt,UserName,1);
3187         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3188         char *p2;
3189         const char *level_string;
3190
3191         /* get NIS home of a previously validated user - simeon */
3192         /* With share level security vuid will always be zero.
3193            Don't depend on vuser being non-null !!. JRA */
3194         user_struct *vuser = get_valid_user_struct(vuid);
3195         if(vuser != NULL) {
3196                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3197                         vuser->user.unix_name));
3198         }
3199
3200         if (!str1 || !str2 || !UserName || !p) {
3201                 return False;
3202         }
3203
3204         *rparam_len = 6;
3205         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3206         if (!*rparam) {
3207                 return False;
3208         }
3209
3210         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3211   
3212         /* check it's a supported variant */
3213         if (strcmp(str1,"zWrLh") != 0) {
3214                 return False;
3215         }
3216         switch( uLevel ) {
3217                 case 0: level_string = "B21"; break;
3218                 case 1: level_string = "B21BB16DWzzWz"; break;
3219                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3220                 case 10: level_string = "B21Bzzz"; break;
3221                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3222                 default: return False;
3223         }
3224
3225         if (strcmp(level_string,str2) != 0) {
3226                 return False;
3227         }
3228
3229         *rdata_len = mdrcnt + 1024;
3230         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3231         if (!*rdata) {
3232                 return False;
3233         }
3234
3235         SSVAL(*rparam,0,NERR_Success);
3236         SSVAL(*rparam,2,0);             /* converter word */
3237
3238         p = *rdata;
3239         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3240         if (!p2) {
3241                 return False;
3242         }
3243
3244         memset(p,0,21); 
3245         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3246
3247         if (uLevel > 0) {
3248                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3249                 *p2 = 0;
3250         }
3251
3252         if (uLevel >= 10) {
3253                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3254                 pstrcpy(p2,"Comment");
3255                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3256                 if (!p2) {
3257                         return False;
3258                 }
3259
3260                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3261                 pstrcpy(p2,"UserComment");
3262                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3263                 if (!p2) {
3264                         return False;
3265                 }
3266
3267                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3268                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3269                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3270                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3271                 if (!p2) {
3272                         return False;
3273                 }
3274         }
3275
3276         if (uLevel == 11) {
3277                 /* modelled after NTAS 3.51 reply */
3278                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3279                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3280                 SIVALS(p,usri11_password_age,-1);               /* password age */
3281                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3282                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3283                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3284                 if (!p2) {
3285                         return False;
3286                 }
3287                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3288                 pstrcpy(p2,"");
3289                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3290                 if (!p2) {
3291                         return False;
3292                 }
3293                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3294                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3295                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3296                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3297                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3298                 pstrcpy(p2,"\\\\*");
3299                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3300                 if (!p2) {
3301                         return False;
3302                 }
3303                 SSVAL(p,usri11_country_code,0);         /* country code */
3304
3305                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3306                 pstrcpy(p2,"");
3307                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3308                 if (!p2) {
3309                         return False;
3310                 }
3311
3312                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3313                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3314                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3315
3316                 /* a simple way to get logon hours at all times. */
3317                 memset(p2,0xff,21);
3318                 SCVAL(p2,21,0);           /* fix zero termination */
3319                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3320                 if (!p2) {
3321                         return False;
3322                 }
3323
3324                 SSVAL(p,usri11_code_page,0);            /* code page */
3325         }
3326
3327         if (uLevel == 1 || uLevel == 2) {
3328                 memset(p+22,' ',16);    /* password */
3329                 SIVALS(p,38,-1);                /* password age */
3330                 SSVAL(p,42,
3331                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3332                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3333                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3334                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3335                 if (!p2) {
3336                         return False;
3337                 }
3338                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3339                 *p2++ = 0;
3340                 SSVAL(p,52,0);          /* flags */
3341                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3342                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3343                 p2 = skip_string(*rdata,*rdata_len,p2,1);
3344                 if (!p2) {
3345                         return False;
3346                 }
3347                 if (uLevel == 2) {
3348                         SIVAL(p,60,0);          /* auth_flags */
3349                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3350                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3351                         p2 = skip_string(*rdata,*rdata_len,p2,1);
3352                         if (!p2) {
3353                                 return False;
3354                         }
3355                         SIVAL(p,68,0);          /* urs_comment */
3356                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3357                         pstrcpy(p2,"");
3358                         p2 = skip_string(*rdata,*rdata_len,p2,1);
3359                         if (!p2) {
3360                                 return False;
3361                         }
3362                         SIVAL(p,76,0);          /* workstations */
3363                         SIVAL(p,80,0);          /* last_logon */
3364                         SIVAL(p,84,0);          /* last_logoff */
3365                         SIVALS(p,88,-1);                /* acct_expires */
3366                         SIVALS(p,92,-1);                /* max_storage */
3367                         SSVAL(p,96,168);        /* units_per_week */
3368                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3369                         memset(p2,-1,21);
3370                         p2 += 21;
3371                         SSVALS(p,102,-1);       /* bad_pw_count */
3372                         SSVALS(p,104,-1);       /* num_logons */
3373                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3374                         {
3375                                 pstring tmp;
3376   &