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