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