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