Remove unused wpstring and macros. Stop using pstrcpy in smbd/*.c
[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
1181                 if (!*ptr) {
1182                         continue;
1183                 }
1184     
1185                 if (count == alloced) {
1186                         alloced += 10;
1187                         *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1188                         if (!*servers) {
1189                                 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1190                                 file_lines_free(lines);
1191                                 return 0;
1192                         }
1193                         memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1194                 }
1195                 s = &(*servers)[count];
1196     
1197                 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1198                         continue;
1199                 }
1200                 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1201                         continue;
1202                 }
1203                 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1204                         continue;
1205                 }
1206                 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1207                         /* this allows us to cope with an old nmbd */
1208                         fstrcpy(s->domain,lp_workgroup()); 
1209                 }
1210     
1211                 if (sscanf(stype,"%X",&s->type) != 1) { 
1212                         DEBUG(4,("r:host file ")); 
1213                         ok = False; 
1214                 }
1215     
1216                 /* Filter the servers/domains we return based on what was asked for. */
1217
1218                 /* Check to see if we are being asked for a local list only. */
1219                 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1220                         DEBUG(4,("r: local list only"));
1221                         ok = False;
1222                 }
1223
1224                 /* doesn't match up: don't want it */
1225                 if (!(servertype & s->type)) { 
1226                         DEBUG(4,("r:serv type ")); 
1227                         ok = False; 
1228                 }
1229     
1230                 if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1231                                 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1232                         DEBUG(4,("s: dom mismatch "));
1233                         ok = False;
1234                 }
1235     
1236                 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1237                         ok = False;
1238                 }
1239     
1240                 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1241                 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1242
1243                 if (ok) {
1244                         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1245                                 s->name, s->type, s->comment, s->domain));
1246                         s->server_added = True;
1247                         count++;
1248                 } else {
1249                         DEBUG(4,("%20s %8x %25s %15s\n",
1250                                 s->name, s->type, s->comment, s->domain));
1251                 }
1252         }
1253   
1254         file_lines_free(lines);
1255         return count;
1256 }
1257
1258 /*******************************************************************
1259  Fill in a server info structure.
1260 ******************************************************************/
1261
1262 static int fill_srv_info(struct srv_info_struct *service, 
1263                          int uLevel, char **buf, int *buflen, 
1264                          char **stringbuf, int *stringspace, char *baseaddr)
1265 {
1266         int struct_len;
1267         char* p;
1268         char* p2;
1269         int l2;
1270         int len;
1271  
1272         switch (uLevel) {
1273                 case 0:
1274                         struct_len = 16;
1275                         break;
1276                 case 1:
1277                         struct_len = 26;
1278                         break;
1279                 default:
1280                         return -1;
1281         }
1282  
1283         if (!buf) {
1284                 len = 0;
1285                 switch (uLevel) {
1286                         case 1:
1287                                 len = strlen(service->comment)+1;
1288                                 break;
1289                 }
1290
1291                 *buflen = struct_len;
1292                 *stringspace = len;
1293                 return struct_len + len;
1294         }
1295   
1296         len = struct_len;
1297         p = *buf;
1298         if (*buflen < struct_len) {
1299                 return -1;
1300         }
1301         if (stringbuf) {
1302                 p2 = *stringbuf;
1303                 l2 = *stringspace;
1304         } else {
1305                 p2 = p + struct_len;
1306                 l2 = *buflen - struct_len;
1307         }
1308         if (!baseaddr) {
1309                 baseaddr = p;
1310         }
1311   
1312         switch (uLevel) {
1313                 case 0:
1314                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1315                         break;
1316
1317                 case 1:
1318                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1319                         SIVAL(p,18,service->type);
1320                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1321                         len += CopyAndAdvance(&p2,service->comment,&l2);
1322                         break;
1323         }
1324
1325         if (stringbuf) {
1326                 *buf = p + struct_len;
1327                 *buflen -= struct_len;
1328                 *stringbuf = p2;
1329                 *stringspace = l2;
1330         } else {
1331                 *buf = p2;
1332                 *buflen -= len;
1333         }
1334         return len;
1335 }
1336
1337
1338 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1339 {
1340         return(strcmp(s1->name,s2->name));
1341 }
1342
1343 /****************************************************************************
1344  View list of servers available (or possibly domains). The info is
1345  extracted from lists saved by nmbd on the local host.
1346 ****************************************************************************/
1347
1348 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1349                                 char *param, int tpscnt,
1350                                 char *data, int tdscnt,
1351                                 int mdrcnt, int mprcnt, char **rdata, 
1352                                 char **rparam, int *rdata_len, int *rparam_len)
1353 {
1354         char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1355         char *str2 = skip_string(param,tpscnt,str1);
1356         char *p = skip_string(param,tpscnt,str2);
1357         int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1358         int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1359         uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1360         char *p2;
1361         int data_len, fixed_len, string_len;
1362         int f_len = 0, s_len = 0;
1363         struct srv_info_struct *servers=NULL;
1364         int counted=0,total=0;
1365         int i,missed;
1366         fstring domain;
1367         bool domain_request;
1368         bool local_request;
1369
1370         if (!str1 || !str2 || !p) {
1371                 return False;
1372         }
1373
1374         /* If someone sets all the bits they don't really mean to set
1375            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1376            known servers. */
1377
1378         if (servertype == SV_TYPE_ALL) {
1379                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1380         }
1381
1382         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1383            any other bit (they may just set this bit on its own) they 
1384            want all the locally seen servers. However this bit can be 
1385            set on its own so set the requested servers to be 
1386            ALL - DOMAIN_ENUM. */
1387
1388         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1389                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1390         }
1391
1392         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1393         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1394
1395         p += 8;
1396
1397         if (!prefix_ok(str1,"WrLehD")) {
1398                 return False;
1399         }
1400         if (!check_server_info(uLevel,str2)) {
1401                 return False;
1402         }
1403   
1404         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1405         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1406         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1407
1408         if (strcmp(str1, "WrLehDz") == 0) {
1409                 if (skip_string(param,tpscnt,p) == NULL) {
1410                         return False;
1411                 }
1412                 pull_ascii_fstring(domain, p);
1413         } else {
1414                 fstrcpy(domain, lp_workgroup());
1415         }
1416
1417         if (lp_browse_list()) {
1418                 total = get_server_info(servertype,&servers,domain);
1419         }
1420
1421         data_len = fixed_len = string_len = 0;
1422         missed = 0;
1423
1424         if (total > 0) {
1425                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1426         }
1427
1428         {
1429                 char *lastname=NULL;
1430
1431                 for (i=0;i<total;i++) {
1432                         struct srv_info_struct *s = &servers[i];
1433
1434                         if (lastname && strequal(lastname,s->name)) {
1435                                 continue;
1436                         }
1437                         lastname = s->name;
1438                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1439                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1440                                 s->name, s->type, s->comment, s->domain));
1441       
1442                         if (data_len <= buf_len) {
1443                                 counted++;
1444                                 fixed_len += f_len;
1445                                 string_len += s_len;
1446                         } else {
1447                                 missed++;
1448                         }
1449                 }
1450         }
1451
1452         *rdata_len = fixed_len + string_len;
1453         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1454         if (!*rdata) {
1455                 return False;
1456         }
1457   
1458         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1459         p = *rdata;
1460         f_len = fixed_len;
1461         s_len = string_len;
1462
1463         {
1464                 char *lastname=NULL;
1465                 int count2 = counted;
1466
1467                 for (i = 0; i < total && count2;i++) {
1468                         struct srv_info_struct *s = &servers[i];
1469
1470                         if (lastname && strequal(lastname,s->name)) {
1471                                 continue;
1472                         }
1473                         lastname = s->name;
1474                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1475                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1476                                 s->name, s->type, s->comment, s->domain));
1477                         count2--;
1478                 }
1479         }
1480   
1481         *rparam_len = 8;
1482         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1483         if (!*rparam) {
1484                 return False;
1485         }
1486         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1487         SSVAL(*rparam,2,0);
1488         SSVAL(*rparam,4,counted);
1489         SSVAL(*rparam,6,counted+missed);
1490
1491         SAFE_FREE(servers);
1492
1493         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1494                 domain,uLevel,counted,counted+missed));
1495
1496         return True;
1497 }
1498
1499 /****************************************************************************
1500   command 0x34 - suspected of being a "Lookup Names" stub api
1501   ****************************************************************************/
1502
1503 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1504                                 char *param, int tpscnt,
1505                                 char *data, int tdscnt,
1506                                 int mdrcnt, int mprcnt, char **rdata, 
1507                                 char **rparam, int *rdata_len, int *rparam_len)
1508 {
1509         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1510         char *str2 = skip_string(param,tpscnt,str1);
1511         char *p = skip_string(param,tpscnt,str2);
1512         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1513         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1514         int counted=0;
1515         int missed=0;
1516
1517         if (!str1 || !str2 || !p) {
1518                 return False;
1519         }
1520
1521         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1522                 str1, str2, p, uLevel, buf_len));
1523
1524         if (!prefix_ok(str1,"zWrLeh")) {
1525                 return False;
1526         }
1527   
1528         *rdata_len = 0;
1529   
1530         *rparam_len = 8;
1531         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1532         if (!*rparam) {
1533                 return False;
1534         }
1535
1536         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1537         SSVAL(*rparam,2,0);
1538         SSVAL(*rparam,4,counted);
1539         SSVAL(*rparam,6,counted+missed);
1540
1541         return True;
1542 }
1543
1544 /****************************************************************************
1545   get info about a share
1546   ****************************************************************************/
1547
1548 static bool check_share_info(int uLevel, char* id)
1549 {
1550         switch( uLevel ) {
1551                 case 0:
1552                         if (strcmp(id,"B13") != 0) {
1553                                 return False;
1554                         }
1555                         break;
1556                 case 1:
1557                         if (strcmp(id,"B13BWz") != 0) {
1558                                 return False;
1559                         }
1560                         break;
1561                 case 2:
1562                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1563                                 return False;
1564                         }
1565                         break;
1566                 case 91:
1567                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1568                                 return False;
1569                         }
1570                         break;
1571                 default:
1572                         return False;
1573         }
1574         return True;
1575 }
1576
1577 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1578                            char** buf, int* buflen,
1579                            char** stringbuf, int* stringspace, char* baseaddr)
1580 {
1581         int struct_len;
1582         char* p;
1583         char* p2;
1584         int l2;
1585         int len;
1586  
1587         switch( uLevel ) {
1588                 case 0:
1589                         struct_len = 13;
1590                         break;
1591                 case 1:
1592                         struct_len = 20;
1593                         break;
1594                 case 2:
1595                         struct_len = 40;
1596                         break;
1597                 case 91:
1598                         struct_len = 68;
1599                         break;
1600                 default:
1601                         return -1;
1602         }
1603   
1604  
1605         if (!buf) {
1606                 len = 0;
1607
1608                 if (uLevel > 0) {
1609                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1610                 }
1611                 if (uLevel > 1) {
1612                         len += strlen(lp_pathname(snum)) + 1;
1613                 }
1614                 if (buflen) {
1615                         *buflen = struct_len;
1616                 }
1617                 if (stringspace) {
1618                         *stringspace = len;
1619                 }
1620                 return struct_len + len;
1621         }
1622   
1623         len = struct_len;
1624         p = *buf;
1625         if ((*buflen) < struct_len) {
1626                 return -1;
1627         }
1628
1629         if (stringbuf) {
1630                 p2 = *stringbuf;
1631                 l2 = *stringspace;
1632         } else {
1633                 p2 = p + struct_len;
1634                 l2 = (*buflen) - struct_len;
1635         }
1636
1637         if (!baseaddr) {
1638                 baseaddr = p;
1639         }
1640   
1641         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1642   
1643         if (uLevel > 0) {
1644                 int type;
1645
1646                 SCVAL(p,13,0);
1647                 type = STYPE_DISKTREE;
1648                 if (lp_print_ok(snum)) {
1649                         type = STYPE_PRINTQ;
1650                 }
1651                 if (strequal("IPC",lp_fstype(snum))) {
1652                         type = STYPE_IPC;
1653                 }
1654                 SSVAL(p,14,type);               /* device type */
1655                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1656                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1657         }
1658   
1659         if (uLevel > 1) {
1660                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1661                 SSVALS(p,22,-1);                /* max uses */
1662                 SSVAL(p,24,1); /* current uses */
1663                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1664                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1665                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1666         }
1667   
1668         if (uLevel > 2) {
1669                 memset(p+40,0,SHPWLEN+2);
1670                 SSVAL(p,50,0);
1671                 SIVAL(p,52,0);
1672                 SSVAL(p,56,0);
1673                 SSVAL(p,58,0);
1674                 SIVAL(p,60,0);
1675                 SSVAL(p,64,0);
1676                 SSVAL(p,66,0);
1677         }
1678        
1679         if (stringbuf) {
1680                 (*buf) = p + struct_len;
1681                 (*buflen) -= struct_len;
1682                 (*stringbuf) = p2;
1683                 (*stringspace) = l2;
1684         } else {
1685                 (*buf) = p2;
1686                 (*buflen) -= len;
1687         }
1688
1689         return len;
1690 }
1691
1692 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1693                                 char *param, int tpscnt,
1694                                 char *data, int tdscnt,
1695                                 int mdrcnt,int mprcnt,
1696                                 char **rdata,char **rparam,
1697                                 int *rdata_len,int *rparam_len)
1698 {
1699         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1700         char *str2 = skip_string(param,tpscnt,str1);
1701         char *netname = skip_string(param,tpscnt,str2);
1702         char *p = skip_string(param,tpscnt,netname);
1703         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1704         int snum;
1705   
1706         if (!str1 || !str2 || !netname || !p) {
1707                 return False;
1708         }
1709
1710         snum = find_service(netname);
1711         if (snum < 0) {
1712                 return False;
1713         }
1714   
1715         /* check it's a supported varient */
1716         if (!prefix_ok(str1,"zWrLh")) {
1717                 return False;
1718         }
1719         if (!check_share_info(uLevel,str2)) {
1720                 return False;
1721         }
1722  
1723         *rdata = smb_realloc_limit(*rdata,mdrcnt);
1724         if (!*rdata) {
1725                 return False;
1726         }
1727         p = *rdata;
1728         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1729         if (*rdata_len < 0) {
1730                 return False;
1731         }
1732  
1733         *rparam_len = 6;
1734         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1735         if (!*rparam) {
1736                 return False;
1737         }
1738         SSVAL(*rparam,0,NERR_Success);
1739         SSVAL(*rparam,2,0);             /* converter word */
1740         SSVAL(*rparam,4,*rdata_len);
1741  
1742         return True;
1743 }
1744
1745 /****************************************************************************
1746   View the list of available shares.
1747
1748   This function is the server side of the NetShareEnum() RAP call.
1749   It fills the return buffer with share names and share comments.
1750   Note that the return buffer normally (in all known cases) allows only
1751   twelve byte strings for share names (plus one for a nul terminator).
1752   Share names longer than 12 bytes must be skipped.
1753  ****************************************************************************/
1754
1755 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1756                                 char *param, int tpscnt,
1757                                 char *data, int tdscnt,
1758                                 int                mdrcnt,
1759                                 int                mprcnt,
1760                                 char             **rdata,
1761                                 char             **rparam,
1762                                 int               *rdata_len,
1763                                 int               *rparam_len )
1764 {
1765         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1766         char *str2 = skip_string(param,tpscnt,str1);
1767         char *p = skip_string(param,tpscnt,str2);
1768         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1769         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1770         char *p2;
1771         int count = 0;
1772         int total=0,counted=0;
1773         bool missed = False;
1774         int i;
1775         int data_len, fixed_len, string_len;
1776         int f_len = 0, s_len = 0;
1777  
1778         if (!str1 || !str2 || !p) {
1779                 return False;
1780         }
1781
1782         if (!prefix_ok(str1,"WrLeh")) {
1783                 return False;
1784         }
1785         if (!check_share_info(uLevel,str2)) {
1786                 return False;
1787         }
1788   
1789         /* Ensure all the usershares are loaded. */
1790         become_root();
1791         load_registry_shares();
1792         count = load_usershare_shares();
1793         unbecome_root();
1794
1795         data_len = fixed_len = string_len = 0;
1796         for (i=0;i<count;i++) {
1797                 fstring servicename_dos;
1798                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1799                         continue;
1800                 }
1801                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1802                 /* Maximum name length = 13. */
1803                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1804                         total++;
1805                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1806                         if (data_len <= buf_len) {
1807                                 counted++;
1808                                 fixed_len += f_len;
1809                                 string_len += s_len;
1810                         } else {
1811                                 missed = True;
1812                         }
1813                 }
1814         }
1815
1816         *rdata_len = fixed_len + string_len;
1817         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1818         if (!*rdata) {
1819                 return False;
1820         }
1821  
1822         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1823         p = *rdata;
1824         f_len = fixed_len;
1825         s_len = string_len;
1826
1827         for( i = 0; i < count; i++ ) {
1828                 fstring servicename_dos;
1829                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1830                         continue;
1831                 }
1832
1833                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1834                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1835                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1836                                 break;
1837                         }
1838                 }
1839         }
1840   
1841         *rparam_len = 8;
1842         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1843         if (!*rparam) {
1844                 return False;
1845         }
1846         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1847         SSVAL(*rparam,2,0);
1848         SSVAL(*rparam,4,counted);
1849         SSVAL(*rparam,6,total);
1850   
1851         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1852                 counted,total,uLevel,
1853                 buf_len,*rdata_len,mdrcnt));
1854
1855         return True;
1856 }
1857
1858 /****************************************************************************
1859   Add a share
1860   ****************************************************************************/
1861
1862 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1863                                 char *param, int tpscnt,
1864                                 char *data, int tdscnt,
1865                                 int mdrcnt,int mprcnt,
1866                                 char **rdata,char **rparam,
1867                                 int *rdata_len,int *rparam_len)
1868 {
1869         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1870         char *str2 = skip_string(param,tpscnt,str1);
1871         char *p = skip_string(param,tpscnt,str2);
1872         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1873         fstring sharename;
1874         fstring comment;
1875         char *pathname = NULL;
1876         char *command, *cmdname;
1877         unsigned int offset;
1878         int snum;
1879         int res = ERRunsup;
1880
1881         if (!str1 || !str2 || !p) {
1882                 return False;
1883         }
1884
1885         /* check it's a supported varient */
1886         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1887                 return False;
1888         }
1889         if (!check_share_info(uLevel,str2)) {
1890                 return False;
1891         }
1892         if (uLevel != 2) {
1893                 return False;
1894         }
1895
1896         /* Do we have a string ? */
1897         if (skip_string(data,mdrcnt,data) == NULL) {
1898                 return False;
1899         }
1900         pull_ascii_fstring(sharename,data);
1901         snum = find_service(sharename);
1902         if (snum >= 0) { /* already exists */
1903                 res = ERRfilexists;
1904                 goto error_exit;
1905         }
1906
1907         if (mdrcnt < 28) {
1908                 return False;
1909         }
1910
1911         /* only support disk share adds */
1912         if (SVAL(data,14)!=STYPE_DISKTREE) {
1913                 return False;
1914         }
1915
1916         offset = IVAL(data, 16);
1917         if (offset >= mdrcnt) {
1918                 res = ERRinvalidparam;
1919                 goto error_exit;
1920         }
1921
1922         /* Do we have a string ? */
1923         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1924                 return False;
1925         }
1926         pull_ascii_fstring(comment, offset? (data+offset) : "");
1927
1928         offset = IVAL(data, 26);
1929
1930         if (offset >= mdrcnt) {
1931                 res = ERRinvalidparam;
1932                 goto error_exit;
1933         }
1934
1935         /* Do we have a string ? */
1936         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1937                 return False;
1938         }
1939
1940         pull_ascii_talloc(talloc_tos(), &pathname, offset? (data+offset) : "");
1941         if (!pathname) {
1942                 return false;
1943         }
1944
1945         string_replace(sharename, '"', ' ');
1946         string_replace(pathname, '"', ' ');
1947         string_replace(comment, '"', ' ');
1948
1949         cmdname = lp_add_share_cmd();
1950
1951         if (!cmdname || *cmdname == '\0') {
1952                 return False;
1953         }
1954
1955         asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1956                 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1957
1958         if (command) {
1959                 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1960
1961                 if ((res = smbrun(command, NULL)) != 0) {
1962                         DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1963                         SAFE_FREE(command);
1964                         res = ERRnoaccess;
1965                         goto error_exit;
1966                 } else {
1967                         SAFE_FREE(command);
1968                         message_send_all(smbd_messaging_context(),
1969                                          MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1970                 }
1971         } else {
1972                 return False;
1973         }
1974
1975         *rparam_len = 6;
1976         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1977         if (!*rparam) {
1978                 return False;
1979         }
1980         SSVAL(*rparam,0,NERR_Success);
1981         SSVAL(*rparam,2,0);             /* converter word */
1982         SSVAL(*rparam,4,*rdata_len);
1983         *rdata_len = 0;
1984   
1985         return True;
1986
1987   error_exit:
1988
1989         *rparam_len = 4;
1990         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1991         if (!*rparam) {
1992                 return False;
1993         }
1994         *rdata_len = 0;
1995         SSVAL(*rparam,0,res);
1996         SSVAL(*rparam,2,0);
1997         return True;
1998 }
1999
2000 /****************************************************************************
2001   view list of groups available
2002   ****************************************************************************/
2003
2004 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2005                                 char *param, int tpscnt,
2006                                 char *data, int tdscnt,
2007                                 int mdrcnt,int mprcnt,
2008                                 char **rdata,char **rparam,
2009                                 int *rdata_len,int *rparam_len)
2010 {
2011         int i;
2012         int errflags=0;
2013         int resume_context, cli_buf_size;
2014         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2015         char *str2 = skip_string(param,tpscnt,str1);
2016         char *p = skip_string(param,tpscnt,str2);
2017
2018         struct pdb_search *search;
2019         struct samr_displayentry *entries;
2020
2021         int num_entries;
2022  
2023         if (!str1 || !str2 || !p) {
2024                 return False;
2025         }
2026
2027         if (strcmp(str1,"WrLeh") != 0) {
2028                 return False;
2029         }
2030
2031         /* parameters  
2032          * W-> resume context (number of users to skip)
2033          * r -> return parameter pointer to receive buffer 
2034          * L -> length of receive buffer
2035          * e -> return parameter number of entries
2036          * h -> return parameter total number of users
2037          */
2038
2039         if (strcmp("B21",str2) != 0) {
2040                 return False;
2041         }
2042
2043         /* get list of domain groups SID_DOMAIN_GRP=2 */
2044         become_root();
2045         search = pdb_search_groups();
2046         unbecome_root();
2047
2048         if (search == NULL) {
2049                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2050                 return False;
2051         }
2052
2053         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2054         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2055         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2056                   "%d\n", resume_context, cli_buf_size));
2057
2058         become_root();
2059         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2060                                          &entries);
2061         unbecome_root();
2062
2063         *rdata_len = cli_buf_size;
2064         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2065         if (!*rdata) {
2066                 return False;
2067         }
2068
2069         p = *rdata;
2070
2071         for(i=0; i<num_entries; i++) {
2072                 fstring name;
2073                 fstrcpy(name, entries[i].account_name);
2074                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2075                         /* truncate the name at 21 chars. */
2076                         memcpy(p, name, 21); 
2077                         DEBUG(10,("adding entry %d group %s\n", i, p));
2078                         p += 21;
2079                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
2080                                    No idea why... */
2081                 } else {
2082                         /* set overflow error */
2083                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
2084                         errflags=234;
2085                         break;
2086                 }
2087         }
2088
2089         pdb_search_destroy(search);
2090
2091         *rdata_len = PTR_DIFF(p,*rdata);
2092
2093         *rparam_len = 8;
2094         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2095         if (!*rparam) {
2096                 return False;
2097         }
2098         SSVAL(*rparam, 0, errflags);
2099         SSVAL(*rparam, 2, 0);           /* converter word */
2100         SSVAL(*rparam, 4, i);   /* is this right?? */
2101         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
2102
2103         return(True);
2104 }
2105
2106 /*******************************************************************
2107  Get groups that a user is a member of.
2108 ******************************************************************/
2109
2110 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2111                                 char *param, int tpscnt,
2112                                 char *data, int tdscnt,
2113                                 int mdrcnt,int mprcnt,
2114                                 char **rdata,char **rparam,
2115                                 int *rdata_len,int *rparam_len)
2116 {
2117         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2118         char *str2 = skip_string(param,tpscnt,str1);
2119         char *UserName = skip_string(param,tpscnt,str2);
2120         char *p = skip_string(param,tpscnt,UserName);
2121         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2122         const char *level_string;
2123         int count=0;
2124         struct samu *sampw = NULL;
2125         bool ret = False;
2126         DOM_SID *sids;
2127         gid_t *gids;
2128         size_t num_groups;
2129         size_t i;
2130         NTSTATUS result;
2131         DOM_SID user_sid;
2132         enum lsa_SidType type;
2133         char *endp = NULL;
2134         TALLOC_CTX *mem_ctx;
2135
2136         if (!str1 || !str2 || !UserName || !p) {
2137                 return False;
2138         }
2139
2140         *rparam_len = 8;
2141         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2142         if (!*rparam) {
2143                 return False;
2144         }
2145
2146         /* check it's a supported varient */
2147
2148         if ( strcmp(str1,"zWrLeh") != 0 )
2149                 return False;
2150
2151         switch( uLevel ) {
2152                 case 0:
2153                         level_string = "B21";
2154                         break;
2155                 default:
2156                         return False;
2157         }
2158
2159         if (strcmp(level_string,str2) != 0)
2160                 return False;
2161
2162         *rdata_len = mdrcnt + 1024;
2163         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2164         if (!*rdata) {
2165                 return False;
2166         }
2167
2168         SSVAL(*rparam,0,NERR_Success);
2169         SSVAL(*rparam,2,0);             /* converter word */
2170
2171         p = *rdata;
2172         endp = *rdata + *rdata_len;
2173
2174         mem_ctx = talloc_new(NULL);
2175         if (mem_ctx == NULL) {
2176                 DEBUG(0, ("talloc_new failed\n"));
2177                 return False;
2178         }
2179
2180         if ( !(sampw = samu_new(mem_ctx)) ) {
2181                 DEBUG(0, ("samu_new() failed!\n"));
2182                 TALLOC_FREE(mem_ctx);
2183                 return False;
2184         }
2185
2186         /* Lookup the user information; This should only be one of
2187            our accounts (not remote domains) */
2188
2189         become_root();                                  /* ROOT BLOCK */
2190
2191         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2192                          NULL, NULL, &user_sid, &type)) {
2193                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2194                 goto done;
2195         }
2196
2197         if (type != SID_NAME_USER) {
2198                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2199                            sid_type_lookup(type)));
2200                 goto done;
2201         }
2202
2203         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2204                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2205                            sid_string_static(&user_sid), UserName));
2206                 goto done;
2207         }
2208
2209         gids = NULL;
2210         sids = NULL;
2211         num_groups = 0;
2212
2213         result = pdb_enum_group_memberships(mem_ctx, sampw,
2214                                             &sids, &gids, &num_groups);
2215
2216         if (!NT_STATUS_IS_OK(result)) {
2217                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2218                            UserName));
2219                 goto done;
2220         }
2221
2222         for (i=0; i<num_groups; i++) {
2223                 const char *grp_name;
2224
2225                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2226                         strlcpy(p, grp_name, PTR_DIFF(endp,p));
2227                         p += 21;
2228                         count++;
2229                 }
2230         }
2231
2232         *rdata_len = PTR_DIFF(p,*rdata);
2233
2234         SSVAL(*rparam,4,count); /* is this right?? */
2235         SSVAL(*rparam,6,count); /* is this right?? */
2236
2237         ret = True;
2238
2239 done:
2240         unbecome_root();                                /* END ROOT BLOCK */
2241
2242         TALLOC_FREE(mem_ctx);
2243
2244         return ret;
2245 }
2246
2247 /*******************************************************************
2248  Get all users.
2249 ******************************************************************/
2250
2251 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2252                                 char *param, int tpscnt,
2253                                 char *data, int tdscnt,
2254                                 int mdrcnt,int mprcnt,
2255                                 char **rdata,char **rparam,
2256                                 int *rdata_len,int *rparam_len)
2257 {
2258         int count_sent=0;
2259         int num_users=0;
2260         int errflags=0;
2261         int i, resume_context, cli_buf_size;
2262         struct pdb_search *search;
2263         struct samr_displayentry *users;
2264
2265         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2266         char *str2 = skip_string(param,tpscnt,str1);
2267         char *p = skip_string(param,tpscnt,str2);
2268         char *endp = NULL;
2269
2270         if (!str1 || !str2 || !p) {
2271                 return False;
2272         }
2273
2274         if (strcmp(str1,"WrLeh") != 0)
2275                 return False;
2276         /* parameters
2277           * W-> resume context (number of users to skip)
2278           * r -> return parameter pointer to receive buffer
2279           * L -> length of receive buffer
2280           * e -> return parameter number of entries
2281           * h -> return parameter total number of users
2282           */
2283
2284         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2285         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2286         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2287                         resume_context, cli_buf_size));
2288
2289         *rparam_len = 8;
2290         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2291         if (!*rparam) {
2292                 return False;
2293         }
2294
2295         /* check it's a supported varient */
2296         if (strcmp("B21",str2) != 0)
2297                 return False;
2298
2299         *rdata_len = cli_buf_size;
2300         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2301         if (!*rdata) {
2302                 return False;
2303         }
2304
2305         p = *rdata;
2306         endp = *rdata + *rdata_len;
2307
2308         become_root();
2309         search = pdb_search_users(ACB_NORMAL);
2310         unbecome_root();
2311         if (search == NULL) {
2312                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2313                 return False;
2314         }
2315
2316         become_root();
2317         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2318                                        &users);
2319         unbecome_root();
2320
2321         errflags=NERR_Success;
2322
2323         for (i=0; i<num_users; i++) {
2324                 const char *name = users[i].account_name;
2325
2326                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2327                         strlcpy(p,name,PTR_DIFF(endp,p));
2328                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2329                                   "%s\n",count_sent,p));
2330                         p += 21;
2331                         count_sent++;
2332                 } else {
2333                         /* set overflow error */
2334                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2335                                   "username %s\n",count_sent,name));
2336                         errflags=234;
2337                         break;
2338                 }
2339         }
2340
2341         pdb_search_destroy(search);
2342
2343         *rdata_len = PTR_DIFF(p,*rdata);
2344
2345         SSVAL(*rparam,0,errflags);
2346         SSVAL(*rparam,2,0);           /* converter word */
2347         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2348         SSVAL(*rparam,6,num_users); /* is this right?? */
2349
2350         return True;
2351 }
2352
2353 /****************************************************************************
2354  Get the time of day info.
2355 ****************************************************************************/
2356
2357 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2358                                 char *param, int tpscnt,
2359                                 char *data, int tdscnt,
2360                                 int mdrcnt,int mprcnt,
2361                                 char **rdata,char **rparam,
2362                                 int *rdata_len,int *rparam_len)
2363 {
2364         struct tm *t;
2365         time_t unixdate = time(NULL);
2366         char *p;
2367
2368         *rparam_len = 4;
2369         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2370         if (!*rparam) {
2371                 return False;
2372         }
2373
2374         *rdata_len = 21;
2375         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2376         if (!*rdata) {
2377                 return False;
2378         }
2379
2380         SSVAL(*rparam,0,NERR_Success);
2381         SSVAL(*rparam,2,0);             /* converter word */
2382
2383         p = *rdata;
2384
2385         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2386                                             by NT in a "net time" operation,
2387                                             it seems to ignore the one below */
2388
2389         /* the client expects to get localtime, not GMT, in this bit 
2390                 (I think, this needs testing) */
2391         t = localtime(&unixdate);
2392         if (!t) {
2393                 return False;
2394         }
2395
2396         SIVAL(p,4,0);           /* msecs ? */
2397         SCVAL(p,8,t->tm_hour);
2398         SCVAL(p,9,t->tm_min);
2399         SCVAL(p,10,t->tm_sec);
2400         SCVAL(p,11,0);          /* hundredths of seconds */
2401         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2402         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2403         SCVAL(p,16,t->tm_mday);
2404         SCVAL(p,17,t->tm_mon + 1);
2405         SSVAL(p,18,1900+t->tm_year);
2406         SCVAL(p,20,t->tm_wday);
2407
2408         return True;
2409 }
2410
2411 /****************************************************************************
2412  Set the user password.
2413 *****************************************************************************/
2414
2415 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2416                                 char *param, int tpscnt,
2417                                 char *data, int tdscnt,
2418                                 int mdrcnt,int mprcnt,
2419                                 char **rdata,char **rparam,
2420                                 int *rdata_len,int *rparam_len)
2421 {
2422         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2423         char *p = NULL;
2424         fstring user;
2425         fstring pass1,pass2;
2426
2427         /* Skip 2 strings. */
2428         p = skip_string(param,tpscnt,np);
2429         p = skip_string(param,tpscnt,p);
2430
2431         if (!np || !p) {
2432                 return False;
2433         }
2434
2435         /* Do we have a string ? */
2436         if (skip_string(param,tpscnt,p) == NULL) {
2437                 return False;
2438         }
2439         pull_ascii_fstring(user,p);
2440
2441         p = skip_string(param,tpscnt,p);
2442         if (!p) {
2443                 return False;
2444         }
2445
2446         memset(pass1,'\0',sizeof(pass1));
2447         memset(pass2,'\0',sizeof(pass2));
2448         /*
2449          * We use 31 here not 32 as we're checking
2450          * the last byte we want to access is safe.
2451          */
2452         if (!is_offset_safe(param,tpscnt,p,31)) {
2453                 return False;
2454         }
2455         memcpy(pass1,p,16);
2456         memcpy(pass2,p+16,16);
2457
2458         *rparam_len = 4;
2459         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2460         if (!*rparam) {
2461                 return False;
2462         }
2463
2464         *rdata_len = 0;
2465
2466         SSVAL(*rparam,0,NERR_badpass);
2467         SSVAL(*rparam,2,0);             /* converter word */
2468
2469         DEBUG(3,("Set password for <%s>\n",user));
2470
2471         /*
2472          * Attempt to verify the old password against smbpasswd entries
2473          * Win98 clients send old and new password in plaintext for this call.
2474          */
2475
2476         {
2477                 auth_serversupplied_info *server_info = NULL;
2478                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2479
2480                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2481
2482                         become_root();
2483                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2484                                 SSVAL(*rparam,0,NERR_Success);
2485                         }
2486                         unbecome_root();
2487
2488                         TALLOC_FREE(server_info);
2489                 }
2490                 data_blob_clear_free(&password);
2491         }
2492
2493         /*
2494          * If the plaintext change failed, attempt
2495          * the old encrypted method. NT will generate this
2496          * after trying the samr method. Note that this
2497          * method is done as a last resort as this
2498          * password change method loses the NT password hash
2499          * and cannot change the UNIX password as no plaintext
2500          * is received.
2501          */
2502
2503         if(SVAL(*rparam,0) != NERR_Success) {
2504                 struct samu *hnd = NULL;
2505
2506                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2507                         become_root();
2508                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2509                                 SSVAL(*rparam,0,NERR_Success);
2510                         }
2511                         unbecome_root();
2512                         TALLOC_FREE(hnd);
2513                 }
2514         }
2515
2516         memset((char *)pass1,'\0',sizeof(fstring));
2517         memset((char *)pass2,'\0',sizeof(fstring));      
2518          
2519         return(True);
2520 }
2521
2522 /****************************************************************************
2523   Set the user password (SamOEM version - gets plaintext).
2524 ****************************************************************************/
2525
2526 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2527                                 char *param, int tpscnt,
2528                                 char *data, int tdscnt,
2529                                 int mdrcnt,int mprcnt,
2530                                 char **rdata,char **rparam,
2531                                 int *rdata_len,int *rparam_len)
2532 {
2533         fstring user;
2534         char *p = get_safe_str_ptr(param,tpscnt,param,2);
2535         *rparam_len = 2;
2536         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2537         if (!*rparam) {
2538                 return False;
2539         }
2540
2541         if (!p) {
2542                 return False;
2543         }
2544         *rdata_len = 0;
2545
2546         SSVAL(*rparam,0,NERR_badpass);
2547
2548         /*
2549          * Check the parameter definition is correct.
2550          */
2551
2552         /* Do we have a string ? */
2553         if (skip_string(param,tpscnt,p) == 0) {
2554                 return False;
2555         }
2556         if(!strequal(p, "zsT")) {
2557                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2558                 return False;
2559         }
2560         p = skip_string(param, tpscnt, p);
2561         if (!p) {
2562                 return False;
2563         }
2564
2565         /* Do we have a string ? */
2566         if (skip_string(param,tpscnt,p) == 0) {
2567                 return False;
2568         }
2569         if(!strequal(p, "B516B16")) {
2570                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2571                 return False;
2572         }
2573         p = skip_string(param,tpscnt,p);
2574         if (!p) {
2575                 return False;
2576         }
2577         /* Do we have a string ? */
2578         if (skip_string(param,tpscnt,p) == 0) {
2579                 return False;
2580         }
2581         p += pull_ascii_fstring(user,p);
2582
2583         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2584
2585         /*
2586          * Pass the user through the NT -> unix user mapping
2587          * function.
2588          */
2589
2590         (void)map_username(user);
2591
2592         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2593                 SSVAL(*rparam,0,NERR_Success);
2594         }
2595
2596         return(True);
2597 }
2598
2599 /****************************************************************************
2600   delete a print job
2601   Form: <W> <> 
2602   ****************************************************************************/
2603
2604 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2605                                 char *param, int tpscnt,
2606                                 char *data, int tdscnt,
2607                                 int mdrcnt,int mprcnt,
2608                                 char **rdata,char **rparam,
2609                                 int *rdata_len,int *rparam_len)
2610 {
2611         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2612         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2613         char *str2 = skip_string(param,tpscnt,str1);
2614         char *p = skip_string(param,tpscnt,str2);
2615         uint32 jobid;
2616         int snum;
2617         fstring sharename;
2618         int errcode;
2619         WERROR werr = WERR_OK;
2620
2621         if (!str1 || !str2 || !p) {
2622                 return False;
2623         }
2624         /*
2625          * We use 1 here not 2 as we're checking
2626          * the last byte we want to access is safe.
2627          */
2628         if (!is_offset_safe(param,tpscnt,p,1)) {
2629                 return False;
2630         }
2631         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2632                 return False;
2633
2634         /* check it's a supported varient */
2635         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2636                 return(False);
2637
2638         *rparam_len = 4;
2639         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2640         if (!*rparam) {
2641                 return False;
2642         }
2643         *rdata_len = 0;
2644
2645         if (!print_job_exists(sharename, jobid)) {
2646                 errcode = NERR_JobNotFound;
2647                 goto out;
2648         }
2649
2650         snum = lp_servicenumber( sharename);
2651         if (snum == -1) {
2652                 errcode = NERR_DestNotFound;
2653                 goto out;
2654         }
2655
2656         errcode = NERR_notsupported;
2657         
2658         switch (function) {
2659         case 81:                /* delete */ 
2660                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2661                         errcode = NERR_Success;
2662                 break;
2663         case 82:                /* pause */
2664                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2665                         errcode = NERR_Success;
2666                 break;
2667         case 83:                /* resume */
2668                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2669                         errcode = NERR_Success;
2670                 break;
2671         }
2672
2673         if (!W_ERROR_IS_OK(werr))
2674                 errcode = W_ERROR_V(werr);
2675         
2676  out:
2677         SSVAL(*rparam,0,errcode);       
2678         SSVAL(*rparam,2,0);             /* converter word */
2679
2680         return(True);
2681 }
2682
2683 /****************************************************************************
2684   Purge a print queue - or pause or resume it.
2685   ****************************************************************************/
2686
2687 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2688                                 char *param, int tpscnt,
2689                                 char *data, int tdscnt,
2690                                 int mdrcnt,int mprcnt,
2691                                 char **rdata,char **rparam,
2692                                 int *rdata_len,int *rparam_len)
2693 {
2694         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2695         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2696         char *str2 = skip_string(param,tpscnt,str1);
2697         char *QueueName = skip_string(param,tpscnt,str2);
2698         int errcode = NERR_notsupported;
2699         int snum;
2700         WERROR werr = WERR_OK;
2701
2702         if (!str1 || !str2 || !QueueName) {
2703                 return False;
2704         }
2705
2706         /* check it's a supported varient */
2707         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2708                 return(False);
2709
2710         *rparam_len = 4;
2711         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2712         if (!*rparam) {
2713                 return False;
2714         }
2715         *rdata_len = 0;
2716
2717         if (skip_string(param,tpscnt,QueueName) == NULL) {
2718                 return False;
2719         }
2720         snum = print_queue_snum(QueueName);
2721
2722         if (snum == -1) {
2723                 errcode = NERR_JobNotFound;
2724                 goto out;
2725         }
2726
2727         switch (function) {
2728         case 74: /* Pause queue */
2729                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2730                 break;
2731         case 75: /* Resume queue */
2732                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2733                 break;
2734         case 103: /* Purge */
2735                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2736                 break;
2737         }
2738
2739         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2740
2741  out:
2742         SSVAL(*rparam,0,errcode);
2743         SSVAL(*rparam,2,0);             /* converter word */
2744
2745         return(True);
2746 }
2747
2748 /****************************************************************************
2749   set the property of a print job (undocumented?)
2750   ? function = 0xb -> set name of print job
2751   ? function = 0x6 -> move print job up/down
2752   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2753   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2754 ****************************************************************************/
2755
2756 static int check_printjob_info(struct pack_desc* desc,
2757                                int uLevel, char* id)
2758 {
2759         desc->subformat = NULL;
2760         switch( uLevel ) {
2761         case 0: desc->format = "W"; break;
2762         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2763         case 2: desc->format = "WWzWWDDzz"; break;
2764         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2765         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2766         default:
2767                 DEBUG(0,("check_printjob_info: invalid level %d\n",
2768                         uLevel ));
2769                 return False;
2770         }
2771         if (id == NULL || strcmp(desc->format,id) != 0) {
2772                 DEBUG(0,("check_printjob_info: invalid format %s\n",
2773                         id ? id : "<NULL>" ));
2774                 return False;
2775         }
2776         return True;
2777 }
2778
2779 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2780                                 char *param, int tpscnt,
2781                                 char *data, int tdscnt,
2782                                 int mdrcnt,int mprcnt,
2783                                 char **rdata,char **rparam,
2784                                 int *rdata_len,int *rparam_len)
2785 {
2786         struct pack_desc desc;
2787         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2788         char *str2 = skip_string(param,tpscnt,str1);
2789         char *p = skip_string(param,tpscnt,str2);
2790         uint32 jobid;
2791         fstring sharename;
2792         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2793         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2794         int place, errcode;
2795
2796         if (!str1 || !str2 || !p) {
2797                 return False;
2798         }
2799         /*
2800          * We use 1 here not 2 as we're checking
2801          * the last byte we want to access is safe.
2802          */
2803         if (!is_offset_safe(param,tpscnt,p,1)) {
2804                 return False;
2805         }
2806         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2807                 return False;
2808         *rparam_len = 4;
2809         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2810         if (!*rparam) {
2811                 return False;
2812         }
2813
2814         if (!share_defined(sharename)) {
2815                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2816                          sharename));
2817                 return False;
2818         }
2819   
2820         *rdata_len = 0;
2821         
2822         /* check it's a supported varient */
2823         if ((strcmp(str1,"WWsTP")) || 
2824             (!check_printjob_info(&desc,uLevel,str2)))
2825                 return(False);
2826
2827         if (!print_job_exists(sharename, jobid)) {
2828                 errcode=NERR_JobNotFound;
2829                 goto out;
2830         }
2831
2832         errcode = NERR_notsupported;
2833
2834         switch (function) {
2835         case 0x6:
2836                 /* change job place in the queue, 
2837                    data gives the new place */
2838                 place = SVAL(data,0);
2839                 if (print_job_set_place(sharename, jobid, place)) {
2840                         errcode=NERR_Success;
2841                 }
2842                 break;
2843
2844         case 0xb:   
2845                 /* change print job name, data gives the name */
2846                 if (print_job_set_name(sharename, jobid, data)) {
2847                         errcode=NERR_Success;
2848                 }
2849                 break;
2850
2851         default:
2852                 return False;
2853         }
2854
2855  out:
2856         SSVALS(*rparam,0,errcode);
2857         SSVAL(*rparam,2,0);             /* converter word */
2858         
2859         return(True);
2860 }
2861
2862
2863 /****************************************************************************
2864  Get info about the server.
2865 ****************************************************************************/
2866
2867 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2868                                 char *param, int tpscnt,
2869                                 char *data, int tdscnt,
2870                                 int mdrcnt,int mprcnt,
2871                                 char **rdata,char **rparam,
2872                                 int *rdata_len,int *rparam_len)
2873 {
2874         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2875         char *str2 = skip_string(param,tpscnt,str1);
2876         char *p = skip_string(param,tpscnt,str2);
2877         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2878         char *p2;
2879         int struct_len;
2880
2881         if (!str1 || !str2 || !p) {
2882                 return False;
2883         }
2884
2885         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2886
2887         /* check it's a supported varient */
2888         if (!prefix_ok(str1,"WrLh")) {
2889                 return False;
2890         }
2891
2892         switch( uLevel ) {
2893                 case 0:
2894                         if (strcmp(str2,"B16") != 0) {
2895                                 return False;
2896                         }
2897                         struct_len = 16;
2898                         break;
2899                 case 1:
2900                         if (strcmp(str2,"B16BBDz") != 0) {
2901                                 return False;
2902                         }
2903                         struct_len = 26;
2904                         break;
2905                 case 2:
2906                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2907                                 return False;
2908                         }
2909                         struct_len = 134;
2910                         break;
2911                 case 3:
2912                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2913                                 return False;
2914                         }
2915                         struct_len = 144;
2916                         break;
2917                 case 20:
2918                         if (strcmp(str2,"DN") != 0) {
2919                                 return False;
2920                         }
2921                         struct_len = 6;
2922                         break;
2923                 case 50:
2924                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2925                                 return False;
2926                         }
2927                         struct_len = 42;
2928                         break;
2929                 default:
2930                         return False;
2931         }
2932
2933         *rdata_len = mdrcnt;
2934         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2935         if (!*rdata) {
2936                 return False;
2937         }
2938
2939         p = *rdata;
2940         p2 = p + struct_len;
2941         if (uLevel != 20) {
2942                 srvstr_push(NULL, 0, p,global_myname(),16,
2943                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2944         }
2945         p += 16;
2946         if (uLevel > 0) {
2947                 struct srv_info_struct *servers=NULL;
2948                 int i,count;
2949                 char *comment = NULL;
2950                 TALLOC_CTX *ctx = talloc_tos();
2951                 uint32 servertype= lp_default_server_announce();
2952
2953                 comment = talloc_strdup(ctx,lp_serverstring());
2954                 if (!comment) {
2955                         return false;
2956                 }
2957
2958                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2959                         for (i=0;i<count;i++) {
2960                                 if (strequal(servers[i].name,global_myname())) {
2961                                         servertype = servers[i].type;
2962                                         TALLOC_FREE(comment);
2963                                         comment = talloc_strdup(ctx,
2964                                                         servers[i].comment);
2965                                         if (comment) {
2966                                                 return false;
2967                                         }
2968                                 }
2969                         }
2970                 }
2971
2972                 SAFE_FREE(servers);
2973
2974                 SCVAL(p,0,lp_major_announce_version());
2975                 SCVAL(p,1,lp_minor_announce_version());
2976                 SIVAL(p,2,servertype);
2977
2978                 if (mdrcnt == struct_len) {
2979                         SIVAL(p,6,0);
2980                 } else {
2981                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2982                         comment = talloc_sub_advanced(ctx,
2983                                                 lp_servicename(SNUM(conn)),
2984                                                 conn->user,
2985                                                 conn->connectpath,
2986                                                 conn->gid,
2987                                                 get_current_username(),
2988                                                 current_user_info.domain,
2989                                                 comment);
2990                         if (comment) {
2991                                 return false;
2992                         }
2993                         if (mdrcnt - struct_len <= 0) {
2994                                 return false;
2995                         }
2996                         push_ascii(p2,
2997                                 comment,
2998                                 MIN(mdrcnt - struct_len,
2999                                         MAX_SERVER_STRING_LENGTH),
3000                                 STR_TERMINATE);
3001                         p2 = skip_string(*rdata,*rdata_len,p2);
3002                         if (!p2) {
3003                                 return False;
3004                         }
3005                 }
3006         }
3007
3008         if (uLevel > 1) {
3009                 return False;           /* not yet implemented */
3010         }
3011
3012         *rdata_len = PTR_DIFF(p2,*rdata);
3013
3014         *rparam_len = 6;
3015         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3016         if (!*rparam) {
3017                 return False;
3018         }
3019         SSVAL(*rparam,0,NERR_Success);
3020         SSVAL(*rparam,2,0);             /* converter word */
3021         SSVAL(*rparam,4,*rdata_len);
3022
3023         return True;
3024 }
3025
3026 /****************************************************************************
3027  Get info about the server.
3028 ****************************************************************************/
3029
3030 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3031                                 char *param, int tpscnt,
3032                                 char *data, int tdscnt,
3033                                 int mdrcnt,int mprcnt,
3034                                 char **rdata,char **rparam,
3035                                 int *rdata_len,int *rparam_len)
3036 {
3037         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3038         char *str2 = skip_string(param,tpscnt,str1);
3039         char *p = skip_string(param,tpscnt,str2);
3040         char *p2;
3041         char *endp;
3042         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3043
3044         if (!str1 || !str2 || !p) {
3045                 return False;
3046         }
3047
3048         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3049
3050         *rparam_len = 6;
3051         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3052         if (!*rparam) {
3053                 return False;
3054         }
3055
3056         /* check it's a supported varient */
3057         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3058                 return False;
3059         }
3060
3061         *rdata_len = mdrcnt + 1024;
3062         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3063         if (!*rdata) {
3064                 return False;
3065         }
3066
3067         SSVAL(*rparam,0,NERR_Success);
3068         SSVAL(*rparam,2,0);             /* converter word */
3069
3070         p = *rdata;
3071         endp = *rdata + *rdata_len;
3072
3073         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3074         if (!p2) {
3075                 return False;
3076         }
3077
3078         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3079         strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3080         strupper_m(p2);
3081         p2 = skip_string(*rdata,*rdata_len,p2);
3082         if (!p2) {
3083                 return False;
3084         }
3085         p += 4;
3086
3087         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3088         strlcpy(p2,current_user_info.smb_name,PTR_DIFF(endp,p2));
3089         p2 = skip_string(*rdata,*rdata_len,p2);
3090         if (!p2) {
3091                 return False;
3092         }
3093         p += 4;
3094
3095         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3096         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3097         strupper_m(p2);
3098         p2 = skip_string(*rdata,*rdata_len,p2);
3099         if (!p2) {
3100                 return False;
3101         }
3102         p += 4;
3103
3104         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3105         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3106         p += 2;
3107
3108         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3109         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));   /* don't know.  login domain?? */
3110         p2 = skip_string(*rdata,*rdata_len,p2);
3111         if (!p2) {
3112                 return False;
3113         }
3114         p += 4;
3115
3116         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3117         strlcpy(p2,"",PTR_DIFF(endp,p2));
3118         p2 = skip_string(*rdata,*rdata_len,p2);
3119         if (!p2) {
3120                 return False;
3121         }
3122         p += 4;
3123
3124         *rdata_len = PTR_DIFF(p2,*rdata);
3125
3126         SSVAL(*rparam,4,*rdata_len);
3127
3128         return True;
3129 }
3130
3131 /****************************************************************************
3132   get info about a user
3133
3134     struct user_info_11 {
3135         char                usri11_name[21];  0-20 
3136         char                usri11_pad;       21 
3137         char                *usri11_comment;  22-25 
3138         char            *usri11_usr_comment;  26-29
3139         unsigned short      usri11_priv;      30-31
3140         unsigned long       usri11_auth_flags; 32-35
3141         long                usri11_password_age; 36-39
3142         char                *usri11_homedir; 40-43
3143         char            *usri11_parms; 44-47
3144         long                usri11_last_logon; 48-51
3145         long                usri11_last_logoff; 52-55
3146         unsigned short      usri11_bad_pw_count; 56-57
3147         unsigned short      usri11_num_logons; 58-59
3148         char                *usri11_logon_server; 60-63
3149         unsigned short      usri11_country_code; 64-65
3150         char            *usri11_workstations; 66-69
3151         unsigned long       usri11_max_storage; 70-73
3152         unsigned short      usri11_units_per_week; 74-75
3153         unsigned char       *usri11_logon_hours; 76-79
3154         unsigned short      usri11_code_page; 80-81
3155     };
3156
3157 where:
3158
3159   usri11_name specifies the user name for which information is retireved
3160
3161   usri11_pad aligns the next data structure element to a word boundary
3162
3163   usri11_comment is a null terminated ASCII comment
3164
3165   usri11_user_comment is a null terminated ASCII comment about the user
3166
3167   usri11_priv specifies the level of the privilege assigned to the user.
3168        The possible values are:
3169
3170 Name             Value  Description
3171 USER_PRIV_GUEST  0      Guest privilege
3172 USER_PRIV_USER   1      User privilege
3173 USER_PRV_ADMIN   2      Administrator privilege
3174
3175   usri11_auth_flags specifies the account operator privileges. The
3176        possible values are:
3177
3178 Name            Value   Description
3179 AF_OP_PRINT     0       Print operator
3180
3181
3182 Leach, Naik                                        [Page 28]
3183 \f
3184
3185
3186 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3187
3188
3189 AF_OP_COMM      1       Communications operator
3190 AF_OP_SERVER    2       Server operator
3191 AF_OP_ACCOUNTS  3       Accounts operator
3192
3193
3194   usri11_password_age specifies how many seconds have elapsed since the
3195        password was last changed.
3196
3197   usri11_home_dir points to a null terminated ASCII string that contains
3198        the path name of the user's home directory.
3199
3200   usri11_parms points to a null terminated ASCII string that is set
3201        aside for use by applications.
3202
3203   usri11_last_logon specifies the time when the user last logged on.
3204        This value is stored as the number of seconds elapsed since
3205        00:00:00, January 1, 1970.
3206
3207   usri11_last_logoff specifies the time when the user last logged off.
3208        This value is stored as the number of seconds elapsed since
3209        00:00:00, January 1, 1970. A value of 0 means the last logoff
3210        time is unknown.
3211
3212   usri11_bad_pw_count specifies the number of incorrect passwords
3213        entered since the last successful logon.
3214
3215   usri11_log1_num_logons specifies the number of times this user has
3216        logged on. A value of -1 means the number of logons is unknown.
3217
3218   usri11_logon_server points to a null terminated ASCII string that
3219        contains the name of the server to which logon requests are sent.
3220        A null string indicates logon requests should be sent to the
3221        domain controller.
3222
3223   usri11_country_code specifies the country code for the user's language
3224        of choice.
3225
3226   usri11_workstations points to a null terminated ASCII string that
3227        contains the names of workstations the user may log on from.
3228        There may be up to 8 workstations, with the names separated by
3229        commas. A null strings indicates there are no restrictions.
3230
3231   usri11_max_storage specifies the maximum amount of disk space the user
3232        can occupy. A value of 0xffffffff indicates there are no
3233        restrictions.
3234
3235   usri11_units_per_week specifies the equal number of time units into
3236        which a week is divided. This value must be equal to 168.
3237
3238   usri11_logon_hours points to a 21 byte (168 bits) string that
3239        specifies the time during which the user can log on. Each bit
3240        represents one unique hour in a week. The first bit (bit 0, word
3241        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3242
3243
3244
3245 Leach, Naik                                        [Page 29]
3246 \f
3247
3248
3249 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3250
3251
3252        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3253        are no restrictions.
3254
3255   usri11_code_page specifies the code page for the user's language of
3256        choice
3257
3258 All of the pointers in this data structure need to be treated
3259 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
3260 to be ignored. The converter word returned in the parameters section
3261 needs to be subtracted from the lower 16 bits to calculate an offset
3262 into the return buffer where this ASCII string resides.
3263
3264 There is no auxiliary data in the response.
3265
3266   ****************************************************************************/
3267
3268 #define usri11_name           0 
3269 #define usri11_pad            21
3270 #define usri11_comment        22
3271 #define usri11_usr_comment    26
3272 #define usri11_full_name      30
3273 #define usri11_priv           34
3274 #define usri11_auth_flags     36
3275 #define usri11_password_age   40
3276 #define usri11_homedir        44
3277 #define usri11_parms          48
3278 #define usri11_last_logon     52
3279 #define usri11_last_logoff    56
3280 #define usri11_bad_pw_count   60
3281 #define usri11_num_logons     62
3282 #define usri11_logon_server   64
3283 #define usri11_country_code   68
3284 #define usri11_workstations   70
3285 #define usri11_max_storage    74
3286 #define usri11_units_per_week 78
3287 #define usri11_logon_hours    80
3288 #define usri11_code_page      84
3289 #define usri11_end            86
3290
3291 #define USER_PRIV_GUEST 0
3292 #define USER_PRIV_USER 1
3293 #define USER_PRIV_ADMIN 2
3294
3295 #define AF_OP_PRINT     0 
3296 #define AF_OP_COMM      1
3297 #define AF_OP_SERVER    2
3298 #define AF_OP_ACCOUNTS  3
3299
3300
3301 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3302                                 char *param, int tpscnt,
3303                                 char *data, int tdscnt,
3304                                 int mdrcnt,int mprcnt,
3305                                 char **rdata,char **rparam,
3306                                 int *rdata_len,int *rparam_len)
3307 {
3308         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3309         char *str2 = skip_string(param,tpscnt,str1);
3310         char *UserName = skip_string(param,tpscnt,str2);
3311         char *p = skip_string(param,tpscnt,UserName);
3312         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3313         char *p2;
3314         char *endp;
3315         const char *level_string;
3316
3317         /* get NIS home of a previously validated user - simeon */
3318         /* With share level security vuid will always be zero.
3319            Don't depend on vuser being non-null !!. JRA */
3320         user_struct *vuser = get_valid_user_struct(vuid);
3321         if(vuser != NULL) {
3322                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid,
3323                         vuser->user.unix_name));
3324         }
3325
3326         if (!str1 || !str2 || !UserName || !p) {
3327                 return False;
3328         }
3329
3330         *rparam_len = 6;
3331         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3332         if (!*rparam) {
3333                 return False;
3334         }
3335
3336         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3337
3338         /* check it's a supported variant */
3339         if (strcmp(str1,"zWrLh") != 0) {
3340                 return False;
3341         }
3342         switch( uLevel ) {
3343                 case 0: level_string = "B21"; break;
3344                 case 1: level_string = "B21BB16DWzzWz"; break;
3345                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3346                 case 10: level_string = "B21Bzzz"; break;
3347                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3348                 default: return False;
3349         }
3350
3351         if (strcmp(level_string,str2) != 0) {
3352                 return False;
3353         }
3354
3355         *rdata_len = mdrcnt + 1024;
3356         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3357         if (!*rdata) {
3358                 return False;
3359         }
3360
3361         SSVAL(*rparam,0,NERR_Success);
3362         SSVAL(*rparam,2,0);             /* converter word */
3363
3364         p = *rdata;
3365         endp = *rdata + *rdata_len;
3366         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3367         if (!p2) {
3368                 return False;
3369         }
3370
3371         memset(p,0,21);
3372         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3373
3374         if (uLevel > 0) {
3375                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3376                 *p2 = 0;
3377         }
3378
3379         if (uLevel >= 10) {
3380                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3381                 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3382                 p2 = skip_string(*rdata,*rdata_len,p2);
3383                 if (!p2) {
3384                         return False;
3385                 }
3386
3387                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3388                 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3389                 p2 = skip_string(*rdata,*rdata_len,p2);
3390                 if (!p2) {
3391                         return False;
3392                 }
3393
3394                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3395                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3396                 strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2));
3397                 p2 = skip_string(*rdata,*rdata_len,p2);
3398                 if (!p2) {
3399                         return False;
3400                 }
3401         }
3402
3403         if (uLevel == 11) {
3404                 /* modelled after NTAS 3.51 reply */
3405                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3406                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3407                 SIVALS(p,usri11_password_age,-1);               /* password age */
3408                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3409                 strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2));
3410                 p2 = skip_string(*rdata,*rdata_len,p2);
3411                 if (!p2) {
3412                         return False;
3413                 }
3414                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3415                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3416                 p2 = skip_string(*rdata,*rdata_len,p2);
3417                 if (!p2) {
3418                         return False;
3419                 }
3420                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3421                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3422                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3423                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3424                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3425                 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3426                 p2 = skip_string(*rdata,*rdata_len,p2);
3427                 if (!p2) {
3428                         return False;
3429                 }
3430                 SSVAL(p,usri11_country_code,0);         /* country code */
3431
3432                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3433                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3434                 p2 = skip_string(*rdata,*rdata_len,p2);
3435                 if (!p2) {
3436                         return False;
3437                 }
3438
3439                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3440                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3441                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3442
3443                 /* a simple way to get logon hours at all times. */
3444                 memset(p2,0xff,21);
3445                 SCVAL(p2,21,0);           /* fix zero termination */
3446                 p2 = skip_string(*rdata,*rdata_len,p2);
3447                 if (!p2) {
3448                         return False;
3449                 }
3450
3451                 SSVAL(p,usri11_code_page,0);            /* code page */
3452         }
3453
3454         if (uLevel == 1 || uLevel == 2) {
3455                 memset(p+22,' ',16);    /* password */
3456                 SIVALS(p,38,-1);                /* password age */
3457                 SSVAL(p,42,
3458                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3459                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3460                 strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2));
3461                 p2 = skip_string(*rdata,*rdata_len,p2);
3462                 if (!p2) {
3463                         return False;
3464                 }
3465                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3466                 *p2++ = 0;
3467                 SSVAL(p,52,0);          /* flags */
3468                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3469                 strlcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "",PTR_DIFF(endp,p2));
3470                 p2 = skip_string(*rdata,*rdata_len,p2);
3471                 if (!p2) {
3472                         return False;
3473                 }
3474                 if (uLevel == 2) {
3475                         SIVAL(p,60,0);          /* auth_flags */
3476                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3477                         strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2));
3478                         p2 = skip_string(*rdata,*rdata_len,p2);
3479                         if (!p2) {
3480                                 return False;
3481                         }
3482                         SIVAL(p,68,0);          /* urs_comment */
3483                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3484                         strlcpy(p2,"",PTR_DIFF(endp,p2));
3485                         p2 = skip_string(*rdata,*rdata_len,p2);
3486                         if (!p2) {
3487                                 return False;
3488                         }
3489                         SIVAL(p,76,0);          /* workstations */
3490                         SIVAL(p,80,0);          /* last_logon */
3491                         SIVAL(p,84,0);          /* last_logoff */
3492                         SIVALS(p,88,-1);                /* acct_expires */
3493                         SIVALS(p,92,-1);                /* max_storage */
3494                         SSVAL(p,96,168);        /* units_per_week */
3495                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3496                         memset(p2,-1,21);
3497                         p2 += 21;
3498                         SSVALS(p,102,-1);       /* bad_pw_count */
3499                         SSVALS(p,104,-1);       /* num_logons */
3500                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3501                         {
3502                                 TALLOC_CTX *ctx = talloc_tos();
3503                                 int space_rem = *rdata_len - (p2 - *rdata);
3504                                 char *tmp;
3505
3506                                 if (space_rem <= 0) {
3507                                         return false;
3508                                 }
3509                                 tmp = talloc_strdup(ctx, "\\\\%L");
3510                                 if (!tmp) {
3511                                         return false;
3512                                 }
3513                                 tmp = talloc_sub_basic(ctx,
3514                                                 "",
3515                                                 "",
3516                                                 tmp);
3517                                 if (!tmp) {
3518                                         return false;
3519                                 }
3520
3521                                 push_ascii(p2,
3522                                         tmp,
3523                                         space_rem,
3524                                         STR_TERMINATE);
3525                         }
3526                         p2 = skip_string(*rdata,*rdata_len,p2);
3527                         if (!p2) {
3528                                 return False;
3529                         }
3530                         SSVAL(p,110,49);        /* country_code */
3531                         SSVAL(p,112,860);       /* code page */
3532                 }
3533         }
3534
3535         *rdata_len = PTR_DIFF(p2,*rdata);
3536
3537         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3538
3539         return(True);
3540 }
3541
3542 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3543                                 char *param, int tpscnt,
3544                                 char *data, int tdscnt,
3545                                 int mdrcnt,int mprcnt,
3546                                 char **rdata,char **rparam,
3547                                 int *rdata_len,int *rparam_len)
3548 {
3549         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3550         char *str2 = skip_string(param,tpscnt,str1);
3551         char *p = skip_string(param,tpscnt,str2);
3552         int uLevel;
3553         struct pack_desc desc;
3554         char* name;
3555                 /* With share level security vuid will always be zero.
3556                    Don't depend on vuser being non-null !!. JRA */
3557         user_struct *vuser = get_valid_user_struct(vuid);
3558
3559         if (!str1 || !str2 || !p) {
3560                 return False;
3561         }
3562
3563         if(vuser != NULL) {
3564                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3565                         vuser->user.unix_name));
3566         }
3567
3568         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3569         name = get_safe_str_ptr(param,tpscnt,p,2);
3570         if (!name) {
3571                 return False;
3572         }
3573
3574         memset((char *)&desc,'\0',sizeof(desc));
3575
3576         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3577
3578         /* check it's a supported varient */
3579         if (strcmp(str1,"OOWb54WrLh") != 0) {
3580                 return False;
3581         }
3582         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3583                 return False;
3584         }
3585         if (mdrcnt > 0) {
3586                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3587                 if (!*rdata) {
3588                         return False;
3589                 }
3590         }
3591
3592         desc.base = *rdata;
3593         desc.buflen = mdrcnt;
3594         desc.subformat = NULL;
3595         desc.format = str2;
3596   
3597         if (init_package(&desc,1,0)) {
3598                 PACKI(&desc,"W",0);             /* code */
3599                 PACKS(&desc,"B21",name);        /* eff. name */
3600                 PACKS(&desc,"B","");            /* pad */
3601                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3602                 PACKI(&desc,"D",0);             /* auth flags XXX */
3603                 PACKI(&desc,"W",0);             /* num logons */
3604                 PACKI(&desc,"W",0);             /* bad pw count */
3605                 PACKI(&desc,"D",0);             /* last logon */
3606                 PACKI(&desc,"D",-1);            /* last logoff */
3607                 PACKI(&desc,"D",-1);            /* logoff time */
3608                 PACKI(&desc,"D",-1);            /* kickoff time */
3609                 PACKI(&desc,"D",0);             /* password age */
3610                 PACKI(&desc,"D",0);             /* password can change */
3611                 PACKI(&desc,"D",-1);            /* password must change */
3612
3613                 {
3614                         fstring mypath;
3615                         fstrcpy(mypath,"\\\\");
3616                         fstrcat(mypath,get_local_machine_name());
3617                         strupper_m(mypath);
3618                         PACKS(&desc,"z",mypath); /* computer */
3619                 }
3620
3621                 PACKS(&desc,"z",lp_workgroup());/* domain */
3622                 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3623                 PACKI(&desc,"D",0x00000000);            /* reserved */
3624         }
3625
3626         *rdata_len = desc.usedlen;
3627         *rparam_len = 6;
3628         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3629         if (!*rparam) {
3630                 return False;
3631         }
3632         SSVALS(*rparam,0,desc.errcode);
3633         SSVAL(*rparam,2,0);
3634         SSVAL(*rparam,4,desc.neededlen);
3635
3636         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3637
3638         return True;
3639 }
3640
3641 /****************************************************************************
3642  api_WAccessGetUserPerms
3643 ****************************************************************************/
3644
3645 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3646                                 char *param, int tpscnt,
3647                                 char *data, int tdscnt,
3648                                 int mdrcnt,int mprcnt,
3649                                 char **rdata,char **rparam,
3650                                 int *rdata_len,int *rparam_len)
3651 {
3652         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3653         char *str2 = skip_string(param,tpscnt,str1);
3654         char *user = skip_string(param,tpscnt,str2);
3655         char *resource = skip_string(param,tpscnt,user);
3656
3657         if (!str1 || !str2 || !user || !resource) {
3658                 return False;
3659         }
3660
3661         if (skip_string(param,tpscnt,resource) == NULL) {
3662                 return False;
3663         }
3664         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3665
3666         /* check it's a supported varient */
3667         if (strcmp(str1,"zzh") != 0) {
3668                 return False;
3669         }
3670         if (strcmp(str2,"") != 0) {
3671                 return False;
3672         }
3673
3674         *rparam_len = 6;
3675         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3676         if (!*rparam) {
3677                 return False;
3678         }
3679         SSVALS(*rparam,0,0);            /* errorcode */
3680         SSVAL(*rparam,2,0);             /* converter word */
3681         SSVAL(*rparam,4,0x7f);  /* permission flags */
3682
3683         return True;
3684 }
3685
3686 /****************************************************************************
3687   api_WPrintJobEnumerate
3688   ****************************************************************************/
3689
3690 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3691                                 char *param, int tpscnt,
3692                                 char *data, int tdscnt,
3693                                 int mdrcnt,int mprcnt,
3694                                 char **rdata,char **rparam,
3695                                 int *rdata_len,int *rparam_len)
3696 {
3697         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3698         char *str2 = skip_string(param,tpscnt,str1);
3699         char *p = skip_string(param,tpscnt,str2);
3700         int uLevel;
3701         int count;
3702         int i;
3703         int snum;
3704         fstring sharename;
3705         uint32 jobid;
3706         struct pack_desc desc;
3707         print_queue_struct *queue=NULL;
3708         print_status_struct status;
3709         char *tmpdata=NULL;
3710
3711         if (!str1 || !str2 || !p) {
3712                 return False;
3713         }
3714
3715         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3716
3717         memset((char *)&desc,'\0',sizeof(desc));
3718         memset((char *)&status,'\0',sizeof(status));
3719
3720         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3721
3722         /* check it's a supported varient */
3723         if (strcmp(str1,"WWrLh") != 0) {
3724                 return False;
3725         }
3726         if (!check_printjob_info(&desc,uLevel,str2)) {
3727                 return False;
3728         }
3729
3730         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3731                 return False;
3732         }
3733
3734         snum = lp_servicenumber( sharename);
3735         if (snum < 0 || !VALID_SNUM(snum)) {
3736                 return(False);
3737         }
3738
3739         count = print_queue_status(snum,&queue,&status);
3740         for (i = 0; i < count; i++) {
3741                 if (queue[i].job == jobid) {
3742                         break;
3743                 }
3744         }
3745
3746         if (mdrcnt > 0) {
3747                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3748                 if (!*rdata) {
3749                         return False;
3750                 }
3751                 desc.base = *rdata;
3752                 desc.buflen = mdrcnt;
3753         } else {
3754                 /*
3755                  * Don't return data but need to get correct length
3756                  *  init_package will return wrong size if buflen=0
3757                  */
3758                 desc.buflen = getlen(desc.format);
3759                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3760         }
3761
3762         if (init_package(&desc,1,0)) {
3763                 if (i < count) {
3764                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3765                         *rdata_len = desc.usedlen;
3766                 } else {
3767                         desc.errcode = NERR_JobNotFound;
3768                         *rdata_len = 0;
3769                 }
3770         }
3771
3772         *rparam_len = 6;
3773         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3774         if (!*rparam) {
3775                 return False;
3776         }
3777         SSVALS(*rparam,0,desc.errcode);
3778         SSVAL(*rparam,2,0);
3779         SSVAL(*rparam,4,desc.neededlen);
3780
3781         SAFE_FREE(queue);
3782         SAFE_FREE(tmpdata);
3783
3784         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3785
3786         return True;
3787 }
3788
3789 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3790                                 char *param, int tpscnt,
3791                                 char *data, int tdscnt,
3792                                 int mdrcnt,int mprcnt,
3793                                 char **rdata,char **rparam,
3794                                 int *rdata_len,int *rparam_len)
3795 {
3796         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3797         char *str2 = skip_string(param,tpscnt,str1);
3798         char *p = skip_string(param,tpscnt,str2);
3799         char *name = p;
3800         int uLevel;
3801         int count;
3802         int i, succnt=0;
3803         int snum;
3804         struct pack_desc desc;
3805         print_queue_struct *queue=NULL;
3806         print_status_struct status;
3807
3808         if (!str1 || !str2 || !p) {
3809                 return False;
3810         }
3811
3812         memset((char *)&desc,'\0',sizeof(desc));
3813         memset((char *)&status,'\0',sizeof(status));
3814
3815         p = skip_string(param,tpscnt,p);
3816         if (!p) {
3817                 return False;
3818         }
3819         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3820
3821         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3822
3823         /* check it's a supported variant */
3824         if (strcmp(str1,"zWrLeh") != 0) {
3825                 return False;
3826         }
3827     
3828         if (uLevel > 2) {
3829                 return False;   /* defined only for uLevel 0,1,2 */
3830         }
3831     
3832         if (!check_printjob_info(&desc,uLevel,str2)) { 
3833                 return False;
3834         }
3835
3836         snum = find_service(name);
3837         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3838                 return False;
3839         }
3840
3841         count = print_queue_status(snum,&queue,&status);
3842         if (mdrcnt > 0) {
3843                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3844                 if (!*rdata) {
3845                         return False;
3846                 }
3847         }
3848         desc.base = *rdata;
3849         desc.buflen = mdrcnt;
3850
3851         if (init_package(&desc,count,0)) {
3852                 succnt = 0;
3853                 for (i = 0; i < count; i++) {
3854                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3855                         if (desc.errcode == NERR_Success) {
3856                                 succnt = i+1;
3857                         }
3858                 }
3859         }
3860
3861         *rdata_len = desc.usedlen;
3862
3863         *rparam_len = 8;
3864         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3865         if (!*rparam) {
3866                 return False;
3867         }
3868         SSVALS(*rparam,0,desc.errcode);
3869         SSVAL(*rparam,2,0);
3870         SSVAL(*rparam,4,succnt);
3871         SSVAL(*rparam,6,count);
3872
3873         SAFE_FREE(queue);
3874
3875         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3876
3877         return True;
3878 }
3879
3880 static int check_printdest_info(struct pack_desc* desc,
3881                                 int uLevel, char* id)
3882 {
3883         desc->subformat = NULL;
3884         switch( uLevel ) {
3885                 case 0:
3886                         desc->format = "B9";
3887                         break;
3888                 case 1:
3889                         desc->format = "B9B21WWzW";
3890                         break;
3891                 case 2:
3892                         desc->format = "z";
3893                         break;
3894                 case 3:
3895                         desc->format = "zzzWWzzzWW";
3896                         break;
3897                 default:
3898                         DEBUG(0,("check_printdest_info: invalid level %d\n",
3899                                 uLevel));
3900                         return False;
3901         }
3902         if (id == NULL || strcmp(desc->format,id) != 0) {
3903                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
3904                         id ? id : "<NULL>" ));
3905                 return False;
3906         }
3907         return True;
3908 }
3909
3910 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3911                                 struct pack_desc* desc)
3912 {
3913         char buf[100];
3914
3915         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3916         buf[sizeof(buf)-1] = 0;
3917         strupper_m(buf);
3918
3919         if (uLevel <= 1) {
3920                 PACKS(desc,"B9",buf);   /* szName */
3921                 if (uLevel == 1) {
3922                         PACKS(desc,"B21","");   /* szUserName */
3923                         PACKI(desc,"W",0);              /* uJobId */
3924                         PACKI(desc,"W",0);              /* fsStatus */
3925                         PACKS(desc,"z","");     /* pszStatus */
3926                         PACKI(desc,"W",0);              /* time */
3927                 }
3928         }
3929
3930         if (uLevel == 2 || uLevel == 3) {
3931                 PACKS(desc,"z",buf);            /* pszPrinterName */
3932                 if (uLevel == 3) {
3933                         PACKS(desc,"z","");     /* pszUserName */
3934                         PACKS(desc,"z","");     /* pszLogAddr */
3935                         PACKI(desc,"W",0);              /* uJobId */
3936                         PACKI(desc,"W",0);              /* fsStatus */
3937                         PACKS(desc,"z","");     /* pszStatus */
3938                         PACKS(desc,"z","");     /* pszComment */
3939                         PACKS(desc,"z","NULL"); /* pszDrivers */
3940                         PACKI(desc,"W",0);              /* time */
3941                         PACKI(desc,"W",0);              /* pad1 */
3942                 }
3943         }
3944 }
3945
3946 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3947                                 char *param, int tpscnt,
3948                                 char *data, int tdscnt,
3949                                 int mdrcnt,int mprcnt,
3950                                 char **rdata,char **rparam,
3951                                 int *rdata_len,int *rparam_len)
3952 {
3953         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3954         char *str2 = skip_string(param,tpscnt,str1);
3955         char *p = skip_string(param,tpscnt,str2);
3956         char* PrinterName = p;
3957         int uLevel;
3958         struct pack_desc desc;
3959         int snum;
3960         char *tmpdata=NULL;
3961
3962         if (!str1 || !str2 || !p) {
3963                 return False;
3964         }
3965
3966         memset((char *)&desc,'\0',sizeof(desc));
3967
3968         p = skip_string(param,tpscnt,p);
3969         if (!p) {
3970                 return False;
3971         }
3972         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3973
3974         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3975
3976         /* check it's a supported varient */
3977         if (strcmp(str1,"zWrLh") != 0) {
3978                 return False;
3979         }
3980         if (!check_printdest_info(&desc,uLevel,str2)) {
3981                 return False;
3982         }
3983
3984         snum = find_service(PrinterName);
3985         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3986                 *rdata_len = 0;
3987                 desc.errcode = NERR_DestNotFound;
3988                 desc.neededlen = 0;
3989         } else {
3990                 if (mdrcnt > 0) {
3991                         *rdata = smb_realloc_limit(*rdata,mdrcnt);
3992                         if (!*rdata) {
3993                                 return False;
3994                         }
3995                         desc.base = *rdata;
3996                         desc.buflen = mdrcnt;
3997                 } else {
3998                         /*
3999                          * Don't return data but need to get correct length
4000                          * init_package will return wrong size if buflen=0
4001                          */
4002                         desc.buflen = getlen(desc.format);
4003                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4004                 }
4005                 if (init_package(&desc,1,0)) {
4006                         fill_printdest_info(conn,snum,uLevel,&desc);
4007                 }
4008                 *rdata_len = desc.usedlen;
4009         }
4010
4011         *rparam_len = 6;
4012         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4013         if (!*rparam) {
4014                 return False;
4015         }
4016         SSVALS(*rparam,0,desc.errcode);
4017         SSVAL(*rparam,2,0);
4018         SSVAL(*rparam,4,desc.neededlen);
4019
4020         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4021         SAFE_FREE(tmpdata);
4022
4023         return True;
4024 }
4025
4026 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4027                                 char *param, int tpscnt,
4028                                 char *data, int tdscnt,
4029                                 int mdrcnt,int mprcnt,
4030                                 char **rdata,char **rparam,
4031                                 int *rdata_len,int *rparam_len)
4032 {
4033         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4034         char *str2 = skip_string(param,tpscnt,str1);
4035         char *p = skip_string(param,tpscnt,str2);
4036         int uLevel;
4037         int queuecnt;
4038         int i, n, succnt=0;
4039         struct pack_desc desc;
4040         int services = lp_numservices();
4041
4042         if (!str1 || !str2 || !p) {
4043                 return False;
4044         }
4045
4046         memset((char *)&desc,'\0',sizeof(desc));
4047
4048         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4049
4050         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4051
4052         /* check it's a supported varient */
4053         if (strcmp(str1,"WrLeh") != 0) {
4054                 return False;
4055         }
4056         if (!check_printdest_info(&desc,uLevel,str2)) {
4057                 return False;
4058         }
4059
4060         queuecnt = 0;
4061         for (i = 0; i < services; i++) {
4062                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4063                         queuecnt++;
4064                 }
4065         }
4066
4067         if (mdrcnt > 0) {
4068                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4069                 if (!*rdata) {
4070                         return False;
4071                 }
4072         }
4073
4074         desc.base = *rdata;
4075         desc.buflen = mdrcnt;
4076         if (init_package(&desc,queuecnt,0)) {    
4077                 succnt = 0;
4078                 n = 0;
4079                 for (i = 0; i < services; i++) {
4080                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4081                                 fill_printdest_info(conn,i,uLevel,&desc);
4082                                 n++;
4083                                 if (desc.errcode == NERR_Success) {
4084                                         succnt = n;
4085                                 }
4086                         }
4087                 }
4088         }
4089
4090         *rdata_len = desc.usedlen;
4091
4092         *rparam_len = 8;
4093         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4094         if (!*rparam) {
4095                 return False;
4096         }
4097         SSVALS(*rparam,0,desc.errcode);
4098         SSVAL(*rparam,2,0);
4099         SSVAL(*rparam,4,succnt);
4100         SSVAL(*rparam,6,queuecnt);
4101
4102         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4103
4104         return True;
4105 }
4106
4107 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4108                                 char *param, int tpscnt,
4109                                 char *data, int tdscnt,
4110                                 int mdrcnt,int mprcnt,
4111                                 char **rdata,char **rparam,
4112                                 int *rdata_len,int *rparam_len)
4113 {
4114         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4115         char *str2 = skip_string(param,tpscnt,str1);
4116         char *p = skip_string(param,tpscnt,str2);
4117         int uLevel;
4118         int succnt;
4119         struct pack_desc desc;
4120
4121         if (!str1 || !str2 || !p) {
4122                 return False;
4123         }
4124
4125         memset((char *)&desc,'\0',sizeof(desc));
4126
4127         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4128
4129         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4130
4131         /* check it's a supported varient */
4132         if (strcmp(str1,"WrLeh") != 0) {
4133                 return False;
4134         }
4135         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4136                 return False;
4137         }
4138
4139         if (mdrcnt > 0) {
4140                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4141                 if (!*rdata) {
4142                         return False;
4143                 }
4144         }
4145         desc.base = *rdata;
4146         desc.buflen = mdrcnt;
4147         if (init_package(&desc,1,0)) {
4148                 PACKS(&desc,"B41","NULL");
4149         }
4150
4151         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4152
4153         *rdata_len = desc.usedlen;
4154
4155         *rparam_len = 8;
4156         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4157         if (!*rparam) {
4158                 return False;
4159         }
4160         SSVALS(*rparam,0,desc.errcode);
4161         SSVAL(*rparam,2,0);
4162         SSVAL(*rparam,4,succnt);
4163         SSVAL(*rparam,6,1);
4164
4165         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4166
4167         return True;
4168 }
4169
4170 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4171                                 char *param, int tpscnt,
4172                                 char *data, int tdscnt,
4173                                 int mdrcnt,int mprcnt,
4174                                 char **rdata,char **rparam,
4175                                 int *rdata_len,int *rparam_len)
4176 {
4177         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4178         char *str2 = skip_string(param,tpscnt,str1);
4179         char *p = skip_string(param,tpscnt,str2);
4180         int uLevel;
4181         int succnt;
4182         struct pack_desc desc;
4183
4184         if (!str1 || !str2 || !p) {
4185                 return False;
4186         }
4187         memset((char *)&desc,'\0',sizeof(desc));
4188
4189         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4190
4191         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4192
4193         /* check it's a supported varient */
4194         if (strcmp(str1,"WrLeh") != 0) {
4195                 return False;
4196         }
4197         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4198                 return False;
4199         }
4200
4201         if (mdrcnt > 0) {
4202                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4203                 if (!*rdata) {
4204                         return False;
4205                 }
4206         }
4207         desc.base = *rdata;
4208         desc.buflen = mdrcnt;
4209         desc.format = str2;
4210         if (init_package(&desc,1,0)) {
4211                 PACKS(&desc,"B13","lpd");
4212         }
4213
4214         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4215
4216         *rdata_len = desc.usedlen;
4217
4218         *rparam_len = 8;
4219         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4220         if (!*rparam) {
4221                 return False;
4222         }
4223         SSVALS(*rparam,0,desc.errcode);
4224         SSVAL(*rparam,2,0);
4225         SSVAL(*rparam,4,succnt);
4226         SSVAL(*rparam,6,1);
4227
4228         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4229
4230         return True;
4231 }
4232
4233 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4234                                 char *param, int tpscnt,
4235                                 char *data, int tdscnt,
4236                                 int mdrcnt,int mprcnt,
4237                                 char **rdata,char **rparam,
4238                                 int *rdata_len,int *rparam_len)
4239 {
4240         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4241         char *str2 = skip_string(param,tpscnt,str1);
4242         char *p = skip_string(param,tpscnt,str2);
4243         int uLevel;
4244         int succnt;
4245         struct pack_desc desc;
4246
4247         if (!str1 || !str2 || !p) {
4248                 return False;
4249         }
4250
4251         memset((char *)&desc,'\0',sizeof(desc));
4252
4253         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4254
4255         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4256
4257         /* check it's a supported varient */
4258         if (strcmp(str1,"WrLeh") != 0) {
4259                 return False;
4260         }
4261         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4262                 return False;
4263         }
4264
4265         if (mdrcnt > 0) {
4266                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4267                 if (!*rdata) {
4268                         return False;
4269                 }
4270         }
4271         memset((char *)&desc,'\0',sizeof(desc));
4272         desc.base = *rdata;
4273         desc.buflen = mdrcnt;
4274         desc.format = str2;
4275         if (init_package(&desc,1,0)) {
4276                 PACKS(&desc,"B13","lp0");
4277         }
4278
4279         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4280
4281         *rdata_len = desc.usedlen;
4282
4283         *rparam_len = 8;
4284         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4285         if (!*rparam) {
4286                 return False;
4287         }
4288         SSVALS(*rparam,0,desc.errcode);
4289         SSVAL(*rparam,2,0);
4290         SSVAL(*rparam,4,succnt);
4291         SSVAL(*rparam,6,1);
4292
4293         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4294
4295         return True;
4296 }
4297
4298 /****************************************************************************
4299  List open sessions
4300  ****************************************************************************/
4301
4302 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4303                                 char *param, int tpscnt,
4304                                 char *data, int tdscnt,
4305                                 int mdrcnt,int mprcnt,
4306                                 char **rdata,char **rparam,
4307                                 int *rdata_len,int *rparam_len)
4308
4309 {
4310         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4311         char *str2 = skip_string(param,tpscnt,str1);
4312         char *p = skip_string(param,tpscnt,str2);
4313         int uLevel;
4314         struct pack_desc desc;
4315         struct sessionid *session_list;
4316         int i, num_sessions;
4317
4318         if (!str1 || !str2 || !p) {
4319                 return False;
4320         }
4321
4322         memset((char *)&desc,'\0',sizeof(desc));
4323
4324         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4325
4326         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4327         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4328         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4329
4330         /* check it's a supported varient */
4331         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4332                 return False;
4333         }
4334         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4335                 return False;
4336         }
4337
4338         num_sessions = list_sessions(talloc_tos(), &session_list);
4339
4340         if (mdrcnt > 0) {
4341                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4342                 if (!*rdata) {
4343                         return False;
4344                 }
4345         }
4346         memset((char *)&desc,'\0',sizeof(desc));
4347         desc.base = *rdata;
4348         desc.buflen = mdrcnt;
4349         desc.format = str2;
4350         if (!init_package(&desc,num_sessions,0)) {
4351                 return False;
4352         }
4353
4354         for(i=0; i<num_sessions; i++) {
4355                 PACKS(&desc, "z", session_list[i].remote_machine);
4356                 PACKS(&desc, "z", session_list[i].username);
4357                 PACKI(&desc, "W", 1); /* num conns */
4358                 PACKI(&desc, "W", 0); /* num opens */
4359                 PACKI(&desc, "W", 1); /* num users */
4360                 PACKI(&desc, "D", 0); /* session time */
4361                 PACKI(&desc, "D", 0); /* idle time */
4362                 PACKI(&desc, "D", 0); /* flags */
4363                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4364         }
4365
4366         *rdata_len = desc.usedlen;
4367
4368         *rparam_len = 8;
4369         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4370         if (!*rparam) {
4371                 return False;
4372         }
4373         SSVALS(*rparam,0,desc.errcode);
4374         SSVAL(*rparam,2,0); /* converter */
4375         SSVAL(*rparam,4,num_sessions); /* count */
4376
4377         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4378
4379         return True;
4380 }
4381
4382
4383 /****************************************************************************
4384  The buffer was too small.
4385  ****************************************************************************/
4386
4387 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4388                          int mdrcnt, int mprcnt,
4389                          char **rdata, char **rparam,
4390                          int *rdata_len, int *rparam_len)
4391 {
4392         *rparam_len = MIN(*rparam_len,mprcnt);
4393         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4394         if (!*rparam) {
4395                 return False;
4396         }
4397
4398         *rdata_len = 0;
4399
4400         SSVAL(*rparam,0,NERR_BufTooSmall);
4401
4402         DEBUG(3,("Supplied buffer too small in API command\n"));
4403
4404         return True;
4405 }
4406
4407 /****************************************************************************
4408  The request is not supported.
4409  ****************************************************************************/
4410
4411 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4412                                 char *param, int tpscnt,
4413                                 char *data, int tdscnt,
4414                                 int mdrcnt, int mprcnt,
4415                                 char **rdata, char **rparam,
4416                                 int *rdata_len, int *rparam_len)
4417 {
4418         *rparam_len = 4;
4419         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4420         if (!*rparam) {
4421                 return False;
4422         }
4423
4424         *rdata_len = 0;
4425
4426         SSVAL(*rparam,0,NERR_notsupported);
4427         SSVAL(*rparam,2,0);             /* converter word */
4428
4429         DEBUG(3,("Unsupported API command\n"));
4430
4431         return True;
4432 }
4433
4434 static const struct {
4435         const char *name;
4436         int id;
4437         bool (*fn)(connection_struct *, uint16,
4438                         char *, int,
4439                         char *, int,
4440                         int,int,char **,char **,int *,int *);
4441         bool auth_user;         /* Deny anonymous access? */
4442 } api_commands[] = {
4443         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
4444         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
4445         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
4446         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
4447         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
4448         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
4449         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
4450         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
4451         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
4452         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
4453         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
4454         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
4455         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
4456         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
4457         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4458         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4459         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4460         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4461         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4462         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4463         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4464         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4465         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4466         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4467         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4468         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4469         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4470         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4471         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4472         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4473         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4474         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4475         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4476         {NULL,          -1,     api_Unsupported}
4477         /*  The following RAP calls are not implemented by Samba:
4478
4479         RAP_WFileEnum2 - anon not OK 
4480         */
4481 };
4482
4483
4484 /****************************************************************************
4485  Handle remote api calls.
4486 ****************************************************************************/
4487
4488 void api_reply(connection_struct *conn, uint16 vuid,
4489                struct smb_request *req,
4490                char *data, char *params,
4491                int tdscnt, int tpscnt,
4492                int mdrcnt, int mprcnt)
4493 {
4494         int api_command;
4495         char *rdata = NULL;
4496         char *rparam = NULL;
4497         const char *name1 = NULL;
4498         const char *name2 = NULL;
4499         int rdata_len = 0;
4500         int rparam_len = 0;
4501         bool reply=False;
4502         int i;
4503
4504         if (!params) {
4505                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4506                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4507                 return;
4508         }
4509
4510         if (tpscnt < 2) {
4511                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4512                 return;
4513         }
4514         api_command = SVAL(params,0);
4515         /* Is there a string at position params+2 ? */
4516         if (skip_string(params,tpscnt,params+2)) {
4517                 name1 = params + 2;
4518         } else {
4519                 name1 = "";
4520         }
4521         name2 = skip_string(params,tpscnt,params+2);
4522         if (!name2) {
4523                 name2 = "";
4524         }
4525
4526         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4527                 api_command,
4528                 name1,
4529                 name2,
4530                 tdscnt,tpscnt,mdrcnt,mprcnt));
4531
4532         for (i=0;api_commands[i].name;i++) {
4533                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4534                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4535                         break;
4536                 }
4537         }
4538
4539         /* Check whether this api call can be done anonymously */
4540
4541         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4542                 user_struct *user = get_valid_user_struct(vuid);
4543
4544                 if (!user || user->guest) {
4545                         reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4546                         return;
4547                 }
4548         }
4549
4550         rdata = (char *)SMB_MALLOC(1024);
4551         if (rdata) {
4552                 memset(rdata,'\0',1024);
4553         }
4554
4555         rparam = (char *)SMB_MALLOC(1024);
4556         if (rparam) {
4557                 memset(rparam,'\0',1024);
4558         }
4559
4560         if(!rdata || !rparam) {
4561                 DEBUG(0,("api_reply: malloc fail !\n"));
4562                 SAFE_FREE(rdata);
4563                 SAFE_FREE(rparam);
4564                 reply_nterror(req, NT_STATUS_NO_MEMORY);
4565                 return;
4566         }
4567
4568         reply = api_commands[i].fn(conn,
4569                                 vuid,
4570                                 params,tpscnt,  /* params + length */
4571                                 data,tdscnt,    /* data + length */
4572                                 mdrcnt,mprcnt,
4573                                 &rdata,&rparam,&rdata_len,&rparam_len);
4574
4575
4576         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4577                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4578                                         &rdata,&rparam,&rdata_len,&rparam_len);
4579         }
4580
4581         /* if we get False back then it's actually unsupported */
4582         if (!reply) {
4583                 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4584                         &rdata,&rparam,&rdata_len,&rparam_len);
4585         }
4586
4587         /* If api_Unsupported returns false we can't return anything. */
4588         if (reply) {
4589                 send_trans_reply(req, rparam, rparam_len,
4590                                  rdata, rdata_len, False);
4591         }
4592
4593         SAFE_FREE(rdata);
4594         SAFE_FREE(rparam);
4595         return;
4596 }