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