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