s3:winbind: remove the method SET_MAPPING from winbind's API
[ira/wip.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                                         conn->server_info,
2239                                         conn->sconn->msg_ctx,
2240                                         &cli);
2241         if (!NT_STATUS_IS_OK(status)) {
2242                 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2243                           nt_errstr(status)));
2244                 res = W_ERROR_V(ntstatus_to_werror(status));
2245                 goto out;
2246         }
2247
2248         info2.name              = sharename;
2249         info2.type              = STYPE_DISKTREE;
2250         info2.comment           = comment;
2251         info2.permissions       = 0;
2252         info2.max_users         = 0;
2253         info2.current_users     = 0;
2254         info2.path              = pathname;
2255         info2.password          = NULL;
2256
2257         info.info2 = &info2;
2258
2259         status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2260                                            cli->srv_name_slash,
2261                                            2,
2262                                            &info,
2263                                            NULL,
2264                                            &werr);
2265         if (!NT_STATUS_IS_OK(status)) {
2266                 res = W_ERROR_V(ntstatus_to_werror(status));
2267                 goto out;
2268         }
2269         if (!W_ERROR_IS_OK(werr)) {
2270                 res = W_ERROR_V(werr);
2271                 goto out;
2272         }
2273
2274         *rparam_len = 6;
2275         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2276         if (!*rparam) {
2277                 return False;
2278         }
2279         SSVAL(*rparam,0,NERR_Success);
2280         SSVAL(*rparam,2,0);             /* converter word */
2281         SSVAL(*rparam,4,*rdata_len);
2282         *rdata_len = 0;
2283
2284         return True;
2285
2286   out:
2287
2288         *rparam_len = 4;
2289         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2290         if (!*rparam) {
2291                 return False;
2292         }
2293         *rdata_len = 0;
2294         SSVAL(*rparam,0,res);
2295         SSVAL(*rparam,2,0);
2296         return True;
2297 }
2298
2299 /****************************************************************************
2300   view list of groups available
2301   ****************************************************************************/
2302
2303 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2304                               connection_struct *conn,uint16 vuid,
2305                                 char *param, int tpscnt,
2306                                 char *data, int tdscnt,
2307                                 int mdrcnt,int mprcnt,
2308                                 char **rdata,char **rparam,
2309                                 int *rdata_len,int *rparam_len)
2310 {
2311         int i;
2312         int errflags=0;
2313         int resume_context, cli_buf_size;
2314         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2315         char *str2 = skip_string(param,tpscnt,str1);
2316         char *p = skip_string(param,tpscnt,str2);
2317
2318         uint32_t num_groups;
2319         uint32_t resume_handle;
2320         struct rpc_pipe_client *samr_pipe;
2321         struct policy_handle samr_handle, domain_handle;
2322         NTSTATUS status;
2323
2324         if (!str1 || !str2 || !p) {
2325                 return False;
2326         }
2327
2328         if (strcmp(str1,"WrLeh") != 0) {
2329                 return False;
2330         }
2331
2332         /* parameters  
2333          * W-> resume context (number of users to skip)
2334          * r -> return parameter pointer to receive buffer 
2335          * L -> length of receive buffer
2336          * e -> return parameter number of entries
2337          * h -> return parameter total number of users
2338          */
2339
2340         if (strcmp("B21",str2) != 0) {
2341                 return False;
2342         }
2343
2344         status = rpc_pipe_open_internal(
2345                 talloc_tos(), &ndr_table_samr.syntax_id,
2346                 conn->server_info, conn->sconn->msg_ctx, &samr_pipe);
2347         if (!NT_STATUS_IS_OK(status)) {
2348                 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2349                           nt_errstr(status)));
2350                 return false;
2351         }
2352
2353         status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2354                                       SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2355         if (!NT_STATUS_IS_OK(status)) {
2356                 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2357                           nt_errstr(status)));
2358                 return false;
2359         }
2360
2361         status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2362                                         SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2363                                         get_global_sam_sid(), &domain_handle);
2364         if (!NT_STATUS_IS_OK(status)) {
2365                 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2366                           nt_errstr(status)));
2367                 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2368                 return false;
2369         }
2370
2371         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2372         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2373         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2374                   "%d\n", resume_context, cli_buf_size));
2375
2376         *rdata_len = cli_buf_size;
2377         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2378         if (!*rdata) {
2379                 return False;
2380         }
2381
2382         p = *rdata;
2383
2384         errflags = NERR_Success;
2385         num_groups = 0;
2386         resume_handle = 0;
2387
2388         while (true) {
2389                 struct samr_SamArray *sam_entries;
2390                 uint32_t num_entries;
2391
2392                 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2393                                                       &domain_handle,
2394                                                       &resume_handle,
2395                                                       &sam_entries, 1,
2396                                                       &num_entries);
2397                 if (!NT_STATUS_IS_OK(status)) {
2398                         DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2399                                    "%s\n", nt_errstr(status)));
2400                         break;
2401                 }
2402
2403                 if (num_entries == 0) {
2404                         DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2405                                    "no entries -- done\n"));
2406                         break;
2407                 }
2408
2409                 for(i=0; i<num_entries; i++) {
2410                         const char *name;
2411
2412                         name = sam_entries->entries[i].name.string;
2413
2414                         if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2415                                 /* set overflow error */
2416                                 DEBUG(3,("overflow on entry %d group %s\n", i,
2417                                          name));
2418                                 errflags=234;
2419                                 break;
2420                         }
2421
2422                         /* truncate the name at 21 chars. */
2423                         memset(p, 0, 21);
2424                         strlcpy(p, name, 21);
2425                         DEBUG(10,("adding entry %d group %s\n", i, p));
2426                         p += 21;
2427                         p += 5; /* Both NT4 and W2k3SP1 do padding here.  No
2428                                  * idea why... */
2429                         num_groups += 1;
2430                 }
2431
2432                 if (errflags != NERR_Success) {
2433                         break;
2434                 }
2435
2436                 TALLOC_FREE(sam_entries);
2437         }
2438
2439         rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2440         rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2441
2442         *rdata_len = PTR_DIFF(p,*rdata);
2443
2444         *rparam_len = 8;
2445         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2446         if (!*rparam) {
2447                 return False;
2448         }
2449         SSVAL(*rparam, 0, errflags);
2450         SSVAL(*rparam, 2, 0);           /* converter word */
2451         SSVAL(*rparam, 4, num_groups);  /* is this right?? */
2452         SSVAL(*rparam, 6, resume_context+num_groups);   /* is this right?? */
2453
2454         return(True);
2455 }
2456
2457 /*******************************************************************
2458  Get groups that a user is a member of.
2459 ******************************************************************/
2460
2461 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2462                                  connection_struct *conn,uint16 vuid,
2463                                 char *param, int tpscnt,
2464                                 char *data, int tdscnt,
2465                                 int mdrcnt,int mprcnt,
2466                                 char **rdata,char **rparam,
2467                                 int *rdata_len,int *rparam_len)
2468 {
2469         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2470         char *str2 = skip_string(param,tpscnt,str1);
2471         char *UserName = skip_string(param,tpscnt,str2);
2472         char *p = skip_string(param,tpscnt,UserName);
2473         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2474         const char *level_string;
2475         int count=0;
2476         bool ret = False;
2477         uint32_t i;
2478         char *endp = NULL;
2479
2480         struct rpc_pipe_client *samr_pipe;
2481         struct policy_handle samr_handle, domain_handle, user_handle;
2482         struct lsa_String name;
2483         struct lsa_Strings names;
2484         struct samr_Ids type, rid;
2485         struct samr_RidWithAttributeArray *rids;
2486         NTSTATUS status;
2487
2488         if (!str1 || !str2 || !UserName || !p) {
2489                 return False;
2490         }
2491
2492         *rparam_len = 8;
2493         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2494         if (!*rparam) {
2495                 return False;
2496         }
2497
2498         /* check it's a supported varient */
2499
2500         if ( strcmp(str1,"zWrLeh") != 0 )
2501                 return False;
2502
2503         switch( uLevel ) {
2504                 case 0:
2505                         level_string = "B21";
2506                         break;
2507                 default:
2508                         return False;
2509         }
2510
2511         if (strcmp(level_string,str2) != 0)
2512                 return False;
2513
2514         *rdata_len = mdrcnt + 1024;
2515         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2516         if (!*rdata) {
2517                 return False;
2518         }
2519
2520         SSVAL(*rparam,0,NERR_Success);
2521         SSVAL(*rparam,2,0);             /* converter word */
2522
2523         p = *rdata;
2524         endp = *rdata + *rdata_len;
2525
2526         status = rpc_pipe_open_internal(
2527                 talloc_tos(), &ndr_table_samr.syntax_id,
2528                 conn->server_info, conn->sconn->msg_ctx, &samr_pipe);
2529         if (!NT_STATUS_IS_OK(status)) {
2530                 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2531                           nt_errstr(status)));
2532                 return false;
2533         }
2534
2535         status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2536                                       SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2537         if (!NT_STATUS_IS_OK(status)) {
2538                 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2539                           nt_errstr(status)));
2540                 return false;
2541         }
2542
2543         status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2544                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2545                                         get_global_sam_sid(), &domain_handle);
2546         if (!NT_STATUS_IS_OK(status)) {
2547                 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2548                           nt_errstr(status)));
2549                 goto close_sam;
2550         }
2551
2552         name.string = UserName;
2553
2554         status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2555                                          &domain_handle, 1, &name,
2556                                          &rid, &type);
2557         if (!NT_STATUS_IS_OK(status)) {
2558                 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2559                           nt_errstr(status)));
2560                 goto close_domain;
2561         }
2562
2563         if (type.ids[0] != SID_NAME_USER) {
2564                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2565                            sid_type_lookup(type.ids[0])));
2566                 goto close_domain;
2567         }
2568
2569         status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2570                                       &domain_handle,
2571                                       SAMR_USER_ACCESS_GET_GROUPS,
2572                                       rid.ids[0], &user_handle);
2573         if (!NT_STATUS_IS_OK(status)) {
2574                 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2575                           nt_errstr(status)));
2576                 goto close_domain;
2577         }
2578
2579         status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2580                                               &user_handle, &rids);
2581         if (!NT_STATUS_IS_OK(status)) {
2582                 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2583                           nt_errstr(status)));
2584                 goto close_user;
2585         }
2586
2587         for (i=0; i<rids->count; i++) {
2588
2589                 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2590                                                 &domain_handle,
2591                                                 1, &rids->rids[i].rid,
2592                                                 &names, &type);
2593                 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2594                         strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2595                         p += 21;
2596                         count++;
2597                 }
2598         }
2599
2600         *rdata_len = PTR_DIFF(p,*rdata);
2601
2602         SSVAL(*rparam,4,count); /* is this right?? */
2603         SSVAL(*rparam,6,count); /* is this right?? */
2604
2605         ret = True;
2606
2607  close_user:
2608         rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2609  close_domain:
2610         rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2611  close_sam:
2612         rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2613
2614         return ret;
2615 }
2616
2617 /*******************************************************************
2618  Get all users.
2619 ******************************************************************/
2620
2621 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2622                              connection_struct *conn, uint16 vuid,
2623                                 char *param, int tpscnt,
2624                                 char *data, int tdscnt,
2625                                 int mdrcnt,int mprcnt,
2626                                 char **rdata,char **rparam,
2627                                 int *rdata_len,int *rparam_len)
2628 {
2629         int count_sent=0;
2630         int num_users=0;
2631         int errflags=0;
2632         int i, resume_context, cli_buf_size;
2633         uint32_t resume_handle;
2634
2635         struct rpc_pipe_client *samr_pipe;
2636         struct policy_handle samr_handle, domain_handle;
2637         NTSTATUS status;
2638
2639         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2640         char *str2 = skip_string(param,tpscnt,str1);
2641         char *p = skip_string(param,tpscnt,str2);
2642         char *endp = NULL;
2643
2644         if (!str1 || !str2 || !p) {
2645                 return False;
2646         }
2647
2648         if (strcmp(str1,"WrLeh") != 0)
2649                 return False;
2650         /* parameters
2651           * W-> resume context (number of users to skip)
2652           * r -> return parameter pointer to receive buffer
2653           * L -> length of receive buffer
2654           * e -> return parameter number of entries
2655           * h -> return parameter total number of users
2656           */
2657
2658         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2659         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2660         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2661                         resume_context, cli_buf_size));
2662
2663         *rparam_len = 8;
2664         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2665         if (!*rparam) {
2666                 return False;
2667         }
2668
2669         /* check it's a supported varient */
2670         if (strcmp("B21",str2) != 0)
2671                 return False;
2672
2673         *rdata_len = cli_buf_size;
2674         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2675         if (!*rdata) {
2676                 return False;
2677         }
2678
2679         p = *rdata;
2680         endp = *rdata + *rdata_len;
2681
2682         status = rpc_pipe_open_internal(
2683                 talloc_tos(), &ndr_table_samr.syntax_id,
2684                 conn->server_info, conn->sconn->msg_ctx, &samr_pipe);
2685         if (!NT_STATUS_IS_OK(status)) {
2686                 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2687                           nt_errstr(status)));
2688                 return false;
2689         }
2690
2691         status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2692                                       SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2693         if (!NT_STATUS_IS_OK(status)) {
2694                 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2695                           nt_errstr(status)));
2696                 return false;
2697         }
2698
2699         status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2700                                         SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2701                                         get_global_sam_sid(), &domain_handle);
2702         if (!NT_STATUS_IS_OK(status)) {
2703                 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2704                           nt_errstr(status)));
2705                 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2706                 return false;
2707         }
2708
2709         errflags=NERR_Success;
2710
2711         resume_handle = 0;
2712
2713         while (true) {
2714                 struct samr_SamArray *sam_entries;
2715                 uint32_t num_entries;
2716
2717                 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2718                                                      &domain_handle,
2719                                                      &resume_handle,
2720                                                      0, &sam_entries, 1,
2721                                                      &num_entries);
2722
2723                 if (!NT_STATUS_IS_OK(status)) {
2724                         DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2725                                    "%s\n", nt_errstr(status)));
2726                         break;
2727                 }
2728
2729                 if (num_entries == 0) {
2730                         DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2731                                    "no entries -- done\n"));
2732                         break;
2733                 }
2734
2735                 for (i=0; i<num_entries; i++) {
2736                         const char *name;
2737
2738                         name = sam_entries->entries[i].name.string;
2739
2740                         if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2741                            &&(strlen(name)<=21)) {
2742                                 strlcpy(p,name,PTR_DIFF(endp,p));
2743                                 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2744                                           "username %s\n",count_sent,p));
2745                                 p += 21;
2746                                 count_sent++;
2747                         } else {
2748                                 /* set overflow error */
2749                                 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2750                                           "username %s\n",count_sent,name));
2751                                 errflags=234;
2752                                 break;
2753                         }
2754                 }
2755
2756                 if (errflags != NERR_Success) {
2757                         break;
2758                 }
2759
2760                 TALLOC_FREE(sam_entries);
2761         }
2762
2763         rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2764         rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2765
2766         *rdata_len = PTR_DIFF(p,*rdata);
2767
2768         SSVAL(*rparam,0,errflags);
2769         SSVAL(*rparam,2,0);           /* converter word */
2770         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2771         SSVAL(*rparam,6,num_users); /* is this right?? */
2772
2773         return True;
2774 }
2775
2776 /****************************************************************************
2777  Get the time of day info.
2778 ****************************************************************************/
2779
2780 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2781                              connection_struct *conn,uint16 vuid,
2782                                 char *param, int tpscnt,
2783                                 char *data, int tdscnt,
2784                                 int mdrcnt,int mprcnt,
2785                                 char **rdata,char **rparam,
2786                                 int *rdata_len,int *rparam_len)
2787 {
2788         struct tm *t;
2789         time_t unixdate = time(NULL);
2790         char *p;
2791
2792         *rparam_len = 4;
2793         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2794         if (!*rparam) {
2795                 return False;
2796         }
2797
2798         *rdata_len = 21;
2799         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2800         if (!*rdata) {
2801                 return False;
2802         }
2803
2804         SSVAL(*rparam,0,NERR_Success);
2805         SSVAL(*rparam,2,0);             /* converter word */
2806
2807         p = *rdata;
2808
2809         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2810                                             by NT in a "net time" operation,
2811                                             it seems to ignore the one below */
2812
2813         /* the client expects to get localtime, not GMT, in this bit 
2814                 (I think, this needs testing) */
2815         t = localtime(&unixdate);
2816         if (!t) {
2817                 return False;
2818         }
2819
2820         SIVAL(p,4,0);           /* msecs ? */
2821         SCVAL(p,8,t->tm_hour);
2822         SCVAL(p,9,t->tm_min);
2823         SCVAL(p,10,t->tm_sec);
2824         SCVAL(p,11,0);          /* hundredths of seconds */
2825         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2826         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2827         SCVAL(p,16,t->tm_mday);
2828         SCVAL(p,17,t->tm_mon + 1);
2829         SSVAL(p,18,1900+t->tm_year);
2830         SCVAL(p,20,t->tm_wday);
2831
2832         return True;
2833 }
2834
2835 /****************************************************************************
2836  Set the user password.
2837 *****************************************************************************/
2838
2839 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2840                                 connection_struct *conn,uint16 vuid,
2841                                 char *param, int tpscnt,
2842                                 char *data, int tdscnt,
2843                                 int mdrcnt,int mprcnt,
2844                                 char **rdata,char **rparam,
2845                                 int *rdata_len,int *rparam_len)
2846 {
2847         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2848         char *p = NULL;
2849         fstring user;
2850         fstring pass1,pass2;
2851         TALLOC_CTX *mem_ctx = talloc_tos();
2852         NTSTATUS status;
2853         struct rpc_pipe_client *cli = NULL;
2854         struct policy_handle connect_handle, domain_handle, user_handle;
2855         struct lsa_String domain_name;
2856         struct dom_sid2 *domain_sid;
2857         struct lsa_String names;
2858         struct samr_Ids rids;
2859         struct samr_Ids types;
2860         struct samr_Password old_lm_hash;
2861         struct samr_Password new_lm_hash;
2862         int errcode = NERR_badpass;
2863         uint32_t rid;
2864         int encrypted;
2865         int min_pwd_length;
2866
2867         /* Skip 2 strings. */
2868         p = skip_string(param,tpscnt,np);
2869         p = skip_string(param,tpscnt,p);
2870
2871         if (!np || !p) {
2872                 return False;
2873         }
2874
2875         /* Do we have a string ? */
2876         if (skip_string(param,tpscnt,p) == NULL) {
2877                 return False;
2878         }
2879         pull_ascii_fstring(user,p);
2880
2881         p = skip_string(param,tpscnt,p);
2882         if (!p) {
2883                 return False;
2884         }
2885
2886         memset(pass1,'\0',sizeof(pass1));
2887         memset(pass2,'\0',sizeof(pass2));
2888         /*
2889          * We use 31 here not 32 as we're checking
2890          * the last byte we want to access is safe.
2891          */
2892         if (!is_offset_safe(param,tpscnt,p,31)) {
2893                 return False;
2894         }
2895         memcpy(pass1,p,16);
2896         memcpy(pass2,p+16,16);
2897
2898         encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2899         if (encrypted == -1) {
2900                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2901                 goto out;
2902         }
2903
2904         min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2905         if (min_pwd_length == -1) {
2906                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2907                 goto out;
2908         }
2909
2910         *rparam_len = 4;
2911         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2912         if (!*rparam) {
2913                 return False;
2914         }
2915
2916         *rdata_len = 0;
2917
2918         DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2919                 user, encrypted, min_pwd_length));
2920
2921         ZERO_STRUCT(connect_handle);
2922         ZERO_STRUCT(domain_handle);
2923         ZERO_STRUCT(user_handle);
2924
2925         status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2926                                         conn->server_info,
2927                                         conn->sconn->msg_ctx,
2928                                         &cli);
2929         if (!NT_STATUS_IS_OK(status)) {
2930                 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2931                           nt_errstr(status)));
2932                 errcode = W_ERROR_V(ntstatus_to_werror(status));
2933                 goto out;
2934         }
2935
2936         status = rpccli_samr_Connect2(cli, mem_ctx,
2937                                       global_myname(),
2938                                       SAMR_ACCESS_CONNECT_TO_SERVER |
2939                                       SAMR_ACCESS_ENUM_DOMAINS |
2940                                       SAMR_ACCESS_LOOKUP_DOMAIN,
2941                                       &connect_handle);
2942         if (!NT_STATUS_IS_OK(status)) {
2943                 errcode = W_ERROR_V(ntstatus_to_werror(status));
2944                 goto out;
2945         }
2946
2947         init_lsa_String(&domain_name, get_global_sam_name());
2948
2949         status = rpccli_samr_LookupDomain(cli, mem_ctx,
2950                                           &connect_handle,
2951                                           &domain_name,
2952                                           &domain_sid);
2953         if (!NT_STATUS_IS_OK(status)) {
2954                 errcode = W_ERROR_V(ntstatus_to_werror(status));
2955                 goto out;
2956         }
2957
2958         status = rpccli_samr_OpenDomain(cli, mem_ctx,
2959                                         &connect_handle,
2960                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2961                                         domain_sid,
2962                                         &domain_handle);
2963         if (!NT_STATUS_IS_OK(status)) {
2964                 errcode = W_ERROR_V(ntstatus_to_werror(status));
2965                 goto out;
2966         }
2967
2968         init_lsa_String(&names, user);
2969
2970         status = rpccli_samr_LookupNames(cli, mem_ctx,
2971                                          &domain_handle,
2972                                          1,
2973                                          &names,
2974                                          &rids,
2975                                          &types);
2976         if (!NT_STATUS_IS_OK(status)) {
2977                 errcode = W_ERROR_V(ntstatus_to_werror(status));
2978                 goto out;
2979         }
2980
2981         if (rids.count != 1) {
2982                 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
2983                 goto out;
2984         }
2985         if (rids.count != types.count) {
2986                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2987                 goto out;
2988         }
2989         if (types.ids[0] != SID_NAME_USER) {
2990                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2991                 goto out;
2992         }
2993
2994         rid = rids.ids[0];
2995
2996         status = rpccli_samr_OpenUser(cli, mem_ctx,
2997                                       &domain_handle,
2998                                       SAMR_USER_ACCESS_CHANGE_PASSWORD,
2999                                       rid,
3000                                       &user_handle);
3001         if (!NT_STATUS_IS_OK(status)) {
3002                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3003                 goto out;
3004         }
3005
3006         if (encrypted == 0) {
3007                 E_deshash(pass1, old_lm_hash.hash);
3008                 E_deshash(pass2, new_lm_hash.hash);
3009         } else {
3010                 ZERO_STRUCT(old_lm_hash);
3011                 ZERO_STRUCT(new_lm_hash);
3012                 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3013                 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3014         }
3015
3016         status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
3017                                                 &user_handle,
3018                                                 true, /* lm_present */
3019                                                 &old_lm_hash,
3020                                                 &new_lm_hash,
3021                                                 false, /* nt_present */
3022                                                 NULL, /* old_nt_crypted */
3023                                                 NULL, /* new_nt_crypted */
3024                                                 false, /* cross1_present */
3025                                                 NULL, /* nt_cross */
3026                                                 false, /* cross2_present */
3027                                                 NULL); /* lm_cross */
3028         if (!NT_STATUS_IS_OK(status)) {
3029                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3030                 goto out;
3031         }
3032
3033         errcode = NERR_Success;
3034  out:
3035
3036         if (cli && is_valid_policy_hnd(&user_handle)) {
3037                 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3038         }
3039         if (cli && is_valid_policy_hnd(&domain_handle)) {
3040                 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3041         }
3042         if (cli && is_valid_policy_hnd(&connect_handle)) {
3043                 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3044         }
3045
3046         memset((char *)pass1,'\0',sizeof(fstring));
3047         memset((char *)pass2,'\0',sizeof(fstring));      
3048
3049         SSVAL(*rparam,0,errcode);
3050         SSVAL(*rparam,2,0);             /* converter word */
3051         return(True);
3052 }
3053
3054 /****************************************************************************
3055   Set the user password (SamOEM version - gets plaintext).
3056 ****************************************************************************/
3057
3058 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3059                                      connection_struct *conn,uint16 vuid,
3060                                 char *param, int tpscnt,
3061                                 char *data, int tdscnt,
3062                                 int mdrcnt,int mprcnt,
3063                                 char **rdata,char **rparam,
3064                                 int *rdata_len,int *rparam_len)
3065 {
3066         fstring user;
3067         char *p = get_safe_str_ptr(param,tpscnt,param,2);
3068
3069         TALLOC_CTX *mem_ctx = talloc_tos();
3070         NTSTATUS status;
3071         struct rpc_pipe_client *cli = NULL;
3072         struct lsa_AsciiString server, account;
3073         struct samr_CryptPassword password;
3074         struct samr_Password hash;
3075         int errcode = NERR_badpass;
3076         int bufsize;
3077
3078         *rparam_len = 4;
3079         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3080         if (!*rparam) {
3081                 return False;
3082         }
3083
3084         if (!p) {
3085                 return False;
3086         }
3087         *rdata_len = 0;
3088
3089         SSVAL(*rparam,0,NERR_badpass);
3090
3091         /*
3092          * Check the parameter definition is correct.
3093          */
3094
3095         /* Do we have a string ? */
3096         if (skip_string(param,tpscnt,p) == 0) {
3097                 return False;
3098         }
3099         if(!strequal(p, "zsT")) {
3100                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3101                 return False;
3102         }
3103         p = skip_string(param, tpscnt, p);
3104         if (!p) {
3105                 return False;
3106         }
3107
3108         /* Do we have a string ? */
3109         if (skip_string(param,tpscnt,p) == 0) {
3110                 return False;
3111         }
3112         if(!strequal(p, "B516B16")) {
3113                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3114                 return False;
3115         }
3116         p = skip_string(param,tpscnt,p);
3117         if (!p) {
3118                 return False;
3119         }
3120         /* Do we have a string ? */
3121         if (skip_string(param,tpscnt,p) == 0) {
3122                 return False;
3123         }
3124         p += pull_ascii_fstring(user,p);
3125
3126         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3127
3128         if (tdscnt != 532) {
3129                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3130                 goto out;
3131         }
3132
3133         bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3134         if (bufsize != 532) {
3135                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3136                 goto out;
3137         }
3138
3139         memcpy(password.data, data, 516);
3140         memcpy(hash.hash, data+516, 16);
3141
3142         status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3143                                         conn->server_info,
3144                                         conn->sconn->msg_ctx,
3145                                         &cli);
3146         if (!NT_STATUS_IS_OK(status)) {
3147                 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3148                           nt_errstr(status)));
3149                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3150                 goto out;
3151         }
3152
3153         init_lsa_AsciiString(&server, global_myname());
3154         init_lsa_AsciiString(&account, user);
3155
3156         status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3157                                                     &server,
3158                                                     &account,
3159                                                     &password,
3160                                                     &hash);
3161         if (!NT_STATUS_IS_OK(status)) {
3162                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3163                 goto out;
3164         }
3165
3166         errcode = NERR_Success;
3167  out:
3168         SSVAL(*rparam,0,errcode);
3169         SSVAL(*rparam,2,0);             /* converter word */
3170
3171         return(True);
3172 }
3173
3174 /****************************************************************************
3175   delete a print job
3176   Form: <W> <> 
3177   ****************************************************************************/
3178
3179 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3180                                 connection_struct *conn,uint16 vuid,
3181                                 char *param, int tpscnt,
3182                                 char *data, int tdscnt,
3183                                 int mdrcnt,int mprcnt,
3184                                 char **rdata,char **rparam,
3185                                 int *rdata_len,int *rparam_len)
3186 {
3187         int function = get_safe_SVAL(param,tpscnt,param,0,0);
3188         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3189         char *str2 = skip_string(param,tpscnt,str1);
3190         char *p = skip_string(param,tpscnt,str2);
3191         uint32 jobid;
3192         fstring sharename;
3193         int errcode;
3194         WERROR werr = WERR_OK;
3195
3196         TALLOC_CTX *mem_ctx = talloc_tos();
3197         NTSTATUS status;
3198         struct rpc_pipe_client *cli = NULL;
3199         struct policy_handle handle;
3200         struct spoolss_DevmodeContainer devmode_ctr;
3201         enum spoolss_JobControl command;
3202
3203         if (!str1 || !str2 || !p) {
3204                 return False;
3205         }
3206         /*
3207          * We use 1 here not 2 as we're checking
3208          * the last byte we want to access is safe.
3209          */
3210         if (!is_offset_safe(param,tpscnt,p,1)) {
3211                 return False;
3212         }
3213         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3214                 return False;
3215
3216         /* check it's a supported varient */
3217         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3218                 return(False);
3219
3220         *rparam_len = 4;
3221         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3222         if (!*rparam) {
3223                 return False;
3224         }
3225         *rdata_len = 0;
3226
3227         ZERO_STRUCT(handle);
3228
3229         status = rpc_connect_spoolss_pipe(conn, &cli);
3230         if (!NT_STATUS_IS_OK(status)) {
3231                 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3232                           nt_errstr(status)));
3233                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3234                 goto out;
3235         }
3236
3237         ZERO_STRUCT(devmode_ctr);
3238
3239         status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3240                                             sharename,
3241                                             "RAW",
3242                                             devmode_ctr,
3243                                             JOB_ACCESS_ADMINISTER,
3244                                             &handle,
3245                                             &werr);
3246         if (!NT_STATUS_IS_OK(status)) {
3247                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3248                 goto out;
3249         }
3250         if (!W_ERROR_IS_OK(werr)) {
3251                 errcode = W_ERROR_V(werr);
3252                 goto out;
3253         }
3254
3255         /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3256          * and NERR_DestNotFound if share did not exist */
3257
3258         errcode = NERR_Success;
3259
3260         switch (function) {
3261         case 81:                /* delete */
3262                 command = SPOOLSS_JOB_CONTROL_DELETE;
3263                 break;
3264         case 82:                /* pause */
3265                 command = SPOOLSS_JOB_CONTROL_PAUSE;
3266                 break;
3267         case 83:                /* resume */
3268                 command = SPOOLSS_JOB_CONTROL_RESUME;
3269                 break;
3270         default:
3271                 errcode = NERR_notsupported;
3272                 goto out;
3273         }
3274
3275         status = rpccli_spoolss_SetJob(cli, mem_ctx,
3276                                        &handle,
3277                                        jobid,
3278                                        NULL, /* unique ptr ctr */
3279                                        command,
3280                                        &werr);
3281         if (!NT_STATUS_IS_OK(status)) {
3282                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3283                 goto out;
3284         }
3285         if (!W_ERROR_IS_OK(werr)) {
3286                 errcode = W_ERROR_V(werr);
3287                 goto out;
3288         }
3289
3290  out:
3291         if (cli && is_valid_policy_hnd(&handle)) {
3292                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3293         }
3294
3295         SSVAL(*rparam,0,errcode);       
3296         SSVAL(*rparam,2,0);             /* converter word */
3297
3298         return(True);
3299 }
3300
3301 /****************************************************************************
3302   Purge a print queue - or pause or resume it.
3303   ****************************************************************************/
3304
3305 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3306                                 connection_struct *conn,uint16 vuid,
3307                                 char *param, int tpscnt,
3308                                 char *data, int tdscnt,
3309                                 int mdrcnt,int mprcnt,
3310                                 char **rdata,char **rparam,
3311                                 int *rdata_len,int *rparam_len)
3312 {
3313         int function = get_safe_SVAL(param,tpscnt,param,0,0);
3314         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3315         char *str2 = skip_string(param,tpscnt,str1);
3316         char *QueueName = skip_string(param,tpscnt,str2);
3317         int errcode = NERR_notsupported;
3318         WERROR werr = WERR_OK;
3319         NTSTATUS status;
3320
3321         TALLOC_CTX *mem_ctx = talloc_tos();
3322         struct rpc_pipe_client *cli = NULL;
3323         struct policy_handle handle;
3324         struct spoolss_SetPrinterInfoCtr info_ctr;
3325         struct spoolss_DevmodeContainer devmode_ctr;
3326         struct sec_desc_buf secdesc_ctr;
3327         enum spoolss_PrinterControl command;
3328
3329         if (!str1 || !str2 || !QueueName) {
3330                 return False;
3331         }
3332
3333         /* check it's a supported varient */
3334         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3335                 return(False);
3336
3337         *rparam_len = 4;
3338         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3339         if (!*rparam) {
3340                 return False;
3341         }
3342         *rdata_len = 0;
3343
3344         if (skip_string(param,tpscnt,QueueName) == NULL) {
3345                 return False;
3346         }
3347
3348         ZERO_STRUCT(handle);
3349
3350         status = rpc_connect_spoolss_pipe(conn, &cli);
3351         if (!NT_STATUS_IS_OK(status)) {
3352                 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3353                           nt_errstr(status)));
3354                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3355                 goto out;
3356         }
3357
3358         ZERO_STRUCT(devmode_ctr);
3359
3360         status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3361                                             QueueName,
3362                                             NULL,
3363                                             devmode_ctr,
3364                                             SEC_FLAG_MAXIMUM_ALLOWED,
3365                                             &handle,
3366                                             &werr);
3367         if (!NT_STATUS_IS_OK(status)) {
3368                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3369                 goto out;
3370         }
3371         if (!W_ERROR_IS_OK(werr)) {
3372                 errcode = W_ERROR_V(werr);
3373                 goto out;
3374         }
3375
3376         switch (function) {
3377         case 74: /* Pause queue */
3378                 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3379                 break;
3380         case 75: /* Resume queue */
3381                 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3382                 break;
3383         case 103: /* Purge */
3384                 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3385                 break;
3386         default:
3387                 werr = WERR_NOT_SUPPORTED;
3388                 break;
3389         }
3390
3391         if (!W_ERROR_IS_OK(werr)) {
3392                 errcode = W_ERROR_V(werr);
3393                 goto out;
3394         }
3395
3396         ZERO_STRUCT(info_ctr);
3397         ZERO_STRUCT(secdesc_ctr);
3398
3399         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3400                                            &handle,
3401                                            &info_ctr,
3402                                            &devmode_ctr,
3403                                            &secdesc_ctr,
3404                                            command,
3405                                            &werr);
3406         if (!NT_STATUS_IS_OK(status)) {
3407                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3408                 goto out;
3409         }
3410         if (!W_ERROR_IS_OK(werr)) {
3411                 errcode = W_ERROR_V(werr);
3412                 goto out;
3413         }
3414
3415         errcode = W_ERROR_V(werr);
3416
3417  out:
3418
3419         if (cli && is_valid_policy_hnd(&handle)) {
3420                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3421         }
3422
3423         SSVAL(*rparam,0,errcode);
3424         SSVAL(*rparam,2,0);             /* converter word */
3425
3426         return(True);
3427 }
3428
3429 /****************************************************************************
3430   set the property of a print job (undocumented?)
3431   ? function = 0xb -> set name of print job
3432   ? function = 0x6 -> move print job up/down
3433   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
3434   or   <WWsTP> <WB21BB16B10zWWzDDz> 
3435 ****************************************************************************/
3436
3437 static int check_printjob_info(struct pack_desc* desc,
3438                                int uLevel, char* id)
3439 {
3440         desc->subformat = NULL;
3441         switch( uLevel ) {
3442         case 0: desc->format = "W"; break;
3443         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3444         case 2: desc->format = "WWzWWDDzz"; break;
3445         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3446         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3447         default:
3448                 DEBUG(0,("check_printjob_info: invalid level %d\n",
3449                         uLevel ));
3450                 return False;
3451         }
3452         if (id == NULL || strcmp(desc->format,id) != 0) {
3453                 DEBUG(0,("check_printjob_info: invalid format %s\n",
3454                         id ? id : "<NULL>" ));
3455                 return False;
3456         }
3457         return True;
3458 }
3459
3460 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3461                              connection_struct *conn, uint16 vuid,
3462                                 char *param, int tpscnt,
3463                                 char *data, int tdscnt,
3464                                 int mdrcnt,int mprcnt,
3465                                 char **rdata,char **rparam,
3466                                 int *rdata_len,int *rparam_len)
3467 {
3468         struct pack_desc desc;
3469         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3470         char *str2 = skip_string(param,tpscnt,str1);
3471         char *p = skip_string(param,tpscnt,str2);
3472         uint32 jobid;
3473         fstring sharename;
3474         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3475         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3476         int errcode;
3477
3478         TALLOC_CTX *mem_ctx = talloc_tos();
3479         WERROR werr;
3480         NTSTATUS status;
3481         struct rpc_pipe_client *cli = NULL;
3482         struct policy_handle handle;
3483         struct spoolss_DevmodeContainer devmode_ctr;
3484         struct spoolss_JobInfoContainer ctr;
3485         union spoolss_JobInfo info;
3486         struct spoolss_SetJobInfo1 info1;
3487
3488         if (!str1 || !str2 || !p) {
3489                 return False;
3490         }
3491         /*
3492          * We use 1 here not 2 as we're checking
3493          * the last byte we want to access is safe.
3494          */
3495         if (!is_offset_safe(param,tpscnt,p,1)) {
3496                 return False;
3497         }
3498         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3499                 return False;
3500         *rparam_len = 4;
3501         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3502         if (!*rparam) {
3503                 return False;
3504         }
3505
3506         *rdata_len = 0;
3507
3508         /* check it's a supported varient */
3509         if ((strcmp(str1,"WWsTP")) ||
3510             (!check_printjob_info(&desc,uLevel,str2)))
3511                 return(False);
3512
3513         errcode = NERR_notsupported;
3514
3515         switch (function) {
3516         case 0xb:
3517                 /* change print job name, data gives the name */
3518                 break;
3519         default:
3520                 goto out;
3521         }
3522
3523         ZERO_STRUCT(handle);
3524
3525         status = rpc_connect_spoolss_pipe(conn, &cli);
3526         if (!NT_STATUS_IS_OK(status)) {
3527                 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3528                           nt_errstr(status)));
3529                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3530                 goto out;
3531         }
3532
3533         ZERO_STRUCT(devmode_ctr);
3534
3535         status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3536                                             sharename,
3537                                             "RAW",
3538                                             devmode_ctr,
3539                                             PRINTER_ACCESS_USE,
3540                                             &handle,
3541                                             &werr);
3542         if (!NT_STATUS_IS_OK(status)) {
3543                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3544                 goto out;
3545         }
3546         if (!W_ERROR_IS_OK(werr)) {
3547                 errcode = W_ERROR_V(werr);
3548                 goto out;
3549         }
3550
3551         werr = rpccli_spoolss_getjob(cli, mem_ctx,
3552                                      &handle,
3553                                      jobid,
3554                                      1, /* level */
3555                                      0, /* offered */
3556                                      &info);
3557         if (!W_ERROR_IS_OK(werr)) {
3558                 errcode = W_ERROR_V(werr);
3559                 goto out;
3560         }
3561
3562         ZERO_STRUCT(ctr);
3563
3564         info1.job_id            = info.info1.job_id;
3565         info1.printer_name      = info.info1.printer_name;
3566         info1.user_name         = info.info1.user_name;
3567         info1.document_name     = data;
3568         info1.data_type         = info.info1.data_type;
3569         info1.text_status       = info.info1.text_status;
3570         info1.status            = info.info1.status;
3571         info1.priority          = info.info1.priority;
3572         info1.position          = info.info1.position;
3573         info1.total_pages       = info.info1.total_pages;
3574         info1.pages_printed     = info.info1.pages_printed;
3575         info1.submitted         = info.info1.submitted;
3576
3577         ctr.level = 1;
3578         ctr.info.info1 = &info1;
3579
3580         status = rpccli_spoolss_SetJob(cli, mem_ctx,
3581                                        &handle,
3582                                        jobid,
3583                                        &ctr,
3584                                        0,
3585                                        &werr);
3586         if (!NT_STATUS_IS_OK(status)) {
3587                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3588                 goto out;
3589         }
3590         if (!W_ERROR_IS_OK(werr)) {
3591                 errcode = W_ERROR_V(werr);
3592                 goto out;
3593         }
3594
3595         errcode = NERR_Success;
3596  out:
3597
3598         if (cli && is_valid_policy_hnd(&handle)) {
3599                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3600         }
3601
3602         SSVALS(*rparam,0,errcode);
3603         SSVAL(*rparam,2,0);             /* converter word */
3604
3605         return(True);
3606 }
3607
3608
3609 /****************************************************************************
3610  Get info about the server.
3611 ****************************************************************************/
3612
3613 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3614                                   connection_struct *conn,uint16 vuid,
3615                                 char *param, int tpscnt,
3616                                 char *data, int tdscnt,
3617                                 int mdrcnt,int mprcnt,
3618                                 char **rdata,char **rparam,
3619                                 int *rdata_len,int *rparam_len)
3620 {
3621         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3622         char *str2 = skip_string(param,tpscnt,str1);
3623         char *p = skip_string(param,tpscnt,str2);
3624         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3625         char *p2;
3626         int struct_len;
3627
3628         NTSTATUS status;
3629         WERROR werr;
3630         TALLOC_CTX *mem_ctx = talloc_tos();
3631         struct rpc_pipe_client *cli = NULL;
3632         union srvsvc_NetSrvInfo info;
3633         int errcode;
3634
3635         if (!str1 || !str2 || !p) {
3636                 return False;
3637         }
3638
3639         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3640
3641         /* check it's a supported varient */
3642         if (!prefix_ok(str1,"WrLh")) {
3643                 return False;
3644         }
3645
3646         switch( uLevel ) {
3647                 case 0:
3648                         if (strcmp(str2,"B16") != 0) {
3649                                 return False;
3650                         }
3651                         struct_len = 16;
3652                         break;
3653                 case 1:
3654                         if (strcmp(str2,"B16BBDz") != 0) {
3655                                 return False;
3656                         }
3657                         struct_len = 26;
3658                         break;
3659                 case 2:
3660                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3661                                 return False;
3662                         }
3663                         struct_len = 134;
3664                         break;
3665                 case 3:
3666                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3667                                 return False;
3668                         }
3669                         struct_len = 144;
3670                         break;
3671                 case 20:
3672                         if (strcmp(str2,"DN") != 0) {
3673                                 return False;
3674                         }
3675                         struct_len = 6;
3676                         break;
3677                 case 50:
3678                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3679                                 return False;
3680                         }
3681                         struct_len = 42;
3682                         break;
3683                 default:
3684                         return False;
3685         }
3686
3687         *rdata_len = mdrcnt;
3688         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3689         if (!*rdata) {
3690                 return False;
3691         }
3692
3693         p = *rdata;
3694         p2 = p + struct_len;
3695
3696         status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3697                                         conn->server_info,
3698                                         conn->sconn->msg_ctx,
3699                                         &cli);
3700         if (!NT_STATUS_IS_OK(status)) {
3701                 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3702                           nt_errstr(status)));
3703                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3704                 goto out;
3705         }
3706
3707         status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3708                                              NULL,
3709                                              101,
3710                                              &info,
3711                                              &werr);
3712         if (!NT_STATUS_IS_OK(status)) {
3713                 errcode = W_ERROR_V(ntstatus_to_werror(status));
3714                 goto out;
3715         }
3716         if (!W_ERROR_IS_OK(werr)) {
3717                 errcode = W_ERROR_V(werr);
3718                 goto out;
3719         }
3720
3721         if (info.info101 == NULL) {
3722                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3723                 goto out;
3724         }
3725
3726         if (uLevel != 20) {
3727                 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3728                         STR_ASCII|STR_UPPER|STR_TERMINATE);
3729         }
3730         p += 16;
3731         if (uLevel > 0) {
3732                 SCVAL(p,0,info.info101->version_major);
3733                 SCVAL(p,1,info.info101->version_minor);
3734                 SIVAL(p,2,info.info101->server_type);
3735
3736                 if (mdrcnt == struct_len) {
3737                         SIVAL(p,6,0);
3738                 } else {
3739                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
3740                         if (mdrcnt - struct_len <= 0) {
3741                                 return false;
3742                         }
3743                         push_ascii(p2,
3744                                 info.info101->comment,
3745                                 MIN(mdrcnt - struct_len,
3746                                         MAX_SERVER_STRING_LENGTH),
3747                                 STR_TERMINATE);
3748                         p2 = skip_string(*rdata,*rdata_len,p2);
3749                         if (!p2) {
3750                                 return False;
3751                         }
3752                 }
3753         }
3754
3755         if (uLevel > 1) {
3756                 return False;           /* not yet implemented */
3757         }
3758
3759         errcode = NERR_Success;
3760
3761  out:
3762
3763         *rdata_len = PTR_DIFF(p2,*rdata);
3764
3765         *rparam_len = 6;
3766         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3767         if (!*rparam) {
3768                 return False;
3769         }
3770         SSVAL(*rparam,0,errcode);
3771         SSVAL(*rparam,2,0);             /* converter word */
3772         SSVAL(*rparam,4,*rdata_len);
3773
3774         return True;
3775 }
3776
3777 /****************************************************************************
3778  Get info about the server.
3779 ****************************************************************************/
3780
3781 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3782                                 connection_struct *conn,uint16 vuid,
3783                                 char *param, int tpscnt,
3784                                 char *data, int tdscnt,
3785                                 int mdrcnt,int mprcnt,
3786                                 char **rdata,char **rparam,
3787                                 int *rdata_len,int *rparam_len)
3788 {
3789         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3790         char *str2 = skip_string(param,tpscnt,str1);
3791         char *p = skip_string(param,tpscnt,str2);
3792         char *p2;
3793         char *endp;
3794         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3795
3796         if (!str1 || !str2 || !p) {
3797                 return False;
3798         }
3799
3800         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3801
3802         *rparam_len = 6;
3803         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3804         if (!*rparam) {
3805                 return False;
3806         }
3807
3808         /* check it's a supported varient */
3809         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3810                 return False;
3811         }
3812
3813         *rdata_len = mdrcnt + 1024;
3814         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3815         if (!*rdata) {
3816                 return False;
3817         }
3818
3819         SSVAL(*rparam,0,NERR_Success);
3820         SSVAL(*rparam,2,0);             /* converter word */
3821
3822         p = *rdata;
3823         endp = *rdata + *rdata_len;
3824
3825         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3826         if (!p2) {
3827                 return False;
3828         }
3829
3830         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3831         strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3832         strupper_m(p2);
3833         p2 = skip_string(*rdata,*rdata_len,p2);
3834         if (!p2) {
3835                 return False;
3836         }
3837         p += 4;
3838
3839         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3840         strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3841         p2 = skip_string(*rdata,*rdata_len,p2);
3842         if (!p2) {
3843                 return False;
3844         }
3845         p += 4;
3846
3847         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3848         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3849         strupper_m(p2);
3850         p2 = skip_string(*rdata,*rdata_len,p2);
3851         if (!p2) {
3852                 return False;
3853         }
3854         p += 4;
3855
3856         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3857         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3858         p += 2;
3859
3860         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3861         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));   /* don't know.  login domain?? */
3862         p2 = skip_string(*rdata,*rdata_len,p2);
3863         if (!p2) {
3864                 return False;
3865         }
3866         p += 4;
3867
3868         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3869         strlcpy(p2,"",PTR_DIFF(endp,p2));
3870         p2 = skip_string(*rdata,*rdata_len,p2);
3871         if (!p2) {
3872                 return False;
3873         }
3874         p += 4;
3875
3876         *rdata_len = PTR_DIFF(p2,*rdata);
3877
3878         SSVAL(*rparam,4,*rdata_len);
3879
3880         return True;
3881 }
3882
3883 /****************************************************************************
3884   get info about a user
3885
3886     struct user_info_11 {
3887         char                usri11_name[21];  0-20 
3888         char                usri11_pad;       21 
3889         char                *usri11_comment;  22-25 
3890         char            *usri11_usr_comment;  26-29
3891         unsigned short      usri11_priv;      30-31
3892         unsigned long       usri11_auth_flags; 32-35
3893         long                usri11_password_age; 36-39
3894         char                *usri11_homedir; 40-43
3895         char            *usri11_parms; 44-47
3896         long                usri11_last_logon; 48-51
3897         long                usri11_last_logoff; 52-55
3898         unsigned short      usri11_bad_pw_count; 56-57
3899         unsigned short      usri11_num_logons; 58-59
3900         char                *usri11_logon_server; 60-63
3901         unsigned short      usri11_country_code; 64-65
3902         char            *usri11_workstations; 66-69
3903         unsigned long       usri11_max_storage; 70-73
3904         unsigned short      usri11_units_per_week; 74-75
3905         unsigned char       *usri11_logon_hours; 76-79
3906         unsigned short      usri11_code_page; 80-81
3907     };
3908
3909 where:
3910
3911   usri11_name specifies the user name for which information is retrieved
3912
3913   usri11_pad aligns the next data structure element to a word boundary
3914
3915   usri11_comment is a null terminated ASCII comment
3916
3917   usri11_user_comment is a null terminated ASCII comment about the user
3918
3919   usri11_priv specifies the level of the privilege assigned to the user.
3920        The possible values are:
3921
3922 Name             Value  Description
3923 USER_PRIV_GUEST  0      Guest privilege
3924 USER_PRIV_USER   1      User privilege
3925 USER_PRV_ADMIN   2      Administrator privilege
3926
3927   usri11_auth_flags specifies the account operator privileges. The
3928        possible values are:
3929
3930 Name            Value   Description
3931 AF_OP_PRINT     0       Print operator
3932
3933
3934 Leach, Naik                                        [Page 28]
3935 \f
3936
3937
3938 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3939
3940
3941 AF_OP_COMM      1       Communications operator
3942 AF_OP_SERVER    2       Server operator
3943 AF_OP_ACCOUNTS  3       Accounts operator
3944
3945
3946   usri11_password_age specifies how many seconds have elapsed since the
3947        password was last changed.
3948
3949   usri11_home_dir points to a null terminated ASCII string that contains
3950        the path name of the user's home directory.
3951
3952   usri11_parms points to a null terminated ASCII string that is set
3953        aside for use by applications.
3954
3955   usri11_last_logon specifies the time when the user last logged on.
3956        This value is stored as the number of seconds elapsed since
3957        00:00:00, January 1, 1970.
3958
3959   usri11_last_logoff specifies the time when the user last logged off.
3960        This value is stored as the number of seconds elapsed since
3961        00:00:00, January 1, 1970. A value of 0 means the last logoff
3962        time is unknown.
3963
3964   usri11_bad_pw_count specifies the number of incorrect passwords
3965        entered since the last successful logon.
3966
3967   usri11_log1_num_logons specifies the number of times this user has
3968        logged on. A value of -1 means the number of logons is unknown.
3969
3970   usri11_logon_server points to a null terminated ASCII string that
3971        contains the name of the server to which logon requests are sent.
3972        A null string indicates logon requests should be sent to the
3973        domain controller.
3974
3975   usri11_country_code specifies the country code for the user's language
3976        of choice.
3977
3978   usri11_workstations points to a null terminated ASCII string that
3979        contains the names of workstations the user may log on from.
3980        There may be up to 8 workstations, with the names separated by
3981        commas. A null strings indicates there are no restrictions.
3982
3983   usri11_max_storage specifies the maximum amount of disk space the user
3984        can occupy. A value of 0xffffffff indicates there are no
3985        restrictions.
3986
3987   usri11_units_per_week specifies the equal number of time units into
3988        which a week is divided. This value must be equal to 168.
3989
3990   usri11_logon_hours points to a 21 byte (168 bits) string that
3991        specifies the time during which the user can log on. Each bit
3992        represents one unique hour in a week. The first bit (bit 0, word
3993        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3994
3995
3996
3997 Leach, Naik                                        [Page 29]
3998 \f
3999
4000
4001 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
4002
4003
4004        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4005        are no restrictions.
4006
4007   usri11_code_page specifies the code page for the user's language of
4008        choice
4009
4010 All of the pointers in this data structure need to be treated
4011 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
4012 to be ignored. The converter word returned in the parameters section
4013 needs to be subtracted from the lower 16 bits to calculate an offset
4014 into the return buffer where this ASCII string resides.
4015
4016 There is no auxiliary data in the response.
4017
4018   ****************************************************************************/
4019
4020 #define usri11_name           0 
4021 #define usri11_pad            21
4022 #define usri11_comment        22
4023 #define usri11_usr_comment    26
4024 #define usri11_full_name      30
4025 #define usri11_priv           34
4026 #define usri11_auth_flags     36
4027 #define usri11_password_age   40
4028 #define usri11_homedir        44
4029 #define usri11_parms          48
4030 #define usri11_last_logon     52
4031 #define usri11_last_logoff    56
4032 #define usri11_bad_pw_count   60
4033 #define usri11_num_logons     62
4034 #define usri11_logon_server   64
4035 #define usri11_country_code   68
4036 #define usri11_workstations   70
4037 #define usri11_max_storage    74
4038 #define usri11_units_per_week 78
4039 #define usri11_logon_hours    80
4040 #define usri11_code_page      84
4041 #define usri11_end            86
4042
4043 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4044                                 connection_struct *conn, uint16 vuid,
4045                                 char *param, int tpscnt,
4046                                 char *data, int tdscnt,
4047                                 int mdrcnt,int mprcnt,
4048                                 char **rdata,char **rparam,
4049                                 int *rdata_len,int *rparam_len)
4050 {
4051         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4052         char *str2 = skip_string(param,tpscnt,str1);
4053         char *UserName = skip_string(param,tpscnt,str2);
4054         char *p = skip_string(param,tpscnt,UserName);
4055         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4056         char *p2;
4057         char *endp;
4058         const char *level_string;
4059
4060         TALLOC_CTX *mem_ctx = talloc_tos();
4061         NTSTATUS status;
4062         struct rpc_pipe_client *cli = NULL;
4063         struct policy_handle connect_handle, domain_handle, user_handle;
4064         struct lsa_String domain_name;
4065         struct dom_sid2 *domain_sid;
4066         struct lsa_String names;
4067         struct samr_Ids rids;
4068         struct samr_Ids types;
4069         int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4070         uint32_t rid;
4071         union samr_UserInfo *info;
4072
4073         if (!str1 || !str2 || !UserName || !p) {
4074                 return False;
4075         }
4076
4077         *rparam_len = 6;
4078         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4079         if (!*rparam) {
4080                 return False;
4081         }
4082
4083         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4084
4085         /* check it's a supported variant */
4086         if (strcmp(str1,"zWrLh") != 0) {
4087                 return False;
4088         }
4089         switch( uLevel ) {
4090                 case 0: level_string = "B21"; break;
4091                 case 1: level_string = "B21BB16DWzzWz"; break;
4092                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4093                 case 10: level_string = "B21Bzzz"; break;
4094                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4095                 default: return False;
4096         }
4097
4098         if (strcmp(level_string,str2) != 0) {
4099                 return False;
4100         }
4101
4102         *rdata_len = mdrcnt + 1024;
4103         *rdata = smb_realloc_limit(*rdata,*rdata_len);
4104         if (!*rdata) {
4105                 return False;
4106         }
4107
4108         p = *rdata;
4109         endp = *rdata + *rdata_len;
4110         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4111         if (!p2) {
4112                 return False;
4113         }
4114
4115         ZERO_STRUCT(connect_handle);
4116         ZERO_STRUCT(domain_handle);
4117         ZERO_STRUCT(user_handle);
4118
4119         status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4120                                         conn->server_info,
4121                                         conn->sconn->msg_ctx,
4122                                         &cli);
4123         if (!NT_STATUS_IS_OK(status)) {
4124                 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4125                           nt_errstr(status)));
4126                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4127                 goto out;
4128         }
4129
4130         status = rpccli_samr_Connect2(cli, mem_ctx,
4131                                       global_myname(),
4132                                       SAMR_ACCESS_CONNECT_TO_SERVER |
4133                                       SAMR_ACCESS_ENUM_DOMAINS |
4134                                       SAMR_ACCESS_LOOKUP_DOMAIN,
4135                                       &connect_handle);
4136         if (!NT_STATUS_IS_OK(status)) {
4137                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4138                 goto out;
4139         }
4140
4141         init_lsa_String(&domain_name, get_global_sam_name());
4142
4143         status = rpccli_samr_LookupDomain(cli, mem_ctx,
4144                                           &connect_handle,
4145                                           &domain_name,
4146                                           &domain_sid);
4147         if (!NT_STATUS_IS_OK(status)) {
4148                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4149                 goto out;
4150         }
4151
4152         status = rpccli_samr_OpenDomain(cli, mem_ctx,
4153                                         &connect_handle,
4154                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4155                                         domain_sid,
4156                                         &domain_handle);
4157         if (!NT_STATUS_IS_OK(status)) {
4158                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4159                 goto out;
4160         }
4161
4162         init_lsa_String(&names, UserName);
4163
4164         status = rpccli_samr_LookupNames(cli, mem_ctx,
4165                                          &domain_handle,
4166                                          1,
4167                                          &names,
4168                                          &rids,
4169                                          &types);
4170         if (!NT_STATUS_IS_OK(status)) {
4171                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4172                 goto out;
4173         }
4174
4175         if (rids.count != 1) {
4176                 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4177                 goto out;
4178         }
4179         if (rids.count != types.count) {
4180                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4181                 goto out;
4182         }
4183         if (types.ids[0] != SID_NAME_USER) {
4184                 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4185                 goto out;
4186         }
4187
4188         rid = rids.ids[0];
4189
4190         status = rpccli_samr_OpenUser(cli, mem_ctx,
4191                                       &domain_handle,
4192                                       SAMR_USER_ACCESS_GET_LOCALE |
4193                                       SAMR_USER_ACCESS_GET_LOGONINFO |
4194                                       SAMR_USER_ACCESS_GET_ATTRIBUTES |
4195                                       SAMR_USER_ACCESS_GET_GROUPS |
4196                                       SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4197                                       SEC_STD_READ_CONTROL,
4198                                       rid,
4199                                       &user_handle);
4200         if (!NT_STATUS_IS_OK(status)) {
4201                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4202                 goto out;
4203         }
4204
4205         status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4206                                             &user_handle,
4207                                             UserAllInformation,
4208                                             &info);
4209         if (!NT_STATUS_IS_OK(status)) {
4210                 errcode = W_ERROR_V(ntstatus_to_werror(status));
4211                 goto out;
4212         }
4213
4214         memset(p,0,21);
4215         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4216
4217         if (uLevel > 0) {
4218                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4219                 *p2 = 0;
4220         }
4221
4222         if (uLevel >= 10) {
4223                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4224                 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4225                 p2 = skip_string(*rdata,*rdata_len,p2);
4226                 if (!p2) {
4227                         return False;
4228                 }
4229
4230                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4231                 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4232                 p2 = skip_string(*rdata,*rdata_len,p2);
4233                 if (!p2) {
4234                         return False;
4235                 }
4236
4237                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4238                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4239                 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4240                 p2 = skip_string(*rdata,*rdata_len,p2);
4241                 if (!p2) {
4242                         return False;
4243                 }
4244         }
4245
4246         if (uLevel == 11) {
4247                 const char *homedir = info->info21.home_directory.string;
4248                 /* modelled after NTAS 3.51 reply */
4249                 SSVAL(p,usri11_priv,
4250                         (get_current_uid(conn) == sec_initial_uid())?
4251                         USER_PRIV_ADMIN:USER_PRIV_USER);
4252                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
4253                 SIVALS(p,usri11_password_age,-1);               /* password age */
4254                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4255                 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4256                 p2 = skip_string(*rdata,*rdata_len,p2);
4257                 if (!p2) {
4258                         return False;
4259                 }
4260                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4261                 strlcpy(p2,"",PTR_DIFF(endp,p2));
4262                 p2 = skip_string(*rdata,*rdata_len,p2);
4263                 if (!p2) {
4264                         return False;
4265                 }
4266                 SIVAL(p,usri11_last_logon,0);           /* last logon */
4267                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
4268                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
4269                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
4270                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4271                 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4272                 p2 = skip_string(*rdata,*rdata_len,p2);
4273                 if (!p2) {
4274                         return False;
4275                 }
4276                 SSVAL(p,usri11_country_code,0);         /* country code */
4277
4278                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4279                 strlcpy(p2,"",PTR_DIFF(endp,p2));
4280                 p2 = skip_string(*rdata,*rdata_len,p2);
4281                 if (!p2) {
4282                         return False;
4283                 }
4284
4285                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
4286                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
4287                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4288
4289                 /* a simple way to get logon hours at all times. */
4290                 memset(p2,0xff,21);
4291                 SCVAL(p2,21,0);           /* fix zero termination */
4292                 p2 = skip_string(*rdata,*rdata_len,p2);
4293                 if (!p2) {
4294                         return False;
4295                 }
4296
4297                 SSVAL(p,usri11_code_page,0);            /* code page */
4298         }
4299
4300         if (uLevel == 1 || uLevel == 2) {
4301                 memset(p+22,' ',16);    /* password */
4302                 SIVALS(p,38,-1);                /* password age */
4303                 SSVAL(p,42,
4304                         (get_current_uid(conn) == sec_initial_uid())?
4305                         USER_PRIV_ADMIN:USER_PRIV_USER);
4306                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4307                 strlcpy(p2, info->info21.home_directory.string,
4308                         PTR_DIFF(endp,p2));
4309                 p2 = skip_string(*rdata,*rdata_len,p2);
4310                 if (!p2) {
4311                         return False;
4312                 }
4313                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4314                 *p2++ = 0;
4315                 SSVAL(p,52,0);          /* flags */
4316                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
4317                 strlcpy(p2, info->info21.logon_script.string,
4318                         PTR_DIFF(endp,p2));
4319                 p2 = skip_string(*rdata,*rdata_len,p2);
4320                 if (!p2) {
4321                         return False;
4322                 }
4323                 if (uLevel == 2) {
4324                         SIVAL(p,58,0);          /* auth_flags */
4325                         SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4326                         strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4327                         p2 = skip_string(*rdata,*rdata_len,p2);
4328                         if (!p2) {
4329                                 return False;
4330                         }
4331                         SIVAL(p,66,0);          /* urs_comment */
4332                         SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4333                         strlcpy(p2,"",PTR_DIFF(endp,p2));
4334                         p2 = skip_string(*rdata,*rdata_len,p2);
4335                         if (!p2) {
4336                                 return False;
4337                         }
4338                         SIVAL(p,74,0);          /* workstations */
4339                         SIVAL(p,78,0);          /* last_logon */
4340                         SIVAL(p,82,0);          /* last_logoff */
4341                         SIVALS(p,86,-1);                /* acct_expires */
4342                         SIVALS(p,90,-1);                /* max_storage */
4343                         SSVAL(p,94,168);        /* units_per_week */
4344                         SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4345                         memset(p2,-1,21);
4346                         p2 += 21;
4347                         SSVALS(p,100,-1);       /* bad_pw_count */
4348                         SSVALS(p,102,-1);       /* num_logons */
4349                         SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4350                         {
4351                                 TALLOC_CTX *ctx = talloc_tos();
4352                                 int space_rem = *rdata_len - (p2 - *rdata);
4353                                 char *tmp;
4354
4355                                 if (space_rem <= 0) {
4356                                         return false;
4357                                 }
4358                                 tmp = talloc_strdup(ctx, "\\\\%L");
4359                                 if (!tmp) {
4360                                         return false;
4361                                 }
4362                                 tmp = talloc_sub_basic(ctx,
4363                                                 "",
4364                                                 "",
4365                                                 tmp);
4366                                 if (!tmp) {
4367                                         return false;
4368                                 }
4369
4370                                 push_ascii(p2,
4371                                         tmp,
4372                                         space_rem,
4373                                         STR_TERMINATE);
4374                         }
4375                         p2 = skip_string(*rdata,*rdata_len,p2);
4376                         if (!p2) {
4377                                 return False;
4378                         }
4379                         SSVAL(p,108,49);        /* country_code */
4380                         SSVAL(p,110,860);       /* code page */
4381                 }
4382         }
4383
4384         errcode = NERR_Success;
4385
4386  out:
4387         *rdata_len = PTR_DIFF(p2,*rdata);
4388
4389         if (cli && is_valid_policy_hnd(&user_handle)) {
4390                 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4391         }
4392         if (cli && is_valid_policy_hnd(&domain_handle)) {
4393                 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4394         }
4395         if (cli && is_valid_policy_hnd(&connect_handle)) {
4396                 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4397         }
4398
4399         SSVAL(*rparam,0,errcode);
4400         SSVAL(*rparam,2,0);             /* converter word */
4401         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
4402
4403         return(True);
4404 }
4405
4406 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4407                                 connection_struct *conn,uint16 vuid,
4408                                 char *param, int tpscnt,
4409                                 char *data, int tdscnt,
4410                                 int mdrcnt,int mprcnt,
4411                                 char **rdata,char **rparam,
4412                                 int *rdata_len,int *rparam_len)
4413 {
4414         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4415         char *str2 = skip_string(param,tpscnt,str1);
4416         char *p = skip_string(param,tpscnt,str2);
4417         int uLevel;
4418         struct pack_desc desc;
4419         char* name;
4420                 /* With share level security vuid will always be zero.
4421                    Don't depend on vuser being non-null !!. JRA */
4422         user_struct *vuser = get_valid_user_struct(sconn, vuid);
4423
4424         if (!str1 || !str2 || !p) {
4425                 return False;
4426         }
4427
4428         if(vuser != NULL) {
4429                 DEBUG(3,("  Username of UID %d is %s\n",
4430                          (int)vuser->server_info->utok.uid,
4431                          vuser->server_info->unix_name));
4432         }
4433
4434         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4435         name = get_safe_str_ptr(param,tpscnt,p,2);
4436         if (!name) {
4437                 return False;
4438         }
4439
4440         memset((char *)&desc,'\0',sizeof(desc));
4441
4442         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4443
4444         /* check it's a supported varient */
4445         if (strcmp(str1,"OOWb54WrLh") != 0) {
4446                 return False;
4447         }
4448         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4449                 return False;
4450         }
4451         if (mdrcnt > 0) {
4452                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4453                 if (!*rdata) {
4454                         return False;
4455                 }
4456         }
4457
4458         desc.base = *rdata;
4459         desc.buflen = mdrcnt;
4460         desc.subformat = NULL;
4461         desc.format = str2;
4462
4463         if (init_package(&desc,1,0)) {
4464                 PACKI(&desc,"W",0);             /* code */
4465                 PACKS(&desc,"B21",name);        /* eff. name */
4466                 PACKS(&desc,"B","");            /* pad */
4467                 PACKI(&desc,"W",
4468                         (get_current_uid(conn) == sec_initial_uid())?
4469                         USER_PRIV_ADMIN:USER_PRIV_USER);
4470                 PACKI(&desc,"D",0);             /* auth flags XXX */
4471                 PACKI(&desc,"W",0);             /* num logons */
4472                 PACKI(&desc,"W",0);             /* bad pw count */
4473                 PACKI(&desc,"D",0);             /* last logon */
4474                 PACKI(&desc,"D",-1);            /* last logoff */
4475                 PACKI(&desc,"D",-1);            /* logoff time */
4476                 PACKI(&desc,"D",-1);            /* kickoff time */
4477                 PACKI(&desc,"D",0);             /* password age */
4478                 PACKI(&desc,"D",0);             /* password can change */
4479                 PACKI(&desc,"D",-1);            /* password must change */
4480
4481                 {
4482                         fstring mypath;
4483                         fstrcpy(mypath,"\\\\");
4484                         fstrcat(mypath,get_local_machine_name());
4485                         strupper_m(mypath);
4486                         PACKS(&desc,"z",mypath); /* computer */
4487                 }
4488
4489                 PACKS(&desc,"z",lp_workgroup());/* domain */
4490                 PACKS(&desc,"z", vuser ?
4491                         vuser->server_info->info3->base.logon_script.string
4492                         : ""); /* script path */
4493                 PACKI(&desc,"D",0x00000000);            /* reserved */
4494         }
4495
4496         *rdata_len = desc.usedlen;
4497         *rparam_len = 6;
4498         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4499         if (!*rparam) {
4500                 return False;
4501         }
4502         SSVALS(*rparam,0,desc.errcode);
4503         SSVAL(*rparam,2,0);
4504         SSVAL(*rparam,4,desc.neededlen);
4505
4506         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4507
4508         return True;
4509 }
4510
4511 /****************************************************************************
4512  api_WAccessGetUserPerms
4513 ****************************************************************************/
4514
4515 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4516                                     connection_struct *conn,uint16 vuid,
4517                                 char *param, int tpscnt,
4518                                 char *data, int tdscnt,
4519                                 int mdrcnt,int mprcnt,
4520                                 char **rdata,char **rparam,
4521                                 int *rdata_len,int *rparam_len)
4522 {
4523         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4524         char *str2 = skip_string(param,tpscnt,str1);
4525         char *user = skip_string(param,tpscnt,str2);
4526         char *resource = skip_string(param,tpscnt,user);
4527
4528         if (!str1 || !str2 || !user || !resource) {
4529                 return False;
4530         }
4531
4532         if (skip_string(param,tpscnt,resource) == NULL) {
4533                 return False;
4534         }
4535         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4536
4537         /* check it's a supported varient */
4538         if (strcmp(str1,"zzh") != 0) {
4539                 return False;
4540         }
4541         if (strcmp(str2,"") != 0) {
4542                 return False;
4543         }
4544
4545         *rparam_len = 6;
4546         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4547         if (!*rparam) {
4548                 return False;
4549         }
4550         SSVALS(*rparam,0,0);            /* errorcode */
4551         SSVAL(*rparam,2,0);             /* converter word */
4552         SSVAL(*rparam,4,0x7f);  /* permission flags */
4553
4554         return True;
4555 }
4556
4557 /****************************************************************************
4558   api_WPrintJobEnumerate
4559   ****************************************************************************/
4560
4561 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4562                                  connection_struct *conn, uint16 vuid,
4563                                 char *param, int tpscnt,
4564                                 char *data, int tdscnt,
4565                                 int mdrcnt,int mprcnt,
4566                                 char **rdata,char **rparam,
4567                                 int *rdata_len,int *rparam_len)
4568 {
4569         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4570         char *str2 = skip_string(param,tpscnt,str1);
4571         char *p = skip_string(param,tpscnt,str2);
4572         int uLevel;
4573         fstring sharename;
4574         uint32 jobid;
4575         struct pack_desc desc;
4576         char *tmpdata=NULL;
4577
4578         TALLOC_CTX *mem_ctx = talloc_tos();
4579         WERROR werr;
4580         NTSTATUS status;
4581         struct rpc_pipe_client *cli = NULL;
4582         struct policy_handle handle;
4583         struct spoolss_DevmodeContainer devmode_ctr;
4584         union spoolss_JobInfo info;
4585
4586         if (!str1 || !str2 || !p) {
4587                 return False;
4588         }
4589
4590         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4591
4592         memset((char *)&desc,'\0',sizeof(desc));
4593         memset((char *)&status,'\0',sizeof(status));
4594
4595         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4596
4597         /* check it's a supported varient */
4598         if (strcmp(str1,"WWrLh") != 0) {
4599                 return False;
4600         }
4601         if (!check_printjob_info(&desc,uLevel,str2)) {
4602                 return False;
4603         }
4604
4605         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4606                 return False;
4607         }
4608
4609         ZERO_STRUCT(handle);
4610
4611         status = rpc_connect_spoolss_pipe(conn, &cli);
4612         if (!NT_STATUS_IS_OK(status)) {
4613                 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4614                           nt_errstr(status)));
4615                 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4616                 goto out;
4617         }
4618
4619         ZERO_STRUCT(devmode_ctr);
4620
4621         status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4622                                             sharename,
4623                                             "RAW",
4624                                             devmode_ctr,
4625                                             PRINTER_ACCESS_USE,
4626                                             &handle,
4627                                             &werr);
4628         if (!NT_STATUS_IS_OK(status)) {
4629                 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4630                 goto out;
4631         }
4632         if (!W_ERROR_IS_OK(werr)) {
4633                 desc.errcode = W_ERROR_V(werr);
4634                 goto out;
4635         }
4636
4637         werr = rpccli_spoolss_getjob(cli, mem_ctx,
4638                                      &handle,
4639                                      jobid,
4640                                      2, /* level */
4641                                      0, /* offered */
4642                                      &info);
4643         if (!W_ERROR_IS_OK(werr)) {
4644                 desc.errcode = W_ERROR_V(werr);
4645                 goto out;
4646         }
4647
4648         if (mdrcnt > 0) {
4649                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4650                 if (!*rdata) {
4651                         return False;
4652                 }
4653                 desc.base = *rdata;
4654                 desc.buflen = mdrcnt;
4655         } else {
4656                 /*
4657                  * Don't return data but need to get correct length
4658                  *  init_package will return wrong size if buflen=0
4659                  */
4660                 desc.buflen = getlen(desc.format);
4661                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4662         }
4663
4664         if (init_package(&desc,1,0)) {
4665                 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4666                 *rdata_len = desc.usedlen;
4667         } else {
4668                 desc.errcode = NERR_JobNotFound;
4669                 *rdata_len = 0;
4670         }
4671  out:
4672         if (cli && is_valid_policy_hnd(&handle)) {
4673                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4674         }
4675
4676         *rparam_len = 6;
4677         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4678         if (!*rparam) {
4679                 return False;
4680         }
4681         SSVALS(*rparam,0,desc.errcode);
4682         SSVAL(*rparam,2,0);
4683         SSVAL(*rparam,4,desc.neededlen);
4684
4685         SAFE_FREE(tmpdata);
4686
4687         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4688
4689         return True;
4690 }
4691
4692 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4693                                    connection_struct *conn, uint16 vuid,
4694                                 char *param, int tpscnt,
4695                                 char *data, int tdscnt,
4696                                 int mdrcnt,int mprcnt,
4697                                 char **rdata,char **rparam,
4698                                 int *rdata_len,int *rparam_len)
4699 {
4700         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4701         char *str2 = skip_string(param,tpscnt,str1);
4702         char *p = skip_string(param,tpscnt,str2);
4703         char *name = p;
4704         int uLevel;
4705         int i, succnt=0;
4706         struct pack_desc desc;
4707
4708         TALLOC_CTX *mem_ctx = talloc_tos();
4709         WERROR werr;
4710         NTSTATUS status;
4711         struct rpc_pipe_client *cli = NULL;
4712         struct policy_handle handle;
4713         struct spoolss_DevmodeContainer devmode_ctr;
4714         uint32_t count = 0;
4715         union spoolss_JobInfo *info;
4716
4717         if (!str1 || !str2 || !p) {
4718                 return False;
4719         }
4720
4721         memset((char *)&desc,'\0',sizeof(desc));
4722
4723         p = skip_string(param,tpscnt,p);
4724         if (!p) {
4725                 return False;
4726         }
4727         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4728
4729         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4730
4731         /* check it's a supported variant */
4732         if (strcmp(str1,"zWrLeh") != 0) {
4733                 return False;
4734         }
4735
4736         if (uLevel > 2) {
4737                 return False;   /* defined only for uLevel 0,1,2 */
4738         }
4739
4740         if (!check_printjob_info(&desc,uLevel,str2)) { 
4741                 return False;
4742         }
4743
4744         ZERO_STRUCT(handle);
4745
4746         status = rpc_connect_spoolss_pipe(conn, &cli);
4747         if (!NT_STATUS_IS_OK(status)) {
4748                 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4749                           nt_errstr(status)));
4750                 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4751                 goto out;
4752         }
4753
4754         ZERO_STRUCT(devmode_ctr);
4755
4756         status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4757                                             name,
4758                                             NULL,
4759                                             devmode_ctr,
4760                                             SEC_FLAG_MAXIMUM_ALLOWED,
4761                                             &handle,
4762                                             &werr);
4763         if (!NT_STATUS_IS_OK(status)) {
4764                 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4765                 goto out;
4766         }
4767         if (!W_ERROR_IS_OK(werr)) {
4768                 desc.errcode = W_ERROR_V(werr);
4769                 goto out;
4770         }
4771
4772         werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4773                                        &handle,
4774                                        0, /* firstjob */
4775                                        0xff, /* numjobs */
4776                                        2, /* level */
4777                                        0, /* offered */
4778                                        &count,
4779                                        &info);
4780         if (!W_ERROR_IS_OK(werr)) {
4781                 desc.errcode = W_ERROR_V(werr);
4782                 goto out;
4783         }
4784
4785         if (mdrcnt > 0) {
4786                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4787                 if (!*rdata) {
4788                         return False;
4789                 }
4790         }
4791         desc.base = *rdata;
4792         desc.buflen = mdrcnt;
4793
4794         if (init_package(&desc,count,0)) {
4795                 succnt = 0;
4796                 for (i = 0; i < count; i++) {
4797                         fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4798                         if (desc.errcode == NERR_Success) {
4799                                 succnt = i+1;
4800                         }
4801                 }
4802         }
4803  out:
4804         if (cli && is_valid_policy_hnd(&handle)) {
4805                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4806         }
4807
4808         *rdata_len = desc.usedlen;
4809
4810         *rparam_len = 8;
4811         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4812         if (!*rparam) {
4813                 return False;
4814         }
4815         SSVALS(*rparam,0,desc.errcode);
4816         SSVAL(*rparam,2,0);
4817         SSVAL(*rparam,4,succnt);
4818         SSVAL(*rparam,6,count);
4819
4820         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4821
4822         return True;
4823 }
4824
4825 static int check_printdest_info(struct pack_desc* desc,
4826                                 int uLevel, char* id)
4827 {
4828         desc->subformat = NULL;
4829         switch( uLevel ) {
4830                 case 0:
4831                         desc->format = "B9";
4832                         break;
4833                 case 1:
4834                         desc->format = "B9B21WWzW";
4835                         break;
4836                 case 2:
4837                         desc->format = "z";
4838                         break;
4839                 case 3:
4840                         desc->format = "zzzWWzzzWW";
4841                         break;
4842                 default:
4843                         DEBUG(0,("check_printdest_info: invalid level %d\n",
4844                                 uLevel));
4845                         return False;
4846         }
4847         if (id == NULL || strcmp(desc->format,id) != 0) {
4848                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
4849                         id ? id : "<NULL>" ));
4850                 return False;
4851         }
4852         return True;
4853 }
4854
4855 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4856                                 struct pack_desc* desc)
4857 {
4858         char buf[100];
4859
4860         strncpy(buf, info2->printername, sizeof(buf)-1);
4861         buf[sizeof(buf)-1] = 0;
4862         strupper_m(buf);
4863
4864         if (uLevel <= 1) {
4865                 PACKS(desc,"B9",buf);   /* szName */
4866                 if (uLevel == 1) {
4867                         PACKS(desc,"B21","");   /* szUserName */
4868                         PACKI(desc,"W",0);              /* uJobId */
4869                         PACKI(desc,"W",0);              /* fsStatus */
4870                         PACKS(desc,"z","");     /* pszStatus */
4871                         PACKI(desc,"W",0);              /* time */
4872                 }
4873         }
4874
4875         if (uLevel == 2 || uLevel == 3) {
4876                 PACKS(desc,"z",buf);            /* pszPrinterName */
4877                 if (uLevel == 3) {
4878                         PACKS(desc,"z","");     /* pszUserName */
4879                         PACKS(desc,"z","");     /* pszLogAddr */
4880                         PACKI(desc,"W",0);              /* uJobId */
4881                         PACKI(desc,"W",0);              /* fsStatus */
4882                         PACKS(desc,"z","");     /* pszStatus */
4883                         PACKS(desc,"z","");     /* pszComment */
4884                         PACKS(desc,"z","NULL"); /* pszDrivers */
4885                         PACKI(desc,"W",0);              /* time */
4886                         PACKI(desc,"W",0);              /* pad1 */
4887                 }
4888         }
4889 }
4890
4891 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4892                                   connection_struct *conn, uint16 vuid,
4893                                 char *param, int tpscnt,
4894                                 char *data, int tdscnt,
4895                                 int mdrcnt,int mprcnt,
4896                                 char **rdata,char **rparam,
4897                                 int *rdata_len,int *rparam_len)
4898 {
4899         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4900         char *str2 = skip_string(param,tpscnt,str1);
4901         char *p = skip_string(param,tpscnt,str2);
4902         char* PrinterName = p;
4903         int uLevel;
4904         struct pack_desc desc;
4905         char *tmpdata=NULL;
4906
4907         TALLOC_CTX *mem_ctx = talloc_tos();
4908         WERROR werr;
4909         NTSTATUS status;
4910         struct rpc_pipe_client *cli = NULL;
4911         struct policy_handle handle;
4912         struct spoolss_DevmodeContainer devmode_ctr;
4913         union spoolss_PrinterInfo info;
4914
4915         if (!str1 || !str2 || !p) {
4916                 return False;
4917         }
4918
4919         memset((char *)&desc,'\0',sizeof(desc));
4920
4921         p = skip_string(param,tpscnt,p);
4922         if (!p) {
4923                 return False;
4924         }
4925         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4926
4927         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4928
4929         /* check it's a supported varient */
4930         if (strcmp(str1,"zWrLh") != 0) {
4931                 return False;
4932         }
4933         if (!check_printdest_info(&desc,uLevel,str2)) {
4934                 return False;
4935         }
4936
4937         ZERO_STRUCT(handle);
4938
4939         status = rpc_connect_spoolss_pipe(conn, &cli);
4940         if (!NT_STATUS_IS_OK(status)) {
4941                 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4942                           nt_errstr(status)));
4943                 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4944                 goto out;
4945         }
4946
4947         ZERO_STRUCT(devmode_ctr);
4948
4949         status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4950                                             PrinterName,
4951                                             NULL,
4952                                             devmode_ctr,
4953                                             SEC_FLAG_MAXIMUM_ALLOWED,
4954                                             &handle,
4955                                             &werr);
4956         if (!NT_STATUS_IS_OK(status)) {
4957                 *rdata_len = 0;
4958                 desc.errcode = NERR_DestNotFound;
4959                 desc.neededlen = 0;
4960                 goto out;
4961         }
4962         if (!W_ERROR_IS_OK(werr)) {
4963                 *rdata_len = 0;
4964                 desc.errcode = NERR_DestNotFound;
4965                 desc.neededlen = 0;
4966                 goto out;
4967         }
4968
4969         werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4970                                          &handle,
4971                                          2,
4972                                          0,
4973                                          &info);
4974         if (!W_ERROR_IS_OK(werr)) {
4975                 *rdata_len = 0;
4976                 desc.errcode = NERR_DestNotFound;
4977                 desc.neededlen = 0;
4978                 goto out;
4979         }
4980
4981         if (mdrcnt > 0) {
4982                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4983                 if (!*rdata) {
4984                         return False;
4985                 }
4986                 desc.base = *rdata;
4987                 desc.buflen = mdrcnt;
4988         } else {
4989                 /*
4990                  * Don't return data but need to get correct length
4991                  * init_package will return wrong size if buflen=0
4992                  */
4993                 desc.buflen = getlen(desc.format);
4994                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4995         }
4996         if (init_package(&desc,1,0)) {
4997                 fill_printdest_info(&info.info2, uLevel,&desc);
4998         }
4999
5000  out:
5001         if (cli && is_valid_policy_hnd(&handle)) {
5002                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5003         }
5004
5005         *rdata_len = desc.usedlen;
5006
5007         *rparam_len = 6;
5008         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5009         if (!*rparam) {
5010                 return False;
5011         }
5012         SSVALS(*rparam,0,desc.errcode);
5013         SSVAL(*rparam,2,0);
5014         SSVAL(*rparam,4,desc.neededlen);
5015
5016         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5017         SAFE_FREE(tmpdata);
5018
5019         return True;
5020 }
5021
5022 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5023                                connection_struct *conn, uint16 vuid,
5024                                 char *param, int tpscnt,
5025                                 char *data, int tdscnt,
5026                                 int mdrcnt,int mprcnt,
5027                                 char **rdata,char **rparam,
5028                                 int *rdata_len,int *rparam_len)
5029 {
5030         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5031         char *str2 = skip_string(param,tpscnt,str1);
5032         char *p = skip_string(param,tpscnt,str2);
5033         int uLevel;
5034         int queuecnt;
5035         int i, n, succnt=0;
5036         struct pack_desc desc;
5037
5038         TALLOC_CTX *mem_ctx = talloc_tos();
5039         WERROR werr;
5040         NTSTATUS status;
5041         struct rpc_pipe_client *cli = NULL;
5042         union spoolss_PrinterInfo *info;
5043         uint32_t count;
5044
5045         if (!str1 || !str2 || !p) {
5046                 return False;
5047         }
5048
5049         memset((char *)&desc,'\0',sizeof(desc));
5050
5051         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5052
5053         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5054
5055         /* check it's a supported varient */
5056         if (strcmp(str1,"WrLeh") != 0) {
5057                 return False;
5058         }
5059         if (!check_printdest_info(&desc,uLevel,str2)) {
5060                 return False;
5061         }
5062
5063         queuecnt = 0;
5064
5065         status = rpc_connect_spoolss_pipe(conn, &cli);
5066         if (!NT_STATUS_IS_OK(status)) {
5067                 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5068                           nt_errstr(status)));
5069                 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5070                 goto out;
5071         }
5072
5073         werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5074                                            PRINTER_ENUM_LOCAL,
5075                                            cli->srv_name_slash,
5076                                            2,
5077                                            0,
5078                                            &count,
5079                                            &info);
5080         if (!W_ERROR_IS_OK(werr)) {
5081                 desc.errcode = W_ERROR_V(werr);
5082                 *rdata_len = 0;
5083                 desc.errcode = NERR_DestNotFound;
5084                 desc.neededlen = 0;
5085                 goto out;
5086         }
5087
5088         queuecnt = count;
5089
5090         if (mdrcnt > 0) {
5091                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5092                 if (!*rdata) {
5093                         return False;
5094                 }
5095         }
5096
5097         desc.base = *rdata;
5098         desc.buflen = mdrcnt;
5099         if (init_package(&desc,queuecnt,0)) {    
5100                 succnt = 0;
5101                 n = 0;
5102                 for (i = 0; i < count; i++) {
5103                         fill_printdest_info(&info[i].info2, uLevel,&desc);
5104                         n++;
5105                         if (desc.errcode == NERR_Success) {
5106                                 succnt = n;
5107                         }
5108                 }
5109         }
5110  out:
5111         *rdata_len = desc.usedlen;
5112
5113         *rparam_len = 8;
5114         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5115         if (!*rparam) {
5116                 return False;
5117         }
5118         SSVALS(*rparam,0,desc.errcode);
5119         SSVAL(*rparam,2,0);
5120         SSVAL(*rparam,4,succnt);
5121         SSVAL(*rparam,6,queuecnt);
5122
5123         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5124
5125         return True;
5126 }
5127
5128 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5129                                  connection_struct *conn, uint16 vuid,
5130                                 char *param, int tpscnt,
5131                                 char *data, int tdscnt,
5132                                 int mdrcnt,int mprcnt,
5133                                 char **rdata,char **rparam,
5134                                 int *rdata_len,int *rparam_len)
5135 {
5136         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5137         char *str2 = skip_string(param,tpscnt,str1);
5138         char *p = skip_string(param,tpscnt,str2);
5139         int uLevel;
5140         int succnt;
5141         struct pack_desc desc;
5142
5143         if (!str1 || !str2 || !p) {
5144                 return False;
5145         }
5146
5147         memset((char *)&desc,'\0',sizeof(desc));
5148
5149         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5150
5151         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5152
5153         /* check it's a supported varient */
5154         if (strcmp(str1,"WrLeh") != 0) {
5155                 return False;
5156         }
5157         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5158                 return False;
5159         }
5160
5161         if (mdrcnt > 0) {
5162                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5163                 if (!*rdata) {
5164                         return False;
5165                 }
5166         }
5167         desc.base = *rdata;
5168         desc.buflen = mdrcnt;
5169         if (init_package(&desc,1,0)) {
5170                 PACKS(&desc,"B41","NULL");
5171         }
5172
5173         succnt = (desc.errcode == NERR_Success ? 1 : 0);
5174
5175         *rdata_len = desc.usedlen;
5176
5177         *rparam_len = 8;
5178         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5179         if (!*rparam) {
5180                 return False;
5181         }
5182         SSVALS(*rparam,0,desc.errcode);
5183         SSVAL(*rparam,2,0);
5184         SSVAL(*rparam,4,succnt);
5185         SSVAL(*rparam,6,1);
5186
5187         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5188
5189         return True;
5190 }
5191
5192 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5193                                 connection_struct *conn, uint16 vuid,
5194                                 char *param, int tpscnt,
5195                                 char *data, int tdscnt,
5196                                 int mdrcnt,int mprcnt,
5197                                 char **rdata,char **rparam,
5198                                 int *rdata_len,int *rparam_len)
5199 {
5200         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5201         char *str2 = skip_string(param,tpscnt,str1);
5202         char *p = skip_string(param,tpscnt,str2);
5203         int uLevel;
5204         int succnt;
5205         struct pack_desc desc;
5206
5207         if (!str1 || !str2 || !p) {
5208                 return False;
5209         }
5210         memset((char *)&desc,'\0',sizeof(desc));
5211
5212         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5213
5214         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5215
5216         /* check it's a supported varient */
5217         if (strcmp(str1,"WrLeh") != 0) {
5218                 return False;
5219         }
5220         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5221                 return False;
5222         }
5223
5224         if (mdrcnt > 0) {
5225                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5226                 if (!*rdata) {
5227                         return False;
5228                 }
5229         }
5230         desc.base = *rdata;
5231         desc.buflen = mdrcnt;
5232         desc.format = str2;
5233         if (init_package(&desc,1,0)) {
5234                 PACKS(&desc,"B13","lpd");
5235         }
5236
5237         succnt = (desc.errcode == NERR_Success ? 1 : 0);
5238
5239         *rdata_len = desc.usedlen;
5240
5241         *rparam_len = 8;
5242         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5243         if (!*rparam) {
5244                 return False;
5245         }
5246         SSVALS(*rparam,0,desc.errcode);
5247         SSVAL(*rparam,2,0);
5248         SSVAL(*rparam,4,succnt);
5249         SSVAL(*rparam,6,1);
5250
5251         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5252
5253         return True;
5254 }
5255
5256 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5257                                connection_struct *conn, uint16 vuid,
5258                                 char *param, int tpscnt,
5259                                 char *data, int tdscnt,
5260                                 int mdrcnt,int mprcnt,
5261                                 char **rdata,char **rparam,
5262                                 int *rdata_len,int *rparam_len)
5263 {
5264         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5265         char *str2 = skip_string(param,tpscnt,str1);
5266         char *p = skip_string(param,tpscnt,str2);
5267         int uLevel;
5268         int succnt;
5269         struct pack_desc desc;
5270
5271         if (!str1 || !str2 || !p) {
5272                 return False;
5273         }
5274
5275         memset((char *)&desc,'\0',sizeof(desc));
5276
5277         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5278
5279         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5280
5281         /* check it's a supported varient */
5282         if (strcmp(str1,"WrLeh") != 0) {
5283                 return False;
5284         }
5285         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5286                 return False;
5287         }
5288
5289         if (mdrcnt > 0) {
5290                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5291                 if (!*rdata) {
5292                         return False;
5293                 }
5294         }
5295         memset((char *)&desc,'\0',sizeof(desc));
5296         desc.base = *rdata;
5297         desc.buflen = mdrcnt;
5298         desc.format = str2;
5299         if (init_package(&desc,1,0)) {
5300                 PACKS(&desc,"B13","lp0");
5301         }
5302
5303         succnt = (desc.errcode == NERR_Success ? 1 : 0);
5304
5305         *rdata_len = desc.usedlen;
5306
5307         *rparam_len = 8;
5308         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5309         if (!*rparam) {
5310                 return False;
5311         }
5312         SSVALS(*rparam,0,desc.errcode);
5313         SSVAL(*rparam,2,0);
5314         SSVAL(*rparam,4,succnt);
5315         SSVAL(*rparam,6,1);
5316
5317         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5318
5319         return True;
5320 }
5321
5322 /****************************************************************************
5323  List open sessions
5324  ****************************************************************************/
5325
5326 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5327                                 connection_struct *conn, uint16 vuid,
5328                                 char *param, int tpscnt,
5329                                 char *data, int tdscnt,
5330                                 int mdrcnt,int mprcnt,
5331                                 char **rdata,char **rparam,
5332                                 int *rdata_len,int *rparam_len)
5333
5334 {
5335         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5336         char *str2 = skip_string(param,tpscnt,str1);
5337         char *p = skip_string(param,tpscnt,str2);
5338         int uLevel;
5339         struct pack_desc desc;
5340         struct sessionid *session_list;
5341         int i, num_sessions;
5342
5343         if (!str1 || !str2 || !p) {
5344                 return False;
5345         }
5346
5347         memset((char *)&desc,'\0',sizeof(desc));
5348
5349         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5350
5351         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5352         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5353         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5354
5355         /* check it's a supported varient */
5356         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5357                 return False;
5358         }
5359         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5360                 return False;
5361         }
5362
5363         num_sessions = list_sessions(talloc_tos(), &session_list);
5364
5365         if (mdrcnt > 0) {
5366                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5367                 if (!*rdata) {
5368                         return False;
5369                 }
5370         }
5371         memset((char *)&desc,'\0',sizeof(desc));
5372         desc.base = *rdata;
5373         desc.buflen = mdrcnt;
5374         desc.format = str2;
5375         if (!init_package(&desc,num_sessions,0)) {
5376                 return False;
5377         }
5378
5379         for(i=0; i<num_sessions; i++) {
5380                 PACKS(&desc, "z", session_list[i].remote_machine);
5381                 PACKS(&desc, "z", session_list[i].username);
5382                 PACKI(&desc, "W", 1); /* num conns */
5383                 PACKI(&desc, "W", 0); /* num opens */
5384                 PACKI(&desc, "W", 1); /* num users */
5385                 PACKI(&desc, "D", 0); /* session time */
5386                 PACKI(&desc, "D", 0); /* idle time */
5387                 PACKI(&desc, "D", 0); /* flags */
5388                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5389         }
5390
5391         *rdata_len = desc.usedlen;
5392
5393         *rparam_len = 8;
5394         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5395         if (!*rparam) {
5396                 return False;
5397         }
5398         SSVALS(*rparam,0,desc.errcode);
5399         SSVAL(*rparam,2,0); /* converter */
5400         SSVAL(*rparam,4,num_sessions); /* count */
5401
5402         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5403
5404         return True;
5405 }
5406
5407
5408 /****************************************************************************
5409  The buffer was too small.
5410  ****************************************************************************/
5411
5412 static bool api_TooSmall(struct smbd_server_connection *sconn,
5413                          connection_struct *conn,uint16 vuid, char *param, char *data,
5414                          int mdrcnt, int mprcnt,
5415                          char **rdata, char **rparam,
5416                          int *rdata_len, int *rparam_len)
5417 {
5418         *rparam_len = MIN(*rparam_len,mprcnt);
5419         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5420         if (!*rparam) {
5421                 return False;
5422         }
5423
5424         *rdata_len = 0;
5425
5426         SSVAL(*rparam,0,NERR_BufTooSmall);
5427
5428         DEBUG(3,("Supplied buffer too small in API command\n"));
5429
5430         return True;
5431 }
5432
5433 /****************************************************************************
5434  The request is not supported.
5435  ****************************************************************************/
5436
5437 static bool api_Unsupported(struct smbd_server_connection *sconn,
5438                             connection_struct *conn, uint16 vuid,
5439                                 char *param, int tpscnt,
5440                                 char *data, int tdscnt,
5441                                 int mdrcnt, int mprcnt,
5442                                 char **rdata, char **rparam,
5443                                 int *rdata_len, int *rparam_len)
5444 {
5445         *rparam_len = 4;
5446         *rparam = smb_realloc_limit(*rparam,*rparam_len);
5447         if (!*rparam) {
5448                 return False;
5449         }
5450
5451         *rdata_len = 0;
5452
5453         SSVAL(*rparam,0,NERR_notsupported);
5454         SSVAL(*rparam,2,0);             /* converter word */
5455
5456         DEBUG(3,("Unsupported API command\n"));
5457
5458         return True;
5459 }
5460
5461 static const struct {
5462         const char *name;
5463         int id;
5464         bool (*fn)(struct smbd_server_connection *sconn,
5465                    connection_struct *, uint16,
5466                         char *, int,
5467                         char *, int,
5468                         int,int,char **,char **,int *,int *);
5469         bool auth_user;         /* Deny anonymous access? */
5470 } api_commands[] = {
5471         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
5472         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
5473         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
5474         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
5475         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
5476         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
5477         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
5478         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
5479         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
5480         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
5481         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
5482         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
5483         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
5484         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
5485         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
5486         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
5487         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
5488         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
5489         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
5490         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
5491         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
5492         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
5493         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
5494         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
5495         {"NetServerEnum2",      RAP_NetServerEnum2,     api_RNetServerEnum2}, /* anon OK */
5496         {"NetServerEnum3",      RAP_NetServerEnum3,     api_RNetServerEnum3}, /* anon OK */
5497         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5498         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
5499         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
5500         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
5501         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
5502         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5503         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
5504         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5505         {NULL,          -1,     api_Unsupported}
5506         /*  The following RAP calls are not implemented by Samba:
5507
5508         RAP_WFileEnum2 - anon not OK 
5509         */
5510 };
5511
5512
5513 /****************************************************************************
5514  Handle remote api calls.
5515 ****************************************************************************/
5516
5517 void api_reply(connection_struct *conn, uint16 vuid,
5518                struct smb_request *req,
5519                char *data, char *params,
5520                int tdscnt, int tpscnt,
5521                int mdrcnt, int mprcnt)
5522 {
5523         int api_command;
5524         char *rdata = NULL;
5525         char *rparam = NULL;
5526         const char *name1 = NULL;
5527         const char *name2 = NULL;
5528         int rdata_len = 0;
5529         int rparam_len = 0;
5530         bool reply=False;
5531         int i;
5532
5533         if (!params) {
5534                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5535                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5536                 return;
5537         }
5538
5539         if (tpscnt < 2) {
5540                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5541                 return;
5542         }
5543         api_command = SVAL(params,0);
5544         /* Is there a string at position params+2 ? */
5545         if (skip_string(params,tpscnt,params+2)) {
5546                 name1 = params + 2;
5547         } else {
5548                 name1 = "";
5549         }
5550         name2 = skip_string(params,tpscnt,params+2);
5551         if (!name2) {
5552                 name2 = "";
5553         }
5554
5555         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5556                 api_command,
5557                 name1,
5558                 name2,
5559                 tdscnt,tpscnt,mdrcnt,mprcnt));
5560
5561         for (i=0;api_commands[i].name;i++) {
5562                 if (api_commands[i].id == api_command && api_commands[i].fn) {
5563                         DEBUG(3,("Doing %s\n",api_commands[i].name));
5564                         break;
5565                 }
5566         }
5567
5568         /* Check whether this api call can be done anonymously */
5569
5570         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5571                 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5572
5573                 if (!user || user->server_info->guest) {
5574                         reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5575                         return;
5576                 }
5577         }
5578
5579         rdata = (char *)SMB_MALLOC(1024);
5580         if (rdata) {
5581                 memset(rdata,'\0',1024);
5582         }
5583
5584         rparam = (char *)SMB_MALLOC(1024);
5585         if (rparam) {
5586                 memset(rparam,'\0',1024);
5587         }
5588
5589         if(!rdata || !rparam) {
5590                 DEBUG(0,("api_reply: malloc fail !\n"));
5591                 SAFE_FREE(rdata);
5592                 SAFE_FREE(rparam);
5593                 reply_nterror(req, NT_STATUS_NO_MEMORY);
5594                 return;
5595         }
5596
5597         reply = api_commands[i].fn(req->sconn, conn,
5598                                 vuid,
5599                                 params,tpscnt,  /* params + length */
5600                                 data,tdscnt,    /* data + length */
5601                                 mdrcnt,mprcnt,
5602                                 &rdata,&rparam,&rdata_len,&rparam_len);
5603
5604
5605         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5606                 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5607                                      mdrcnt,mprcnt,
5608                                         &rdata,&rparam,&rdata_len,&rparam_len);
5609         }
5610
5611         /* if we get False back then it's actually unsupported */
5612         if (!reply) {
5613                 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5614                                         data,
5615                                         tdscnt,mdrcnt,mprcnt,
5616                         &rdata,&rparam,&rdata_len,&rparam_len);
5617         }
5618
5619         /* If api_Unsupported returns false we can't return anything. */
5620         if (reply) {
5621                 send_trans_reply(conn, req, rparam, rparam_len,
5622                                  rdata, rdata_len, False);
5623         }
5624
5625         SAFE_FREE(rdata);
5626         SAFE_FREE(rparam);
5627         return;
5628 }