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