s3/torture: use stack buffer for rbtree loop
[Samba.git] / source3 / smbd / lanman.c
blobabbec164217c2e89a14b97c35880864433e04d03
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.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
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.
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.
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/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
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"
47 #ifdef CHECK_TYPES
48 #undef CHECK_TYPES
49 #endif
50 #define CHECK_TYPES 0
52 #define NERR_Success 0
53 #define NERR_badpass 86
54 #define NERR_notsupported 50
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)
61 #define ACCESS_READ 0x01
62 #define ACCESS_WRITE 0x02
63 #define ACCESS_CREATE 0x04
65 #define SHPWLEN 8 /* share password length */
67 /* Limit size of ipc replies */
69 static char *smb_realloc_limit(void *ptr, size_t size)
71 char *val;
73 size = MAX((size),4*1024);
74 val = (char *)SMB_REALLOC(ptr,size);
75 if (val) {
76 memset(val,'\0',size);
78 return val;
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);
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);
96 static int CopyExpanded(connection_struct *conn,
97 int snum, char **dst, char *src, int *p_space_remaining)
99 TALLOC_CTX *ctx = talloc_tos();
100 const struct loadparm_substitution *lp_sub =
101 loadparm_s3_global_substitution();
102 char *buf = NULL;
103 int l;
105 if (!src || !dst || !p_space_remaining || !(*dst) ||
106 *p_space_remaining <= 0) {
107 return 0;
110 buf = talloc_strdup(ctx, src);
111 if (!buf) {
112 *p_space_remaining = 0;
113 return 0;
115 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, lp_sub, snum));
116 if (!buf) {
117 *p_space_remaining = 0;
118 return 0;
120 buf = talloc_sub_full(ctx,
121 lp_servicename(ctx, lp_sub, SNUM(conn)),
122 conn->session_info->unix_info->unix_name,
123 conn->connectpath,
124 conn->session_info->unix_token->gid,
125 conn->session_info->unix_info->sanitized_username,
126 conn->session_info->info->domain_name,
127 buf);
128 if (!buf) {
129 *p_space_remaining = 0;
130 return 0;
132 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
133 if (l == 0) {
134 return 0;
136 (*dst) += l;
137 (*p_space_remaining) -= l;
138 return l;
141 static int CopyAndAdvance(char **dst, char *src, int *n)
143 int l;
144 if (!src || !dst || !n || !(*dst)) {
145 return 0;
147 l = push_ascii(*dst,src,*n, STR_TERMINATE);
148 if (l == 0) {
149 return 0;
151 (*dst) += l;
152 (*n) -= l;
153 return l;
156 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
158 TALLOC_CTX *ctx = talloc_tos();
159 const struct loadparm_substitution *lp_sub =
160 loadparm_s3_global_substitution();
161 char *buf = NULL;
162 if (!s) {
163 return 0;
165 buf = talloc_strdup(ctx,s);
166 if (!buf) {
167 return 0;
169 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, lp_sub, snum));
170 if (!buf) {
171 return 0;
173 buf = talloc_sub_full(ctx,
174 lp_servicename(ctx, lp_sub, SNUM(conn)),
175 conn->session_info->unix_info->unix_name,
176 conn->connectpath,
177 conn->session_info->unix_token->gid,
178 conn->session_info->unix_info->sanitized_username,
179 conn->session_info->info->domain_name,
180 buf);
181 if (!buf) {
182 return 0;
184 return strlen(buf) + 1;
187 /*******************************************************************
188 Check a API string for validity when we only need to check the prefix.
189 ******************************************************************/
191 static bool prefix_ok(const char *str, const char *prefix)
193 return(strncmp(str,prefix,strlen(prefix)) == 0);
196 struct pack_desc {
197 const char *format; /* formatstring for structure */
198 const char *subformat; /* subformat for structure */
199 char *base; /* baseaddress of buffer */
200 int buflen; /* remaining size for fixed part; on init: length of base */
201 int subcount; /* count of substructures */
202 char *structbuf; /* pointer into buffer for remaining fixed part */
203 int stringlen; /* remaining size for variable part */
204 char *stringbuf; /* pointer into buffer for remaining variable part */
205 int neededlen; /* total needed size */
206 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
207 const char *curpos; /* current position; pointer into format or subformat */
208 int errcode;
211 static int get_counter(const char **p)
213 int i, n;
214 if (!p || !(*p)) {
215 return 1;
217 if (!isdigit((int)**p)) {
218 return 1;
220 for (n = 0;;) {
221 i = **p;
222 if (isdigit(i)) {
223 n = 10 * n + (i - '0');
224 } else {
225 return n;
227 (*p)++;
231 static int getlen(const char *p)
233 int n = 0;
234 if (!p) {
235 return 0;
238 while (*p) {
239 switch( *p++ ) {
240 case 'W': /* word (2 byte) */
241 n += 2;
242 break;
243 case 'K': /* status word? (2 byte) */
244 n += 2;
245 break;
246 case 'N': /* count of substructures (word) at end */
247 n += 2;
248 break;
249 case 'D': /* double word (4 byte) */
250 case 'z': /* offset to zero terminated string (4 byte) */
251 case 'l': /* offset to user data (4 byte) */
252 n += 4;
253 break;
254 case 'b': /* offset to data (with counter) (4 byte) */
255 n += 4;
256 get_counter(&p);
257 break;
258 case 'B': /* byte (with optional counter) */
259 n += get_counter(&p);
260 break;
263 return n;
266 static bool init_package(struct pack_desc *p, int count, int subcount)
268 int n = p->buflen;
269 int i;
271 if (!p->format || !p->base) {
272 return False;
275 i = count * getlen(p->format);
276 if (p->subformat) {
277 i += subcount * getlen(p->subformat);
279 p->structbuf = p->base;
280 p->neededlen = 0;
281 p->usedlen = 0;
282 p->subcount = 0;
283 p->curpos = p->format;
284 if (i > n) {
285 p->neededlen = i;
286 i = n = 0;
287 #if 0
289 * This is the old error code we used. Aparently
290 * WinNT/2k systems return ERRbuftoosmall (2123) and
291 * OS/2 needs this. I'm leaving this here so we can revert
292 * if needed. JRA.
294 p->errcode = ERRmoredata;
295 #else
296 p->errcode = ERRbuftoosmall;
297 #endif
298 } else {
299 p->errcode = NERR_Success;
301 p->buflen = i;
302 n -= i;
303 p->stringbuf = p->base + i;
304 p->stringlen = n;
305 return (p->errcode == NERR_Success);
308 static int package(struct pack_desc *p, ...)
310 va_list args;
311 int needed=0, stringneeded;
312 const char *str=NULL;
313 int is_string=0, stringused;
314 int32_t temp;
316 va_start(args,p);
318 if (!*p->curpos) {
319 if (!p->subcount) {
320 p->curpos = p->format;
321 } else {
322 p->curpos = p->subformat;
323 p->subcount--;
326 #if CHECK_TYPES
327 str = va_arg(args,char*);
328 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
329 #endif
330 stringneeded = -1;
332 if (!p->curpos) {
333 va_end(args);
334 return 0;
337 switch( *p->curpos++ ) {
338 case 'W': /* word (2 byte) */
339 needed = 2;
340 temp = va_arg(args,int);
341 if (p->buflen >= needed) {
342 SSVAL(p->structbuf,0,temp);
344 break;
345 case 'K': /* status word? (2 byte) */
346 needed = 2;
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SSVAL(p->structbuf,0,temp);
351 break;
352 case 'N': /* count of substructures (word) at end */
353 needed = 2;
354 p->subcount = va_arg(args,int);
355 if (p->buflen >= needed) {
356 SSVAL(p->structbuf,0,p->subcount);
358 break;
359 case 'D': /* double word (4 byte) */
360 needed = 4;
361 temp = va_arg(args,int);
362 if (p->buflen >= needed) {
363 SIVAL(p->structbuf,0,temp);
365 break;
366 case 'B': /* byte (with optional counter) */
367 needed = get_counter(&p->curpos);
369 char *s = va_arg(args,char*);
370 if (p->buflen >= needed) {
371 strlcpy(p->structbuf,s?s:"",needed);
374 break;
375 case 'z': /* offset to zero terminated string (4 byte) */
376 str = va_arg(args,char*);
377 stringneeded = (str ? strlen(str)+1 : 0);
378 is_string = 1;
379 break;
380 case 'l': /* offset to user data (4 byte) */
381 str = va_arg(args,char*);
382 stringneeded = va_arg(args,int);
383 is_string = 0;
384 break;
385 case 'b': /* offset to data (with counter) (4 byte) */
386 str = va_arg(args,char*);
387 stringneeded = get_counter(&p->curpos);
388 is_string = 0;
389 break;
392 va_end(args);
393 if (stringneeded >= 0) {
394 needed = 4;
395 if (p->buflen >= needed) {
396 stringused = stringneeded;
397 if (stringused > p->stringlen) {
398 stringused = (is_string ? p->stringlen : 0);
399 if (p->errcode == NERR_Success) {
400 p->errcode = ERRmoredata;
403 if (!stringused) {
404 SIVAL(p->structbuf,0,0);
405 } else {
406 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
407 memcpy(p->stringbuf,str?str:"",stringused);
408 if (is_string) {
409 p->stringbuf[stringused-1] = '\0';
411 p->stringbuf += stringused;
412 p->stringlen -= stringused;
413 p->usedlen += stringused;
416 p->neededlen += stringneeded;
419 p->neededlen += needed;
420 if (p->buflen >= needed) {
421 p->structbuf += needed;
422 p->buflen -= needed;
423 p->usedlen += needed;
424 } else {
425 if (p->errcode == NERR_Success) {
426 p->errcode = ERRmoredata;
429 return 1;
432 #if CHECK_TYPES
433 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
434 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
435 #else
436 #define PACK(desc,t,v) package(desc,v)
437 #define PACKl(desc,t,v,l) package(desc,v,l)
438 #endif
440 static void PACKI(struct pack_desc* desc, const char *t,int v)
442 PACK(desc,t,v);
445 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
447 PACK(desc,t,v);
450 /****************************************************************************
451 Get a print queue.
452 ****************************************************************************/
454 static void PackDriverData(struct pack_desc* desc)
456 char drivdata[4+4+32];
457 SIVAL(drivdata,0,sizeof drivdata); /* cb */
458 SIVAL(drivdata,4,1000); /* lVersion */
459 memset(drivdata+8,0,32); /* szDeviceName */
460 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
461 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
464 static int check_printq_info(struct pack_desc* desc,
465 unsigned int uLevel, char *id1, char *id2)
467 desc->subformat = NULL;
468 switch( uLevel ) {
469 case 0:
470 desc->format = "B13";
471 break;
472 case 1:
473 desc->format = "B13BWWWzzzzzWW";
474 break;
475 case 2:
476 desc->format = "B13BWWWzzzzzWN";
477 desc->subformat = "WB21BB16B10zWWzDDz";
478 break;
479 case 3:
480 desc->format = "zWWWWzzzzWWzzl";
481 break;
482 case 4:
483 desc->format = "zWWWWzzzzWNzzl";
484 desc->subformat = "WWzWWDDzz";
485 break;
486 case 5:
487 desc->format = "z";
488 break;
489 case 51:
490 desc->format = "K";
491 break;
492 case 52:
493 desc->format = "WzzzzzzzzN";
494 desc->subformat = "z";
495 break;
496 default:
497 DEBUG(0,("check_printq_info: invalid level %d\n",
498 uLevel ));
499 return False;
501 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
502 DEBUG(0,("check_printq_info: invalid format %s\n",
503 id1 ? id1 : "<NULL>" ));
504 return False;
506 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
507 DEBUG(0,("check_printq_info: invalid subformat %s\n",
508 id2 ? id2 : "<NULL>" ));
509 return False;
511 return True;
515 #define RAP_JOB_STATUS_QUEUED 0
516 #define RAP_JOB_STATUS_PAUSED 1
517 #define RAP_JOB_STATUS_SPOOLING 2
518 #define RAP_JOB_STATUS_PRINTING 3
519 #define RAP_JOB_STATUS_PRINTED 4
521 #define RAP_QUEUE_STATUS_PAUSED 1
522 #define RAP_QUEUE_STATUS_ERROR 2
524 /* turn a print job status into a on the wire status
526 static int printj_spoolss_status(int v)
528 if (v == JOB_STATUS_QUEUED)
529 return RAP_JOB_STATUS_QUEUED;
530 if (v & JOB_STATUS_PAUSED)
531 return RAP_JOB_STATUS_PAUSED;
532 if (v & JOB_STATUS_SPOOLING)
533 return RAP_JOB_STATUS_SPOOLING;
534 if (v & JOB_STATUS_PRINTING)
535 return RAP_JOB_STATUS_PRINTING;
536 return 0;
539 /* turn a print queue status into a on the wire status
541 static int printq_spoolss_status(int v)
543 if (v == PRINTER_STATUS_OK)
544 return 0;
545 if (v & PRINTER_STATUS_PAUSED)
546 return RAP_QUEUE_STATUS_PAUSED;
547 return RAP_QUEUE_STATUS_ERROR;
550 static void fill_spoolss_printjob_info(int uLevel,
551 struct pack_desc *desc,
552 struct spoolss_JobInfo2 *info2,
553 int n)
555 time_t t = spoolss_Time_to_time_t(&info2->submitted);
557 /* the client expects localtime */
558 t -= get_time_zone(t);
560 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
561 if (uLevel == 1) {
562 PACKS(desc,"B21", info2->user_name); /* szUserName */
563 PACKS(desc,"B",""); /* pad */
564 PACKS(desc,"B16",""); /* szNotifyName */
565 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
566 PACKS(desc,"z",""); /* pszParms */
567 PACKI(desc,"W",n+1); /* uPosition */
568 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
569 PACKS(desc,"z",""); /* pszStatus */
570 PACKI(desc,"D", t); /* ulSubmitted */
571 PACKI(desc,"D", info2->size); /* ulSize */
572 PACKS(desc,"z", info2->document_name); /* pszComment */
574 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
575 PACKI(desc,"W", info2->priority); /* uPriority */
576 PACKS(desc,"z", info2->user_name); /* pszUserName */
577 PACKI(desc,"W",n+1); /* uPosition */
578 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
579 PACKI(desc,"D",t); /* ulSubmitted */
580 PACKI(desc,"D", info2->size); /* ulSize */
581 PACKS(desc,"z","Samba"); /* pszComment */
582 PACKS(desc,"z", info2->document_name); /* pszDocument */
583 if (uLevel == 3) {
584 PACKS(desc,"z",""); /* pszNotifyName */
585 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
586 PACKS(desc,"z",""); /* pszParms */
587 PACKS(desc,"z",""); /* pszStatus */
588 PACKS(desc,"z", info2->printer_name); /* pszQueue */
589 PACKS(desc,"z","lpd"); /* pszQProcName */
590 PACKS(desc,"z",""); /* pszQProcParms */
591 PACKS(desc,"z","NULL"); /* pszDriverName */
592 PackDriverData(desc); /* pDriverData */
593 PACKS(desc,"z",""); /* pszPrinterName */
594 } else if (uLevel == 4) { /* OS2 */
595 PACKS(desc,"z",""); /* pszSpoolFileName */
596 PACKS(desc,"z",""); /* pszPortName */
597 PACKS(desc,"z",""); /* pszStatus */
598 PACKI(desc,"D",0); /* ulPagesSpooled */
599 PACKI(desc,"D",0); /* ulPagesSent */
600 PACKI(desc,"D",0); /* ulPagesPrinted */
601 PACKI(desc,"D",0); /* ulTimePrinted */
602 PACKI(desc,"D",0); /* ulExtendJobStatus */
603 PACKI(desc,"D",0); /* ulStartPage */
604 PACKI(desc,"D",0); /* ulEndPage */
609 /********************************************************************
610 Respond to the DosPrintQInfo command with a level of 52
611 This is used to get printer driver information for Win9x clients
612 ********************************************************************/
613 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
614 struct pack_desc* desc, int count,
615 const char *printer_name)
617 int i;
618 fstring location;
619 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
620 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
621 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
623 PACKI(desc, "W", 0x0400); /* don't know */
624 PACKS(desc, "z", driver->driver_name); /* long printer name */
625 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
626 PACKS(desc, "z", driver->data_file); /* Datafile name */
627 PACKS(desc, "z", driver->monitor_name); /* language monitor */
629 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
630 standard_sub_basic( "", "", location, sizeof(location)-1 );
631 PACKS(desc,"z", location); /* share to retrieve files */
633 PACKS(desc,"z", driver->default_datatype); /* default data type */
634 PACKS(desc,"z", driver->help_file); /* helpfile name */
635 PACKS(desc,"z", driver->driver_path); /* driver name */
637 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
638 DEBUG(3,("Driver: %s:\n",driver->driver_path));
639 DEBUG(3,("Data File: %s:\n",driver->data_file));
640 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
641 DEBUG(3,("Driver Location: %s:\n",location));
642 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
643 DEBUG(3,("Help File: %s:\n",driver->help_file));
644 PACKI(desc,"N",count); /* number of files to copy */
646 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
648 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
649 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
650 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
653 /* sanity check */
654 if ( i != count )
655 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
656 count, i));
658 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
660 desc->errcode=NERR_Success;
664 static const char *strip_unc(const char *unc)
666 char *p;
668 if (unc == NULL) {
669 return NULL;
672 if ((p = strrchr(unc, '\\')) != NULL) {
673 return p+1;
676 return unc;
679 static void fill_printq_info(int uLevel,
680 struct pack_desc* desc,
681 int count,
682 union spoolss_JobInfo *job_info,
683 struct spoolss_DriverInfo3 *driver_info,
684 struct spoolss_PrinterInfo2 *printer_info)
686 switch (uLevel) {
687 case 0:
688 case 1:
689 case 2:
690 PACKS(desc,"B13", strip_unc(printer_info->printername));
691 break;
692 case 3:
693 case 4:
694 case 5:
695 PACKS(desc,"z", strip_unc(printer_info->printername));
696 break;
697 case 51:
698 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
699 break;
702 if (uLevel == 1 || uLevel == 2) {
703 PACKS(desc,"B",""); /* alignment */
704 PACKI(desc,"W",5); /* priority */
705 PACKI(desc,"W",0); /* start time */
706 PACKI(desc,"W",0); /* until time */
707 PACKS(desc,"z",""); /* pSepFile */
708 PACKS(desc,"z","lpd"); /* pPrProc */
709 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
710 PACKS(desc,"z",""); /* pParms */
711 if (printer_info->printername == NULL) {
712 PACKS(desc,"z","UNKNOWN PRINTER");
713 PACKI(desc,"W",LPSTAT_ERROR);
714 } else {
715 PACKS(desc,"z", printer_info->comment);
716 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
718 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
721 if (uLevel == 3 || uLevel == 4) {
722 PACKI(desc,"W",5); /* uPriority */
723 PACKI(desc,"W",0); /* uStarttime */
724 PACKI(desc,"W",0); /* uUntiltime */
725 PACKI(desc,"W",5); /* pad1 */
726 PACKS(desc,"z",""); /* pszSepFile */
727 PACKS(desc,"z","WinPrint"); /* pszPrProc */
728 PACKS(desc,"z",NULL); /* pszParms */
729 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
730 /* "don't ask" that it's done this way to fix corrupted
731 Win9X/ME printer comments. */
732 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
733 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
734 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
735 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
736 PackDriverData(desc); /* pDriverData */
739 if (uLevel == 2 || uLevel == 4) {
740 int i;
741 for (i = 0; i < count; i++) {
742 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
746 if (uLevel==52)
747 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
750 /* This function returns the number of files for a given driver */
751 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
753 int result = 0;
755 /* count the number of files */
756 while (driver->dependent_files && *driver->dependent_files[result])
757 result++;
759 return result;
762 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
763 connection_struct *conn, uint64_t vuid,
764 char *param, int tpscnt,
765 char *data, int tdscnt,
766 int mdrcnt,int mprcnt,
767 char **rdata,char **rparam,
768 int *rdata_len,int *rparam_len)
770 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
771 char *str2 = skip_string(param,tpscnt,str1);
772 char *p = skip_string(param,tpscnt,str2);
773 char *QueueName = p;
774 unsigned int uLevel;
775 uint32_t count = 0;
776 char *str3;
777 struct pack_desc desc;
778 char* tmpdata=NULL;
780 WERROR werr = WERR_OK;
781 TALLOC_CTX *mem_ctx = talloc_tos();
782 NTSTATUS status;
783 struct rpc_pipe_client *cli = NULL;
784 struct dcerpc_binding_handle *b = NULL;
785 struct policy_handle handle;
786 struct spoolss_DevmodeContainer devmode_ctr;
787 union spoolss_DriverInfo driver_info;
788 union spoolss_JobInfo *job_info = NULL;
789 union spoolss_PrinterInfo printer_info;
791 if (!str1 || !str2 || !p) {
792 return False;
794 memset((char *)&desc,'\0',sizeof(desc));
796 p = skip_string(param,tpscnt,p);
797 if (!p) {
798 return False;
800 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
801 str3 = get_safe_str_ptr(param,tpscnt,p,4);
802 /* str3 may be null here and is checked in check_printq_info(). */
804 /* remove any trailing username */
805 if ((p = strchr_m(QueueName,'%')))
806 *p = 0;
808 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
810 /* check it's a supported varient */
811 if (!prefix_ok(str1,"zWrLh"))
812 return False;
813 if (!check_printq_info(&desc,uLevel,str2,str3)) {
815 * Patch from Scott Moomaw <scott@bridgewater.edu>
816 * to return the 'invalid info level' error if an
817 * unknown level was requested.
819 *rdata_len = 0;
820 *rparam_len = 6;
821 *rparam = smb_realloc_limit(*rparam,*rparam_len);
822 if (!*rparam) {
823 return False;
825 SSVALS(*rparam,0,ERRunknownlevel);
826 SSVAL(*rparam,2,0);
827 SSVAL(*rparam,4,0);
828 return(True);
831 ZERO_STRUCT(handle);
833 if (QueueName == NULL || (strlen(QueueName) < 1)) {
834 desc.errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
835 goto out;
838 status = rpc_pipe_open_interface(mem_ctx,
839 &ndr_table_spoolss,
840 conn->session_info,
841 conn->sconn->remote_address,
842 conn->sconn->local_address,
843 conn->sconn->msg_ctx,
844 &cli);
845 if (!NT_STATUS_IS_OK(status)) {
846 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
847 nt_errstr(status)));
848 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
849 goto out;
851 b = cli->binding_handle;
853 ZERO_STRUCT(devmode_ctr);
855 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
856 QueueName,
857 "RAW",
858 devmode_ctr,
859 PRINTER_ACCESS_USE,
860 &handle,
861 &werr);
862 if (!NT_STATUS_IS_OK(status)) {
863 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
864 goto out;
866 if (!W_ERROR_IS_OK(werr)) {
867 desc.errcode = W_ERROR_V(werr);
868 goto out;
871 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
872 &handle,
875 &printer_info);
876 if (!W_ERROR_IS_OK(werr)) {
877 desc.errcode = W_ERROR_V(werr);
878 goto out;
881 if (uLevel==52) {
882 uint32_t server_major_version;
883 uint32_t server_minor_version;
885 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
886 &handle,
887 "Windows 4.0",
888 3, /* level */
890 0, /* version */
892 &driver_info,
893 &server_major_version,
894 &server_minor_version);
895 if (!W_ERROR_IS_OK(werr)) {
896 desc.errcode = W_ERROR_V(werr);
897 goto out;
900 count = get_printerdrivernumber(&driver_info.info3);
901 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
902 } else {
903 uint32_t num_jobs;
904 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
905 &handle,
906 0, /* firstjob */
907 0xff, /* numjobs */
908 2, /* level */
909 0, /* offered */
910 &num_jobs,
911 &job_info);
912 if (!W_ERROR_IS_OK(werr)) {
913 desc.errcode = W_ERROR_V(werr);
914 goto out;
917 count = num_jobs;
920 if (mdrcnt > 0) {
921 *rdata = smb_realloc_limit(*rdata,mdrcnt);
922 if (!*rdata) {
923 return False;
925 desc.base = *rdata;
926 desc.buflen = mdrcnt;
927 } else {
929 * Don't return data but need to get correct length
930 * init_package will return wrong size if buflen=0
932 desc.buflen = getlen(desc.format);
933 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
936 if (init_package(&desc,1,count)) {
937 desc.subcount = count;
938 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
941 *rdata_len = desc.usedlen;
944 * We must set the return code to ERRbuftoosmall
945 * in order to support lanman style printing with Win NT/2k
946 * clients --jerry
948 if (!mdrcnt && lp_disable_spoolss())
949 desc.errcode = ERRbuftoosmall;
951 out:
952 if (b && is_valid_policy_hnd(&handle)) {
953 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
956 *rdata_len = desc.usedlen;
957 *rparam_len = 6;
958 *rparam = smb_realloc_limit(*rparam,*rparam_len);
959 if (!*rparam) {
960 SAFE_FREE(tmpdata);
961 return False;
963 SSVALS(*rparam,0,desc.errcode);
964 SSVAL(*rparam,2,0);
965 SSVAL(*rparam,4,desc.neededlen);
967 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
969 SAFE_FREE(tmpdata);
971 return(True);
974 /****************************************************************************
975 View list of all print jobs on all queues.
976 ****************************************************************************/
978 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
979 connection_struct *conn, uint64_t vuid,
980 char *param, int tpscnt,
981 char *data, int tdscnt,
982 int mdrcnt, int mprcnt,
983 char **rdata, char** rparam,
984 int *rdata_len, int *rparam_len)
986 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
987 char *output_format1 = skip_string(param,tpscnt,param_format);
988 char *p = skip_string(param,tpscnt,output_format1);
989 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
990 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
991 int i;
992 struct pack_desc desc;
993 int *subcntarr = NULL;
994 int queuecnt = 0, subcnt = 0, succnt = 0;
996 WERROR werr = WERR_OK;
997 TALLOC_CTX *mem_ctx = talloc_tos();
998 NTSTATUS status;
999 struct rpc_pipe_client *cli = NULL;
1000 struct dcerpc_binding_handle *b = NULL;
1001 struct spoolss_DevmodeContainer devmode_ctr;
1002 uint32_t num_printers;
1003 union spoolss_PrinterInfo *printer_info;
1004 union spoolss_DriverInfo *driver_info;
1005 union spoolss_JobInfo **job_info;
1007 if (!param_format || !output_format1 || !p) {
1008 return False;
1011 memset((char *)&desc,'\0',sizeof(desc));
1013 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1015 if (!prefix_ok(param_format,"WrLeh")) {
1016 return False;
1018 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1020 * Patch from Scott Moomaw <scott@bridgewater.edu>
1021 * to return the 'invalid info level' error if an
1022 * unknown level was requested.
1024 *rdata_len = 0;
1025 *rparam_len = 6;
1026 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1027 if (!*rparam) {
1028 return False;
1030 SSVALS(*rparam,0,ERRunknownlevel);
1031 SSVAL(*rparam,2,0);
1032 SSVAL(*rparam,4,0);
1033 return(True);
1036 status = rpc_pipe_open_interface(mem_ctx,
1037 &ndr_table_spoolss,
1038 conn->session_info,
1039 conn->sconn->remote_address,
1040 conn->sconn->local_address,
1041 conn->sconn->msg_ctx,
1042 &cli);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1045 nt_errstr(status)));
1046 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1047 goto out;
1049 b = cli->binding_handle;
1051 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1052 PRINTER_ENUM_LOCAL,
1053 cli->srv_name_slash,
1056 &num_printers,
1057 &printer_info);
1058 if (!W_ERROR_IS_OK(werr)) {
1059 desc.errcode = W_ERROR_V(werr);
1060 goto out;
1063 queuecnt = num_printers;
1065 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1066 if (job_info == NULL) {
1067 goto err;
1070 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1071 if (driver_info == NULL) {
1072 goto err;
1075 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1076 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1077 goto err;
1080 if (mdrcnt > 0) {
1081 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1082 if (!*rdata) {
1083 goto err;
1086 desc.base = *rdata;
1087 desc.buflen = mdrcnt;
1089 subcnt = 0;
1090 for (i = 0; i < num_printers; i++) {
1092 uint32_t num_jobs;
1093 struct policy_handle handle;
1094 const char *printername;
1096 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1097 if (printername == NULL) {
1098 goto err;
1101 ZERO_STRUCT(handle);
1102 ZERO_STRUCT(devmode_ctr);
1104 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1105 printername,
1106 "RAW",
1107 devmode_ctr,
1108 PRINTER_ACCESS_USE,
1109 &handle,
1110 &werr);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1113 goto out;
1115 if (!W_ERROR_IS_OK(werr)) {
1116 desc.errcode = W_ERROR_V(werr);
1117 goto out;
1120 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1121 &handle,
1122 0, /* firstjob */
1123 0xff, /* numjobs */
1124 2, /* level */
1125 0, /* offered */
1126 &num_jobs,
1127 &job_info[i]);
1128 if (!W_ERROR_IS_OK(werr)) {
1129 desc.errcode = W_ERROR_V(werr);
1130 goto out;
1133 if (uLevel==52) {
1134 uint32_t server_major_version;
1135 uint32_t server_minor_version;
1137 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1138 &handle,
1139 "Windows 4.0",
1140 3, /* level */
1142 0, /* version */
1144 &driver_info[i],
1145 &server_major_version,
1146 &server_minor_version);
1147 if (!W_ERROR_IS_OK(werr)) {
1148 desc.errcode = W_ERROR_V(werr);
1149 goto out;
1153 subcntarr[i] = num_jobs;
1154 subcnt += subcntarr[i];
1156 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1159 if (init_package(&desc,queuecnt,subcnt)) {
1160 for (i = 0; i < num_printers; i++) {
1161 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1162 if (desc.errcode == NERR_Success) {
1163 succnt = i;
1168 out:
1169 SAFE_FREE(subcntarr);
1170 *rdata_len = desc.usedlen;
1171 *rparam_len = 8;
1172 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1173 if (!*rparam) {
1174 goto err;
1176 SSVALS(*rparam,0,desc.errcode);
1177 SSVAL(*rparam,2,0);
1178 SSVAL(*rparam,4,succnt);
1179 SSVAL(*rparam,6,queuecnt);
1181 return True;
1183 err:
1185 SAFE_FREE(subcntarr);
1187 return False;
1190 /****************************************************************************
1191 Get info level for a server list query.
1192 ****************************************************************************/
1194 static bool check_session_info(int uLevel, char* id)
1196 switch( uLevel ) {
1197 case 0:
1198 if (strcmp(id,"B16") != 0) {
1199 return False;
1201 break;
1202 case 1:
1203 if (strcmp(id,"B16BBDz") != 0) {
1204 return False;
1206 break;
1207 default:
1208 return False;
1210 return True;
1213 struct srv_info_struct {
1214 fstring name;
1215 uint32_t type;
1216 fstring comment;
1217 fstring domain;
1218 bool server_added;
1221 /*******************************************************************
1222 Get server info lists from the files saved by nmbd. Return the
1223 number of entries.
1224 ******************************************************************/
1226 static int get_session_info(uint32_t servertype,
1227 struct srv_info_struct **servers,
1228 const char *domain)
1230 int count=0;
1231 int alloced=0;
1232 char **lines;
1233 bool local_list_only;
1234 int i;
1235 char *slist_cache_path = cache_path(talloc_tos(), SERVER_LIST);
1236 if (slist_cache_path == NULL) {
1237 return 0;
1240 lines = file_lines_load(slist_cache_path, NULL, 0, NULL);
1241 if (!lines) {
1242 DEBUG(4, ("Can't open %s - %s\n",
1243 slist_cache_path, strerror(errno)));
1244 TALLOC_FREE(slist_cache_path);
1245 return 0;
1247 TALLOC_FREE(slist_cache_path);
1249 /* request for everything is code for request all servers */
1250 if (servertype == SV_TYPE_ALL) {
1251 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1254 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1256 DEBUG(4,("Servertype search: %8x\n",servertype));
1258 for (i=0;lines[i];i++) {
1259 fstring stype;
1260 struct srv_info_struct *s;
1261 const char *ptr = lines[i];
1262 bool ok = True;
1263 TALLOC_CTX *frame = NULL;
1264 char *p;
1266 if (!*ptr) {
1267 continue;
1270 if (count == alloced) {
1271 alloced += 10;
1272 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1273 if (!*servers) {
1274 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1275 TALLOC_FREE(lines);
1276 return 0;
1278 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1280 s = &(*servers)[count];
1282 frame = talloc_stackframe();
1283 s->name[0] = '\0';
1284 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1285 TALLOC_FREE(frame);
1286 continue;
1288 fstrcpy(s->name, p);
1290 stype[0] = '\0';
1291 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1292 TALLOC_FREE(frame);
1293 continue;
1295 fstrcpy(stype, p);
1297 s->comment[0] = '\0';
1298 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1299 TALLOC_FREE(frame);
1300 continue;
1302 fstrcpy(s->comment, p);
1303 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1305 s->domain[0] = '\0';
1306 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1307 /* this allows us to cope with an old nmbd */
1308 fstrcpy(s->domain,lp_workgroup());
1309 } else {
1310 fstrcpy(s->domain, p);
1312 TALLOC_FREE(frame);
1314 if (sscanf(stype,"%X",&s->type) != 1) {
1315 DEBUG(4,("r:host file "));
1316 ok = False;
1319 /* Filter the servers/domains we return based on what was asked for. */
1321 /* Check to see if we are being asked for a local list only. */
1322 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1323 DEBUG(4,("r: local list only"));
1324 ok = False;
1327 /* doesn't match up: don't want it */
1328 if (!(servertype & s->type)) {
1329 DEBUG(4,("r:serv type "));
1330 ok = False;
1333 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1334 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1335 DEBUG(4,("s: dom mismatch "));
1336 ok = False;
1339 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1340 ok = False;
1343 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1344 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1346 if (ok) {
1347 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1348 s->name, s->type, s->comment, s->domain));
1349 s->server_added = True;
1350 count++;
1351 } else {
1352 DEBUG(4,("%20s %8x %25s %15s\n",
1353 s->name, s->type, s->comment, s->domain));
1357 TALLOC_FREE(lines);
1358 return count;
1361 /*******************************************************************
1362 Fill in a server info structure.
1363 ******************************************************************/
1365 static int fill_srv_info(struct srv_info_struct *service,
1366 int uLevel, char **buf, int *buflen,
1367 char **stringbuf, int *stringspace, char *baseaddr)
1369 int struct_len;
1370 char* p;
1371 char* p2;
1372 int l2;
1373 int len;
1375 switch (uLevel) {
1376 case 0:
1377 struct_len = 16;
1378 break;
1379 case 1:
1380 struct_len = 26;
1381 break;
1382 default:
1383 return -1;
1386 if (!buf) {
1387 len = 0;
1388 switch (uLevel) {
1389 case 1:
1390 len = strlen(service->comment)+1;
1391 break;
1394 *buflen = struct_len;
1395 *stringspace = len;
1396 return struct_len + len;
1399 len = struct_len;
1400 p = *buf;
1401 if (*buflen < struct_len) {
1402 return -1;
1404 if (stringbuf) {
1405 p2 = *stringbuf;
1406 l2 = *stringspace;
1407 } else {
1408 p2 = p + struct_len;
1409 l2 = *buflen - struct_len;
1411 if (!baseaddr) {
1412 baseaddr = p;
1415 switch (uLevel) {
1416 case 0:
1417 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1418 break;
1420 case 1:
1421 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1422 SIVAL(p,18,service->type);
1423 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1424 len += CopyAndAdvance(&p2,service->comment,&l2);
1425 break;
1428 if (stringbuf) {
1429 *buf = p + struct_len;
1430 *buflen -= struct_len;
1431 *stringbuf = p2;
1432 *stringspace = l2;
1433 } else {
1434 *buf = p2;
1435 *buflen -= len;
1437 return len;
1441 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1443 return strcasecmp_m(s1->name,s2->name);
1446 /****************************************************************************
1447 View list of servers available (or possibly domains). The info is
1448 extracted from lists saved by nmbd on the local host.
1449 ****************************************************************************/
1451 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1452 connection_struct *conn, uint64_t vuid,
1453 char *param, int tpscnt,
1454 char *data, int tdscnt,
1455 int mdrcnt, int mprcnt, char **rdata,
1456 char **rparam, int *rdata_len, int *rparam_len)
1458 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1459 char *str2 = skip_string(param,tpscnt,str1);
1460 char *p = skip_string(param,tpscnt,str2);
1461 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1462 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1463 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1464 char *p2;
1465 int data_len, fixed_len, string_len;
1466 int f_len = 0, s_len = 0;
1467 struct srv_info_struct *servers=NULL;
1468 int counted=0,total=0;
1469 int i,missed;
1470 fstring domain;
1471 bool domain_request;
1472 bool local_request;
1474 if (!str1 || !str2 || !p) {
1475 return False;
1478 /* If someone sets all the bits they don't really mean to set
1479 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1480 known servers. */
1482 if (servertype == SV_TYPE_ALL) {
1483 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1486 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1487 any other bit (they may just set this bit on its own) they
1488 want all the locally seen servers. However this bit can be
1489 set on its own so set the requested servers to be
1490 ALL - DOMAIN_ENUM. */
1492 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1493 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1496 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1497 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1499 p += 8;
1501 if (!prefix_ok(str1,"WrLehD")) {
1502 return False;
1504 if (!check_session_info(uLevel,str2)) {
1505 return False;
1508 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1509 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1510 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1512 if (strcmp(str1, "WrLehDz") == 0) {
1513 if (skip_string(param,tpscnt,p) == NULL) {
1514 return False;
1516 pull_ascii_fstring(domain, p);
1517 } else {
1518 fstrcpy(domain, lp_workgroup());
1521 DEBUG(4, ("domain [%s]\n", domain));
1523 if (lp_browse_list()) {
1524 total = get_session_info(servertype,&servers,domain);
1527 data_len = fixed_len = string_len = 0;
1528 missed = 0;
1530 TYPESAFE_QSORT(servers, total, srv_comp);
1533 char *lastname=NULL;
1535 for (i=0;i<total;i++) {
1536 struct srv_info_struct *s = &servers[i];
1538 if (lastname && strequal(lastname,s->name)) {
1539 continue;
1541 lastname = s->name;
1542 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1543 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1544 i, s->name, s->type, s->comment, s->domain));
1546 if (data_len < buf_len) {
1547 counted++;
1548 fixed_len += f_len;
1549 string_len += s_len;
1550 } else {
1551 missed++;
1556 *rdata_len = fixed_len + string_len;
1557 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1558 if (!*rdata) {
1559 return False;
1562 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1563 p = *rdata;
1564 f_len = fixed_len;
1565 s_len = string_len;
1568 char *lastname=NULL;
1569 int count2 = counted;
1571 for (i = 0; i < total && count2;i++) {
1572 struct srv_info_struct *s = &servers[i];
1574 if (lastname && strequal(lastname,s->name)) {
1575 continue;
1577 lastname = s->name;
1578 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1579 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1580 i, s->name, s->type, s->comment, s->domain));
1581 count2--;
1585 *rparam_len = 8;
1586 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1587 if (!*rparam) {
1588 return False;
1590 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1591 SSVAL(*rparam,2,0);
1592 SSVAL(*rparam,4,counted);
1593 SSVAL(*rparam,6,counted+missed);
1595 SAFE_FREE(servers);
1597 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1598 domain,uLevel,counted,counted+missed));
1600 return True;
1603 static int srv_name_match(const char *n1, const char *n2)
1606 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1608 * In Windows, FirstNameToReturn need not be an exact match:
1609 * the server will return a list of servers that exist on
1610 * the network greater than or equal to the FirstNameToReturn.
1612 int ret = strcasecmp_m(n1, n2);
1614 if (ret <= 0) {
1615 return 0;
1618 return ret;
1621 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1622 connection_struct *conn, uint64_t vuid,
1623 char *param, int tpscnt,
1624 char *data, int tdscnt,
1625 int mdrcnt, int mprcnt, char **rdata,
1626 char **rparam, int *rdata_len, int *rparam_len)
1628 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1629 char *str2 = skip_string(param,tpscnt,str1);
1630 char *p = skip_string(param,tpscnt,str2);
1631 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1632 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1633 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1634 char *p2;
1635 int data_len, fixed_len, string_len;
1636 int f_len = 0, s_len = 0;
1637 struct srv_info_struct *servers=NULL;
1638 int counted=0,first=0,total=0;
1639 int i,missed;
1640 fstring domain;
1641 fstring first_name;
1642 bool domain_request;
1643 bool local_request;
1645 if (!str1 || !str2 || !p) {
1646 return False;
1649 /* If someone sets all the bits they don't really mean to set
1650 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1651 known servers. */
1653 if (servertype == SV_TYPE_ALL) {
1654 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1657 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1658 any other bit (they may just set this bit on its own) they
1659 want all the locally seen servers. However this bit can be
1660 set on its own so set the requested servers to be
1661 ALL - DOMAIN_ENUM. */
1663 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1664 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1667 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1668 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1670 p += 8;
1672 if (strcmp(str1, "WrLehDzz") != 0) {
1673 return false;
1675 if (!check_session_info(uLevel,str2)) {
1676 return False;
1679 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1680 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1681 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1683 if (skip_string(param,tpscnt,p) == NULL) {
1684 return False;
1686 pull_ascii_fstring(domain, p);
1687 if (domain[0] == '\0') {
1688 fstrcpy(domain, lp_workgroup());
1690 p = skip_string(param,tpscnt,p);
1691 if (skip_string(param,tpscnt,p) == NULL) {
1692 return False;
1694 pull_ascii_fstring(first_name, p);
1696 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1697 domain, first_name));
1699 if (lp_browse_list()) {
1700 total = get_session_info(servertype,&servers,domain);
1703 data_len = fixed_len = string_len = 0;
1704 missed = 0;
1706 TYPESAFE_QSORT(servers, total, srv_comp);
1708 if (first_name[0] != '\0') {
1709 struct srv_info_struct *first_server = NULL;
1711 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1712 srv_name_match, first_server);
1713 if (first_server) {
1714 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1716 * The binary search may not find the exact match
1717 * so we need to search backward to find the first match
1719 * This implements the strange matching windows
1720 * implements. (see the comment in srv_name_match().
1722 for (;first > 0;) {
1723 int ret;
1724 ret = strcasecmp_m(first_name,
1725 servers[first-1].name);
1726 if (ret > 0) {
1727 break;
1729 first--;
1731 } else {
1732 /* we should return no entries */
1733 first = total;
1738 char *lastname=NULL;
1740 for (i=first;i<total;i++) {
1741 struct srv_info_struct *s = &servers[i];
1743 if (lastname && strequal(lastname,s->name)) {
1744 continue;
1746 lastname = s->name;
1747 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1748 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1749 i, s->name, s->type, s->comment, s->domain));
1751 if (data_len < buf_len) {
1752 counted++;
1753 fixed_len += f_len;
1754 string_len += s_len;
1755 } else {
1756 missed++;
1761 *rdata_len = fixed_len + string_len;
1762 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1763 if (!*rdata) {
1764 return False;
1767 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1768 p = *rdata;
1769 f_len = fixed_len;
1770 s_len = string_len;
1773 char *lastname=NULL;
1774 int count2 = counted;
1776 for (i = first; i < total && count2;i++) {
1777 struct srv_info_struct *s = &servers[i];
1779 if (lastname && strequal(lastname,s->name)) {
1780 continue;
1782 lastname = s->name;
1783 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1784 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1785 i, s->name, s->type, s->comment, s->domain));
1786 count2--;
1790 *rparam_len = 8;
1791 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1792 if (!*rparam) {
1793 return False;
1795 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1796 SSVAL(*rparam,2,0);
1797 SSVAL(*rparam,4,counted);
1798 SSVAL(*rparam,6,counted+missed);
1800 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1801 domain,uLevel,first,first_name,
1802 first < total ? servers[first].name : "",
1803 counted,counted+missed));
1805 SAFE_FREE(servers);
1807 return True;
1810 /****************************************************************************
1811 command 0x34 - suspected of being a "Lookup Names" stub api
1812 ****************************************************************************/
1814 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1815 connection_struct *conn, uint64_t vuid,
1816 char *param, int tpscnt,
1817 char *data, int tdscnt,
1818 int mdrcnt, int mprcnt, char **rdata,
1819 char **rparam, int *rdata_len, int *rparam_len)
1821 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1822 char *str2 = skip_string(param,tpscnt,str1);
1823 char *p = skip_string(param,tpscnt,str2);
1824 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1825 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1826 int counted=0;
1827 int missed=0;
1829 if (!str1 || !str2 || !p) {
1830 return False;
1833 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1834 str1, str2, p, uLevel, buf_len));
1836 if (!prefix_ok(str1,"zWrLeh")) {
1837 return False;
1840 *rdata_len = 0;
1842 *rparam_len = 8;
1843 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1844 if (!*rparam) {
1845 return False;
1848 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1849 SSVAL(*rparam,2,0);
1850 SSVAL(*rparam,4,counted);
1851 SSVAL(*rparam,6,counted+missed);
1853 return True;
1856 /****************************************************************************
1857 get info about a share
1858 ****************************************************************************/
1860 static bool check_share_info(int uLevel, char* id)
1862 switch( uLevel ) {
1863 case 0:
1864 if (strcmp(id,"B13") != 0) {
1865 return False;
1867 break;
1868 case 1:
1869 /* Level-2 descriptor is allowed (and ignored) */
1870 if (strcmp(id,"B13BWz") != 0 &&
1871 strcmp(id,"B13BWzWWWzB9B") != 0) {
1872 return False;
1874 break;
1875 case 2:
1876 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1877 return False;
1879 break;
1880 case 91:
1881 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1882 return False;
1884 break;
1885 default:
1886 return False;
1888 return True;
1891 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1892 char** buf, int* buflen,
1893 char** stringbuf, int* stringspace, char* baseaddr)
1895 const struct loadparm_substitution *lp_sub =
1896 loadparm_s3_global_substitution();
1897 int struct_len;
1898 char* p;
1899 char* p2;
1900 int l2;
1901 int len;
1903 switch( uLevel ) {
1904 case 0:
1905 struct_len = 13;
1906 break;
1907 case 1:
1908 struct_len = 20;
1909 break;
1910 case 2:
1911 struct_len = 40;
1912 break;
1913 case 91:
1914 struct_len = 68;
1915 break;
1916 default:
1917 return -1;
1920 if (!buf) {
1921 len = 0;
1923 if (uLevel > 0) {
1924 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), lp_sub, snum));
1926 if (uLevel > 1) {
1927 len += strlen(lp_path(talloc_tos(), lp_sub, snum)) + 1;
1929 if (buflen) {
1930 *buflen = struct_len;
1932 if (stringspace) {
1933 *stringspace = len;
1935 return struct_len + len;
1938 len = struct_len;
1939 p = *buf;
1940 if ((*buflen) < struct_len) {
1941 return -1;
1944 if (stringbuf) {
1945 p2 = *stringbuf;
1946 l2 = *stringspace;
1947 } else {
1948 p2 = p + struct_len;
1949 l2 = (*buflen) - struct_len;
1952 if (!baseaddr) {
1953 baseaddr = p;
1956 push_ascii(p,lp_servicename(talloc_tos(), lp_sub, snum),13, STR_TERMINATE);
1958 if (uLevel > 0) {
1959 int type;
1961 SCVAL(p,13,0);
1962 type = STYPE_DISKTREE;
1963 if (lp_printable(snum)) {
1964 type = STYPE_PRINTQ;
1966 if (strequal("IPC",lp_fstype(snum))) {
1967 type = STYPE_IPC;
1969 SSVAL(p,14,type); /* device type */
1970 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1971 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(), lp_sub, snum),&l2);
1974 if (uLevel > 1) {
1975 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1976 SSVALS(p,22,-1); /* max uses */
1977 SSVAL(p,24,1); /* current uses */
1978 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1979 len += CopyAndAdvance(&p2,lp_path(talloc_tos(),lp_sub, snum),&l2);
1980 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1983 if (uLevel > 2) {
1984 memset(p+40,0,SHPWLEN+2);
1985 SSVAL(p,50,0);
1986 SIVAL(p,52,0);
1987 SSVAL(p,56,0);
1988 SSVAL(p,58,0);
1989 SIVAL(p,60,0);
1990 SSVAL(p,64,0);
1991 SSVAL(p,66,0);
1994 if (stringbuf) {
1995 (*buf) = p + struct_len;
1996 (*buflen) -= struct_len;
1997 (*stringbuf) = p2;
1998 (*stringspace) = l2;
1999 } else {
2000 (*buf) = p2;
2001 (*buflen) -= len;
2004 return len;
2007 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
2008 connection_struct *conn,uint64_t vuid,
2009 char *param, int tpscnt,
2010 char *data, int tdscnt,
2011 int mdrcnt,int mprcnt,
2012 char **rdata,char **rparam,
2013 int *rdata_len,int *rparam_len)
2015 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2016 char *str2 = skip_string(param,tpscnt,str1);
2017 char *netname_in = skip_string(param,tpscnt,str2);
2018 char *netname = NULL;
2019 char *p = skip_string(param,tpscnt,netname);
2020 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2021 int snum;
2023 if (!str1 || !str2 || !netname_in || !p) {
2024 return False;
2027 snum = find_service(talloc_tos(), netname_in, &netname);
2028 if (snum < 0 || !netname) {
2029 return False;
2032 /* check it's a supported varient */
2033 if (!prefix_ok(str1,"zWrLh")) {
2034 return False;
2036 if (!check_share_info(uLevel,str2)) {
2037 return False;
2040 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2041 if (!*rdata) {
2042 return False;
2044 p = *rdata;
2045 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2046 if (*rdata_len < 0) {
2047 return False;
2050 *rparam_len = 6;
2051 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2052 if (!*rparam) {
2053 return False;
2055 SSVAL(*rparam,0,NERR_Success);
2056 SSVAL(*rparam,2,0); /* converter word */
2057 SSVAL(*rparam,4,*rdata_len);
2059 return True;
2062 /****************************************************************************
2063 View the list of available shares.
2065 This function is the server side of the NetShareEnum() RAP call.
2066 It fills the return buffer with share names and share comments.
2067 Note that the return buffer normally (in all known cases) allows only
2068 twelve byte strings for share names (plus one for a nul terminator).
2069 Share names longer than 12 bytes must be skipped.
2070 ****************************************************************************/
2072 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2073 connection_struct *conn, uint64_t vuid,
2074 char *param, int tpscnt,
2075 char *data, int tdscnt,
2076 int mdrcnt,
2077 int mprcnt,
2078 char **rdata,
2079 char **rparam,
2080 int *rdata_len,
2081 int *rparam_len )
2083 const struct loadparm_substitution *lp_sub =
2084 loadparm_s3_global_substitution();
2085 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2086 char *str2 = skip_string(param,tpscnt,str1);
2087 char *p = skip_string(param,tpscnt,str2);
2088 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2089 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2090 char *p2;
2091 int count = 0;
2092 int total=0,counted=0;
2093 bool missed = False;
2094 int i;
2095 int data_len, fixed_len, string_len;
2096 int f_len = 0, s_len = 0;
2098 if (!str1 || !str2 || !p) {
2099 return False;
2102 if (!prefix_ok(str1,"WrLeh")) {
2103 return False;
2105 if (!check_share_info(uLevel,str2)) {
2106 return False;
2109 /* Ensure all the usershares are loaded. */
2110 become_root();
2111 delete_and_reload_printers();
2112 load_registry_shares();
2113 count = load_usershare_shares(NULL, connections_snum_used);
2114 unbecome_root();
2116 data_len = fixed_len = string_len = 0;
2117 for (i=0;i<count;i++) {
2118 fstring servicename_dos;
2119 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2120 continue;
2122 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), lp_sub, i));
2123 /* Maximum name length = 13. */
2124 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2125 total++;
2126 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2127 if (data_len < buf_len) {
2128 counted++;
2129 fixed_len += f_len;
2130 string_len += s_len;
2131 } else {
2132 missed = True;
2137 *rdata_len = fixed_len + string_len;
2138 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2139 if (!*rdata) {
2140 return False;
2143 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2144 p = *rdata;
2145 f_len = fixed_len;
2146 s_len = string_len;
2148 for( i = 0; i < count; i++ ) {
2149 fstring servicename_dos;
2150 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2151 continue;
2154 push_ascii_fstring(servicename_dos,
2155 lp_servicename(talloc_tos(), lp_sub, i));
2156 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2157 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2158 break;
2163 *rparam_len = 8;
2164 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2165 if (!*rparam) {
2166 return False;
2168 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2169 SSVAL(*rparam,2,0);
2170 SSVAL(*rparam,4,counted);
2171 SSVAL(*rparam,6,total);
2173 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2174 counted,total,uLevel,
2175 buf_len,*rdata_len,mdrcnt));
2177 return True;
2180 /****************************************************************************
2181 Add a share
2182 ****************************************************************************/
2184 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2185 connection_struct *conn,uint64_t vuid,
2186 char *param, int tpscnt,
2187 char *data, int tdscnt,
2188 int mdrcnt,int mprcnt,
2189 char **rdata,char **rparam,
2190 int *rdata_len,int *rparam_len)
2192 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2193 char *str2 = skip_string(param,tpscnt,str1);
2194 char *p = skip_string(param,tpscnt,str2);
2195 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2196 fstring sharename;
2197 fstring comment;
2198 char *pathname = NULL;
2199 unsigned int offset;
2200 int res = ERRunsup;
2201 size_t converted_size;
2203 WERROR werr = WERR_OK;
2204 TALLOC_CTX *mem_ctx = talloc_tos();
2205 NTSTATUS status;
2206 struct rpc_pipe_client *cli = NULL;
2207 union srvsvc_NetShareInfo info;
2208 struct srvsvc_NetShareInfo2 info2;
2209 struct dcerpc_binding_handle *b;
2211 if (!str1 || !str2 || !p) {
2212 return False;
2215 /* check it's a supported varient */
2216 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2217 return False;
2219 if (!check_share_info(uLevel,str2)) {
2220 return False;
2222 if (uLevel != 2) {
2223 return False;
2226 /* Do we have a string ? */
2227 if (skip_string(data,mdrcnt,data) == NULL) {
2228 return False;
2230 pull_ascii_fstring(sharename,data);
2232 if (mdrcnt < 28) {
2233 return False;
2236 /* only support disk share adds */
2237 if (SVAL(data,14)!=STYPE_DISKTREE) {
2238 return False;
2241 offset = IVAL(data, 16);
2242 if (offset >= mdrcnt) {
2243 res = ERRinvalidparam;
2244 goto out;
2247 /* Do we have a string ? */
2248 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2249 return False;
2251 pull_ascii_fstring(comment, offset? (data+offset) : "");
2253 offset = IVAL(data, 26);
2255 if (offset >= mdrcnt) {
2256 res = ERRinvalidparam;
2257 goto out;
2260 /* Do we have a string ? */
2261 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2262 return False;
2265 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2266 offset ? (data+offset) : "", &converted_size))
2268 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2269 strerror(errno)));
2272 if (!pathname) {
2273 return false;
2276 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
2277 conn->session_info,
2278 conn->sconn->remote_address,
2279 conn->sconn->local_address,
2280 conn->sconn->msg_ctx,
2281 &cli);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2284 nt_errstr(status)));
2285 res = W_ERROR_V(ntstatus_to_werror(status));
2286 goto out;
2289 b = cli->binding_handle;
2291 info2.name = sharename;
2292 info2.type = STYPE_DISKTREE;
2293 info2.comment = comment;
2294 info2.permissions = 0;
2295 info2.max_users = 0;
2296 info2.current_users = 0;
2297 info2.path = pathname;
2298 info2.password = NULL;
2300 info.info2 = &info2;
2302 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2303 cli->srv_name_slash,
2305 &info,
2306 NULL,
2307 &werr);
2308 if (!NT_STATUS_IS_OK(status)) {
2309 res = W_ERROR_V(ntstatus_to_werror(status));
2310 goto out;
2312 if (!W_ERROR_IS_OK(werr)) {
2313 res = W_ERROR_V(werr);
2314 goto out;
2317 *rparam_len = 6;
2318 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2319 if (!*rparam) {
2320 return False;
2322 SSVAL(*rparam,0,NERR_Success);
2323 SSVAL(*rparam,2,0); /* converter word */
2324 SSVAL(*rparam,4,*rdata_len);
2325 *rdata_len = 0;
2327 return True;
2329 out:
2331 *rparam_len = 4;
2332 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2333 if (!*rparam) {
2334 return False;
2336 *rdata_len = 0;
2337 SSVAL(*rparam,0,res);
2338 SSVAL(*rparam,2,0);
2339 return True;
2342 /****************************************************************************
2343 view list of groups available
2344 ****************************************************************************/
2346 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2347 connection_struct *conn,uint64_t vuid,
2348 char *param, int tpscnt,
2349 char *data, int tdscnt,
2350 int mdrcnt,int mprcnt,
2351 char **rdata,char **rparam,
2352 int *rdata_len,int *rparam_len)
2354 int i;
2355 int errflags=0;
2356 int resume_context, cli_buf_size;
2357 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2358 char *str2 = skip_string(param,tpscnt,str1);
2359 char *p = skip_string(param,tpscnt,str2);
2361 uint32_t num_groups;
2362 uint32_t resume_handle;
2363 struct rpc_pipe_client *samr_pipe = NULL;
2364 struct policy_handle samr_handle, domain_handle;
2365 NTSTATUS status, result;
2366 struct dcerpc_binding_handle *b;
2368 if (!str1 || !str2 || !p) {
2369 return False;
2372 if (strcmp(str1,"WrLeh") != 0) {
2373 return False;
2376 /* parameters
2377 * W-> resume context (number of users to skip)
2378 * r -> return parameter pointer to receive buffer
2379 * L -> length of receive buffer
2380 * e -> return parameter number of entries
2381 * h -> return parameter total number of users
2384 if (strcmp("B21",str2) != 0) {
2385 return False;
2388 status = rpc_pipe_open_interface(
2389 talloc_tos(), &ndr_table_samr,
2390 conn->session_info, conn->sconn->remote_address,
2391 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2392 if (!NT_STATUS_IS_OK(status)) {
2393 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2394 nt_errstr(status)));
2395 return false;
2398 b = samr_pipe->binding_handle;
2400 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2401 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2402 &result);
2403 if (!NT_STATUS_IS_OK(status)) {
2404 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2405 nt_errstr(status)));
2406 return false;
2408 if (!NT_STATUS_IS_OK(result)) {
2409 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2410 nt_errstr(result)));
2411 return false;
2414 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2415 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2416 get_global_sam_sid(), &domain_handle,
2417 &result);
2418 if (!NT_STATUS_IS_OK(status)) {
2419 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2420 nt_errstr(status)));
2421 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2422 return false;
2424 if (!NT_STATUS_IS_OK(result)) {
2425 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2426 nt_errstr(result)));
2427 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2428 return false;
2431 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2432 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2433 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2434 "%d\n", resume_context, cli_buf_size));
2436 *rdata_len = cli_buf_size;
2437 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2438 if (!*rdata) {
2439 return False;
2442 p = *rdata;
2444 errflags = NERR_Success;
2445 num_groups = 0;
2446 resume_handle = 0;
2448 while (true) {
2449 struct samr_SamArray *sam_entries;
2450 uint32_t num_entries;
2452 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2453 &domain_handle,
2454 &resume_handle,
2455 &sam_entries, 1,
2456 &num_entries,
2457 &result);
2458 if (!NT_STATUS_IS_OK(status)) {
2459 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2460 "%s\n", nt_errstr(status)));
2461 break;
2463 if (!NT_STATUS_IS_OK(result)) {
2464 status = result;
2465 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2466 "%s\n", nt_errstr(result)));
2467 break;
2470 if (num_entries == 0) {
2471 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2472 "no entries -- done\n"));
2473 break;
2476 for(i=0; i<num_entries; i++) {
2477 const char *name;
2479 name = sam_entries->entries[i].name.string;
2481 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2482 /* set overflow error */
2483 DEBUG(3,("overflow on entry %d group %s\n", i,
2484 name));
2485 errflags=234;
2486 break;
2489 /* truncate the name at 21 chars. */
2490 memset(p, 0, 21);
2491 strlcpy(p, name, 21);
2492 DEBUG(10,("adding entry %d group %s\n", i, p));
2493 p += 21;
2494 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2495 * idea why... */
2496 num_groups += 1;
2499 if (errflags != NERR_Success) {
2500 break;
2503 TALLOC_FREE(sam_entries);
2506 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2507 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2509 *rdata_len = PTR_DIFF(p,*rdata);
2511 *rparam_len = 8;
2512 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2513 if (!*rparam) {
2514 return False;
2516 SSVAL(*rparam, 0, errflags);
2517 SSVAL(*rparam, 2, 0); /* converter word */
2518 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2519 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2521 return(True);
2524 /*******************************************************************
2525 Get groups that a user is a member of.
2526 ******************************************************************/
2528 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2529 connection_struct *conn,uint64_t vuid,
2530 char *param, int tpscnt,
2531 char *data, int tdscnt,
2532 int mdrcnt,int mprcnt,
2533 char **rdata,char **rparam,
2534 int *rdata_len,int *rparam_len)
2536 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2537 char *str2 = skip_string(param,tpscnt,str1);
2538 char *UserName = skip_string(param,tpscnt,str2);
2539 char *p = skip_string(param,tpscnt,UserName);
2540 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2541 const char *level_string;
2542 int count=0;
2543 bool ret = False;
2544 uint32_t i;
2545 char *endp = NULL;
2547 struct rpc_pipe_client *samr_pipe = NULL;
2548 struct policy_handle samr_handle, domain_handle, user_handle;
2549 struct lsa_String name;
2550 struct lsa_Strings names;
2551 struct samr_Ids type, rid;
2552 struct samr_RidWithAttributeArray *rids;
2553 NTSTATUS status, result;
2554 struct dcerpc_binding_handle *b;
2556 if (!str1 || !str2 || !UserName || !p) {
2557 return False;
2560 *rparam_len = 8;
2561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2562 if (!*rparam) {
2563 return False;
2566 /* check it's a supported varient */
2568 if ( strcmp(str1,"zWrLeh") != 0 )
2569 return False;
2571 switch( uLevel ) {
2572 case 0:
2573 level_string = "B21";
2574 break;
2575 default:
2576 return False;
2579 if (strcmp(level_string,str2) != 0)
2580 return False;
2582 *rdata_len = mdrcnt + 1024;
2583 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2584 if (!*rdata) {
2585 return False;
2588 SSVAL(*rparam,0,NERR_Success);
2589 SSVAL(*rparam,2,0); /* converter word */
2591 p = *rdata;
2592 endp = *rdata + *rdata_len;
2594 status = rpc_pipe_open_interface(
2595 talloc_tos(), &ndr_table_samr,
2596 conn->session_info, conn->sconn->remote_address,
2597 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2598 if (!NT_STATUS_IS_OK(status)) {
2599 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2600 nt_errstr(status)));
2601 return false;
2604 b = samr_pipe->binding_handle;
2606 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2607 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2608 &result);
2609 if (!NT_STATUS_IS_OK(status)) {
2610 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2611 nt_errstr(status)));
2612 return false;
2614 if (!NT_STATUS_IS_OK(result)) {
2615 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2616 nt_errstr(result)));
2617 return false;
2620 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2621 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2622 get_global_sam_sid(), &domain_handle,
2623 &result);
2624 if (!NT_STATUS_IS_OK(status)) {
2625 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2626 nt_errstr(status)));
2627 goto close_sam;
2629 if (!NT_STATUS_IS_OK(result)) {
2630 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2631 nt_errstr(result)));
2632 goto close_sam;
2635 name.string = UserName;
2637 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2638 &domain_handle, 1, &name,
2639 &rid, &type,
2640 &result);
2641 if (!NT_STATUS_IS_OK(status)) {
2642 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2643 nt_errstr(status)));
2644 goto close_domain;
2646 if (!NT_STATUS_IS_OK(result)) {
2647 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2648 nt_errstr(result)));
2649 goto close_domain;
2651 if (rid.count != 1) {
2652 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2653 goto close_domain;
2655 if (type.count != 1) {
2656 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2657 goto close_domain;
2660 if (type.ids[0] != SID_NAME_USER) {
2661 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2662 sid_type_lookup(type.ids[0])));
2663 goto close_domain;
2666 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2667 &domain_handle,
2668 SAMR_USER_ACCESS_GET_GROUPS,
2669 rid.ids[0], &user_handle,
2670 &result);
2671 if (!NT_STATUS_IS_OK(status)) {
2672 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2673 nt_errstr(status)));
2674 goto close_domain;
2676 if (!NT_STATUS_IS_OK(result)) {
2677 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2678 nt_errstr(result)));
2679 goto close_domain;
2682 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2683 &user_handle, &rids,
2684 &result);
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2687 nt_errstr(status)));
2688 goto close_user;
2690 if (!NT_STATUS_IS_OK(result)) {
2691 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2692 nt_errstr(result)));
2693 goto close_user;
2696 for (i=0; i<rids->count; i++) {
2698 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2699 &domain_handle,
2700 1, &rids->rids[i].rid,
2701 &names, &type,
2702 &result);
2703 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2704 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2705 p += 21;
2706 count++;
2710 *rdata_len = PTR_DIFF(p,*rdata);
2712 SSVAL(*rparam,4,count); /* is this right?? */
2713 SSVAL(*rparam,6,count); /* is this right?? */
2715 ret = True;
2717 close_user:
2718 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2719 close_domain:
2720 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2721 close_sam:
2722 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2724 return ret;
2727 /*******************************************************************
2728 Get all users.
2729 ******************************************************************/
2731 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2732 connection_struct *conn, uint64_t vuid,
2733 char *param, int tpscnt,
2734 char *data, int tdscnt,
2735 int mdrcnt,int mprcnt,
2736 char **rdata,char **rparam,
2737 int *rdata_len,int *rparam_len)
2739 int count_sent=0;
2740 int num_users=0;
2741 int errflags=0;
2742 int i, resume_context, cli_buf_size;
2743 uint32_t resume_handle;
2745 struct rpc_pipe_client *samr_pipe = NULL;
2746 struct policy_handle samr_handle, domain_handle;
2747 NTSTATUS status, result;
2749 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2750 char *str2 = skip_string(param,tpscnt,str1);
2751 char *p = skip_string(param,tpscnt,str2);
2752 char *endp = NULL;
2754 struct dcerpc_binding_handle *b;
2756 if (!str1 || !str2 || !p) {
2757 return False;
2760 if (strcmp(str1,"WrLeh") != 0)
2761 return False;
2762 /* parameters
2763 * W-> resume context (number of users to skip)
2764 * r -> return parameter pointer to receive buffer
2765 * L -> length of receive buffer
2766 * e -> return parameter number of entries
2767 * h -> return parameter total number of users
2770 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2771 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2772 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2773 resume_context, cli_buf_size));
2775 *rparam_len = 8;
2776 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2777 if (!*rparam) {
2778 return False;
2781 /* check it's a supported varient */
2782 if (strcmp("B21",str2) != 0)
2783 return False;
2785 *rdata_len = cli_buf_size;
2786 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2787 if (!*rdata) {
2788 return False;
2791 p = *rdata;
2792 endp = *rdata + *rdata_len;
2794 status = rpc_pipe_open_interface(
2795 talloc_tos(), &ndr_table_samr,
2796 conn->session_info, conn->sconn->remote_address,
2797 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2798 if (!NT_STATUS_IS_OK(status)) {
2799 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2800 nt_errstr(status)));
2801 return false;
2804 b = samr_pipe->binding_handle;
2806 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2807 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2808 &result);
2809 if (!NT_STATUS_IS_OK(status)) {
2810 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2811 nt_errstr(status)));
2812 return false;
2814 if (!NT_STATUS_IS_OK(result)) {
2815 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2816 nt_errstr(result)));
2817 return false;
2820 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2821 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2822 get_global_sam_sid(), &domain_handle,
2823 &result);
2824 if (!NT_STATUS_IS_OK(status)) {
2825 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2826 nt_errstr(status)));
2827 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2828 return false;
2830 if (!NT_STATUS_IS_OK(result)) {
2831 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2832 nt_errstr(result)));
2833 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2834 return false;
2837 errflags=NERR_Success;
2839 resume_handle = 0;
2841 while (true) {
2842 struct samr_SamArray *sam_entries;
2843 uint32_t num_entries;
2845 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2846 &domain_handle,
2847 &resume_handle,
2848 0, &sam_entries, 1,
2849 &num_entries,
2850 &result);
2852 if (!NT_STATUS_IS_OK(status)) {
2853 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2854 "%s\n", nt_errstr(status)));
2855 break;
2857 if (!NT_STATUS_IS_OK(result)) {
2858 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2859 "%s\n", nt_errstr(result)));
2860 break;
2863 if (num_entries == 0) {
2864 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2865 "no entries -- done\n"));
2866 break;
2869 for (i=0; i<num_entries; i++) {
2870 const char *name;
2872 name = sam_entries->entries[i].name.string;
2874 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2875 &&(strlen(name)<=21)) {
2876 strlcpy(p,name,PTR_DIFF(endp,p));
2877 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2878 "username %s\n",count_sent,p));
2879 p += 21;
2880 count_sent++;
2881 } else {
2882 /* set overflow error */
2883 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2884 "username %s\n",count_sent,name));
2885 errflags=234;
2886 break;
2890 if (errflags != NERR_Success) {
2891 break;
2894 TALLOC_FREE(sam_entries);
2897 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2898 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2900 *rdata_len = PTR_DIFF(p,*rdata);
2902 SSVAL(*rparam,0,errflags);
2903 SSVAL(*rparam,2,0); /* converter word */
2904 SSVAL(*rparam,4,count_sent); /* is this right?? */
2905 SSVAL(*rparam,6,num_users); /* is this right?? */
2907 return True;
2910 /****************************************************************************
2911 Get the time of day info.
2912 ****************************************************************************/
2914 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2915 connection_struct *conn,uint64_t vuid,
2916 char *param, int tpscnt,
2917 char *data, int tdscnt,
2918 int mdrcnt,int mprcnt,
2919 char **rdata,char **rparam,
2920 int *rdata_len,int *rparam_len)
2922 struct tm *t;
2923 time_t unixdate = time(NULL);
2924 char *p;
2926 *rparam_len = 4;
2927 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2928 if (!*rparam) {
2929 return False;
2932 *rdata_len = 21;
2933 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2934 if (!*rdata) {
2935 return False;
2938 SSVAL(*rparam,0,NERR_Success);
2939 SSVAL(*rparam,2,0); /* converter word */
2941 p = *rdata;
2943 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2944 by NT in a "net time" operation,
2945 it seems to ignore the one below */
2947 /* the client expects to get localtime, not GMT, in this bit
2948 (I think, this needs testing) */
2949 t = localtime(&unixdate);
2950 if (!t) {
2951 return False;
2954 SIVAL(p,4,0); /* msecs ? */
2955 SCVAL(p,8,t->tm_hour);
2956 SCVAL(p,9,t->tm_min);
2957 SCVAL(p,10,t->tm_sec);
2958 SCVAL(p,11,0); /* hundredths of seconds */
2959 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2960 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2961 SCVAL(p,16,t->tm_mday);
2962 SCVAL(p,17,t->tm_mon + 1);
2963 SSVAL(p,18,1900+t->tm_year);
2964 SCVAL(p,20,t->tm_wday);
2966 return True;
2969 /****************************************************************************
2970 Set the user password (SamOEM version - gets plaintext).
2971 ****************************************************************************/
2973 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
2974 connection_struct *conn,uint64_t vuid,
2975 char *param, int tpscnt,
2976 char *data, int tdscnt,
2977 int mdrcnt,int mprcnt,
2978 char **rdata,char **rparam,
2979 int *rdata_len,int *rparam_len)
2981 fstring user;
2982 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2984 TALLOC_CTX *mem_ctx = talloc_tos();
2985 NTSTATUS status, result;
2986 struct rpc_pipe_client *cli = NULL;
2987 struct lsa_AsciiString server, account;
2988 struct samr_CryptPassword password;
2989 struct samr_Password hash;
2990 int errcode = NERR_badpass;
2991 int bufsize;
2992 struct dcerpc_binding_handle *b;
2994 *rparam_len = 4;
2995 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2996 if (!*rparam) {
2997 return False;
3000 if (!p) {
3001 return False;
3003 *rdata_len = 0;
3005 SSVAL(*rparam,0,NERR_badpass);
3008 * Check the parameter definition is correct.
3011 /* Do we have a string ? */
3012 if (skip_string(param,tpscnt,p) == 0) {
3013 return False;
3015 if(!strequal(p, "zsT")) {
3016 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3017 return False;
3019 p = skip_string(param, tpscnt, p);
3020 if (!p) {
3021 return False;
3024 /* Do we have a string ? */
3025 if (skip_string(param,tpscnt,p) == 0) {
3026 return False;
3028 if(!strequal(p, "B516B16")) {
3029 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3030 return False;
3032 p = skip_string(param,tpscnt,p);
3033 if (!p) {
3034 return False;
3036 /* Do we have a string ? */
3037 if (skip_string(param,tpscnt,p) == 0) {
3038 return False;
3040 p += pull_ascii_fstring(user,p);
3042 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3044 if (tdscnt != 532) {
3045 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3046 goto out;
3049 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3050 if (bufsize != 532) {
3051 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3052 goto out;
3055 memcpy(password.data, data, 516);
3056 memcpy(hash.hash, data+516, 16);
3058 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
3059 conn->session_info,
3060 conn->sconn->remote_address,
3061 conn->sconn->local_address,
3062 conn->sconn->msg_ctx,
3063 &cli);
3064 if (!NT_STATUS_IS_OK(status)) {
3065 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3066 nt_errstr(status)));
3067 errcode = W_ERROR_V(ntstatus_to_werror(status));
3068 goto out;
3071 b = cli->binding_handle;
3073 init_lsa_AsciiString(&server, lp_netbios_name());
3074 init_lsa_AsciiString(&account, user);
3076 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3077 &server,
3078 &account,
3079 &password,
3080 &hash,
3081 &result);
3082 if (!NT_STATUS_IS_OK(status)) {
3083 errcode = W_ERROR_V(ntstatus_to_werror(status));
3084 goto out;
3086 if (!NT_STATUS_IS_OK(result)) {
3087 errcode = W_ERROR_V(ntstatus_to_werror(result));
3088 goto out;
3091 errcode = NERR_Success;
3092 out:
3093 SSVAL(*rparam,0,errcode);
3094 SSVAL(*rparam,2,0); /* converter word */
3096 return(True);
3099 /****************************************************************************
3100 delete a print job
3101 Form: <W> <>
3102 ****************************************************************************/
3104 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3105 connection_struct *conn,uint64_t vuid,
3106 char *param, int tpscnt,
3107 char *data, int tdscnt,
3108 int mdrcnt,int mprcnt,
3109 char **rdata,char **rparam,
3110 int *rdata_len,int *rparam_len)
3112 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3113 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3114 char *str2 = skip_string(param,tpscnt,str1);
3115 char *p = skip_string(param,tpscnt,str2);
3116 uint32_t jobid;
3117 fstring sharename;
3118 int errcode;
3119 WERROR werr = WERR_OK;
3121 TALLOC_CTX *mem_ctx = talloc_tos();
3122 NTSTATUS status;
3123 struct rpc_pipe_client *cli = NULL;
3124 struct dcerpc_binding_handle *b = NULL;
3125 struct policy_handle handle;
3126 struct spoolss_DevmodeContainer devmode_ctr;
3127 enum spoolss_JobControl command;
3129 if (!str1 || !str2 || !p) {
3130 return False;
3133 * We use 1 here not 2 as we're checking
3134 * the last byte we want to access is safe.
3136 if (!is_offset_safe(param,tpscnt,p,1)) {
3137 return False;
3139 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3140 return False;
3142 /* check it's a supported varient */
3143 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3144 return(False);
3146 *rparam_len = 4;
3147 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3148 if (!*rparam) {
3149 return False;
3151 *rdata_len = 0;
3153 ZERO_STRUCT(handle);
3155 status = rpc_pipe_open_interface(mem_ctx,
3156 &ndr_table_spoolss,
3157 conn->session_info,
3158 conn->sconn->remote_address,
3159 conn->sconn->local_address,
3160 conn->sconn->msg_ctx,
3161 &cli);
3162 if (!NT_STATUS_IS_OK(status)) {
3163 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3164 nt_errstr(status)));
3165 errcode = W_ERROR_V(ntstatus_to_werror(status));
3166 goto out;
3168 b = cli->binding_handle;
3170 ZERO_STRUCT(devmode_ctr);
3172 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3173 sharename,
3174 "RAW",
3175 devmode_ctr,
3176 JOB_ACCESS_ADMINISTER,
3177 &handle,
3178 &werr);
3179 if (!NT_STATUS_IS_OK(status)) {
3180 errcode = W_ERROR_V(ntstatus_to_werror(status));
3181 goto out;
3183 if (!W_ERROR_IS_OK(werr)) {
3184 errcode = W_ERROR_V(werr);
3185 goto out;
3188 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3189 * and NERR_DestNotFound if share did not exist */
3191 errcode = NERR_Success;
3193 switch (function) {
3194 case 81: /* delete */
3195 command = SPOOLSS_JOB_CONTROL_DELETE;
3196 break;
3197 case 82: /* pause */
3198 command = SPOOLSS_JOB_CONTROL_PAUSE;
3199 break;
3200 case 83: /* resume */
3201 command = SPOOLSS_JOB_CONTROL_RESUME;
3202 break;
3203 default:
3204 errcode = NERR_notsupported;
3205 goto out;
3208 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3209 &handle,
3210 jobid,
3211 NULL, /* unique ptr ctr */
3212 command,
3213 &werr);
3214 if (!NT_STATUS_IS_OK(status)) {
3215 errcode = W_ERROR_V(ntstatus_to_werror(status));
3216 goto out;
3218 if (!W_ERROR_IS_OK(werr)) {
3219 errcode = W_ERROR_V(werr);
3220 goto out;
3223 out:
3224 if (b && is_valid_policy_hnd(&handle)) {
3225 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3228 SSVAL(*rparam,0,errcode);
3229 SSVAL(*rparam,2,0); /* converter word */
3231 return(True);
3234 /****************************************************************************
3235 Purge a print queue - or pause or resume it.
3236 ****************************************************************************/
3238 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3239 connection_struct *conn,uint64_t vuid,
3240 char *param, int tpscnt,
3241 char *data, int tdscnt,
3242 int mdrcnt,int mprcnt,
3243 char **rdata,char **rparam,
3244 int *rdata_len,int *rparam_len)
3246 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3247 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3248 char *str2 = skip_string(param,tpscnt,str1);
3249 char *QueueName = skip_string(param,tpscnt,str2);
3250 int errcode = NERR_notsupported;
3251 WERROR werr = WERR_OK;
3252 NTSTATUS status;
3254 TALLOC_CTX *mem_ctx = talloc_tos();
3255 struct rpc_pipe_client *cli = NULL;
3256 struct dcerpc_binding_handle *b = NULL;
3257 struct policy_handle handle;
3258 struct spoolss_SetPrinterInfoCtr info_ctr;
3259 struct spoolss_DevmodeContainer devmode_ctr;
3260 struct sec_desc_buf secdesc_ctr;
3261 enum spoolss_PrinterControl command;
3263 if (!str1 || !str2 || !QueueName) {
3264 return False;
3267 /* check it's a supported varient */
3268 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3269 return(False);
3271 *rparam_len = 4;
3272 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3273 if (!*rparam) {
3274 return False;
3276 *rdata_len = 0;
3278 if (skip_string(param,tpscnt,QueueName) == NULL) {
3279 return False;
3282 ZERO_STRUCT(handle);
3284 status = rpc_pipe_open_interface(mem_ctx,
3285 &ndr_table_spoolss,
3286 conn->session_info,
3287 conn->sconn->remote_address,
3288 conn->sconn->local_address,
3289 conn->sconn->msg_ctx,
3290 &cli);
3291 if (!NT_STATUS_IS_OK(status)) {
3292 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3293 nt_errstr(status)));
3294 errcode = W_ERROR_V(ntstatus_to_werror(status));
3295 goto out;
3297 b = cli->binding_handle;
3299 ZERO_STRUCT(devmode_ctr);
3301 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3302 QueueName,
3303 NULL,
3304 devmode_ctr,
3305 PRINTER_ACCESS_ADMINISTER,
3306 &handle,
3307 &werr);
3308 if (!NT_STATUS_IS_OK(status)) {
3309 errcode = W_ERROR_V(ntstatus_to_werror(status));
3310 goto out;
3312 if (!W_ERROR_IS_OK(werr)) {
3313 errcode = W_ERROR_V(werr);
3314 goto out;
3317 switch (function) {
3318 case 74: /* Pause queue */
3319 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3320 break;
3321 case 75: /* Resume queue */
3322 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3323 break;
3324 case 103: /* Purge */
3325 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3326 break;
3327 default:
3328 werr = WERR_NOT_SUPPORTED;
3329 break;
3332 if (!W_ERROR_IS_OK(werr)) {
3333 errcode = W_ERROR_V(werr);
3334 goto out;
3337 ZERO_STRUCT(info_ctr);
3338 ZERO_STRUCT(secdesc_ctr);
3340 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3341 &handle,
3342 &info_ctr,
3343 &devmode_ctr,
3344 &secdesc_ctr,
3345 command,
3346 &werr);
3347 if (!NT_STATUS_IS_OK(status)) {
3348 errcode = W_ERROR_V(ntstatus_to_werror(status));
3349 goto out;
3351 if (!W_ERROR_IS_OK(werr)) {
3352 errcode = W_ERROR_V(werr);
3353 goto out;
3356 errcode = W_ERROR_V(werr);
3358 out:
3360 if (b && is_valid_policy_hnd(&handle)) {
3361 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3364 SSVAL(*rparam,0,errcode);
3365 SSVAL(*rparam,2,0); /* converter word */
3367 return(True);
3370 /****************************************************************************
3371 set the property of a print job (undocumented?)
3372 ? function = 0xb -> set name of print job
3373 ? function = 0x6 -> move print job up/down
3374 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3375 or <WWsTP> <WB21BB16B10zWWzDDz>
3376 ****************************************************************************/
3378 static int check_printjob_info(struct pack_desc* desc,
3379 int uLevel, char* id)
3381 desc->subformat = NULL;
3382 switch( uLevel ) {
3383 case 0: desc->format = "W"; break;
3384 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3385 case 2: desc->format = "WWzWWDDzz"; break;
3386 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3387 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3388 default:
3389 DEBUG(0,("check_printjob_info: invalid level %d\n",
3390 uLevel ));
3391 return False;
3393 if (id == NULL || strcmp(desc->format,id) != 0) {
3394 DEBUG(0,("check_printjob_info: invalid format %s\n",
3395 id ? id : "<NULL>" ));
3396 return False;
3398 return True;
3401 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3402 connection_struct *conn, uint64_t vuid,
3403 char *param, int tpscnt,
3404 char *data, int tdscnt,
3405 int mdrcnt,int mprcnt,
3406 char **rdata,char **rparam,
3407 int *rdata_len,int *rparam_len)
3409 struct pack_desc desc;
3410 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3411 char *str2 = skip_string(param,tpscnt,str1);
3412 char *p = skip_string(param,tpscnt,str2);
3413 uint32_t jobid;
3414 fstring sharename;
3415 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3416 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3417 int errcode;
3419 TALLOC_CTX *mem_ctx = talloc_tos();
3420 WERROR werr;
3421 NTSTATUS status;
3422 struct rpc_pipe_client *cli = NULL;
3423 struct dcerpc_binding_handle *b = NULL;
3424 struct policy_handle handle;
3425 struct spoolss_DevmodeContainer devmode_ctr;
3426 struct spoolss_JobInfoContainer ctr;
3427 union spoolss_JobInfo info;
3428 struct spoolss_SetJobInfo1 info1;
3430 if (!str1 || !str2 || !p) {
3431 return False;
3434 * We use 1 here not 2 as we're checking
3435 * the last byte we want to access is safe.
3437 if (!is_offset_safe(param,tpscnt,p,1)) {
3438 return False;
3440 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3441 return False;
3442 *rparam_len = 4;
3443 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3444 if (!*rparam) {
3445 return False;
3448 *rdata_len = 0;
3450 /* check it's a supported varient */
3451 if ((strcmp(str1,"WWsTP")) ||
3452 (!check_printjob_info(&desc,uLevel,str2)))
3453 return(False);
3455 errcode = NERR_notsupported;
3457 switch (function) {
3458 case 0xb:
3459 /* change print job name, data gives the name */
3460 break;
3461 default:
3462 goto out;
3465 ZERO_STRUCT(handle);
3467 status = rpc_pipe_open_interface(mem_ctx,
3468 &ndr_table_spoolss,
3469 conn->session_info,
3470 conn->sconn->remote_address,
3471 conn->sconn->local_address,
3472 conn->sconn->msg_ctx,
3473 &cli);
3474 if (!NT_STATUS_IS_OK(status)) {
3475 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3476 nt_errstr(status)));
3477 errcode = W_ERROR_V(ntstatus_to_werror(status));
3478 goto out;
3480 b = cli->binding_handle;
3482 ZERO_STRUCT(devmode_ctr);
3484 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3485 sharename,
3486 "RAW",
3487 devmode_ctr,
3488 PRINTER_ACCESS_USE,
3489 &handle,
3490 &werr);
3491 if (!NT_STATUS_IS_OK(status)) {
3492 errcode = W_ERROR_V(ntstatus_to_werror(status));
3493 goto out;
3495 if (!W_ERROR_IS_OK(werr)) {
3496 errcode = W_ERROR_V(werr);
3497 goto out;
3500 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3501 &handle,
3502 jobid,
3503 1, /* level */
3504 0, /* offered */
3505 &info);
3506 if (!W_ERROR_IS_OK(werr)) {
3507 errcode = W_ERROR_V(werr);
3508 goto out;
3511 ZERO_STRUCT(ctr);
3513 info1.job_id = info.info1.job_id;
3514 info1.printer_name = info.info1.printer_name;
3515 info1.user_name = info.info1.user_name;
3516 info1.document_name = data;
3517 info1.data_type = info.info1.data_type;
3518 info1.text_status = info.info1.text_status;
3519 info1.status = info.info1.status;
3520 info1.priority = info.info1.priority;
3521 info1.position = info.info1.position;
3522 info1.total_pages = info.info1.total_pages;
3523 info1.pages_printed = info.info1.pages_printed;
3524 info1.submitted = info.info1.submitted;
3526 ctr.level = 1;
3527 ctr.info.info1 = &info1;
3529 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3530 &handle,
3531 jobid,
3532 &ctr,
3534 &werr);
3535 if (!NT_STATUS_IS_OK(status)) {
3536 errcode = W_ERROR_V(ntstatus_to_werror(status));
3537 goto out;
3539 if (!W_ERROR_IS_OK(werr)) {
3540 errcode = W_ERROR_V(werr);
3541 goto out;
3544 errcode = NERR_Success;
3545 out:
3547 if (b && is_valid_policy_hnd(&handle)) {
3548 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3551 SSVALS(*rparam,0,errcode);
3552 SSVAL(*rparam,2,0); /* converter word */
3554 return(True);
3558 /****************************************************************************
3559 Get info about the server.
3560 ****************************************************************************/
3562 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3563 connection_struct *conn,uint64_t vuid,
3564 char *param, int tpscnt,
3565 char *data, int tdscnt,
3566 int mdrcnt,int mprcnt,
3567 char **rdata,char **rparam,
3568 int *rdata_len,int *rparam_len)
3570 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3571 char *str2 = skip_string(param,tpscnt,str1);
3572 char *p = skip_string(param,tpscnt,str2);
3573 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3574 char *p2;
3575 int struct_len;
3577 NTSTATUS status;
3578 WERROR werr;
3579 TALLOC_CTX *mem_ctx = talloc_tos();
3580 struct rpc_pipe_client *cli = NULL;
3581 union srvsvc_NetSrvInfo info;
3582 int errcode;
3583 struct dcerpc_binding_handle *b;
3585 if (!str1 || !str2 || !p) {
3586 return False;
3589 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3591 /* check it's a supported varient */
3592 if (!prefix_ok(str1,"WrLh")) {
3593 return False;
3596 switch( uLevel ) {
3597 case 0:
3598 if (strcmp(str2,"B16") != 0) {
3599 return False;
3601 struct_len = 16;
3602 break;
3603 case 1:
3604 if (strcmp(str2,"B16BBDz") != 0) {
3605 return False;
3607 struct_len = 26;
3608 break;
3609 case 2:
3610 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3611 return False;
3613 struct_len = 134;
3614 break;
3615 case 3:
3616 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3617 return False;
3619 struct_len = 144;
3620 break;
3621 case 20:
3622 if (strcmp(str2,"DN") != 0) {
3623 return False;
3625 struct_len = 6;
3626 break;
3627 case 50:
3628 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3629 return False;
3631 struct_len = 42;
3632 break;
3633 default:
3634 return False;
3637 *rdata_len = mdrcnt;
3638 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3639 if (!*rdata) {
3640 return False;
3643 p = *rdata;
3644 p2 = p + struct_len;
3646 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
3647 conn->session_info,
3648 conn->sconn->remote_address,
3649 conn->sconn->local_address,
3650 conn->sconn->msg_ctx,
3651 &cli);
3652 if (!NT_STATUS_IS_OK(status)) {
3653 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3654 nt_errstr(status)));
3655 errcode = W_ERROR_V(ntstatus_to_werror(status));
3656 goto out;
3659 b = cli->binding_handle;
3661 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3662 NULL,
3663 101,
3664 &info,
3665 &werr);
3666 if (!NT_STATUS_IS_OK(status)) {
3667 errcode = W_ERROR_V(ntstatus_to_werror(status));
3668 goto out;
3670 if (!W_ERROR_IS_OK(werr)) {
3671 errcode = W_ERROR_V(werr);
3672 goto out;
3675 if (info.info101 == NULL) {
3676 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3677 goto out;
3680 if (uLevel != 20) {
3681 size_t len = 0;
3682 status = srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3683 STR_ASCII|STR_UPPER|STR_TERMINATE, &len);
3684 if (!NT_STATUS_IS_OK(status)) {
3685 errcode = W_ERROR_V(ntstatus_to_werror(status));
3686 goto out;
3689 p += 16;
3690 if (uLevel > 0) {
3691 SCVAL(p,0,info.info101->version_major);
3692 SCVAL(p,1,info.info101->version_minor);
3693 SIVAL(p,2,info.info101->server_type);
3695 if (mdrcnt == struct_len) {
3696 SIVAL(p,6,0);
3697 } else {
3698 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3699 if (mdrcnt - struct_len <= 0) {
3700 return false;
3702 push_ascii(p2,
3703 info.info101->comment,
3704 MIN(mdrcnt - struct_len,
3705 MAX_SERVER_STRING_LENGTH),
3706 STR_TERMINATE);
3707 p2 = skip_string(*rdata,*rdata_len,p2);
3708 if (!p2) {
3709 return False;
3714 if (uLevel > 1) {
3715 return False; /* not yet implemented */
3718 errcode = NERR_Success;
3720 out:
3722 *rdata_len = PTR_DIFF(p2,*rdata);
3724 *rparam_len = 6;
3725 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3726 if (!*rparam) {
3727 return False;
3729 SSVAL(*rparam,0,errcode);
3730 SSVAL(*rparam,2,0); /* converter word */
3731 SSVAL(*rparam,4,*rdata_len);
3733 return True;
3736 /****************************************************************************
3737 Get info about the server.
3738 ****************************************************************************/
3740 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3741 connection_struct *conn,uint64_t vuid,
3742 char *param, int tpscnt,
3743 char *data, int tdscnt,
3744 int mdrcnt,int mprcnt,
3745 char **rdata,char **rparam,
3746 int *rdata_len,int *rparam_len)
3748 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3749 char *str2 = skip_string(param,tpscnt,str1);
3750 char *p = skip_string(param,tpscnt,str2);
3751 char *p2;
3752 char *endp;
3753 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3755 if (!str1 || !str2 || !p) {
3756 return False;
3759 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3761 *rparam_len = 6;
3762 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3763 if (!*rparam) {
3764 return False;
3767 /* check it's a supported varient */
3768 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3769 return False;
3772 *rdata_len = mdrcnt + 1024;
3773 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3774 if (!*rdata) {
3775 return False;
3778 SSVAL(*rparam,0,NERR_Success);
3779 SSVAL(*rparam,2,0); /* converter word */
3781 p = *rdata;
3782 endp = *rdata + *rdata_len;
3784 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3785 if (!p2) {
3786 return False;
3789 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3790 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3791 if (!strupper_m(p2)) {
3792 return false;
3794 p2 = skip_string(*rdata,*rdata_len,p2);
3795 if (!p2) {
3796 return False;
3798 p += 4;
3800 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3801 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3802 p2 = skip_string(*rdata,*rdata_len,p2);
3803 if (!p2) {
3804 return False;
3806 p += 4;
3808 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3809 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3810 if (!strupper_m(p2)) {
3811 return false;
3813 p2 = skip_string(*rdata,*rdata_len,p2);
3814 if (!p2) {
3815 return False;
3817 p += 4;
3819 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3820 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3821 p += 2;
3823 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3824 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3825 p2 = skip_string(*rdata,*rdata_len,p2);
3826 if (!p2) {
3827 return False;
3829 p += 4;
3831 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3832 strlcpy(p2,"",PTR_DIFF(endp,p2));
3833 p2 = skip_string(*rdata,*rdata_len,p2);
3834 if (!p2) {
3835 return False;
3837 p += 4;
3839 *rdata_len = PTR_DIFF(p2,*rdata);
3841 SSVAL(*rparam,4,*rdata_len);
3843 return True;
3846 /****************************************************************************
3847 get info about a user
3849 struct user_info_11 {
3850 char usri11_name[21]; 0-20
3851 char usri11_pad; 21
3852 char *usri11_comment; 22-25
3853 char *usri11_usr_comment; 26-29
3854 unsigned short usri11_priv; 30-31
3855 unsigned long usri11_auth_flags; 32-35
3856 long usri11_password_age; 36-39
3857 char *usri11_homedir; 40-43
3858 char *usri11_parms; 44-47
3859 long usri11_last_logon; 48-51
3860 long usri11_last_logoff; 52-55
3861 unsigned short usri11_bad_pw_count; 56-57
3862 unsigned short usri11_num_logons; 58-59
3863 char *usri11_logon_server; 60-63
3864 unsigned short usri11_country_code; 64-65
3865 char *usri11_workstations; 66-69
3866 unsigned long usri11_max_storage; 70-73
3867 unsigned short usri11_units_per_week; 74-75
3868 unsigned char *usri11_logon_hours; 76-79
3869 unsigned short usri11_code_page; 80-81
3872 where:
3874 usri11_name specifies the user name for which information is retrieved
3876 usri11_pad aligns the next data structure element to a word boundary
3878 usri11_comment is a null terminated ASCII comment
3880 usri11_user_comment is a null terminated ASCII comment about the user
3882 usri11_priv specifies the level of the privilege assigned to the user.
3883 The possible values are:
3885 Name Value Description
3886 USER_PRIV_GUEST 0 Guest privilege
3887 USER_PRIV_USER 1 User privilege
3888 USER_PRV_ADMIN 2 Administrator privilege
3890 usri11_auth_flags specifies the account operator privileges. The
3891 possible values are:
3893 Name Value Description
3894 AF_OP_PRINT 0 Print operator
3897 Leach, Naik [Page 28]
3901 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3904 AF_OP_COMM 1 Communications operator
3905 AF_OP_SERVER 2 Server operator
3906 AF_OP_ACCOUNTS 3 Accounts operator
3909 usri11_password_age specifies how many seconds have elapsed since the
3910 password was last changed.
3912 usri11_home_dir points to a null terminated ASCII string that contains
3913 the path name of the user's home directory.
3915 usri11_parms points to a null terminated ASCII string that is set
3916 aside for use by applications.
3918 usri11_last_logon specifies the time when the user last logged on.
3919 This value is stored as the number of seconds elapsed since
3920 00:00:00, January 1, 1970.
3922 usri11_last_logoff specifies the time when the user last logged off.
3923 This value is stored as the number of seconds elapsed since
3924 00:00:00, January 1, 1970. A value of 0 means the last logoff
3925 time is unknown.
3927 usri11_bad_pw_count specifies the number of incorrect passwords
3928 entered since the last successful logon.
3930 usri11_log1_num_logons specifies the number of times this user has
3931 logged on. A value of -1 means the number of logons is unknown.
3933 usri11_logon_server points to a null terminated ASCII string that
3934 contains the name of the server to which logon requests are sent.
3935 A null string indicates logon requests should be sent to the
3936 domain controller.
3938 usri11_country_code specifies the country code for the user's language
3939 of choice.
3941 usri11_workstations points to a null terminated ASCII string that
3942 contains the names of workstations the user may log on from.
3943 There may be up to 8 workstations, with the names separated by
3944 commas. A null strings indicates there are no restrictions.
3946 usri11_max_storage specifies the maximum amount of disk space the user
3947 can occupy. A value of 0xffffffff indicates there are no
3948 restrictions.
3950 usri11_units_per_week specifies the equal number of time units into
3951 which a week is divided. This value must be equal to 168.
3953 usri11_logon_hours points to a 21 byte (168 bits) string that
3954 specifies the time during which the user can log on. Each bit
3955 represents one unique hour in a week. The first bit (bit 0, word
3956 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3960 Leach, Naik [Page 29]
3964 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3967 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3968 are no restrictions.
3970 usri11_code_page specifies the code page for the user's language of
3971 choice
3973 All of the pointers in this data structure need to be treated
3974 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3975 to be ignored. The converter word returned in the parameters section
3976 needs to be subtracted from the lower 16 bits to calculate an offset
3977 into the return buffer where this ASCII string resides.
3979 There is no auxiliary data in the response.
3981 ****************************************************************************/
3983 #define usri11_name 0
3984 #define usri11_pad 21
3985 #define usri11_comment 22
3986 #define usri11_usr_comment 26
3987 #define usri11_full_name 30
3988 #define usri11_priv 34
3989 #define usri11_auth_flags 36
3990 #define usri11_password_age 40
3991 #define usri11_homedir 44
3992 #define usri11_parms 48
3993 #define usri11_last_logon 52
3994 #define usri11_last_logoff 56
3995 #define usri11_bad_pw_count 60
3996 #define usri11_num_logons 62
3997 #define usri11_logon_server 64
3998 #define usri11_country_code 68
3999 #define usri11_workstations 70
4000 #define usri11_max_storage 74
4001 #define usri11_units_per_week 78
4002 #define usri11_logon_hours 80
4003 #define usri11_code_page 84
4004 #define usri11_end 86
4006 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4007 connection_struct *conn, uint64_t vuid,
4008 char *param, int tpscnt,
4009 char *data, int tdscnt,
4010 int mdrcnt,int mprcnt,
4011 char **rdata,char **rparam,
4012 int *rdata_len,int *rparam_len)
4014 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4015 char *str2 = skip_string(param,tpscnt,str1);
4016 char *UserName = skip_string(param,tpscnt,str2);
4017 char *p = skip_string(param,tpscnt,UserName);
4018 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4019 char *p2;
4020 char *endp;
4021 const char *level_string;
4023 TALLOC_CTX *mem_ctx = talloc_tos();
4024 NTSTATUS status, result;
4025 struct rpc_pipe_client *cli = NULL;
4026 struct policy_handle connect_handle, domain_handle, user_handle;
4027 struct lsa_String domain_name;
4028 struct dom_sid2 *domain_sid;
4029 struct lsa_String names;
4030 struct samr_Ids rids;
4031 struct samr_Ids types;
4032 int errcode = W_ERROR_V(WERR_NERR_USERNOTFOUND);
4033 uint32_t rid;
4034 union samr_UserInfo *info;
4035 struct dcerpc_binding_handle *b = NULL;
4037 if (!str1 || !str2 || !UserName || !p) {
4038 return False;
4041 *rparam_len = 6;
4042 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4043 if (!*rparam) {
4044 return False;
4047 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4049 /* check it's a supported variant */
4050 if (strcmp(str1,"zWrLh") != 0) {
4051 return False;
4053 switch( uLevel ) {
4054 case 0: level_string = "B21"; break;
4055 case 1: level_string = "B21BB16DWzzWz"; break;
4056 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4057 case 10: level_string = "B21Bzzz"; break;
4058 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4059 default: return False;
4062 if (strcmp(level_string,str2) != 0) {
4063 return False;
4066 *rdata_len = mdrcnt + 1024;
4067 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4068 if (!*rdata) {
4069 return False;
4072 p = *rdata;
4073 endp = *rdata + *rdata_len;
4074 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4075 if (!p2) {
4076 return False;
4079 ZERO_STRUCT(connect_handle);
4080 ZERO_STRUCT(domain_handle);
4081 ZERO_STRUCT(user_handle);
4083 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
4084 conn->session_info,
4085 conn->sconn->remote_address,
4086 conn->sconn->local_address,
4087 conn->sconn->msg_ctx,
4088 &cli);
4089 if (!NT_STATUS_IS_OK(status)) {
4090 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4091 nt_errstr(status)));
4092 errcode = W_ERROR_V(ntstatus_to_werror(status));
4093 goto out;
4096 b = cli->binding_handle;
4098 status = dcerpc_samr_Connect2(b, mem_ctx,
4099 lp_netbios_name(),
4100 SAMR_ACCESS_CONNECT_TO_SERVER |
4101 SAMR_ACCESS_ENUM_DOMAINS |
4102 SAMR_ACCESS_LOOKUP_DOMAIN,
4103 &connect_handle,
4104 &result);
4105 if (!NT_STATUS_IS_OK(status)) {
4106 errcode = W_ERROR_V(ntstatus_to_werror(status));
4107 goto out;
4109 if (!NT_STATUS_IS_OK(result)) {
4110 errcode = W_ERROR_V(ntstatus_to_werror(result));
4111 goto out;
4114 init_lsa_String(&domain_name, get_global_sam_name());
4116 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4117 &connect_handle,
4118 &domain_name,
4119 &domain_sid,
4120 &result);
4121 if (!NT_STATUS_IS_OK(status)) {
4122 errcode = W_ERROR_V(ntstatus_to_werror(status));
4123 goto out;
4125 if (!NT_STATUS_IS_OK(result)) {
4126 errcode = W_ERROR_V(ntstatus_to_werror(result));
4127 goto out;
4130 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4131 &connect_handle,
4132 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4133 domain_sid,
4134 &domain_handle,
4135 &result);
4136 if (!NT_STATUS_IS_OK(status)) {
4137 errcode = W_ERROR_V(ntstatus_to_werror(status));
4138 goto out;
4140 if (!NT_STATUS_IS_OK(result)) {
4141 errcode = W_ERROR_V(ntstatus_to_werror(result));
4142 goto out;
4145 init_lsa_String(&names, UserName);
4147 status = dcerpc_samr_LookupNames(b, mem_ctx,
4148 &domain_handle,
4150 &names,
4151 &rids,
4152 &types,
4153 &result);
4154 if (!NT_STATUS_IS_OK(status)) {
4155 errcode = W_ERROR_V(ntstatus_to_werror(status));
4156 goto out;
4158 if (!NT_STATUS_IS_OK(result)) {
4159 errcode = W_ERROR_V(ntstatus_to_werror(result));
4160 goto out;
4163 if (rids.count != 1) {
4164 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4165 goto out;
4167 if (rids.count != types.count) {
4168 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4169 goto out;
4171 if (types.ids[0] != SID_NAME_USER) {
4172 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4173 goto out;
4176 rid = rids.ids[0];
4178 status = dcerpc_samr_OpenUser(b, mem_ctx,
4179 &domain_handle,
4180 SAMR_USER_ACCESS_GET_LOCALE |
4181 SAMR_USER_ACCESS_GET_LOGONINFO |
4182 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4183 SAMR_USER_ACCESS_GET_GROUPS |
4184 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4185 SEC_STD_READ_CONTROL,
4186 rid,
4187 &user_handle,
4188 &result);
4189 if (!NT_STATUS_IS_OK(status)) {
4190 errcode = W_ERROR_V(ntstatus_to_werror(status));
4191 goto out;
4193 if (!NT_STATUS_IS_OK(result)) {
4194 errcode = W_ERROR_V(ntstatus_to_werror(result));
4195 goto out;
4198 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4199 &user_handle,
4200 UserAllInformation,
4201 &info,
4202 &result);
4203 if (!NT_STATUS_IS_OK(status)) {
4204 errcode = W_ERROR_V(ntstatus_to_werror(status));
4205 goto out;
4207 if (!NT_STATUS_IS_OK(result)) {
4208 errcode = W_ERROR_V(ntstatus_to_werror(result));
4209 goto out;
4212 memset(p,0,21);
4213 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4215 if (uLevel > 0) {
4216 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4217 *p2 = 0;
4220 if (uLevel >= 10) {
4221 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4222 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4223 p2 = skip_string(*rdata,*rdata_len,p2);
4224 if (!p2) {
4225 return False;
4228 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4229 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4230 p2 = skip_string(*rdata,*rdata_len,p2);
4231 if (!p2) {
4232 return False;
4235 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4236 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4237 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4238 p2 = skip_string(*rdata,*rdata_len,p2);
4239 if (!p2) {
4240 return False;
4244 if (uLevel == 11) {
4245 const char *homedir = info->info21.home_directory.string;
4246 /* modelled after NTAS 3.51 reply */
4247 SSVAL(p,usri11_priv,
4248 (get_current_uid(conn) == sec_initial_uid())?
4249 USER_PRIV_ADMIN:USER_PRIV_USER);
4250 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4251 SIVALS(p,usri11_password_age,-1); /* password age */
4252 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4253 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4254 p2 = skip_string(*rdata,*rdata_len,p2);
4255 if (!p2) {
4256 return False;
4258 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4259 strlcpy(p2,"",PTR_DIFF(endp,p2));
4260 p2 = skip_string(*rdata,*rdata_len,p2);
4261 if (!p2) {
4262 return False;
4264 SIVAL(p,usri11_last_logon,0); /* last logon */
4265 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4266 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4267 SSVALS(p,usri11_num_logons,-1); /* num logons */
4268 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4269 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4270 p2 = skip_string(*rdata,*rdata_len,p2);
4271 if (!p2) {
4272 return False;
4274 SSVAL(p,usri11_country_code,0); /* country code */
4276 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4277 strlcpy(p2,"",PTR_DIFF(endp,p2));
4278 p2 = skip_string(*rdata,*rdata_len,p2);
4279 if (!p2) {
4280 return False;
4283 SIVALS(p,usri11_max_storage,-1); /* max storage */
4284 SSVAL(p,usri11_units_per_week,168); /* units per week */
4285 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4287 /* a simple way to get logon hours at all times. */
4288 memset(p2,0xff,21);
4289 SCVAL(p2,21,0); /* fix zero termination */
4290 p2 = skip_string(*rdata,*rdata_len,p2);
4291 if (!p2) {
4292 return False;
4295 SSVAL(p,usri11_code_page,0); /* code page */
4298 if (uLevel == 1 || uLevel == 2) {
4299 memset(p+22,' ',16); /* password */
4300 SIVALS(p,38,-1); /* password age */
4301 SSVAL(p,42,
4302 (get_current_uid(conn) == sec_initial_uid())?
4303 USER_PRIV_ADMIN:USER_PRIV_USER);
4304 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4305 strlcpy(p2, info->info21.home_directory.string,
4306 PTR_DIFF(endp,p2));
4307 p2 = skip_string(*rdata,*rdata_len,p2);
4308 if (!p2) {
4309 return False;
4311 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4312 *p2++ = 0;
4313 SSVAL(p,52,0); /* flags */
4314 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4315 strlcpy(p2, info->info21.logon_script.string,
4316 PTR_DIFF(endp,p2));
4317 p2 = skip_string(*rdata,*rdata_len,p2);
4318 if (!p2) {
4319 return False;
4321 if (uLevel == 2) {
4322 SIVAL(p,58,0); /* auth_flags */
4323 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4324 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4325 p2 = skip_string(*rdata,*rdata_len,p2);
4326 if (!p2) {
4327 return False;
4329 SIVAL(p,66,0); /* urs_comment */
4330 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4331 strlcpy(p2,"",PTR_DIFF(endp,p2));
4332 p2 = skip_string(*rdata,*rdata_len,p2);
4333 if (!p2) {
4334 return False;
4336 SIVAL(p,74,0); /* workstations */
4337 SIVAL(p,78,0); /* last_logon */
4338 SIVAL(p,82,0); /* last_logoff */
4339 SIVALS(p,86,-1); /* acct_expires */
4340 SIVALS(p,90,-1); /* max_storage */
4341 SSVAL(p,94,168); /* units_per_week */
4342 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4343 memset(p2,-1,21);
4344 p2 += 21;
4345 SSVALS(p,100,-1); /* bad_pw_count */
4346 SSVALS(p,102,-1); /* num_logons */
4347 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4349 TALLOC_CTX *ctx = talloc_tos();
4350 int space_rem = *rdata_len - (p2 - *rdata);
4351 char *tmp;
4353 if (space_rem <= 0) {
4354 return false;
4356 tmp = talloc_strdup(ctx, "\\\\%L");
4357 if (!tmp) {
4358 return false;
4360 tmp = talloc_sub_basic(ctx,
4363 tmp);
4364 if (!tmp) {
4365 return false;
4368 push_ascii(p2,
4369 tmp,
4370 space_rem,
4371 STR_TERMINATE);
4373 p2 = skip_string(*rdata,*rdata_len,p2);
4374 if (!p2) {
4375 return False;
4377 SSVAL(p,108,49); /* country_code */
4378 SSVAL(p,110,860); /* code page */
4382 errcode = NERR_Success;
4384 out:
4385 *rdata_len = PTR_DIFF(p2,*rdata);
4387 if (b && is_valid_policy_hnd(&user_handle)) {
4388 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4390 if (b && is_valid_policy_hnd(&domain_handle)) {
4391 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4393 if (b && is_valid_policy_hnd(&connect_handle)) {
4394 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4397 SSVAL(*rparam,0,errcode);
4398 SSVAL(*rparam,2,0); /* converter word */
4399 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4401 return(True);
4404 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4405 connection_struct *conn,uint64_t vuid,
4406 char *param, int tpscnt,
4407 char *data, int tdscnt,
4408 int mdrcnt,int mprcnt,
4409 char **rdata,char **rparam,
4410 int *rdata_len,int *rparam_len)
4412 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4413 char *str2 = skip_string(param,tpscnt,str1);
4414 char *p = skip_string(param,tpscnt,str2);
4415 int uLevel;
4416 struct pack_desc desc;
4417 char* name;
4418 struct auth_session_info *si = NULL;
4419 NTSTATUS status;
4421 status = smbXsrv_session_info_lookup(conn->sconn->client,
4422 vuid,
4423 &si);
4424 if (!NT_STATUS_IS_OK(status)) {
4425 return false;
4428 if (!str1 || !str2 || !p) {
4429 return False;
4432 DBG_INFO("Username of UID %ju is %s\n",
4433 (uintmax_t)si->unix_token->uid,
4434 si->unix_info->unix_name);
4436 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4437 name = get_safe_str_ptr(param,tpscnt,p,2);
4438 if (!name) {
4439 return False;
4442 memset((char *)&desc,'\0',sizeof(desc));
4444 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4446 /* check it's a supported varient */
4447 if (strcmp(str1,"OOWb54WrLh") != 0) {
4448 return False;
4450 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4451 return False;
4453 if (mdrcnt > 0) {
4454 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4455 if (!*rdata) {
4456 return False;
4460 desc.base = *rdata;
4461 desc.buflen = mdrcnt;
4462 desc.subformat = NULL;
4463 desc.format = str2;
4465 if (init_package(&desc,1,0)) {
4466 PACKI(&desc,"W",0); /* code */
4467 PACKS(&desc,"B21",name); /* eff. name */
4468 PACKS(&desc,"B",""); /* pad */
4469 PACKI(&desc,"W",
4470 (get_current_uid(conn) == sec_initial_uid())?
4471 USER_PRIV_ADMIN:USER_PRIV_USER);
4472 PACKI(&desc,"D",0); /* auth flags XXX */
4473 PACKI(&desc,"W",0); /* num logons */
4474 PACKI(&desc,"W",0); /* bad pw count */
4475 PACKI(&desc,"D",0); /* last logon */
4476 PACKI(&desc,"D",-1); /* last logoff */
4477 PACKI(&desc,"D",-1); /* logoff time */
4478 PACKI(&desc,"D",-1); /* kickoff time */
4479 PACKI(&desc,"D",0); /* password age */
4480 PACKI(&desc,"D",0); /* password can change */
4481 PACKI(&desc,"D",-1); /* password must change */
4484 fstring mypath;
4485 fstrcpy(mypath,"\\\\");
4486 fstrcat(mypath,get_local_machine_name());
4487 if (!strupper_m(mypath)) {
4488 return false;
4490 PACKS(&desc,"z",mypath); /* computer */
4493 PACKS(&desc,"z",lp_workgroup());/* domain */
4494 PACKS(&desc,"z", si->info->logon_script); /* script path */
4495 PACKI(&desc,"D",0x00000000); /* reserved */
4498 *rdata_len = desc.usedlen;
4499 *rparam_len = 6;
4500 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4501 if (!*rparam) {
4502 return False;
4504 SSVALS(*rparam,0,desc.errcode);
4505 SSVAL(*rparam,2,0);
4506 SSVAL(*rparam,4,desc.neededlen);
4508 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4510 return True;
4513 /****************************************************************************
4514 api_WAccessGetUserPerms
4515 ****************************************************************************/
4517 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4518 connection_struct *conn,uint64_t vuid,
4519 char *param, int tpscnt,
4520 char *data, int tdscnt,
4521 int mdrcnt,int mprcnt,
4522 char **rdata,char **rparam,
4523 int *rdata_len,int *rparam_len)
4525 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4526 char *str2 = skip_string(param,tpscnt,str1);
4527 char *user = skip_string(param,tpscnt,str2);
4528 char *resource = skip_string(param,tpscnt,user);
4530 if (!str1 || !str2 || !user || !resource) {
4531 return False;
4534 if (skip_string(param,tpscnt,resource) == NULL) {
4535 return False;
4537 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4539 /* check it's a supported varient */
4540 if (strcmp(str1,"zzh") != 0) {
4541 return False;
4543 if (strcmp(str2,"") != 0) {
4544 return False;
4547 *rparam_len = 6;
4548 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4549 if (!*rparam) {
4550 return False;
4552 SSVALS(*rparam,0,0); /* errorcode */
4553 SSVAL(*rparam,2,0); /* converter word */
4554 SSVAL(*rparam,4,0x7f); /* permission flags */
4556 return True;
4559 /****************************************************************************
4560 api_WPrintJobEnumerate
4561 ****************************************************************************/
4563 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4564 connection_struct *conn, uint64_t vuid,
4565 char *param, int tpscnt,
4566 char *data, int tdscnt,
4567 int mdrcnt,int mprcnt,
4568 char **rdata,char **rparam,
4569 int *rdata_len,int *rparam_len)
4571 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4572 char *str2 = skip_string(param,tpscnt,str1);
4573 char *p = skip_string(param,tpscnt,str2);
4574 int uLevel;
4575 fstring sharename;
4576 uint32_t jobid;
4577 struct pack_desc desc;
4578 char *tmpdata=NULL;
4580 TALLOC_CTX *mem_ctx = talloc_tos();
4581 WERROR werr;
4582 NTSTATUS status;
4583 struct rpc_pipe_client *cli = NULL;
4584 struct dcerpc_binding_handle *b = NULL;
4585 struct policy_handle handle;
4586 struct spoolss_DevmodeContainer devmode_ctr;
4587 union spoolss_JobInfo info;
4589 if (!str1 || !str2 || !p) {
4590 return False;
4593 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4595 memset((char *)&desc,'\0',sizeof(desc));
4596 memset((char *)&status,'\0',sizeof(status));
4598 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4600 /* check it's a supported varient */
4601 if (strcmp(str1,"WWrLh") != 0) {
4602 return False;
4604 if (!check_printjob_info(&desc,uLevel,str2)) {
4605 return False;
4608 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4609 return False;
4612 ZERO_STRUCT(handle);
4614 status = rpc_pipe_open_interface(mem_ctx,
4615 &ndr_table_spoolss,
4616 conn->session_info,
4617 conn->sconn->remote_address,
4618 conn->sconn->local_address,
4619 conn->sconn->msg_ctx,
4620 &cli);
4621 if (!NT_STATUS_IS_OK(status)) {
4622 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4623 nt_errstr(status)));
4624 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4625 goto out;
4627 b = cli->binding_handle;
4629 ZERO_STRUCT(devmode_ctr);
4631 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4632 sharename,
4633 "RAW",
4634 devmode_ctr,
4635 PRINTER_ACCESS_USE,
4636 &handle,
4637 &werr);
4638 if (!NT_STATUS_IS_OK(status)) {
4639 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4640 goto out;
4642 if (!W_ERROR_IS_OK(werr)) {
4643 desc.errcode = W_ERROR_V(werr);
4644 goto out;
4647 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4648 &handle,
4649 jobid,
4650 2, /* level */
4651 0, /* offered */
4652 &info);
4653 if (!W_ERROR_IS_OK(werr)) {
4654 desc.errcode = W_ERROR_V(werr);
4655 goto out;
4658 if (mdrcnt > 0) {
4659 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4660 if (!*rdata) {
4661 return False;
4663 desc.base = *rdata;
4664 desc.buflen = mdrcnt;
4665 } else {
4667 * Don't return data but need to get correct length
4668 * init_package will return wrong size if buflen=0
4670 desc.buflen = getlen(desc.format);
4671 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4674 if (init_package(&desc,1,0)) {
4675 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4676 *rdata_len = desc.usedlen;
4677 } else {
4678 desc.errcode = NERR_JobNotFound;
4679 *rdata_len = 0;
4681 out:
4682 if (b && is_valid_policy_hnd(&handle)) {
4683 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4686 *rparam_len = 6;
4687 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4688 if (!*rparam) {
4689 return False;
4691 SSVALS(*rparam,0,desc.errcode);
4692 SSVAL(*rparam,2,0);
4693 SSVAL(*rparam,4,desc.neededlen);
4695 SAFE_FREE(tmpdata);
4697 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4699 return True;
4702 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4703 connection_struct *conn, uint64_t vuid,
4704 char *param, int tpscnt,
4705 char *data, int tdscnt,
4706 int mdrcnt,int mprcnt,
4707 char **rdata,char **rparam,
4708 int *rdata_len,int *rparam_len)
4710 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4711 char *str2 = skip_string(param,tpscnt,str1);
4712 char *p = skip_string(param,tpscnt,str2);
4713 char *name = p;
4714 int uLevel;
4715 int i, succnt=0;
4716 struct pack_desc desc;
4718 TALLOC_CTX *mem_ctx = talloc_tos();
4719 WERROR werr;
4720 NTSTATUS status;
4721 struct rpc_pipe_client *cli = NULL;
4722 struct dcerpc_binding_handle *b = NULL;
4723 struct policy_handle handle;
4724 struct spoolss_DevmodeContainer devmode_ctr;
4725 uint32_t count = 0;
4726 union spoolss_JobInfo *info;
4728 if (!str1 || !str2 || !p) {
4729 return False;
4732 memset((char *)&desc,'\0',sizeof(desc));
4734 p = skip_string(param,tpscnt,p);
4735 if (!p) {
4736 return False;
4738 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4740 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4742 /* check it's a supported variant */
4743 if (strcmp(str1,"zWrLeh") != 0) {
4744 return False;
4747 if (uLevel > 2) {
4748 return False; /* defined only for uLevel 0,1,2 */
4751 if (!check_printjob_info(&desc,uLevel,str2)) {
4752 return False;
4755 ZERO_STRUCT(handle);
4757 status = rpc_pipe_open_interface(mem_ctx,
4758 &ndr_table_spoolss,
4759 conn->session_info,
4760 conn->sconn->remote_address,
4761 conn->sconn->local_address,
4762 conn->sconn->msg_ctx,
4763 &cli);
4764 if (!NT_STATUS_IS_OK(status)) {
4765 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4766 nt_errstr(status)));
4767 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4768 goto out;
4770 b = cli->binding_handle;
4772 ZERO_STRUCT(devmode_ctr);
4774 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4775 name,
4776 NULL,
4777 devmode_ctr,
4778 PRINTER_ACCESS_USE,
4779 &handle,
4780 &werr);
4781 if (!NT_STATUS_IS_OK(status)) {
4782 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4783 goto out;
4785 if (!W_ERROR_IS_OK(werr)) {
4786 desc.errcode = W_ERROR_V(werr);
4787 goto out;
4790 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4791 &handle,
4792 0, /* firstjob */
4793 0xff, /* numjobs */
4794 2, /* level */
4795 0, /* offered */
4796 &count,
4797 &info);
4798 if (!W_ERROR_IS_OK(werr)) {
4799 desc.errcode = W_ERROR_V(werr);
4800 goto out;
4803 if (mdrcnt > 0) {
4804 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4805 if (!*rdata) {
4806 return False;
4809 desc.base = *rdata;
4810 desc.buflen = mdrcnt;
4812 if (init_package(&desc,count,0)) {
4813 succnt = 0;
4814 for (i = 0; i < count; i++) {
4815 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4816 if (desc.errcode == NERR_Success) {
4817 succnt = i+1;
4821 out:
4822 if (b && is_valid_policy_hnd(&handle)) {
4823 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4826 *rdata_len = desc.usedlen;
4828 *rparam_len = 8;
4829 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4830 if (!*rparam) {
4831 return False;
4833 SSVALS(*rparam,0,desc.errcode);
4834 SSVAL(*rparam,2,0);
4835 SSVAL(*rparam,4,succnt);
4836 SSVAL(*rparam,6,count);
4838 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4840 return True;
4843 static int check_printdest_info(struct pack_desc* desc,
4844 int uLevel, char* id)
4846 desc->subformat = NULL;
4847 switch( uLevel ) {
4848 case 0:
4849 desc->format = "B9";
4850 break;
4851 case 1:
4852 desc->format = "B9B21WWzW";
4853 break;
4854 case 2:
4855 desc->format = "z";
4856 break;
4857 case 3:
4858 desc->format = "zzzWWzzzWW";
4859 break;
4860 default:
4861 DEBUG(0,("check_printdest_info: invalid level %d\n",
4862 uLevel));
4863 return False;
4865 if (id == NULL || strcmp(desc->format,id) != 0) {
4866 DEBUG(0,("check_printdest_info: invalid string %s\n",
4867 id ? id : "<NULL>" ));
4868 return False;
4870 return True;
4873 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4874 struct pack_desc* desc)
4876 char buf[100];
4878 strncpy(buf, info2->printername, sizeof(buf)-1);
4879 buf[sizeof(buf)-1] = 0;
4880 (void)strupper_m(buf);
4882 if (uLevel <= 1) {
4883 PACKS(desc,"B9",buf); /* szName */
4884 if (uLevel == 1) {
4885 PACKS(desc,"B21",""); /* szUserName */
4886 PACKI(desc,"W",0); /* uJobId */
4887 PACKI(desc,"W",0); /* fsStatus */
4888 PACKS(desc,"z",""); /* pszStatus */
4889 PACKI(desc,"W",0); /* time */
4893 if (uLevel == 2 || uLevel == 3) {
4894 PACKS(desc,"z",buf); /* pszPrinterName */
4895 if (uLevel == 3) {
4896 PACKS(desc,"z",""); /* pszUserName */
4897 PACKS(desc,"z",""); /* pszLogAddr */
4898 PACKI(desc,"W",0); /* uJobId */
4899 PACKI(desc,"W",0); /* fsStatus */
4900 PACKS(desc,"z",""); /* pszStatus */
4901 PACKS(desc,"z",""); /* pszComment */
4902 PACKS(desc,"z","NULL"); /* pszDrivers */
4903 PACKI(desc,"W",0); /* time */
4904 PACKI(desc,"W",0); /* pad1 */
4909 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4910 connection_struct *conn, uint64_t vuid,
4911 char *param, int tpscnt,
4912 char *data, int tdscnt,
4913 int mdrcnt,int mprcnt,
4914 char **rdata,char **rparam,
4915 int *rdata_len,int *rparam_len)
4917 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4918 char *str2 = skip_string(param,tpscnt,str1);
4919 char *p = skip_string(param,tpscnt,str2);
4920 char* PrinterName = p;
4921 int uLevel;
4922 struct pack_desc desc;
4923 char *tmpdata=NULL;
4925 TALLOC_CTX *mem_ctx = talloc_tos();
4926 WERROR werr;
4927 NTSTATUS status;
4928 struct rpc_pipe_client *cli = NULL;
4929 struct dcerpc_binding_handle *b = NULL;
4930 struct policy_handle handle;
4931 struct spoolss_DevmodeContainer devmode_ctr;
4932 union spoolss_PrinterInfo info;
4934 if (!str1 || !str2 || !p) {
4935 return False;
4938 memset((char *)&desc,'\0',sizeof(desc));
4940 p = skip_string(param,tpscnt,p);
4941 if (!p) {
4942 return False;
4944 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4946 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4948 /* check it's a supported varient */
4949 if (strcmp(str1,"zWrLh") != 0) {
4950 return False;
4952 if (!check_printdest_info(&desc,uLevel,str2)) {
4953 return False;
4956 ZERO_STRUCT(handle);
4958 status = rpc_pipe_open_interface(mem_ctx,
4959 &ndr_table_spoolss,
4960 conn->session_info,
4961 conn->sconn->remote_address,
4962 conn->sconn->local_address,
4963 conn->sconn->msg_ctx,
4964 &cli);
4965 if (!NT_STATUS_IS_OK(status)) {
4966 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4967 nt_errstr(status)));
4968 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4969 goto out;
4971 b = cli->binding_handle;
4973 ZERO_STRUCT(devmode_ctr);
4975 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4976 PrinterName,
4977 NULL,
4978 devmode_ctr,
4979 PRINTER_ACCESS_USE,
4980 &handle,
4981 &werr);
4982 if (!NT_STATUS_IS_OK(status)) {
4983 *rdata_len = 0;
4984 desc.errcode = NERR_DestNotFound;
4985 desc.neededlen = 0;
4986 goto out;
4988 if (!W_ERROR_IS_OK(werr)) {
4989 *rdata_len = 0;
4990 desc.errcode = NERR_DestNotFound;
4991 desc.neededlen = 0;
4992 goto out;
4995 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4996 &handle,
4999 &info);
5000 if (!W_ERROR_IS_OK(werr)) {
5001 *rdata_len = 0;
5002 desc.errcode = NERR_DestNotFound;
5003 desc.neededlen = 0;
5004 goto out;
5007 if (mdrcnt > 0) {
5008 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5009 if (!*rdata) {
5010 return False;
5012 desc.base = *rdata;
5013 desc.buflen = mdrcnt;
5014 } else {
5016 * Don't return data but need to get correct length
5017 * init_package will return wrong size if buflen=0
5019 desc.buflen = getlen(desc.format);
5020 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5022 if (init_package(&desc,1,0)) {
5023 fill_printdest_info(&info.info2, uLevel,&desc);
5026 out:
5027 if (b && is_valid_policy_hnd(&handle)) {
5028 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5031 *rdata_len = desc.usedlen;
5033 *rparam_len = 6;
5034 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5035 if (!*rparam) {
5036 return False;
5038 SSVALS(*rparam,0,desc.errcode);
5039 SSVAL(*rparam,2,0);
5040 SSVAL(*rparam,4,desc.neededlen);
5042 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5043 SAFE_FREE(tmpdata);
5045 return True;
5048 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5049 connection_struct *conn, uint64_t vuid,
5050 char *param, int tpscnt,
5051 char *data, int tdscnt,
5052 int mdrcnt,int mprcnt,
5053 char **rdata,char **rparam,
5054 int *rdata_len,int *rparam_len)
5056 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5057 char *str2 = skip_string(param,tpscnt,str1);
5058 char *p = skip_string(param,tpscnt,str2);
5059 int uLevel;
5060 int queuecnt;
5061 int i, n, succnt=0;
5062 struct pack_desc desc;
5064 TALLOC_CTX *mem_ctx = talloc_tos();
5065 WERROR werr;
5066 NTSTATUS status;
5067 struct rpc_pipe_client *cli = NULL;
5068 union spoolss_PrinterInfo *info;
5069 uint32_t count;
5071 if (!str1 || !str2 || !p) {
5072 return False;
5075 memset((char *)&desc,'\0',sizeof(desc));
5077 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5079 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5081 /* check it's a supported varient */
5082 if (strcmp(str1,"WrLeh") != 0) {
5083 return False;
5085 if (!check_printdest_info(&desc,uLevel,str2)) {
5086 return False;
5089 queuecnt = 0;
5091 status = rpc_pipe_open_interface(mem_ctx,
5092 &ndr_table_spoolss,
5093 conn->session_info,
5094 conn->sconn->remote_address,
5095 conn->sconn->local_address,
5096 conn->sconn->msg_ctx,
5097 &cli);
5098 if (!NT_STATUS_IS_OK(status)) {
5099 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5100 nt_errstr(status)));
5101 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5102 goto out;
5105 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5106 PRINTER_ENUM_LOCAL,
5107 cli->srv_name_slash,
5110 &count,
5111 &info);
5112 if (!W_ERROR_IS_OK(werr)) {
5113 desc.errcode = W_ERROR_V(werr);
5114 *rdata_len = 0;
5115 desc.errcode = NERR_DestNotFound;
5116 desc.neededlen = 0;
5117 goto out;
5120 queuecnt = count;
5122 if (mdrcnt > 0) {
5123 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5124 if (!*rdata) {
5125 return False;
5129 desc.base = *rdata;
5130 desc.buflen = mdrcnt;
5131 if (init_package(&desc,queuecnt,0)) {
5132 succnt = 0;
5133 n = 0;
5134 for (i = 0; i < count; i++) {
5135 fill_printdest_info(&info[i].info2, uLevel,&desc);
5136 n++;
5137 if (desc.errcode == NERR_Success) {
5138 succnt = n;
5142 out:
5143 *rdata_len = desc.usedlen;
5145 *rparam_len = 8;
5146 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5147 if (!*rparam) {
5148 return False;
5150 SSVALS(*rparam,0,desc.errcode);
5151 SSVAL(*rparam,2,0);
5152 SSVAL(*rparam,4,succnt);
5153 SSVAL(*rparam,6,queuecnt);
5155 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5157 return True;
5160 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5161 connection_struct *conn, uint64_t vuid,
5162 char *param, int tpscnt,
5163 char *data, int tdscnt,
5164 int mdrcnt,int mprcnt,
5165 char **rdata,char **rparam,
5166 int *rdata_len,int *rparam_len)
5168 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5169 char *str2 = skip_string(param,tpscnt,str1);
5170 char *p = skip_string(param,tpscnt,str2);
5171 int uLevel;
5172 int succnt;
5173 struct pack_desc desc;
5175 if (!str1 || !str2 || !p) {
5176 return False;
5179 memset((char *)&desc,'\0',sizeof(desc));
5181 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5183 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5185 /* check it's a supported varient */
5186 if (strcmp(str1,"WrLeh") != 0) {
5187 return False;
5189 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5190 return False;
5193 if (mdrcnt > 0) {
5194 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5195 if (!*rdata) {
5196 return False;
5199 desc.base = *rdata;
5200 desc.buflen = mdrcnt;
5201 if (init_package(&desc,1,0)) {
5202 PACKS(&desc,"B41","NULL");
5205 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5207 *rdata_len = desc.usedlen;
5209 *rparam_len = 8;
5210 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5211 if (!*rparam) {
5212 return False;
5214 SSVALS(*rparam,0,desc.errcode);
5215 SSVAL(*rparam,2,0);
5216 SSVAL(*rparam,4,succnt);
5217 SSVAL(*rparam,6,1);
5219 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5221 return True;
5224 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5225 connection_struct *conn, uint64_t vuid,
5226 char *param, int tpscnt,
5227 char *data, int tdscnt,
5228 int mdrcnt,int mprcnt,
5229 char **rdata,char **rparam,
5230 int *rdata_len,int *rparam_len)
5232 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5233 char *str2 = skip_string(param,tpscnt,str1);
5234 char *p = skip_string(param,tpscnt,str2);
5235 int uLevel;
5236 int succnt;
5237 struct pack_desc desc;
5239 if (!str1 || !str2 || !p) {
5240 return False;
5242 memset((char *)&desc,'\0',sizeof(desc));
5244 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5246 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5248 /* check it's a supported varient */
5249 if (strcmp(str1,"WrLeh") != 0) {
5250 return False;
5252 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5253 return False;
5256 if (mdrcnt > 0) {
5257 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5258 if (!*rdata) {
5259 return False;
5262 desc.base = *rdata;
5263 desc.buflen = mdrcnt;
5264 desc.format = str2;
5265 if (init_package(&desc,1,0)) {
5266 PACKS(&desc,"B13","lpd");
5269 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5271 *rdata_len = desc.usedlen;
5273 *rparam_len = 8;
5274 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5275 if (!*rparam) {
5276 return False;
5278 SSVALS(*rparam,0,desc.errcode);
5279 SSVAL(*rparam,2,0);
5280 SSVAL(*rparam,4,succnt);
5281 SSVAL(*rparam,6,1);
5283 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5285 return True;
5288 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5289 connection_struct *conn, uint64_t vuid,
5290 char *param, int tpscnt,
5291 char *data, int tdscnt,
5292 int mdrcnt,int mprcnt,
5293 char **rdata,char **rparam,
5294 int *rdata_len,int *rparam_len)
5296 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5297 char *str2 = skip_string(param,tpscnt,str1);
5298 char *p = skip_string(param,tpscnt,str2);
5299 int uLevel;
5300 int succnt;
5301 struct pack_desc desc;
5303 if (!str1 || !str2 || !p) {
5304 return False;
5307 memset((char *)&desc,'\0',sizeof(desc));
5309 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5311 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5313 /* check it's a supported varient */
5314 if (strcmp(str1,"WrLeh") != 0) {
5315 return False;
5317 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5318 return False;
5321 if (mdrcnt > 0) {
5322 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5323 if (!*rdata) {
5324 return False;
5327 memset((char *)&desc,'\0',sizeof(desc));
5328 desc.base = *rdata;
5329 desc.buflen = mdrcnt;
5330 desc.format = str2;
5331 if (init_package(&desc,1,0)) {
5332 PACKS(&desc,"B13","lp0");
5335 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5337 *rdata_len = desc.usedlen;
5339 *rparam_len = 8;
5340 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5341 if (!*rparam) {
5342 return False;
5344 SSVALS(*rparam,0,desc.errcode);
5345 SSVAL(*rparam,2,0);
5346 SSVAL(*rparam,4,succnt);
5347 SSVAL(*rparam,6,1);
5349 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5351 return True;
5354 /****************************************************************************
5355 List open sessions
5356 ****************************************************************************/
5358 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5359 connection_struct *conn, uint64_t vuid,
5360 char *param, int tpscnt,
5361 char *data, int tdscnt,
5362 int mdrcnt,int mprcnt,
5363 char **rdata,char **rparam,
5364 int *rdata_len,int *rparam_len)
5367 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5368 char *str2 = skip_string(param,tpscnt,str1);
5369 char *p = skip_string(param,tpscnt,str2);
5370 int uLevel;
5371 struct pack_desc desc;
5372 int i;
5374 TALLOC_CTX *mem_ctx = talloc_tos();
5375 WERROR werr;
5376 NTSTATUS status;
5377 struct rpc_pipe_client *cli = NULL;
5378 struct dcerpc_binding_handle *b = NULL;
5379 struct srvsvc_NetSessInfoCtr info_ctr;
5380 uint32_t totalentries, resume_handle = 0;
5381 uint32_t count = 0;
5383 if (!str1 || !str2 || !p) {
5384 return False;
5387 ZERO_STRUCT(desc);
5389 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5391 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5392 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5393 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5395 /* check it's a supported varient */
5396 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5397 return False;
5399 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5400 return False;
5403 status = rpc_pipe_open_interface(mem_ctx,
5404 &ndr_table_srvsvc,
5405 conn->session_info,
5406 conn->sconn->remote_address,
5407 conn->sconn->local_address,
5408 conn->sconn->msg_ctx,
5409 &cli);
5410 if (!NT_STATUS_IS_OK(status)) {
5411 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5412 nt_errstr(status)));
5413 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5414 goto out;
5416 b = cli->binding_handle;
5418 info_ctr.level = 1;
5419 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5420 if (info_ctr.ctr.ctr1 == NULL) {
5421 desc.errcode = W_ERROR_V(WERR_NOT_ENOUGH_MEMORY);
5422 goto out;
5425 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5426 cli->srv_name_slash,
5427 NULL, /* client */
5428 NULL, /* user */
5429 &info_ctr,
5430 (uint32_t)-1, /* max_buffer */
5431 &totalentries,
5432 &resume_handle,
5433 &werr);
5434 if (!NT_STATUS_IS_OK(status)) {
5435 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5436 nt_errstr(status)));
5437 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5438 goto out;
5441 if (!W_ERROR_IS_OK(werr)) {
5442 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5443 win_errstr(werr)));
5444 desc.errcode = W_ERROR_V(werr);
5445 goto out;
5448 count = info_ctr.ctr.ctr1->count;
5450 out:
5451 if (mdrcnt > 0) {
5452 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5453 if (!*rdata) {
5454 return False;
5458 desc.base = *rdata;
5459 desc.buflen = mdrcnt;
5460 desc.format = str2;
5461 if (!init_package(&desc, count,0)) {
5462 return False;
5465 for(i=0; i < count; i++) {
5466 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5467 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5468 PACKI(&desc, "W", 1); /* num conns */
5469 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5470 PACKI(&desc, "W", 1); /* num users */
5471 PACKI(&desc, "D", 0); /* session time */
5472 PACKI(&desc, "D", 0); /* idle time */
5473 PACKI(&desc, "D", 0); /* flags */
5474 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5477 *rdata_len = desc.usedlen;
5479 *rparam_len = 8;
5480 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5481 if (!*rparam) {
5482 return False;
5484 SSVALS(*rparam,0,desc.errcode);
5485 SSVAL(*rparam,2,0); /* converter */
5486 SSVAL(*rparam,4, count); /* count */
5488 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5490 return True;
5494 /****************************************************************************
5495 The buffer was too small.
5496 ****************************************************************************/
5498 static bool api_TooSmall(struct smbd_server_connection *sconn,
5499 connection_struct *conn,uint64_t vuid, char *param, char *data,
5500 int mdrcnt, int mprcnt,
5501 char **rdata, char **rparam,
5502 int *rdata_len, int *rparam_len)
5504 *rparam_len = MIN(*rparam_len,mprcnt);
5505 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5506 if (!*rparam) {
5507 return False;
5510 *rdata_len = 0;
5512 SSVAL(*rparam,0,NERR_BufTooSmall);
5514 DEBUG(3,("Supplied buffer too small in API command\n"));
5516 return True;
5519 /****************************************************************************
5520 The request is not supported.
5521 ****************************************************************************/
5523 static bool api_Unsupported(struct smbd_server_connection *sconn,
5524 connection_struct *conn, uint64_t vuid,
5525 char *param, int tpscnt,
5526 char *data, int tdscnt,
5527 int mdrcnt, int mprcnt,
5528 char **rdata, char **rparam,
5529 int *rdata_len, int *rparam_len)
5531 *rparam_len = 4;
5532 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5533 if (!*rparam) {
5534 return False;
5537 *rdata_len = 0;
5539 SSVAL(*rparam,0,NERR_notsupported);
5540 SSVAL(*rparam,2,0); /* converter word */
5542 DEBUG(3,("Unsupported API command\n"));
5544 return True;
5547 static const struct {
5548 const char *name;
5549 int id;
5550 bool (*fn)(struct smbd_server_connection *sconn,
5551 connection_struct *, uint64_t,
5552 char *, int,
5553 char *, int,
5554 int,int,char **,char **,int *,int *);
5555 bool auth_user; /* Deny anonymous access? */
5556 } api_commands[] = {
5558 .name = "RNetShareEnum",
5559 .id = RAP_WshareEnum,
5560 .fn = api_RNetShareEnum,
5561 .auth_user = true,
5564 .name = "RNetShareGetInfo",
5565 .id = RAP_WshareGetInfo,
5566 .fn = api_RNetShareGetInfo
5569 .name = "RNetShareAdd",
5570 .id = RAP_WshareAdd,
5571 .fn = api_RNetShareAdd
5574 .name = "RNetSessionEnum",
5575 .id = RAP_WsessionEnum,
5576 .fn = api_RNetSessionEnum,
5577 .auth_user = true,
5580 .name = "RNetServerGetInfo",
5581 .id = RAP_WserverGetInfo,
5582 .fn = api_RNetServerGetInfo
5585 .name = "RNetGroupEnum",
5586 .id = RAP_WGroupEnum,
5587 .fn = api_RNetGroupEnum, True
5590 .name = "RNetGroupGetUsers",
5591 .id = RAP_WGroupGetUsers,
5592 .fn = api_RNetGroupGetUsers,
5593 .auth_user = true},
5595 .name = "RNetUserEnum",
5596 .id = RAP_WUserEnum,
5597 .fn = api_RNetUserEnum,
5598 .auth_user = true,
5601 .name = "RNetUserGetInfo",
5602 .id = RAP_WUserGetInfo,
5603 .fn = api_RNetUserGetInfo
5606 .name = "NetUserGetGroups",
5607 .id = RAP_WUserGetGroups,
5608 .fn = api_NetUserGetGroups
5611 .name = "NetWkstaGetInfo",
5612 .id = RAP_WWkstaGetInfo,
5613 .fn = api_NetWkstaGetInfo
5616 .name = "DosPrintQEnum",
5617 .id = RAP_WPrintQEnum,
5618 .fn = api_DosPrintQEnum,
5619 .auth_user = true,
5622 .name = "DosPrintQGetInfo",
5623 .id = RAP_WPrintQGetInfo,
5624 .fn = api_DosPrintQGetInfo
5627 .name = "WPrintQueuePause",
5628 .id = RAP_WPrintQPause,
5629 .fn = api_WPrintQueueCtrl
5632 .name = "WPrintQueueResume",
5633 .id = RAP_WPrintQContinue,
5634 .fn = api_WPrintQueueCtrl
5637 .name = "WPrintJobEnumerate",
5638 .id = RAP_WPrintJobEnum,
5639 .fn = api_WPrintJobEnumerate
5642 .name = "WPrintJobGetInfo",
5643 .id = RAP_WPrintJobGetInfo,
5644 .fn = api_WPrintJobGetInfo
5647 .name = "RDosPrintJobDel",
5648 .id = RAP_WPrintJobDel,
5649 .fn = api_RDosPrintJobDel
5652 .name = "RDosPrintJobPause",
5653 .id = RAP_WPrintJobPause,
5654 .fn = api_RDosPrintJobDel
5657 .name = "RDosPrintJobResume",
5658 .id = RAP_WPrintJobContinue,
5659 .fn = api_RDosPrintJobDel
5662 .name = "WPrintDestEnum",
5663 .id = RAP_WPrintDestEnum,
5664 .fn = api_WPrintDestEnum
5667 .name = "WPrintDestGetInfo",
5668 .id = RAP_WPrintDestGetInfo,
5669 .fn = api_WPrintDestGetInfo
5672 .name = "NetRemoteTOD",
5673 .id = RAP_NetRemoteTOD,
5674 .fn = api_NetRemoteTOD
5677 .name = "WPrintQueuePurge",
5678 .id = RAP_WPrintQPurge,
5679 .fn = api_WPrintQueueCtrl
5682 .name = "NetServerEnum2",
5683 .id = RAP_NetServerEnum2,
5684 .fn = api_RNetServerEnum2
5685 }, /* anon OK */
5687 .name = "NetServerEnum3",
5688 .id = RAP_NetServerEnum3,
5689 .fn = api_RNetServerEnum3
5690 }, /* anon OK */
5692 .name = "WAccessGetUserPerms",
5693 .id = RAP_WAccessGetUserPerms,
5694 .fn = api_WAccessGetUserPerms
5697 .name = "WWkstaUserLogon",
5698 .id = RAP_WWkstaUserLogon,
5699 .fn = api_WWkstaUserLogon
5702 .name = "PrintJobInfo",
5703 .id = RAP_WPrintJobSetInfo,
5704 .fn = api_PrintJobInfo
5707 .name = "WPrintDriverEnum",
5708 .id = RAP_WPrintDriverEnum,
5709 .fn = api_WPrintDriverEnum
5712 .name = "WPrintQProcEnum",
5713 .id = RAP_WPrintQProcessorEnum,
5714 .fn = api_WPrintQProcEnum
5717 .name = "WPrintPortEnum",
5718 .id = RAP_WPrintPortEnum,
5719 .fn = api_WPrintPortEnum
5722 .name = "SamOEMChangePassword",
5723 .id = RAP_SamOEMChgPasswordUser2_P,
5724 .fn = api_SamOEMChangePassword
5725 }, /* anon OK */
5727 .name = NULL,
5728 .id = -1,
5729 .fn = api_Unsupported}
5731 * The following RAP calls are not implemented by Samba:
5732 * RAP_WFileEnum2 - anon not OK
5737 /****************************************************************************
5738 Handle remote api calls.
5739 ****************************************************************************/
5741 void api_reply(connection_struct *conn, uint64_t vuid,
5742 struct smb_request *req,
5743 char *data, char *params,
5744 int tdscnt, int tpscnt,
5745 int mdrcnt, int mprcnt)
5747 int api_command;
5748 char *rdata = NULL;
5749 char *rparam = NULL;
5750 const char *name1 = NULL;
5751 const char *name2 = NULL;
5752 int rdata_len = 0;
5753 int rparam_len = 0;
5754 bool reply=False;
5755 int i;
5757 if (!params) {
5758 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5759 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5760 return;
5763 if (tpscnt < 2) {
5764 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5765 return;
5767 api_command = SVAL(params,0);
5768 /* Is there a string at position params+2 ? */
5769 if (skip_string(params,tpscnt,params+2)) {
5770 name1 = params + 2;
5771 } else {
5772 name1 = "";
5774 name2 = skip_string(params,tpscnt,params+2);
5775 if (!name2) {
5776 name2 = "";
5779 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5780 api_command,
5781 name1,
5782 name2,
5783 tdscnt,tpscnt,mdrcnt,mprcnt));
5785 for (i=0;api_commands[i].name;i++) {
5786 if (api_commands[i].id == api_command && api_commands[i].fn) {
5787 DEBUG(3,("Doing %s\n",api_commands[i].name));
5788 break;
5792 /* Check whether this api call can be done anonymously */
5794 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5795 struct auth_session_info *si = NULL;
5796 NTSTATUS status;
5798 status = smbXsrv_session_info_lookup(conn->sconn->client,
5799 vuid,
5800 &si);
5801 if (!NT_STATUS_IS_OK(status)) {
5802 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5803 return;
5806 if (security_session_user_level(si, NULL) < SECURITY_USER) {
5807 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5808 return;
5812 rdata = (char *)SMB_MALLOC(1024);
5813 if (rdata) {
5814 memset(rdata,'\0',1024);
5817 rparam = (char *)SMB_MALLOC(1024);
5818 if (rparam) {
5819 memset(rparam,'\0',1024);
5822 if(!rdata || !rparam) {
5823 DEBUG(0,("api_reply: malloc fail !\n"));
5824 SAFE_FREE(rdata);
5825 SAFE_FREE(rparam);
5826 reply_nterror(req, NT_STATUS_NO_MEMORY);
5827 return;
5830 reply = api_commands[i].fn(req->sconn, conn,
5831 vuid,
5832 params,tpscnt, /* params + length */
5833 data,tdscnt, /* data + length */
5834 mdrcnt,mprcnt,
5835 &rdata,&rparam,&rdata_len,&rparam_len);
5838 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5839 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5840 mdrcnt,mprcnt,
5841 &rdata,&rparam,&rdata_len,&rparam_len);
5844 /* if we get False back then it's actually unsupported */
5845 if (!reply) {
5846 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5847 data,
5848 tdscnt,mdrcnt,mprcnt,
5849 &rdata,&rparam,&rdata_len,&rparam_len);
5852 /* If api_Unsupported returns false we can't return anything. */
5853 if (reply) {
5854 send_trans_reply(conn, req, rparam, rparam_len,
5855 rdata, rdata_len, False);
5858 SAFE_FREE(rdata);
5859 SAFE_FREE(rparam);
5860 return;