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