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