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