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