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