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