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