Rever e80ceb1d7355c8c46a2ed90d5721cf367640f4e8 "Remove more uses of "extern struct...
[amitay/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,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3771                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3772                 SIVALS(p,usri11_password_age,-1);               /* password age */
3773                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3774                 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3775                 p2 = skip_string(*rdata,*rdata_len,p2);
3776                 if (!p2) {
3777                         return False;
3778                 }
3779                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3780                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3781                 p2 = skip_string(*rdata,*rdata_len,p2);
3782                 if (!p2) {
3783                         return False;
3784                 }
3785                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3786                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3787                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3788                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3789                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3790                 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3791                 p2 = skip_string(*rdata,*rdata_len,p2);
3792                 if (!p2) {
3793                         return False;
3794                 }
3795                 SSVAL(p,usri11_country_code,0);         /* country code */
3796
3797                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3798                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3799                 p2 = skip_string(*rdata,*rdata_len,p2);
3800                 if (!p2) {
3801                         return False;
3802                 }
3803
3804                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3805                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3806                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3807
3808                 /* a simple way to get logon hours at all times. */
3809                 memset(p2,0xff,21);
3810                 SCVAL(p2,21,0);           /* fix zero termination */
3811                 p2 = skip_string(*rdata,*rdata_len,p2);
3812                 if (!p2) {
3813                         return False;
3814                 }
3815
3816                 SSVAL(p,usri11_code_page,0);            /* code page */
3817         }
3818
3819         if (uLevel == 1 || uLevel == 2) {
3820                 memset(p+22,' ',16);    /* password */
3821                 SIVALS(p,38,-1);                /* password age */
3822                 SSVAL(p,42,
3823                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3824                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3825                 strlcpy(p2, vuser ? pdb_get_homedir(
3826                                 vuser->server_info->sam_account) : "",
3827                         PTR_DIFF(endp,p2));
3828                 p2 = skip_string(*rdata,*rdata_len,p2);
3829                 if (!p2) {
3830                         return False;
3831                 }
3832                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3833                 *p2++ = 0;
3834                 SSVAL(p,52,0);          /* flags */
3835                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3836                 strlcpy(p2, vuser ? pdb_get_logon_script(
3837                                 vuser->server_info->sam_account) : "",
3838                         PTR_DIFF(endp,p2));
3839                 p2 = skip_string(*rdata,*rdata_len,p2);
3840                 if (!p2) {
3841                         return False;
3842                 }
3843                 if (uLevel == 2) {
3844                         SIVAL(p,60,0);          /* auth_flags */
3845                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3846                         strlcpy(p2,((vuser != NULL)
3847                                     ? pdb_get_fullname(vuser->server_info->sam_account)
3848                                     : UserName),PTR_DIFF(endp,p2));
3849                         p2 = skip_string(*rdata,*rdata_len,p2);
3850                         if (!p2) {
3851                                 return False;
3852                         }
3853                         SIVAL(p,68,0);          /* urs_comment */
3854                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3855                         strlcpy(p2,"",PTR_DIFF(endp,p2));
3856                         p2 = skip_string(*rdata,*rdata_len,p2);
3857                         if (!p2) {
3858                                 return False;
3859                         }
3860                         SIVAL(p,76,0);          /* workstations */
3861                         SIVAL(p,80,0);          /* last_logon */
3862                         SIVAL(p,84,0);          /* last_logoff */
3863                         SIVALS(p,88,-1);                /* acct_expires */
3864                         SIVALS(p,92,-1);                /* max_storage */
3865                         SSVAL(p,96,168);        /* units_per_week */
3866                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3867                         memset(p2,-1,21);
3868                         p2 += 21;
3869                         SSVALS(p,102,-1);       /* bad_pw_count */
3870                         SSVALS(p,104,-1);       /* num_logons */
3871                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3872                         {
3873                                 TALLOC_CTX *ctx = talloc_tos();
3874                                 int space_rem = *rdata_len - (p2 - *rdata);
3875                                 char *tmp;
3876
3877                                 if (space_rem <= 0) {
3878                                         return false;
3879                                 }
3880                                 tmp = talloc_strdup(ctx, "\\\\%L");
3881                                 if (!tmp) {
3882                                         return false;
3883                                 }
3884                                 tmp = talloc_sub_basic(ctx,
3885                                                 "",
3886                                                 "",
3887                                                 tmp);
3888                                 if (!tmp) {
3889                                         return false;
3890                                 }
3891
3892                                 push_ascii(p2,
3893                                         tmp,
3894                                         space_rem,
3895                                         STR_TERMINATE);
3896                         }
3897                         p2 = skip_string(*rdata,*rdata_len,p2);
3898                         if (!p2) {
3899                                 return False;
3900                         }
3901                         SSVAL(p,110,49);        /* country_code */
3902                         SSVAL(p,112,860);       /* code page */
3903                 }
3904         }
3905
3906         *rdata_len = PTR_DIFF(p2,*rdata);
3907
3908         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3909
3910         return(True);
3911 }
3912
3913 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3914                                 char *param, int tpscnt,
3915                                 char *data, int tdscnt,
3916                                 int mdrcnt,int mprcnt,
3917                                 char **rdata,char **rparam,
3918                                 int *rdata_len,int *rparam_len)
3919 {
3920         struct smbd_server_connection *sconn = smbd_server_conn;
3921         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3922         char *str2 = skip_string(param,tpscnt,str1);
3923         char *p = skip_string(param,tpscnt,str2);
3924         int uLevel;
3925         struct pack_desc desc;
3926         char* name;
3927                 /* With share level security vuid will always be zero.
3928                    Don't depend on vuser being non-null !!. JRA */
3929         user_struct *vuser = get_valid_user_struct(sconn, vuid);
3930
3931         if (!str1 || !str2 || !p) {
3932                 return False;
3933         }
3934
3935         if(vuser != NULL) {
3936                 DEBUG(3,("  Username of UID %d is %s\n",
3937                          (int)vuser->server_info->utok.uid,
3938                          vuser->server_info->unix_name));
3939         }
3940
3941         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3942         name = get_safe_str_ptr(param,tpscnt,p,2);
3943         if (!name) {
3944                 return False;
3945         }
3946
3947         memset((char *)&desc,'\0',sizeof(desc));
3948
3949         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3950
3951         /* check it's a supported varient */
3952         if (strcmp(str1,"OOWb54WrLh") != 0) {
3953                 return False;
3954         }
3955         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3956                 return False;
3957         }
3958         if (mdrcnt > 0) {
3959                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3960                 if (!*rdata) {
3961                         return False;
3962                 }
3963         }
3964
3965         desc.base = *rdata;
3966         desc.buflen = mdrcnt;
3967         desc.subformat = NULL;
3968         desc.format = str2;
3969
3970         if (init_package(&desc,1,0)) {
3971                 PACKI(&desc,"W",0);             /* code */
3972                 PACKS(&desc,"B21",name);        /* eff. name */
3973                 PACKS(&desc,"B","");            /* pad */
3974                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3975                 PACKI(&desc,"D",0);             /* auth flags XXX */
3976                 PACKI(&desc,"W",0);             /* num logons */
3977                 PACKI(&desc,"W",0);             /* bad pw count */
3978                 PACKI(&desc,"D",0);             /* last logon */
3979                 PACKI(&desc,"D",-1);            /* last logoff */
3980                 PACKI(&desc,"D",-1);            /* logoff time */
3981                 PACKI(&desc,"D",-1);            /* kickoff time */
3982                 PACKI(&desc,"D",0);             /* password age */
3983                 PACKI(&desc,"D",0);             /* password can change */
3984                 PACKI(&desc,"D",-1);            /* password must change */
3985
3986                 {
3987                         fstring mypath;
3988                         fstrcpy(mypath,"\\\\");
3989                         fstrcat(mypath,get_local_machine_name());
3990                         strupper_m(mypath);
3991                         PACKS(&desc,"z",mypath); /* computer */
3992                 }
3993
3994                 PACKS(&desc,"z",lp_workgroup());/* domain */
3995                 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3996                               vuser->server_info->sam_account) : ""); /* script path */
3997                 PACKI(&desc,"D",0x00000000);            /* reserved */
3998         }
3999
4000         *rdata_len = desc.usedlen;
4001         *rparam_len = 6;
4002         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4003         if (!*rparam) {
4004                 return False;
4005         }
4006         SSVALS(*rparam,0,desc.errcode);
4007         SSVAL(*rparam,2,0);
4008         SSVAL(*rparam,4,desc.neededlen);
4009
4010         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4011
4012         return True;
4013 }
4014
4015 /****************************************************************************
4016  api_WAccessGetUserPerms
4017 ****************************************************************************/
4018
4019 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4020                                 char *param, int tpscnt,
4021                                 char *data, int tdscnt,
4022                                 int mdrcnt,int mprcnt,
4023                                 char **rdata,char **rparam,
4024                                 int *rdata_len,int *rparam_len)
4025 {
4026         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4027         char *str2 = skip_string(param,tpscnt,str1);
4028         char *user = skip_string(param,tpscnt,str2);
4029         char *resource = skip_string(param,tpscnt,user);
4030
4031         if (!str1 || !str2 || !user || !resource) {
4032                 return False;
4033         }
4034
4035         if (skip_string(param,tpscnt,resource) == NULL) {
4036                 return False;
4037         }
4038         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4039
4040         /* check it's a supported varient */
4041         if (strcmp(str1,"zzh") != 0) {
4042                 return False;
4043         }
4044         if (strcmp(str2,"") != 0) {
4045                 return False;
4046         }
4047
4048         *rparam_len = 6;
4049         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4050         if (!*rparam) {
4051                 return False;
4052         }
4053         SSVALS(*rparam,0,0);            /* errorcode */
4054         SSVAL(*rparam,2,0);             /* converter word */
4055         SSVAL(*rparam,4,0x7f);  /* permission flags */
4056
4057         return True;
4058 }
4059
4060 /****************************************************************************
4061   api_WPrintJobEnumerate
4062   ****************************************************************************/
4063
4064 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4065                                 char *param, int tpscnt,
4066                                 char *data, int tdscnt,
4067                                 int mdrcnt,int mprcnt,
4068                                 char **rdata,char **rparam,
4069                                 int *rdata_len,int *rparam_len)
4070 {
4071         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4072         char *str2 = skip_string(param,tpscnt,str1);
4073         char *p = skip_string(param,tpscnt,str2);
4074         int uLevel;
4075         int count;
4076         int i;
4077         int snum;
4078         fstring sharename;
4079         uint32 jobid;
4080         struct pack_desc desc;
4081         print_queue_struct *queue=NULL;
4082         print_status_struct status;
4083         char *tmpdata=NULL;
4084
4085         if (!str1 || !str2 || !p) {
4086                 return False;
4087         }
4088
4089         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4090
4091         memset((char *)&desc,'\0',sizeof(desc));
4092         memset((char *)&status,'\0',sizeof(status));
4093
4094         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4095
4096         /* check it's a supported varient */
4097         if (strcmp(str1,"WWrLh") != 0) {
4098                 return False;
4099         }
4100         if (!check_printjob_info(&desc,uLevel,str2)) {
4101                 return False;
4102         }
4103
4104         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4105                 return False;
4106         }
4107
4108         snum = lp_servicenumber( sharename);
4109         if (snum < 0 || !VALID_SNUM(snum)) {
4110                 return(False);
4111         }
4112
4113         count = print_queue_status(snum,&queue,&status);
4114         for (i = 0; i < count; i++) {
4115                 if (queue[i].job == jobid) {
4116                         break;
4117                 }
4118         }
4119
4120         if (mdrcnt > 0) {
4121                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4122                 if (!*rdata) {
4123                         return False;
4124                 }
4125                 desc.base = *rdata;
4126                 desc.buflen = mdrcnt;
4127         } else {
4128                 /*
4129                  * Don't return data but need to get correct length
4130                  *  init_package will return wrong size if buflen=0
4131                  */
4132                 desc.buflen = getlen(desc.format);
4133                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4134         }
4135
4136         if (init_package(&desc,1,0)) {
4137                 if (i < count) {
4138                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4139                         *rdata_len = desc.usedlen;
4140                 } else {
4141                         desc.errcode = NERR_JobNotFound;
4142                         *rdata_len = 0;
4143                 }
4144         }
4145
4146         *rparam_len = 6;
4147         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4148         if (!*rparam) {
4149                 return False;
4150         }
4151         SSVALS(*rparam,0,desc.errcode);
4152         SSVAL(*rparam,2,0);
4153         SSVAL(*rparam,4,desc.neededlen);
4154
4155         SAFE_FREE(queue);
4156         SAFE_FREE(tmpdata);
4157
4158         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4159
4160         return True;
4161 }
4162
4163 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4164                                 char *param, int tpscnt,
4165                                 char *data, int tdscnt,
4166                                 int mdrcnt,int mprcnt,
4167                                 char **rdata,char **rparam,
4168                                 int *rdata_len,int *rparam_len)
4169 {
4170         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4171         char *str2 = skip_string(param,tpscnt,str1);
4172         char *p = skip_string(param,tpscnt,str2);
4173         char *name = p;
4174         int uLevel;
4175         int count;
4176         int i, succnt=0;
4177         int snum;
4178         struct pack_desc desc;
4179         print_queue_struct *queue=NULL;
4180         print_status_struct status;
4181
4182         if (!str1 || !str2 || !p) {
4183                 return False;
4184         }
4185
4186         memset((char *)&desc,'\0',sizeof(desc));
4187         memset((char *)&status,'\0',sizeof(status));
4188
4189         p = skip_string(param,tpscnt,p);
4190         if (!p) {
4191                 return False;
4192         }
4193         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4194
4195         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4196
4197         /* check it's a supported variant */
4198         if (strcmp(str1,"zWrLeh") != 0) {
4199                 return False;
4200         }
4201
4202         if (uLevel > 2) {
4203                 return False;   /* defined only for uLevel 0,1,2 */
4204         }
4205
4206         if (!check_printjob_info(&desc,uLevel,str2)) { 
4207                 return False;
4208         }
4209
4210         snum = find_service(name);
4211         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4212                 return False;
4213         }
4214
4215         count = print_queue_status(snum,&queue,&status);
4216         if (mdrcnt > 0) {
4217                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4218                 if (!*rdata) {
4219                         return False;
4220                 }
4221         }
4222         desc.base = *rdata;
4223         desc.buflen = mdrcnt;
4224
4225         if (init_package(&desc,count,0)) {
4226                 succnt = 0;
4227                 for (i = 0; i < count; i++) {
4228                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4229                         if (desc.errcode == NERR_Success) {
4230                                 succnt = i+1;
4231                         }
4232                 }
4233         }
4234
4235         *rdata_len = desc.usedlen;
4236
4237         *rparam_len = 8;
4238         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4239         if (!*rparam) {
4240                 return False;
4241         }
4242         SSVALS(*rparam,0,desc.errcode);
4243         SSVAL(*rparam,2,0);
4244         SSVAL(*rparam,4,succnt);
4245         SSVAL(*rparam,6,count);
4246
4247         SAFE_FREE(queue);
4248
4249         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4250
4251         return True;
4252 }
4253
4254 static int check_printdest_info(struct pack_desc* desc,
4255                                 int uLevel, char* id)
4256 {
4257         desc->subformat = NULL;
4258         switch( uLevel ) {
4259                 case 0:
4260                         desc->format = "B9";
4261                         break;
4262                 case 1:
4263                         desc->format = "B9B21WWzW";
4264                         break;
4265                 case 2:
4266                         desc->format = "z";
4267                         break;
4268                 case 3:
4269                         desc->format = "zzzWWzzzWW";
4270                         break;
4271                 default:
4272                         DEBUG(0,("check_printdest_info: invalid level %d\n",
4273                                 uLevel));
4274                         return False;
4275         }
4276         if (id == NULL || strcmp(desc->format,id) != 0) {
4277                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
4278                         id ? id : "<NULL>" ));
4279                 return False;
4280         }
4281         return True;
4282 }
4283
4284 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4285                                 struct pack_desc* desc)
4286 {
4287         char buf[100];
4288
4289         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4290         buf[sizeof(buf)-1] = 0;
4291         strupper_m(buf);
4292
4293         if (uLevel <= 1) {
4294                 PACKS(desc,"B9",buf);   /* szName */
4295                 if (uLevel == 1) {
4296                         PACKS(desc,"B21","");   /* szUserName */
4297                         PACKI(desc,"W",0);              /* uJobId */
4298                         PACKI(desc,"W",0);              /* fsStatus */
4299                         PACKS(desc,"z","");     /* pszStatus */
4300                         PACKI(desc,"W",0);              /* time */
4301                 }
4302         }
4303
4304         if (uLevel == 2 || uLevel == 3) {
4305                 PACKS(desc,"z",buf);            /* pszPrinterName */
4306                 if (uLevel == 3) {
4307                         PACKS(desc,"z","");     /* pszUserName */
4308                         PACKS(desc,"z","");     /* pszLogAddr */
4309                         PACKI(desc,"W",0);              /* uJobId */
4310                         PACKI(desc,"W",0);              /* fsStatus */
4311                         PACKS(desc,"z","");     /* pszStatus */
4312                         PACKS(desc,"z","");     /* pszComment */
4313                         PACKS(desc,"z","NULL"); /* pszDrivers */
4314                         PACKI(desc,"W",0);              /* time */
4315                         PACKI(desc,"W",0);              /* pad1 */
4316                 }
4317         }
4318 }
4319
4320 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4321                                 char *param, int tpscnt,
4322                                 char *data, int tdscnt,
4323                                 int mdrcnt,int mprcnt,
4324                                 char **rdata,char **rparam,
4325                                 int *rdata_len,int *rparam_len)
4326 {
4327         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4328         char *str2 = skip_string(param,tpscnt,str1);
4329         char *p = skip_string(param,tpscnt,str2);
4330         char* PrinterName = p;
4331         int uLevel;
4332         struct pack_desc desc;
4333         int snum;
4334         char *tmpdata=NULL;
4335
4336         if (!str1 || !str2 || !p) {
4337                 return False;
4338         }
4339
4340         memset((char *)&desc,'\0',sizeof(desc));
4341
4342         p = skip_string(param,tpscnt,p);
4343         if (!p) {
4344                 return False;
4345         }
4346         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4347
4348         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4349
4350         /* check it's a supported varient */
4351         if (strcmp(str1,"zWrLh") != 0) {
4352                 return False;
4353         }
4354         if (!check_printdest_info(&desc,uLevel,str2)) {
4355                 return False;
4356         }
4357
4358         snum = find_service(PrinterName);
4359         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4360                 *rdata_len = 0;
4361                 desc.errcode = NERR_DestNotFound;
4362                 desc.neededlen = 0;
4363         } else {
4364                 if (mdrcnt > 0) {
4365                         *rdata = smb_realloc_limit(*rdata,mdrcnt);
4366                         if (!*rdata) {
4367                                 return False;
4368                         }
4369                         desc.base = *rdata;
4370                         desc.buflen = mdrcnt;
4371                 } else {
4372                         /*
4373                          * Don't return data but need to get correct length
4374                          * init_package will return wrong size if buflen=0
4375                          */
4376                         desc.buflen = getlen(desc.format);
4377                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4378                 }
4379                 if (init_package(&desc,1,0)) {
4380                         fill_printdest_info(conn,snum,uLevel,&desc);
4381                 }
4382                 *rdata_len = desc.usedlen;
4383         }
4384
4385         *rparam_len = 6;
4386         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4387         if (!*rparam) {
4388                 return False;
4389         }
4390         SSVALS(*rparam,0,desc.errcode);
4391         SSVAL(*rparam,2,0);
4392         SSVAL(*rparam,4,desc.neededlen);
4393
4394         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4395         SAFE_FREE(tmpdata);
4396
4397         return True;
4398 }
4399
4400 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4401                                 char *param, int tpscnt,
4402                                 char *data, int tdscnt,
4403                                 int mdrcnt,int mprcnt,
4404                                 char **rdata,char **rparam,
4405                                 int *rdata_len,int *rparam_len)
4406 {
4407         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4408         char *str2 = skip_string(param,tpscnt,str1);
4409         char *p = skip_string(param,tpscnt,str2);
4410         int uLevel;
4411         int queuecnt;
4412         int i, n, succnt=0;
4413         struct pack_desc desc;
4414         int services = lp_numservices();
4415
4416         if (!str1 || !str2 || !p) {
4417                 return False;
4418         }
4419
4420         memset((char *)&desc,'\0',sizeof(desc));
4421
4422         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4423
4424         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4425
4426         /* check it's a supported varient */
4427         if (strcmp(str1,"WrLeh") != 0) {
4428                 return False;
4429         }
4430         if (!check_printdest_info(&desc,uLevel,str2)) {
4431                 return False;
4432         }
4433
4434         queuecnt = 0;
4435         for (i = 0; i < services; i++) {
4436                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4437                         queuecnt++;
4438                 }
4439         }
4440
4441         if (mdrcnt > 0) {
4442                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4443                 if (!*rdata) {
4444                         return False;
4445                 }
4446         }
4447
4448         desc.base = *rdata;
4449         desc.buflen = mdrcnt;
4450         if (init_package(&desc,queuecnt,0)) {    
4451                 succnt = 0;
4452                 n = 0;
4453                 for (i = 0; i < services; i++) {
4454                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4455                                 fill_printdest_info(conn,i,uLevel,&desc);
4456                                 n++;
4457                                 if (desc.errcode == NERR_Success) {
4458                                         succnt = n;
4459                                 }
4460                         }
4461                 }
4462         }
4463
4464         *rdata_len = desc.usedlen;
4465
4466         *rparam_len = 8;
4467         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4468         if (!*rparam) {
4469                 return False;
4470         }
4471         SSVALS(*rparam,0,desc.errcode);
4472         SSVAL(*rparam,2,0);
4473         SSVAL(*rparam,4,succnt);
4474         SSVAL(*rparam,6,queuecnt);
4475
4476         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4477
4478         return True;
4479 }
4480
4481 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4482                                 char *param, int tpscnt,
4483                                 char *data, int tdscnt,
4484                                 int mdrcnt,int mprcnt,
4485                                 char **rdata,char **rparam,
4486                                 int *rdata_len,int *rparam_len)
4487 {
4488         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4489         char *str2 = skip_string(param,tpscnt,str1);
4490         char *p = skip_string(param,tpscnt,str2);
4491         int uLevel;
4492         int succnt;
4493         struct pack_desc desc;
4494
4495         if (!str1 || !str2 || !p) {
4496                 return False;
4497         }
4498
4499         memset((char *)&desc,'\0',sizeof(desc));
4500
4501         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4502
4503         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4504
4505         /* check it's a supported varient */
4506         if (strcmp(str1,"WrLeh") != 0) {
4507                 return False;
4508         }
4509         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4510                 return False;
4511         }
4512
4513         if (mdrcnt > 0) {
4514                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4515                 if (!*rdata) {
4516                         return False;
4517                 }
4518         }
4519         desc.base = *rdata;
4520         desc.buflen = mdrcnt;
4521         if (init_package(&desc,1,0)) {
4522                 PACKS(&desc,"B41","NULL");
4523         }
4524
4525         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4526
4527         *rdata_len = desc.usedlen;
4528
4529         *rparam_len = 8;
4530         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4531         if (!*rparam) {
4532                 return False;
4533         }
4534         SSVALS(*rparam,0,desc.errcode);
4535         SSVAL(*rparam,2,0);
4536         SSVAL(*rparam,4,succnt);
4537         SSVAL(*rparam,6,1);
4538
4539         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4540
4541         return True;
4542 }
4543
4544 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4545                                 char *param, int tpscnt,
4546                                 char *data, int tdscnt,
4547                                 int mdrcnt,int mprcnt,
4548                                 char **rdata,char **rparam,
4549                                 int *rdata_len,int *rparam_len)
4550 {
4551         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4552         char *str2 = skip_string(param,tpscnt,str1);
4553         char *p = skip_string(param,tpscnt,str2);
4554         int uLevel;
4555         int succnt;
4556         struct pack_desc desc;
4557
4558         if (!str1 || !str2 || !p) {
4559                 return False;
4560         }
4561         memset((char *)&desc,'\0',sizeof(desc));
4562
4563         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4564
4565         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4566
4567         /* check it's a supported varient */
4568         if (strcmp(str1,"WrLeh") != 0) {
4569                 return False;
4570         }
4571         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4572                 return False;
4573         }
4574
4575         if (mdrcnt > 0) {
4576                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4577                 if (!*rdata) {
4578                         return False;
4579                 }
4580         }
4581         desc.base = *rdata;
4582         desc.buflen = mdrcnt;
4583         desc.format = str2;
4584         if (init_package(&desc,1,0)) {
4585                 PACKS(&desc,"B13","lpd");
4586         }
4587
4588         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4589
4590         *rdata_len = desc.usedlen;
4591
4592         *rparam_len = 8;
4593         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4594         if (!*rparam) {
4595                 return False;
4596         }
4597         SSVALS(*rparam,0,desc.errcode);
4598         SSVAL(*rparam,2,0);
4599         SSVAL(*rparam,4,succnt);
4600         SSVAL(*rparam,6,1);
4601
4602         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4603
4604         return True;
4605 }
4606
4607 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4608                                 char *param, int tpscnt,
4609                                 char *data, int tdscnt,
4610                                 int mdrcnt,int mprcnt,
4611                                 char **rdata,char **rparam,
4612                                 int *rdata_len,int *rparam_len)
4613 {
4614         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4615         char *str2 = skip_string(param,tpscnt,str1);
4616         char *p = skip_string(param,tpscnt,str2);
4617         int uLevel;
4618         int succnt;
4619         struct pack_desc desc;
4620
4621         if (!str1 || !str2 || !p) {
4622                 return False;
4623         }
4624
4625         memset((char *)&desc,'\0',sizeof(desc));
4626
4627         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4628
4629         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4630
4631         /* check it's a supported varient */
4632         if (strcmp(str1,"WrLeh") != 0) {
4633                 return False;
4634         }
4635         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4636                 return False;
4637         }
4638
4639         if (mdrcnt > 0) {
4640                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4641                 if (!*rdata) {
4642                         return False;
4643                 }
4644         }
4645         memset((char *)&desc,'\0',sizeof(desc));
4646         desc.base = *rdata;
4647         desc.buflen = mdrcnt;
4648         desc.format = str2;
4649         if (init_package(&desc,1,0)) {
4650                 PACKS(&desc,"B13","lp0");
4651         }
4652
4653         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4654
4655         *rdata_len = desc.usedlen;
4656
4657         *rparam_len = 8;
4658         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4659         if (!*rparam) {
4660                 return False;
4661         }
4662         SSVALS(*rparam,0,desc.errcode);
4663         SSVAL(*rparam,2,0);
4664         SSVAL(*rparam,4,succnt);
4665         SSVAL(*rparam,6,1);
4666
4667         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4668
4669         return True;
4670 }
4671
4672 /****************************************************************************
4673  List open sessions
4674  ****************************************************************************/
4675
4676 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4677                                 char *param, int tpscnt,
4678                                 char *data, int tdscnt,
4679                                 int mdrcnt,int mprcnt,
4680                                 char **rdata,char **rparam,
4681                                 int *rdata_len,int *rparam_len)
4682
4683 {
4684         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4685         char *str2 = skip_string(param,tpscnt,str1);
4686         char *p = skip_string(param,tpscnt,str2);
4687         int uLevel;
4688         struct pack_desc desc;
4689         struct sessionid *session_list;
4690         int i, num_sessions;
4691
4692         if (!str1 || !str2 || !p) {
4693                 return False;
4694         }
4695
4696         memset((char *)&desc,'\0',sizeof(desc));
4697
4698         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4699
4700         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4701         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4702         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4703
4704         /* check it's a supported varient */
4705         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4706                 return False;
4707         }
4708         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4709                 return False;
4710         }
4711
4712         num_sessions = list_sessions(talloc_tos(), &session_list);
4713
4714         if (mdrcnt > 0) {
4715                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4716                 if (!*rdata) {
4717                         return False;
4718                 }
4719         }
4720         memset((char *)&desc,'\0',sizeof(desc));
4721         desc.base = *rdata;
4722         desc.buflen = mdrcnt;
4723         desc.format = str2;
4724         if (!init_package(&desc,num_sessions,0)) {
4725                 return False;
4726         }
4727
4728         for(i=0; i<num_sessions; i++) {
4729                 PACKS(&desc, "z", session_list[i].remote_machine);
4730                 PACKS(&desc, "z", session_list[i].username);
4731                 PACKI(&desc, "W", 1); /* num conns */
4732                 PACKI(&desc, "W", 0); /* num opens */
4733                 PACKI(&desc, "W", 1); /* num users */
4734                 PACKI(&desc, "D", 0); /* session time */
4735                 PACKI(&desc, "D", 0); /* idle time */
4736                 PACKI(&desc, "D", 0); /* flags */
4737                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4738         }
4739
4740         *rdata_len = desc.usedlen;
4741
4742         *rparam_len = 8;
4743         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4744         if (!*rparam) {
4745                 return False;
4746         }
4747         SSVALS(*rparam,0,desc.errcode);
4748         SSVAL(*rparam,2,0); /* converter */
4749         SSVAL(*rparam,4,num_sessions); /* count */
4750
4751         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4752
4753         return True;
4754 }
4755
4756
4757 /****************************************************************************
4758  The buffer was too small.
4759  ****************************************************************************/
4760
4761 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4762                          int mdrcnt, int mprcnt,
4763                          char **rdata, char **rparam,
4764                          int *rdata_len, int *rparam_len)
4765 {
4766         *rparam_len = MIN(*rparam_len,mprcnt);
4767         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4768         if (!*rparam) {
4769                 return False;
4770         }
4771
4772         *rdata_len = 0;
4773
4774         SSVAL(*rparam,0,NERR_BufTooSmall);
4775
4776         DEBUG(3,("Supplied buffer too small in API command\n"));
4777
4778         return True;
4779 }
4780
4781 /****************************************************************************
4782  The request is not supported.
4783  ****************************************************************************/
4784
4785 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4786                                 char *param, int tpscnt,
4787                                 char *data, int tdscnt,
4788                                 int mdrcnt, int mprcnt,
4789                                 char **rdata, char **rparam,
4790                                 int *rdata_len, int *rparam_len)
4791 {
4792         *rparam_len = 4;
4793         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4794         if (!*rparam) {
4795                 return False;
4796         }
4797
4798         *rdata_len = 0;
4799
4800         SSVAL(*rparam,0,NERR_notsupported);
4801         SSVAL(*rparam,2,0);             /* converter word */
4802
4803         DEBUG(3,("Unsupported API command\n"));
4804
4805         return True;
4806 }
4807
4808 static const struct {
4809         const char *name;
4810         int id;
4811         bool (*fn)(connection_struct *, uint16,
4812                         char *, int,
4813                         char *, int,
4814                         int,int,char **,char **,int *,int *);
4815         bool auth_user;         /* Deny anonymous access? */
4816 } api_commands[] = {
4817         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
4818         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
4819         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
4820         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
4821         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
4822         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
4823         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
4824         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
4825         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
4826         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
4827         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
4828         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
4829         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
4830         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
4831         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4832         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4833         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4834         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4835         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4836         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4837         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4838         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4839         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4840         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4841         {"NetServerEnum2",      RAP_NetServerEnum2,     api_RNetServerEnum2}, /* anon OK */
4842         {"NetServerEnum3",      RAP_NetServerEnum3,     api_RNetServerEnum3}, /* anon OK */
4843         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4844         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4845         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4846         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4847         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4848         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4849         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4850         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4851         {NULL,          -1,     api_Unsupported}
4852         /*  The following RAP calls are not implemented by Samba:
4853
4854         RAP_WFileEnum2 - anon not OK 
4855         */
4856 };
4857
4858
4859 /****************************************************************************
4860  Handle remote api calls.
4861 ****************************************************************************/
4862
4863 void api_reply(connection_struct *conn, uint16 vuid,
4864                struct smb_request *req,
4865                char *data, char *params,
4866                int tdscnt, int tpscnt,
4867                int mdrcnt, int mprcnt)
4868 {
4869         struct smbd_server_connection *sconn = smbd_server_conn;
4870         int api_command;
4871         char *rdata = NULL;
4872         char *rparam = NULL;
4873         const char *name1 = NULL;
4874         const char *name2 = NULL;
4875         int rdata_len = 0;
4876         int rparam_len = 0;
4877         bool reply=False;
4878         int i;
4879
4880         if (!params) {
4881                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4882                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4883                 return;
4884         }
4885
4886         if (tpscnt < 2) {
4887                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4888                 return;
4889         }
4890         api_command = SVAL(params,0);
4891         /* Is there a string at position params+2 ? */
4892         if (skip_string(params,tpscnt,params+2)) {
4893                 name1 = params + 2;
4894         } else {
4895                 name1 = "";
4896         }
4897         name2 = skip_string(params,tpscnt,params+2);
4898         if (!name2) {
4899                 name2 = "";
4900         }
4901
4902         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4903                 api_command,
4904                 name1,
4905                 name2,
4906                 tdscnt,tpscnt,mdrcnt,mprcnt));
4907
4908         for (i=0;api_commands[i].name;i++) {
4909                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4910                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4911                         break;
4912                 }
4913         }
4914
4915         /* Check whether this api call can be done anonymously */
4916
4917         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4918                 user_struct *user = get_valid_user_struct(sconn, vuid);
4919
4920                 if (!user || user->server_info->guest) {
4921                         reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4922                         return;
4923                 }
4924         }
4925
4926         rdata = (char *)SMB_MALLOC(1024);
4927         if (rdata) {
4928                 memset(rdata,'\0',1024);
4929         }
4930
4931         rparam = (char *)SMB_MALLOC(1024);
4932         if (rparam) {
4933                 memset(rparam,'\0',1024);
4934         }
4935
4936         if(!rdata || !rparam) {
4937                 DEBUG(0,("api_reply: malloc fail !\n"));
4938                 SAFE_FREE(rdata);
4939                 SAFE_FREE(rparam);
4940                 reply_nterror(req, NT_STATUS_NO_MEMORY);
4941                 return;
4942         }
4943
4944         reply = api_commands[i].fn(conn,
4945                                 vuid,
4946                                 params,tpscnt,  /* params + length */
4947                                 data,tdscnt,    /* data + length */
4948                                 mdrcnt,mprcnt,
4949                                 &rdata,&rparam,&rdata_len,&rparam_len);
4950
4951
4952         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4953                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4954                                         &rdata,&rparam,&rdata_len,&rparam_len);
4955         }
4956
4957         /* if we get False back then it's actually unsupported */
4958         if (!reply) {
4959                 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4960                         &rdata,&rparam,&rdata_len,&rparam_len);
4961         }
4962
4963         /* If api_Unsupported returns false we can't return anything. */
4964         if (reply) {
4965                 send_trans_reply(conn, req, rparam, rparam_len,
4966                                  rdata, rdata_len, False);
4967         }
4968
4969         SAFE_FREE(rdata);
4970         SAFE_FREE(rparam);
4971         return;
4972 }