ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source3 / smbd / smb1_lanman.c
blob8bcddcbb8c2e0d5f5dc7e2da1497eaace604cbb2
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 "lib/util/util_file.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "source3/smbd/smbXsrv_session.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_samr_c.h"
35 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
39 #include "../librpc/gen_ndr/rap.h"
40 #include "../lib/util/binsearch.h"
41 #include "../libcli/auth/libcli_auth.h"
42 #include "rpc_client/init_lsa.h"
43 #include "../libcli/security/security.h"
44 #include "printing.h"
45 #include "passdb/machine_sid.h"
46 #include "auth.h"
47 #include "rpc_server/rpc_ncacn_np.h"
48 #include "lib/util/string_wrappers.h"
49 #include "source3/printing/rap_jobid.h"
50 #include "source3/lib/substitute.h"
52 #ifdef CHECK_TYPES
53 #undef CHECK_TYPES
54 #endif
55 #define CHECK_TYPES 0
57 #define NERR_Success 0
58 #define NERR_badpass 86
59 #define NERR_notsupported 50
61 #define NERR_BASE (2100)
62 #define NERR_BufTooSmall (NERR_BASE+23)
63 #define NERR_JobNotFound (NERR_BASE+51)
64 #define NERR_DestNotFound (NERR_BASE+52)
66 #define ACCESS_READ 0x01
67 #define ACCESS_WRITE 0x02
68 #define ACCESS_CREATE 0x04
70 #define SHPWLEN 8 /* share password length */
72 /* Limit size of ipc replies */
74 static char *smb_realloc_limit(void *ptr, size_t size)
76 char *val;
78 size = MAX((size),4*1024);
79 val = (char *)SMB_REALLOC(ptr,size);
80 if (val) {
81 memset(val,'\0',size);
83 return val;
86 static bool api_Unsupported(struct smbd_server_connection *sconn,
87 connection_struct *conn, uint64_t vuid,
88 char *param, int tpscnt,
89 char *data, int tdscnt,
90 int mdrcnt, int mprcnt,
91 char **rdata, char **rparam,
92 int *rdata_len, int *rparam_len);
94 static bool api_TooSmall(struct smbd_server_connection *sconn,
95 connection_struct *conn, uint64_t vuid, char *param, char *data,
96 int mdrcnt, int mprcnt,
97 char **rdata, char **rparam,
98 int *rdata_len, int *rparam_len);
101 static int CopyExpanded(connection_struct *conn,
102 int snum, char **dst, char *src, int *p_space_remaining)
104 TALLOC_CTX *ctx = talloc_tos();
105 const struct loadparm_substitution *lp_sub =
106 loadparm_s3_global_substitution();
107 char *buf = NULL;
108 int l;
110 if (!src || !dst || !p_space_remaining || !(*dst) ||
111 *p_space_remaining <= 0) {
112 return 0;
115 buf = talloc_strdup(ctx, src);
116 if (!buf) {
117 *p_space_remaining = 0;
118 return 0;
120 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, lp_sub, snum));
121 if (!buf) {
122 *p_space_remaining = 0;
123 return 0;
125 buf = talloc_sub_full(ctx,
126 lp_servicename(ctx, lp_sub, SNUM(conn)),
127 conn->session_info->unix_info->unix_name,
128 conn->connectpath,
129 conn->session_info->unix_token->gid,
130 conn->session_info->unix_info->sanitized_username,
131 conn->session_info->info->domain_name,
132 buf);
133 if (!buf) {
134 *p_space_remaining = 0;
135 return 0;
137 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
138 if (l == 0) {
139 return 0;
141 (*dst) += l;
142 (*p_space_remaining) -= l;
143 return l;
146 static int CopyAndAdvance(char **dst, char *src, int *n)
148 int l;
149 if (!src || !dst || !n || !(*dst)) {
150 return 0;
152 l = push_ascii(*dst,src,*n, STR_TERMINATE);
153 if (l == 0) {
154 return 0;
156 (*dst) += l;
157 (*n) -= l;
158 return l;
161 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
163 TALLOC_CTX *ctx = talloc_tos();
164 const struct loadparm_substitution *lp_sub =
165 loadparm_s3_global_substitution();
166 char *buf = NULL;
167 if (!s) {
168 return 0;
170 buf = talloc_strdup(ctx,s);
171 if (!buf) {
172 return 0;
174 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, lp_sub, snum));
175 if (!buf) {
176 return 0;
178 buf = talloc_sub_full(ctx,
179 lp_servicename(ctx, lp_sub, SNUM(conn)),
180 conn->session_info->unix_info->unix_name,
181 conn->connectpath,
182 conn->session_info->unix_token->gid,
183 conn->session_info->unix_info->sanitized_username,
184 conn->session_info->info->domain_name,
185 buf);
186 if (!buf) {
187 return 0;
189 return strlen(buf) + 1;
192 /****************************************************************
193 Return an SVAL at a pointer, or failval if beyond the end.
194 ****************************************************************/
196 static int get_safe_SVAL(
197 const char *buf_base,
198 size_t buf_len,
199 char *ptr,
200 size_t off,
201 int failval)
204 * Note we use off+1 here, not off+2 as SVAL accesses ptr[0]
205 * and ptr[1], NOT ptr[2].
207 if (!is_offset_safe(buf_base, buf_len, ptr, off+1)) {
208 return failval;
210 return SVAL(ptr,off);
213 /****************************************************************
214 Return an IVAL at a pointer, or failval if beyond the end.
215 ****************************************************************/
217 static int get_safe_IVAL(
218 const char *buf_base,
219 size_t buf_len,
220 char *ptr,
221 size_t off,
222 int failval)
225 * Note we use off+3 here, not off+4 as IVAL accesses
226 * ptr[0] ptr[1] ptr[2] ptr[3] NOT ptr[4].
228 if (!is_offset_safe(buf_base, buf_len, ptr, off+3)) {
229 return failval;
231 return IVAL(ptr,off);
234 /****************************************************************
235 Return a safe pointer into a buffer, or NULL.
236 ****************************************************************/
238 static char *get_safe_ptr(
239 const char *buf_base,
240 size_t buf_len,
241 char *ptr,
242 size_t off)
244 return is_offset_safe(buf_base, buf_len, ptr, off) ?
245 ptr + off : NULL;
248 /*******************************************************************
249 Check a API string for validity when we only need to check the prefix.
250 ******************************************************************/
252 static bool prefix_ok(const char *str, const char *prefix)
254 return(strncmp(str,prefix,strlen(prefix)) == 0);
257 struct pack_desc {
258 const char *format; /* formatstring for structure */
259 const char *subformat; /* subformat for structure */
260 char *base; /* baseaddress of buffer */
261 int buflen; /* remaining size for fixed part; on init: length of base */
262 int subcount; /* count of substructures */
263 char *structbuf; /* pointer into buffer for remaining fixed part */
264 int stringlen; /* remaining size for variable part */
265 char *stringbuf; /* pointer into buffer for remaining variable part */
266 int neededlen; /* total needed size */
267 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
268 const char *curpos; /* current position; pointer into format or subformat */
269 int errcode;
272 static int get_counter(const char **p)
274 int i, n;
275 if (!p || !(*p)) {
276 return 1;
278 if (!isdigit((int)**p)) {
279 return 1;
281 for (n = 0;;) {
282 i = **p;
283 if (isdigit(i)) {
284 n = 10 * n + (i - '0');
285 } else {
286 return n;
288 (*p)++;
292 static int getlen(const char *p)
294 int n = 0;
295 if (!p) {
296 return 0;
299 while (*p) {
300 switch( *p++ ) {
301 case 'W': /* word (2 byte) */
302 n += 2;
303 break;
304 case 'K': /* status word? (2 byte) */
305 n += 2;
306 break;
307 case 'N': /* count of substructures (word) at end */
308 n += 2;
309 break;
310 case 'D': /* double word (4 byte) */
311 case 'z': /* offset to zero terminated string (4 byte) */
312 case 'l': /* offset to user data (4 byte) */
313 n += 4;
314 break;
315 case 'b': /* offset to data (with counter) (4 byte) */
316 n += 4;
317 get_counter(&p);
318 break;
319 case 'B': /* byte (with optional counter) */
320 n += get_counter(&p);
321 break;
324 return n;
327 static bool init_package(struct pack_desc *p, int count, int subcount)
329 int n = p->buflen;
330 int i;
332 if (!p->format || !p->base) {
333 return False;
336 i = count * getlen(p->format);
337 if (p->subformat) {
338 i += subcount * getlen(p->subformat);
340 p->structbuf = p->base;
341 p->neededlen = 0;
342 p->usedlen = 0;
343 p->subcount = 0;
344 p->curpos = p->format;
345 if (i > n) {
346 p->neededlen = i;
347 i = n = 0;
348 #if 0
350 * This is the old error code we used. Apparently
351 * WinNT/2k systems return ERRbuftoosmall (2123) and
352 * OS/2 needs this. I'm leaving this here so we can revert
353 * if needed. JRA.
355 p->errcode = ERRmoredata;
356 #else
357 p->errcode = ERRbuftoosmall;
358 #endif
359 } else {
360 p->errcode = NERR_Success;
362 p->buflen = i;
363 n -= i;
364 p->stringbuf = p->base + i;
365 p->stringlen = n;
366 return (p->errcode == NERR_Success);
369 static int package(struct pack_desc *p, ...)
371 va_list args;
372 int needed=0, stringneeded;
373 const char *str=NULL;
374 int is_string=0, stringused;
375 int32_t temp;
377 va_start(args,p);
379 if (!*p->curpos) {
380 if (!p->subcount) {
381 p->curpos = p->format;
382 } else {
383 p->curpos = p->subformat;
384 p->subcount--;
387 #if CHECK_TYPES
388 str = va_arg(args,char*);
389 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
390 #endif
391 stringneeded = -1;
393 if (!p->curpos) {
394 va_end(args);
395 return 0;
398 switch( *p->curpos++ ) {
399 case 'W': /* word (2 byte) */
400 needed = 2;
401 temp = va_arg(args,int);
402 if (p->buflen >= needed) {
403 SSVAL(p->structbuf,0,temp);
405 break;
406 case 'K': /* status word? (2 byte) */
407 needed = 2;
408 temp = va_arg(args,int);
409 if (p->buflen >= needed) {
410 SSVAL(p->structbuf,0,temp);
412 break;
413 case 'N': /* count of substructures (word) at end */
414 needed = 2;
415 p->subcount = va_arg(args,int);
416 if (p->buflen >= needed) {
417 SSVAL(p->structbuf,0,p->subcount);
419 break;
420 case 'D': /* double word (4 byte) */
421 needed = 4;
422 temp = va_arg(args,int);
423 if (p->buflen >= needed) {
424 SIVAL(p->structbuf,0,temp);
426 break;
427 case 'B': /* byte (with optional counter) */
428 needed = get_counter(&p->curpos);
430 char *s = va_arg(args,char*);
431 if (p->buflen >= needed) {
432 strlcpy(p->structbuf,s?s:"",needed);
435 break;
436 case 'z': /* offset to zero terminated string (4 byte) */
437 str = va_arg(args,char*);
438 stringneeded = (str ? strlen(str)+1 : 0);
439 is_string = 1;
440 break;
441 case 'l': /* offset to user data (4 byte) */
442 str = va_arg(args,char*);
443 stringneeded = va_arg(args,int);
444 is_string = 0;
445 break;
446 case 'b': /* offset to data (with counter) (4 byte) */
447 str = va_arg(args,char*);
448 stringneeded = get_counter(&p->curpos);
449 is_string = 0;
450 break;
453 va_end(args);
454 if (stringneeded >= 0) {
455 needed = 4;
456 if (p->buflen >= needed) {
457 stringused = stringneeded;
458 if (stringused > p->stringlen) {
459 stringused = (is_string ? p->stringlen : 0);
460 if (p->errcode == NERR_Success) {
461 p->errcode = ERRmoredata;
464 if (!stringused) {
465 SIVAL(p->structbuf,0,0);
466 } else {
467 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
468 memcpy(p->stringbuf,str?str:"",stringused);
469 if (is_string) {
470 p->stringbuf[stringused-1] = '\0';
472 p->stringbuf += stringused;
473 p->stringlen -= stringused;
474 p->usedlen += stringused;
477 p->neededlen += stringneeded;
480 p->neededlen += needed;
481 if (p->buflen >= needed) {
482 p->structbuf += needed;
483 p->buflen -= needed;
484 p->usedlen += needed;
485 } else {
486 if (p->errcode == NERR_Success) {
487 p->errcode = ERRmoredata;
490 return 1;
493 #if CHECK_TYPES
494 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
495 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
496 #else
497 #define PACK(desc,t,v) package(desc,v)
498 #define PACKl(desc,t,v,l) package(desc,v,l)
499 #endif
501 static void PACKI(struct pack_desc* desc, const char *t,int v)
503 PACK(desc,t,v);
506 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
508 PACK(desc,t,v);
511 /****************************************************************************
512 Get a print queue.
513 ****************************************************************************/
515 static void PackDriverData(struct pack_desc* desc)
517 char drivdata[4+4+32];
518 SIVAL(drivdata,0,sizeof drivdata); /* cb */
519 SIVAL(drivdata,4,1000); /* lVersion */
520 memset(drivdata+8,0,32); /* szDeviceName */
521 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
522 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
525 static int check_printq_info(struct pack_desc* desc,
526 unsigned int uLevel, char *id1, char *id2)
528 desc->subformat = NULL;
529 switch( uLevel ) {
530 case 0:
531 desc->format = "B13";
532 break;
533 case 1:
534 desc->format = "B13BWWWzzzzzWW";
535 break;
536 case 2:
537 desc->format = "B13BWWWzzzzzWN";
538 desc->subformat = "WB21BB16B10zWWzDDz";
539 break;
540 case 3:
541 desc->format = "zWWWWzzzzWWzzl";
542 break;
543 case 4:
544 desc->format = "zWWWWzzzzWNzzl";
545 desc->subformat = "WWzWWDDzz";
546 break;
547 case 5:
548 desc->format = "z";
549 break;
550 case 51:
551 desc->format = "K";
552 break;
553 case 52:
554 desc->format = "WzzzzzzzzN";
555 desc->subformat = "z";
556 break;
557 default:
558 DEBUG(0,("check_printq_info: invalid level %d\n",
559 uLevel ));
560 return False;
562 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
563 DEBUG(0,("check_printq_info: invalid format %s\n",
564 id1 ? id1 : "<NULL>" ));
565 return False;
567 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
568 DEBUG(0,("check_printq_info: invalid subformat %s\n",
569 id2 ? id2 : "<NULL>" ));
570 return False;
572 return True;
576 #define RAP_JOB_STATUS_QUEUED 0
577 #define RAP_JOB_STATUS_PAUSED 1
578 #define RAP_JOB_STATUS_SPOOLING 2
579 #define RAP_JOB_STATUS_PRINTING 3
580 #define RAP_JOB_STATUS_PRINTED 4
582 #define RAP_QUEUE_STATUS_PAUSED 1
583 #define RAP_QUEUE_STATUS_ERROR 2
585 /* turn a print job status into a on the wire status
587 static int printj_spoolss_status(int v)
589 if (v == JOB_STATUS_QUEUED)
590 return RAP_JOB_STATUS_QUEUED;
591 if (v & JOB_STATUS_PAUSED)
592 return RAP_JOB_STATUS_PAUSED;
593 if (v & JOB_STATUS_SPOOLING)
594 return RAP_JOB_STATUS_SPOOLING;
595 if (v & JOB_STATUS_PRINTING)
596 return RAP_JOB_STATUS_PRINTING;
597 return 0;
600 /* turn a print queue status into a on the wire status
602 static int printq_spoolss_status(int v)
604 if (v == PRINTER_STATUS_OK)
605 return 0;
606 if (v & PRINTER_STATUS_PAUSED)
607 return RAP_QUEUE_STATUS_PAUSED;
608 return RAP_QUEUE_STATUS_ERROR;
611 static void fill_spoolss_printjob_info(int uLevel,
612 struct pack_desc *desc,
613 struct spoolss_JobInfo2 *info2,
614 int n)
616 time_t t = spoolss_Time_to_time_t(&info2->submitted);
618 /* the client expects localtime */
619 t -= get_time_zone(t);
621 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
622 if (uLevel == 1) {
623 PACKS(desc,"B21", info2->user_name); /* szUserName */
624 PACKS(desc,"B",""); /* pad */
625 PACKS(desc,"B16",""); /* szNotifyName */
626 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
627 PACKS(desc,"z",""); /* pszParms */
628 PACKI(desc,"W",n+1); /* uPosition */
629 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
630 PACKS(desc,"z",""); /* pszStatus */
631 PACKI(desc,"D", t); /* ulSubmitted */
632 PACKI(desc,"D", info2->size); /* ulSize */
633 PACKS(desc,"z", info2->document_name); /* pszComment */
635 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
636 PACKI(desc,"W", info2->priority); /* uPriority */
637 PACKS(desc,"z", info2->user_name); /* pszUserName */
638 PACKI(desc,"W",n+1); /* uPosition */
639 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
640 PACKI(desc,"D",t); /* ulSubmitted */
641 PACKI(desc,"D", info2->size); /* ulSize */
642 PACKS(desc,"z","Samba"); /* pszComment */
643 PACKS(desc,"z", info2->document_name); /* pszDocument */
644 if (uLevel == 3) {
645 PACKS(desc,"z",""); /* pszNotifyName */
646 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
647 PACKS(desc,"z",""); /* pszParms */
648 PACKS(desc,"z",""); /* pszStatus */
649 PACKS(desc,"z", info2->printer_name); /* pszQueue */
650 PACKS(desc,"z","lpd"); /* pszQProcName */
651 PACKS(desc,"z",""); /* pszQProcParms */
652 PACKS(desc,"z","NULL"); /* pszDriverName */
653 PackDriverData(desc); /* pDriverData */
654 PACKS(desc,"z",""); /* pszPrinterName */
655 } else if (uLevel == 4) { /* OS2 */
656 PACKS(desc,"z",""); /* pszSpoolFileName */
657 PACKS(desc,"z",""); /* pszPortName */
658 PACKS(desc,"z",""); /* pszStatus */
659 PACKI(desc,"D",0); /* ulPagesSpooled */
660 PACKI(desc,"D",0); /* ulPagesSent */
661 PACKI(desc,"D",0); /* ulPagesPrinted */
662 PACKI(desc,"D",0); /* ulTimePrinted */
663 PACKI(desc,"D",0); /* ulExtendJobStatus */
664 PACKI(desc,"D",0); /* ulStartPage */
665 PACKI(desc,"D",0); /* ulEndPage */
670 /********************************************************************
671 Respond to the DosPrintQInfo command with a level of 52
672 This is used to get printer driver information for Win9x clients
673 ********************************************************************/
674 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
675 struct pack_desc* desc, int count,
676 const char *printer_name)
678 int i;
679 fstring location;
680 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
681 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
682 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
684 PACKI(desc, "W", 0x0400); /* don't know */
685 PACKS(desc, "z", driver->driver_name); /* long printer name */
686 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
687 PACKS(desc, "z", driver->data_file); /* Datafile name */
688 PACKS(desc, "z", driver->monitor_name); /* language monitor */
690 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
691 standard_sub_basic( "", "", location, sizeof(location)-1 );
692 PACKS(desc,"z", location); /* share to retrieve files */
694 PACKS(desc,"z", driver->default_datatype); /* default data type */
695 PACKS(desc,"z", driver->help_file); /* helpfile name */
696 PACKS(desc,"z", driver->driver_path); /* driver name */
698 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
699 DEBUG(3,("Driver: %s:\n",driver->driver_path));
700 DEBUG(3,("Data File: %s:\n",driver->data_file));
701 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
702 DEBUG(3,("Driver Location: %s:\n",location));
703 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
704 DEBUG(3,("Help File: %s:\n",driver->help_file));
705 PACKI(desc,"N",count); /* number of files to copy */
707 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
709 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
710 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
711 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
714 /* sanity check */
715 if ( i != count )
716 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
717 count, i));
719 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
721 desc->errcode=NERR_Success;
725 static const char *strip_unc(const char *unc)
727 char *p;
729 if (unc == NULL) {
730 return NULL;
733 if ((p = strrchr(unc, '\\')) != NULL) {
734 return p+1;
737 return unc;
740 static void fill_printq_info(int uLevel,
741 struct pack_desc* desc,
742 int count,
743 union spoolss_JobInfo *job_info,
744 struct spoolss_DriverInfo3 *driver_info,
745 struct spoolss_PrinterInfo2 *printer_info)
747 switch (uLevel) {
748 case 0:
749 case 1:
750 case 2:
751 PACKS(desc,"B13", strip_unc(printer_info->printername));
752 break;
753 case 3:
754 case 4:
755 case 5:
756 PACKS(desc,"z", strip_unc(printer_info->printername));
757 break;
758 case 51:
759 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
760 break;
763 if (uLevel == 1 || uLevel == 2) {
764 PACKS(desc,"B",""); /* alignment */
765 PACKI(desc,"W",5); /* priority */
766 PACKI(desc,"W",0); /* start time */
767 PACKI(desc,"W",0); /* until time */
768 PACKS(desc,"z",""); /* pSepFile */
769 PACKS(desc,"z","lpd"); /* pPrProc */
770 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
771 PACKS(desc,"z",""); /* pParms */
772 if (printer_info->printername == NULL) {
773 PACKS(desc,"z","UNKNOWN PRINTER");
774 PACKI(desc,"W",LPSTAT_ERROR);
775 } else {
776 PACKS(desc,"z", printer_info->comment);
777 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
779 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
782 if (uLevel == 3 || uLevel == 4) {
783 PACKI(desc,"W",5); /* uPriority */
784 PACKI(desc,"W",0); /* uStarttime */
785 PACKI(desc,"W",0); /* uUntiltime */
786 PACKI(desc,"W",5); /* pad1 */
787 PACKS(desc,"z",""); /* pszSepFile */
788 PACKS(desc,"z","WinPrint"); /* pszPrProc */
789 PACKS(desc,"z",NULL); /* pszParms */
790 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
791 /* "don't ask" that it's done this way to fix corrupted
792 Win9X/ME printer comments. */
793 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
794 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
795 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
796 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
797 PackDriverData(desc); /* pDriverData */
800 if (uLevel == 2 || uLevel == 4) {
801 int i;
802 for (i = 0; i < count; i++) {
803 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
807 if (uLevel==52)
808 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
811 /* This function returns the number of files for a given driver */
812 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
814 int result = 0;
816 /* count the number of files */
817 while (driver->dependent_files && *driver->dependent_files[result])
818 result++;
820 return result;
823 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
824 connection_struct *conn, uint64_t vuid,
825 char *param, int tpscnt,
826 char *data, int tdscnt,
827 int mdrcnt,int mprcnt,
828 char **rdata,char **rparam,
829 int *rdata_len,int *rparam_len)
831 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
832 char *str2 = skip_string(param,tpscnt,str1);
833 char *p = skip_string(param,tpscnt,str2);
834 char *QueueName = p;
835 unsigned int uLevel;
836 uint32_t count = 0;
837 char *str3;
838 struct pack_desc desc;
839 char* tmpdata=NULL;
841 WERROR werr = WERR_OK;
842 TALLOC_CTX *mem_ctx = talloc_tos();
843 NTSTATUS status;
844 struct rpc_pipe_client *cli = NULL;
845 struct dcerpc_binding_handle *b = NULL;
846 struct policy_handle handle;
847 struct spoolss_DevmodeContainer devmode_ctr;
848 union spoolss_DriverInfo driver_info;
849 union spoolss_JobInfo *job_info = NULL;
850 union spoolss_PrinterInfo printer_info;
852 if (!str1 || !str2 || !p) {
853 return False;
855 memset((char *)&desc,'\0',sizeof(desc));
857 p = skip_string(param,tpscnt,p);
858 if (!p) {
859 return False;
861 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
862 str3 = get_safe_str_ptr(param,tpscnt,p,4);
863 /* str3 may be null here and is checked in check_printq_info(). */
865 /* remove any trailing username */
866 if ((p = strchr_m(QueueName,'%')))
867 *p = 0;
869 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
871 /* check it's a supported variant */
872 if (!prefix_ok(str1,"zWrLh"))
873 return False;
874 if (!check_printq_info(&desc,uLevel,str2,str3)) {
876 * Patch from Scott Moomaw <scott@bridgewater.edu>
877 * to return the 'invalid info level' error if an
878 * unknown level was requested.
880 *rdata_len = 0;
881 *rparam_len = 6;
882 *rparam = smb_realloc_limit(*rparam,*rparam_len);
883 if (!*rparam) {
884 return False;
886 SSVALS(*rparam,0,ERRunknownlevel);
887 SSVAL(*rparam,2,0);
888 SSVAL(*rparam,4,0);
889 return(True);
892 ZERO_STRUCT(handle);
894 if (QueueName == NULL || (strlen(QueueName) < 1)) {
895 desc.errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
896 goto out;
899 status = rpc_pipe_open_interface(mem_ctx,
900 &ndr_table_spoolss,
901 conn->session_info,
902 conn->sconn->remote_address,
903 conn->sconn->local_address,
904 conn->sconn->msg_ctx,
905 &cli);
906 if (!NT_STATUS_IS_OK(status)) {
907 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
908 nt_errstr(status)));
909 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
910 goto out;
912 b = cli->binding_handle;
914 ZERO_STRUCT(devmode_ctr);
916 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
917 QueueName,
918 "RAW",
919 devmode_ctr,
920 PRINTER_ACCESS_USE,
921 &handle,
922 &werr);
923 if (!NT_STATUS_IS_OK(status)) {
924 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
925 goto out;
927 if (!W_ERROR_IS_OK(werr)) {
928 desc.errcode = W_ERROR_V(werr);
929 goto out;
932 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
933 &handle,
936 &printer_info);
937 if (!W_ERROR_IS_OK(werr)) {
938 desc.errcode = W_ERROR_V(werr);
939 goto out;
942 if (uLevel==52) {
943 uint32_t server_major_version;
944 uint32_t server_minor_version;
946 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
947 &handle,
948 "Windows 4.0",
949 3, /* level */
951 0, /* version */
953 &driver_info,
954 &server_major_version,
955 &server_minor_version);
956 if (!W_ERROR_IS_OK(werr)) {
957 desc.errcode = W_ERROR_V(werr);
958 goto out;
961 count = get_printerdrivernumber(&driver_info.info3);
962 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
963 } else {
964 uint32_t num_jobs;
965 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
966 &handle,
967 0, /* firstjob */
968 0xff, /* numjobs */
969 2, /* level */
970 0, /* offered */
971 &num_jobs,
972 &job_info);
973 if (!W_ERROR_IS_OK(werr)) {
974 desc.errcode = W_ERROR_V(werr);
975 goto out;
978 count = num_jobs;
981 if (mdrcnt > 0) {
982 *rdata = smb_realloc_limit(*rdata,mdrcnt);
983 if (!*rdata) {
984 return False;
986 desc.base = *rdata;
987 desc.buflen = mdrcnt;
988 } else {
990 * Don't return data but need to get correct length
991 * init_package will return wrong size if buflen=0
993 desc.buflen = getlen(desc.format);
994 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
997 if (init_package(&desc,1,count)) {
998 desc.subcount = count;
999 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
1002 *rdata_len = desc.usedlen;
1005 * We must set the return code to ERRbuftoosmall
1006 * in order to support lanman style printing with Win NT/2k
1007 * clients --jerry
1009 if (!mdrcnt && lp_disable_spoolss())
1010 desc.errcode = ERRbuftoosmall;
1012 out:
1013 if (b && is_valid_policy_hnd(&handle)) {
1014 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1017 *rdata_len = desc.usedlen;
1018 *rparam_len = 6;
1019 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1020 if (!*rparam) {
1021 SAFE_FREE(tmpdata);
1022 return False;
1024 SSVALS(*rparam,0,desc.errcode);
1025 SSVAL(*rparam,2,0);
1026 SSVAL(*rparam,4,desc.neededlen);
1028 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
1030 SAFE_FREE(tmpdata);
1032 return(True);
1035 /****************************************************************************
1036 View list of all print jobs on all queues.
1037 ****************************************************************************/
1039 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
1040 connection_struct *conn, uint64_t vuid,
1041 char *param, int tpscnt,
1042 char *data, int tdscnt,
1043 int mdrcnt, int mprcnt,
1044 char **rdata, char** rparam,
1045 int *rdata_len, int *rparam_len)
1047 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
1048 char *output_format1 = skip_string(param,tpscnt,param_format);
1049 char *p = skip_string(param,tpscnt,output_format1);
1050 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1051 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
1052 int i;
1053 struct pack_desc desc;
1054 int *subcntarr = NULL;
1055 int queuecnt = 0, subcnt = 0, succnt = 0;
1057 WERROR werr = WERR_OK;
1058 TALLOC_CTX *mem_ctx = talloc_tos();
1059 NTSTATUS status;
1060 struct rpc_pipe_client *cli = NULL;
1061 struct dcerpc_binding_handle *b = NULL;
1062 struct spoolss_DevmodeContainer devmode_ctr;
1063 uint32_t num_printers;
1064 union spoolss_PrinterInfo *printer_info;
1065 union spoolss_DriverInfo *driver_info;
1066 union spoolss_JobInfo **job_info;
1068 if (!param_format || !output_format1 || !p) {
1069 return False;
1072 memset((char *)&desc,'\0',sizeof(desc));
1074 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1076 if (!prefix_ok(param_format,"WrLeh")) {
1077 return False;
1079 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1081 * Patch from Scott Moomaw <scott@bridgewater.edu>
1082 * to return the 'invalid info level' error if an
1083 * unknown level was requested.
1085 *rdata_len = 0;
1086 *rparam_len = 6;
1087 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1088 if (!*rparam) {
1089 return False;
1091 SSVALS(*rparam,0,ERRunknownlevel);
1092 SSVAL(*rparam,2,0);
1093 SSVAL(*rparam,4,0);
1094 return(True);
1097 status = rpc_pipe_open_interface(mem_ctx,
1098 &ndr_table_spoolss,
1099 conn->session_info,
1100 conn->sconn->remote_address,
1101 conn->sconn->local_address,
1102 conn->sconn->msg_ctx,
1103 &cli);
1104 if (!NT_STATUS_IS_OK(status)) {
1105 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1106 nt_errstr(status)));
1107 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1108 goto out;
1110 b = cli->binding_handle;
1112 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1113 PRINTER_ENUM_LOCAL,
1114 cli->srv_name_slash,
1117 &num_printers,
1118 &printer_info);
1119 if (!W_ERROR_IS_OK(werr)) {
1120 desc.errcode = W_ERROR_V(werr);
1121 goto out;
1124 queuecnt = num_printers;
1126 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1127 if (job_info == NULL) {
1128 goto err;
1131 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1132 if (driver_info == NULL) {
1133 goto err;
1136 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1137 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1138 goto err;
1141 if (mdrcnt > 0) {
1142 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1143 if (!*rdata) {
1144 goto err;
1147 desc.base = *rdata;
1148 desc.buflen = mdrcnt;
1150 subcnt = 0;
1151 for (i = 0; i < num_printers; i++) {
1153 uint32_t num_jobs;
1154 struct policy_handle handle;
1155 const char *printername;
1157 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1158 if (printername == NULL) {
1159 goto err;
1162 ZERO_STRUCT(handle);
1163 ZERO_STRUCT(devmode_ctr);
1165 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1166 printername,
1167 "RAW",
1168 devmode_ctr,
1169 PRINTER_ACCESS_USE,
1170 &handle,
1171 &werr);
1172 if (!NT_STATUS_IS_OK(status)) {
1173 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1174 goto out;
1176 if (!W_ERROR_IS_OK(werr)) {
1177 desc.errcode = W_ERROR_V(werr);
1178 goto out;
1181 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1182 &handle,
1183 0, /* firstjob */
1184 0xff, /* numjobs */
1185 2, /* level */
1186 0, /* offered */
1187 &num_jobs,
1188 &job_info[i]);
1189 if (!W_ERROR_IS_OK(werr)) {
1190 desc.errcode = W_ERROR_V(werr);
1191 goto out;
1194 if (uLevel==52) {
1195 uint32_t server_major_version;
1196 uint32_t server_minor_version;
1198 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1199 &handle,
1200 "Windows 4.0",
1201 3, /* level */
1203 0, /* version */
1205 &driver_info[i],
1206 &server_major_version,
1207 &server_minor_version);
1208 if (!W_ERROR_IS_OK(werr)) {
1209 desc.errcode = W_ERROR_V(werr);
1210 goto out;
1214 subcntarr[i] = num_jobs;
1215 subcnt += subcntarr[i];
1217 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1220 if (init_package(&desc,queuecnt,subcnt)) {
1221 for (i = 0; i < num_printers; i++) {
1222 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1223 if (desc.errcode == NERR_Success) {
1224 succnt = i;
1229 out:
1230 SAFE_FREE(subcntarr);
1231 *rdata_len = desc.usedlen;
1232 *rparam_len = 8;
1233 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1234 if (!*rparam) {
1235 goto err;
1237 SSVALS(*rparam,0,desc.errcode);
1238 SSVAL(*rparam,2,0);
1239 SSVAL(*rparam,4,succnt);
1240 SSVAL(*rparam,6,queuecnt);
1242 return True;
1244 err:
1246 SAFE_FREE(subcntarr);
1248 return False;
1251 /****************************************************************************
1252 Get info level for a server list query.
1253 ****************************************************************************/
1255 static bool check_session_info(int uLevel, char* id)
1257 switch( uLevel ) {
1258 case 0:
1259 if (strcmp(id,"B16") != 0) {
1260 return False;
1262 break;
1263 case 1:
1264 if (strcmp(id,"B16BBDz") != 0) {
1265 return False;
1267 break;
1268 default:
1269 return False;
1271 return True;
1274 struct srv_info_struct {
1275 fstring name;
1276 uint32_t type;
1277 fstring comment;
1278 fstring domain;
1279 bool server_added;
1282 /*******************************************************************
1283 Get server info lists from the files saved by nmbd. Return the
1284 number of entries.
1285 ******************************************************************/
1287 static int get_session_info(uint32_t servertype,
1288 struct srv_info_struct **servers,
1289 const char *domain)
1291 int count=0;
1292 int alloced=0;
1293 char **lines;
1294 bool local_list_only;
1295 int i;
1296 char *slist_cache_path = cache_path(talloc_tos(), SERVER_LIST);
1297 if (slist_cache_path == NULL) {
1298 return 0;
1301 lines = file_lines_load(slist_cache_path, NULL, 0, NULL);
1302 if (!lines) {
1303 DEBUG(4, ("Can't open %s - %s\n",
1304 slist_cache_path, strerror(errno)));
1305 TALLOC_FREE(slist_cache_path);
1306 return 0;
1308 TALLOC_FREE(slist_cache_path);
1310 /* request for everything is code for request all servers */
1311 if (servertype == SV_TYPE_ALL) {
1312 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1315 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1317 DEBUG(4,("Servertype search: %8x\n",servertype));
1319 for (i=0;lines[i];i++) {
1320 fstring stype;
1321 struct srv_info_struct *s;
1322 const char *ptr = lines[i];
1323 bool ok = True;
1324 TALLOC_CTX *frame = NULL;
1325 char *p;
1327 if (!*ptr) {
1328 continue;
1331 if (count == alloced) {
1332 alloced += 10;
1333 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1334 if (!*servers) {
1335 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1336 TALLOC_FREE(lines);
1337 return 0;
1339 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1341 s = &(*servers)[count];
1343 frame = talloc_stackframe();
1344 s->name[0] = '\0';
1345 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1346 TALLOC_FREE(frame);
1347 continue;
1349 fstrcpy(s->name, p);
1351 stype[0] = '\0';
1352 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1353 TALLOC_FREE(frame);
1354 continue;
1356 fstrcpy(stype, p);
1358 s->comment[0] = '\0';
1359 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1360 TALLOC_FREE(frame);
1361 continue;
1363 fstrcpy(s->comment, p);
1364 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1366 s->domain[0] = '\0';
1367 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1368 /* this allows us to cope with an old nmbd */
1369 fstrcpy(s->domain,lp_workgroup());
1370 } else {
1371 fstrcpy(s->domain, p);
1373 TALLOC_FREE(frame);
1375 if (sscanf(stype,"%X",&s->type) != 1) {
1376 DEBUG(4,("r:host file "));
1377 ok = False;
1380 /* Filter the servers/domains we return based on what was asked for. */
1382 /* Check to see if we are being asked for a local list only. */
1383 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1384 DEBUG(4,("r: local list only"));
1385 ok = False;
1388 /* doesn't match up: don't want it */
1389 if (!(servertype & s->type)) {
1390 DEBUG(4,("r:serv type "));
1391 ok = False;
1394 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1395 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1396 DEBUG(4,("s: dom mismatch "));
1397 ok = False;
1400 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1401 ok = False;
1404 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1405 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1407 if (ok) {
1408 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1409 s->name, s->type, s->comment, s->domain));
1410 s->server_added = True;
1411 count++;
1412 } else {
1413 DEBUG(4,("%20s %8x %25s %15s\n",
1414 s->name, s->type, s->comment, s->domain));
1418 TALLOC_FREE(lines);
1419 return count;
1422 /*******************************************************************
1423 Fill in a server info structure.
1424 ******************************************************************/
1426 static int fill_srv_info(struct srv_info_struct *service,
1427 int uLevel, char **buf, int *buflen,
1428 char **stringbuf, int *stringspace, char *baseaddr)
1430 int struct_len;
1431 char* p;
1432 char* p2;
1433 int l2;
1434 int len;
1436 switch (uLevel) {
1437 case 0:
1438 struct_len = 16;
1439 break;
1440 case 1:
1441 struct_len = 26;
1442 break;
1443 default:
1444 return -1;
1447 if (!buf) {
1448 len = 0;
1449 switch (uLevel) {
1450 case 1:
1451 len = strlen(service->comment)+1;
1452 break;
1455 *buflen = struct_len;
1456 *stringspace = len;
1457 return struct_len + len;
1460 len = struct_len;
1461 p = *buf;
1462 if (*buflen < struct_len) {
1463 return -1;
1465 if (stringbuf) {
1466 p2 = *stringbuf;
1467 l2 = *stringspace;
1468 } else {
1469 p2 = p + struct_len;
1470 l2 = *buflen - struct_len;
1472 if (!baseaddr) {
1473 baseaddr = p;
1476 switch (uLevel) {
1477 case 0:
1478 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1479 break;
1481 case 1:
1482 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1483 SIVAL(p,18,service->type);
1484 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1485 len += CopyAndAdvance(&p2,service->comment,&l2);
1486 break;
1489 if (stringbuf) {
1490 *buf = p + struct_len;
1491 *buflen -= struct_len;
1492 *stringbuf = p2;
1493 *stringspace = l2;
1494 } else {
1495 *buf = p2;
1496 *buflen -= len;
1498 return len;
1502 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1504 return strcasecmp_m(s1->name,s2->name);
1507 /****************************************************************************
1508 View list of servers available (or possibly domains). The info is
1509 extracted from lists saved by nmbd on the local host.
1510 ****************************************************************************/
1512 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1513 connection_struct *conn, uint64_t vuid,
1514 char *param, int tpscnt,
1515 char *data, int tdscnt,
1516 int mdrcnt, int mprcnt, char **rdata,
1517 char **rparam, int *rdata_len, int *rparam_len)
1519 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1520 char *str2 = skip_string(param,tpscnt,str1);
1521 char *p = skip_string(param,tpscnt,str2);
1522 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1523 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1524 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1525 char *p2;
1526 int data_len, fixed_len, string_len;
1527 int f_len = 0, s_len = 0;
1528 struct srv_info_struct *servers=NULL;
1529 int counted=0,total=0;
1530 int i,missed;
1531 fstring domain;
1532 bool domain_request;
1533 bool local_request;
1535 if (!str1 || !str2 || !p) {
1536 return False;
1539 /* If someone sets all the bits they don't really mean to set
1540 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1541 known servers. */
1543 if (servertype == SV_TYPE_ALL) {
1544 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1547 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1548 any other bit (they may just set this bit on its own) they
1549 want all the locally seen servers. However this bit can be
1550 set on its own so set the requested servers to be
1551 ALL - DOMAIN_ENUM. */
1553 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1554 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1557 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1558 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1560 p += 8;
1562 if (!prefix_ok(str1,"WrLehD")) {
1563 return False;
1565 if (!check_session_info(uLevel,str2)) {
1566 return False;
1569 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1570 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1571 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1573 if (strcmp(str1, "WrLehDz") == 0) {
1574 if (skip_string(param,tpscnt,p) == NULL) {
1575 return False;
1577 pull_ascii_fstring(domain, p);
1578 } else {
1579 fstrcpy(domain, lp_workgroup());
1582 DEBUG(4, ("domain [%s]\n", domain));
1584 if (lp_browse_list()) {
1585 total = get_session_info(servertype,&servers,domain);
1588 data_len = fixed_len = string_len = 0;
1589 missed = 0;
1591 TYPESAFE_QSORT(servers, total, srv_comp);
1594 char *lastname=NULL;
1596 for (i=0;i<total;i++) {
1597 struct srv_info_struct *s = &servers[i];
1599 if (lastname && strequal(lastname,s->name)) {
1600 continue;
1602 lastname = s->name;
1603 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1604 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1605 i, s->name, s->type, s->comment, s->domain));
1607 if (data_len < buf_len) {
1608 counted++;
1609 fixed_len += f_len;
1610 string_len += s_len;
1611 } else {
1612 missed++;
1617 *rdata_len = fixed_len + string_len;
1618 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1619 if (!*rdata) {
1620 return False;
1623 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1624 p = *rdata;
1625 f_len = fixed_len;
1626 s_len = string_len;
1629 char *lastname=NULL;
1630 int count2 = counted;
1632 for (i = 0; i < total && count2;i++) {
1633 struct srv_info_struct *s = &servers[i];
1635 if (lastname && strequal(lastname,s->name)) {
1636 continue;
1638 lastname = s->name;
1639 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1640 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1641 i, s->name, s->type, s->comment, s->domain));
1642 count2--;
1646 *rparam_len = 8;
1647 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1648 if (!*rparam) {
1649 return False;
1651 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1652 SSVAL(*rparam,2,0);
1653 SSVAL(*rparam,4,counted);
1654 SSVAL(*rparam,6,counted+missed);
1656 SAFE_FREE(servers);
1658 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1659 domain,uLevel,counted,counted+missed));
1661 return True;
1664 static int srv_name_match(const char *n1, const char *n2)
1667 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1669 * In Windows, FirstNameToReturn need not be an exact match:
1670 * the server will return a list of servers that exist on
1671 * the network greater than or equal to the FirstNameToReturn.
1673 int ret = strcasecmp_m(n1, n2);
1675 if (ret <= 0) {
1676 return 0;
1679 return ret;
1682 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1683 connection_struct *conn, uint64_t vuid,
1684 char *param, int tpscnt,
1685 char *data, int tdscnt,
1686 int mdrcnt, int mprcnt, char **rdata,
1687 char **rparam, int *rdata_len, int *rparam_len)
1689 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1690 char *str2 = skip_string(param,tpscnt,str1);
1691 char *p = skip_string(param,tpscnt,str2);
1692 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1693 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1694 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1695 char *p2;
1696 int data_len, fixed_len, string_len;
1697 int f_len = 0, s_len = 0;
1698 struct srv_info_struct *servers=NULL;
1699 int counted=0,first=0,total=0;
1700 int i,missed;
1701 fstring domain;
1702 fstring first_name;
1703 bool domain_request;
1704 bool local_request;
1706 if (!str1 || !str2 || !p) {
1707 return False;
1710 /* If someone sets all the bits they don't really mean to set
1711 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1712 known servers. */
1714 if (servertype == SV_TYPE_ALL) {
1715 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1718 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1719 any other bit (they may just set this bit on its own) they
1720 want all the locally seen servers. However this bit can be
1721 set on its own so set the requested servers to be
1722 ALL - DOMAIN_ENUM. */
1724 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1725 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1728 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1729 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1731 p += 8;
1733 if (strcmp(str1, "WrLehDzz") != 0) {
1734 return false;
1736 if (!check_session_info(uLevel,str2)) {
1737 return False;
1740 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1741 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1742 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1744 if (skip_string(param,tpscnt,p) == NULL) {
1745 return False;
1747 pull_ascii_fstring(domain, p);
1748 if (domain[0] == '\0') {
1749 fstrcpy(domain, lp_workgroup());
1751 p = skip_string(param,tpscnt,p);
1752 if (skip_string(param,tpscnt,p) == NULL) {
1753 return False;
1755 pull_ascii_fstring(first_name, p);
1757 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1758 domain, first_name));
1760 if (lp_browse_list()) {
1761 total = get_session_info(servertype,&servers,domain);
1764 data_len = fixed_len = string_len = 0;
1765 missed = 0;
1767 TYPESAFE_QSORT(servers, total, srv_comp);
1769 if (first_name[0] != '\0') {
1770 struct srv_info_struct *first_server = NULL;
1772 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1773 srv_name_match, first_server);
1774 if (first_server) {
1775 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1777 * The binary search may not find the exact match
1778 * so we need to search backward to find the first match
1780 * This implements the strange matching windows
1781 * implements. (see the comment in srv_name_match().
1783 for (;first > 0;) {
1784 int ret;
1785 ret = strcasecmp_m(first_name,
1786 servers[first-1].name);
1787 if (ret > 0) {
1788 break;
1790 first--;
1792 } else {
1793 /* we should return no entries */
1794 first = total;
1799 char *lastname=NULL;
1801 for (i=first;i<total;i++) {
1802 struct srv_info_struct *s = &servers[i];
1804 if (lastname && strequal(lastname,s->name)) {
1805 continue;
1807 lastname = s->name;
1808 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1809 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1810 i, s->name, s->type, s->comment, s->domain));
1812 if (data_len < buf_len) {
1813 counted++;
1814 fixed_len += f_len;
1815 string_len += s_len;
1816 } else {
1817 missed++;
1822 *rdata_len = fixed_len + string_len;
1823 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1824 if (!*rdata) {
1825 return False;
1828 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1829 p = *rdata;
1830 f_len = fixed_len;
1831 s_len = string_len;
1834 char *lastname=NULL;
1835 int count2 = counted;
1837 for (i = first; i < total && count2;i++) {
1838 struct srv_info_struct *s = &servers[i];
1840 if (lastname && strequal(lastname,s->name)) {
1841 continue;
1843 lastname = s->name;
1844 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1845 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1846 i, s->name, s->type, s->comment, s->domain));
1847 count2--;
1851 *rparam_len = 8;
1852 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1853 if (!*rparam) {
1854 return False;
1856 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1857 SSVAL(*rparam,2,0);
1858 SSVAL(*rparam,4,counted);
1859 SSVAL(*rparam,6,counted+missed);
1861 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1862 domain,uLevel,first,first_name,
1863 first < total ? servers[first].name : "",
1864 counted,counted+missed));
1866 SAFE_FREE(servers);
1868 return True;
1871 /****************************************************************************
1872 command 0x34 - suspected of being a "Lookup Names" stub api
1873 ****************************************************************************/
1875 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1876 connection_struct *conn, uint64_t vuid,
1877 char *param, int tpscnt,
1878 char *data, int tdscnt,
1879 int mdrcnt, int mprcnt, char **rdata,
1880 char **rparam, int *rdata_len, int *rparam_len)
1882 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1883 char *str2 = skip_string(param,tpscnt,str1);
1884 char *p = skip_string(param,tpscnt,str2);
1885 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1886 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1887 int counted=0;
1888 int missed=0;
1890 if (!str1 || !str2 || !p) {
1891 return False;
1894 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1895 str1, str2, p, uLevel, buf_len));
1897 if (!prefix_ok(str1,"zWrLeh")) {
1898 return False;
1901 *rdata_len = 0;
1903 *rparam_len = 8;
1904 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1905 if (!*rparam) {
1906 return False;
1909 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1910 SSVAL(*rparam,2,0);
1911 SSVAL(*rparam,4,counted);
1912 SSVAL(*rparam,6,counted+missed);
1914 return True;
1917 /****************************************************************************
1918 get info about a share
1919 ****************************************************************************/
1921 static bool check_share_info(int uLevel, char* id)
1923 switch( uLevel ) {
1924 case 0:
1925 if (strcmp(id,"B13") != 0) {
1926 return False;
1928 break;
1929 case 1:
1930 /* Level-2 descriptor is allowed (and ignored) */
1931 if (strcmp(id,"B13BWz") != 0 &&
1932 strcmp(id,"B13BWzWWWzB9B") != 0) {
1933 return False;
1935 break;
1936 case 2:
1937 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1938 return False;
1940 break;
1941 case 91:
1942 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1943 return False;
1945 break;
1946 default:
1947 return False;
1949 return True;
1952 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1953 char** buf, int* buflen,
1954 char** stringbuf, int* stringspace, char* baseaddr)
1956 const struct loadparm_substitution *lp_sub =
1957 loadparm_s3_global_substitution();
1958 int struct_len;
1959 char* p;
1960 char* p2;
1961 int l2;
1962 int len;
1964 switch( uLevel ) {
1965 case 0:
1966 struct_len = 13;
1967 break;
1968 case 1:
1969 struct_len = 20;
1970 break;
1971 case 2:
1972 struct_len = 40;
1973 break;
1974 case 91:
1975 struct_len = 68;
1976 break;
1977 default:
1978 return -1;
1981 if (!buf) {
1982 len = 0;
1984 if (uLevel > 0) {
1985 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), lp_sub, snum));
1987 if (uLevel > 1) {
1988 len += strlen(lp_path(talloc_tos(), lp_sub, snum)) + 1;
1990 if (buflen) {
1991 *buflen = struct_len;
1993 if (stringspace) {
1994 *stringspace = len;
1996 return struct_len + len;
1999 len = struct_len;
2000 p = *buf;
2001 if ((*buflen) < struct_len) {
2002 return -1;
2005 if (stringbuf) {
2006 p2 = *stringbuf;
2007 l2 = *stringspace;
2008 } else {
2009 p2 = p + struct_len;
2010 l2 = (*buflen) - struct_len;
2013 if (!baseaddr) {
2014 baseaddr = p;
2017 push_ascii(p,lp_servicename(talloc_tos(), lp_sub, snum),13, STR_TERMINATE);
2019 if (uLevel > 0) {
2020 int type;
2022 SCVAL(p,13,0);
2023 type = STYPE_DISKTREE;
2024 if (lp_printable(snum)) {
2025 type = STYPE_PRINTQ;
2027 if (strequal("IPC",lp_fstype(snum))) {
2028 type = STYPE_IPC;
2030 SSVAL(p,14,type); /* device type */
2031 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
2032 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(), lp_sub, snum),&l2);
2035 if (uLevel > 1) {
2036 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
2037 SSVALS(p,22,-1); /* max uses */
2038 SSVAL(p,24,1); /* current uses */
2039 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
2040 len += CopyAndAdvance(&p2,lp_path(talloc_tos(),lp_sub, snum),&l2);
2041 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
2044 if (uLevel > 2) {
2045 memset(p+40,0,SHPWLEN+2);
2046 SSVAL(p,50,0);
2047 SIVAL(p,52,0);
2048 SSVAL(p,56,0);
2049 SSVAL(p,58,0);
2050 SIVAL(p,60,0);
2051 SSVAL(p,64,0);
2052 SSVAL(p,66,0);
2055 if (stringbuf) {
2056 (*buf) = p + struct_len;
2057 (*buflen) -= struct_len;
2058 (*stringbuf) = p2;
2059 (*stringspace) = l2;
2060 } else {
2061 (*buf) = p2;
2062 (*buflen) -= len;
2065 return len;
2068 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
2069 connection_struct *conn,uint64_t vuid,
2070 char *param, int tpscnt,
2071 char *data, int tdscnt,
2072 int mdrcnt,int mprcnt,
2073 char **rdata,char **rparam,
2074 int *rdata_len,int *rparam_len)
2076 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2077 char *str2 = skip_string(param,tpscnt,str1);
2078 char *netname_in = skip_string(param,tpscnt,str2);
2079 char *netname = NULL;
2080 char *p = skip_string(param,tpscnt,netname);
2081 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2082 int snum;
2084 if (!str1 || !str2 || !netname_in || !p) {
2085 return False;
2088 snum = find_service(talloc_tos(), netname_in, &netname);
2089 if (snum < 0 || !netname) {
2090 return False;
2093 /* check it's a supported variant */
2094 if (!prefix_ok(str1,"zWrLh")) {
2095 return False;
2097 if (!check_share_info(uLevel,str2)) {
2098 return False;
2101 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2102 if (!*rdata) {
2103 return False;
2105 p = *rdata;
2106 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2107 if (*rdata_len < 0) {
2108 return False;
2111 *rparam_len = 6;
2112 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2113 if (!*rparam) {
2114 return False;
2116 SSVAL(*rparam,0,NERR_Success);
2117 SSVAL(*rparam,2,0); /* converter word */
2118 SSVAL(*rparam,4,*rdata_len);
2120 return True;
2123 /****************************************************************************
2124 View the list of available shares.
2126 This function is the server side of the NetShareEnum() RAP call.
2127 It fills the return buffer with share names and share comments.
2128 Note that the return buffer normally (in all known cases) allows only
2129 twelve byte strings for share names (plus one for a nul terminator).
2130 Share names longer than 12 bytes must be skipped.
2131 ****************************************************************************/
2133 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2134 connection_struct *conn, uint64_t vuid,
2135 char *param, int tpscnt,
2136 char *data, int tdscnt,
2137 int mdrcnt,
2138 int mprcnt,
2139 char **rdata,
2140 char **rparam,
2141 int *rdata_len,
2142 int *rparam_len )
2144 const struct loadparm_substitution *lp_sub =
2145 loadparm_s3_global_substitution();
2146 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2147 char *str2 = skip_string(param,tpscnt,str1);
2148 char *p = skip_string(param,tpscnt,str2);
2149 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2150 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2151 char *p2;
2152 int count = 0;
2153 int total=0,counted=0;
2154 bool missed = False;
2155 int i;
2156 int data_len, fixed_len, string_len;
2157 int f_len = 0, s_len = 0;
2159 if (!str1 || !str2 || !p) {
2160 return False;
2163 if (!prefix_ok(str1,"WrLeh")) {
2164 return False;
2166 if (!check_share_info(uLevel,str2)) {
2167 return False;
2170 /* Ensure all the usershares are loaded. */
2171 become_root();
2172 delete_and_reload_printers();
2173 load_registry_shares();
2174 count = load_usershare_shares(NULL, connections_snum_used);
2175 unbecome_root();
2177 data_len = fixed_len = string_len = 0;
2178 for (i=0;i<count;i++) {
2179 fstring servicename_dos;
2180 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2181 continue;
2183 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), lp_sub, i));
2184 /* Maximum name length = 13. */
2185 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2186 total++;
2187 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2188 if (data_len < buf_len) {
2189 counted++;
2190 fixed_len += f_len;
2191 string_len += s_len;
2192 } else {
2193 missed = True;
2198 *rdata_len = fixed_len + string_len;
2199 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2200 if (!*rdata) {
2201 return False;
2204 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2205 p = *rdata;
2206 f_len = fixed_len;
2207 s_len = string_len;
2209 for( i = 0; i < count; i++ ) {
2210 fstring servicename_dos;
2211 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2212 continue;
2215 push_ascii_fstring(servicename_dos,
2216 lp_servicename(talloc_tos(), lp_sub, i));
2217 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2218 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2219 break;
2224 *rparam_len = 8;
2225 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2226 if (!*rparam) {
2227 return False;
2229 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2230 SSVAL(*rparam,2,0);
2231 SSVAL(*rparam,4,counted);
2232 SSVAL(*rparam,6,total);
2234 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2235 counted,total,uLevel,
2236 buf_len,*rdata_len,mdrcnt));
2238 return True;
2241 /****************************************************************************
2242 Add a share
2243 ****************************************************************************/
2245 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2246 connection_struct *conn,uint64_t vuid,
2247 char *param, int tpscnt,
2248 char *data, int tdscnt,
2249 int mdrcnt,int mprcnt,
2250 char **rdata,char **rparam,
2251 int *rdata_len,int *rparam_len)
2253 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2254 char *str2 = skip_string(param,tpscnt,str1);
2255 char *p = skip_string(param,tpscnt,str2);
2256 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2257 fstring sharename;
2258 fstring comment;
2259 char *pathname = NULL;
2260 unsigned int offset;
2261 int res = ERRunsup;
2262 size_t converted_size;
2264 WERROR werr = WERR_OK;
2265 TALLOC_CTX *mem_ctx = talloc_tos();
2266 NTSTATUS status;
2267 struct rpc_pipe_client *cli = NULL;
2268 union srvsvc_NetShareInfo info;
2269 struct srvsvc_NetShareInfo2 info2;
2270 struct dcerpc_binding_handle *b;
2272 if (!str1 || !str2 || !p) {
2273 return False;
2276 /* check it's a supported variant */
2277 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2278 return False;
2280 if (!check_share_info(uLevel,str2)) {
2281 return False;
2283 if (uLevel != 2) {
2284 return False;
2287 /* Do we have a string ? */
2288 if (skip_string(data,mdrcnt,data) == NULL) {
2289 return False;
2291 pull_ascii_fstring(sharename,data);
2293 if (mdrcnt < 28) {
2294 return False;
2297 /* only support disk share adds */
2298 if (SVAL(data,14)!=STYPE_DISKTREE) {
2299 return False;
2302 offset = IVAL(data, 16);
2303 if (offset >= mdrcnt) {
2304 res = ERRinvalidparam;
2305 goto out;
2308 /* Do we have a string ? */
2309 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2310 return False;
2312 pull_ascii_fstring(comment, offset? (data+offset) : "");
2314 offset = IVAL(data, 26);
2316 if (offset >= mdrcnt) {
2317 res = ERRinvalidparam;
2318 goto out;
2321 /* Do we have a string ? */
2322 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2323 return False;
2326 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2327 offset ? (data+offset) : "", &converted_size))
2329 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s\n",
2330 strerror(errno)));
2333 if (!pathname) {
2334 return false;
2337 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
2338 conn->session_info,
2339 conn->sconn->remote_address,
2340 conn->sconn->local_address,
2341 conn->sconn->msg_ctx,
2342 &cli);
2343 if (!NT_STATUS_IS_OK(status)) {
2344 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2345 nt_errstr(status)));
2346 res = W_ERROR_V(ntstatus_to_werror(status));
2347 goto out;
2350 b = cli->binding_handle;
2352 info2.name = sharename;
2353 info2.type = STYPE_DISKTREE;
2354 info2.comment = comment;
2355 info2.permissions = 0;
2356 info2.max_users = 0;
2357 info2.current_users = 0;
2358 info2.path = pathname;
2359 info2.password = NULL;
2361 info.info2 = &info2;
2363 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2364 cli->srv_name_slash,
2366 &info,
2367 NULL,
2368 &werr);
2369 if (!NT_STATUS_IS_OK(status)) {
2370 res = W_ERROR_V(ntstatus_to_werror(status));
2371 goto out;
2373 if (!W_ERROR_IS_OK(werr)) {
2374 res = W_ERROR_V(werr);
2375 goto out;
2378 *rparam_len = 6;
2379 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2380 if (!*rparam) {
2381 return False;
2383 SSVAL(*rparam,0,NERR_Success);
2384 SSVAL(*rparam,2,0); /* converter word */
2385 SSVAL(*rparam,4,*rdata_len);
2386 *rdata_len = 0;
2388 return True;
2390 out:
2392 *rparam_len = 4;
2393 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2394 if (!*rparam) {
2395 return False;
2397 *rdata_len = 0;
2398 SSVAL(*rparam,0,res);
2399 SSVAL(*rparam,2,0);
2400 return True;
2403 /****************************************************************************
2404 view list of groups available
2405 ****************************************************************************/
2407 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2408 connection_struct *conn,uint64_t vuid,
2409 char *param, int tpscnt,
2410 char *data, int tdscnt,
2411 int mdrcnt,int mprcnt,
2412 char **rdata,char **rparam,
2413 int *rdata_len,int *rparam_len)
2415 int i;
2416 int errflags=0;
2417 int resume_context, cli_buf_size;
2418 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2419 char *str2 = skip_string(param,tpscnt,str1);
2420 char *p = skip_string(param,tpscnt,str2);
2422 uint32_t num_groups;
2423 uint32_t resume_handle;
2424 struct rpc_pipe_client *samr_pipe = NULL;
2425 struct policy_handle samr_handle, domain_handle;
2426 NTSTATUS status, result;
2427 struct dcerpc_binding_handle *b;
2429 if (!str1 || !str2 || !p) {
2430 return False;
2433 if (strcmp(str1,"WrLeh") != 0) {
2434 return False;
2437 /* parameters
2438 * W-> resume context (number of users to skip)
2439 * r -> return parameter pointer to receive buffer
2440 * L -> length of receive buffer
2441 * e -> return parameter number of entries
2442 * h -> return parameter total number of users
2445 if (strcmp("B21",str2) != 0) {
2446 return False;
2449 status = rpc_pipe_open_interface(
2450 talloc_tos(), &ndr_table_samr,
2451 conn->session_info, conn->sconn->remote_address,
2452 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2453 if (!NT_STATUS_IS_OK(status)) {
2454 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2455 nt_errstr(status)));
2456 return false;
2459 b = samr_pipe->binding_handle;
2461 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2462 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2463 &result);
2464 if (!NT_STATUS_IS_OK(status)) {
2465 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2466 nt_errstr(status)));
2467 return false;
2469 if (!NT_STATUS_IS_OK(result)) {
2470 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2471 nt_errstr(result)));
2472 return false;
2475 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2476 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2477 get_global_sam_sid(), &domain_handle,
2478 &result);
2479 if (!NT_STATUS_IS_OK(status)) {
2480 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2481 nt_errstr(status)));
2482 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2483 return false;
2485 if (!NT_STATUS_IS_OK(result)) {
2486 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2487 nt_errstr(result)));
2488 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2489 return false;
2492 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2493 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2494 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2495 "%d\n", resume_context, cli_buf_size));
2497 *rdata_len = cli_buf_size;
2498 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2499 if (!*rdata) {
2500 return False;
2503 p = *rdata;
2505 errflags = NERR_Success;
2506 num_groups = 0;
2507 resume_handle = 0;
2509 while (true) {
2510 struct samr_SamArray *sam_entries;
2511 uint32_t num_entries;
2513 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2514 &domain_handle,
2515 &resume_handle,
2516 &sam_entries, 1,
2517 &num_entries,
2518 &result);
2519 if (!NT_STATUS_IS_OK(status)) {
2520 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2521 "%s\n", nt_errstr(status)));
2522 break;
2524 if (!NT_STATUS_IS_OK(result)) {
2525 status = result;
2526 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2527 "%s\n", nt_errstr(result)));
2528 break;
2531 if (num_entries == 0) {
2532 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2533 "no entries -- done\n"));
2534 break;
2537 for(i=0; i<num_entries; i++) {
2538 const char *name;
2540 name = sam_entries->entries[i].name.string;
2542 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2543 /* set overflow error */
2544 DEBUG(3,("overflow on entry %d group %s\n", i,
2545 name));
2546 errflags=234;
2547 break;
2550 /* truncate the name at 21 chars. */
2551 memset(p, 0, 21);
2552 strlcpy(p, name, 21);
2553 DEBUG(10,("adding entry %d group %s\n", i, p));
2554 p += 21;
2555 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2556 * idea why... */
2557 num_groups += 1;
2560 if (errflags != NERR_Success) {
2561 break;
2564 TALLOC_FREE(sam_entries);
2567 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2568 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2570 *rdata_len = PTR_DIFF(p,*rdata);
2572 *rparam_len = 8;
2573 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2574 if (!*rparam) {
2575 return False;
2577 SSVAL(*rparam, 0, errflags);
2578 SSVAL(*rparam, 2, 0); /* converter word */
2579 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2580 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2582 return(True);
2585 /*******************************************************************
2586 Get groups that a user is a member of.
2587 ******************************************************************/
2589 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2590 connection_struct *conn,uint64_t vuid,
2591 char *param, int tpscnt,
2592 char *data, int tdscnt,
2593 int mdrcnt,int mprcnt,
2594 char **rdata,char **rparam,
2595 int *rdata_len,int *rparam_len)
2597 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2598 char *str2 = skip_string(param,tpscnt,str1);
2599 char *UserName = skip_string(param,tpscnt,str2);
2600 char *p = skip_string(param,tpscnt,UserName);
2601 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2602 const char *level_string;
2603 int count=0;
2604 bool ret = False;
2605 uint32_t i;
2606 char *endp = NULL;
2608 struct rpc_pipe_client *samr_pipe = NULL;
2609 struct policy_handle samr_handle, domain_handle, user_handle;
2610 struct lsa_String name;
2611 struct lsa_Strings names;
2612 struct samr_Ids type, rid;
2613 struct samr_RidWithAttributeArray *rids;
2614 NTSTATUS status, result;
2615 struct dcerpc_binding_handle *b;
2617 if (!str1 || !str2 || !UserName || !p) {
2618 return False;
2621 *rparam_len = 8;
2622 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2623 if (!*rparam) {
2624 return False;
2627 /* check it's a supported variant */
2629 if ( strcmp(str1,"zWrLeh") != 0 )
2630 return False;
2632 switch( uLevel ) {
2633 case 0:
2634 level_string = "B21";
2635 break;
2636 default:
2637 return False;
2640 if (strcmp(level_string,str2) != 0)
2641 return False;
2643 *rdata_len = mdrcnt + 1024;
2644 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2645 if (!*rdata) {
2646 return False;
2649 SSVAL(*rparam,0,NERR_Success);
2650 SSVAL(*rparam,2,0); /* converter word */
2652 p = *rdata;
2653 endp = *rdata + *rdata_len;
2655 status = rpc_pipe_open_interface(
2656 talloc_tos(), &ndr_table_samr,
2657 conn->session_info, conn->sconn->remote_address,
2658 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2659 if (!NT_STATUS_IS_OK(status)) {
2660 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2661 nt_errstr(status)));
2662 return false;
2665 b = samr_pipe->binding_handle;
2667 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2668 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2669 &result);
2670 if (!NT_STATUS_IS_OK(status)) {
2671 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2672 nt_errstr(status)));
2673 return false;
2675 if (!NT_STATUS_IS_OK(result)) {
2676 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2677 nt_errstr(result)));
2678 return false;
2681 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2682 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2683 get_global_sam_sid(), &domain_handle,
2684 &result);
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2687 nt_errstr(status)));
2688 goto close_sam;
2690 if (!NT_STATUS_IS_OK(result)) {
2691 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2692 nt_errstr(result)));
2693 goto close_sam;
2696 name.string = UserName;
2698 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2699 &domain_handle, 1, &name,
2700 &rid, &type,
2701 &result);
2702 if (!NT_STATUS_IS_OK(status)) {
2703 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2704 nt_errstr(status)));
2705 goto close_domain;
2707 if (!NT_STATUS_IS_OK(result)) {
2708 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2709 nt_errstr(result)));
2710 goto close_domain;
2712 if (rid.count != 1) {
2713 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2714 goto close_domain;
2716 if (type.count != 1) {
2717 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2718 goto close_domain;
2721 if (type.ids[0] != SID_NAME_USER) {
2722 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2723 sid_type_lookup(type.ids[0])));
2724 goto close_domain;
2727 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2728 &domain_handle,
2729 SAMR_USER_ACCESS_GET_GROUPS,
2730 rid.ids[0], &user_handle,
2731 &result);
2732 if (!NT_STATUS_IS_OK(status)) {
2733 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2734 nt_errstr(status)));
2735 goto close_domain;
2737 if (!NT_STATUS_IS_OK(result)) {
2738 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2739 nt_errstr(result)));
2740 goto close_domain;
2743 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2744 &user_handle, &rids,
2745 &result);
2746 if (!NT_STATUS_IS_OK(status)) {
2747 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2748 nt_errstr(status)));
2749 goto close_user;
2751 if (!NT_STATUS_IS_OK(result)) {
2752 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2753 nt_errstr(result)));
2754 goto close_user;
2757 for (i=0; i<rids->count; i++) {
2759 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2760 &domain_handle,
2761 1, &rids->rids[i].rid,
2762 &names, &type,
2763 &result);
2764 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2765 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2766 p += 21;
2767 count++;
2771 *rdata_len = PTR_DIFF(p,*rdata);
2773 SSVAL(*rparam,4,count); /* is this right?? */
2774 SSVAL(*rparam,6,count); /* is this right?? */
2776 ret = True;
2778 close_user:
2779 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2780 close_domain:
2781 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2782 close_sam:
2783 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2785 return ret;
2788 /*******************************************************************
2789 Get all users.
2790 ******************************************************************/
2792 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2793 connection_struct *conn, uint64_t vuid,
2794 char *param, int tpscnt,
2795 char *data, int tdscnt,
2796 int mdrcnt,int mprcnt,
2797 char **rdata,char **rparam,
2798 int *rdata_len,int *rparam_len)
2800 int count_sent=0;
2801 int num_users=0;
2802 int errflags=0;
2803 int i, resume_context, cli_buf_size;
2804 uint32_t resume_handle;
2806 struct rpc_pipe_client *samr_pipe = NULL;
2807 struct policy_handle samr_handle, domain_handle;
2808 NTSTATUS status, result;
2810 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2811 char *str2 = skip_string(param,tpscnt,str1);
2812 char *p = skip_string(param,tpscnt,str2);
2813 char *endp = NULL;
2815 struct dcerpc_binding_handle *b;
2817 if (!str1 || !str2 || !p) {
2818 return False;
2821 if (strcmp(str1,"WrLeh") != 0)
2822 return False;
2823 /* parameters
2824 * W-> resume context (number of users to skip)
2825 * r -> return parameter pointer to receive buffer
2826 * L -> length of receive buffer
2827 * e -> return parameter number of entries
2828 * h -> return parameter total number of users
2831 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2832 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2833 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2834 resume_context, cli_buf_size));
2836 *rparam_len = 8;
2837 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2838 if (!*rparam) {
2839 return False;
2842 /* check it's a supported variant */
2843 if (strcmp("B21",str2) != 0)
2844 return False;
2846 *rdata_len = cli_buf_size;
2847 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2848 if (!*rdata) {
2849 return False;
2852 p = *rdata;
2853 endp = *rdata + *rdata_len;
2855 status = rpc_pipe_open_interface(
2856 talloc_tos(), &ndr_table_samr,
2857 conn->session_info, conn->sconn->remote_address,
2858 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2859 if (!NT_STATUS_IS_OK(status)) {
2860 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2861 nt_errstr(status)));
2862 return false;
2865 b = samr_pipe->binding_handle;
2867 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2868 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2869 &result);
2870 if (!NT_STATUS_IS_OK(status)) {
2871 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2872 nt_errstr(status)));
2873 return false;
2875 if (!NT_STATUS_IS_OK(result)) {
2876 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2877 nt_errstr(result)));
2878 return false;
2881 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2882 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2883 get_global_sam_sid(), &domain_handle,
2884 &result);
2885 if (!NT_STATUS_IS_OK(status)) {
2886 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2887 nt_errstr(status)));
2888 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2889 return false;
2891 if (!NT_STATUS_IS_OK(result)) {
2892 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2893 nt_errstr(result)));
2894 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2895 return false;
2898 errflags=NERR_Success;
2900 resume_handle = 0;
2902 while (true) {
2903 struct samr_SamArray *sam_entries;
2904 uint32_t num_entries;
2906 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2907 &domain_handle,
2908 &resume_handle,
2909 0, &sam_entries, 1,
2910 &num_entries,
2911 &result);
2913 if (!NT_STATUS_IS_OK(status)) {
2914 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2915 "%s\n", nt_errstr(status)));
2916 break;
2918 if (!NT_STATUS_IS_OK(result)) {
2919 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2920 "%s\n", nt_errstr(result)));
2921 break;
2924 if (num_entries == 0) {
2925 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2926 "no entries -- done\n"));
2927 break;
2930 for (i=0; i<num_entries; i++) {
2931 const char *name;
2933 name = sam_entries->entries[i].name.string;
2935 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2936 &&(strlen(name)<=21)) {
2937 strlcpy(p,name,PTR_DIFF(endp,p));
2938 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2939 "username %s\n",count_sent,p));
2940 p += 21;
2941 count_sent++;
2942 } else {
2943 /* set overflow error */
2944 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2945 "username %s\n",count_sent,name));
2946 errflags=234;
2947 break;
2951 if (errflags != NERR_Success) {
2952 break;
2955 TALLOC_FREE(sam_entries);
2958 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2959 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2961 *rdata_len = PTR_DIFF(p,*rdata);
2963 SSVAL(*rparam,0,errflags);
2964 SSVAL(*rparam,2,0); /* converter word */
2965 SSVAL(*rparam,4,count_sent); /* is this right?? */
2966 SSVAL(*rparam,6,num_users); /* is this right?? */
2968 return True;
2971 /****************************************************************************
2972 Get the time of day info.
2973 ****************************************************************************/
2975 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2976 connection_struct *conn,uint64_t vuid,
2977 char *param, int tpscnt,
2978 char *data, int tdscnt,
2979 int mdrcnt,int mprcnt,
2980 char **rdata,char **rparam,
2981 int *rdata_len,int *rparam_len)
2983 struct tm *t;
2984 time_t unixdate = time(NULL);
2985 char *p;
2987 *rparam_len = 4;
2988 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2989 if (!*rparam) {
2990 return False;
2993 *rdata_len = 21;
2994 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2995 if (!*rdata) {
2996 return False;
2999 SSVAL(*rparam,0,NERR_Success);
3000 SSVAL(*rparam,2,0); /* converter word */
3002 p = *rdata;
3004 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
3005 by NT in a "net time" operation,
3006 it seems to ignore the one below */
3008 /* the client expects to get localtime, not GMT, in this bit
3009 (I think, this needs testing) */
3010 t = localtime(&unixdate);
3011 if (!t) {
3012 return False;
3015 SIVAL(p,4,0); /* msecs ? */
3016 SCVAL(p,8,t->tm_hour);
3017 SCVAL(p,9,t->tm_min);
3018 SCVAL(p,10,t->tm_sec);
3019 SCVAL(p,11,0); /* hundredths of seconds */
3020 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
3021 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
3022 SCVAL(p,16,t->tm_mday);
3023 SCVAL(p,17,t->tm_mon + 1);
3024 SSVAL(p,18,1900+t->tm_year);
3025 SCVAL(p,20,t->tm_wday);
3027 return True;
3030 /****************************************************************************
3031 Set the user password (SamOEM version - gets plaintext).
3032 ****************************************************************************/
3034 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3035 connection_struct *conn,uint64_t vuid,
3036 char *param, int tpscnt,
3037 char *data, int tdscnt,
3038 int mdrcnt,int mprcnt,
3039 char **rdata,char **rparam,
3040 int *rdata_len,int *rparam_len)
3042 fstring user;
3043 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3045 TALLOC_CTX *mem_ctx = talloc_tos();
3046 NTSTATUS status, result;
3047 struct rpc_pipe_client *cli = NULL;
3048 struct lsa_AsciiString server, account;
3049 struct samr_CryptPassword password;
3050 struct samr_Password hash;
3051 int errcode = NERR_badpass;
3052 int bufsize;
3053 struct dcerpc_binding_handle *b;
3055 *rparam_len = 4;
3056 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3057 if (!*rparam) {
3058 return False;
3061 if (!p) {
3062 return False;
3064 *rdata_len = 0;
3066 SSVAL(*rparam,0,NERR_badpass);
3069 * Check the parameter definition is correct.
3072 /* Do we have a string ? */
3073 if (skip_string(param,tpscnt,p) == 0) {
3074 return False;
3076 if(!strequal(p, "zsT")) {
3077 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3078 return False;
3080 p = skip_string(param, tpscnt, p);
3081 if (!p) {
3082 return False;
3085 /* Do we have a string ? */
3086 if (skip_string(param,tpscnt,p) == 0) {
3087 return False;
3089 if(!strequal(p, "B516B16")) {
3090 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3091 return False;
3093 p = skip_string(param,tpscnt,p);
3094 if (!p) {
3095 return False;
3097 /* Do we have a string ? */
3098 if (skip_string(param,tpscnt,p) == 0) {
3099 return False;
3101 p += pull_ascii_fstring(user,p);
3103 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3105 if (tdscnt != 532) {
3106 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3107 goto out;
3110 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3111 if (bufsize != 532) {
3112 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3113 goto out;
3116 memcpy(password.data, data, 516);
3117 memcpy(hash.hash, data+516, 16);
3119 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
3120 conn->session_info,
3121 conn->sconn->remote_address,
3122 conn->sconn->local_address,
3123 conn->sconn->msg_ctx,
3124 &cli);
3125 if (!NT_STATUS_IS_OK(status)) {
3126 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3127 nt_errstr(status)));
3128 errcode = W_ERROR_V(ntstatus_to_werror(status));
3129 goto out;
3132 b = cli->binding_handle;
3134 init_lsa_AsciiString(&server, lp_netbios_name());
3135 init_lsa_AsciiString(&account, user);
3137 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3138 &server,
3139 &account,
3140 &password,
3141 &hash,
3142 &result);
3143 if (!NT_STATUS_IS_OK(status)) {
3144 errcode = W_ERROR_V(ntstatus_to_werror(status));
3145 goto out;
3147 if (!NT_STATUS_IS_OK(result)) {
3148 errcode = W_ERROR_V(ntstatus_to_werror(result));
3149 goto out;
3152 errcode = NERR_Success;
3153 out:
3154 SSVAL(*rparam,0,errcode);
3155 SSVAL(*rparam,2,0); /* converter word */
3157 return(True);
3160 /****************************************************************************
3161 delete a print job
3162 Form: <W> <>
3163 ****************************************************************************/
3165 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3166 connection_struct *conn,uint64_t vuid,
3167 char *param, int tpscnt,
3168 char *data, int tdscnt,
3169 int mdrcnt,int mprcnt,
3170 char **rdata,char **rparam,
3171 int *rdata_len,int *rparam_len)
3173 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3174 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3175 char *str2 = skip_string(param,tpscnt,str1);
3176 char *p = skip_string(param,tpscnt,str2);
3177 uint32_t jobid;
3178 fstring sharename;
3179 int errcode;
3180 WERROR werr = WERR_OK;
3182 TALLOC_CTX *mem_ctx = talloc_tos();
3183 NTSTATUS status;
3184 struct rpc_pipe_client *cli = NULL;
3185 struct dcerpc_binding_handle *b = NULL;
3186 struct policy_handle handle;
3187 struct spoolss_DevmodeContainer devmode_ctr;
3188 enum spoolss_JobControl command;
3190 if (!str1 || !str2 || !p) {
3191 return False;
3194 * We use 1 here not 2 as we're checking
3195 * the last byte we want to access is safe.
3197 if (!is_offset_safe(param,tpscnt,p,1)) {
3198 return False;
3200 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3201 return False;
3203 /* check it's a supported variant */
3204 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3205 return(False);
3207 *rparam_len = 4;
3208 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3209 if (!*rparam) {
3210 return False;
3212 *rdata_len = 0;
3214 ZERO_STRUCT(handle);
3216 status = rpc_pipe_open_interface(mem_ctx,
3217 &ndr_table_spoolss,
3218 conn->session_info,
3219 conn->sconn->remote_address,
3220 conn->sconn->local_address,
3221 conn->sconn->msg_ctx,
3222 &cli);
3223 if (!NT_STATUS_IS_OK(status)) {
3224 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3225 nt_errstr(status)));
3226 errcode = W_ERROR_V(ntstatus_to_werror(status));
3227 goto out;
3229 b = cli->binding_handle;
3231 ZERO_STRUCT(devmode_ctr);
3233 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3234 sharename,
3235 "RAW",
3236 devmode_ctr,
3237 JOB_ACCESS_ADMINISTER,
3238 &handle,
3239 &werr);
3240 if (!NT_STATUS_IS_OK(status)) {
3241 errcode = W_ERROR_V(ntstatus_to_werror(status));
3242 goto out;
3244 if (!W_ERROR_IS_OK(werr)) {
3245 errcode = W_ERROR_V(werr);
3246 goto out;
3249 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3250 * and NERR_DestNotFound if share did not exist */
3252 errcode = NERR_Success;
3254 switch (function) {
3255 case 81: /* delete */
3256 command = SPOOLSS_JOB_CONTROL_DELETE;
3257 break;
3258 case 82: /* pause */
3259 command = SPOOLSS_JOB_CONTROL_PAUSE;
3260 break;
3261 case 83: /* resume */
3262 command = SPOOLSS_JOB_CONTROL_RESUME;
3263 break;
3264 default:
3265 errcode = NERR_notsupported;
3266 goto out;
3269 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3270 &handle,
3271 jobid,
3272 NULL, /* unique ptr ctr */
3273 command,
3274 &werr);
3275 if (!NT_STATUS_IS_OK(status)) {
3276 errcode = W_ERROR_V(ntstatus_to_werror(status));
3277 goto out;
3279 if (!W_ERROR_IS_OK(werr)) {
3280 errcode = W_ERROR_V(werr);
3281 goto out;
3284 out:
3285 if (b && is_valid_policy_hnd(&handle)) {
3286 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3289 SSVAL(*rparam,0,errcode);
3290 SSVAL(*rparam,2,0); /* converter word */
3292 return(True);
3295 /****************************************************************************
3296 Purge a print queue - or pause or resume it.
3297 ****************************************************************************/
3299 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3300 connection_struct *conn,uint64_t vuid,
3301 char *param, int tpscnt,
3302 char *data, int tdscnt,
3303 int mdrcnt,int mprcnt,
3304 char **rdata,char **rparam,
3305 int *rdata_len,int *rparam_len)
3307 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3308 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3309 char *str2 = skip_string(param,tpscnt,str1);
3310 char *QueueName = skip_string(param,tpscnt,str2);
3311 int errcode = NERR_notsupported;
3312 WERROR werr = WERR_OK;
3313 NTSTATUS status;
3315 TALLOC_CTX *mem_ctx = talloc_tos();
3316 struct rpc_pipe_client *cli = NULL;
3317 struct dcerpc_binding_handle *b = NULL;
3318 struct policy_handle handle;
3319 struct spoolss_SetPrinterInfoCtr info_ctr;
3320 struct spoolss_DevmodeContainer devmode_ctr;
3321 struct sec_desc_buf secdesc_ctr;
3322 enum spoolss_PrinterControl command = SPOOLSS_PRINTER_CONTROL_UNPAUSE;
3324 if (!str1 || !str2 || !QueueName) {
3325 return False;
3328 /* check it's a supported variant */
3329 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3330 return(False);
3332 *rparam_len = 4;
3333 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3334 if (!*rparam) {
3335 return False;
3337 *rdata_len = 0;
3339 if (skip_string(param,tpscnt,QueueName) == NULL) {
3340 return False;
3343 ZERO_STRUCT(handle);
3345 status = rpc_pipe_open_interface(mem_ctx,
3346 &ndr_table_spoolss,
3347 conn->session_info,
3348 conn->sconn->remote_address,
3349 conn->sconn->local_address,
3350 conn->sconn->msg_ctx,
3351 &cli);
3352 if (!NT_STATUS_IS_OK(status)) {
3353 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3354 nt_errstr(status)));
3355 errcode = W_ERROR_V(ntstatus_to_werror(status));
3356 goto out;
3358 b = cli->binding_handle;
3360 ZERO_STRUCT(devmode_ctr);
3362 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3363 QueueName,
3364 NULL,
3365 devmode_ctr,
3366 PRINTER_ACCESS_ADMINISTER,
3367 &handle,
3368 &werr);
3369 if (!NT_STATUS_IS_OK(status)) {
3370 errcode = W_ERROR_V(ntstatus_to_werror(status));
3371 goto out;
3373 if (!W_ERROR_IS_OK(werr)) {
3374 errcode = W_ERROR_V(werr);
3375 goto out;
3378 switch (function) {
3379 case 74: /* Pause queue */
3380 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3381 break;
3382 case 75: /* Resume queue */
3383 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3384 break;
3385 case 103: /* Purge */
3386 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3387 break;
3388 default:
3389 werr = WERR_NOT_SUPPORTED;
3390 break;
3393 if (!W_ERROR_IS_OK(werr)) {
3394 errcode = W_ERROR_V(werr);
3395 goto out;
3398 ZERO_STRUCT(info_ctr);
3399 ZERO_STRUCT(secdesc_ctr);
3401 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3402 &handle,
3403 &info_ctr,
3404 &devmode_ctr,
3405 &secdesc_ctr,
3406 command,
3407 &werr);
3408 if (!NT_STATUS_IS_OK(status)) {
3409 errcode = W_ERROR_V(ntstatus_to_werror(status));
3410 goto out;
3412 if (!W_ERROR_IS_OK(werr)) {
3413 errcode = W_ERROR_V(werr);
3414 goto out;
3417 errcode = W_ERROR_V(werr);
3419 out:
3421 if (b && is_valid_policy_hnd(&handle)) {
3422 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3425 SSVAL(*rparam,0,errcode);
3426 SSVAL(*rparam,2,0); /* converter word */
3428 return(True);
3431 /****************************************************************************
3432 set the property of a print job (undocumented?)
3433 ? function = 0xb -> set name of print job
3434 ? function = 0x6 -> move print job up/down
3435 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3436 or <WWsTP> <WB21BB16B10zWWzDDz>
3437 ****************************************************************************/
3439 static int check_printjob_info(struct pack_desc* desc,
3440 int uLevel, char* id)
3442 desc->subformat = NULL;
3443 switch( uLevel ) {
3444 case 0: desc->format = "W"; break;
3445 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3446 case 2: desc->format = "WWzWWDDzz"; break;
3447 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3448 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3449 default:
3450 DEBUG(0,("check_printjob_info: invalid level %d\n",
3451 uLevel ));
3452 return False;
3454 if (id == NULL || strcmp(desc->format,id) != 0) {
3455 DEBUG(0,("check_printjob_info: invalid format %s\n",
3456 id ? id : "<NULL>" ));
3457 return False;
3459 return True;
3462 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3463 connection_struct *conn, uint64_t vuid,
3464 char *param, int tpscnt,
3465 char *data, int tdscnt,
3466 int mdrcnt,int mprcnt,
3467 char **rdata,char **rparam,
3468 int *rdata_len,int *rparam_len)
3470 struct pack_desc desc;
3471 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3472 char *str2 = skip_string(param,tpscnt,str1);
3473 char *p = skip_string(param,tpscnt,str2);
3474 uint32_t jobid;
3475 fstring sharename;
3476 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3477 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3478 int errcode;
3480 TALLOC_CTX *mem_ctx = talloc_tos();
3481 WERROR werr;
3482 NTSTATUS status;
3483 struct rpc_pipe_client *cli = NULL;
3484 struct dcerpc_binding_handle *b = NULL;
3485 struct policy_handle handle;
3486 struct spoolss_DevmodeContainer devmode_ctr;
3487 struct spoolss_JobInfoContainer ctr;
3488 union spoolss_JobInfo info;
3489 struct spoolss_SetJobInfo1 info1;
3491 if (!str1 || !str2 || !p) {
3492 return False;
3495 * We use 1 here not 2 as we're checking
3496 * the last byte we want to access is safe.
3498 if (!is_offset_safe(param,tpscnt,p,1)) {
3499 return False;
3501 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3502 return False;
3503 *rparam_len = 4;
3504 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3505 if (!*rparam) {
3506 return False;
3509 *rdata_len = 0;
3511 /* check it's a supported variant */
3512 if ((strcmp(str1,"WWsTP")) ||
3513 (!check_printjob_info(&desc,uLevel,str2)))
3514 return(False);
3516 errcode = NERR_notsupported;
3518 switch (function) {
3519 case 0xb:
3520 /* change print job name, data gives the name */
3521 break;
3522 default:
3523 goto out;
3526 ZERO_STRUCT(handle);
3528 status = rpc_pipe_open_interface(mem_ctx,
3529 &ndr_table_spoolss,
3530 conn->session_info,
3531 conn->sconn->remote_address,
3532 conn->sconn->local_address,
3533 conn->sconn->msg_ctx,
3534 &cli);
3535 if (!NT_STATUS_IS_OK(status)) {
3536 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3537 nt_errstr(status)));
3538 errcode = W_ERROR_V(ntstatus_to_werror(status));
3539 goto out;
3541 b = cli->binding_handle;
3543 ZERO_STRUCT(devmode_ctr);
3545 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3546 sharename,
3547 "RAW",
3548 devmode_ctr,
3549 PRINTER_ACCESS_USE,
3550 &handle,
3551 &werr);
3552 if (!NT_STATUS_IS_OK(status)) {
3553 errcode = W_ERROR_V(ntstatus_to_werror(status));
3554 goto out;
3556 if (!W_ERROR_IS_OK(werr)) {
3557 errcode = W_ERROR_V(werr);
3558 goto out;
3561 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3562 &handle,
3563 jobid,
3564 1, /* level */
3565 0, /* offered */
3566 &info);
3567 if (!W_ERROR_IS_OK(werr)) {
3568 errcode = W_ERROR_V(werr);
3569 goto out;
3572 ZERO_STRUCT(ctr);
3574 info1.job_id = info.info1.job_id;
3575 info1.printer_name = info.info1.printer_name;
3576 info1.user_name = info.info1.user_name;
3577 info1.document_name = data;
3578 info1.data_type = info.info1.data_type;
3579 info1.text_status = info.info1.text_status;
3580 info1.status = info.info1.status;
3581 info1.priority = info.info1.priority;
3582 info1.position = info.info1.position;
3583 info1.total_pages = info.info1.total_pages;
3584 info1.pages_printed = info.info1.pages_printed;
3585 info1.submitted = info.info1.submitted;
3587 ctr.level = 1;
3588 ctr.info.info1 = &info1;
3590 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3591 &handle,
3592 jobid,
3593 &ctr,
3595 &werr);
3596 if (!NT_STATUS_IS_OK(status)) {
3597 errcode = W_ERROR_V(ntstatus_to_werror(status));
3598 goto out;
3600 if (!W_ERROR_IS_OK(werr)) {
3601 errcode = W_ERROR_V(werr);
3602 goto out;
3605 errcode = NERR_Success;
3606 out:
3608 if (b && is_valid_policy_hnd(&handle)) {
3609 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3612 SSVALS(*rparam,0,errcode);
3613 SSVAL(*rparam,2,0); /* converter word */
3615 return(True);
3619 /****************************************************************************
3620 Get info about the server.
3621 ****************************************************************************/
3623 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3624 connection_struct *conn,uint64_t vuid,
3625 char *param, int tpscnt,
3626 char *data, int tdscnt,
3627 int mdrcnt,int mprcnt,
3628 char **rdata,char **rparam,
3629 int *rdata_len,int *rparam_len)
3631 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3632 char *str2 = skip_string(param,tpscnt,str1);
3633 char *p = skip_string(param,tpscnt,str2);
3634 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3635 char *p2;
3636 int struct_len;
3638 NTSTATUS status;
3639 WERROR werr;
3640 TALLOC_CTX *mem_ctx = talloc_tos();
3641 struct rpc_pipe_client *cli = NULL;
3642 union srvsvc_NetSrvInfo info;
3643 int errcode;
3644 struct dcerpc_binding_handle *b;
3646 if (!str1 || !str2 || !p) {
3647 return False;
3650 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3652 /* check it's a supported variant */
3653 if (!prefix_ok(str1,"WrLh")) {
3654 return False;
3657 switch( uLevel ) {
3658 case 0:
3659 if (strcmp(str2,"B16") != 0) {
3660 return False;
3662 struct_len = 16;
3663 break;
3664 case 1:
3665 if (strcmp(str2,"B16BBDz") != 0) {
3666 return False;
3668 struct_len = 26;
3669 break;
3670 case 2:
3671 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3672 return False;
3674 struct_len = 134;
3675 break;
3676 case 3:
3677 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3678 return False;
3680 struct_len = 144;
3681 break;
3682 case 20:
3683 if (strcmp(str2,"DN") != 0) {
3684 return False;
3686 struct_len = 6;
3687 break;
3688 case 50:
3689 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3690 return False;
3692 struct_len = 42;
3693 break;
3694 default:
3695 return False;
3698 *rdata_len = mdrcnt;
3699 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3700 if (!*rdata) {
3701 return False;
3704 p = *rdata;
3705 p2 = p + struct_len;
3707 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
3708 conn->session_info,
3709 conn->sconn->remote_address,
3710 conn->sconn->local_address,
3711 conn->sconn->msg_ctx,
3712 &cli);
3713 if (!NT_STATUS_IS_OK(status)) {
3714 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3715 nt_errstr(status)));
3716 errcode = W_ERROR_V(ntstatus_to_werror(status));
3717 goto out;
3720 b = cli->binding_handle;
3722 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3723 NULL,
3724 101,
3725 &info,
3726 &werr);
3727 if (!NT_STATUS_IS_OK(status)) {
3728 errcode = W_ERROR_V(ntstatus_to_werror(status));
3729 goto out;
3731 if (!W_ERROR_IS_OK(werr)) {
3732 errcode = W_ERROR_V(werr);
3733 goto out;
3736 if (info.info101 == NULL) {
3737 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3738 goto out;
3741 if (uLevel != 20) {
3742 size_t len = 0;
3743 status = srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3744 STR_ASCII|STR_UPPER|STR_TERMINATE, &len);
3745 if (!NT_STATUS_IS_OK(status)) {
3746 errcode = W_ERROR_V(ntstatus_to_werror(status));
3747 goto out;
3750 p += 16;
3751 if (uLevel > 0) {
3752 SCVAL(p,0,info.info101->version_major);
3753 SCVAL(p,1,info.info101->version_minor);
3754 SIVAL(p,2,info.info101->server_type);
3756 if (mdrcnt == struct_len) {
3757 SIVAL(p,6,0);
3758 } else {
3759 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3760 if (mdrcnt - struct_len <= 0) {
3761 return false;
3763 push_ascii(p2,
3764 info.info101->comment,
3765 MIN(mdrcnt - struct_len,
3766 MAX_SERVER_STRING_LENGTH),
3767 STR_TERMINATE);
3768 p2 = skip_string(*rdata,*rdata_len,p2);
3769 if (!p2) {
3770 return False;
3775 if (uLevel > 1) {
3776 return False; /* not yet implemented */
3779 errcode = NERR_Success;
3781 out:
3783 *rdata_len = PTR_DIFF(p2,*rdata);
3785 *rparam_len = 6;
3786 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3787 if (!*rparam) {
3788 return False;
3790 SSVAL(*rparam,0,errcode);
3791 SSVAL(*rparam,2,0); /* converter word */
3792 SSVAL(*rparam,4,*rdata_len);
3794 return True;
3797 /****************************************************************************
3798 Get info about the server.
3799 ****************************************************************************/
3801 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3802 connection_struct *conn,uint64_t vuid,
3803 char *param, int tpscnt,
3804 char *data, int tdscnt,
3805 int mdrcnt,int mprcnt,
3806 char **rdata,char **rparam,
3807 int *rdata_len,int *rparam_len)
3809 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3810 char *str2 = skip_string(param,tpscnt,str1);
3811 char *p = skip_string(param,tpscnt,str2);
3812 char *p2;
3813 char *endp;
3814 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3816 if (!str1 || !str2 || !p) {
3817 return False;
3820 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3822 *rparam_len = 6;
3823 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3824 if (!*rparam) {
3825 return False;
3828 /* check it's a supported variant */
3829 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3830 return False;
3833 *rdata_len = mdrcnt + 1024;
3834 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3835 if (!*rdata) {
3836 return False;
3839 SSVAL(*rparam,0,NERR_Success);
3840 SSVAL(*rparam,2,0); /* converter word */
3842 p = *rdata;
3843 endp = *rdata + *rdata_len;
3845 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3846 if (!p2) {
3847 return False;
3850 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3851 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3852 if (!strupper_m(p2)) {
3853 return false;
3855 p2 = skip_string(*rdata,*rdata_len,p2);
3856 if (!p2) {
3857 return False;
3859 p += 4;
3861 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3862 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3863 p2 = skip_string(*rdata,*rdata_len,p2);
3864 if (!p2) {
3865 return False;
3867 p += 4;
3869 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3870 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3871 if (!strupper_m(p2)) {
3872 return false;
3874 p2 = skip_string(*rdata,*rdata_len,p2);
3875 if (!p2) {
3876 return False;
3878 p += 4;
3880 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3881 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3882 p += 2;
3884 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3885 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3886 p2 = skip_string(*rdata,*rdata_len,p2);
3887 if (!p2) {
3888 return False;
3890 p += 4;
3892 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3893 strlcpy(p2,"",PTR_DIFF(endp,p2));
3894 p2 = skip_string(*rdata,*rdata_len,p2);
3895 if (!p2) {
3896 return False;
3898 p += 4;
3900 *rdata_len = PTR_DIFF(p2,*rdata);
3902 SSVAL(*rparam,4,*rdata_len);
3904 return True;
3907 /****************************************************************************
3908 get info about a user
3910 struct user_info_11 {
3911 char usri11_name[21]; 0-20
3912 char usri11_pad; 21
3913 char *usri11_comment; 22-25
3914 char *usri11_usr_comment; 26-29
3915 unsigned short usri11_priv; 30-31
3916 unsigned long usri11_auth_flags; 32-35
3917 long usri11_password_age; 36-39
3918 char *usri11_homedir; 40-43
3919 char *usri11_parms; 44-47
3920 long usri11_last_logon; 48-51
3921 long usri11_last_logoff; 52-55
3922 unsigned short usri11_bad_pw_count; 56-57
3923 unsigned short usri11_num_logons; 58-59
3924 char *usri11_logon_server; 60-63
3925 unsigned short usri11_country_code; 64-65
3926 char *usri11_workstations; 66-69
3927 unsigned long usri11_max_storage; 70-73
3928 unsigned short usri11_units_per_week; 74-75
3929 unsigned char *usri11_logon_hours; 76-79
3930 unsigned short usri11_code_page; 80-81
3933 where:
3935 usri11_name specifies the user name for which information is retrieved
3937 usri11_pad aligns the next data structure element to a word boundary
3939 usri11_comment is a null terminated ASCII comment
3941 usri11_user_comment is a null terminated ASCII comment about the user
3943 usri11_priv specifies the level of the privilege assigned to the user.
3944 The possible values are:
3946 Name Value Description
3947 USER_PRIV_GUEST 0 Guest privilege
3948 USER_PRIV_USER 1 User privilege
3949 USER_PRV_ADMIN 2 Administrator privilege
3951 usri11_auth_flags specifies the account operator privileges. The
3952 possible values are:
3954 Name Value Description
3955 AF_OP_PRINT 0 Print operator
3958 Leach, Naik [Page 28]
3962 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3965 AF_OP_COMM 1 Communications operator
3966 AF_OP_SERVER 2 Server operator
3967 AF_OP_ACCOUNTS 3 Accounts operator
3970 usri11_password_age specifies how many seconds have elapsed since the
3971 password was last changed.
3973 usri11_home_dir points to a null terminated ASCII string that contains
3974 the path name of the user's home directory.
3976 usri11_parms points to a null terminated ASCII string that is set
3977 aside for use by applications.
3979 usri11_last_logon specifies the time when the user last logged on.
3980 This value is stored as the number of seconds elapsed since
3981 00:00:00, January 1, 1970.
3983 usri11_last_logoff specifies the time when the user last logged off.
3984 This value is stored as the number of seconds elapsed since
3985 00:00:00, January 1, 1970. A value of 0 means the last logoff
3986 time is unknown.
3988 usri11_bad_pw_count specifies the number of incorrect passwords
3989 entered since the last successful logon.
3991 usri11_log1_num_logons specifies the number of times this user has
3992 logged on. A value of -1 means the number of logons is unknown.
3994 usri11_logon_server points to a null terminated ASCII string that
3995 contains the name of the server to which logon requests are sent.
3996 A null string indicates logon requests should be sent to the
3997 domain controller.
3999 usri11_country_code specifies the country code for the user's language
4000 of choice.
4002 usri11_workstations points to a null terminated ASCII string that
4003 contains the names of workstations the user may log on from.
4004 There may be up to 8 workstations, with the names separated by
4005 commas. A null strings indicates there are no restrictions.
4007 usri11_max_storage specifies the maximum amount of disk space the user
4008 can occupy. A value of 0xffffffff indicates there are no
4009 restrictions.
4011 usri11_units_per_week specifies the equal number of time units into
4012 which a week is divided. This value must be equal to 168.
4014 usri11_logon_hours points to a 21 byte (168 bits) string that
4015 specifies the time during which the user can log on. Each bit
4016 represents one unique hour in a week. The first bit (bit 0, word
4017 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4021 Leach, Naik [Page 29]
4025 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4028 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4029 are no restrictions.
4031 usri11_code_page specifies the code page for the user's language of
4032 choice
4034 All of the pointers in this data structure need to be treated
4035 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4036 to be ignored. The converter word returned in the parameters section
4037 needs to be subtracted from the lower 16 bits to calculate an offset
4038 into the return buffer where this ASCII string resides.
4040 There is no auxiliary data in the response.
4042 ****************************************************************************/
4044 #define usri11_name 0
4045 #define usri11_pad 21
4046 #define usri11_comment 22
4047 #define usri11_usr_comment 26
4048 #define usri11_full_name 30
4049 #define usri11_priv 34
4050 #define usri11_auth_flags 36
4051 #define usri11_password_age 40
4052 #define usri11_homedir 44
4053 #define usri11_parms 48
4054 #define usri11_last_logon 52
4055 #define usri11_last_logoff 56
4056 #define usri11_bad_pw_count 60
4057 #define usri11_num_logons 62
4058 #define usri11_logon_server 64
4059 #define usri11_country_code 68
4060 #define usri11_workstations 70
4061 #define usri11_max_storage 74
4062 #define usri11_units_per_week 78
4063 #define usri11_logon_hours 80
4064 #define usri11_code_page 84
4065 #define usri11_end 86
4067 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4068 connection_struct *conn, uint64_t vuid,
4069 char *param, int tpscnt,
4070 char *data, int tdscnt,
4071 int mdrcnt,int mprcnt,
4072 char **rdata,char **rparam,
4073 int *rdata_len,int *rparam_len)
4075 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4076 char *str2 = skip_string(param,tpscnt,str1);
4077 char *UserName = skip_string(param,tpscnt,str2);
4078 char *p = skip_string(param,tpscnt,UserName);
4079 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4080 char *p2;
4081 char *endp;
4082 const char *level_string;
4084 TALLOC_CTX *mem_ctx = talloc_tos();
4085 NTSTATUS status, result;
4086 struct rpc_pipe_client *cli = NULL;
4087 struct policy_handle connect_handle, domain_handle, user_handle;
4088 struct lsa_String domain_name;
4089 struct dom_sid2 *domain_sid;
4090 struct lsa_String names;
4091 struct samr_Ids rids;
4092 struct samr_Ids types;
4093 int errcode = W_ERROR_V(WERR_NERR_USERNOTFOUND);
4094 uint32_t rid;
4095 union samr_UserInfo *info;
4096 struct dcerpc_binding_handle *b = NULL;
4098 if (!str1 || !str2 || !UserName || !p) {
4099 return False;
4102 *rparam_len = 6;
4103 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4104 if (!*rparam) {
4105 return False;
4108 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4110 /* check it's a supported variant */
4111 if (strcmp(str1,"zWrLh") != 0) {
4112 return False;
4114 switch( uLevel ) {
4115 case 0: level_string = "B21"; break;
4116 case 1: level_string = "B21BB16DWzzWz"; break;
4117 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4118 case 10: level_string = "B21Bzzz"; break;
4119 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4120 default: return False;
4123 if (strcmp(level_string,str2) != 0) {
4124 return False;
4127 *rdata_len = mdrcnt + 1024;
4128 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4129 if (!*rdata) {
4130 return False;
4133 p = *rdata;
4134 endp = *rdata + *rdata_len;
4135 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4136 if (!p2) {
4137 return False;
4140 ZERO_STRUCT(connect_handle);
4141 ZERO_STRUCT(domain_handle);
4142 ZERO_STRUCT(user_handle);
4144 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
4145 conn->session_info,
4146 conn->sconn->remote_address,
4147 conn->sconn->local_address,
4148 conn->sconn->msg_ctx,
4149 &cli);
4150 if (!NT_STATUS_IS_OK(status)) {
4151 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4152 nt_errstr(status)));
4153 errcode = W_ERROR_V(ntstatus_to_werror(status));
4154 goto out;
4157 b = cli->binding_handle;
4159 status = dcerpc_samr_Connect2(b, mem_ctx,
4160 lp_netbios_name(),
4161 SAMR_ACCESS_CONNECT_TO_SERVER |
4162 SAMR_ACCESS_ENUM_DOMAINS |
4163 SAMR_ACCESS_LOOKUP_DOMAIN,
4164 &connect_handle,
4165 &result);
4166 if (!NT_STATUS_IS_OK(status)) {
4167 errcode = W_ERROR_V(ntstatus_to_werror(status));
4168 goto out;
4170 if (!NT_STATUS_IS_OK(result)) {
4171 errcode = W_ERROR_V(ntstatus_to_werror(result));
4172 goto out;
4175 init_lsa_String(&domain_name, get_global_sam_name());
4177 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4178 &connect_handle,
4179 &domain_name,
4180 &domain_sid,
4181 &result);
4182 if (!NT_STATUS_IS_OK(status)) {
4183 errcode = W_ERROR_V(ntstatus_to_werror(status));
4184 goto out;
4186 if (!NT_STATUS_IS_OK(result)) {
4187 errcode = W_ERROR_V(ntstatus_to_werror(result));
4188 goto out;
4191 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4192 &connect_handle,
4193 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4194 domain_sid,
4195 &domain_handle,
4196 &result);
4197 if (!NT_STATUS_IS_OK(status)) {
4198 errcode = W_ERROR_V(ntstatus_to_werror(status));
4199 goto out;
4201 if (!NT_STATUS_IS_OK(result)) {
4202 errcode = W_ERROR_V(ntstatus_to_werror(result));
4203 goto out;
4206 init_lsa_String(&names, UserName);
4208 status = dcerpc_samr_LookupNames(b, mem_ctx,
4209 &domain_handle,
4211 &names,
4212 &rids,
4213 &types,
4214 &result);
4215 if (!NT_STATUS_IS_OK(status)) {
4216 errcode = W_ERROR_V(ntstatus_to_werror(status));
4217 goto out;
4219 if (!NT_STATUS_IS_OK(result)) {
4220 errcode = W_ERROR_V(ntstatus_to_werror(result));
4221 goto out;
4224 if (rids.count != 1) {
4225 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4226 goto out;
4228 if (rids.count != types.count) {
4229 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4230 goto out;
4232 if (types.ids[0] != SID_NAME_USER) {
4233 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4234 goto out;
4237 rid = rids.ids[0];
4239 status = dcerpc_samr_OpenUser(b, mem_ctx,
4240 &domain_handle,
4241 SAMR_USER_ACCESS_GET_LOCALE |
4242 SAMR_USER_ACCESS_GET_LOGONINFO |
4243 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4244 SAMR_USER_ACCESS_GET_GROUPS |
4245 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4246 SEC_STD_READ_CONTROL,
4247 rid,
4248 &user_handle,
4249 &result);
4250 if (!NT_STATUS_IS_OK(status)) {
4251 errcode = W_ERROR_V(ntstatus_to_werror(status));
4252 goto out;
4254 if (!NT_STATUS_IS_OK(result)) {
4255 errcode = W_ERROR_V(ntstatus_to_werror(result));
4256 goto out;
4259 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4260 &user_handle,
4261 UserAllInformation,
4262 &info,
4263 &result);
4264 if (!NT_STATUS_IS_OK(status)) {
4265 errcode = W_ERROR_V(ntstatus_to_werror(status));
4266 goto out;
4268 if (!NT_STATUS_IS_OK(result)) {
4269 errcode = W_ERROR_V(ntstatus_to_werror(result));
4270 goto out;
4273 memset(p,0,21);
4274 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4276 if (uLevel > 0) {
4277 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4278 *p2 = 0;
4281 if (uLevel >= 10) {
4282 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4283 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4284 p2 = skip_string(*rdata,*rdata_len,p2);
4285 if (!p2) {
4286 return False;
4289 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4290 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4291 p2 = skip_string(*rdata,*rdata_len,p2);
4292 if (!p2) {
4293 return False;
4296 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4297 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4298 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4299 p2 = skip_string(*rdata,*rdata_len,p2);
4300 if (!p2) {
4301 return False;
4305 if (uLevel == 11) {
4306 const char *homedir = info->info21.home_directory.string;
4307 /* modelled after NTAS 3.51 reply */
4308 SSVAL(p,usri11_priv,
4309 (get_current_uid(conn) == sec_initial_uid())?
4310 USER_PRIV_ADMIN:USER_PRIV_USER);
4311 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4312 SIVALS(p,usri11_password_age,-1); /* password age */
4313 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4314 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4315 p2 = skip_string(*rdata,*rdata_len,p2);
4316 if (!p2) {
4317 return False;
4319 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4320 strlcpy(p2,"",PTR_DIFF(endp,p2));
4321 p2 = skip_string(*rdata,*rdata_len,p2);
4322 if (!p2) {
4323 return False;
4325 SIVAL(p,usri11_last_logon,0); /* last logon */
4326 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4327 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4328 SSVALS(p,usri11_num_logons,-1); /* num logons */
4329 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4330 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4331 p2 = skip_string(*rdata,*rdata_len,p2);
4332 if (!p2) {
4333 return False;
4335 SSVAL(p,usri11_country_code,0); /* country code */
4337 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4338 strlcpy(p2,"",PTR_DIFF(endp,p2));
4339 p2 = skip_string(*rdata,*rdata_len,p2);
4340 if (!p2) {
4341 return False;
4344 SIVALS(p,usri11_max_storage,-1); /* max storage */
4345 SSVAL(p,usri11_units_per_week,168); /* units per week */
4346 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4348 /* a simple way to get logon hours at all times. */
4349 memset(p2,0xff,21);
4350 SCVAL(p2,21,0); /* fix zero termination */
4351 p2 = skip_string(*rdata,*rdata_len,p2);
4352 if (!p2) {
4353 return False;
4356 SSVAL(p,usri11_code_page,0); /* code page */
4359 if (uLevel == 1 || uLevel == 2) {
4360 memset(p+22,' ',16); /* password */
4361 SIVALS(p,38,-1); /* password age */
4362 SSVAL(p,42,
4363 (get_current_uid(conn) == sec_initial_uid())?
4364 USER_PRIV_ADMIN:USER_PRIV_USER);
4365 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4366 strlcpy(p2, info->info21.home_directory.string,
4367 PTR_DIFF(endp,p2));
4368 p2 = skip_string(*rdata,*rdata_len,p2);
4369 if (!p2) {
4370 return False;
4372 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4373 *p2++ = 0;
4374 SSVAL(p,52,0); /* flags */
4375 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4376 strlcpy(p2, info->info21.logon_script.string,
4377 PTR_DIFF(endp,p2));
4378 p2 = skip_string(*rdata,*rdata_len,p2);
4379 if (!p2) {
4380 return False;
4382 if (uLevel == 2) {
4383 SIVAL(p,58,0); /* auth_flags */
4384 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4385 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4386 p2 = skip_string(*rdata,*rdata_len,p2);
4387 if (!p2) {
4388 return False;
4390 SIVAL(p,66,0); /* urs_comment */
4391 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4392 strlcpy(p2,"",PTR_DIFF(endp,p2));
4393 p2 = skip_string(*rdata,*rdata_len,p2);
4394 if (!p2) {
4395 return False;
4397 SIVAL(p,74,0); /* workstations */
4398 SIVAL(p,78,0); /* last_logon */
4399 SIVAL(p,82,0); /* last_logoff */
4400 SIVALS(p,86,-1); /* acct_expires */
4401 SIVALS(p,90,-1); /* max_storage */
4402 SSVAL(p,94,168); /* units_per_week */
4403 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4404 memset(p2,-1,21);
4405 p2 += 21;
4406 SSVALS(p,100,-1); /* bad_pw_count */
4407 SSVALS(p,102,-1); /* num_logons */
4408 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4410 TALLOC_CTX *ctx = talloc_tos();
4411 int space_rem = *rdata_len - (p2 - *rdata);
4412 char *tmp;
4414 if (space_rem <= 0) {
4415 return false;
4417 tmp = talloc_strdup(ctx, "\\\\%L");
4418 if (!tmp) {
4419 return false;
4421 tmp = talloc_sub_basic(ctx,
4424 tmp);
4425 if (!tmp) {
4426 return false;
4429 push_ascii(p2,
4430 tmp,
4431 space_rem,
4432 STR_TERMINATE);
4434 p2 = skip_string(*rdata,*rdata_len,p2);
4435 if (!p2) {
4436 return False;
4438 SSVAL(p,108,49); /* country_code */
4439 SSVAL(p,110,860); /* code page */
4443 errcode = NERR_Success;
4445 out:
4446 *rdata_len = PTR_DIFF(p2,*rdata);
4448 if (b && is_valid_policy_hnd(&user_handle)) {
4449 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4451 if (b && is_valid_policy_hnd(&domain_handle)) {
4452 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4454 if (b && is_valid_policy_hnd(&connect_handle)) {
4455 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4458 SSVAL(*rparam,0,errcode);
4459 SSVAL(*rparam,2,0); /* converter word */
4460 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4462 return(True);
4465 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4466 connection_struct *conn,uint64_t vuid,
4467 char *param, int tpscnt,
4468 char *data, int tdscnt,
4469 int mdrcnt,int mprcnt,
4470 char **rdata,char **rparam,
4471 int *rdata_len,int *rparam_len)
4473 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4474 char *str2 = skip_string(param,tpscnt,str1);
4475 char *p = skip_string(param,tpscnt,str2);
4476 int uLevel;
4477 struct pack_desc desc;
4478 char* name;
4479 struct auth_session_info *si = NULL;
4480 NTSTATUS status;
4482 status = smbXsrv_session_info_lookup(conn->sconn->client,
4483 vuid,
4484 &si);
4485 if (!NT_STATUS_IS_OK(status)) {
4486 return false;
4489 if (!str1 || !str2 || !p) {
4490 return False;
4493 DBG_INFO("Username of UID %ju is %s\n",
4494 (uintmax_t)si->unix_token->uid,
4495 si->unix_info->unix_name);
4497 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4498 name = get_safe_str_ptr(param,tpscnt,p,2);
4499 if (!name) {
4500 return False;
4503 memset((char *)&desc,'\0',sizeof(desc));
4505 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4507 /* check it's a supported variant */
4508 if (strcmp(str1,"OOWb54WrLh") != 0) {
4509 return False;
4511 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4512 return False;
4514 if (mdrcnt > 0) {
4515 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4516 if (!*rdata) {
4517 return False;
4521 desc.base = *rdata;
4522 desc.buflen = mdrcnt;
4523 desc.subformat = NULL;
4524 desc.format = str2;
4526 if (init_package(&desc,1,0)) {
4527 PACKI(&desc,"W",0); /* code */
4528 PACKS(&desc,"B21",name); /* eff. name */
4529 PACKS(&desc,"B",""); /* pad */
4530 PACKI(&desc,"W",
4531 (get_current_uid(conn) == sec_initial_uid())?
4532 USER_PRIV_ADMIN:USER_PRIV_USER);
4533 PACKI(&desc,"D",0); /* auth flags XXX */
4534 PACKI(&desc,"W",0); /* num logons */
4535 PACKI(&desc,"W",0); /* bad pw count */
4536 PACKI(&desc,"D",0); /* last logon */
4537 PACKI(&desc,"D",-1); /* last logoff */
4538 PACKI(&desc,"D",-1); /* logoff time */
4539 PACKI(&desc,"D",-1); /* kickoff time */
4540 PACKI(&desc,"D",0); /* password age */
4541 PACKI(&desc,"D",0); /* password can change */
4542 PACKI(&desc,"D",-1); /* password must change */
4545 fstring mypath;
4546 fstrcpy(mypath,"\\\\");
4547 fstrcat(mypath,get_local_machine_name());
4548 if (!strupper_m(mypath)) {
4549 return false;
4551 PACKS(&desc,"z",mypath); /* computer */
4554 PACKS(&desc,"z",lp_workgroup());/* domain */
4555 PACKS(&desc,"z", si->info->logon_script); /* script path */
4556 PACKI(&desc,"D",0x00000000); /* reserved */
4559 *rdata_len = desc.usedlen;
4560 *rparam_len = 6;
4561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4562 if (!*rparam) {
4563 return False;
4565 SSVALS(*rparam,0,desc.errcode);
4566 SSVAL(*rparam,2,0);
4567 SSVAL(*rparam,4,desc.neededlen);
4569 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4571 return True;
4574 /****************************************************************************
4575 api_WAccessGetUserPerms
4576 ****************************************************************************/
4578 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4579 connection_struct *conn,uint64_t vuid,
4580 char *param, int tpscnt,
4581 char *data, int tdscnt,
4582 int mdrcnt,int mprcnt,
4583 char **rdata,char **rparam,
4584 int *rdata_len,int *rparam_len)
4586 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4587 char *str2 = skip_string(param,tpscnt,str1);
4588 char *user = skip_string(param,tpscnt,str2);
4589 char *resource = skip_string(param,tpscnt,user);
4591 if (!str1 || !str2 || !user || !resource) {
4592 return False;
4595 if (skip_string(param,tpscnt,resource) == NULL) {
4596 return False;
4598 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4600 /* check it's a supported variant */
4601 if (strcmp(str1,"zzh") != 0) {
4602 return False;
4604 if (strcmp(str2,"") != 0) {
4605 return False;
4608 *rparam_len = 6;
4609 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4610 if (!*rparam) {
4611 return False;
4613 SSVALS(*rparam,0,0); /* errorcode */
4614 SSVAL(*rparam,2,0); /* converter word */
4615 SSVAL(*rparam,4,0x7f); /* permission flags */
4617 return True;
4620 /****************************************************************************
4621 api_WPrintJobEnumerate
4622 ****************************************************************************/
4624 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4625 connection_struct *conn, uint64_t vuid,
4626 char *param, int tpscnt,
4627 char *data, int tdscnt,
4628 int mdrcnt,int mprcnt,
4629 char **rdata,char **rparam,
4630 int *rdata_len,int *rparam_len)
4632 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4633 char *str2 = skip_string(param,tpscnt,str1);
4634 char *p = skip_string(param,tpscnt,str2);
4635 int uLevel;
4636 fstring sharename;
4637 uint32_t jobid;
4638 struct pack_desc desc;
4639 char *tmpdata=NULL;
4641 TALLOC_CTX *mem_ctx = talloc_tos();
4642 WERROR werr;
4643 NTSTATUS status;
4644 struct rpc_pipe_client *cli = NULL;
4645 struct dcerpc_binding_handle *b = NULL;
4646 struct policy_handle handle;
4647 struct spoolss_DevmodeContainer devmode_ctr;
4648 union spoolss_JobInfo info;
4650 if (!str1 || !str2 || !p) {
4651 return False;
4654 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4656 memset((char *)&desc,'\0',sizeof(desc));
4657 memset((char *)&status,'\0',sizeof(status));
4659 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4661 /* check it's a supported variant */
4662 if (strcmp(str1,"WWrLh") != 0) {
4663 return False;
4665 if (!check_printjob_info(&desc,uLevel,str2)) {
4666 return False;
4669 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4670 return False;
4673 ZERO_STRUCT(handle);
4675 status = rpc_pipe_open_interface(mem_ctx,
4676 &ndr_table_spoolss,
4677 conn->session_info,
4678 conn->sconn->remote_address,
4679 conn->sconn->local_address,
4680 conn->sconn->msg_ctx,
4681 &cli);
4682 if (!NT_STATUS_IS_OK(status)) {
4683 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4684 nt_errstr(status)));
4685 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4686 goto out;
4688 b = cli->binding_handle;
4690 ZERO_STRUCT(devmode_ctr);
4692 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4693 sharename,
4694 "RAW",
4695 devmode_ctr,
4696 PRINTER_ACCESS_USE,
4697 &handle,
4698 &werr);
4699 if (!NT_STATUS_IS_OK(status)) {
4700 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4701 goto out;
4703 if (!W_ERROR_IS_OK(werr)) {
4704 desc.errcode = W_ERROR_V(werr);
4705 goto out;
4708 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4709 &handle,
4710 jobid,
4711 2, /* level */
4712 0, /* offered */
4713 &info);
4714 if (!W_ERROR_IS_OK(werr)) {
4715 desc.errcode = W_ERROR_V(werr);
4716 goto out;
4719 if (mdrcnt > 0) {
4720 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4721 if (!*rdata) {
4722 return False;
4724 desc.base = *rdata;
4725 desc.buflen = mdrcnt;
4726 } else {
4728 * Don't return data but need to get correct length
4729 * init_package will return wrong size if buflen=0
4731 desc.buflen = getlen(desc.format);
4732 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4735 if (init_package(&desc,1,0)) {
4736 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4737 *rdata_len = desc.usedlen;
4738 } else {
4739 desc.errcode = NERR_JobNotFound;
4740 *rdata_len = 0;
4742 out:
4743 if (b && is_valid_policy_hnd(&handle)) {
4744 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4747 *rparam_len = 6;
4748 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4749 if (!*rparam) {
4750 return False;
4752 SSVALS(*rparam,0,desc.errcode);
4753 SSVAL(*rparam,2,0);
4754 SSVAL(*rparam,4,desc.neededlen);
4756 SAFE_FREE(tmpdata);
4758 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4760 return True;
4763 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4764 connection_struct *conn, uint64_t vuid,
4765 char *param, int tpscnt,
4766 char *data, int tdscnt,
4767 int mdrcnt,int mprcnt,
4768 char **rdata,char **rparam,
4769 int *rdata_len,int *rparam_len)
4771 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4772 char *str2 = skip_string(param,tpscnt,str1);
4773 char *p = skip_string(param,tpscnt,str2);
4774 char *name = p;
4775 int uLevel;
4776 int i, succnt=0;
4777 struct pack_desc desc;
4779 TALLOC_CTX *mem_ctx = talloc_tos();
4780 WERROR werr;
4781 NTSTATUS status;
4782 struct rpc_pipe_client *cli = NULL;
4783 struct dcerpc_binding_handle *b = NULL;
4784 struct policy_handle handle;
4785 struct spoolss_DevmodeContainer devmode_ctr;
4786 uint32_t count = 0;
4787 union spoolss_JobInfo *info;
4789 if (!str1 || !str2 || !p) {
4790 return False;
4793 memset((char *)&desc,'\0',sizeof(desc));
4795 p = skip_string(param,tpscnt,p);
4796 if (!p) {
4797 return False;
4799 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4801 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4803 /* check it's a supported variant */
4804 if (strcmp(str1,"zWrLeh") != 0) {
4805 return False;
4808 if (uLevel > 2) {
4809 return False; /* defined only for uLevel 0,1,2 */
4812 if (!check_printjob_info(&desc,uLevel,str2)) {
4813 return False;
4816 ZERO_STRUCT(handle);
4818 status = rpc_pipe_open_interface(mem_ctx,
4819 &ndr_table_spoolss,
4820 conn->session_info,
4821 conn->sconn->remote_address,
4822 conn->sconn->local_address,
4823 conn->sconn->msg_ctx,
4824 &cli);
4825 if (!NT_STATUS_IS_OK(status)) {
4826 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4827 nt_errstr(status)));
4828 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4829 goto out;
4831 b = cli->binding_handle;
4833 ZERO_STRUCT(devmode_ctr);
4835 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4836 name,
4837 NULL,
4838 devmode_ctr,
4839 PRINTER_ACCESS_USE,
4840 &handle,
4841 &werr);
4842 if (!NT_STATUS_IS_OK(status)) {
4843 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4844 goto out;
4846 if (!W_ERROR_IS_OK(werr)) {
4847 desc.errcode = W_ERROR_V(werr);
4848 goto out;
4851 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4852 &handle,
4853 0, /* firstjob */
4854 0xff, /* numjobs */
4855 2, /* level */
4856 0, /* offered */
4857 &count,
4858 &info);
4859 if (!W_ERROR_IS_OK(werr)) {
4860 desc.errcode = W_ERROR_V(werr);
4861 goto out;
4864 if (mdrcnt > 0) {
4865 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4866 if (!*rdata) {
4867 return False;
4870 desc.base = *rdata;
4871 desc.buflen = mdrcnt;
4873 if (init_package(&desc,count,0)) {
4874 succnt = 0;
4875 for (i = 0; i < count; i++) {
4876 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4877 if (desc.errcode == NERR_Success) {
4878 succnt = i+1;
4882 out:
4883 if (b && is_valid_policy_hnd(&handle)) {
4884 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4887 *rdata_len = desc.usedlen;
4889 *rparam_len = 8;
4890 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4891 if (!*rparam) {
4892 return False;
4894 SSVALS(*rparam,0,desc.errcode);
4895 SSVAL(*rparam,2,0);
4896 SSVAL(*rparam,4,succnt);
4897 SSVAL(*rparam,6,count);
4899 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4901 return True;
4904 static int check_printdest_info(struct pack_desc* desc,
4905 int uLevel, char* id)
4907 desc->subformat = NULL;
4908 switch( uLevel ) {
4909 case 0:
4910 desc->format = "B9";
4911 break;
4912 case 1:
4913 desc->format = "B9B21WWzW";
4914 break;
4915 case 2:
4916 desc->format = "z";
4917 break;
4918 case 3:
4919 desc->format = "zzzWWzzzWW";
4920 break;
4921 default:
4922 DEBUG(0,("check_printdest_info: invalid level %d\n",
4923 uLevel));
4924 return False;
4926 if (id == NULL || strcmp(desc->format,id) != 0) {
4927 DEBUG(0,("check_printdest_info: invalid string %s\n",
4928 id ? id : "<NULL>" ));
4929 return False;
4931 return True;
4934 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4935 struct pack_desc* desc)
4937 char buf[100];
4939 strncpy(buf, info2->printername, sizeof(buf)-1);
4940 buf[sizeof(buf)-1] = 0;
4941 (void)strupper_m(buf);
4943 if (uLevel <= 1) {
4944 PACKS(desc,"B9",buf); /* szName */
4945 if (uLevel == 1) {
4946 PACKS(desc,"B21",""); /* szUserName */
4947 PACKI(desc,"W",0); /* uJobId */
4948 PACKI(desc,"W",0); /* fsStatus */
4949 PACKS(desc,"z",""); /* pszStatus */
4950 PACKI(desc,"W",0); /* time */
4954 if (uLevel == 2 || uLevel == 3) {
4955 PACKS(desc,"z",buf); /* pszPrinterName */
4956 if (uLevel == 3) {
4957 PACKS(desc,"z",""); /* pszUserName */
4958 PACKS(desc,"z",""); /* pszLogAddr */
4959 PACKI(desc,"W",0); /* uJobId */
4960 PACKI(desc,"W",0); /* fsStatus */
4961 PACKS(desc,"z",""); /* pszStatus */
4962 PACKS(desc,"z",""); /* pszComment */
4963 PACKS(desc,"z","NULL"); /* pszDrivers */
4964 PACKI(desc,"W",0); /* time */
4965 PACKI(desc,"W",0); /* pad1 */
4970 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4971 connection_struct *conn, uint64_t vuid,
4972 char *param, int tpscnt,
4973 char *data, int tdscnt,
4974 int mdrcnt,int mprcnt,
4975 char **rdata,char **rparam,
4976 int *rdata_len,int *rparam_len)
4978 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4979 char *str2 = skip_string(param,tpscnt,str1);
4980 char *p = skip_string(param,tpscnt,str2);
4981 char* PrinterName = p;
4982 int uLevel;
4983 struct pack_desc desc;
4984 char *tmpdata=NULL;
4986 TALLOC_CTX *mem_ctx = talloc_tos();
4987 WERROR werr;
4988 NTSTATUS status;
4989 struct rpc_pipe_client *cli = NULL;
4990 struct dcerpc_binding_handle *b = NULL;
4991 struct policy_handle handle;
4992 struct spoolss_DevmodeContainer devmode_ctr;
4993 union spoolss_PrinterInfo info;
4995 if (!str1 || !str2 || !p) {
4996 return False;
4999 memset((char *)&desc,'\0',sizeof(desc));
5001 p = skip_string(param,tpscnt,p);
5002 if (!p) {
5003 return False;
5005 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5007 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
5009 /* check it's a supported variant */
5010 if (strcmp(str1,"zWrLh") != 0) {
5011 return False;
5013 if (!check_printdest_info(&desc,uLevel,str2)) {
5014 return False;
5017 ZERO_STRUCT(handle);
5019 status = rpc_pipe_open_interface(mem_ctx,
5020 &ndr_table_spoolss,
5021 conn->session_info,
5022 conn->sconn->remote_address,
5023 conn->sconn->local_address,
5024 conn->sconn->msg_ctx,
5025 &cli);
5026 if (!NT_STATUS_IS_OK(status)) {
5027 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
5028 nt_errstr(status)));
5029 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5030 goto out;
5032 b = cli->binding_handle;
5034 ZERO_STRUCT(devmode_ctr);
5036 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5037 PrinterName,
5038 NULL,
5039 devmode_ctr,
5040 PRINTER_ACCESS_USE,
5041 &handle,
5042 &werr);
5043 if (!NT_STATUS_IS_OK(status)) {
5044 *rdata_len = 0;
5045 desc.errcode = NERR_DestNotFound;
5046 desc.neededlen = 0;
5047 goto out;
5049 if (!W_ERROR_IS_OK(werr)) {
5050 *rdata_len = 0;
5051 desc.errcode = NERR_DestNotFound;
5052 desc.neededlen = 0;
5053 goto out;
5056 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5057 &handle,
5060 &info);
5061 if (!W_ERROR_IS_OK(werr)) {
5062 *rdata_len = 0;
5063 desc.errcode = NERR_DestNotFound;
5064 desc.neededlen = 0;
5065 goto out;
5068 if (mdrcnt > 0) {
5069 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5070 if (!*rdata) {
5071 return False;
5073 desc.base = *rdata;
5074 desc.buflen = mdrcnt;
5075 } else {
5077 * Don't return data but need to get correct length
5078 * init_package will return wrong size if buflen=0
5080 desc.buflen = getlen(desc.format);
5081 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5083 if (init_package(&desc,1,0)) {
5084 fill_printdest_info(&info.info2, uLevel,&desc);
5087 out:
5088 if (b && is_valid_policy_hnd(&handle)) {
5089 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5092 *rdata_len = desc.usedlen;
5094 *rparam_len = 6;
5095 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5096 if (!*rparam) {
5097 return False;
5099 SSVALS(*rparam,0,desc.errcode);
5100 SSVAL(*rparam,2,0);
5101 SSVAL(*rparam,4,desc.neededlen);
5103 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5104 SAFE_FREE(tmpdata);
5106 return True;
5109 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5110 connection_struct *conn, uint64_t vuid,
5111 char *param, int tpscnt,
5112 char *data, int tdscnt,
5113 int mdrcnt,int mprcnt,
5114 char **rdata,char **rparam,
5115 int *rdata_len,int *rparam_len)
5117 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5118 char *str2 = skip_string(param,tpscnt,str1);
5119 char *p = skip_string(param,tpscnt,str2);
5120 int uLevel;
5121 int queuecnt;
5122 int i, n, succnt=0;
5123 struct pack_desc desc;
5125 TALLOC_CTX *mem_ctx = talloc_tos();
5126 WERROR werr;
5127 NTSTATUS status;
5128 struct rpc_pipe_client *cli = NULL;
5129 union spoolss_PrinterInfo *info;
5130 uint32_t count;
5132 if (!str1 || !str2 || !p) {
5133 return False;
5136 memset((char *)&desc,'\0',sizeof(desc));
5138 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5140 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5142 /* check it's a supported variant */
5143 if (strcmp(str1,"WrLeh") != 0) {
5144 return False;
5146 if (!check_printdest_info(&desc,uLevel,str2)) {
5147 return False;
5150 queuecnt = 0;
5152 status = rpc_pipe_open_interface(mem_ctx,
5153 &ndr_table_spoolss,
5154 conn->session_info,
5155 conn->sconn->remote_address,
5156 conn->sconn->local_address,
5157 conn->sconn->msg_ctx,
5158 &cli);
5159 if (!NT_STATUS_IS_OK(status)) {
5160 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5161 nt_errstr(status)));
5162 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5163 goto out;
5166 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5167 PRINTER_ENUM_LOCAL,
5168 cli->srv_name_slash,
5171 &count,
5172 &info);
5173 if (!W_ERROR_IS_OK(werr)) {
5174 desc.errcode = W_ERROR_V(werr);
5175 *rdata_len = 0;
5176 desc.errcode = NERR_DestNotFound;
5177 desc.neededlen = 0;
5178 goto out;
5181 queuecnt = count;
5183 if (mdrcnt > 0) {
5184 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5185 if (!*rdata) {
5186 return False;
5190 desc.base = *rdata;
5191 desc.buflen = mdrcnt;
5192 if (init_package(&desc,queuecnt,0)) {
5193 succnt = 0;
5194 n = 0;
5195 for (i = 0; i < count; i++) {
5196 fill_printdest_info(&info[i].info2, uLevel,&desc);
5197 n++;
5198 if (desc.errcode == NERR_Success) {
5199 succnt = n;
5203 out:
5204 *rdata_len = desc.usedlen;
5206 *rparam_len = 8;
5207 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5208 if (!*rparam) {
5209 return False;
5211 SSVALS(*rparam,0,desc.errcode);
5212 SSVAL(*rparam,2,0);
5213 SSVAL(*rparam,4,succnt);
5214 SSVAL(*rparam,6,queuecnt);
5216 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5218 return True;
5221 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5222 connection_struct *conn, uint64_t vuid,
5223 char *param, int tpscnt,
5224 char *data, int tdscnt,
5225 int mdrcnt,int mprcnt,
5226 char **rdata,char **rparam,
5227 int *rdata_len,int *rparam_len)
5229 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5230 char *str2 = skip_string(param,tpscnt,str1);
5231 char *p = skip_string(param,tpscnt,str2);
5232 int uLevel;
5233 int succnt;
5234 struct pack_desc desc;
5236 if (!str1 || !str2 || !p) {
5237 return False;
5240 memset((char *)&desc,'\0',sizeof(desc));
5242 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5244 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5246 /* check it's a supported variant */
5247 if (strcmp(str1,"WrLeh") != 0) {
5248 return False;
5250 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5251 return False;
5254 if (mdrcnt > 0) {
5255 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5256 if (!*rdata) {
5257 return False;
5260 desc.base = *rdata;
5261 desc.buflen = mdrcnt;
5262 if (init_package(&desc,1,0)) {
5263 PACKS(&desc,"B41","NULL");
5266 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5268 *rdata_len = desc.usedlen;
5270 *rparam_len = 8;
5271 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5272 if (!*rparam) {
5273 return False;
5275 SSVALS(*rparam,0,desc.errcode);
5276 SSVAL(*rparam,2,0);
5277 SSVAL(*rparam,4,succnt);
5278 SSVAL(*rparam,6,1);
5280 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5282 return True;
5285 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5286 connection_struct *conn, uint64_t vuid,
5287 char *param, int tpscnt,
5288 char *data, int tdscnt,
5289 int mdrcnt,int mprcnt,
5290 char **rdata,char **rparam,
5291 int *rdata_len,int *rparam_len)
5293 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5294 char *str2 = skip_string(param,tpscnt,str1);
5295 char *p = skip_string(param,tpscnt,str2);
5296 int uLevel;
5297 int succnt;
5298 struct pack_desc desc;
5300 if (!str1 || !str2 || !p) {
5301 return False;
5303 memset((char *)&desc,'\0',sizeof(desc));
5305 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5307 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5309 /* check it's a supported variant */
5310 if (strcmp(str1,"WrLeh") != 0) {
5311 return False;
5313 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5314 return False;
5317 if (mdrcnt > 0) {
5318 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5319 if (!*rdata) {
5320 return False;
5323 desc.base = *rdata;
5324 desc.buflen = mdrcnt;
5325 desc.format = str2;
5326 if (init_package(&desc,1,0)) {
5327 PACKS(&desc,"B13","lpd");
5330 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5332 *rdata_len = desc.usedlen;
5334 *rparam_len = 8;
5335 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5336 if (!*rparam) {
5337 return False;
5339 SSVALS(*rparam,0,desc.errcode);
5340 SSVAL(*rparam,2,0);
5341 SSVAL(*rparam,4,succnt);
5342 SSVAL(*rparam,6,1);
5344 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5346 return True;
5349 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5350 connection_struct *conn, uint64_t vuid,
5351 char *param, int tpscnt,
5352 char *data, int tdscnt,
5353 int mdrcnt,int mprcnt,
5354 char **rdata,char **rparam,
5355 int *rdata_len,int *rparam_len)
5357 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5358 char *str2 = skip_string(param,tpscnt,str1);
5359 char *p = skip_string(param,tpscnt,str2);
5360 int uLevel;
5361 int succnt;
5362 struct pack_desc desc;
5364 if (!str1 || !str2 || !p) {
5365 return False;
5368 memset((char *)&desc,'\0',sizeof(desc));
5370 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5372 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5374 /* check it's a supported variant */
5375 if (strcmp(str1,"WrLeh") != 0) {
5376 return False;
5378 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5379 return False;
5382 if (mdrcnt > 0) {
5383 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5384 if (!*rdata) {
5385 return False;
5388 memset((char *)&desc,'\0',sizeof(desc));
5389 desc.base = *rdata;
5390 desc.buflen = mdrcnt;
5391 desc.format = str2;
5392 if (init_package(&desc,1,0)) {
5393 PACKS(&desc,"B13","lp0");
5396 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5398 *rdata_len = desc.usedlen;
5400 *rparam_len = 8;
5401 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5402 if (!*rparam) {
5403 return False;
5405 SSVALS(*rparam,0,desc.errcode);
5406 SSVAL(*rparam,2,0);
5407 SSVAL(*rparam,4,succnt);
5408 SSVAL(*rparam,6,1);
5410 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5412 return True;
5415 /****************************************************************************
5416 List open sessions
5417 ****************************************************************************/
5419 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5420 connection_struct *conn, uint64_t vuid,
5421 char *param, int tpscnt,
5422 char *data, int tdscnt,
5423 int mdrcnt,int mprcnt,
5424 char **rdata,char **rparam,
5425 int *rdata_len,int *rparam_len)
5428 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5429 char *str2 = skip_string(param,tpscnt,str1);
5430 char *p = skip_string(param,tpscnt,str2);
5431 int uLevel;
5432 struct pack_desc desc;
5433 int i;
5435 TALLOC_CTX *mem_ctx = talloc_tos();
5436 WERROR werr;
5437 NTSTATUS status;
5438 struct rpc_pipe_client *cli = NULL;
5439 struct dcerpc_binding_handle *b = NULL;
5440 struct srvsvc_NetSessInfoCtr info_ctr;
5441 uint32_t totalentries, resume_handle = 0;
5442 uint32_t count = 0;
5444 if (!str1 || !str2 || !p) {
5445 return False;
5448 ZERO_STRUCT(desc);
5450 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5452 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5453 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5454 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5456 /* check it's a supported variant */
5457 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5458 return False;
5460 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5461 return False;
5464 status = rpc_pipe_open_interface(mem_ctx,
5465 &ndr_table_srvsvc,
5466 conn->session_info,
5467 conn->sconn->remote_address,
5468 conn->sconn->local_address,
5469 conn->sconn->msg_ctx,
5470 &cli);
5471 if (!NT_STATUS_IS_OK(status)) {
5472 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5473 nt_errstr(status)));
5474 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5475 goto out;
5477 b = cli->binding_handle;
5479 info_ctr.level = 1;
5480 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5481 if (info_ctr.ctr.ctr1 == NULL) {
5482 desc.errcode = W_ERROR_V(WERR_NOT_ENOUGH_MEMORY);
5483 goto out;
5486 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5487 cli->srv_name_slash,
5488 NULL, /* client */
5489 NULL, /* user */
5490 &info_ctr,
5491 (uint32_t)-1, /* max_buffer */
5492 &totalentries,
5493 &resume_handle,
5494 &werr);
5495 if (!NT_STATUS_IS_OK(status)) {
5496 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5497 nt_errstr(status)));
5498 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5499 goto out;
5502 if (!W_ERROR_IS_OK(werr)) {
5503 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5504 win_errstr(werr)));
5505 desc.errcode = W_ERROR_V(werr);
5506 goto out;
5509 count = info_ctr.ctr.ctr1->count;
5511 out:
5512 if (mdrcnt > 0) {
5513 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5514 if (!*rdata) {
5515 return False;
5519 desc.base = *rdata;
5520 desc.buflen = mdrcnt;
5521 desc.format = str2;
5522 if (!init_package(&desc, count,0)) {
5523 return False;
5526 for(i=0; i < count; i++) {
5527 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5528 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5529 PACKI(&desc, "W", 1); /* num conns */
5530 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5531 PACKI(&desc, "W", 1); /* num users */
5532 PACKI(&desc, "D", 0); /* session time */
5533 PACKI(&desc, "D", 0); /* idle time */
5534 PACKI(&desc, "D", 0); /* flags */
5535 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5538 *rdata_len = desc.usedlen;
5540 *rparam_len = 8;
5541 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5542 if (!*rparam) {
5543 return False;
5545 SSVALS(*rparam,0,desc.errcode);
5546 SSVAL(*rparam,2,0); /* converter */
5547 SSVAL(*rparam,4, count); /* count */
5549 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5551 return True;
5555 /****************************************************************************
5556 The buffer was too small.
5557 ****************************************************************************/
5559 static bool api_TooSmall(struct smbd_server_connection *sconn,
5560 connection_struct *conn,uint64_t vuid, char *param, char *data,
5561 int mdrcnt, int mprcnt,
5562 char **rdata, char **rparam,
5563 int *rdata_len, int *rparam_len)
5565 *rparam_len = MIN(*rparam_len,mprcnt);
5566 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5567 if (!*rparam) {
5568 return False;
5571 *rdata_len = 0;
5573 SSVAL(*rparam,0,NERR_BufTooSmall);
5575 DEBUG(3,("Supplied buffer too small in API command\n"));
5577 return True;
5580 /****************************************************************************
5581 The request is not supported.
5582 ****************************************************************************/
5584 static bool api_Unsupported(struct smbd_server_connection *sconn,
5585 connection_struct *conn, uint64_t vuid,
5586 char *param, int tpscnt,
5587 char *data, int tdscnt,
5588 int mdrcnt, int mprcnt,
5589 char **rdata, char **rparam,
5590 int *rdata_len, int *rparam_len)
5592 *rparam_len = 4;
5593 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5594 if (!*rparam) {
5595 return False;
5598 *rdata_len = 0;
5600 SSVAL(*rparam,0,NERR_notsupported);
5601 SSVAL(*rparam,2,0); /* converter word */
5603 DEBUG(3,("Unsupported API command\n"));
5605 return True;
5608 static const struct {
5609 const char *name;
5610 int id;
5611 bool (*fn)(struct smbd_server_connection *sconn,
5612 connection_struct *, uint64_t,
5613 char *, int,
5614 char *, int,
5615 int,int,char **,char **,int *,int *);
5616 bool auth_user; /* Deny anonymous access? */
5617 } api_commands[] = {
5619 .name = "RNetShareEnum",
5620 .id = RAP_WshareEnum,
5621 .fn = api_RNetShareEnum,
5622 .auth_user = true,
5625 .name = "RNetShareGetInfo",
5626 .id = RAP_WshareGetInfo,
5627 .fn = api_RNetShareGetInfo
5630 .name = "RNetShareAdd",
5631 .id = RAP_WshareAdd,
5632 .fn = api_RNetShareAdd
5635 .name = "RNetSessionEnum",
5636 .id = RAP_WsessionEnum,
5637 .fn = api_RNetSessionEnum,
5638 .auth_user = true,
5641 .name = "RNetServerGetInfo",
5642 .id = RAP_WserverGetInfo,
5643 .fn = api_RNetServerGetInfo
5646 .name = "RNetGroupEnum",
5647 .id = RAP_WGroupEnum,
5648 .fn = api_RNetGroupEnum, True
5651 .name = "RNetGroupGetUsers",
5652 .id = RAP_WGroupGetUsers,
5653 .fn = api_RNetGroupGetUsers,
5654 .auth_user = true},
5656 .name = "RNetUserEnum",
5657 .id = RAP_WUserEnum,
5658 .fn = api_RNetUserEnum,
5659 .auth_user = true,
5662 .name = "RNetUserGetInfo",
5663 .id = RAP_WUserGetInfo,
5664 .fn = api_RNetUserGetInfo
5667 .name = "NetUserGetGroups",
5668 .id = RAP_WUserGetGroups,
5669 .fn = api_NetUserGetGroups
5672 .name = "NetWkstaGetInfo",
5673 .id = RAP_WWkstaGetInfo,
5674 .fn = api_NetWkstaGetInfo
5677 .name = "DosPrintQEnum",
5678 .id = RAP_WPrintQEnum,
5679 .fn = api_DosPrintQEnum,
5680 .auth_user = true,
5683 .name = "DosPrintQGetInfo",
5684 .id = RAP_WPrintQGetInfo,
5685 .fn = api_DosPrintQGetInfo
5688 .name = "WPrintQueuePause",
5689 .id = RAP_WPrintQPause,
5690 .fn = api_WPrintQueueCtrl
5693 .name = "WPrintQueueResume",
5694 .id = RAP_WPrintQContinue,
5695 .fn = api_WPrintQueueCtrl
5698 .name = "WPrintJobEnumerate",
5699 .id = RAP_WPrintJobEnum,
5700 .fn = api_WPrintJobEnumerate
5703 .name = "WPrintJobGetInfo",
5704 .id = RAP_WPrintJobGetInfo,
5705 .fn = api_WPrintJobGetInfo
5708 .name = "RDosPrintJobDel",
5709 .id = RAP_WPrintJobDel,
5710 .fn = api_RDosPrintJobDel
5713 .name = "RDosPrintJobPause",
5714 .id = RAP_WPrintJobPause,
5715 .fn = api_RDosPrintJobDel
5718 .name = "RDosPrintJobResume",
5719 .id = RAP_WPrintJobContinue,
5720 .fn = api_RDosPrintJobDel
5723 .name = "WPrintDestEnum",
5724 .id = RAP_WPrintDestEnum,
5725 .fn = api_WPrintDestEnum
5728 .name = "WPrintDestGetInfo",
5729 .id = RAP_WPrintDestGetInfo,
5730 .fn = api_WPrintDestGetInfo
5733 .name = "NetRemoteTOD",
5734 .id = RAP_NetRemoteTOD,
5735 .fn = api_NetRemoteTOD
5738 .name = "WPrintQueuePurge",
5739 .id = RAP_WPrintQPurge,
5740 .fn = api_WPrintQueueCtrl
5743 .name = "NetServerEnum2",
5744 .id = RAP_NetServerEnum2,
5745 .fn = api_RNetServerEnum2
5746 }, /* anon OK */
5748 .name = "NetServerEnum3",
5749 .id = RAP_NetServerEnum3,
5750 .fn = api_RNetServerEnum3
5751 }, /* anon OK */
5753 .name = "WAccessGetUserPerms",
5754 .id = RAP_WAccessGetUserPerms,
5755 .fn = api_WAccessGetUserPerms
5758 .name = "WWkstaUserLogon",
5759 .id = RAP_WWkstaUserLogon,
5760 .fn = api_WWkstaUserLogon
5763 .name = "PrintJobInfo",
5764 .id = RAP_WPrintJobSetInfo,
5765 .fn = api_PrintJobInfo
5768 .name = "WPrintDriverEnum",
5769 .id = RAP_WPrintDriverEnum,
5770 .fn = api_WPrintDriverEnum
5773 .name = "WPrintQProcEnum",
5774 .id = RAP_WPrintQProcessorEnum,
5775 .fn = api_WPrintQProcEnum
5778 .name = "WPrintPortEnum",
5779 .id = RAP_WPrintPortEnum,
5780 .fn = api_WPrintPortEnum
5783 .name = "SamOEMChangePassword",
5784 .id = RAP_SamOEMChgPasswordUser2_P,
5785 .fn = api_SamOEMChangePassword
5786 }, /* anon OK */
5788 .name = NULL,
5789 .id = -1,
5790 .fn = api_Unsupported}
5792 * The following RAP calls are not implemented by Samba:
5793 * RAP_WFileEnum2 - anon not OK
5798 /****************************************************************************
5799 Handle remote api calls.
5800 ****************************************************************************/
5802 void api_reply(connection_struct *conn, uint64_t vuid,
5803 struct smb_request *req,
5804 char *data, char *params,
5805 int tdscnt, int tpscnt,
5806 int mdrcnt, int mprcnt)
5808 int api_command;
5809 char *rdata = NULL;
5810 char *rparam = NULL;
5811 const char *name1 = NULL;
5812 const char *name2 = NULL;
5813 int rdata_len = 0;
5814 int rparam_len = 0;
5815 bool reply=False;
5816 int i;
5818 if (!params) {
5819 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5820 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5821 return;
5824 if (tpscnt < 2) {
5825 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5826 return;
5828 api_command = SVAL(params,0);
5829 /* Is there a string at position params+2 ? */
5830 if (skip_string(params,tpscnt,params+2)) {
5831 name1 = params + 2;
5832 } else {
5833 name1 = "";
5835 name2 = skip_string(params,tpscnt,params+2);
5836 if (!name2) {
5837 name2 = "";
5840 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5841 api_command,
5842 name1,
5843 name2,
5844 tdscnt,tpscnt,mdrcnt,mprcnt));
5846 for (i=0;api_commands[i].name;i++) {
5847 if (api_commands[i].id == api_command && api_commands[i].fn) {
5848 DEBUG(3,("Doing %s\n",api_commands[i].name));
5849 break;
5853 /* Check whether this api call can be done anonymously */
5855 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5856 struct auth_session_info *si = NULL;
5857 NTSTATUS status;
5859 status = smbXsrv_session_info_lookup(conn->sconn->client,
5860 vuid,
5861 &si);
5862 if (!NT_STATUS_IS_OK(status)) {
5863 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5864 return;
5867 if (security_session_user_level(si, NULL) < SECURITY_USER) {
5868 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5869 return;
5873 rdata = (char *)SMB_MALLOC(1024);
5874 if (rdata) {
5875 memset(rdata,'\0',1024);
5878 rparam = (char *)SMB_MALLOC(1024);
5879 if (rparam) {
5880 memset(rparam,'\0',1024);
5883 if(!rdata || !rparam) {
5884 DEBUG(0,("api_reply: malloc fail !\n"));
5885 SAFE_FREE(rdata);
5886 SAFE_FREE(rparam);
5887 reply_nterror(req, NT_STATUS_NO_MEMORY);
5888 return;
5891 reply = api_commands[i].fn(req->sconn, conn,
5892 vuid,
5893 params,tpscnt, /* params + length */
5894 data,tdscnt, /* data + length */
5895 mdrcnt,mprcnt,
5896 &rdata,&rparam,&rdata_len,&rparam_len);
5899 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5900 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5901 mdrcnt,mprcnt,
5902 &rdata,&rparam,&rdata_len,&rparam_len);
5905 /* if we get False back then it's actually unsupported */
5906 if (!reply) {
5907 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5908 data,
5909 tdscnt,mdrcnt,mprcnt,
5910 &rdata,&rparam,&rdata_len,&rparam_len);
5913 /* If api_Unsupported returns false we can't return anything. */
5914 if (reply) {
5915 send_trans_reply(conn, req, rparam, rparam_len,
5916 rdata, rdata_len, False);
5919 SAFE_FREE(rdata);
5920 SAFE_FREE(rparam);
5921 return;