s3: smbd: Correctly process SMB3 POSIX paths in create.
[Samba.git] / source3 / smbd / smb1_lanman.c
blob65711078c89d02ee0f59ae29b1d1b72ba4f4992a
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"
46 #include "lib/util/string_wrappers.h"
47 #include "source3/printing/rap_jobid.h"
48 #include "source3/lib/substitute.h"
50 #ifdef CHECK_TYPES
51 #undef CHECK_TYPES
52 #endif
53 #define CHECK_TYPES 0
55 #define NERR_Success 0
56 #define NERR_badpass 86
57 #define NERR_notsupported 50
59 #define NERR_BASE (2100)
60 #define NERR_BufTooSmall (NERR_BASE+23)
61 #define NERR_JobNotFound (NERR_BASE+51)
62 #define NERR_DestNotFound (NERR_BASE+52)
64 #define ACCESS_READ 0x01
65 #define ACCESS_WRITE 0x02
66 #define ACCESS_CREATE 0x04
68 #define SHPWLEN 8 /* share password length */
70 /* Limit size of ipc replies */
72 static char *smb_realloc_limit(void *ptr, size_t size)
74 char *val;
76 size = MAX((size),4*1024);
77 val = (char *)SMB_REALLOC(ptr,size);
78 if (val) {
79 memset(val,'\0',size);
81 return val;
84 static bool api_Unsupported(struct smbd_server_connection *sconn,
85 connection_struct *conn, uint64_t vuid,
86 char *param, int tpscnt,
87 char *data, int tdscnt,
88 int mdrcnt, int mprcnt,
89 char **rdata, char **rparam,
90 int *rdata_len, int *rparam_len);
92 static bool api_TooSmall(struct smbd_server_connection *sconn,
93 connection_struct *conn, uint64_t vuid, char *param, char *data,
94 int mdrcnt, int mprcnt,
95 char **rdata, char **rparam,
96 int *rdata_len, int *rparam_len);
99 static int CopyExpanded(connection_struct *conn,
100 int snum, char **dst, char *src, int *p_space_remaining)
102 TALLOC_CTX *ctx = talloc_tos();
103 const struct loadparm_substitution *lp_sub =
104 loadparm_s3_global_substitution();
105 char *buf = NULL;
106 int l;
108 if (!src || !dst || !p_space_remaining || !(*dst) ||
109 *p_space_remaining <= 0) {
110 return 0;
113 buf = talloc_strdup(ctx, src);
114 if (!buf) {
115 *p_space_remaining = 0;
116 return 0;
118 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, lp_sub, snum));
119 if (!buf) {
120 *p_space_remaining = 0;
121 return 0;
123 buf = talloc_sub_full(ctx,
124 lp_servicename(ctx, lp_sub, SNUM(conn)),
125 conn->session_info->unix_info->unix_name,
126 conn->connectpath,
127 conn->session_info->unix_token->gid,
128 conn->session_info->unix_info->sanitized_username,
129 conn->session_info->info->domain_name,
130 buf);
131 if (!buf) {
132 *p_space_remaining = 0;
133 return 0;
135 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
136 if (l == 0) {
137 return 0;
139 (*dst) += l;
140 (*p_space_remaining) -= l;
141 return l;
144 static int CopyAndAdvance(char **dst, char *src, int *n)
146 int l;
147 if (!src || !dst || !n || !(*dst)) {
148 return 0;
150 l = push_ascii(*dst,src,*n, STR_TERMINATE);
151 if (l == 0) {
152 return 0;
154 (*dst) += l;
155 (*n) -= l;
156 return l;
159 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
161 TALLOC_CTX *ctx = talloc_tos();
162 const struct loadparm_substitution *lp_sub =
163 loadparm_s3_global_substitution();
164 char *buf = NULL;
165 if (!s) {
166 return 0;
168 buf = talloc_strdup(ctx,s);
169 if (!buf) {
170 return 0;
172 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, lp_sub, snum));
173 if (!buf) {
174 return 0;
176 buf = talloc_sub_full(ctx,
177 lp_servicename(ctx, lp_sub, SNUM(conn)),
178 conn->session_info->unix_info->unix_name,
179 conn->connectpath,
180 conn->session_info->unix_token->gid,
181 conn->session_info->unix_info->sanitized_username,
182 conn->session_info->info->domain_name,
183 buf);
184 if (!buf) {
185 return 0;
187 return strlen(buf) + 1;
190 /****************************************************************
191 Return an SVAL at a pointer, or failval if beyond the end.
192 ****************************************************************/
194 static int get_safe_SVAL(
195 const char *buf_base,
196 size_t buf_len,
197 char *ptr,
198 size_t off,
199 int failval)
202 * Note we use off+1 here, not off+2 as SVAL accesses ptr[0]
203 * and ptr[1], NOT ptr[2].
205 if (!is_offset_safe(buf_base, buf_len, ptr, off+1)) {
206 return failval;
208 return SVAL(ptr,off);
211 /****************************************************************
212 Return an IVAL at a pointer, or failval if beyond the end.
213 ****************************************************************/
215 static int get_safe_IVAL(
216 const char *buf_base,
217 size_t buf_len,
218 char *ptr,
219 size_t off,
220 int failval)
223 * Note we use off+3 here, not off+4 as IVAL accesses
224 * ptr[0] ptr[1] ptr[2] ptr[3] NOT ptr[4].
226 if (!is_offset_safe(buf_base, buf_len, ptr, off+3)) {
227 return failval;
229 return IVAL(ptr,off);
232 /****************************************************************
233 Return a safe pointer into a buffer, or NULL.
234 ****************************************************************/
236 static char *get_safe_ptr(
237 const char *buf_base,
238 size_t buf_len,
239 char *ptr,
240 size_t off)
242 return is_offset_safe(buf_base, buf_len, ptr, off) ?
243 ptr + off : NULL;
246 /*******************************************************************
247 Check a API string for validity when we only need to check the prefix.
248 ******************************************************************/
250 static bool prefix_ok(const char *str, const char *prefix)
252 return(strncmp(str,prefix,strlen(prefix)) == 0);
255 struct pack_desc {
256 const char *format; /* formatstring for structure */
257 const char *subformat; /* subformat for structure */
258 char *base; /* baseaddress of buffer */
259 int buflen; /* remaining size for fixed part; on init: length of base */
260 int subcount; /* count of substructures */
261 char *structbuf; /* pointer into buffer for remaining fixed part */
262 int stringlen; /* remaining size for variable part */
263 char *stringbuf; /* pointer into buffer for remaining variable part */
264 int neededlen; /* total needed size */
265 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
266 const char *curpos; /* current position; pointer into format or subformat */
267 int errcode;
270 static int get_counter(const char **p)
272 int i, n;
273 if (!p || !(*p)) {
274 return 1;
276 if (!isdigit((int)**p)) {
277 return 1;
279 for (n = 0;;) {
280 i = **p;
281 if (isdigit(i)) {
282 n = 10 * n + (i - '0');
283 } else {
284 return n;
286 (*p)++;
290 static int getlen(const char *p)
292 int n = 0;
293 if (!p) {
294 return 0;
297 while (*p) {
298 switch( *p++ ) {
299 case 'W': /* word (2 byte) */
300 n += 2;
301 break;
302 case 'K': /* status word? (2 byte) */
303 n += 2;
304 break;
305 case 'N': /* count of substructures (word) at end */
306 n += 2;
307 break;
308 case 'D': /* double word (4 byte) */
309 case 'z': /* offset to zero terminated string (4 byte) */
310 case 'l': /* offset to user data (4 byte) */
311 n += 4;
312 break;
313 case 'b': /* offset to data (with counter) (4 byte) */
314 n += 4;
315 get_counter(&p);
316 break;
317 case 'B': /* byte (with optional counter) */
318 n += get_counter(&p);
319 break;
322 return n;
325 static bool init_package(struct pack_desc *p, int count, int subcount)
327 int n = p->buflen;
328 int i;
330 if (!p->format || !p->base) {
331 return False;
334 i = count * getlen(p->format);
335 if (p->subformat) {
336 i += subcount * getlen(p->subformat);
338 p->structbuf = p->base;
339 p->neededlen = 0;
340 p->usedlen = 0;
341 p->subcount = 0;
342 p->curpos = p->format;
343 if (i > n) {
344 p->neededlen = i;
345 i = n = 0;
346 #if 0
348 * This is the old error code we used. Aparently
349 * WinNT/2k systems return ERRbuftoosmall (2123) and
350 * OS/2 needs this. I'm leaving this here so we can revert
351 * if needed. JRA.
353 p->errcode = ERRmoredata;
354 #else
355 p->errcode = ERRbuftoosmall;
356 #endif
357 } else {
358 p->errcode = NERR_Success;
360 p->buflen = i;
361 n -= i;
362 p->stringbuf = p->base + i;
363 p->stringlen = n;
364 return (p->errcode == NERR_Success);
367 static int package(struct pack_desc *p, ...)
369 va_list args;
370 int needed=0, stringneeded;
371 const char *str=NULL;
372 int is_string=0, stringused;
373 int32_t temp;
375 va_start(args,p);
377 if (!*p->curpos) {
378 if (!p->subcount) {
379 p->curpos = p->format;
380 } else {
381 p->curpos = p->subformat;
382 p->subcount--;
385 #if CHECK_TYPES
386 str = va_arg(args,char*);
387 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
388 #endif
389 stringneeded = -1;
391 if (!p->curpos) {
392 va_end(args);
393 return 0;
396 switch( *p->curpos++ ) {
397 case 'W': /* word (2 byte) */
398 needed = 2;
399 temp = va_arg(args,int);
400 if (p->buflen >= needed) {
401 SSVAL(p->structbuf,0,temp);
403 break;
404 case 'K': /* status word? (2 byte) */
405 needed = 2;
406 temp = va_arg(args,int);
407 if (p->buflen >= needed) {
408 SSVAL(p->structbuf,0,temp);
410 break;
411 case 'N': /* count of substructures (word) at end */
412 needed = 2;
413 p->subcount = va_arg(args,int);
414 if (p->buflen >= needed) {
415 SSVAL(p->structbuf,0,p->subcount);
417 break;
418 case 'D': /* double word (4 byte) */
419 needed = 4;
420 temp = va_arg(args,int);
421 if (p->buflen >= needed) {
422 SIVAL(p->structbuf,0,temp);
424 break;
425 case 'B': /* byte (with optional counter) */
426 needed = get_counter(&p->curpos);
428 char *s = va_arg(args,char*);
429 if (p->buflen >= needed) {
430 strlcpy(p->structbuf,s?s:"",needed);
433 break;
434 case 'z': /* offset to zero terminated string (4 byte) */
435 str = va_arg(args,char*);
436 stringneeded = (str ? strlen(str)+1 : 0);
437 is_string = 1;
438 break;
439 case 'l': /* offset to user data (4 byte) */
440 str = va_arg(args,char*);
441 stringneeded = va_arg(args,int);
442 is_string = 0;
443 break;
444 case 'b': /* offset to data (with counter) (4 byte) */
445 str = va_arg(args,char*);
446 stringneeded = get_counter(&p->curpos);
447 is_string = 0;
448 break;
451 va_end(args);
452 if (stringneeded >= 0) {
453 needed = 4;
454 if (p->buflen >= needed) {
455 stringused = stringneeded;
456 if (stringused > p->stringlen) {
457 stringused = (is_string ? p->stringlen : 0);
458 if (p->errcode == NERR_Success) {
459 p->errcode = ERRmoredata;
462 if (!stringused) {
463 SIVAL(p->structbuf,0,0);
464 } else {
465 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
466 memcpy(p->stringbuf,str?str:"",stringused);
467 if (is_string) {
468 p->stringbuf[stringused-1] = '\0';
470 p->stringbuf += stringused;
471 p->stringlen -= stringused;
472 p->usedlen += stringused;
475 p->neededlen += stringneeded;
478 p->neededlen += needed;
479 if (p->buflen >= needed) {
480 p->structbuf += needed;
481 p->buflen -= needed;
482 p->usedlen += needed;
483 } else {
484 if (p->errcode == NERR_Success) {
485 p->errcode = ERRmoredata;
488 return 1;
491 #if CHECK_TYPES
492 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
493 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
494 #else
495 #define PACK(desc,t,v) package(desc,v)
496 #define PACKl(desc,t,v,l) package(desc,v,l)
497 #endif
499 static void PACKI(struct pack_desc* desc, const char *t,int v)
501 PACK(desc,t,v);
504 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
506 PACK(desc,t,v);
509 /****************************************************************************
510 Get a print queue.
511 ****************************************************************************/
513 static void PackDriverData(struct pack_desc* desc)
515 char drivdata[4+4+32];
516 SIVAL(drivdata,0,sizeof drivdata); /* cb */
517 SIVAL(drivdata,4,1000); /* lVersion */
518 memset(drivdata+8,0,32); /* szDeviceName */
519 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
520 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
523 static int check_printq_info(struct pack_desc* desc,
524 unsigned int uLevel, char *id1, char *id2)
526 desc->subformat = NULL;
527 switch( uLevel ) {
528 case 0:
529 desc->format = "B13";
530 break;
531 case 1:
532 desc->format = "B13BWWWzzzzzWW";
533 break;
534 case 2:
535 desc->format = "B13BWWWzzzzzWN";
536 desc->subformat = "WB21BB16B10zWWzDDz";
537 break;
538 case 3:
539 desc->format = "zWWWWzzzzWWzzl";
540 break;
541 case 4:
542 desc->format = "zWWWWzzzzWNzzl";
543 desc->subformat = "WWzWWDDzz";
544 break;
545 case 5:
546 desc->format = "z";
547 break;
548 case 51:
549 desc->format = "K";
550 break;
551 case 52:
552 desc->format = "WzzzzzzzzN";
553 desc->subformat = "z";
554 break;
555 default:
556 DEBUG(0,("check_printq_info: invalid level %d\n",
557 uLevel ));
558 return False;
560 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
561 DEBUG(0,("check_printq_info: invalid format %s\n",
562 id1 ? id1 : "<NULL>" ));
563 return False;
565 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
566 DEBUG(0,("check_printq_info: invalid subformat %s\n",
567 id2 ? id2 : "<NULL>" ));
568 return False;
570 return True;
574 #define RAP_JOB_STATUS_QUEUED 0
575 #define RAP_JOB_STATUS_PAUSED 1
576 #define RAP_JOB_STATUS_SPOOLING 2
577 #define RAP_JOB_STATUS_PRINTING 3
578 #define RAP_JOB_STATUS_PRINTED 4
580 #define RAP_QUEUE_STATUS_PAUSED 1
581 #define RAP_QUEUE_STATUS_ERROR 2
583 /* turn a print job status into a on the wire status
585 static int printj_spoolss_status(int v)
587 if (v == JOB_STATUS_QUEUED)
588 return RAP_JOB_STATUS_QUEUED;
589 if (v & JOB_STATUS_PAUSED)
590 return RAP_JOB_STATUS_PAUSED;
591 if (v & JOB_STATUS_SPOOLING)
592 return RAP_JOB_STATUS_SPOOLING;
593 if (v & JOB_STATUS_PRINTING)
594 return RAP_JOB_STATUS_PRINTING;
595 return 0;
598 /* turn a print queue status into a on the wire status
600 static int printq_spoolss_status(int v)
602 if (v == PRINTER_STATUS_OK)
603 return 0;
604 if (v & PRINTER_STATUS_PAUSED)
605 return RAP_QUEUE_STATUS_PAUSED;
606 return RAP_QUEUE_STATUS_ERROR;
609 static void fill_spoolss_printjob_info(int uLevel,
610 struct pack_desc *desc,
611 struct spoolss_JobInfo2 *info2,
612 int n)
614 time_t t = spoolss_Time_to_time_t(&info2->submitted);
616 /* the client expects localtime */
617 t -= get_time_zone(t);
619 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
620 if (uLevel == 1) {
621 PACKS(desc,"B21", info2->user_name); /* szUserName */
622 PACKS(desc,"B",""); /* pad */
623 PACKS(desc,"B16",""); /* szNotifyName */
624 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
625 PACKS(desc,"z",""); /* pszParms */
626 PACKI(desc,"W",n+1); /* uPosition */
627 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
628 PACKS(desc,"z",""); /* pszStatus */
629 PACKI(desc,"D", t); /* ulSubmitted */
630 PACKI(desc,"D", info2->size); /* ulSize */
631 PACKS(desc,"z", info2->document_name); /* pszComment */
633 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
634 PACKI(desc,"W", info2->priority); /* uPriority */
635 PACKS(desc,"z", info2->user_name); /* pszUserName */
636 PACKI(desc,"W",n+1); /* uPosition */
637 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
638 PACKI(desc,"D",t); /* ulSubmitted */
639 PACKI(desc,"D", info2->size); /* ulSize */
640 PACKS(desc,"z","Samba"); /* pszComment */
641 PACKS(desc,"z", info2->document_name); /* pszDocument */
642 if (uLevel == 3) {
643 PACKS(desc,"z",""); /* pszNotifyName */
644 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
645 PACKS(desc,"z",""); /* pszParms */
646 PACKS(desc,"z",""); /* pszStatus */
647 PACKS(desc,"z", info2->printer_name); /* pszQueue */
648 PACKS(desc,"z","lpd"); /* pszQProcName */
649 PACKS(desc,"z",""); /* pszQProcParms */
650 PACKS(desc,"z","NULL"); /* pszDriverName */
651 PackDriverData(desc); /* pDriverData */
652 PACKS(desc,"z",""); /* pszPrinterName */
653 } else if (uLevel == 4) { /* OS2 */
654 PACKS(desc,"z",""); /* pszSpoolFileName */
655 PACKS(desc,"z",""); /* pszPortName */
656 PACKS(desc,"z",""); /* pszStatus */
657 PACKI(desc,"D",0); /* ulPagesSpooled */
658 PACKI(desc,"D",0); /* ulPagesSent */
659 PACKI(desc,"D",0); /* ulPagesPrinted */
660 PACKI(desc,"D",0); /* ulTimePrinted */
661 PACKI(desc,"D",0); /* ulExtendJobStatus */
662 PACKI(desc,"D",0); /* ulStartPage */
663 PACKI(desc,"D",0); /* ulEndPage */
668 /********************************************************************
669 Respond to the DosPrintQInfo command with a level of 52
670 This is used to get printer driver information for Win9x clients
671 ********************************************************************/
672 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
673 struct pack_desc* desc, int count,
674 const char *printer_name)
676 int i;
677 fstring location;
678 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
679 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
680 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
682 PACKI(desc, "W", 0x0400); /* don't know */
683 PACKS(desc, "z", driver->driver_name); /* long printer name */
684 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
685 PACKS(desc, "z", driver->data_file); /* Datafile name */
686 PACKS(desc, "z", driver->monitor_name); /* language monitor */
688 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
689 standard_sub_basic( "", "", location, sizeof(location)-1 );
690 PACKS(desc,"z", location); /* share to retrieve files */
692 PACKS(desc,"z", driver->default_datatype); /* default data type */
693 PACKS(desc,"z", driver->help_file); /* helpfile name */
694 PACKS(desc,"z", driver->driver_path); /* driver name */
696 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
697 DEBUG(3,("Driver: %s:\n",driver->driver_path));
698 DEBUG(3,("Data File: %s:\n",driver->data_file));
699 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
700 DEBUG(3,("Driver Location: %s:\n",location));
701 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
702 DEBUG(3,("Help File: %s:\n",driver->help_file));
703 PACKI(desc,"N",count); /* number of files to copy */
705 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
707 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
708 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
709 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
712 /* sanity check */
713 if ( i != count )
714 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
715 count, i));
717 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
719 desc->errcode=NERR_Success;
723 static const char *strip_unc(const char *unc)
725 char *p;
727 if (unc == NULL) {
728 return NULL;
731 if ((p = strrchr(unc, '\\')) != NULL) {
732 return p+1;
735 return unc;
738 static void fill_printq_info(int uLevel,
739 struct pack_desc* desc,
740 int count,
741 union spoolss_JobInfo *job_info,
742 struct spoolss_DriverInfo3 *driver_info,
743 struct spoolss_PrinterInfo2 *printer_info)
745 switch (uLevel) {
746 case 0:
747 case 1:
748 case 2:
749 PACKS(desc,"B13", strip_unc(printer_info->printername));
750 break;
751 case 3:
752 case 4:
753 case 5:
754 PACKS(desc,"z", strip_unc(printer_info->printername));
755 break;
756 case 51:
757 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
758 break;
761 if (uLevel == 1 || uLevel == 2) {
762 PACKS(desc,"B",""); /* alignment */
763 PACKI(desc,"W",5); /* priority */
764 PACKI(desc,"W",0); /* start time */
765 PACKI(desc,"W",0); /* until time */
766 PACKS(desc,"z",""); /* pSepFile */
767 PACKS(desc,"z","lpd"); /* pPrProc */
768 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
769 PACKS(desc,"z",""); /* pParms */
770 if (printer_info->printername == NULL) {
771 PACKS(desc,"z","UNKNOWN PRINTER");
772 PACKI(desc,"W",LPSTAT_ERROR);
773 } else {
774 PACKS(desc,"z", printer_info->comment);
775 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
777 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
780 if (uLevel == 3 || uLevel == 4) {
781 PACKI(desc,"W",5); /* uPriority */
782 PACKI(desc,"W",0); /* uStarttime */
783 PACKI(desc,"W",0); /* uUntiltime */
784 PACKI(desc,"W",5); /* pad1 */
785 PACKS(desc,"z",""); /* pszSepFile */
786 PACKS(desc,"z","WinPrint"); /* pszPrProc */
787 PACKS(desc,"z",NULL); /* pszParms */
788 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
789 /* "don't ask" that it's done this way to fix corrupted
790 Win9X/ME printer comments. */
791 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
792 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
793 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
794 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
795 PackDriverData(desc); /* pDriverData */
798 if (uLevel == 2 || uLevel == 4) {
799 int i;
800 for (i = 0; i < count; i++) {
801 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
805 if (uLevel==52)
806 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
809 /* This function returns the number of files for a given driver */
810 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
812 int result = 0;
814 /* count the number of files */
815 while (driver->dependent_files && *driver->dependent_files[result])
816 result++;
818 return result;
821 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
822 connection_struct *conn, uint64_t vuid,
823 char *param, int tpscnt,
824 char *data, int tdscnt,
825 int mdrcnt,int mprcnt,
826 char **rdata,char **rparam,
827 int *rdata_len,int *rparam_len)
829 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
830 char *str2 = skip_string(param,tpscnt,str1);
831 char *p = skip_string(param,tpscnt,str2);
832 char *QueueName = p;
833 unsigned int uLevel;
834 uint32_t count = 0;
835 char *str3;
836 struct pack_desc desc;
837 char* tmpdata=NULL;
839 WERROR werr = WERR_OK;
840 TALLOC_CTX *mem_ctx = talloc_tos();
841 NTSTATUS status;
842 struct rpc_pipe_client *cli = NULL;
843 struct dcerpc_binding_handle *b = NULL;
844 struct policy_handle handle;
845 struct spoolss_DevmodeContainer devmode_ctr;
846 union spoolss_DriverInfo driver_info;
847 union spoolss_JobInfo *job_info = NULL;
848 union spoolss_PrinterInfo printer_info;
850 if (!str1 || !str2 || !p) {
851 return False;
853 memset((char *)&desc,'\0',sizeof(desc));
855 p = skip_string(param,tpscnt,p);
856 if (!p) {
857 return False;
859 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
860 str3 = get_safe_str_ptr(param,tpscnt,p,4);
861 /* str3 may be null here and is checked in check_printq_info(). */
863 /* remove any trailing username */
864 if ((p = strchr_m(QueueName,'%')))
865 *p = 0;
867 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
869 /* check it's a supported varient */
870 if (!prefix_ok(str1,"zWrLh"))
871 return False;
872 if (!check_printq_info(&desc,uLevel,str2,str3)) {
874 * Patch from Scott Moomaw <scott@bridgewater.edu>
875 * to return the 'invalid info level' error if an
876 * unknown level was requested.
878 *rdata_len = 0;
879 *rparam_len = 6;
880 *rparam = smb_realloc_limit(*rparam,*rparam_len);
881 if (!*rparam) {
882 return False;
884 SSVALS(*rparam,0,ERRunknownlevel);
885 SSVAL(*rparam,2,0);
886 SSVAL(*rparam,4,0);
887 return(True);
890 ZERO_STRUCT(handle);
892 if (QueueName == NULL || (strlen(QueueName) < 1)) {
893 desc.errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
894 goto out;
897 status = rpc_pipe_open_interface(mem_ctx,
898 &ndr_table_spoolss,
899 conn->session_info,
900 conn->sconn->remote_address,
901 conn->sconn->local_address,
902 conn->sconn->msg_ctx,
903 &cli);
904 if (!NT_STATUS_IS_OK(status)) {
905 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
906 nt_errstr(status)));
907 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
908 goto out;
910 b = cli->binding_handle;
912 ZERO_STRUCT(devmode_ctr);
914 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
915 QueueName,
916 "RAW",
917 devmode_ctr,
918 PRINTER_ACCESS_USE,
919 &handle,
920 &werr);
921 if (!NT_STATUS_IS_OK(status)) {
922 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
923 goto out;
925 if (!W_ERROR_IS_OK(werr)) {
926 desc.errcode = W_ERROR_V(werr);
927 goto out;
930 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
931 &handle,
934 &printer_info);
935 if (!W_ERROR_IS_OK(werr)) {
936 desc.errcode = W_ERROR_V(werr);
937 goto out;
940 if (uLevel==52) {
941 uint32_t server_major_version;
942 uint32_t server_minor_version;
944 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
945 &handle,
946 "Windows 4.0",
947 3, /* level */
949 0, /* version */
951 &driver_info,
952 &server_major_version,
953 &server_minor_version);
954 if (!W_ERROR_IS_OK(werr)) {
955 desc.errcode = W_ERROR_V(werr);
956 goto out;
959 count = get_printerdrivernumber(&driver_info.info3);
960 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
961 } else {
962 uint32_t num_jobs;
963 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
964 &handle,
965 0, /* firstjob */
966 0xff, /* numjobs */
967 2, /* level */
968 0, /* offered */
969 &num_jobs,
970 &job_info);
971 if (!W_ERROR_IS_OK(werr)) {
972 desc.errcode = W_ERROR_V(werr);
973 goto out;
976 count = num_jobs;
979 if (mdrcnt > 0) {
980 *rdata = smb_realloc_limit(*rdata,mdrcnt);
981 if (!*rdata) {
982 return False;
984 desc.base = *rdata;
985 desc.buflen = mdrcnt;
986 } else {
988 * Don't return data but need to get correct length
989 * init_package will return wrong size if buflen=0
991 desc.buflen = getlen(desc.format);
992 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
995 if (init_package(&desc,1,count)) {
996 desc.subcount = count;
997 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
1000 *rdata_len = desc.usedlen;
1003 * We must set the return code to ERRbuftoosmall
1004 * in order to support lanman style printing with Win NT/2k
1005 * clients --jerry
1007 if (!mdrcnt && lp_disable_spoolss())
1008 desc.errcode = ERRbuftoosmall;
1010 out:
1011 if (b && is_valid_policy_hnd(&handle)) {
1012 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1015 *rdata_len = desc.usedlen;
1016 *rparam_len = 6;
1017 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1018 if (!*rparam) {
1019 SAFE_FREE(tmpdata);
1020 return False;
1022 SSVALS(*rparam,0,desc.errcode);
1023 SSVAL(*rparam,2,0);
1024 SSVAL(*rparam,4,desc.neededlen);
1026 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
1028 SAFE_FREE(tmpdata);
1030 return(True);
1033 /****************************************************************************
1034 View list of all print jobs on all queues.
1035 ****************************************************************************/
1037 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
1038 connection_struct *conn, uint64_t vuid,
1039 char *param, int tpscnt,
1040 char *data, int tdscnt,
1041 int mdrcnt, int mprcnt,
1042 char **rdata, char** rparam,
1043 int *rdata_len, int *rparam_len)
1045 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
1046 char *output_format1 = skip_string(param,tpscnt,param_format);
1047 char *p = skip_string(param,tpscnt,output_format1);
1048 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1049 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
1050 int i;
1051 struct pack_desc desc;
1052 int *subcntarr = NULL;
1053 int queuecnt = 0, subcnt = 0, succnt = 0;
1055 WERROR werr = WERR_OK;
1056 TALLOC_CTX *mem_ctx = talloc_tos();
1057 NTSTATUS status;
1058 struct rpc_pipe_client *cli = NULL;
1059 struct dcerpc_binding_handle *b = NULL;
1060 struct spoolss_DevmodeContainer devmode_ctr;
1061 uint32_t num_printers;
1062 union spoolss_PrinterInfo *printer_info;
1063 union spoolss_DriverInfo *driver_info;
1064 union spoolss_JobInfo **job_info;
1066 if (!param_format || !output_format1 || !p) {
1067 return False;
1070 memset((char *)&desc,'\0',sizeof(desc));
1072 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1074 if (!prefix_ok(param_format,"WrLeh")) {
1075 return False;
1077 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1079 * Patch from Scott Moomaw <scott@bridgewater.edu>
1080 * to return the 'invalid info level' error if an
1081 * unknown level was requested.
1083 *rdata_len = 0;
1084 *rparam_len = 6;
1085 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1086 if (!*rparam) {
1087 return False;
1089 SSVALS(*rparam,0,ERRunknownlevel);
1090 SSVAL(*rparam,2,0);
1091 SSVAL(*rparam,4,0);
1092 return(True);
1095 status = rpc_pipe_open_interface(mem_ctx,
1096 &ndr_table_spoolss,
1097 conn->session_info,
1098 conn->sconn->remote_address,
1099 conn->sconn->local_address,
1100 conn->sconn->msg_ctx,
1101 &cli);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1104 nt_errstr(status)));
1105 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1106 goto out;
1108 b = cli->binding_handle;
1110 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1111 PRINTER_ENUM_LOCAL,
1112 cli->srv_name_slash,
1115 &num_printers,
1116 &printer_info);
1117 if (!W_ERROR_IS_OK(werr)) {
1118 desc.errcode = W_ERROR_V(werr);
1119 goto out;
1122 queuecnt = num_printers;
1124 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1125 if (job_info == NULL) {
1126 goto err;
1129 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1130 if (driver_info == NULL) {
1131 goto err;
1134 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1135 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1136 goto err;
1139 if (mdrcnt > 0) {
1140 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1141 if (!*rdata) {
1142 goto err;
1145 desc.base = *rdata;
1146 desc.buflen = mdrcnt;
1148 subcnt = 0;
1149 for (i = 0; i < num_printers; i++) {
1151 uint32_t num_jobs;
1152 struct policy_handle handle;
1153 const char *printername;
1155 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1156 if (printername == NULL) {
1157 goto err;
1160 ZERO_STRUCT(handle);
1161 ZERO_STRUCT(devmode_ctr);
1163 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1164 printername,
1165 "RAW",
1166 devmode_ctr,
1167 PRINTER_ACCESS_USE,
1168 &handle,
1169 &werr);
1170 if (!NT_STATUS_IS_OK(status)) {
1171 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1172 goto out;
1174 if (!W_ERROR_IS_OK(werr)) {
1175 desc.errcode = W_ERROR_V(werr);
1176 goto out;
1179 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1180 &handle,
1181 0, /* firstjob */
1182 0xff, /* numjobs */
1183 2, /* level */
1184 0, /* offered */
1185 &num_jobs,
1186 &job_info[i]);
1187 if (!W_ERROR_IS_OK(werr)) {
1188 desc.errcode = W_ERROR_V(werr);
1189 goto out;
1192 if (uLevel==52) {
1193 uint32_t server_major_version;
1194 uint32_t server_minor_version;
1196 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1197 &handle,
1198 "Windows 4.0",
1199 3, /* level */
1201 0, /* version */
1203 &driver_info[i],
1204 &server_major_version,
1205 &server_minor_version);
1206 if (!W_ERROR_IS_OK(werr)) {
1207 desc.errcode = W_ERROR_V(werr);
1208 goto out;
1212 subcntarr[i] = num_jobs;
1213 subcnt += subcntarr[i];
1215 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1218 if (init_package(&desc,queuecnt,subcnt)) {
1219 for (i = 0; i < num_printers; i++) {
1220 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1221 if (desc.errcode == NERR_Success) {
1222 succnt = i;
1227 out:
1228 SAFE_FREE(subcntarr);
1229 *rdata_len = desc.usedlen;
1230 *rparam_len = 8;
1231 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1232 if (!*rparam) {
1233 goto err;
1235 SSVALS(*rparam,0,desc.errcode);
1236 SSVAL(*rparam,2,0);
1237 SSVAL(*rparam,4,succnt);
1238 SSVAL(*rparam,6,queuecnt);
1240 return True;
1242 err:
1244 SAFE_FREE(subcntarr);
1246 return False;
1249 /****************************************************************************
1250 Get info level for a server list query.
1251 ****************************************************************************/
1253 static bool check_session_info(int uLevel, char* id)
1255 switch( uLevel ) {
1256 case 0:
1257 if (strcmp(id,"B16") != 0) {
1258 return False;
1260 break;
1261 case 1:
1262 if (strcmp(id,"B16BBDz") != 0) {
1263 return False;
1265 break;
1266 default:
1267 return False;
1269 return True;
1272 struct srv_info_struct {
1273 fstring name;
1274 uint32_t type;
1275 fstring comment;
1276 fstring domain;
1277 bool server_added;
1280 /*******************************************************************
1281 Get server info lists from the files saved by nmbd. Return the
1282 number of entries.
1283 ******************************************************************/
1285 static int get_session_info(uint32_t servertype,
1286 struct srv_info_struct **servers,
1287 const char *domain)
1289 int count=0;
1290 int alloced=0;
1291 char **lines;
1292 bool local_list_only;
1293 int i;
1294 char *slist_cache_path = cache_path(talloc_tos(), SERVER_LIST);
1295 if (slist_cache_path == NULL) {
1296 return 0;
1299 lines = file_lines_load(slist_cache_path, NULL, 0, NULL);
1300 if (!lines) {
1301 DEBUG(4, ("Can't open %s - %s\n",
1302 slist_cache_path, strerror(errno)));
1303 TALLOC_FREE(slist_cache_path);
1304 return 0;
1306 TALLOC_FREE(slist_cache_path);
1308 /* request for everything is code for request all servers */
1309 if (servertype == SV_TYPE_ALL) {
1310 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1313 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1315 DEBUG(4,("Servertype search: %8x\n",servertype));
1317 for (i=0;lines[i];i++) {
1318 fstring stype;
1319 struct srv_info_struct *s;
1320 const char *ptr = lines[i];
1321 bool ok = True;
1322 TALLOC_CTX *frame = NULL;
1323 char *p;
1325 if (!*ptr) {
1326 continue;
1329 if (count == alloced) {
1330 alloced += 10;
1331 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1332 if (!*servers) {
1333 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1334 TALLOC_FREE(lines);
1335 return 0;
1337 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1339 s = &(*servers)[count];
1341 frame = talloc_stackframe();
1342 s->name[0] = '\0';
1343 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1344 TALLOC_FREE(frame);
1345 continue;
1347 fstrcpy(s->name, p);
1349 stype[0] = '\0';
1350 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1351 TALLOC_FREE(frame);
1352 continue;
1354 fstrcpy(stype, p);
1356 s->comment[0] = '\0';
1357 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1358 TALLOC_FREE(frame);
1359 continue;
1361 fstrcpy(s->comment, p);
1362 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1364 s->domain[0] = '\0';
1365 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1366 /* this allows us to cope with an old nmbd */
1367 fstrcpy(s->domain,lp_workgroup());
1368 } else {
1369 fstrcpy(s->domain, p);
1371 TALLOC_FREE(frame);
1373 if (sscanf(stype,"%X",&s->type) != 1) {
1374 DEBUG(4,("r:host file "));
1375 ok = False;
1378 /* Filter the servers/domains we return based on what was asked for. */
1380 /* Check to see if we are being asked for a local list only. */
1381 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1382 DEBUG(4,("r: local list only"));
1383 ok = False;
1386 /* doesn't match up: don't want it */
1387 if (!(servertype & s->type)) {
1388 DEBUG(4,("r:serv type "));
1389 ok = False;
1392 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1393 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1394 DEBUG(4,("s: dom mismatch "));
1395 ok = False;
1398 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1399 ok = False;
1402 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1403 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1405 if (ok) {
1406 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1407 s->name, s->type, s->comment, s->domain));
1408 s->server_added = True;
1409 count++;
1410 } else {
1411 DEBUG(4,("%20s %8x %25s %15s\n",
1412 s->name, s->type, s->comment, s->domain));
1416 TALLOC_FREE(lines);
1417 return count;
1420 /*******************************************************************
1421 Fill in a server info structure.
1422 ******************************************************************/
1424 static int fill_srv_info(struct srv_info_struct *service,
1425 int uLevel, char **buf, int *buflen,
1426 char **stringbuf, int *stringspace, char *baseaddr)
1428 int struct_len;
1429 char* p;
1430 char* p2;
1431 int l2;
1432 int len;
1434 switch (uLevel) {
1435 case 0:
1436 struct_len = 16;
1437 break;
1438 case 1:
1439 struct_len = 26;
1440 break;
1441 default:
1442 return -1;
1445 if (!buf) {
1446 len = 0;
1447 switch (uLevel) {
1448 case 1:
1449 len = strlen(service->comment)+1;
1450 break;
1453 *buflen = struct_len;
1454 *stringspace = len;
1455 return struct_len + len;
1458 len = struct_len;
1459 p = *buf;
1460 if (*buflen < struct_len) {
1461 return -1;
1463 if (stringbuf) {
1464 p2 = *stringbuf;
1465 l2 = *stringspace;
1466 } else {
1467 p2 = p + struct_len;
1468 l2 = *buflen - struct_len;
1470 if (!baseaddr) {
1471 baseaddr = p;
1474 switch (uLevel) {
1475 case 0:
1476 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1477 break;
1479 case 1:
1480 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1481 SIVAL(p,18,service->type);
1482 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1483 len += CopyAndAdvance(&p2,service->comment,&l2);
1484 break;
1487 if (stringbuf) {
1488 *buf = p + struct_len;
1489 *buflen -= struct_len;
1490 *stringbuf = p2;
1491 *stringspace = l2;
1492 } else {
1493 *buf = p2;
1494 *buflen -= len;
1496 return len;
1500 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1502 return strcasecmp_m(s1->name,s2->name);
1505 /****************************************************************************
1506 View list of servers available (or possibly domains). The info is
1507 extracted from lists saved by nmbd on the local host.
1508 ****************************************************************************/
1510 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1511 connection_struct *conn, uint64_t vuid,
1512 char *param, int tpscnt,
1513 char *data, int tdscnt,
1514 int mdrcnt, int mprcnt, char **rdata,
1515 char **rparam, int *rdata_len, int *rparam_len)
1517 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1518 char *str2 = skip_string(param,tpscnt,str1);
1519 char *p = skip_string(param,tpscnt,str2);
1520 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1521 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1522 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1523 char *p2;
1524 int data_len, fixed_len, string_len;
1525 int f_len = 0, s_len = 0;
1526 struct srv_info_struct *servers=NULL;
1527 int counted=0,total=0;
1528 int i,missed;
1529 fstring domain;
1530 bool domain_request;
1531 bool local_request;
1533 if (!str1 || !str2 || !p) {
1534 return False;
1537 /* If someone sets all the bits they don't really mean to set
1538 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1539 known servers. */
1541 if (servertype == SV_TYPE_ALL) {
1542 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1545 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1546 any other bit (they may just set this bit on its own) they
1547 want all the locally seen servers. However this bit can be
1548 set on its own so set the requested servers to be
1549 ALL - DOMAIN_ENUM. */
1551 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1552 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1555 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1556 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1558 p += 8;
1560 if (!prefix_ok(str1,"WrLehD")) {
1561 return False;
1563 if (!check_session_info(uLevel,str2)) {
1564 return False;
1567 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1568 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1569 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1571 if (strcmp(str1, "WrLehDz") == 0) {
1572 if (skip_string(param,tpscnt,p) == NULL) {
1573 return False;
1575 pull_ascii_fstring(domain, p);
1576 } else {
1577 fstrcpy(domain, lp_workgroup());
1580 DEBUG(4, ("domain [%s]\n", domain));
1582 if (lp_browse_list()) {
1583 total = get_session_info(servertype,&servers,domain);
1586 data_len = fixed_len = string_len = 0;
1587 missed = 0;
1589 TYPESAFE_QSORT(servers, total, srv_comp);
1592 char *lastname=NULL;
1594 for (i=0;i<total;i++) {
1595 struct srv_info_struct *s = &servers[i];
1597 if (lastname && strequal(lastname,s->name)) {
1598 continue;
1600 lastname = s->name;
1601 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1602 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1603 i, s->name, s->type, s->comment, s->domain));
1605 if (data_len < buf_len) {
1606 counted++;
1607 fixed_len += f_len;
1608 string_len += s_len;
1609 } else {
1610 missed++;
1615 *rdata_len = fixed_len + string_len;
1616 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1617 if (!*rdata) {
1618 return False;
1621 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1622 p = *rdata;
1623 f_len = fixed_len;
1624 s_len = string_len;
1627 char *lastname=NULL;
1628 int count2 = counted;
1630 for (i = 0; i < total && count2;i++) {
1631 struct srv_info_struct *s = &servers[i];
1633 if (lastname && strequal(lastname,s->name)) {
1634 continue;
1636 lastname = s->name;
1637 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1638 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1639 i, s->name, s->type, s->comment, s->domain));
1640 count2--;
1644 *rparam_len = 8;
1645 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1646 if (!*rparam) {
1647 return False;
1649 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1650 SSVAL(*rparam,2,0);
1651 SSVAL(*rparam,4,counted);
1652 SSVAL(*rparam,6,counted+missed);
1654 SAFE_FREE(servers);
1656 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1657 domain,uLevel,counted,counted+missed));
1659 return True;
1662 static int srv_name_match(const char *n1, const char *n2)
1665 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1667 * In Windows, FirstNameToReturn need not be an exact match:
1668 * the server will return a list of servers that exist on
1669 * the network greater than or equal to the FirstNameToReturn.
1671 int ret = strcasecmp_m(n1, n2);
1673 if (ret <= 0) {
1674 return 0;
1677 return ret;
1680 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1681 connection_struct *conn, uint64_t vuid,
1682 char *param, int tpscnt,
1683 char *data, int tdscnt,
1684 int mdrcnt, int mprcnt, char **rdata,
1685 char **rparam, int *rdata_len, int *rparam_len)
1687 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1688 char *str2 = skip_string(param,tpscnt,str1);
1689 char *p = skip_string(param,tpscnt,str2);
1690 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1691 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1692 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1693 char *p2;
1694 int data_len, fixed_len, string_len;
1695 int f_len = 0, s_len = 0;
1696 struct srv_info_struct *servers=NULL;
1697 int counted=0,first=0,total=0;
1698 int i,missed;
1699 fstring domain;
1700 fstring first_name;
1701 bool domain_request;
1702 bool local_request;
1704 if (!str1 || !str2 || !p) {
1705 return False;
1708 /* If someone sets all the bits they don't really mean to set
1709 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1710 known servers. */
1712 if (servertype == SV_TYPE_ALL) {
1713 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1716 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1717 any other bit (they may just set this bit on its own) they
1718 want all the locally seen servers. However this bit can be
1719 set on its own so set the requested servers to be
1720 ALL - DOMAIN_ENUM. */
1722 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1723 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1726 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1727 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1729 p += 8;
1731 if (strcmp(str1, "WrLehDzz") != 0) {
1732 return false;
1734 if (!check_session_info(uLevel,str2)) {
1735 return False;
1738 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1739 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1740 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1742 if (skip_string(param,tpscnt,p) == NULL) {
1743 return False;
1745 pull_ascii_fstring(domain, p);
1746 if (domain[0] == '\0') {
1747 fstrcpy(domain, lp_workgroup());
1749 p = skip_string(param,tpscnt,p);
1750 if (skip_string(param,tpscnt,p) == NULL) {
1751 return False;
1753 pull_ascii_fstring(first_name, p);
1755 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1756 domain, first_name));
1758 if (lp_browse_list()) {
1759 total = get_session_info(servertype,&servers,domain);
1762 data_len = fixed_len = string_len = 0;
1763 missed = 0;
1765 TYPESAFE_QSORT(servers, total, srv_comp);
1767 if (first_name[0] != '\0') {
1768 struct srv_info_struct *first_server = NULL;
1770 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1771 srv_name_match, first_server);
1772 if (first_server) {
1773 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1775 * The binary search may not find the exact match
1776 * so we need to search backward to find the first match
1778 * This implements the strange matching windows
1779 * implements. (see the comment in srv_name_match().
1781 for (;first > 0;) {
1782 int ret;
1783 ret = strcasecmp_m(first_name,
1784 servers[first-1].name);
1785 if (ret > 0) {
1786 break;
1788 first--;
1790 } else {
1791 /* we should return no entries */
1792 first = total;
1797 char *lastname=NULL;
1799 for (i=first;i<total;i++) {
1800 struct srv_info_struct *s = &servers[i];
1802 if (lastname && strequal(lastname,s->name)) {
1803 continue;
1805 lastname = s->name;
1806 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1807 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1808 i, s->name, s->type, s->comment, s->domain));
1810 if (data_len < buf_len) {
1811 counted++;
1812 fixed_len += f_len;
1813 string_len += s_len;
1814 } else {
1815 missed++;
1820 *rdata_len = fixed_len + string_len;
1821 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1822 if (!*rdata) {
1823 return False;
1826 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1827 p = *rdata;
1828 f_len = fixed_len;
1829 s_len = string_len;
1832 char *lastname=NULL;
1833 int count2 = counted;
1835 for (i = first; i < total && count2;i++) {
1836 struct srv_info_struct *s = &servers[i];
1838 if (lastname && strequal(lastname,s->name)) {
1839 continue;
1841 lastname = s->name;
1842 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1843 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1844 i, s->name, s->type, s->comment, s->domain));
1845 count2--;
1849 *rparam_len = 8;
1850 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1851 if (!*rparam) {
1852 return False;
1854 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1855 SSVAL(*rparam,2,0);
1856 SSVAL(*rparam,4,counted);
1857 SSVAL(*rparam,6,counted+missed);
1859 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1860 domain,uLevel,first,first_name,
1861 first < total ? servers[first].name : "",
1862 counted,counted+missed));
1864 SAFE_FREE(servers);
1866 return True;
1869 /****************************************************************************
1870 command 0x34 - suspected of being a "Lookup Names" stub api
1871 ****************************************************************************/
1873 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1874 connection_struct *conn, uint64_t vuid,
1875 char *param, int tpscnt,
1876 char *data, int tdscnt,
1877 int mdrcnt, int mprcnt, char **rdata,
1878 char **rparam, int *rdata_len, int *rparam_len)
1880 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1881 char *str2 = skip_string(param,tpscnt,str1);
1882 char *p = skip_string(param,tpscnt,str2);
1883 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1884 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1885 int counted=0;
1886 int missed=0;
1888 if (!str1 || !str2 || !p) {
1889 return False;
1892 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1893 str1, str2, p, uLevel, buf_len));
1895 if (!prefix_ok(str1,"zWrLeh")) {
1896 return False;
1899 *rdata_len = 0;
1901 *rparam_len = 8;
1902 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1903 if (!*rparam) {
1904 return False;
1907 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1908 SSVAL(*rparam,2,0);
1909 SSVAL(*rparam,4,counted);
1910 SSVAL(*rparam,6,counted+missed);
1912 return True;
1915 /****************************************************************************
1916 get info about a share
1917 ****************************************************************************/
1919 static bool check_share_info(int uLevel, char* id)
1921 switch( uLevel ) {
1922 case 0:
1923 if (strcmp(id,"B13") != 0) {
1924 return False;
1926 break;
1927 case 1:
1928 /* Level-2 descriptor is allowed (and ignored) */
1929 if (strcmp(id,"B13BWz") != 0 &&
1930 strcmp(id,"B13BWzWWWzB9B") != 0) {
1931 return False;
1933 break;
1934 case 2:
1935 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1936 return False;
1938 break;
1939 case 91:
1940 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1941 return False;
1943 break;
1944 default:
1945 return False;
1947 return True;
1950 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1951 char** buf, int* buflen,
1952 char** stringbuf, int* stringspace, char* baseaddr)
1954 const struct loadparm_substitution *lp_sub =
1955 loadparm_s3_global_substitution();
1956 int struct_len;
1957 char* p;
1958 char* p2;
1959 int l2;
1960 int len;
1962 switch( uLevel ) {
1963 case 0:
1964 struct_len = 13;
1965 break;
1966 case 1:
1967 struct_len = 20;
1968 break;
1969 case 2:
1970 struct_len = 40;
1971 break;
1972 case 91:
1973 struct_len = 68;
1974 break;
1975 default:
1976 return -1;
1979 if (!buf) {
1980 len = 0;
1982 if (uLevel > 0) {
1983 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), lp_sub, snum));
1985 if (uLevel > 1) {
1986 len += strlen(lp_path(talloc_tos(), lp_sub, snum)) + 1;
1988 if (buflen) {
1989 *buflen = struct_len;
1991 if (stringspace) {
1992 *stringspace = len;
1994 return struct_len + len;
1997 len = struct_len;
1998 p = *buf;
1999 if ((*buflen) < struct_len) {
2000 return -1;
2003 if (stringbuf) {
2004 p2 = *stringbuf;
2005 l2 = *stringspace;
2006 } else {
2007 p2 = p + struct_len;
2008 l2 = (*buflen) - struct_len;
2011 if (!baseaddr) {
2012 baseaddr = p;
2015 push_ascii(p,lp_servicename(talloc_tos(), lp_sub, snum),13, STR_TERMINATE);
2017 if (uLevel > 0) {
2018 int type;
2020 SCVAL(p,13,0);
2021 type = STYPE_DISKTREE;
2022 if (lp_printable(snum)) {
2023 type = STYPE_PRINTQ;
2025 if (strequal("IPC",lp_fstype(snum))) {
2026 type = STYPE_IPC;
2028 SSVAL(p,14,type); /* device type */
2029 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
2030 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(), lp_sub, snum),&l2);
2033 if (uLevel > 1) {
2034 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
2035 SSVALS(p,22,-1); /* max uses */
2036 SSVAL(p,24,1); /* current uses */
2037 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
2038 len += CopyAndAdvance(&p2,lp_path(talloc_tos(),lp_sub, snum),&l2);
2039 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
2042 if (uLevel > 2) {
2043 memset(p+40,0,SHPWLEN+2);
2044 SSVAL(p,50,0);
2045 SIVAL(p,52,0);
2046 SSVAL(p,56,0);
2047 SSVAL(p,58,0);
2048 SIVAL(p,60,0);
2049 SSVAL(p,64,0);
2050 SSVAL(p,66,0);
2053 if (stringbuf) {
2054 (*buf) = p + struct_len;
2055 (*buflen) -= struct_len;
2056 (*stringbuf) = p2;
2057 (*stringspace) = l2;
2058 } else {
2059 (*buf) = p2;
2060 (*buflen) -= len;
2063 return len;
2066 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
2067 connection_struct *conn,uint64_t vuid,
2068 char *param, int tpscnt,
2069 char *data, int tdscnt,
2070 int mdrcnt,int mprcnt,
2071 char **rdata,char **rparam,
2072 int *rdata_len,int *rparam_len)
2074 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2075 char *str2 = skip_string(param,tpscnt,str1);
2076 char *netname_in = skip_string(param,tpscnt,str2);
2077 char *netname = NULL;
2078 char *p = skip_string(param,tpscnt,netname);
2079 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2080 int snum;
2082 if (!str1 || !str2 || !netname_in || !p) {
2083 return False;
2086 snum = find_service(talloc_tos(), netname_in, &netname);
2087 if (snum < 0 || !netname) {
2088 return False;
2091 /* check it's a supported varient */
2092 if (!prefix_ok(str1,"zWrLh")) {
2093 return False;
2095 if (!check_share_info(uLevel,str2)) {
2096 return False;
2099 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2100 if (!*rdata) {
2101 return False;
2103 p = *rdata;
2104 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2105 if (*rdata_len < 0) {
2106 return False;
2109 *rparam_len = 6;
2110 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2111 if (!*rparam) {
2112 return False;
2114 SSVAL(*rparam,0,NERR_Success);
2115 SSVAL(*rparam,2,0); /* converter word */
2116 SSVAL(*rparam,4,*rdata_len);
2118 return True;
2121 /****************************************************************************
2122 View the list of available shares.
2124 This function is the server side of the NetShareEnum() RAP call.
2125 It fills the return buffer with share names and share comments.
2126 Note that the return buffer normally (in all known cases) allows only
2127 twelve byte strings for share names (plus one for a nul terminator).
2128 Share names longer than 12 bytes must be skipped.
2129 ****************************************************************************/
2131 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2132 connection_struct *conn, uint64_t vuid,
2133 char *param, int tpscnt,
2134 char *data, int tdscnt,
2135 int mdrcnt,
2136 int mprcnt,
2137 char **rdata,
2138 char **rparam,
2139 int *rdata_len,
2140 int *rparam_len )
2142 const struct loadparm_substitution *lp_sub =
2143 loadparm_s3_global_substitution();
2144 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2145 char *str2 = skip_string(param,tpscnt,str1);
2146 char *p = skip_string(param,tpscnt,str2);
2147 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2148 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2149 char *p2;
2150 int count = 0;
2151 int total=0,counted=0;
2152 bool missed = False;
2153 int i;
2154 int data_len, fixed_len, string_len;
2155 int f_len = 0, s_len = 0;
2157 if (!str1 || !str2 || !p) {
2158 return False;
2161 if (!prefix_ok(str1,"WrLeh")) {
2162 return False;
2164 if (!check_share_info(uLevel,str2)) {
2165 return False;
2168 /* Ensure all the usershares are loaded. */
2169 become_root();
2170 delete_and_reload_printers();
2171 load_registry_shares();
2172 count = load_usershare_shares(NULL, connections_snum_used);
2173 unbecome_root();
2175 data_len = fixed_len = string_len = 0;
2176 for (i=0;i<count;i++) {
2177 fstring servicename_dos;
2178 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2179 continue;
2181 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), lp_sub, i));
2182 /* Maximum name length = 13. */
2183 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2184 total++;
2185 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2186 if (data_len < buf_len) {
2187 counted++;
2188 fixed_len += f_len;
2189 string_len += s_len;
2190 } else {
2191 missed = True;
2196 *rdata_len = fixed_len + string_len;
2197 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2198 if (!*rdata) {
2199 return False;
2202 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2203 p = *rdata;
2204 f_len = fixed_len;
2205 s_len = string_len;
2207 for( i = 0; i < count; i++ ) {
2208 fstring servicename_dos;
2209 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2210 continue;
2213 push_ascii_fstring(servicename_dos,
2214 lp_servicename(talloc_tos(), lp_sub, i));
2215 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2216 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2217 break;
2222 *rparam_len = 8;
2223 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2224 if (!*rparam) {
2225 return False;
2227 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2228 SSVAL(*rparam,2,0);
2229 SSVAL(*rparam,4,counted);
2230 SSVAL(*rparam,6,total);
2232 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2233 counted,total,uLevel,
2234 buf_len,*rdata_len,mdrcnt));
2236 return True;
2239 /****************************************************************************
2240 Add a share
2241 ****************************************************************************/
2243 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2244 connection_struct *conn,uint64_t vuid,
2245 char *param, int tpscnt,
2246 char *data, int tdscnt,
2247 int mdrcnt,int mprcnt,
2248 char **rdata,char **rparam,
2249 int *rdata_len,int *rparam_len)
2251 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2252 char *str2 = skip_string(param,tpscnt,str1);
2253 char *p = skip_string(param,tpscnt,str2);
2254 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2255 fstring sharename;
2256 fstring comment;
2257 char *pathname = NULL;
2258 unsigned int offset;
2259 int res = ERRunsup;
2260 size_t converted_size;
2262 WERROR werr = WERR_OK;
2263 TALLOC_CTX *mem_ctx = talloc_tos();
2264 NTSTATUS status;
2265 struct rpc_pipe_client *cli = NULL;
2266 union srvsvc_NetShareInfo info;
2267 struct srvsvc_NetShareInfo2 info2;
2268 struct dcerpc_binding_handle *b;
2270 if (!str1 || !str2 || !p) {
2271 return False;
2274 /* check it's a supported varient */
2275 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2276 return False;
2278 if (!check_share_info(uLevel,str2)) {
2279 return False;
2281 if (uLevel != 2) {
2282 return False;
2285 /* Do we have a string ? */
2286 if (skip_string(data,mdrcnt,data) == NULL) {
2287 return False;
2289 pull_ascii_fstring(sharename,data);
2291 if (mdrcnt < 28) {
2292 return False;
2295 /* only support disk share adds */
2296 if (SVAL(data,14)!=STYPE_DISKTREE) {
2297 return False;
2300 offset = IVAL(data, 16);
2301 if (offset >= mdrcnt) {
2302 res = ERRinvalidparam;
2303 goto out;
2306 /* Do we have a string ? */
2307 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2308 return False;
2310 pull_ascii_fstring(comment, offset? (data+offset) : "");
2312 offset = IVAL(data, 26);
2314 if (offset >= mdrcnt) {
2315 res = ERRinvalidparam;
2316 goto out;
2319 /* Do we have a string ? */
2320 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2321 return False;
2324 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2325 offset ? (data+offset) : "", &converted_size))
2327 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2328 strerror(errno)));
2331 if (!pathname) {
2332 return false;
2335 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
2336 conn->session_info,
2337 conn->sconn->remote_address,
2338 conn->sconn->local_address,
2339 conn->sconn->msg_ctx,
2340 &cli);
2341 if (!NT_STATUS_IS_OK(status)) {
2342 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2343 nt_errstr(status)));
2344 res = W_ERROR_V(ntstatus_to_werror(status));
2345 goto out;
2348 b = cli->binding_handle;
2350 info2.name = sharename;
2351 info2.type = STYPE_DISKTREE;
2352 info2.comment = comment;
2353 info2.permissions = 0;
2354 info2.max_users = 0;
2355 info2.current_users = 0;
2356 info2.path = pathname;
2357 info2.password = NULL;
2359 info.info2 = &info2;
2361 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2362 cli->srv_name_slash,
2364 &info,
2365 NULL,
2366 &werr);
2367 if (!NT_STATUS_IS_OK(status)) {
2368 res = W_ERROR_V(ntstatus_to_werror(status));
2369 goto out;
2371 if (!W_ERROR_IS_OK(werr)) {
2372 res = W_ERROR_V(werr);
2373 goto out;
2376 *rparam_len = 6;
2377 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2378 if (!*rparam) {
2379 return False;
2381 SSVAL(*rparam,0,NERR_Success);
2382 SSVAL(*rparam,2,0); /* converter word */
2383 SSVAL(*rparam,4,*rdata_len);
2384 *rdata_len = 0;
2386 return True;
2388 out:
2390 *rparam_len = 4;
2391 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2392 if (!*rparam) {
2393 return False;
2395 *rdata_len = 0;
2396 SSVAL(*rparam,0,res);
2397 SSVAL(*rparam,2,0);
2398 return True;
2401 /****************************************************************************
2402 view list of groups available
2403 ****************************************************************************/
2405 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2406 connection_struct *conn,uint64_t vuid,
2407 char *param, int tpscnt,
2408 char *data, int tdscnt,
2409 int mdrcnt,int mprcnt,
2410 char **rdata,char **rparam,
2411 int *rdata_len,int *rparam_len)
2413 int i;
2414 int errflags=0;
2415 int resume_context, cli_buf_size;
2416 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2417 char *str2 = skip_string(param,tpscnt,str1);
2418 char *p = skip_string(param,tpscnt,str2);
2420 uint32_t num_groups;
2421 uint32_t resume_handle;
2422 struct rpc_pipe_client *samr_pipe = NULL;
2423 struct policy_handle samr_handle, domain_handle;
2424 NTSTATUS status, result;
2425 struct dcerpc_binding_handle *b;
2427 if (!str1 || !str2 || !p) {
2428 return False;
2431 if (strcmp(str1,"WrLeh") != 0) {
2432 return False;
2435 /* parameters
2436 * W-> resume context (number of users to skip)
2437 * r -> return parameter pointer to receive buffer
2438 * L -> length of receive buffer
2439 * e -> return parameter number of entries
2440 * h -> return parameter total number of users
2443 if (strcmp("B21",str2) != 0) {
2444 return False;
2447 status = rpc_pipe_open_interface(
2448 talloc_tos(), &ndr_table_samr,
2449 conn->session_info, conn->sconn->remote_address,
2450 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2451 if (!NT_STATUS_IS_OK(status)) {
2452 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2453 nt_errstr(status)));
2454 return false;
2457 b = samr_pipe->binding_handle;
2459 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2460 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2461 &result);
2462 if (!NT_STATUS_IS_OK(status)) {
2463 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2464 nt_errstr(status)));
2465 return false;
2467 if (!NT_STATUS_IS_OK(result)) {
2468 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2469 nt_errstr(result)));
2470 return false;
2473 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2474 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2475 get_global_sam_sid(), &domain_handle,
2476 &result);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2479 nt_errstr(status)));
2480 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2481 return false;
2483 if (!NT_STATUS_IS_OK(result)) {
2484 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2485 nt_errstr(result)));
2486 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2487 return false;
2490 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2491 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2492 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2493 "%d\n", resume_context, cli_buf_size));
2495 *rdata_len = cli_buf_size;
2496 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2497 if (!*rdata) {
2498 return False;
2501 p = *rdata;
2503 errflags = NERR_Success;
2504 num_groups = 0;
2505 resume_handle = 0;
2507 while (true) {
2508 struct samr_SamArray *sam_entries;
2509 uint32_t num_entries;
2511 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2512 &domain_handle,
2513 &resume_handle,
2514 &sam_entries, 1,
2515 &num_entries,
2516 &result);
2517 if (!NT_STATUS_IS_OK(status)) {
2518 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2519 "%s\n", nt_errstr(status)));
2520 break;
2522 if (!NT_STATUS_IS_OK(result)) {
2523 status = result;
2524 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2525 "%s\n", nt_errstr(result)));
2526 break;
2529 if (num_entries == 0) {
2530 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2531 "no entries -- done\n"));
2532 break;
2535 for(i=0; i<num_entries; i++) {
2536 const char *name;
2538 name = sam_entries->entries[i].name.string;
2540 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2541 /* set overflow error */
2542 DEBUG(3,("overflow on entry %d group %s\n", i,
2543 name));
2544 errflags=234;
2545 break;
2548 /* truncate the name at 21 chars. */
2549 memset(p, 0, 21);
2550 strlcpy(p, name, 21);
2551 DEBUG(10,("adding entry %d group %s\n", i, p));
2552 p += 21;
2553 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2554 * idea why... */
2555 num_groups += 1;
2558 if (errflags != NERR_Success) {
2559 break;
2562 TALLOC_FREE(sam_entries);
2565 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2566 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2568 *rdata_len = PTR_DIFF(p,*rdata);
2570 *rparam_len = 8;
2571 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2572 if (!*rparam) {
2573 return False;
2575 SSVAL(*rparam, 0, errflags);
2576 SSVAL(*rparam, 2, 0); /* converter word */
2577 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2578 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2580 return(True);
2583 /*******************************************************************
2584 Get groups that a user is a member of.
2585 ******************************************************************/
2587 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2588 connection_struct *conn,uint64_t vuid,
2589 char *param, int tpscnt,
2590 char *data, int tdscnt,
2591 int mdrcnt,int mprcnt,
2592 char **rdata,char **rparam,
2593 int *rdata_len,int *rparam_len)
2595 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2596 char *str2 = skip_string(param,tpscnt,str1);
2597 char *UserName = skip_string(param,tpscnt,str2);
2598 char *p = skip_string(param,tpscnt,UserName);
2599 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2600 const char *level_string;
2601 int count=0;
2602 bool ret = False;
2603 uint32_t i;
2604 char *endp = NULL;
2606 struct rpc_pipe_client *samr_pipe = NULL;
2607 struct policy_handle samr_handle, domain_handle, user_handle;
2608 struct lsa_String name;
2609 struct lsa_Strings names;
2610 struct samr_Ids type, rid;
2611 struct samr_RidWithAttributeArray *rids;
2612 NTSTATUS status, result;
2613 struct dcerpc_binding_handle *b;
2615 if (!str1 || !str2 || !UserName || !p) {
2616 return False;
2619 *rparam_len = 8;
2620 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2621 if (!*rparam) {
2622 return False;
2625 /* check it's a supported varient */
2627 if ( strcmp(str1,"zWrLeh") != 0 )
2628 return False;
2630 switch( uLevel ) {
2631 case 0:
2632 level_string = "B21";
2633 break;
2634 default:
2635 return False;
2638 if (strcmp(level_string,str2) != 0)
2639 return False;
2641 *rdata_len = mdrcnt + 1024;
2642 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2643 if (!*rdata) {
2644 return False;
2647 SSVAL(*rparam,0,NERR_Success);
2648 SSVAL(*rparam,2,0); /* converter word */
2650 p = *rdata;
2651 endp = *rdata + *rdata_len;
2653 status = rpc_pipe_open_interface(
2654 talloc_tos(), &ndr_table_samr,
2655 conn->session_info, conn->sconn->remote_address,
2656 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2657 if (!NT_STATUS_IS_OK(status)) {
2658 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2659 nt_errstr(status)));
2660 return false;
2663 b = samr_pipe->binding_handle;
2665 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2666 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2667 &result);
2668 if (!NT_STATUS_IS_OK(status)) {
2669 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2670 nt_errstr(status)));
2671 return false;
2673 if (!NT_STATUS_IS_OK(result)) {
2674 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2675 nt_errstr(result)));
2676 return false;
2679 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2680 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2681 get_global_sam_sid(), &domain_handle,
2682 &result);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2685 nt_errstr(status)));
2686 goto close_sam;
2688 if (!NT_STATUS_IS_OK(result)) {
2689 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2690 nt_errstr(result)));
2691 goto close_sam;
2694 name.string = UserName;
2696 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2697 &domain_handle, 1, &name,
2698 &rid, &type,
2699 &result);
2700 if (!NT_STATUS_IS_OK(status)) {
2701 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2702 nt_errstr(status)));
2703 goto close_domain;
2705 if (!NT_STATUS_IS_OK(result)) {
2706 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2707 nt_errstr(result)));
2708 goto close_domain;
2710 if (rid.count != 1) {
2711 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2712 goto close_domain;
2714 if (type.count != 1) {
2715 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2716 goto close_domain;
2719 if (type.ids[0] != SID_NAME_USER) {
2720 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2721 sid_type_lookup(type.ids[0])));
2722 goto close_domain;
2725 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2726 &domain_handle,
2727 SAMR_USER_ACCESS_GET_GROUPS,
2728 rid.ids[0], &user_handle,
2729 &result);
2730 if (!NT_STATUS_IS_OK(status)) {
2731 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2732 nt_errstr(status)));
2733 goto close_domain;
2735 if (!NT_STATUS_IS_OK(result)) {
2736 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2737 nt_errstr(result)));
2738 goto close_domain;
2741 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2742 &user_handle, &rids,
2743 &result);
2744 if (!NT_STATUS_IS_OK(status)) {
2745 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2746 nt_errstr(status)));
2747 goto close_user;
2749 if (!NT_STATUS_IS_OK(result)) {
2750 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2751 nt_errstr(result)));
2752 goto close_user;
2755 for (i=0; i<rids->count; i++) {
2757 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2758 &domain_handle,
2759 1, &rids->rids[i].rid,
2760 &names, &type,
2761 &result);
2762 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2763 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2764 p += 21;
2765 count++;
2769 *rdata_len = PTR_DIFF(p,*rdata);
2771 SSVAL(*rparam,4,count); /* is this right?? */
2772 SSVAL(*rparam,6,count); /* is this right?? */
2774 ret = True;
2776 close_user:
2777 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2778 close_domain:
2779 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2780 close_sam:
2781 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2783 return ret;
2786 /*******************************************************************
2787 Get all users.
2788 ******************************************************************/
2790 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2791 connection_struct *conn, uint64_t vuid,
2792 char *param, int tpscnt,
2793 char *data, int tdscnt,
2794 int mdrcnt,int mprcnt,
2795 char **rdata,char **rparam,
2796 int *rdata_len,int *rparam_len)
2798 int count_sent=0;
2799 int num_users=0;
2800 int errflags=0;
2801 int i, resume_context, cli_buf_size;
2802 uint32_t resume_handle;
2804 struct rpc_pipe_client *samr_pipe = NULL;
2805 struct policy_handle samr_handle, domain_handle;
2806 NTSTATUS status, result;
2808 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2809 char *str2 = skip_string(param,tpscnt,str1);
2810 char *p = skip_string(param,tpscnt,str2);
2811 char *endp = NULL;
2813 struct dcerpc_binding_handle *b;
2815 if (!str1 || !str2 || !p) {
2816 return False;
2819 if (strcmp(str1,"WrLeh") != 0)
2820 return False;
2821 /* parameters
2822 * W-> resume context (number of users to skip)
2823 * r -> return parameter pointer to receive buffer
2824 * L -> length of receive buffer
2825 * e -> return parameter number of entries
2826 * h -> return parameter total number of users
2829 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2830 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2831 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2832 resume_context, cli_buf_size));
2834 *rparam_len = 8;
2835 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2836 if (!*rparam) {
2837 return False;
2840 /* check it's a supported varient */
2841 if (strcmp("B21",str2) != 0)
2842 return False;
2844 *rdata_len = cli_buf_size;
2845 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2846 if (!*rdata) {
2847 return False;
2850 p = *rdata;
2851 endp = *rdata + *rdata_len;
2853 status = rpc_pipe_open_interface(
2854 talloc_tos(), &ndr_table_samr,
2855 conn->session_info, conn->sconn->remote_address,
2856 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2857 if (!NT_STATUS_IS_OK(status)) {
2858 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2859 nt_errstr(status)));
2860 return false;
2863 b = samr_pipe->binding_handle;
2865 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2866 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2867 &result);
2868 if (!NT_STATUS_IS_OK(status)) {
2869 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2870 nt_errstr(status)));
2871 return false;
2873 if (!NT_STATUS_IS_OK(result)) {
2874 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2875 nt_errstr(result)));
2876 return false;
2879 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2880 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2881 get_global_sam_sid(), &domain_handle,
2882 &result);
2883 if (!NT_STATUS_IS_OK(status)) {
2884 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2885 nt_errstr(status)));
2886 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2887 return false;
2889 if (!NT_STATUS_IS_OK(result)) {
2890 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2891 nt_errstr(result)));
2892 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2893 return false;
2896 errflags=NERR_Success;
2898 resume_handle = 0;
2900 while (true) {
2901 struct samr_SamArray *sam_entries;
2902 uint32_t num_entries;
2904 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2905 &domain_handle,
2906 &resume_handle,
2907 0, &sam_entries, 1,
2908 &num_entries,
2909 &result);
2911 if (!NT_STATUS_IS_OK(status)) {
2912 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2913 "%s\n", nt_errstr(status)));
2914 break;
2916 if (!NT_STATUS_IS_OK(result)) {
2917 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2918 "%s\n", nt_errstr(result)));
2919 break;
2922 if (num_entries == 0) {
2923 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2924 "no entries -- done\n"));
2925 break;
2928 for (i=0; i<num_entries; i++) {
2929 const char *name;
2931 name = sam_entries->entries[i].name.string;
2933 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2934 &&(strlen(name)<=21)) {
2935 strlcpy(p,name,PTR_DIFF(endp,p));
2936 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2937 "username %s\n",count_sent,p));
2938 p += 21;
2939 count_sent++;
2940 } else {
2941 /* set overflow error */
2942 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2943 "username %s\n",count_sent,name));
2944 errflags=234;
2945 break;
2949 if (errflags != NERR_Success) {
2950 break;
2953 TALLOC_FREE(sam_entries);
2956 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2957 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2959 *rdata_len = PTR_DIFF(p,*rdata);
2961 SSVAL(*rparam,0,errflags);
2962 SSVAL(*rparam,2,0); /* converter word */
2963 SSVAL(*rparam,4,count_sent); /* is this right?? */
2964 SSVAL(*rparam,6,num_users); /* is this right?? */
2966 return True;
2969 /****************************************************************************
2970 Get the time of day info.
2971 ****************************************************************************/
2973 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2974 connection_struct *conn,uint64_t vuid,
2975 char *param, int tpscnt,
2976 char *data, int tdscnt,
2977 int mdrcnt,int mprcnt,
2978 char **rdata,char **rparam,
2979 int *rdata_len,int *rparam_len)
2981 struct tm *t;
2982 time_t unixdate = time(NULL);
2983 char *p;
2985 *rparam_len = 4;
2986 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2987 if (!*rparam) {
2988 return False;
2991 *rdata_len = 21;
2992 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2993 if (!*rdata) {
2994 return False;
2997 SSVAL(*rparam,0,NERR_Success);
2998 SSVAL(*rparam,2,0); /* converter word */
3000 p = *rdata;
3002 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
3003 by NT in a "net time" operation,
3004 it seems to ignore the one below */
3006 /* the client expects to get localtime, not GMT, in this bit
3007 (I think, this needs testing) */
3008 t = localtime(&unixdate);
3009 if (!t) {
3010 return False;
3013 SIVAL(p,4,0); /* msecs ? */
3014 SCVAL(p,8,t->tm_hour);
3015 SCVAL(p,9,t->tm_min);
3016 SCVAL(p,10,t->tm_sec);
3017 SCVAL(p,11,0); /* hundredths of seconds */
3018 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
3019 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
3020 SCVAL(p,16,t->tm_mday);
3021 SCVAL(p,17,t->tm_mon + 1);
3022 SSVAL(p,18,1900+t->tm_year);
3023 SCVAL(p,20,t->tm_wday);
3025 return True;
3028 /****************************************************************************
3029 Set the user password (SamOEM version - gets plaintext).
3030 ****************************************************************************/
3032 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3033 connection_struct *conn,uint64_t vuid,
3034 char *param, int tpscnt,
3035 char *data, int tdscnt,
3036 int mdrcnt,int mprcnt,
3037 char **rdata,char **rparam,
3038 int *rdata_len,int *rparam_len)
3040 fstring user;
3041 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3043 TALLOC_CTX *mem_ctx = talloc_tos();
3044 NTSTATUS status, result;
3045 struct rpc_pipe_client *cli = NULL;
3046 struct lsa_AsciiString server, account;
3047 struct samr_CryptPassword password;
3048 struct samr_Password hash;
3049 int errcode = NERR_badpass;
3050 int bufsize;
3051 struct dcerpc_binding_handle *b;
3053 *rparam_len = 4;
3054 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3055 if (!*rparam) {
3056 return False;
3059 if (!p) {
3060 return False;
3062 *rdata_len = 0;
3064 SSVAL(*rparam,0,NERR_badpass);
3067 * Check the parameter definition is correct.
3070 /* Do we have a string ? */
3071 if (skip_string(param,tpscnt,p) == 0) {
3072 return False;
3074 if(!strequal(p, "zsT")) {
3075 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3076 return False;
3078 p = skip_string(param, tpscnt, p);
3079 if (!p) {
3080 return False;
3083 /* Do we have a string ? */
3084 if (skip_string(param,tpscnt,p) == 0) {
3085 return False;
3087 if(!strequal(p, "B516B16")) {
3088 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3089 return False;
3091 p = skip_string(param,tpscnt,p);
3092 if (!p) {
3093 return False;
3095 /* Do we have a string ? */
3096 if (skip_string(param,tpscnt,p) == 0) {
3097 return False;
3099 p += pull_ascii_fstring(user,p);
3101 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3103 if (tdscnt != 532) {
3104 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3105 goto out;
3108 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3109 if (bufsize != 532) {
3110 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3111 goto out;
3114 memcpy(password.data, data, 516);
3115 memcpy(hash.hash, data+516, 16);
3117 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
3118 conn->session_info,
3119 conn->sconn->remote_address,
3120 conn->sconn->local_address,
3121 conn->sconn->msg_ctx,
3122 &cli);
3123 if (!NT_STATUS_IS_OK(status)) {
3124 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3125 nt_errstr(status)));
3126 errcode = W_ERROR_V(ntstatus_to_werror(status));
3127 goto out;
3130 b = cli->binding_handle;
3132 init_lsa_AsciiString(&server, lp_netbios_name());
3133 init_lsa_AsciiString(&account, user);
3135 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3136 &server,
3137 &account,
3138 &password,
3139 &hash,
3140 &result);
3141 if (!NT_STATUS_IS_OK(status)) {
3142 errcode = W_ERROR_V(ntstatus_to_werror(status));
3143 goto out;
3145 if (!NT_STATUS_IS_OK(result)) {
3146 errcode = W_ERROR_V(ntstatus_to_werror(result));
3147 goto out;
3150 errcode = NERR_Success;
3151 out:
3152 SSVAL(*rparam,0,errcode);
3153 SSVAL(*rparam,2,0); /* converter word */
3155 return(True);
3158 /****************************************************************************
3159 delete a print job
3160 Form: <W> <>
3161 ****************************************************************************/
3163 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3164 connection_struct *conn,uint64_t vuid,
3165 char *param, int tpscnt,
3166 char *data, int tdscnt,
3167 int mdrcnt,int mprcnt,
3168 char **rdata,char **rparam,
3169 int *rdata_len,int *rparam_len)
3171 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3172 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3173 char *str2 = skip_string(param,tpscnt,str1);
3174 char *p = skip_string(param,tpscnt,str2);
3175 uint32_t jobid;
3176 fstring sharename;
3177 int errcode;
3178 WERROR werr = WERR_OK;
3180 TALLOC_CTX *mem_ctx = talloc_tos();
3181 NTSTATUS status;
3182 struct rpc_pipe_client *cli = NULL;
3183 struct dcerpc_binding_handle *b = NULL;
3184 struct policy_handle handle;
3185 struct spoolss_DevmodeContainer devmode_ctr;
3186 enum spoolss_JobControl command;
3188 if (!str1 || !str2 || !p) {
3189 return False;
3192 * We use 1 here not 2 as we're checking
3193 * the last byte we want to access is safe.
3195 if (!is_offset_safe(param,tpscnt,p,1)) {
3196 return False;
3198 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3199 return False;
3201 /* check it's a supported varient */
3202 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3203 return(False);
3205 *rparam_len = 4;
3206 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3207 if (!*rparam) {
3208 return False;
3210 *rdata_len = 0;
3212 ZERO_STRUCT(handle);
3214 status = rpc_pipe_open_interface(mem_ctx,
3215 &ndr_table_spoolss,
3216 conn->session_info,
3217 conn->sconn->remote_address,
3218 conn->sconn->local_address,
3219 conn->sconn->msg_ctx,
3220 &cli);
3221 if (!NT_STATUS_IS_OK(status)) {
3222 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3223 nt_errstr(status)));
3224 errcode = W_ERROR_V(ntstatus_to_werror(status));
3225 goto out;
3227 b = cli->binding_handle;
3229 ZERO_STRUCT(devmode_ctr);
3231 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3232 sharename,
3233 "RAW",
3234 devmode_ctr,
3235 JOB_ACCESS_ADMINISTER,
3236 &handle,
3237 &werr);
3238 if (!NT_STATUS_IS_OK(status)) {
3239 errcode = W_ERROR_V(ntstatus_to_werror(status));
3240 goto out;
3242 if (!W_ERROR_IS_OK(werr)) {
3243 errcode = W_ERROR_V(werr);
3244 goto out;
3247 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3248 * and NERR_DestNotFound if share did not exist */
3250 errcode = NERR_Success;
3252 switch (function) {
3253 case 81: /* delete */
3254 command = SPOOLSS_JOB_CONTROL_DELETE;
3255 break;
3256 case 82: /* pause */
3257 command = SPOOLSS_JOB_CONTROL_PAUSE;
3258 break;
3259 case 83: /* resume */
3260 command = SPOOLSS_JOB_CONTROL_RESUME;
3261 break;
3262 default:
3263 errcode = NERR_notsupported;
3264 goto out;
3267 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3268 &handle,
3269 jobid,
3270 NULL, /* unique ptr ctr */
3271 command,
3272 &werr);
3273 if (!NT_STATUS_IS_OK(status)) {
3274 errcode = W_ERROR_V(ntstatus_to_werror(status));
3275 goto out;
3277 if (!W_ERROR_IS_OK(werr)) {
3278 errcode = W_ERROR_V(werr);
3279 goto out;
3282 out:
3283 if (b && is_valid_policy_hnd(&handle)) {
3284 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3287 SSVAL(*rparam,0,errcode);
3288 SSVAL(*rparam,2,0); /* converter word */
3290 return(True);
3293 /****************************************************************************
3294 Purge a print queue - or pause or resume it.
3295 ****************************************************************************/
3297 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3298 connection_struct *conn,uint64_t vuid,
3299 char *param, int tpscnt,
3300 char *data, int tdscnt,
3301 int mdrcnt,int mprcnt,
3302 char **rdata,char **rparam,
3303 int *rdata_len,int *rparam_len)
3305 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3306 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3307 char *str2 = skip_string(param,tpscnt,str1);
3308 char *QueueName = skip_string(param,tpscnt,str2);
3309 int errcode = NERR_notsupported;
3310 WERROR werr = WERR_OK;
3311 NTSTATUS status;
3313 TALLOC_CTX *mem_ctx = talloc_tos();
3314 struct rpc_pipe_client *cli = NULL;
3315 struct dcerpc_binding_handle *b = NULL;
3316 struct policy_handle handle;
3317 struct spoolss_SetPrinterInfoCtr info_ctr;
3318 struct spoolss_DevmodeContainer devmode_ctr;
3319 struct sec_desc_buf secdesc_ctr;
3320 enum spoolss_PrinterControl command = SPOOLSS_PRINTER_CONTROL_UNPAUSE;
3322 if (!str1 || !str2 || !QueueName) {
3323 return False;
3326 /* check it's a supported varient */
3327 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3328 return(False);
3330 *rparam_len = 4;
3331 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3332 if (!*rparam) {
3333 return False;
3335 *rdata_len = 0;
3337 if (skip_string(param,tpscnt,QueueName) == NULL) {
3338 return False;
3341 ZERO_STRUCT(handle);
3343 status = rpc_pipe_open_interface(mem_ctx,
3344 &ndr_table_spoolss,
3345 conn->session_info,
3346 conn->sconn->remote_address,
3347 conn->sconn->local_address,
3348 conn->sconn->msg_ctx,
3349 &cli);
3350 if (!NT_STATUS_IS_OK(status)) {
3351 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3352 nt_errstr(status)));
3353 errcode = W_ERROR_V(ntstatus_to_werror(status));
3354 goto out;
3356 b = cli->binding_handle;
3358 ZERO_STRUCT(devmode_ctr);
3360 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3361 QueueName,
3362 NULL,
3363 devmode_ctr,
3364 PRINTER_ACCESS_ADMINISTER,
3365 &handle,
3366 &werr);
3367 if (!NT_STATUS_IS_OK(status)) {
3368 errcode = W_ERROR_V(ntstatus_to_werror(status));
3369 goto out;
3371 if (!W_ERROR_IS_OK(werr)) {
3372 errcode = W_ERROR_V(werr);
3373 goto out;
3376 switch (function) {
3377 case 74: /* Pause queue */
3378 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3379 break;
3380 case 75: /* Resume queue */
3381 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3382 break;
3383 case 103: /* Purge */
3384 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3385 break;
3386 default:
3387 werr = WERR_NOT_SUPPORTED;
3388 break;
3391 if (!W_ERROR_IS_OK(werr)) {
3392 errcode = W_ERROR_V(werr);
3393 goto out;
3396 ZERO_STRUCT(info_ctr);
3397 ZERO_STRUCT(secdesc_ctr);
3399 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3400 &handle,
3401 &info_ctr,
3402 &devmode_ctr,
3403 &secdesc_ctr,
3404 command,
3405 &werr);
3406 if (!NT_STATUS_IS_OK(status)) {
3407 errcode = W_ERROR_V(ntstatus_to_werror(status));
3408 goto out;
3410 if (!W_ERROR_IS_OK(werr)) {
3411 errcode = W_ERROR_V(werr);
3412 goto out;
3415 errcode = W_ERROR_V(werr);
3417 out:
3419 if (b && is_valid_policy_hnd(&handle)) {
3420 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3423 SSVAL(*rparam,0,errcode);
3424 SSVAL(*rparam,2,0); /* converter word */
3426 return(True);
3429 /****************************************************************************
3430 set the property of a print job (undocumented?)
3431 ? function = 0xb -> set name of print job
3432 ? function = 0x6 -> move print job up/down
3433 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3434 or <WWsTP> <WB21BB16B10zWWzDDz>
3435 ****************************************************************************/
3437 static int check_printjob_info(struct pack_desc* desc,
3438 int uLevel, char* id)
3440 desc->subformat = NULL;
3441 switch( uLevel ) {
3442 case 0: desc->format = "W"; break;
3443 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3444 case 2: desc->format = "WWzWWDDzz"; break;
3445 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3446 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3447 default:
3448 DEBUG(0,("check_printjob_info: invalid level %d\n",
3449 uLevel ));
3450 return False;
3452 if (id == NULL || strcmp(desc->format,id) != 0) {
3453 DEBUG(0,("check_printjob_info: invalid format %s\n",
3454 id ? id : "<NULL>" ));
3455 return False;
3457 return True;
3460 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3461 connection_struct *conn, uint64_t vuid,
3462 char *param, int tpscnt,
3463 char *data, int tdscnt,
3464 int mdrcnt,int mprcnt,
3465 char **rdata,char **rparam,
3466 int *rdata_len,int *rparam_len)
3468 struct pack_desc desc;
3469 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3470 char *str2 = skip_string(param,tpscnt,str1);
3471 char *p = skip_string(param,tpscnt,str2);
3472 uint32_t jobid;
3473 fstring sharename;
3474 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3475 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3476 int errcode;
3478 TALLOC_CTX *mem_ctx = talloc_tos();
3479 WERROR werr;
3480 NTSTATUS status;
3481 struct rpc_pipe_client *cli = NULL;
3482 struct dcerpc_binding_handle *b = NULL;
3483 struct policy_handle handle;
3484 struct spoolss_DevmodeContainer devmode_ctr;
3485 struct spoolss_JobInfoContainer ctr;
3486 union spoolss_JobInfo info;
3487 struct spoolss_SetJobInfo1 info1;
3489 if (!str1 || !str2 || !p) {
3490 return False;
3493 * We use 1 here not 2 as we're checking
3494 * the last byte we want to access is safe.
3496 if (!is_offset_safe(param,tpscnt,p,1)) {
3497 return False;
3499 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3500 return False;
3501 *rparam_len = 4;
3502 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3503 if (!*rparam) {
3504 return False;
3507 *rdata_len = 0;
3509 /* check it's a supported varient */
3510 if ((strcmp(str1,"WWsTP")) ||
3511 (!check_printjob_info(&desc,uLevel,str2)))
3512 return(False);
3514 errcode = NERR_notsupported;
3516 switch (function) {
3517 case 0xb:
3518 /* change print job name, data gives the name */
3519 break;
3520 default:
3521 goto out;
3524 ZERO_STRUCT(handle);
3526 status = rpc_pipe_open_interface(mem_ctx,
3527 &ndr_table_spoolss,
3528 conn->session_info,
3529 conn->sconn->remote_address,
3530 conn->sconn->local_address,
3531 conn->sconn->msg_ctx,
3532 &cli);
3533 if (!NT_STATUS_IS_OK(status)) {
3534 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3535 nt_errstr(status)));
3536 errcode = W_ERROR_V(ntstatus_to_werror(status));
3537 goto out;
3539 b = cli->binding_handle;
3541 ZERO_STRUCT(devmode_ctr);
3543 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3544 sharename,
3545 "RAW",
3546 devmode_ctr,
3547 PRINTER_ACCESS_USE,
3548 &handle,
3549 &werr);
3550 if (!NT_STATUS_IS_OK(status)) {
3551 errcode = W_ERROR_V(ntstatus_to_werror(status));
3552 goto out;
3554 if (!W_ERROR_IS_OK(werr)) {
3555 errcode = W_ERROR_V(werr);
3556 goto out;
3559 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3560 &handle,
3561 jobid,
3562 1, /* level */
3563 0, /* offered */
3564 &info);
3565 if (!W_ERROR_IS_OK(werr)) {
3566 errcode = W_ERROR_V(werr);
3567 goto out;
3570 ZERO_STRUCT(ctr);
3572 info1.job_id = info.info1.job_id;
3573 info1.printer_name = info.info1.printer_name;
3574 info1.user_name = info.info1.user_name;
3575 info1.document_name = data;
3576 info1.data_type = info.info1.data_type;
3577 info1.text_status = info.info1.text_status;
3578 info1.status = info.info1.status;
3579 info1.priority = info.info1.priority;
3580 info1.position = info.info1.position;
3581 info1.total_pages = info.info1.total_pages;
3582 info1.pages_printed = info.info1.pages_printed;
3583 info1.submitted = info.info1.submitted;
3585 ctr.level = 1;
3586 ctr.info.info1 = &info1;
3588 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3589 &handle,
3590 jobid,
3591 &ctr,
3593 &werr);
3594 if (!NT_STATUS_IS_OK(status)) {
3595 errcode = W_ERROR_V(ntstatus_to_werror(status));
3596 goto out;
3598 if (!W_ERROR_IS_OK(werr)) {
3599 errcode = W_ERROR_V(werr);
3600 goto out;
3603 errcode = NERR_Success;
3604 out:
3606 if (b && is_valid_policy_hnd(&handle)) {
3607 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3610 SSVALS(*rparam,0,errcode);
3611 SSVAL(*rparam,2,0); /* converter word */
3613 return(True);
3617 /****************************************************************************
3618 Get info about the server.
3619 ****************************************************************************/
3621 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3622 connection_struct *conn,uint64_t vuid,
3623 char *param, int tpscnt,
3624 char *data, int tdscnt,
3625 int mdrcnt,int mprcnt,
3626 char **rdata,char **rparam,
3627 int *rdata_len,int *rparam_len)
3629 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3630 char *str2 = skip_string(param,tpscnt,str1);
3631 char *p = skip_string(param,tpscnt,str2);
3632 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3633 char *p2;
3634 int struct_len;
3636 NTSTATUS status;
3637 WERROR werr;
3638 TALLOC_CTX *mem_ctx = talloc_tos();
3639 struct rpc_pipe_client *cli = NULL;
3640 union srvsvc_NetSrvInfo info;
3641 int errcode;
3642 struct dcerpc_binding_handle *b;
3644 if (!str1 || !str2 || !p) {
3645 return False;
3648 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3650 /* check it's a supported varient */
3651 if (!prefix_ok(str1,"WrLh")) {
3652 return False;
3655 switch( uLevel ) {
3656 case 0:
3657 if (strcmp(str2,"B16") != 0) {
3658 return False;
3660 struct_len = 16;
3661 break;
3662 case 1:
3663 if (strcmp(str2,"B16BBDz") != 0) {
3664 return False;
3666 struct_len = 26;
3667 break;
3668 case 2:
3669 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3670 return False;
3672 struct_len = 134;
3673 break;
3674 case 3:
3675 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3676 return False;
3678 struct_len = 144;
3679 break;
3680 case 20:
3681 if (strcmp(str2,"DN") != 0) {
3682 return False;
3684 struct_len = 6;
3685 break;
3686 case 50:
3687 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3688 return False;
3690 struct_len = 42;
3691 break;
3692 default:
3693 return False;
3696 *rdata_len = mdrcnt;
3697 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3698 if (!*rdata) {
3699 return False;
3702 p = *rdata;
3703 p2 = p + struct_len;
3705 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
3706 conn->session_info,
3707 conn->sconn->remote_address,
3708 conn->sconn->local_address,
3709 conn->sconn->msg_ctx,
3710 &cli);
3711 if (!NT_STATUS_IS_OK(status)) {
3712 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3713 nt_errstr(status)));
3714 errcode = W_ERROR_V(ntstatus_to_werror(status));
3715 goto out;
3718 b = cli->binding_handle;
3720 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3721 NULL,
3722 101,
3723 &info,
3724 &werr);
3725 if (!NT_STATUS_IS_OK(status)) {
3726 errcode = W_ERROR_V(ntstatus_to_werror(status));
3727 goto out;
3729 if (!W_ERROR_IS_OK(werr)) {
3730 errcode = W_ERROR_V(werr);
3731 goto out;
3734 if (info.info101 == NULL) {
3735 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3736 goto out;
3739 if (uLevel != 20) {
3740 size_t len = 0;
3741 status = srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3742 STR_ASCII|STR_UPPER|STR_TERMINATE, &len);
3743 if (!NT_STATUS_IS_OK(status)) {
3744 errcode = W_ERROR_V(ntstatus_to_werror(status));
3745 goto out;
3748 p += 16;
3749 if (uLevel > 0) {
3750 SCVAL(p,0,info.info101->version_major);
3751 SCVAL(p,1,info.info101->version_minor);
3752 SIVAL(p,2,info.info101->server_type);
3754 if (mdrcnt == struct_len) {
3755 SIVAL(p,6,0);
3756 } else {
3757 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3758 if (mdrcnt - struct_len <= 0) {
3759 return false;
3761 push_ascii(p2,
3762 info.info101->comment,
3763 MIN(mdrcnt - struct_len,
3764 MAX_SERVER_STRING_LENGTH),
3765 STR_TERMINATE);
3766 p2 = skip_string(*rdata,*rdata_len,p2);
3767 if (!p2) {
3768 return False;
3773 if (uLevel > 1) {
3774 return False; /* not yet implemented */
3777 errcode = NERR_Success;
3779 out:
3781 *rdata_len = PTR_DIFF(p2,*rdata);
3783 *rparam_len = 6;
3784 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3785 if (!*rparam) {
3786 return False;
3788 SSVAL(*rparam,0,errcode);
3789 SSVAL(*rparam,2,0); /* converter word */
3790 SSVAL(*rparam,4,*rdata_len);
3792 return True;
3795 /****************************************************************************
3796 Get info about the server.
3797 ****************************************************************************/
3799 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3800 connection_struct *conn,uint64_t vuid,
3801 char *param, int tpscnt,
3802 char *data, int tdscnt,
3803 int mdrcnt,int mprcnt,
3804 char **rdata,char **rparam,
3805 int *rdata_len,int *rparam_len)
3807 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3808 char *str2 = skip_string(param,tpscnt,str1);
3809 char *p = skip_string(param,tpscnt,str2);
3810 char *p2;
3811 char *endp;
3812 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3814 if (!str1 || !str2 || !p) {
3815 return False;
3818 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3820 *rparam_len = 6;
3821 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3822 if (!*rparam) {
3823 return False;
3826 /* check it's a supported varient */
3827 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3828 return False;
3831 *rdata_len = mdrcnt + 1024;
3832 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3833 if (!*rdata) {
3834 return False;
3837 SSVAL(*rparam,0,NERR_Success);
3838 SSVAL(*rparam,2,0); /* converter word */
3840 p = *rdata;
3841 endp = *rdata + *rdata_len;
3843 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3844 if (!p2) {
3845 return False;
3848 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3849 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3850 if (!strupper_m(p2)) {
3851 return false;
3853 p2 = skip_string(*rdata,*rdata_len,p2);
3854 if (!p2) {
3855 return False;
3857 p += 4;
3859 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3860 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3861 p2 = skip_string(*rdata,*rdata_len,p2);
3862 if (!p2) {
3863 return False;
3865 p += 4;
3867 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3868 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3869 if (!strupper_m(p2)) {
3870 return false;
3872 p2 = skip_string(*rdata,*rdata_len,p2);
3873 if (!p2) {
3874 return False;
3876 p += 4;
3878 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3879 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3880 p += 2;
3882 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3883 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3884 p2 = skip_string(*rdata,*rdata_len,p2);
3885 if (!p2) {
3886 return False;
3888 p += 4;
3890 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3891 strlcpy(p2,"",PTR_DIFF(endp,p2));
3892 p2 = skip_string(*rdata,*rdata_len,p2);
3893 if (!p2) {
3894 return False;
3896 p += 4;
3898 *rdata_len = PTR_DIFF(p2,*rdata);
3900 SSVAL(*rparam,4,*rdata_len);
3902 return True;
3905 /****************************************************************************
3906 get info about a user
3908 struct user_info_11 {
3909 char usri11_name[21]; 0-20
3910 char usri11_pad; 21
3911 char *usri11_comment; 22-25
3912 char *usri11_usr_comment; 26-29
3913 unsigned short usri11_priv; 30-31
3914 unsigned long usri11_auth_flags; 32-35
3915 long usri11_password_age; 36-39
3916 char *usri11_homedir; 40-43
3917 char *usri11_parms; 44-47
3918 long usri11_last_logon; 48-51
3919 long usri11_last_logoff; 52-55
3920 unsigned short usri11_bad_pw_count; 56-57
3921 unsigned short usri11_num_logons; 58-59
3922 char *usri11_logon_server; 60-63
3923 unsigned short usri11_country_code; 64-65
3924 char *usri11_workstations; 66-69
3925 unsigned long usri11_max_storage; 70-73
3926 unsigned short usri11_units_per_week; 74-75
3927 unsigned char *usri11_logon_hours; 76-79
3928 unsigned short usri11_code_page; 80-81
3931 where:
3933 usri11_name specifies the user name for which information is retrieved
3935 usri11_pad aligns the next data structure element to a word boundary
3937 usri11_comment is a null terminated ASCII comment
3939 usri11_user_comment is a null terminated ASCII comment about the user
3941 usri11_priv specifies the level of the privilege assigned to the user.
3942 The possible values are:
3944 Name Value Description
3945 USER_PRIV_GUEST 0 Guest privilege
3946 USER_PRIV_USER 1 User privilege
3947 USER_PRV_ADMIN 2 Administrator privilege
3949 usri11_auth_flags specifies the account operator privileges. The
3950 possible values are:
3952 Name Value Description
3953 AF_OP_PRINT 0 Print operator
3956 Leach, Naik [Page 28]
3960 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3963 AF_OP_COMM 1 Communications operator
3964 AF_OP_SERVER 2 Server operator
3965 AF_OP_ACCOUNTS 3 Accounts operator
3968 usri11_password_age specifies how many seconds have elapsed since the
3969 password was last changed.
3971 usri11_home_dir points to a null terminated ASCII string that contains
3972 the path name of the user's home directory.
3974 usri11_parms points to a null terminated ASCII string that is set
3975 aside for use by applications.
3977 usri11_last_logon specifies the time when the user last logged on.
3978 This value is stored as the number of seconds elapsed since
3979 00:00:00, January 1, 1970.
3981 usri11_last_logoff specifies the time when the user last logged off.
3982 This value is stored as the number of seconds elapsed since
3983 00:00:00, January 1, 1970. A value of 0 means the last logoff
3984 time is unknown.
3986 usri11_bad_pw_count specifies the number of incorrect passwords
3987 entered since the last successful logon.
3989 usri11_log1_num_logons specifies the number of times this user has
3990 logged on. A value of -1 means the number of logons is unknown.
3992 usri11_logon_server points to a null terminated ASCII string that
3993 contains the name of the server to which logon requests are sent.
3994 A null string indicates logon requests should be sent to the
3995 domain controller.
3997 usri11_country_code specifies the country code for the user's language
3998 of choice.
4000 usri11_workstations points to a null terminated ASCII string that
4001 contains the names of workstations the user may log on from.
4002 There may be up to 8 workstations, with the names separated by
4003 commas. A null strings indicates there are no restrictions.
4005 usri11_max_storage specifies the maximum amount of disk space the user
4006 can occupy. A value of 0xffffffff indicates there are no
4007 restrictions.
4009 usri11_units_per_week specifies the equal number of time units into
4010 which a week is divided. This value must be equal to 168.
4012 usri11_logon_hours points to a 21 byte (168 bits) string that
4013 specifies the time during which the user can log on. Each bit
4014 represents one unique hour in a week. The first bit (bit 0, word
4015 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4019 Leach, Naik [Page 29]
4023 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4026 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4027 are no restrictions.
4029 usri11_code_page specifies the code page for the user's language of
4030 choice
4032 All of the pointers in this data structure need to be treated
4033 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4034 to be ignored. The converter word returned in the parameters section
4035 needs to be subtracted from the lower 16 bits to calculate an offset
4036 into the return buffer where this ASCII string resides.
4038 There is no auxiliary data in the response.
4040 ****************************************************************************/
4042 #define usri11_name 0
4043 #define usri11_pad 21
4044 #define usri11_comment 22
4045 #define usri11_usr_comment 26
4046 #define usri11_full_name 30
4047 #define usri11_priv 34
4048 #define usri11_auth_flags 36
4049 #define usri11_password_age 40
4050 #define usri11_homedir 44
4051 #define usri11_parms 48
4052 #define usri11_last_logon 52
4053 #define usri11_last_logoff 56
4054 #define usri11_bad_pw_count 60
4055 #define usri11_num_logons 62
4056 #define usri11_logon_server 64
4057 #define usri11_country_code 68
4058 #define usri11_workstations 70
4059 #define usri11_max_storage 74
4060 #define usri11_units_per_week 78
4061 #define usri11_logon_hours 80
4062 #define usri11_code_page 84
4063 #define usri11_end 86
4065 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4066 connection_struct *conn, uint64_t vuid,
4067 char *param, int tpscnt,
4068 char *data, int tdscnt,
4069 int mdrcnt,int mprcnt,
4070 char **rdata,char **rparam,
4071 int *rdata_len,int *rparam_len)
4073 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4074 char *str2 = skip_string(param,tpscnt,str1);
4075 char *UserName = skip_string(param,tpscnt,str2);
4076 char *p = skip_string(param,tpscnt,UserName);
4077 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4078 char *p2;
4079 char *endp;
4080 const char *level_string;
4082 TALLOC_CTX *mem_ctx = talloc_tos();
4083 NTSTATUS status, result;
4084 struct rpc_pipe_client *cli = NULL;
4085 struct policy_handle connect_handle, domain_handle, user_handle;
4086 struct lsa_String domain_name;
4087 struct dom_sid2 *domain_sid;
4088 struct lsa_String names;
4089 struct samr_Ids rids;
4090 struct samr_Ids types;
4091 int errcode = W_ERROR_V(WERR_NERR_USERNOTFOUND);
4092 uint32_t rid;
4093 union samr_UserInfo *info;
4094 struct dcerpc_binding_handle *b = NULL;
4096 if (!str1 || !str2 || !UserName || !p) {
4097 return False;
4100 *rparam_len = 6;
4101 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4102 if (!*rparam) {
4103 return False;
4106 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4108 /* check it's a supported variant */
4109 if (strcmp(str1,"zWrLh") != 0) {
4110 return False;
4112 switch( uLevel ) {
4113 case 0: level_string = "B21"; break;
4114 case 1: level_string = "B21BB16DWzzWz"; break;
4115 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4116 case 10: level_string = "B21Bzzz"; break;
4117 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4118 default: return False;
4121 if (strcmp(level_string,str2) != 0) {
4122 return False;
4125 *rdata_len = mdrcnt + 1024;
4126 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4127 if (!*rdata) {
4128 return False;
4131 p = *rdata;
4132 endp = *rdata + *rdata_len;
4133 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4134 if (!p2) {
4135 return False;
4138 ZERO_STRUCT(connect_handle);
4139 ZERO_STRUCT(domain_handle);
4140 ZERO_STRUCT(user_handle);
4142 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
4143 conn->session_info,
4144 conn->sconn->remote_address,
4145 conn->sconn->local_address,
4146 conn->sconn->msg_ctx,
4147 &cli);
4148 if (!NT_STATUS_IS_OK(status)) {
4149 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4150 nt_errstr(status)));
4151 errcode = W_ERROR_V(ntstatus_to_werror(status));
4152 goto out;
4155 b = cli->binding_handle;
4157 status = dcerpc_samr_Connect2(b, mem_ctx,
4158 lp_netbios_name(),
4159 SAMR_ACCESS_CONNECT_TO_SERVER |
4160 SAMR_ACCESS_ENUM_DOMAINS |
4161 SAMR_ACCESS_LOOKUP_DOMAIN,
4162 &connect_handle,
4163 &result);
4164 if (!NT_STATUS_IS_OK(status)) {
4165 errcode = W_ERROR_V(ntstatus_to_werror(status));
4166 goto out;
4168 if (!NT_STATUS_IS_OK(result)) {
4169 errcode = W_ERROR_V(ntstatus_to_werror(result));
4170 goto out;
4173 init_lsa_String(&domain_name, get_global_sam_name());
4175 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4176 &connect_handle,
4177 &domain_name,
4178 &domain_sid,
4179 &result);
4180 if (!NT_STATUS_IS_OK(status)) {
4181 errcode = W_ERROR_V(ntstatus_to_werror(status));
4182 goto out;
4184 if (!NT_STATUS_IS_OK(result)) {
4185 errcode = W_ERROR_V(ntstatus_to_werror(result));
4186 goto out;
4189 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4190 &connect_handle,
4191 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4192 domain_sid,
4193 &domain_handle,
4194 &result);
4195 if (!NT_STATUS_IS_OK(status)) {
4196 errcode = W_ERROR_V(ntstatus_to_werror(status));
4197 goto out;
4199 if (!NT_STATUS_IS_OK(result)) {
4200 errcode = W_ERROR_V(ntstatus_to_werror(result));
4201 goto out;
4204 init_lsa_String(&names, UserName);
4206 status = dcerpc_samr_LookupNames(b, mem_ctx,
4207 &domain_handle,
4209 &names,
4210 &rids,
4211 &types,
4212 &result);
4213 if (!NT_STATUS_IS_OK(status)) {
4214 errcode = W_ERROR_V(ntstatus_to_werror(status));
4215 goto out;
4217 if (!NT_STATUS_IS_OK(result)) {
4218 errcode = W_ERROR_V(ntstatus_to_werror(result));
4219 goto out;
4222 if (rids.count != 1) {
4223 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4224 goto out;
4226 if (rids.count != types.count) {
4227 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4228 goto out;
4230 if (types.ids[0] != SID_NAME_USER) {
4231 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4232 goto out;
4235 rid = rids.ids[0];
4237 status = dcerpc_samr_OpenUser(b, mem_ctx,
4238 &domain_handle,
4239 SAMR_USER_ACCESS_GET_LOCALE |
4240 SAMR_USER_ACCESS_GET_LOGONINFO |
4241 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4242 SAMR_USER_ACCESS_GET_GROUPS |
4243 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4244 SEC_STD_READ_CONTROL,
4245 rid,
4246 &user_handle,
4247 &result);
4248 if (!NT_STATUS_IS_OK(status)) {
4249 errcode = W_ERROR_V(ntstatus_to_werror(status));
4250 goto out;
4252 if (!NT_STATUS_IS_OK(result)) {
4253 errcode = W_ERROR_V(ntstatus_to_werror(result));
4254 goto out;
4257 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4258 &user_handle,
4259 UserAllInformation,
4260 &info,
4261 &result);
4262 if (!NT_STATUS_IS_OK(status)) {
4263 errcode = W_ERROR_V(ntstatus_to_werror(status));
4264 goto out;
4266 if (!NT_STATUS_IS_OK(result)) {
4267 errcode = W_ERROR_V(ntstatus_to_werror(result));
4268 goto out;
4271 memset(p,0,21);
4272 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4274 if (uLevel > 0) {
4275 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4276 *p2 = 0;
4279 if (uLevel >= 10) {
4280 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4281 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4282 p2 = skip_string(*rdata,*rdata_len,p2);
4283 if (!p2) {
4284 return False;
4287 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4288 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4289 p2 = skip_string(*rdata,*rdata_len,p2);
4290 if (!p2) {
4291 return False;
4294 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4295 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4296 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4297 p2 = skip_string(*rdata,*rdata_len,p2);
4298 if (!p2) {
4299 return False;
4303 if (uLevel == 11) {
4304 const char *homedir = info->info21.home_directory.string;
4305 /* modelled after NTAS 3.51 reply */
4306 SSVAL(p,usri11_priv,
4307 (get_current_uid(conn) == sec_initial_uid())?
4308 USER_PRIV_ADMIN:USER_PRIV_USER);
4309 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4310 SIVALS(p,usri11_password_age,-1); /* password age */
4311 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4312 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4313 p2 = skip_string(*rdata,*rdata_len,p2);
4314 if (!p2) {
4315 return False;
4317 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4318 strlcpy(p2,"",PTR_DIFF(endp,p2));
4319 p2 = skip_string(*rdata,*rdata_len,p2);
4320 if (!p2) {
4321 return False;
4323 SIVAL(p,usri11_last_logon,0); /* last logon */
4324 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4325 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4326 SSVALS(p,usri11_num_logons,-1); /* num logons */
4327 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4328 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4329 p2 = skip_string(*rdata,*rdata_len,p2);
4330 if (!p2) {
4331 return False;
4333 SSVAL(p,usri11_country_code,0); /* country code */
4335 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4336 strlcpy(p2,"",PTR_DIFF(endp,p2));
4337 p2 = skip_string(*rdata,*rdata_len,p2);
4338 if (!p2) {
4339 return False;
4342 SIVALS(p,usri11_max_storage,-1); /* max storage */
4343 SSVAL(p,usri11_units_per_week,168); /* units per week */
4344 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4346 /* a simple way to get logon hours at all times. */
4347 memset(p2,0xff,21);
4348 SCVAL(p2,21,0); /* fix zero termination */
4349 p2 = skip_string(*rdata,*rdata_len,p2);
4350 if (!p2) {
4351 return False;
4354 SSVAL(p,usri11_code_page,0); /* code page */
4357 if (uLevel == 1 || uLevel == 2) {
4358 memset(p+22,' ',16); /* password */
4359 SIVALS(p,38,-1); /* password age */
4360 SSVAL(p,42,
4361 (get_current_uid(conn) == sec_initial_uid())?
4362 USER_PRIV_ADMIN:USER_PRIV_USER);
4363 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4364 strlcpy(p2, info->info21.home_directory.string,
4365 PTR_DIFF(endp,p2));
4366 p2 = skip_string(*rdata,*rdata_len,p2);
4367 if (!p2) {
4368 return False;
4370 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4371 *p2++ = 0;
4372 SSVAL(p,52,0); /* flags */
4373 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4374 strlcpy(p2, info->info21.logon_script.string,
4375 PTR_DIFF(endp,p2));
4376 p2 = skip_string(*rdata,*rdata_len,p2);
4377 if (!p2) {
4378 return False;
4380 if (uLevel == 2) {
4381 SIVAL(p,58,0); /* auth_flags */
4382 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4383 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4384 p2 = skip_string(*rdata,*rdata_len,p2);
4385 if (!p2) {
4386 return False;
4388 SIVAL(p,66,0); /* urs_comment */
4389 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4390 strlcpy(p2,"",PTR_DIFF(endp,p2));
4391 p2 = skip_string(*rdata,*rdata_len,p2);
4392 if (!p2) {
4393 return False;
4395 SIVAL(p,74,0); /* workstations */
4396 SIVAL(p,78,0); /* last_logon */
4397 SIVAL(p,82,0); /* last_logoff */
4398 SIVALS(p,86,-1); /* acct_expires */
4399 SIVALS(p,90,-1); /* max_storage */
4400 SSVAL(p,94,168); /* units_per_week */
4401 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4402 memset(p2,-1,21);
4403 p2 += 21;
4404 SSVALS(p,100,-1); /* bad_pw_count */
4405 SSVALS(p,102,-1); /* num_logons */
4406 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4408 TALLOC_CTX *ctx = talloc_tos();
4409 int space_rem = *rdata_len - (p2 - *rdata);
4410 char *tmp;
4412 if (space_rem <= 0) {
4413 return false;
4415 tmp = talloc_strdup(ctx, "\\\\%L");
4416 if (!tmp) {
4417 return false;
4419 tmp = talloc_sub_basic(ctx,
4422 tmp);
4423 if (!tmp) {
4424 return false;
4427 push_ascii(p2,
4428 tmp,
4429 space_rem,
4430 STR_TERMINATE);
4432 p2 = skip_string(*rdata,*rdata_len,p2);
4433 if (!p2) {
4434 return False;
4436 SSVAL(p,108,49); /* country_code */
4437 SSVAL(p,110,860); /* code page */
4441 errcode = NERR_Success;
4443 out:
4444 *rdata_len = PTR_DIFF(p2,*rdata);
4446 if (b && is_valid_policy_hnd(&user_handle)) {
4447 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4449 if (b && is_valid_policy_hnd(&domain_handle)) {
4450 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4452 if (b && is_valid_policy_hnd(&connect_handle)) {
4453 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4456 SSVAL(*rparam,0,errcode);
4457 SSVAL(*rparam,2,0); /* converter word */
4458 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4460 return(True);
4463 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4464 connection_struct *conn,uint64_t vuid,
4465 char *param, int tpscnt,
4466 char *data, int tdscnt,
4467 int mdrcnt,int mprcnt,
4468 char **rdata,char **rparam,
4469 int *rdata_len,int *rparam_len)
4471 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4472 char *str2 = skip_string(param,tpscnt,str1);
4473 char *p = skip_string(param,tpscnt,str2);
4474 int uLevel;
4475 struct pack_desc desc;
4476 char* name;
4477 struct auth_session_info *si = NULL;
4478 NTSTATUS status;
4480 status = smbXsrv_session_info_lookup(conn->sconn->client,
4481 vuid,
4482 &si);
4483 if (!NT_STATUS_IS_OK(status)) {
4484 return false;
4487 if (!str1 || !str2 || !p) {
4488 return False;
4491 DBG_INFO("Username of UID %ju is %s\n",
4492 (uintmax_t)si->unix_token->uid,
4493 si->unix_info->unix_name);
4495 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4496 name = get_safe_str_ptr(param,tpscnt,p,2);
4497 if (!name) {
4498 return False;
4501 memset((char *)&desc,'\0',sizeof(desc));
4503 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4505 /* check it's a supported varient */
4506 if (strcmp(str1,"OOWb54WrLh") != 0) {
4507 return False;
4509 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4510 return False;
4512 if (mdrcnt > 0) {
4513 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4514 if (!*rdata) {
4515 return False;
4519 desc.base = *rdata;
4520 desc.buflen = mdrcnt;
4521 desc.subformat = NULL;
4522 desc.format = str2;
4524 if (init_package(&desc,1,0)) {
4525 PACKI(&desc,"W",0); /* code */
4526 PACKS(&desc,"B21",name); /* eff. name */
4527 PACKS(&desc,"B",""); /* pad */
4528 PACKI(&desc,"W",
4529 (get_current_uid(conn) == sec_initial_uid())?
4530 USER_PRIV_ADMIN:USER_PRIV_USER);
4531 PACKI(&desc,"D",0); /* auth flags XXX */
4532 PACKI(&desc,"W",0); /* num logons */
4533 PACKI(&desc,"W",0); /* bad pw count */
4534 PACKI(&desc,"D",0); /* last logon */
4535 PACKI(&desc,"D",-1); /* last logoff */
4536 PACKI(&desc,"D",-1); /* logoff time */
4537 PACKI(&desc,"D",-1); /* kickoff time */
4538 PACKI(&desc,"D",0); /* password age */
4539 PACKI(&desc,"D",0); /* password can change */
4540 PACKI(&desc,"D",-1); /* password must change */
4543 fstring mypath;
4544 fstrcpy(mypath,"\\\\");
4545 fstrcat(mypath,get_local_machine_name());
4546 if (!strupper_m(mypath)) {
4547 return false;
4549 PACKS(&desc,"z",mypath); /* computer */
4552 PACKS(&desc,"z",lp_workgroup());/* domain */
4553 PACKS(&desc,"z", si->info->logon_script); /* script path */
4554 PACKI(&desc,"D",0x00000000); /* reserved */
4557 *rdata_len = desc.usedlen;
4558 *rparam_len = 6;
4559 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4560 if (!*rparam) {
4561 return False;
4563 SSVALS(*rparam,0,desc.errcode);
4564 SSVAL(*rparam,2,0);
4565 SSVAL(*rparam,4,desc.neededlen);
4567 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4569 return True;
4572 /****************************************************************************
4573 api_WAccessGetUserPerms
4574 ****************************************************************************/
4576 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4577 connection_struct *conn,uint64_t vuid,
4578 char *param, int tpscnt,
4579 char *data, int tdscnt,
4580 int mdrcnt,int mprcnt,
4581 char **rdata,char **rparam,
4582 int *rdata_len,int *rparam_len)
4584 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4585 char *str2 = skip_string(param,tpscnt,str1);
4586 char *user = skip_string(param,tpscnt,str2);
4587 char *resource = skip_string(param,tpscnt,user);
4589 if (!str1 || !str2 || !user || !resource) {
4590 return False;
4593 if (skip_string(param,tpscnt,resource) == NULL) {
4594 return False;
4596 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4598 /* check it's a supported varient */
4599 if (strcmp(str1,"zzh") != 0) {
4600 return False;
4602 if (strcmp(str2,"") != 0) {
4603 return False;
4606 *rparam_len = 6;
4607 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4608 if (!*rparam) {
4609 return False;
4611 SSVALS(*rparam,0,0); /* errorcode */
4612 SSVAL(*rparam,2,0); /* converter word */
4613 SSVAL(*rparam,4,0x7f); /* permission flags */
4615 return True;
4618 /****************************************************************************
4619 api_WPrintJobEnumerate
4620 ****************************************************************************/
4622 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4623 connection_struct *conn, uint64_t vuid,
4624 char *param, int tpscnt,
4625 char *data, int tdscnt,
4626 int mdrcnt,int mprcnt,
4627 char **rdata,char **rparam,
4628 int *rdata_len,int *rparam_len)
4630 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4631 char *str2 = skip_string(param,tpscnt,str1);
4632 char *p = skip_string(param,tpscnt,str2);
4633 int uLevel;
4634 fstring sharename;
4635 uint32_t jobid;
4636 struct pack_desc desc;
4637 char *tmpdata=NULL;
4639 TALLOC_CTX *mem_ctx = talloc_tos();
4640 WERROR werr;
4641 NTSTATUS status;
4642 struct rpc_pipe_client *cli = NULL;
4643 struct dcerpc_binding_handle *b = NULL;
4644 struct policy_handle handle;
4645 struct spoolss_DevmodeContainer devmode_ctr;
4646 union spoolss_JobInfo info;
4648 if (!str1 || !str2 || !p) {
4649 return False;
4652 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4654 memset((char *)&desc,'\0',sizeof(desc));
4655 memset((char *)&status,'\0',sizeof(status));
4657 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4659 /* check it's a supported varient */
4660 if (strcmp(str1,"WWrLh") != 0) {
4661 return False;
4663 if (!check_printjob_info(&desc,uLevel,str2)) {
4664 return False;
4667 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4668 return False;
4671 ZERO_STRUCT(handle);
4673 status = rpc_pipe_open_interface(mem_ctx,
4674 &ndr_table_spoolss,
4675 conn->session_info,
4676 conn->sconn->remote_address,
4677 conn->sconn->local_address,
4678 conn->sconn->msg_ctx,
4679 &cli);
4680 if (!NT_STATUS_IS_OK(status)) {
4681 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4682 nt_errstr(status)));
4683 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4684 goto out;
4686 b = cli->binding_handle;
4688 ZERO_STRUCT(devmode_ctr);
4690 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4691 sharename,
4692 "RAW",
4693 devmode_ctr,
4694 PRINTER_ACCESS_USE,
4695 &handle,
4696 &werr);
4697 if (!NT_STATUS_IS_OK(status)) {
4698 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4699 goto out;
4701 if (!W_ERROR_IS_OK(werr)) {
4702 desc.errcode = W_ERROR_V(werr);
4703 goto out;
4706 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4707 &handle,
4708 jobid,
4709 2, /* level */
4710 0, /* offered */
4711 &info);
4712 if (!W_ERROR_IS_OK(werr)) {
4713 desc.errcode = W_ERROR_V(werr);
4714 goto out;
4717 if (mdrcnt > 0) {
4718 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4719 if (!*rdata) {
4720 return False;
4722 desc.base = *rdata;
4723 desc.buflen = mdrcnt;
4724 } else {
4726 * Don't return data but need to get correct length
4727 * init_package will return wrong size if buflen=0
4729 desc.buflen = getlen(desc.format);
4730 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4733 if (init_package(&desc,1,0)) {
4734 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4735 *rdata_len = desc.usedlen;
4736 } else {
4737 desc.errcode = NERR_JobNotFound;
4738 *rdata_len = 0;
4740 out:
4741 if (b && is_valid_policy_hnd(&handle)) {
4742 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4745 *rparam_len = 6;
4746 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4747 if (!*rparam) {
4748 return False;
4750 SSVALS(*rparam,0,desc.errcode);
4751 SSVAL(*rparam,2,0);
4752 SSVAL(*rparam,4,desc.neededlen);
4754 SAFE_FREE(tmpdata);
4756 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4758 return True;
4761 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4762 connection_struct *conn, uint64_t vuid,
4763 char *param, int tpscnt,
4764 char *data, int tdscnt,
4765 int mdrcnt,int mprcnt,
4766 char **rdata,char **rparam,
4767 int *rdata_len,int *rparam_len)
4769 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4770 char *str2 = skip_string(param,tpscnt,str1);
4771 char *p = skip_string(param,tpscnt,str2);
4772 char *name = p;
4773 int uLevel;
4774 int i, succnt=0;
4775 struct pack_desc desc;
4777 TALLOC_CTX *mem_ctx = talloc_tos();
4778 WERROR werr;
4779 NTSTATUS status;
4780 struct rpc_pipe_client *cli = NULL;
4781 struct dcerpc_binding_handle *b = NULL;
4782 struct policy_handle handle;
4783 struct spoolss_DevmodeContainer devmode_ctr;
4784 uint32_t count = 0;
4785 union spoolss_JobInfo *info;
4787 if (!str1 || !str2 || !p) {
4788 return False;
4791 memset((char *)&desc,'\0',sizeof(desc));
4793 p = skip_string(param,tpscnt,p);
4794 if (!p) {
4795 return False;
4797 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4799 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4801 /* check it's a supported variant */
4802 if (strcmp(str1,"zWrLeh") != 0) {
4803 return False;
4806 if (uLevel > 2) {
4807 return False; /* defined only for uLevel 0,1,2 */
4810 if (!check_printjob_info(&desc,uLevel,str2)) {
4811 return False;
4814 ZERO_STRUCT(handle);
4816 status = rpc_pipe_open_interface(mem_ctx,
4817 &ndr_table_spoolss,
4818 conn->session_info,
4819 conn->sconn->remote_address,
4820 conn->sconn->local_address,
4821 conn->sconn->msg_ctx,
4822 &cli);
4823 if (!NT_STATUS_IS_OK(status)) {
4824 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4825 nt_errstr(status)));
4826 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4827 goto out;
4829 b = cli->binding_handle;
4831 ZERO_STRUCT(devmode_ctr);
4833 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4834 name,
4835 NULL,
4836 devmode_ctr,
4837 PRINTER_ACCESS_USE,
4838 &handle,
4839 &werr);
4840 if (!NT_STATUS_IS_OK(status)) {
4841 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4842 goto out;
4844 if (!W_ERROR_IS_OK(werr)) {
4845 desc.errcode = W_ERROR_V(werr);
4846 goto out;
4849 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4850 &handle,
4851 0, /* firstjob */
4852 0xff, /* numjobs */
4853 2, /* level */
4854 0, /* offered */
4855 &count,
4856 &info);
4857 if (!W_ERROR_IS_OK(werr)) {
4858 desc.errcode = W_ERROR_V(werr);
4859 goto out;
4862 if (mdrcnt > 0) {
4863 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4864 if (!*rdata) {
4865 return False;
4868 desc.base = *rdata;
4869 desc.buflen = mdrcnt;
4871 if (init_package(&desc,count,0)) {
4872 succnt = 0;
4873 for (i = 0; i < count; i++) {
4874 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4875 if (desc.errcode == NERR_Success) {
4876 succnt = i+1;
4880 out:
4881 if (b && is_valid_policy_hnd(&handle)) {
4882 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4885 *rdata_len = desc.usedlen;
4887 *rparam_len = 8;
4888 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4889 if (!*rparam) {
4890 return False;
4892 SSVALS(*rparam,0,desc.errcode);
4893 SSVAL(*rparam,2,0);
4894 SSVAL(*rparam,4,succnt);
4895 SSVAL(*rparam,6,count);
4897 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4899 return True;
4902 static int check_printdest_info(struct pack_desc* desc,
4903 int uLevel, char* id)
4905 desc->subformat = NULL;
4906 switch( uLevel ) {
4907 case 0:
4908 desc->format = "B9";
4909 break;
4910 case 1:
4911 desc->format = "B9B21WWzW";
4912 break;
4913 case 2:
4914 desc->format = "z";
4915 break;
4916 case 3:
4917 desc->format = "zzzWWzzzWW";
4918 break;
4919 default:
4920 DEBUG(0,("check_printdest_info: invalid level %d\n",
4921 uLevel));
4922 return False;
4924 if (id == NULL || strcmp(desc->format,id) != 0) {
4925 DEBUG(0,("check_printdest_info: invalid string %s\n",
4926 id ? id : "<NULL>" ));
4927 return False;
4929 return True;
4932 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4933 struct pack_desc* desc)
4935 char buf[100];
4937 strncpy(buf, info2->printername, sizeof(buf)-1);
4938 buf[sizeof(buf)-1] = 0;
4939 (void)strupper_m(buf);
4941 if (uLevel <= 1) {
4942 PACKS(desc,"B9",buf); /* szName */
4943 if (uLevel == 1) {
4944 PACKS(desc,"B21",""); /* szUserName */
4945 PACKI(desc,"W",0); /* uJobId */
4946 PACKI(desc,"W",0); /* fsStatus */
4947 PACKS(desc,"z",""); /* pszStatus */
4948 PACKI(desc,"W",0); /* time */
4952 if (uLevel == 2 || uLevel == 3) {
4953 PACKS(desc,"z",buf); /* pszPrinterName */
4954 if (uLevel == 3) {
4955 PACKS(desc,"z",""); /* pszUserName */
4956 PACKS(desc,"z",""); /* pszLogAddr */
4957 PACKI(desc,"W",0); /* uJobId */
4958 PACKI(desc,"W",0); /* fsStatus */
4959 PACKS(desc,"z",""); /* pszStatus */
4960 PACKS(desc,"z",""); /* pszComment */
4961 PACKS(desc,"z","NULL"); /* pszDrivers */
4962 PACKI(desc,"W",0); /* time */
4963 PACKI(desc,"W",0); /* pad1 */
4968 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4969 connection_struct *conn, uint64_t vuid,
4970 char *param, int tpscnt,
4971 char *data, int tdscnt,
4972 int mdrcnt,int mprcnt,
4973 char **rdata,char **rparam,
4974 int *rdata_len,int *rparam_len)
4976 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4977 char *str2 = skip_string(param,tpscnt,str1);
4978 char *p = skip_string(param,tpscnt,str2);
4979 char* PrinterName = p;
4980 int uLevel;
4981 struct pack_desc desc;
4982 char *tmpdata=NULL;
4984 TALLOC_CTX *mem_ctx = talloc_tos();
4985 WERROR werr;
4986 NTSTATUS status;
4987 struct rpc_pipe_client *cli = NULL;
4988 struct dcerpc_binding_handle *b = NULL;
4989 struct policy_handle handle;
4990 struct spoolss_DevmodeContainer devmode_ctr;
4991 union spoolss_PrinterInfo info;
4993 if (!str1 || !str2 || !p) {
4994 return False;
4997 memset((char *)&desc,'\0',sizeof(desc));
4999 p = skip_string(param,tpscnt,p);
5000 if (!p) {
5001 return False;
5003 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5005 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
5007 /* check it's a supported varient */
5008 if (strcmp(str1,"zWrLh") != 0) {
5009 return False;
5011 if (!check_printdest_info(&desc,uLevel,str2)) {
5012 return False;
5015 ZERO_STRUCT(handle);
5017 status = rpc_pipe_open_interface(mem_ctx,
5018 &ndr_table_spoolss,
5019 conn->session_info,
5020 conn->sconn->remote_address,
5021 conn->sconn->local_address,
5022 conn->sconn->msg_ctx,
5023 &cli);
5024 if (!NT_STATUS_IS_OK(status)) {
5025 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
5026 nt_errstr(status)));
5027 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5028 goto out;
5030 b = cli->binding_handle;
5032 ZERO_STRUCT(devmode_ctr);
5034 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5035 PrinterName,
5036 NULL,
5037 devmode_ctr,
5038 PRINTER_ACCESS_USE,
5039 &handle,
5040 &werr);
5041 if (!NT_STATUS_IS_OK(status)) {
5042 *rdata_len = 0;
5043 desc.errcode = NERR_DestNotFound;
5044 desc.neededlen = 0;
5045 goto out;
5047 if (!W_ERROR_IS_OK(werr)) {
5048 *rdata_len = 0;
5049 desc.errcode = NERR_DestNotFound;
5050 desc.neededlen = 0;
5051 goto out;
5054 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5055 &handle,
5058 &info);
5059 if (!W_ERROR_IS_OK(werr)) {
5060 *rdata_len = 0;
5061 desc.errcode = NERR_DestNotFound;
5062 desc.neededlen = 0;
5063 goto out;
5066 if (mdrcnt > 0) {
5067 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5068 if (!*rdata) {
5069 return False;
5071 desc.base = *rdata;
5072 desc.buflen = mdrcnt;
5073 } else {
5075 * Don't return data but need to get correct length
5076 * init_package will return wrong size if buflen=0
5078 desc.buflen = getlen(desc.format);
5079 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5081 if (init_package(&desc,1,0)) {
5082 fill_printdest_info(&info.info2, uLevel,&desc);
5085 out:
5086 if (b && is_valid_policy_hnd(&handle)) {
5087 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5090 *rdata_len = desc.usedlen;
5092 *rparam_len = 6;
5093 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5094 if (!*rparam) {
5095 return False;
5097 SSVALS(*rparam,0,desc.errcode);
5098 SSVAL(*rparam,2,0);
5099 SSVAL(*rparam,4,desc.neededlen);
5101 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5102 SAFE_FREE(tmpdata);
5104 return True;
5107 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5108 connection_struct *conn, uint64_t vuid,
5109 char *param, int tpscnt,
5110 char *data, int tdscnt,
5111 int mdrcnt,int mprcnt,
5112 char **rdata,char **rparam,
5113 int *rdata_len,int *rparam_len)
5115 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5116 char *str2 = skip_string(param,tpscnt,str1);
5117 char *p = skip_string(param,tpscnt,str2);
5118 int uLevel;
5119 int queuecnt;
5120 int i, n, succnt=0;
5121 struct pack_desc desc;
5123 TALLOC_CTX *mem_ctx = talloc_tos();
5124 WERROR werr;
5125 NTSTATUS status;
5126 struct rpc_pipe_client *cli = NULL;
5127 union spoolss_PrinterInfo *info;
5128 uint32_t count;
5130 if (!str1 || !str2 || !p) {
5131 return False;
5134 memset((char *)&desc,'\0',sizeof(desc));
5136 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5138 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5140 /* check it's a supported varient */
5141 if (strcmp(str1,"WrLeh") != 0) {
5142 return False;
5144 if (!check_printdest_info(&desc,uLevel,str2)) {
5145 return False;
5148 queuecnt = 0;
5150 status = rpc_pipe_open_interface(mem_ctx,
5151 &ndr_table_spoolss,
5152 conn->session_info,
5153 conn->sconn->remote_address,
5154 conn->sconn->local_address,
5155 conn->sconn->msg_ctx,
5156 &cli);
5157 if (!NT_STATUS_IS_OK(status)) {
5158 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5159 nt_errstr(status)));
5160 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5161 goto out;
5164 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5165 PRINTER_ENUM_LOCAL,
5166 cli->srv_name_slash,
5169 &count,
5170 &info);
5171 if (!W_ERROR_IS_OK(werr)) {
5172 desc.errcode = W_ERROR_V(werr);
5173 *rdata_len = 0;
5174 desc.errcode = NERR_DestNotFound;
5175 desc.neededlen = 0;
5176 goto out;
5179 queuecnt = count;
5181 if (mdrcnt > 0) {
5182 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5183 if (!*rdata) {
5184 return False;
5188 desc.base = *rdata;
5189 desc.buflen = mdrcnt;
5190 if (init_package(&desc,queuecnt,0)) {
5191 succnt = 0;
5192 n = 0;
5193 for (i = 0; i < count; i++) {
5194 fill_printdest_info(&info[i].info2, uLevel,&desc);
5195 n++;
5196 if (desc.errcode == NERR_Success) {
5197 succnt = n;
5201 out:
5202 *rdata_len = desc.usedlen;
5204 *rparam_len = 8;
5205 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5206 if (!*rparam) {
5207 return False;
5209 SSVALS(*rparam,0,desc.errcode);
5210 SSVAL(*rparam,2,0);
5211 SSVAL(*rparam,4,succnt);
5212 SSVAL(*rparam,6,queuecnt);
5214 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5216 return True;
5219 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5220 connection_struct *conn, uint64_t vuid,
5221 char *param, int tpscnt,
5222 char *data, int tdscnt,
5223 int mdrcnt,int mprcnt,
5224 char **rdata,char **rparam,
5225 int *rdata_len,int *rparam_len)
5227 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5228 char *str2 = skip_string(param,tpscnt,str1);
5229 char *p = skip_string(param,tpscnt,str2);
5230 int uLevel;
5231 int succnt;
5232 struct pack_desc desc;
5234 if (!str1 || !str2 || !p) {
5235 return False;
5238 memset((char *)&desc,'\0',sizeof(desc));
5240 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5242 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5244 /* check it's a supported varient */
5245 if (strcmp(str1,"WrLeh") != 0) {
5246 return False;
5248 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5249 return False;
5252 if (mdrcnt > 0) {
5253 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5254 if (!*rdata) {
5255 return False;
5258 desc.base = *rdata;
5259 desc.buflen = mdrcnt;
5260 if (init_package(&desc,1,0)) {
5261 PACKS(&desc,"B41","NULL");
5264 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5266 *rdata_len = desc.usedlen;
5268 *rparam_len = 8;
5269 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5270 if (!*rparam) {
5271 return False;
5273 SSVALS(*rparam,0,desc.errcode);
5274 SSVAL(*rparam,2,0);
5275 SSVAL(*rparam,4,succnt);
5276 SSVAL(*rparam,6,1);
5278 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5280 return True;
5283 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5284 connection_struct *conn, uint64_t vuid,
5285 char *param, int tpscnt,
5286 char *data, int tdscnt,
5287 int mdrcnt,int mprcnt,
5288 char **rdata,char **rparam,
5289 int *rdata_len,int *rparam_len)
5291 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5292 char *str2 = skip_string(param,tpscnt,str1);
5293 char *p = skip_string(param,tpscnt,str2);
5294 int uLevel;
5295 int succnt;
5296 struct pack_desc desc;
5298 if (!str1 || !str2 || !p) {
5299 return False;
5301 memset((char *)&desc,'\0',sizeof(desc));
5303 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5305 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5307 /* check it's a supported varient */
5308 if (strcmp(str1,"WrLeh") != 0) {
5309 return False;
5311 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5312 return False;
5315 if (mdrcnt > 0) {
5316 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5317 if (!*rdata) {
5318 return False;
5321 desc.base = *rdata;
5322 desc.buflen = mdrcnt;
5323 desc.format = str2;
5324 if (init_package(&desc,1,0)) {
5325 PACKS(&desc,"B13","lpd");
5328 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5330 *rdata_len = desc.usedlen;
5332 *rparam_len = 8;
5333 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5334 if (!*rparam) {
5335 return False;
5337 SSVALS(*rparam,0,desc.errcode);
5338 SSVAL(*rparam,2,0);
5339 SSVAL(*rparam,4,succnt);
5340 SSVAL(*rparam,6,1);
5342 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5344 return True;
5347 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5348 connection_struct *conn, uint64_t vuid,
5349 char *param, int tpscnt,
5350 char *data, int tdscnt,
5351 int mdrcnt,int mprcnt,
5352 char **rdata,char **rparam,
5353 int *rdata_len,int *rparam_len)
5355 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5356 char *str2 = skip_string(param,tpscnt,str1);
5357 char *p = skip_string(param,tpscnt,str2);
5358 int uLevel;
5359 int succnt;
5360 struct pack_desc desc;
5362 if (!str1 || !str2 || !p) {
5363 return False;
5366 memset((char *)&desc,'\0',sizeof(desc));
5368 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5370 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5372 /* check it's a supported varient */
5373 if (strcmp(str1,"WrLeh") != 0) {
5374 return False;
5376 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5377 return False;
5380 if (mdrcnt > 0) {
5381 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5382 if (!*rdata) {
5383 return False;
5386 memset((char *)&desc,'\0',sizeof(desc));
5387 desc.base = *rdata;
5388 desc.buflen = mdrcnt;
5389 desc.format = str2;
5390 if (init_package(&desc,1,0)) {
5391 PACKS(&desc,"B13","lp0");
5394 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5396 *rdata_len = desc.usedlen;
5398 *rparam_len = 8;
5399 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5400 if (!*rparam) {
5401 return False;
5403 SSVALS(*rparam,0,desc.errcode);
5404 SSVAL(*rparam,2,0);
5405 SSVAL(*rparam,4,succnt);
5406 SSVAL(*rparam,6,1);
5408 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5410 return True;
5413 /****************************************************************************
5414 List open sessions
5415 ****************************************************************************/
5417 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5418 connection_struct *conn, uint64_t vuid,
5419 char *param, int tpscnt,
5420 char *data, int tdscnt,
5421 int mdrcnt,int mprcnt,
5422 char **rdata,char **rparam,
5423 int *rdata_len,int *rparam_len)
5426 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5427 char *str2 = skip_string(param,tpscnt,str1);
5428 char *p = skip_string(param,tpscnt,str2);
5429 int uLevel;
5430 struct pack_desc desc;
5431 int i;
5433 TALLOC_CTX *mem_ctx = talloc_tos();
5434 WERROR werr;
5435 NTSTATUS status;
5436 struct rpc_pipe_client *cli = NULL;
5437 struct dcerpc_binding_handle *b = NULL;
5438 struct srvsvc_NetSessInfoCtr info_ctr;
5439 uint32_t totalentries, resume_handle = 0;
5440 uint32_t count = 0;
5442 if (!str1 || !str2 || !p) {
5443 return False;
5446 ZERO_STRUCT(desc);
5448 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5450 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5451 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5452 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5454 /* check it's a supported varient */
5455 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5456 return False;
5458 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5459 return False;
5462 status = rpc_pipe_open_interface(mem_ctx,
5463 &ndr_table_srvsvc,
5464 conn->session_info,
5465 conn->sconn->remote_address,
5466 conn->sconn->local_address,
5467 conn->sconn->msg_ctx,
5468 &cli);
5469 if (!NT_STATUS_IS_OK(status)) {
5470 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5471 nt_errstr(status)));
5472 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5473 goto out;
5475 b = cli->binding_handle;
5477 info_ctr.level = 1;
5478 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5479 if (info_ctr.ctr.ctr1 == NULL) {
5480 desc.errcode = W_ERROR_V(WERR_NOT_ENOUGH_MEMORY);
5481 goto out;
5484 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5485 cli->srv_name_slash,
5486 NULL, /* client */
5487 NULL, /* user */
5488 &info_ctr,
5489 (uint32_t)-1, /* max_buffer */
5490 &totalentries,
5491 &resume_handle,
5492 &werr);
5493 if (!NT_STATUS_IS_OK(status)) {
5494 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5495 nt_errstr(status)));
5496 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5497 goto out;
5500 if (!W_ERROR_IS_OK(werr)) {
5501 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5502 win_errstr(werr)));
5503 desc.errcode = W_ERROR_V(werr);
5504 goto out;
5507 count = info_ctr.ctr.ctr1->count;
5509 out:
5510 if (mdrcnt > 0) {
5511 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5512 if (!*rdata) {
5513 return False;
5517 desc.base = *rdata;
5518 desc.buflen = mdrcnt;
5519 desc.format = str2;
5520 if (!init_package(&desc, count,0)) {
5521 return False;
5524 for(i=0; i < count; i++) {
5525 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5526 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5527 PACKI(&desc, "W", 1); /* num conns */
5528 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5529 PACKI(&desc, "W", 1); /* num users */
5530 PACKI(&desc, "D", 0); /* session time */
5531 PACKI(&desc, "D", 0); /* idle time */
5532 PACKI(&desc, "D", 0); /* flags */
5533 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5536 *rdata_len = desc.usedlen;
5538 *rparam_len = 8;
5539 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5540 if (!*rparam) {
5541 return False;
5543 SSVALS(*rparam,0,desc.errcode);
5544 SSVAL(*rparam,2,0); /* converter */
5545 SSVAL(*rparam,4, count); /* count */
5547 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5549 return True;
5553 /****************************************************************************
5554 The buffer was too small.
5555 ****************************************************************************/
5557 static bool api_TooSmall(struct smbd_server_connection *sconn,
5558 connection_struct *conn,uint64_t vuid, char *param, char *data,
5559 int mdrcnt, int mprcnt,
5560 char **rdata, char **rparam,
5561 int *rdata_len, int *rparam_len)
5563 *rparam_len = MIN(*rparam_len,mprcnt);
5564 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5565 if (!*rparam) {
5566 return False;
5569 *rdata_len = 0;
5571 SSVAL(*rparam,0,NERR_BufTooSmall);
5573 DEBUG(3,("Supplied buffer too small in API command\n"));
5575 return True;
5578 /****************************************************************************
5579 The request is not supported.
5580 ****************************************************************************/
5582 static bool api_Unsupported(struct smbd_server_connection *sconn,
5583 connection_struct *conn, uint64_t vuid,
5584 char *param, int tpscnt,
5585 char *data, int tdscnt,
5586 int mdrcnt, int mprcnt,
5587 char **rdata, char **rparam,
5588 int *rdata_len, int *rparam_len)
5590 *rparam_len = 4;
5591 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5592 if (!*rparam) {
5593 return False;
5596 *rdata_len = 0;
5598 SSVAL(*rparam,0,NERR_notsupported);
5599 SSVAL(*rparam,2,0); /* converter word */
5601 DEBUG(3,("Unsupported API command\n"));
5603 return True;
5606 static const struct {
5607 const char *name;
5608 int id;
5609 bool (*fn)(struct smbd_server_connection *sconn,
5610 connection_struct *, uint64_t,
5611 char *, int,
5612 char *, int,
5613 int,int,char **,char **,int *,int *);
5614 bool auth_user; /* Deny anonymous access? */
5615 } api_commands[] = {
5617 .name = "RNetShareEnum",
5618 .id = RAP_WshareEnum,
5619 .fn = api_RNetShareEnum,
5620 .auth_user = true,
5623 .name = "RNetShareGetInfo",
5624 .id = RAP_WshareGetInfo,
5625 .fn = api_RNetShareGetInfo
5628 .name = "RNetShareAdd",
5629 .id = RAP_WshareAdd,
5630 .fn = api_RNetShareAdd
5633 .name = "RNetSessionEnum",
5634 .id = RAP_WsessionEnum,
5635 .fn = api_RNetSessionEnum,
5636 .auth_user = true,
5639 .name = "RNetServerGetInfo",
5640 .id = RAP_WserverGetInfo,
5641 .fn = api_RNetServerGetInfo
5644 .name = "RNetGroupEnum",
5645 .id = RAP_WGroupEnum,
5646 .fn = api_RNetGroupEnum, True
5649 .name = "RNetGroupGetUsers",
5650 .id = RAP_WGroupGetUsers,
5651 .fn = api_RNetGroupGetUsers,
5652 .auth_user = true},
5654 .name = "RNetUserEnum",
5655 .id = RAP_WUserEnum,
5656 .fn = api_RNetUserEnum,
5657 .auth_user = true,
5660 .name = "RNetUserGetInfo",
5661 .id = RAP_WUserGetInfo,
5662 .fn = api_RNetUserGetInfo
5665 .name = "NetUserGetGroups",
5666 .id = RAP_WUserGetGroups,
5667 .fn = api_NetUserGetGroups
5670 .name = "NetWkstaGetInfo",
5671 .id = RAP_WWkstaGetInfo,
5672 .fn = api_NetWkstaGetInfo
5675 .name = "DosPrintQEnum",
5676 .id = RAP_WPrintQEnum,
5677 .fn = api_DosPrintQEnum,
5678 .auth_user = true,
5681 .name = "DosPrintQGetInfo",
5682 .id = RAP_WPrintQGetInfo,
5683 .fn = api_DosPrintQGetInfo
5686 .name = "WPrintQueuePause",
5687 .id = RAP_WPrintQPause,
5688 .fn = api_WPrintQueueCtrl
5691 .name = "WPrintQueueResume",
5692 .id = RAP_WPrintQContinue,
5693 .fn = api_WPrintQueueCtrl
5696 .name = "WPrintJobEnumerate",
5697 .id = RAP_WPrintJobEnum,
5698 .fn = api_WPrintJobEnumerate
5701 .name = "WPrintJobGetInfo",
5702 .id = RAP_WPrintJobGetInfo,
5703 .fn = api_WPrintJobGetInfo
5706 .name = "RDosPrintJobDel",
5707 .id = RAP_WPrintJobDel,
5708 .fn = api_RDosPrintJobDel
5711 .name = "RDosPrintJobPause",
5712 .id = RAP_WPrintJobPause,
5713 .fn = api_RDosPrintJobDel
5716 .name = "RDosPrintJobResume",
5717 .id = RAP_WPrintJobContinue,
5718 .fn = api_RDosPrintJobDel
5721 .name = "WPrintDestEnum",
5722 .id = RAP_WPrintDestEnum,
5723 .fn = api_WPrintDestEnum
5726 .name = "WPrintDestGetInfo",
5727 .id = RAP_WPrintDestGetInfo,
5728 .fn = api_WPrintDestGetInfo
5731 .name = "NetRemoteTOD",
5732 .id = RAP_NetRemoteTOD,
5733 .fn = api_NetRemoteTOD
5736 .name = "WPrintQueuePurge",
5737 .id = RAP_WPrintQPurge,
5738 .fn = api_WPrintQueueCtrl
5741 .name = "NetServerEnum2",
5742 .id = RAP_NetServerEnum2,
5743 .fn = api_RNetServerEnum2
5744 }, /* anon OK */
5746 .name = "NetServerEnum3",
5747 .id = RAP_NetServerEnum3,
5748 .fn = api_RNetServerEnum3
5749 }, /* anon OK */
5751 .name = "WAccessGetUserPerms",
5752 .id = RAP_WAccessGetUserPerms,
5753 .fn = api_WAccessGetUserPerms
5756 .name = "WWkstaUserLogon",
5757 .id = RAP_WWkstaUserLogon,
5758 .fn = api_WWkstaUserLogon
5761 .name = "PrintJobInfo",
5762 .id = RAP_WPrintJobSetInfo,
5763 .fn = api_PrintJobInfo
5766 .name = "WPrintDriverEnum",
5767 .id = RAP_WPrintDriverEnum,
5768 .fn = api_WPrintDriverEnum
5771 .name = "WPrintQProcEnum",
5772 .id = RAP_WPrintQProcessorEnum,
5773 .fn = api_WPrintQProcEnum
5776 .name = "WPrintPortEnum",
5777 .id = RAP_WPrintPortEnum,
5778 .fn = api_WPrintPortEnum
5781 .name = "SamOEMChangePassword",
5782 .id = RAP_SamOEMChgPasswordUser2_P,
5783 .fn = api_SamOEMChangePassword
5784 }, /* anon OK */
5786 .name = NULL,
5787 .id = -1,
5788 .fn = api_Unsupported}
5790 * The following RAP calls are not implemented by Samba:
5791 * RAP_WFileEnum2 - anon not OK
5796 /****************************************************************************
5797 Handle remote api calls.
5798 ****************************************************************************/
5800 void api_reply(connection_struct *conn, uint64_t vuid,
5801 struct smb_request *req,
5802 char *data, char *params,
5803 int tdscnt, int tpscnt,
5804 int mdrcnt, int mprcnt)
5806 int api_command;
5807 char *rdata = NULL;
5808 char *rparam = NULL;
5809 const char *name1 = NULL;
5810 const char *name2 = NULL;
5811 int rdata_len = 0;
5812 int rparam_len = 0;
5813 bool reply=False;
5814 int i;
5816 if (!params) {
5817 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5818 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5819 return;
5822 if (tpscnt < 2) {
5823 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5824 return;
5826 api_command = SVAL(params,0);
5827 /* Is there a string at position params+2 ? */
5828 if (skip_string(params,tpscnt,params+2)) {
5829 name1 = params + 2;
5830 } else {
5831 name1 = "";
5833 name2 = skip_string(params,tpscnt,params+2);
5834 if (!name2) {
5835 name2 = "";
5838 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5839 api_command,
5840 name1,
5841 name2,
5842 tdscnt,tpscnt,mdrcnt,mprcnt));
5844 for (i=0;api_commands[i].name;i++) {
5845 if (api_commands[i].id == api_command && api_commands[i].fn) {
5846 DEBUG(3,("Doing %s\n",api_commands[i].name));
5847 break;
5851 /* Check whether this api call can be done anonymously */
5853 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5854 struct auth_session_info *si = NULL;
5855 NTSTATUS status;
5857 status = smbXsrv_session_info_lookup(conn->sconn->client,
5858 vuid,
5859 &si);
5860 if (!NT_STATUS_IS_OK(status)) {
5861 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5862 return;
5865 if (security_session_user_level(si, NULL) < SECURITY_USER) {
5866 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5867 return;
5871 rdata = (char *)SMB_MALLOC(1024);
5872 if (rdata) {
5873 memset(rdata,'\0',1024);
5876 rparam = (char *)SMB_MALLOC(1024);
5877 if (rparam) {
5878 memset(rparam,'\0',1024);
5881 if(!rdata || !rparam) {
5882 DEBUG(0,("api_reply: malloc fail !\n"));
5883 SAFE_FREE(rdata);
5884 SAFE_FREE(rparam);
5885 reply_nterror(req, NT_STATUS_NO_MEMORY);
5886 return;
5889 reply = api_commands[i].fn(req->sconn, conn,
5890 vuid,
5891 params,tpscnt, /* params + length */
5892 data,tdscnt, /* data + length */
5893 mdrcnt,mprcnt,
5894 &rdata,&rparam,&rdata_len,&rparam_len);
5897 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5898 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5899 mdrcnt,mprcnt,
5900 &rdata,&rparam,&rdata_len,&rparam_len);
5903 /* if we get False back then it's actually unsupported */
5904 if (!reply) {
5905 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5906 data,
5907 tdscnt,mdrcnt,mprcnt,
5908 &rdata,&rparam,&rdata_len,&rparam_len);
5911 /* If api_Unsupported returns false we can't return anything. */
5912 if (reply) {
5913 send_trans_reply(conn, req, rparam, rparam_len,
5914 rdata, rdata_len, False);
5917 SAFE_FREE(rdata);
5918 SAFE_FREE(rparam);
5919 return;