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