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