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