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.
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
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "rpc_client/cli_spoolss.h"
33 #include "../librpc/gen_ndr/cli_srvsvc.h"
34 #include "../librpc/gen_ndr/srv_samr.h"
35 #include "../librpc/gen_ndr/srv_spoolss.h"
36 #include "../librpc/gen_ndr/srv_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
45 #define NERR_Success 0
46 #define NERR_badpass 86
47 #define NERR_notsupported 50
49 #define NERR_BASE (2100)
50 #define NERR_BufTooSmall (NERR_BASE+23)
51 #define NERR_JobNotFound (NERR_BASE+51)
52 #define NERR_DestNotFound (NERR_BASE+52)
54 #define ACCESS_READ 0x01
55 #define ACCESS_WRITE 0x02
56 #define ACCESS_CREATE 0x04
58 #define SHPWLEN 8 /* share password length */
60 /* Limit size of ipc replies */
62 static char *smb_realloc_limit(void *ptr, size_t size)
66 size = MAX((size),4*1024);
67 val = (char *)SMB_REALLOC(ptr,size);
69 memset(val,'\0',size);
74 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
75 char *param, int tpscnt,
76 char *data, int tdscnt,
77 int mdrcnt, int mprcnt,
78 char **rdata, char **rparam,
79 int *rdata_len, int *rparam_len);
81 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
82 int mdrcnt, int mprcnt,
83 char **rdata, char **rparam,
84 int *rdata_len, int *rparam_len);
87 static int CopyExpanded(connection_struct *conn,
88 int snum, char **dst, char *src, int *p_space_remaining)
90 TALLOC_CTX *ctx = talloc_tos();
94 if (!src || !dst || !p_space_remaining || !(*dst) ||
95 *p_space_remaining <= 0) {
99 buf = talloc_strdup(ctx, src);
101 *p_space_remaining = 0;
104 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
106 *p_space_remaining = 0;
109 buf = talloc_sub_advanced(ctx,
110 lp_servicename(SNUM(conn)),
111 conn->server_info->unix_name,
113 conn->server_info->utok.gid,
114 conn->server_info->sanitized_username,
115 pdb_get_domain(conn->server_info->sam_account),
118 *p_space_remaining = 0;
121 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
126 (*p_space_remaining) -= l;
130 static int CopyAndAdvance(char **dst, char *src, int *n)
133 if (!src || !dst || !n || !(*dst)) {
136 l = push_ascii(*dst,src,*n, STR_TERMINATE);
145 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
147 TALLOC_CTX *ctx = talloc_tos();
152 buf = talloc_strdup(ctx,s);
156 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
160 buf = talloc_sub_advanced(ctx,
161 lp_servicename(SNUM(conn)),
162 conn->server_info->unix_name,
164 conn->server_info->utok.gid,
165 conn->server_info->sanitized_username,
166 pdb_get_domain(conn->server_info->sam_account),
171 return strlen(buf) + 1;
174 /*******************************************************************
175 Check a API string for validity when we only need to check the prefix.
176 ******************************************************************/
178 static bool prefix_ok(const char *str, const char *prefix)
180 return(strncmp(str,prefix,strlen(prefix)) == 0);
184 const char *format; /* formatstring for structure */
185 const char *subformat; /* subformat for structure */
186 char *base; /* baseaddress of buffer */
187 int buflen; /* remaining size for fixed part; on init: length of base */
188 int subcount; /* count of substructures */
189 char *structbuf; /* pointer into buffer for remaining fixed part */
190 int stringlen; /* remaining size for variable part */
191 char *stringbuf; /* pointer into buffer for remaining variable part */
192 int neededlen; /* total needed size */
193 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
194 const char *curpos; /* current position; pointer into format or subformat */
198 static int get_counter(const char **p)
204 if (!isdigit((int)**p)) {
210 n = 10 * n + (i - '0');
218 static int getlen(const char *p)
227 case 'W': /* word (2 byte) */
230 case 'K': /* status word? (2 byte) */
233 case 'N': /* count of substructures (word) at end */
236 case 'D': /* double word (4 byte) */
237 case 'z': /* offset to zero terminated string (4 byte) */
238 case 'l': /* offset to user data (4 byte) */
241 case 'b': /* offset to data (with counter) (4 byte) */
245 case 'B': /* byte (with optional counter) */
246 n += get_counter(&p);
253 static bool init_package(struct pack_desc *p, int count, int subcount)
258 if (!p->format || !p->base) {
262 i = count * getlen(p->format);
264 i += subcount * getlen(p->subformat);
266 p->structbuf = p->base;
270 p->curpos = p->format;
276 * This is the old error code we used. Aparently
277 * WinNT/2k systems return ERRbuftoosmall (2123) and
278 * OS/2 needs this. I'm leaving this here so we can revert
281 p->errcode = ERRmoredata;
283 p->errcode = ERRbuftoosmall;
286 p->errcode = NERR_Success;
290 p->stringbuf = p->base + i;
292 return (p->errcode == NERR_Success);
295 static int package(struct pack_desc *p, ...)
298 int needed=0, stringneeded;
299 const char *str=NULL;
300 int is_string=0, stringused;
307 p->curpos = p->format;
309 p->curpos = p->subformat;
314 str = va_arg(args,char*);
315 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
324 switch( *p->curpos++ ) {
325 case 'W': /* word (2 byte) */
327 temp = va_arg(args,int);
328 if (p->buflen >= needed) {
329 SSVAL(p->structbuf,0,temp);
332 case 'K': /* status word? (2 byte) */
334 temp = va_arg(args,int);
335 if (p->buflen >= needed) {
336 SSVAL(p->structbuf,0,temp);
339 case 'N': /* count of substructures (word) at end */
341 p->subcount = va_arg(args,int);
342 if (p->buflen >= needed) {
343 SSVAL(p->structbuf,0,p->subcount);
346 case 'D': /* double word (4 byte) */
348 temp = va_arg(args,int);
349 if (p->buflen >= needed) {
350 SIVAL(p->structbuf,0,temp);
353 case 'B': /* byte (with optional counter) */
354 needed = get_counter(&p->curpos);
356 char *s = va_arg(args,char*);
357 if (p->buflen >= needed) {
358 StrnCpy(p->structbuf,s?s:"",needed-1);
362 case 'z': /* offset to zero terminated string (4 byte) */
363 str = va_arg(args,char*);
364 stringneeded = (str ? strlen(str)+1 : 0);
367 case 'l': /* offset to user data (4 byte) */
368 str = va_arg(args,char*);
369 stringneeded = va_arg(args,int);
372 case 'b': /* offset to data (with counter) (4 byte) */
373 str = va_arg(args,char*);
374 stringneeded = get_counter(&p->curpos);
380 if (stringneeded >= 0) {
382 if (p->buflen >= needed) {
383 stringused = stringneeded;
384 if (stringused > p->stringlen) {
385 stringused = (is_string ? p->stringlen : 0);
386 if (p->errcode == NERR_Success) {
387 p->errcode = ERRmoredata;
391 SIVAL(p->structbuf,0,0);
393 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
394 memcpy(p->stringbuf,str?str:"",stringused);
396 p->stringbuf[stringused-1] = '\0';
398 p->stringbuf += stringused;
399 p->stringlen -= stringused;
400 p->usedlen += stringused;
403 p->neededlen += stringneeded;
406 p->neededlen += needed;
407 if (p->buflen >= needed) {
408 p->structbuf += needed;
410 p->usedlen += needed;
412 if (p->errcode == NERR_Success) {
413 p->errcode = ERRmoredata;
420 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
421 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
423 #define PACK(desc,t,v) package(desc,v)
424 #define PACKl(desc,t,v,l) package(desc,v,l)
427 static void PACKI(struct pack_desc* desc, const char *t,int v)
432 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
437 /****************************************************************************
439 ****************************************************************************/
441 static void PackDriverData(struct pack_desc* desc)
443 char drivdata[4+4+32];
444 SIVAL(drivdata,0,sizeof drivdata); /* cb */
445 SIVAL(drivdata,4,1000); /* lVersion */
446 memset(drivdata+8,0,32); /* szDeviceName */
447 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
448 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
451 static int check_printq_info(struct pack_desc* desc,
452 unsigned int uLevel, char *id1, char *id2)
454 desc->subformat = NULL;
457 desc->format = "B13";
460 desc->format = "B13BWWWzzzzzWW";
463 desc->format = "B13BWWWzzzzzWN";
464 desc->subformat = "WB21BB16B10zWWzDDz";
467 desc->format = "zWWWWzzzzWWzzl";
470 desc->format = "zWWWWzzzzWNzzl";
471 desc->subformat = "WWzWWDDzz";
480 desc->format = "WzzzzzzzzN";
481 desc->subformat = "z";
484 DEBUG(0,("check_printq_info: invalid level %d\n",
488 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
489 DEBUG(0,("check_printq_info: invalid format %s\n",
490 id1 ? id1 : "<NULL>" ));
493 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
494 DEBUG(0,("check_printq_info: invalid subformat %s\n",
495 id2 ? id2 : "<NULL>" ));
502 #define RAP_JOB_STATUS_QUEUED 0
503 #define RAP_JOB_STATUS_PAUSED 1
504 #define RAP_JOB_STATUS_SPOOLING 2
505 #define RAP_JOB_STATUS_PRINTING 3
506 #define RAP_JOB_STATUS_PRINTED 4
508 #define RAP_QUEUE_STATUS_PAUSED 1
509 #define RAP_QUEUE_STATUS_ERROR 2
511 /* turn a print job status into a on the wire status
513 static int printj_spoolss_status(int v)
515 if (v == JOB_STATUS_QUEUED)
516 return RAP_JOB_STATUS_QUEUED;
517 if (v & JOB_STATUS_PAUSED)
518 return RAP_JOB_STATUS_PAUSED;
519 if (v & JOB_STATUS_SPOOLING)
520 return RAP_JOB_STATUS_SPOOLING;
521 if (v & JOB_STATUS_PRINTING)
522 return RAP_JOB_STATUS_PRINTING;
526 /* turn a print queue status into a on the wire status
528 static int printq_spoolss_status(int v)
530 if (v == PRINTER_STATUS_OK)
532 if (v & PRINTER_STATUS_PAUSED)
533 return RAP_QUEUE_STATUS_PAUSED;
534 return RAP_QUEUE_STATUS_ERROR;
537 static void fill_spoolss_printjob_info(int uLevel,
538 struct pack_desc *desc,
539 struct spoolss_JobInfo2 *info2,
542 time_t t = spoolss_Time_to_time_t(&info2->submitted);
544 /* the client expects localtime */
545 t -= get_time_zone(t);
547 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
549 PACKS(desc,"B21", info2->user_name); /* szUserName */
550 PACKS(desc,"B",""); /* pad */
551 PACKS(desc,"B16",""); /* szNotifyName */
552 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
553 PACKS(desc,"z",""); /* pszParms */
554 PACKI(desc,"W",n+1); /* uPosition */
555 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
556 PACKS(desc,"z",""); /* pszStatus */
557 PACKI(desc,"D", t); /* ulSubmitted */
558 PACKI(desc,"D", info2->size); /* ulSize */
559 PACKS(desc,"z", info2->document_name); /* pszComment */
561 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
562 PACKI(desc,"W", info2->priority); /* uPriority */
563 PACKS(desc,"z", info2->user_name); /* pszUserName */
564 PACKI(desc,"W",n+1); /* uPosition */
565 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
566 PACKI(desc,"D",t); /* ulSubmitted */
567 PACKI(desc,"D", info2->size); /* ulSize */
568 PACKS(desc,"z","Samba"); /* pszComment */
569 PACKS(desc,"z", info2->document_name); /* pszDocument */
571 PACKS(desc,"z",""); /* pszNotifyName */
572 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
573 PACKS(desc,"z",""); /* pszParms */
574 PACKS(desc,"z",""); /* pszStatus */
575 PACKS(desc,"z", info2->printer_name); /* pszQueue */
576 PACKS(desc,"z","lpd"); /* pszQProcName */
577 PACKS(desc,"z",""); /* pszQProcParms */
578 PACKS(desc,"z","NULL"); /* pszDriverName */
579 PackDriverData(desc); /* pDriverData */
580 PACKS(desc,"z",""); /* pszPrinterName */
581 } else if (uLevel == 4) { /* OS2 */
582 PACKS(desc,"z",""); /* pszSpoolFileName */
583 PACKS(desc,"z",""); /* pszPortName */
584 PACKS(desc,"z",""); /* pszStatus */
585 PACKI(desc,"D",0); /* ulPagesSpooled */
586 PACKI(desc,"D",0); /* ulPagesSent */
587 PACKI(desc,"D",0); /* ulPagesPrinted */
588 PACKI(desc,"D",0); /* ulTimePrinted */
589 PACKI(desc,"D",0); /* ulExtendJobStatus */
590 PACKI(desc,"D",0); /* ulStartPage */
591 PACKI(desc,"D",0); /* ulEndPage */
596 /********************************************************************
597 Respond to the DosPrintQInfo command with a level of 52
598 This is used to get printer driver information for Win9x clients
599 ********************************************************************/
600 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
601 struct pack_desc* desc, int count,
602 const char *printer_name)
606 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
607 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
608 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
610 PACKI(desc, "W", 0x0400); /* don't know */
611 PACKS(desc, "z", driver->driver_name); /* long printer name */
612 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
613 PACKS(desc, "z", driver->data_file); /* Datafile name */
614 PACKS(desc, "z", driver->monitor_name); /* language monitor */
616 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
617 standard_sub_basic( "", "", location, sizeof(location)-1 );
618 PACKS(desc,"z", location); /* share to retrieve files */
620 PACKS(desc,"z", driver->default_datatype); /* default data type */
621 PACKS(desc,"z", driver->help_file); /* helpfile name */
622 PACKS(desc,"z", driver->driver_path); /* driver name */
624 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
625 DEBUG(3,("Driver: %s:\n",driver->driver_path));
626 DEBUG(3,("Data File: %s:\n",driver->data_file));
627 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
628 DEBUG(3,("Driver Location: %s:\n",location));
629 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
630 DEBUG(3,("Help File: %s:\n",driver->help_file));
631 PACKI(desc,"N",count); /* number of files to copy */
633 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
635 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
636 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
637 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
642 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
645 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
647 desc->errcode=NERR_Success;
651 static const char *strip_unc(const char *unc)
659 if ((p = strrchr(unc, '\\')) != NULL) {
666 static void fill_printq_info(int uLevel,
667 struct pack_desc* desc,
669 union spoolss_JobInfo *job_info,
670 struct spoolss_DriverInfo3 *driver_info,
671 struct spoolss_PrinterInfo2 *printer_info)
677 PACKS(desc,"B13", strip_unc(printer_info->printername));
682 PACKS(desc,"z", strip_unc(printer_info->printername));
685 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
689 if (uLevel == 1 || uLevel == 2) {
690 PACKS(desc,"B",""); /* alignment */
691 PACKI(desc,"W",5); /* priority */
692 PACKI(desc,"W",0); /* start time */
693 PACKI(desc,"W",0); /* until time */
694 PACKS(desc,"z",""); /* pSepFile */
695 PACKS(desc,"z","lpd"); /* pPrProc */
696 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
697 PACKS(desc,"z",""); /* pParms */
698 if (printer_info->printername == NULL) {
699 PACKS(desc,"z","UNKNOWN PRINTER");
700 PACKI(desc,"W",LPSTAT_ERROR);
702 PACKS(desc,"z", printer_info->comment);
703 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
705 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
708 if (uLevel == 3 || uLevel == 4) {
709 PACKI(desc,"W",5); /* uPriority */
710 PACKI(desc,"W",0); /* uStarttime */
711 PACKI(desc,"W",0); /* uUntiltime */
712 PACKI(desc,"W",5); /* pad1 */
713 PACKS(desc,"z",""); /* pszSepFile */
714 PACKS(desc,"z","WinPrint"); /* pszPrProc */
715 PACKS(desc,"z",NULL); /* pszParms */
716 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
717 /* "don't ask" that it's done this way to fix corrupted
718 Win9X/ME printer comments. */
719 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
720 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
721 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
722 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
723 PackDriverData(desc); /* pDriverData */
726 if (uLevel == 2 || uLevel == 4) {
728 for (i = 0; i < count; i++) {
729 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
734 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
737 /* This function returns the number of files for a given driver */
738 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
742 /* count the number of files */
743 while (driver->dependent_files && *driver->dependent_files[result])
749 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
750 char *param, int tpscnt,
751 char *data, int tdscnt,
752 int mdrcnt,int mprcnt,
753 char **rdata,char **rparam,
754 int *rdata_len,int *rparam_len)
756 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
757 char *str2 = skip_string(param,tpscnt,str1);
758 char *p = skip_string(param,tpscnt,str2);
763 struct pack_desc desc;
766 WERROR werr = WERR_OK;
767 TALLOC_CTX *mem_ctx = talloc_tos();
769 struct rpc_pipe_client *cli = NULL;
770 struct policy_handle handle;
771 struct spoolss_DevmodeContainer devmode_ctr;
772 union spoolss_DriverInfo driver_info;
773 union spoolss_JobInfo *job_info;
774 union spoolss_PrinterInfo printer_info;
776 if (!str1 || !str2 || !p) {
779 memset((char *)&desc,'\0',sizeof(desc));
781 p = skip_string(param,tpscnt,p);
785 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
786 str3 = get_safe_str_ptr(param,tpscnt,p,4);
787 /* str3 may be null here and is checked in check_printq_info(). */
789 /* remove any trailing username */
790 if ((p = strchr_m(QueueName,'%')))
793 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
795 /* check it's a supported varient */
796 if (!prefix_ok(str1,"zWrLh"))
798 if (!check_printq_info(&desc,uLevel,str2,str3)) {
800 * Patch from Scott Moomaw <scott@bridgewater.edu>
801 * to return the 'invalid info level' error if an
802 * unknown level was requested.
806 *rparam = smb_realloc_limit(*rparam,*rparam_len);
810 SSVALS(*rparam,0,ERRunknownlevel);
818 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
819 rpc_spoolss_dispatch, conn->server_info,
821 if (!NT_STATUS_IS_OK(status)) {
822 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
824 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
828 ZERO_STRUCT(devmode_ctr);
830 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
834 SEC_FLAG_MAXIMUM_ALLOWED,
837 if (!NT_STATUS_IS_OK(status)) {
838 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
841 if (!W_ERROR_IS_OK(werr)) {
842 desc.errcode = W_ERROR_V(werr);
846 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
851 if (!W_ERROR_IS_OK(werr)) {
852 desc.errcode = W_ERROR_V(werr);
857 uint32_t server_major_version;
858 uint32_t server_minor_version;
860 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
868 &server_major_version,
869 &server_minor_version);
870 if (!W_ERROR_IS_OK(werr)) {
871 desc.errcode = W_ERROR_V(werr);
875 count = get_printerdrivernumber(&driver_info.info3);
876 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
879 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
887 if (!W_ERROR_IS_OK(werr)) {
888 desc.errcode = W_ERROR_V(werr);
896 *rdata = smb_realloc_limit(*rdata,mdrcnt);
901 desc.buflen = mdrcnt;
904 * Don't return data but need to get correct length
905 * init_package will return wrong size if buflen=0
907 desc.buflen = getlen(desc.format);
908 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
911 if (init_package(&desc,1,count)) {
912 desc.subcount = count;
913 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
916 *rdata_len = desc.usedlen;
919 * We must set the return code to ERRbuftoosmall
920 * in order to support lanman style printing with Win NT/2k
923 if (!mdrcnt && lp_disable_spoolss())
924 desc.errcode = ERRbuftoosmall;
927 if (cli && is_valid_policy_hnd(&handle)) {
928 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
931 *rdata_len = desc.usedlen;
933 *rparam = smb_realloc_limit(*rparam,*rparam_len);
938 SSVALS(*rparam,0,desc.errcode);
940 SSVAL(*rparam,4,desc.neededlen);
942 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
949 /****************************************************************************
950 View list of all print jobs on all queues.
951 ****************************************************************************/
953 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
954 char *param, int tpscnt,
955 char *data, int tdscnt,
956 int mdrcnt, int mprcnt,
957 char **rdata, char** rparam,
958 int *rdata_len, int *rparam_len)
960 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
961 char *output_format1 = skip_string(param,tpscnt,param_format);
962 char *p = skip_string(param,tpscnt,output_format1);
963 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
964 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
966 struct pack_desc desc;
967 int *subcntarr = NULL;
968 int queuecnt = 0, subcnt = 0, succnt = 0;
970 WERROR werr = WERR_OK;
971 TALLOC_CTX *mem_ctx = talloc_tos();
973 struct rpc_pipe_client *cli = NULL;
974 struct spoolss_DevmodeContainer devmode_ctr;
975 uint32_t num_printers;
976 union spoolss_PrinterInfo *printer_info;
977 union spoolss_DriverInfo *driver_info;
978 union spoolss_JobInfo **job_info;
980 if (!param_format || !output_format1 || !p) {
984 memset((char *)&desc,'\0',sizeof(desc));
986 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
988 if (!prefix_ok(param_format,"WrLeh")) {
991 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
993 * Patch from Scott Moomaw <scott@bridgewater.edu>
994 * to return the 'invalid info level' error if an
995 * unknown level was requested.
999 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1003 SSVALS(*rparam,0,ERRunknownlevel);
1009 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1010 rpc_spoolss_dispatch, conn->server_info,
1012 if (!NT_STATUS_IS_OK(status)) {
1013 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1014 nt_errstr(status)));
1015 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1019 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1021 cli->srv_name_slash,
1026 if (!W_ERROR_IS_OK(werr)) {
1027 desc.errcode = W_ERROR_V(werr);
1031 queuecnt = num_printers;
1033 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1034 if (job_info == NULL) {
1038 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1039 if (driver_info == NULL) {
1043 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1044 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1049 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1055 desc.buflen = mdrcnt;
1058 for (i = 0; i < num_printers; i++) {
1061 struct policy_handle handle;
1062 const char *printername;
1064 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1065 if (printername == NULL) {
1069 ZERO_STRUCT(handle);
1070 ZERO_STRUCT(devmode_ctr);
1072 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1076 SEC_FLAG_MAXIMUM_ALLOWED,
1079 if (!NT_STATUS_IS_OK(status)) {
1080 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1083 if (!W_ERROR_IS_OK(werr)) {
1084 desc.errcode = W_ERROR_V(werr);
1088 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1096 if (!W_ERROR_IS_OK(werr)) {
1097 desc.errcode = W_ERROR_V(werr);
1102 uint32_t server_major_version;
1103 uint32_t server_minor_version;
1105 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1113 &server_major_version,
1114 &server_minor_version);
1115 if (!W_ERROR_IS_OK(werr)) {
1116 desc.errcode = W_ERROR_V(werr);
1121 subcntarr[i] = num_jobs;
1122 subcnt += subcntarr[i];
1124 if (cli && is_valid_policy_hnd(&handle)) {
1125 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1129 if (init_package(&desc,queuecnt,subcnt)) {
1130 for (i = 0; i < num_printers; i++) {
1131 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1132 if (desc.errcode == NERR_Success) {
1138 SAFE_FREE(subcntarr);
1140 *rdata_len = desc.usedlen;
1142 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1146 SSVALS(*rparam,0,desc.errcode);
1148 SSVAL(*rparam,4,succnt);
1149 SSVAL(*rparam,6,queuecnt);
1155 SAFE_FREE(subcntarr);
1160 /****************************************************************************
1161 Get info level for a server list query.
1162 ****************************************************************************/
1164 static bool check_server_info(int uLevel, char* id)
1168 if (strcmp(id,"B16") != 0) {
1173 if (strcmp(id,"B16BBDz") != 0) {
1183 struct srv_info_struct {
1191 /*******************************************************************
1192 Get server info lists from the files saved by nmbd. Return the
1194 ******************************************************************/
1196 static int get_server_info(uint32 servertype,
1197 struct srv_info_struct **servers,
1203 bool local_list_only;
1206 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1208 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1212 /* request for everything is code for request all servers */
1213 if (servertype == SV_TYPE_ALL) {
1214 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1217 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1219 DEBUG(4,("Servertype search: %8x\n",servertype));
1221 for (i=0;lines[i];i++) {
1223 struct srv_info_struct *s;
1224 const char *ptr = lines[i];
1226 TALLOC_CTX *frame = NULL;
1233 if (count == alloced) {
1235 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1237 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1241 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1243 s = &(*servers)[count];
1245 frame = talloc_stackframe();
1247 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1251 fstrcpy(s->name, p);
1254 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1260 s->comment[0] = '\0';
1261 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1265 fstrcpy(s->comment, p);
1266 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1268 s->domain[0] = '\0';
1269 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1270 /* this allows us to cope with an old nmbd */
1271 fstrcpy(s->domain,lp_workgroup());
1273 fstrcpy(s->domain, p);
1277 if (sscanf(stype,"%X",&s->type) != 1) {
1278 DEBUG(4,("r:host file "));
1282 /* Filter the servers/domains we return based on what was asked for. */
1284 /* Check to see if we are being asked for a local list only. */
1285 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1286 DEBUG(4,("r: local list only"));
1290 /* doesn't match up: don't want it */
1291 if (!(servertype & s->type)) {
1292 DEBUG(4,("r:serv type "));
1296 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1297 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1298 DEBUG(4,("s: dom mismatch "));
1302 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1306 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1307 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1310 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1311 s->name, s->type, s->comment, s->domain));
1312 s->server_added = True;
1315 DEBUG(4,("%20s %8x %25s %15s\n",
1316 s->name, s->type, s->comment, s->domain));
1324 /*******************************************************************
1325 Fill in a server info structure.
1326 ******************************************************************/
1328 static int fill_srv_info(struct srv_info_struct *service,
1329 int uLevel, char **buf, int *buflen,
1330 char **stringbuf, int *stringspace, char *baseaddr)
1353 len = strlen(service->comment)+1;
1357 *buflen = struct_len;
1359 return struct_len + len;
1364 if (*buflen < struct_len) {
1371 p2 = p + struct_len;
1372 l2 = *buflen - struct_len;
1380 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1384 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1385 SIVAL(p,18,service->type);
1386 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1387 len += CopyAndAdvance(&p2,service->comment,&l2);
1392 *buf = p + struct_len;
1393 *buflen -= struct_len;
1404 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1406 return StrCaseCmp(s1->name,s2->name);
1409 /****************************************************************************
1410 View list of servers available (or possibly domains). The info is
1411 extracted from lists saved by nmbd on the local host.
1412 ****************************************************************************/
1414 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1415 char *param, int tpscnt,
1416 char *data, int tdscnt,
1417 int mdrcnt, int mprcnt, char **rdata,
1418 char **rparam, int *rdata_len, int *rparam_len)
1420 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1421 char *str2 = skip_string(param,tpscnt,str1);
1422 char *p = skip_string(param,tpscnt,str2);
1423 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1424 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1425 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1427 int data_len, fixed_len, string_len;
1428 int f_len = 0, s_len = 0;
1429 struct srv_info_struct *servers=NULL;
1430 int counted=0,total=0;
1433 bool domain_request;
1436 if (!str1 || !str2 || !p) {
1440 /* If someone sets all the bits they don't really mean to set
1441 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1444 if (servertype == SV_TYPE_ALL) {
1445 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1448 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1449 any other bit (they may just set this bit on its own) they
1450 want all the locally seen servers. However this bit can be
1451 set on its own so set the requested servers to be
1452 ALL - DOMAIN_ENUM. */
1454 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1455 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1458 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1459 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1463 if (!prefix_ok(str1,"WrLehD")) {
1466 if (!check_server_info(uLevel,str2)) {
1470 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1471 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1472 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1474 if (strcmp(str1, "WrLehDz") == 0) {
1475 if (skip_string(param,tpscnt,p) == NULL) {
1478 pull_ascii_fstring(domain, p);
1480 fstrcpy(domain, lp_workgroup());
1483 DEBUG(4, ("domain [%s]\n", domain));
1485 if (lp_browse_list()) {
1486 total = get_server_info(servertype,&servers,domain);
1489 data_len = fixed_len = string_len = 0;
1492 TYPESAFE_QSORT(servers, total, srv_comp);
1495 char *lastname=NULL;
1497 for (i=0;i<total;i++) {
1498 struct srv_info_struct *s = &servers[i];
1500 if (lastname && strequal(lastname,s->name)) {
1504 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1505 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1506 i, s->name, s->type, s->comment, s->domain));
1508 if (data_len < buf_len) {
1511 string_len += s_len;
1518 *rdata_len = fixed_len + string_len;
1519 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1524 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1530 char *lastname=NULL;
1531 int count2 = counted;
1533 for (i = 0; i < total && count2;i++) {
1534 struct srv_info_struct *s = &servers[i];
1536 if (lastname && strequal(lastname,s->name)) {
1540 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1541 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1542 i, s->name, s->type, s->comment, s->domain));
1548 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1552 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1554 SSVAL(*rparam,4,counted);
1555 SSVAL(*rparam,6,counted+missed);
1559 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1560 domain,uLevel,counted,counted+missed));
1565 static int srv_name_match(const char *n1, const char *n2)
1568 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1570 * In Windows, FirstNameToReturn need not be an exact match:
1571 * the server will return a list of servers that exist on
1572 * the network greater than or equal to the FirstNameToReturn.
1574 int ret = StrCaseCmp(n1, n2);
1583 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1584 char *param, int tpscnt,
1585 char *data, int tdscnt,
1586 int mdrcnt, int mprcnt, char **rdata,
1587 char **rparam, int *rdata_len, int *rparam_len)
1589 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1590 char *str2 = skip_string(param,tpscnt,str1);
1591 char *p = skip_string(param,tpscnt,str2);
1592 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1593 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1594 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1596 int data_len, fixed_len, string_len;
1597 int f_len = 0, s_len = 0;
1598 struct srv_info_struct *servers=NULL;
1599 int counted=0,first=0,total=0;
1603 bool domain_request;
1606 if (!str1 || !str2 || !p) {
1610 /* If someone sets all the bits they don't really mean to set
1611 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1614 if (servertype == SV_TYPE_ALL) {
1615 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1618 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1619 any other bit (they may just set this bit on its own) they
1620 want all the locally seen servers. However this bit can be
1621 set on its own so set the requested servers to be
1622 ALL - DOMAIN_ENUM. */
1624 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1625 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1628 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1629 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1633 if (strcmp(str1, "WrLehDzz") != 0) {
1636 if (!check_server_info(uLevel,str2)) {
1640 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1641 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1642 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1644 if (skip_string(param,tpscnt,p) == NULL) {
1647 pull_ascii_fstring(domain, p);
1648 if (domain[0] == '\0') {
1649 fstrcpy(domain, lp_workgroup());
1651 p = skip_string(param,tpscnt,p);
1652 if (skip_string(param,tpscnt,p) == NULL) {
1655 pull_ascii_fstring(first_name, p);
1657 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1658 domain, first_name));
1660 if (lp_browse_list()) {
1661 total = get_server_info(servertype,&servers,domain);
1664 data_len = fixed_len = string_len = 0;
1667 TYPESAFE_QSORT(servers, total, srv_comp);
1669 if (first_name[0] != '\0') {
1670 struct srv_info_struct *first_server = NULL;
1672 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1673 srv_name_match, first_server);
1675 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1677 * The binary search may not find the exact match
1678 * so we need to search backward to find the first match
1680 * This implements the strange matching windows
1681 * implements. (see the comment in srv_name_match().
1685 ret = StrCaseCmp(first_name,
1686 servers[first-1].name);
1693 /* we should return no entries */
1699 char *lastname=NULL;
1701 for (i=first;i<total;i++) {
1702 struct srv_info_struct *s = &servers[i];
1704 if (lastname && strequal(lastname,s->name)) {
1708 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1709 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1710 i, s->name, s->type, s->comment, s->domain));
1712 if (data_len < buf_len) {
1715 string_len += s_len;
1722 *rdata_len = fixed_len + string_len;
1723 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1728 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1734 char *lastname=NULL;
1735 int count2 = counted;
1737 for (i = first; i < total && count2;i++) {
1738 struct srv_info_struct *s = &servers[i];
1740 if (lastname && strequal(lastname,s->name)) {
1744 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1745 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1746 i, s->name, s->type, s->comment, s->domain));
1752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1756 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1758 SSVAL(*rparam,4,counted);
1759 SSVAL(*rparam,6,counted+missed);
1761 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1762 domain,uLevel,first,first_name,
1763 first < total ? servers[first].name : "",
1764 counted,counted+missed));
1771 /****************************************************************************
1772 command 0x34 - suspected of being a "Lookup Names" stub api
1773 ****************************************************************************/
1775 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1776 char *param, int tpscnt,
1777 char *data, int tdscnt,
1778 int mdrcnt, int mprcnt, char **rdata,
1779 char **rparam, int *rdata_len, int *rparam_len)
1781 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1782 char *str2 = skip_string(param,tpscnt,str1);
1783 char *p = skip_string(param,tpscnt,str2);
1784 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1785 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1789 if (!str1 || !str2 || !p) {
1793 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1794 str1, str2, p, uLevel, buf_len));
1796 if (!prefix_ok(str1,"zWrLeh")) {
1803 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1808 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1810 SSVAL(*rparam,4,counted);
1811 SSVAL(*rparam,6,counted+missed);
1816 /****************************************************************************
1817 get info about a share
1818 ****************************************************************************/
1820 static bool check_share_info(int uLevel, char* id)
1824 if (strcmp(id,"B13") != 0) {
1829 /* Level-2 descriptor is allowed (and ignored) */
1830 if (strcmp(id,"B13BWz") != 0 &&
1831 strcmp(id,"B13BWzWWWzB9B") != 0) {
1836 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1841 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1851 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1852 char** buf, int* buflen,
1853 char** stringbuf, int* stringspace, char* baseaddr)
1882 len += StrlenExpanded(conn,snum,lp_comment(snum));
1885 len += strlen(lp_pathname(snum)) + 1;
1888 *buflen = struct_len;
1893 return struct_len + len;
1898 if ((*buflen) < struct_len) {
1906 p2 = p + struct_len;
1907 l2 = (*buflen) - struct_len;
1914 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1920 type = STYPE_DISKTREE;
1921 if (lp_print_ok(snum)) {
1922 type = STYPE_PRINTQ;
1924 if (strequal("IPC",lp_fstype(snum))) {
1927 SSVAL(p,14,type); /* device type */
1928 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1929 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1933 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1934 SSVALS(p,22,-1); /* max uses */
1935 SSVAL(p,24,1); /* current uses */
1936 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1937 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1938 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1942 memset(p+40,0,SHPWLEN+2);
1953 (*buf) = p + struct_len;
1954 (*buflen) -= struct_len;
1956 (*stringspace) = l2;
1965 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1966 char *param, int tpscnt,
1967 char *data, int tdscnt,
1968 int mdrcnt,int mprcnt,
1969 char **rdata,char **rparam,
1970 int *rdata_len,int *rparam_len)
1972 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1973 char *str2 = skip_string(param,tpscnt,str1);
1974 char *netname = skip_string(param,tpscnt,str2);
1975 char *p = skip_string(param,tpscnt,netname);
1976 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1979 if (!str1 || !str2 || !netname || !p) {
1983 snum = find_service(netname);
1988 /* check it's a supported varient */
1989 if (!prefix_ok(str1,"zWrLh")) {
1992 if (!check_share_info(uLevel,str2)) {
1996 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2001 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2002 if (*rdata_len < 0) {
2007 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2011 SSVAL(*rparam,0,NERR_Success);
2012 SSVAL(*rparam,2,0); /* converter word */
2013 SSVAL(*rparam,4,*rdata_len);
2018 /****************************************************************************
2019 View the list of available shares.
2021 This function is the server side of the NetShareEnum() RAP call.
2022 It fills the return buffer with share names and share comments.
2023 Note that the return buffer normally (in all known cases) allows only
2024 twelve byte strings for share names (plus one for a nul terminator).
2025 Share names longer than 12 bytes must be skipped.
2026 ****************************************************************************/
2028 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2029 char *param, int tpscnt,
2030 char *data, int tdscnt,
2038 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2039 char *str2 = skip_string(param,tpscnt,str1);
2040 char *p = skip_string(param,tpscnt,str2);
2041 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2042 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2045 int total=0,counted=0;
2046 bool missed = False;
2048 int data_len, fixed_len, string_len;
2049 int f_len = 0, s_len = 0;
2051 if (!str1 || !str2 || !p) {
2055 if (!prefix_ok(str1,"WrLeh")) {
2058 if (!check_share_info(uLevel,str2)) {
2062 /* Ensure all the usershares are loaded. */
2064 load_registry_shares();
2065 count = load_usershare_shares();
2068 data_len = fixed_len = string_len = 0;
2069 for (i=0;i<count;i++) {
2070 fstring servicename_dos;
2071 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2074 push_ascii_fstring(servicename_dos, lp_servicename(i));
2075 /* Maximum name length = 13. */
2076 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2078 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2079 if (data_len < buf_len) {
2082 string_len += s_len;
2089 *rdata_len = fixed_len + string_len;
2090 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2095 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2100 for( i = 0; i < count; i++ ) {
2101 fstring servicename_dos;
2102 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2106 push_ascii_fstring(servicename_dos, lp_servicename(i));
2107 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2108 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2115 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2119 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2121 SSVAL(*rparam,4,counted);
2122 SSVAL(*rparam,6,total);
2124 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2125 counted,total,uLevel,
2126 buf_len,*rdata_len,mdrcnt));
2131 /****************************************************************************
2133 ****************************************************************************/
2135 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2136 char *param, int tpscnt,
2137 char *data, int tdscnt,
2138 int mdrcnt,int mprcnt,
2139 char **rdata,char **rparam,
2140 int *rdata_len,int *rparam_len)
2142 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2143 char *str2 = skip_string(param,tpscnt,str1);
2144 char *p = skip_string(param,tpscnt,str2);
2145 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2148 char *pathname = NULL;
2149 unsigned int offset;
2151 size_t converted_size;
2153 WERROR werr = WERR_OK;
2154 TALLOC_CTX *mem_ctx = talloc_tos();
2156 struct rpc_pipe_client *cli = NULL;
2157 union srvsvc_NetShareInfo info;
2158 struct srvsvc_NetShareInfo2 info2;
2160 if (!str1 || !str2 || !p) {
2164 /* check it's a supported varient */
2165 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2168 if (!check_share_info(uLevel,str2)) {
2175 /* Do we have a string ? */
2176 if (skip_string(data,mdrcnt,data) == NULL) {
2179 pull_ascii_fstring(sharename,data);
2185 /* only support disk share adds */
2186 if (SVAL(data,14)!=STYPE_DISKTREE) {
2190 offset = IVAL(data, 16);
2191 if (offset >= mdrcnt) {
2192 res = ERRinvalidparam;
2196 /* Do we have a string ? */
2197 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2200 pull_ascii_fstring(comment, offset? (data+offset) : "");
2202 offset = IVAL(data, 26);
2204 if (offset >= mdrcnt) {
2205 res = ERRinvalidparam;
2209 /* Do we have a string ? */
2210 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2214 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2215 offset ? (data+offset) : "", &converted_size))
2217 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2225 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2226 rpc_srvsvc_dispatch, conn->server_info,
2228 if (!NT_STATUS_IS_OK(status)) {
2229 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2230 nt_errstr(status)));
2231 res = W_ERROR_V(ntstatus_to_werror(status));
2235 info2.name = sharename;
2236 info2.type = STYPE_DISKTREE;
2237 info2.comment = comment;
2238 info2.permissions = 0;
2239 info2.max_users = 0;
2240 info2.current_users = 0;
2241 info2.path = pathname;
2242 info2.password = NULL;
2244 info.info2 = &info2;
2246 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2247 cli->srv_name_slash,
2252 if (!NT_STATUS_IS_OK(status)) {
2253 res = W_ERROR_V(ntstatus_to_werror(status));
2256 if (!W_ERROR_IS_OK(werr)) {
2257 res = W_ERROR_V(werr);
2262 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2266 SSVAL(*rparam,0,NERR_Success);
2267 SSVAL(*rparam,2,0); /* converter word */
2268 SSVAL(*rparam,4,*rdata_len);
2276 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2281 SSVAL(*rparam,0,res);
2286 /****************************************************************************
2287 view list of groups available
2288 ****************************************************************************/
2290 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2291 char *param, int tpscnt,
2292 char *data, int tdscnt,
2293 int mdrcnt,int mprcnt,
2294 char **rdata,char **rparam,
2295 int *rdata_len,int *rparam_len)
2299 int resume_context, cli_buf_size;
2300 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2301 char *str2 = skip_string(param,tpscnt,str1);
2302 char *p = skip_string(param,tpscnt,str2);
2304 uint32_t num_groups;
2305 uint32_t resume_handle;
2306 struct rpc_pipe_client *samr_pipe;
2307 struct policy_handle samr_handle, domain_handle;
2310 if (!str1 || !str2 || !p) {
2314 if (strcmp(str1,"WrLeh") != 0) {
2319 * W-> resume context (number of users to skip)
2320 * r -> return parameter pointer to receive buffer
2321 * L -> length of receive buffer
2322 * e -> return parameter number of entries
2323 * h -> return parameter total number of users
2326 if (strcmp("B21",str2) != 0) {
2330 status = rpc_pipe_open_internal(
2331 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2332 conn->server_info, &samr_pipe);
2333 if (!NT_STATUS_IS_OK(status)) {
2334 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2335 nt_errstr(status)));
2339 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2340 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2341 if (!NT_STATUS_IS_OK(status)) {
2342 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2343 nt_errstr(status)));
2347 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2348 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2349 get_global_sam_sid(), &domain_handle);
2350 if (!NT_STATUS_IS_OK(status)) {
2351 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2352 nt_errstr(status)));
2353 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2357 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2358 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2359 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2360 "%d\n", resume_context, cli_buf_size));
2362 *rdata_len = cli_buf_size;
2363 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2370 errflags = NERR_Success;
2375 struct samr_SamArray *sam_entries;
2376 uint32_t num_entries;
2378 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2383 if (!NT_STATUS_IS_OK(status)) {
2384 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2385 "%s\n", nt_errstr(status)));
2389 if (num_entries == 0) {
2390 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2391 "no entries -- done\n"));
2395 for(i=0; i<num_entries; i++) {
2398 name = sam_entries->entries[i].name.string;
2400 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2401 /* set overflow error */
2402 DEBUG(3,("overflow on entry %d group %s\n", i,
2408 /* truncate the name at 21 chars. */
2410 strlcpy(p, name, 21);
2411 DEBUG(10,("adding entry %d group %s\n", i, p));
2413 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2418 if (errflags != NERR_Success) {
2422 TALLOC_FREE(sam_entries);
2425 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2426 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2428 *rdata_len = PTR_DIFF(p,*rdata);
2431 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2435 SSVAL(*rparam, 0, errflags);
2436 SSVAL(*rparam, 2, 0); /* converter word */
2437 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2438 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2443 /*******************************************************************
2444 Get groups that a user is a member of.
2445 ******************************************************************/
2447 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2448 char *param, int tpscnt,
2449 char *data, int tdscnt,
2450 int mdrcnt,int mprcnt,
2451 char **rdata,char **rparam,
2452 int *rdata_len,int *rparam_len)
2454 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2455 char *str2 = skip_string(param,tpscnt,str1);
2456 char *UserName = skip_string(param,tpscnt,str2);
2457 char *p = skip_string(param,tpscnt,UserName);
2458 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2459 const char *level_string;
2465 struct rpc_pipe_client *samr_pipe;
2466 struct policy_handle samr_handle, domain_handle, user_handle;
2467 struct lsa_String name;
2468 struct lsa_Strings names;
2469 struct samr_Ids type, rid;
2470 struct samr_RidWithAttributeArray *rids;
2473 if (!str1 || !str2 || !UserName || !p) {
2478 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2483 /* check it's a supported varient */
2485 if ( strcmp(str1,"zWrLeh") != 0 )
2490 level_string = "B21";
2496 if (strcmp(level_string,str2) != 0)
2499 *rdata_len = mdrcnt + 1024;
2500 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2505 SSVAL(*rparam,0,NERR_Success);
2506 SSVAL(*rparam,2,0); /* converter word */
2509 endp = *rdata + *rdata_len;
2511 status = rpc_pipe_open_internal(
2512 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2513 conn->server_info, &samr_pipe);
2514 if (!NT_STATUS_IS_OK(status)) {
2515 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2516 nt_errstr(status)));
2520 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2521 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2522 if (!NT_STATUS_IS_OK(status)) {
2523 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2524 nt_errstr(status)));
2528 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2529 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2530 get_global_sam_sid(), &domain_handle);
2531 if (!NT_STATUS_IS_OK(status)) {
2532 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2533 nt_errstr(status)));
2537 name.string = UserName;
2539 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2540 &domain_handle, 1, &name,
2542 if (!NT_STATUS_IS_OK(status)) {
2543 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2544 nt_errstr(status)));
2548 if (type.ids[0] != SID_NAME_USER) {
2549 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2550 sid_type_lookup(type.ids[0])));
2554 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2556 SAMR_USER_ACCESS_GET_GROUPS,
2557 rid.ids[0], &user_handle);
2558 if (!NT_STATUS_IS_OK(status)) {
2559 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2560 nt_errstr(status)));
2564 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2565 &user_handle, &rids);
2566 if (!NT_STATUS_IS_OK(status)) {
2567 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2568 nt_errstr(status)));
2572 for (i=0; i<rids->count; i++) {
2574 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2576 1, &rids->rids[i].rid,
2578 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2579 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2585 *rdata_len = PTR_DIFF(p,*rdata);
2587 SSVAL(*rparam,4,count); /* is this right?? */
2588 SSVAL(*rparam,6,count); /* is this right?? */
2593 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2595 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2597 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2602 /*******************************************************************
2604 ******************************************************************/
2606 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2607 char *param, int tpscnt,
2608 char *data, int tdscnt,
2609 int mdrcnt,int mprcnt,
2610 char **rdata,char **rparam,
2611 int *rdata_len,int *rparam_len)
2616 int i, resume_context, cli_buf_size;
2617 uint32_t resume_handle;
2619 struct rpc_pipe_client *samr_pipe;
2620 struct policy_handle samr_handle, domain_handle;
2623 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2624 char *str2 = skip_string(param,tpscnt,str1);
2625 char *p = skip_string(param,tpscnt,str2);
2628 if (!str1 || !str2 || !p) {
2632 if (strcmp(str1,"WrLeh") != 0)
2635 * W-> resume context (number of users to skip)
2636 * r -> return parameter pointer to receive buffer
2637 * L -> length of receive buffer
2638 * e -> return parameter number of entries
2639 * h -> return parameter total number of users
2642 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2643 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2644 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2645 resume_context, cli_buf_size));
2648 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2653 /* check it's a supported varient */
2654 if (strcmp("B21",str2) != 0)
2657 *rdata_len = cli_buf_size;
2658 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2664 endp = *rdata + *rdata_len;
2666 status = rpc_pipe_open_internal(
2667 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2668 conn->server_info, &samr_pipe);
2669 if (!NT_STATUS_IS_OK(status)) {
2670 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2671 nt_errstr(status)));
2675 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2676 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2677 if (!NT_STATUS_IS_OK(status)) {
2678 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2679 nt_errstr(status)));
2683 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2684 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2685 get_global_sam_sid(), &domain_handle);
2686 if (!NT_STATUS_IS_OK(status)) {
2687 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2688 nt_errstr(status)));
2689 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2693 errflags=NERR_Success;
2698 struct samr_SamArray *sam_entries;
2699 uint32_t num_entries;
2701 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2707 if (!NT_STATUS_IS_OK(status)) {
2708 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2709 "%s\n", nt_errstr(status)));
2713 if (num_entries == 0) {
2714 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2715 "no entries -- done\n"));
2719 for (i=0; i<num_entries; i++) {
2722 name = sam_entries->entries[i].name.string;
2724 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2725 &&(strlen(name)<=21)) {
2726 strlcpy(p,name,PTR_DIFF(endp,p));
2727 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2728 "username %s\n",count_sent,p));
2732 /* set overflow error */
2733 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2734 "username %s\n",count_sent,name));
2740 if (errflags != NERR_Success) {
2744 TALLOC_FREE(sam_entries);
2747 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2748 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2750 *rdata_len = PTR_DIFF(p,*rdata);
2752 SSVAL(*rparam,0,errflags);
2753 SSVAL(*rparam,2,0); /* converter word */
2754 SSVAL(*rparam,4,count_sent); /* is this right?? */
2755 SSVAL(*rparam,6,num_users); /* is this right?? */
2760 /****************************************************************************
2761 Get the time of day info.
2762 ****************************************************************************/
2764 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2765 char *param, int tpscnt,
2766 char *data, int tdscnt,
2767 int mdrcnt,int mprcnt,
2768 char **rdata,char **rparam,
2769 int *rdata_len,int *rparam_len)
2772 time_t unixdate = time(NULL);
2776 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2782 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2787 SSVAL(*rparam,0,NERR_Success);
2788 SSVAL(*rparam,2,0); /* converter word */
2792 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2793 by NT in a "net time" operation,
2794 it seems to ignore the one below */
2796 /* the client expects to get localtime, not GMT, in this bit
2797 (I think, this needs testing) */
2798 t = localtime(&unixdate);
2803 SIVAL(p,4,0); /* msecs ? */
2804 SCVAL(p,8,t->tm_hour);
2805 SCVAL(p,9,t->tm_min);
2806 SCVAL(p,10,t->tm_sec);
2807 SCVAL(p,11,0); /* hundredths of seconds */
2808 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2809 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2810 SCVAL(p,16,t->tm_mday);
2811 SCVAL(p,17,t->tm_mon + 1);
2812 SSVAL(p,18,1900+t->tm_year);
2813 SCVAL(p,20,t->tm_wday);
2818 /****************************************************************************
2819 Set the user password.
2820 *****************************************************************************/
2822 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2823 char *param, int tpscnt,
2824 char *data, int tdscnt,
2825 int mdrcnt,int mprcnt,
2826 char **rdata,char **rparam,
2827 int *rdata_len,int *rparam_len)
2829 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2832 fstring pass1,pass2;
2834 /* Skip 2 strings. */
2835 p = skip_string(param,tpscnt,np);
2836 p = skip_string(param,tpscnt,p);
2842 /* Do we have a string ? */
2843 if (skip_string(param,tpscnt,p) == NULL) {
2846 pull_ascii_fstring(user,p);
2848 p = skip_string(param,tpscnt,p);
2853 memset(pass1,'\0',sizeof(pass1));
2854 memset(pass2,'\0',sizeof(pass2));
2856 * We use 31 here not 32 as we're checking
2857 * the last byte we want to access is safe.
2859 if (!is_offset_safe(param,tpscnt,p,31)) {
2863 memcpy(pass2,p+16,16);
2866 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2873 SSVAL(*rparam,0,NERR_badpass);
2874 SSVAL(*rparam,2,0); /* converter word */
2876 DEBUG(3,("Set password for <%s>\n",user));
2879 * Attempt to verify the old password against smbpasswd entries
2880 * Win98 clients send old and new password in plaintext for this call.
2884 struct auth_serversupplied_info *server_info = NULL;
2885 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2887 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2890 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2891 SSVAL(*rparam,0,NERR_Success);
2895 TALLOC_FREE(server_info);
2897 data_blob_clear_free(&password);
2901 * If the plaintext change failed, attempt
2902 * the old encrypted method. NT will generate this
2903 * after trying the samr method. Note that this
2904 * method is done as a last resort as this
2905 * password change method loses the NT password hash
2906 * and cannot change the UNIX password as no plaintext
2910 if(SVAL(*rparam,0) != NERR_Success) {
2911 struct samu *hnd = NULL;
2913 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2915 if (change_lanman_password(hnd,(uchar *)pass2)) {
2916 SSVAL(*rparam,0,NERR_Success);
2923 memset((char *)pass1,'\0',sizeof(fstring));
2924 memset((char *)pass2,'\0',sizeof(fstring));
2929 /****************************************************************************
2930 Set the user password (SamOEM version - gets plaintext).
2931 ****************************************************************************/
2933 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2934 char *param, int tpscnt,
2935 char *data, int tdscnt,
2936 int mdrcnt,int mprcnt,
2937 char **rdata,char **rparam,
2938 int *rdata_len,int *rparam_len)
2941 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2943 TALLOC_CTX *mem_ctx = talloc_tos();
2945 struct rpc_pipe_client *cli = NULL;
2946 struct lsa_AsciiString server, account;
2947 struct samr_CryptPassword password;
2948 struct samr_Password hash;
2949 int errcode = NERR_badpass;
2953 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2963 SSVAL(*rparam,0,NERR_badpass);
2966 * Check the parameter definition is correct.
2969 /* Do we have a string ? */
2970 if (skip_string(param,tpscnt,p) == 0) {
2973 if(!strequal(p, "zsT")) {
2974 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2977 p = skip_string(param, tpscnt, p);
2982 /* Do we have a string ? */
2983 if (skip_string(param,tpscnt,p) == 0) {
2986 if(!strequal(p, "B516B16")) {
2987 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2990 p = skip_string(param,tpscnt,p);
2994 /* Do we have a string ? */
2995 if (skip_string(param,tpscnt,p) == 0) {
2998 p += pull_ascii_fstring(user,p);
3000 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3002 if (tdscnt != 532) {
3003 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3007 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3008 if (bufsize != 532) {
3009 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3013 memcpy(password.data, data, 516);
3014 memcpy(hash.hash, data+516, 16);
3016 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3017 rpc_samr_dispatch, conn->server_info,
3019 if (!NT_STATUS_IS_OK(status)) {
3020 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3021 nt_errstr(status)));
3022 errcode = W_ERROR_V(ntstatus_to_werror(status));
3026 init_lsa_AsciiString(&server, global_myname());
3027 init_lsa_AsciiString(&account, user);
3029 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3034 if (!NT_STATUS_IS_OK(status)) {
3035 errcode = W_ERROR_V(ntstatus_to_werror(status));
3039 errcode = NERR_Success;
3041 SSVAL(*rparam,0,errcode);
3042 SSVAL(*rparam,2,0); /* converter word */
3047 /****************************************************************************
3050 ****************************************************************************/
3052 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3053 char *param, int tpscnt,
3054 char *data, int tdscnt,
3055 int mdrcnt,int mprcnt,
3056 char **rdata,char **rparam,
3057 int *rdata_len,int *rparam_len)
3059 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3060 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3061 char *str2 = skip_string(param,tpscnt,str1);
3062 char *p = skip_string(param,tpscnt,str2);
3066 WERROR werr = WERR_OK;
3068 TALLOC_CTX *mem_ctx = talloc_tos();
3070 struct rpc_pipe_client *cli = NULL;
3071 struct policy_handle handle;
3072 struct spoolss_DevmodeContainer devmode_ctr;
3073 enum spoolss_JobControl command;
3075 if (!str1 || !str2 || !p) {
3079 * We use 1 here not 2 as we're checking
3080 * the last byte we want to access is safe.
3082 if (!is_offset_safe(param,tpscnt,p,1)) {
3085 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3088 /* check it's a supported varient */
3089 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3093 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3099 ZERO_STRUCT(handle);
3101 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3102 rpc_spoolss_dispatch, conn->server_info,
3104 if (!NT_STATUS_IS_OK(status)) {
3105 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3106 nt_errstr(status)));
3107 errcode = W_ERROR_V(ntstatus_to_werror(status));
3111 ZERO_STRUCT(devmode_ctr);
3113 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3117 SEC_FLAG_MAXIMUM_ALLOWED,
3120 if (!NT_STATUS_IS_OK(status)) {
3121 errcode = W_ERROR_V(ntstatus_to_werror(status));
3124 if (!W_ERROR_IS_OK(werr)) {
3125 errcode = W_ERROR_V(werr);
3129 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3130 * and NERR_DestNotFound if share did not exist */
3132 errcode = NERR_Success;
3135 case 81: /* delete */
3136 command = SPOOLSS_JOB_CONTROL_DELETE;
3138 case 82: /* pause */
3139 command = SPOOLSS_JOB_CONTROL_PAUSE;
3141 case 83: /* resume */
3142 command = SPOOLSS_JOB_CONTROL_RESUME;
3145 errcode = NERR_notsupported;
3149 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3152 NULL, /* unique ptr ctr */
3155 if (!NT_STATUS_IS_OK(status)) {
3156 errcode = W_ERROR_V(ntstatus_to_werror(status));
3159 if (!W_ERROR_IS_OK(werr)) {
3160 errcode = W_ERROR_V(werr);
3165 if (cli && is_valid_policy_hnd(&handle)) {
3166 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3169 SSVAL(*rparam,0,errcode);
3170 SSVAL(*rparam,2,0); /* converter word */
3175 /****************************************************************************
3176 Purge a print queue - or pause or resume it.
3177 ****************************************************************************/
3179 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3180 char *param, int tpscnt,
3181 char *data, int tdscnt,
3182 int mdrcnt,int mprcnt,
3183 char **rdata,char **rparam,
3184 int *rdata_len,int *rparam_len)
3186 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3187 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3188 char *str2 = skip_string(param,tpscnt,str1);
3189 char *QueueName = skip_string(param,tpscnt,str2);
3190 int errcode = NERR_notsupported;
3191 WERROR werr = WERR_OK;
3194 TALLOC_CTX *mem_ctx = talloc_tos();
3195 struct rpc_pipe_client *cli = NULL;
3196 struct policy_handle handle;
3197 struct spoolss_SetPrinterInfoCtr info_ctr;
3198 struct spoolss_DevmodeContainer devmode_ctr;
3199 struct sec_desc_buf secdesc_ctr;
3200 enum spoolss_PrinterControl command;
3202 if (!str1 || !str2 || !QueueName) {
3206 /* check it's a supported varient */
3207 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3211 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3217 if (skip_string(param,tpscnt,QueueName) == NULL) {
3221 ZERO_STRUCT(handle);
3223 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3224 rpc_spoolss_dispatch, conn->server_info,
3226 if (!NT_STATUS_IS_OK(status)) {
3227 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3228 nt_errstr(status)));
3229 errcode = W_ERROR_V(ntstatus_to_werror(status));
3233 ZERO_STRUCT(devmode_ctr);
3235 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3239 SEC_FLAG_MAXIMUM_ALLOWED,
3242 if (!NT_STATUS_IS_OK(status)) {
3243 errcode = W_ERROR_V(ntstatus_to_werror(status));
3246 if (!W_ERROR_IS_OK(werr)) {
3247 errcode = W_ERROR_V(werr);
3252 case 74: /* Pause queue */
3253 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3255 case 75: /* Resume queue */
3256 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3258 case 103: /* Purge */
3259 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3262 werr = WERR_NOT_SUPPORTED;
3266 if (!W_ERROR_IS_OK(werr)) {
3267 errcode = W_ERROR_V(werr);
3271 ZERO_STRUCT(info_ctr);
3272 ZERO_STRUCT(secdesc_ctr);
3274 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3281 if (!NT_STATUS_IS_OK(status)) {
3282 errcode = W_ERROR_V(ntstatus_to_werror(status));
3285 if (!W_ERROR_IS_OK(werr)) {
3286 errcode = W_ERROR_V(werr);
3290 errcode = W_ERROR_V(werr);
3294 if (cli && is_valid_policy_hnd(&handle)) {
3295 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3298 SSVAL(*rparam,0,errcode);
3299 SSVAL(*rparam,2,0); /* converter word */
3304 /****************************************************************************
3305 set the property of a print job (undocumented?)
3306 ? function = 0xb -> set name of print job
3307 ? function = 0x6 -> move print job up/down
3308 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3309 or <WWsTP> <WB21BB16B10zWWzDDz>
3310 ****************************************************************************/
3312 static int check_printjob_info(struct pack_desc* desc,
3313 int uLevel, char* id)
3315 desc->subformat = NULL;
3317 case 0: desc->format = "W"; break;
3318 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3319 case 2: desc->format = "WWzWWDDzz"; break;
3320 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3321 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3323 DEBUG(0,("check_printjob_info: invalid level %d\n",
3327 if (id == NULL || strcmp(desc->format,id) != 0) {
3328 DEBUG(0,("check_printjob_info: invalid format %s\n",
3329 id ? id : "<NULL>" ));
3335 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3336 char *param, int tpscnt,
3337 char *data, int tdscnt,
3338 int mdrcnt,int mprcnt,
3339 char **rdata,char **rparam,
3340 int *rdata_len,int *rparam_len)
3342 struct pack_desc desc;
3343 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3344 char *str2 = skip_string(param,tpscnt,str1);
3345 char *p = skip_string(param,tpscnt,str2);
3348 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3349 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3352 TALLOC_CTX *mem_ctx = talloc_tos();
3355 struct rpc_pipe_client *cli = NULL;
3356 struct policy_handle handle;
3357 struct spoolss_DevmodeContainer devmode_ctr;
3358 struct spoolss_JobInfoContainer ctr;
3359 union spoolss_JobInfo info;
3360 struct spoolss_SetJobInfo1 info1;
3362 if (!str1 || !str2 || !p) {
3366 * We use 1 here not 2 as we're checking
3367 * the last byte we want to access is safe.
3369 if (!is_offset_safe(param,tpscnt,p,1)) {
3372 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3375 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3382 /* check it's a supported varient */
3383 if ((strcmp(str1,"WWsTP")) ||
3384 (!check_printjob_info(&desc,uLevel,str2)))
3387 errcode = NERR_notsupported;
3391 /* change print job name, data gives the name */
3397 ZERO_STRUCT(handle);
3399 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3400 rpc_spoolss_dispatch, conn->server_info,
3402 if (!NT_STATUS_IS_OK(status)) {
3403 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3404 nt_errstr(status)));
3405 errcode = W_ERROR_V(ntstatus_to_werror(status));
3409 ZERO_STRUCT(devmode_ctr);
3411 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3415 SEC_FLAG_MAXIMUM_ALLOWED,
3418 if (!NT_STATUS_IS_OK(status)) {
3419 errcode = W_ERROR_V(ntstatus_to_werror(status));
3422 if (!W_ERROR_IS_OK(werr)) {
3423 errcode = W_ERROR_V(werr);
3427 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3433 if (!W_ERROR_IS_OK(werr)) {
3434 errcode = W_ERROR_V(werr);
3440 info1.job_id = info.info1.job_id;
3441 info1.printer_name = info.info1.printer_name;
3442 info1.user_name = info.info1.user_name;
3443 info1.document_name = data;
3444 info1.data_type = info.info1.data_type;
3445 info1.text_status = info.info1.text_status;
3446 info1.status = info.info1.status;
3447 info1.priority = info.info1.priority;
3448 info1.position = info.info1.position;
3449 info1.total_pages = info.info1.total_pages;
3450 info1.pages_printed = info.info1.pages_printed;
3451 info1.submitted = info.info1.submitted;
3454 ctr.info.info1 = &info1;
3456 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3462 if (!NT_STATUS_IS_OK(status)) {
3463 errcode = W_ERROR_V(ntstatus_to_werror(status));
3466 if (!W_ERROR_IS_OK(werr)) {
3467 errcode = W_ERROR_V(werr);
3471 errcode = NERR_Success;
3474 if (cli && is_valid_policy_hnd(&handle)) {
3475 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3478 SSVALS(*rparam,0,errcode);
3479 SSVAL(*rparam,2,0); /* converter word */
3485 /****************************************************************************
3486 Get info about the server.
3487 ****************************************************************************/
3489 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3490 char *param, int tpscnt,
3491 char *data, int tdscnt,
3492 int mdrcnt,int mprcnt,
3493 char **rdata,char **rparam,
3494 int *rdata_len,int *rparam_len)
3496 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3497 char *str2 = skip_string(param,tpscnt,str1);
3498 char *p = skip_string(param,tpscnt,str2);
3499 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3505 TALLOC_CTX *mem_ctx = talloc_tos();
3506 struct rpc_pipe_client *cli = NULL;
3507 union srvsvc_NetSrvInfo info;
3510 if (!str1 || !str2 || !p) {
3514 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3516 /* check it's a supported varient */
3517 if (!prefix_ok(str1,"WrLh")) {
3523 if (strcmp(str2,"B16") != 0) {
3529 if (strcmp(str2,"B16BBDz") != 0) {
3535 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3541 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3547 if (strcmp(str2,"DN") != 0) {
3553 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3562 *rdata_len = mdrcnt;
3563 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3569 p2 = p + struct_len;
3571 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3572 rpc_srvsvc_dispatch, conn->server_info,
3574 if (!NT_STATUS_IS_OK(status)) {
3575 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3576 nt_errstr(status)));
3577 errcode = W_ERROR_V(ntstatus_to_werror(status));
3581 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3586 if (!NT_STATUS_IS_OK(status)) {
3587 errcode = W_ERROR_V(ntstatus_to_werror(status));
3590 if (!W_ERROR_IS_OK(werr)) {
3591 errcode = W_ERROR_V(werr);
3595 if (info.info101 == NULL) {
3596 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3601 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3602 STR_ASCII|STR_UPPER|STR_TERMINATE);
3606 SCVAL(p,0,info.info101->version_major);
3607 SCVAL(p,1,info.info101->version_minor);
3608 SIVAL(p,2,info.info101->server_type);
3610 if (mdrcnt == struct_len) {
3613 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3614 if (mdrcnt - struct_len <= 0) {
3618 info.info101->comment,
3619 MIN(mdrcnt - struct_len,
3620 MAX_SERVER_STRING_LENGTH),
3622 p2 = skip_string(*rdata,*rdata_len,p2);
3630 return False; /* not yet implemented */
3633 errcode = NERR_Success;
3637 *rdata_len = PTR_DIFF(p2,*rdata);
3640 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3644 SSVAL(*rparam,0,errcode);
3645 SSVAL(*rparam,2,0); /* converter word */
3646 SSVAL(*rparam,4,*rdata_len);
3651 /****************************************************************************
3652 Get info about the server.
3653 ****************************************************************************/
3655 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3656 char *param, int tpscnt,
3657 char *data, int tdscnt,
3658 int mdrcnt,int mprcnt,
3659 char **rdata,char **rparam,
3660 int *rdata_len,int *rparam_len)
3662 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3663 char *str2 = skip_string(param,tpscnt,str1);
3664 char *p = skip_string(param,tpscnt,str2);
3667 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3669 if (!str1 || !str2 || !p) {
3673 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3676 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3681 /* check it's a supported varient */
3682 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3686 *rdata_len = mdrcnt + 1024;
3687 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3692 SSVAL(*rparam,0,NERR_Success);
3693 SSVAL(*rparam,2,0); /* converter word */
3696 endp = *rdata + *rdata_len;
3698 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3703 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3704 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3706 p2 = skip_string(*rdata,*rdata_len,p2);
3712 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3713 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3714 p2 = skip_string(*rdata,*rdata_len,p2);
3720 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3721 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3723 p2 = skip_string(*rdata,*rdata_len,p2);
3729 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3730 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3733 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3734 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3735 p2 = skip_string(*rdata,*rdata_len,p2);
3741 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3742 strlcpy(p2,"",PTR_DIFF(endp,p2));
3743 p2 = skip_string(*rdata,*rdata_len,p2);
3749 *rdata_len = PTR_DIFF(p2,*rdata);
3751 SSVAL(*rparam,4,*rdata_len);
3756 /****************************************************************************
3757 get info about a user
3759 struct user_info_11 {
3760 char usri11_name[21]; 0-20
3762 char *usri11_comment; 22-25
3763 char *usri11_usr_comment; 26-29
3764 unsigned short usri11_priv; 30-31
3765 unsigned long usri11_auth_flags; 32-35
3766 long usri11_password_age; 36-39
3767 char *usri11_homedir; 40-43
3768 char *usri11_parms; 44-47
3769 long usri11_last_logon; 48-51
3770 long usri11_last_logoff; 52-55
3771 unsigned short usri11_bad_pw_count; 56-57
3772 unsigned short usri11_num_logons; 58-59
3773 char *usri11_logon_server; 60-63
3774 unsigned short usri11_country_code; 64-65
3775 char *usri11_workstations; 66-69
3776 unsigned long usri11_max_storage; 70-73
3777 unsigned short usri11_units_per_week; 74-75
3778 unsigned char *usri11_logon_hours; 76-79
3779 unsigned short usri11_code_page; 80-81
3784 usri11_name specifies the user name for which information is retrieved
3786 usri11_pad aligns the next data structure element to a word boundary
3788 usri11_comment is a null terminated ASCII comment
3790 usri11_user_comment is a null terminated ASCII comment about the user
3792 usri11_priv specifies the level of the privilege assigned to the user.
3793 The possible values are:
3795 Name Value Description
3796 USER_PRIV_GUEST 0 Guest privilege
3797 USER_PRIV_USER 1 User privilege
3798 USER_PRV_ADMIN 2 Administrator privilege
3800 usri11_auth_flags specifies the account operator privileges. The
3801 possible values are:
3803 Name Value Description
3804 AF_OP_PRINT 0 Print operator
3807 Leach, Naik [Page 28]
3811 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3814 AF_OP_COMM 1 Communications operator
3815 AF_OP_SERVER 2 Server operator
3816 AF_OP_ACCOUNTS 3 Accounts operator
3819 usri11_password_age specifies how many seconds have elapsed since the
3820 password was last changed.
3822 usri11_home_dir points to a null terminated ASCII string that contains
3823 the path name of the user's home directory.
3825 usri11_parms points to a null terminated ASCII string that is set
3826 aside for use by applications.
3828 usri11_last_logon specifies the time when the user last logged on.
3829 This value is stored as the number of seconds elapsed since
3830 00:00:00, January 1, 1970.
3832 usri11_last_logoff specifies the time when the user last logged off.
3833 This value is stored as the number of seconds elapsed since
3834 00:00:00, January 1, 1970. A value of 0 means the last logoff
3837 usri11_bad_pw_count specifies the number of incorrect passwords
3838 entered since the last successful logon.
3840 usri11_log1_num_logons specifies the number of times this user has
3841 logged on. A value of -1 means the number of logons is unknown.
3843 usri11_logon_server points to a null terminated ASCII string that
3844 contains the name of the server to which logon requests are sent.
3845 A null string indicates logon requests should be sent to the
3848 usri11_country_code specifies the country code for the user's language
3851 usri11_workstations points to a null terminated ASCII string that
3852 contains the names of workstations the user may log on from.
3853 There may be up to 8 workstations, with the names separated by
3854 commas. A null strings indicates there are no restrictions.
3856 usri11_max_storage specifies the maximum amount of disk space the user
3857 can occupy. A value of 0xffffffff indicates there are no
3860 usri11_units_per_week specifies the equal number of time units into
3861 which a week is divided. This value must be equal to 168.
3863 usri11_logon_hours points to a 21 byte (168 bits) string that
3864 specifies the time during which the user can log on. Each bit
3865 represents one unique hour in a week. The first bit (bit 0, word
3866 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3870 Leach, Naik [Page 29]
3874 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3877 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3878 are no restrictions.
3880 usri11_code_page specifies the code page for the user's language of
3883 All of the pointers in this data structure need to be treated
3884 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3885 to be ignored. The converter word returned in the parameters section
3886 needs to be subtracted from the lower 16 bits to calculate an offset
3887 into the return buffer where this ASCII string resides.
3889 There is no auxiliary data in the response.
3891 ****************************************************************************/
3893 #define usri11_name 0
3894 #define usri11_pad 21
3895 #define usri11_comment 22
3896 #define usri11_usr_comment 26
3897 #define usri11_full_name 30
3898 #define usri11_priv 34
3899 #define usri11_auth_flags 36
3900 #define usri11_password_age 40
3901 #define usri11_homedir 44
3902 #define usri11_parms 48
3903 #define usri11_last_logon 52
3904 #define usri11_last_logoff 56
3905 #define usri11_bad_pw_count 60
3906 #define usri11_num_logons 62
3907 #define usri11_logon_server 64
3908 #define usri11_country_code 68
3909 #define usri11_workstations 70
3910 #define usri11_max_storage 74
3911 #define usri11_units_per_week 78
3912 #define usri11_logon_hours 80
3913 #define usri11_code_page 84
3914 #define usri11_end 86
3916 #define USER_PRIV_GUEST 0
3917 #define USER_PRIV_USER 1
3918 #define USER_PRIV_ADMIN 2
3920 #define AF_OP_PRINT 0
3921 #define AF_OP_COMM 1
3922 #define AF_OP_SERVER 2
3923 #define AF_OP_ACCOUNTS 3
3926 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3927 char *param, int tpscnt,
3928 char *data, int tdscnt,
3929 int mdrcnt,int mprcnt,
3930 char **rdata,char **rparam,
3931 int *rdata_len,int *rparam_len)
3933 struct smbd_server_connection *sconn = smbd_server_conn;
3934 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3935 char *str2 = skip_string(param,tpscnt,str1);
3936 char *UserName = skip_string(param,tpscnt,str2);
3937 char *p = skip_string(param,tpscnt,UserName);
3938 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3941 const char *level_string;
3943 /* get NIS home of a previously validated user - simeon */
3944 /* With share level security vuid will always be zero.
3945 Don't depend on vuser being non-null !!. JRA */
3946 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3948 DEBUG(3,(" Username of UID %d is %s\n",
3949 (int)vuser->server_info->utok.uid,
3950 vuser->server_info->unix_name));
3953 if (!str1 || !str2 || !UserName || !p) {
3958 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3963 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3965 /* check it's a supported variant */
3966 if (strcmp(str1,"zWrLh") != 0) {
3970 case 0: level_string = "B21"; break;
3971 case 1: level_string = "B21BB16DWzzWz"; break;
3972 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3973 case 10: level_string = "B21Bzzz"; break;
3974 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3975 default: return False;
3978 if (strcmp(level_string,str2) != 0) {
3982 *rdata_len = mdrcnt + 1024;
3983 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3988 SSVAL(*rparam,0,NERR_Success);
3989 SSVAL(*rparam,2,0); /* converter word */
3992 endp = *rdata + *rdata_len;
3993 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3999 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4002 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4007 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4008 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4009 p2 = skip_string(*rdata,*rdata_len,p2);
4014 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4015 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4016 p2 = skip_string(*rdata,*rdata_len,p2);
4021 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4022 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4023 strlcpy(p2,((vuser != NULL)
4024 ? pdb_get_fullname(vuser->server_info->sam_account)
4025 : UserName),PTR_DIFF(endp,p2));
4026 p2 = skip_string(*rdata,*rdata_len,p2);
4033 const char *homedir = "";
4034 if (vuser != NULL) {
4035 homedir = pdb_get_homedir(
4036 vuser->server_info->sam_account);
4038 /* modelled after NTAS 3.51 reply */
4039 SSVAL(p,usri11_priv,
4040 (get_current_uid(conn) == sec_initial_uid())?
4041 USER_PRIV_ADMIN:USER_PRIV_USER);
4042 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4043 SIVALS(p,usri11_password_age,-1); /* password age */
4044 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4045 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4046 p2 = skip_string(*rdata,*rdata_len,p2);
4050 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4051 strlcpy(p2,"",PTR_DIFF(endp,p2));
4052 p2 = skip_string(*rdata,*rdata_len,p2);
4056 SIVAL(p,usri11_last_logon,0); /* last logon */
4057 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4058 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4059 SSVALS(p,usri11_num_logons,-1); /* num logons */
4060 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4061 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4062 p2 = skip_string(*rdata,*rdata_len,p2);
4066 SSVAL(p,usri11_country_code,0); /* country code */
4068 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4069 strlcpy(p2,"",PTR_DIFF(endp,p2));
4070 p2 = skip_string(*rdata,*rdata_len,p2);
4075 SIVALS(p,usri11_max_storage,-1); /* max storage */
4076 SSVAL(p,usri11_units_per_week,168); /* units per week */
4077 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4079 /* a simple way to get logon hours at all times. */
4081 SCVAL(p2,21,0); /* fix zero termination */
4082 p2 = skip_string(*rdata,*rdata_len,p2);
4087 SSVAL(p,usri11_code_page,0); /* code page */
4090 if (uLevel == 1 || uLevel == 2) {
4091 memset(p+22,' ',16); /* password */
4092 SIVALS(p,38,-1); /* password age */
4094 (get_current_uid(conn) == sec_initial_uid())?
4095 USER_PRIV_ADMIN:USER_PRIV_USER);
4096 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4097 strlcpy(p2, vuser ? pdb_get_homedir(
4098 vuser->server_info->sam_account) : "",
4100 p2 = skip_string(*rdata,*rdata_len,p2);
4104 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4106 SSVAL(p,52,0); /* flags */
4107 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4108 strlcpy(p2, vuser ? pdb_get_logon_script(
4109 vuser->server_info->sam_account) : "",
4111 p2 = skip_string(*rdata,*rdata_len,p2);
4116 SIVAL(p,60,0); /* auth_flags */
4117 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4118 strlcpy(p2,((vuser != NULL)
4119 ? pdb_get_fullname(vuser->server_info->sam_account)
4120 : UserName),PTR_DIFF(endp,p2));
4121 p2 = skip_string(*rdata,*rdata_len,p2);
4125 SIVAL(p,68,0); /* urs_comment */
4126 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4127 strlcpy(p2,"",PTR_DIFF(endp,p2));
4128 p2 = skip_string(*rdata,*rdata_len,p2);
4132 SIVAL(p,76,0); /* workstations */
4133 SIVAL(p,80,0); /* last_logon */
4134 SIVAL(p,84,0); /* last_logoff */
4135 SIVALS(p,88,-1); /* acct_expires */
4136 SIVALS(p,92,-1); /* max_storage */
4137 SSVAL(p,96,168); /* units_per_week */
4138 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4141 SSVALS(p,102,-1); /* bad_pw_count */
4142 SSVALS(p,104,-1); /* num_logons */
4143 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4145 TALLOC_CTX *ctx = talloc_tos();
4146 int space_rem = *rdata_len - (p2 - *rdata);
4149 if (space_rem <= 0) {
4152 tmp = talloc_strdup(ctx, "\\\\%L");
4156 tmp = talloc_sub_basic(ctx,
4169 p2 = skip_string(*rdata,*rdata_len,p2);
4173 SSVAL(p,110,49); /* country_code */
4174 SSVAL(p,112,860); /* code page */
4178 *rdata_len = PTR_DIFF(p2,*rdata);
4180 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4185 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4186 char *param, int tpscnt,
4187 char *data, int tdscnt,
4188 int mdrcnt,int mprcnt,
4189 char **rdata,char **rparam,
4190 int *rdata_len,int *rparam_len)
4192 struct smbd_server_connection *sconn = smbd_server_conn;
4193 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4194 char *str2 = skip_string(param,tpscnt,str1);
4195 char *p = skip_string(param,tpscnt,str2);
4197 struct pack_desc desc;
4199 /* With share level security vuid will always be zero.
4200 Don't depend on vuser being non-null !!. JRA */
4201 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4203 if (!str1 || !str2 || !p) {
4208 DEBUG(3,(" Username of UID %d is %s\n",
4209 (int)vuser->server_info->utok.uid,
4210 vuser->server_info->unix_name));
4213 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4214 name = get_safe_str_ptr(param,tpscnt,p,2);
4219 memset((char *)&desc,'\0',sizeof(desc));
4221 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4223 /* check it's a supported varient */
4224 if (strcmp(str1,"OOWb54WrLh") != 0) {
4227 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4231 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4238 desc.buflen = mdrcnt;
4239 desc.subformat = NULL;
4242 if (init_package(&desc,1,0)) {
4243 PACKI(&desc,"W",0); /* code */
4244 PACKS(&desc,"B21",name); /* eff. name */
4245 PACKS(&desc,"B",""); /* pad */
4247 (get_current_uid(conn) == sec_initial_uid())?
4248 USER_PRIV_ADMIN:USER_PRIV_USER);
4249 PACKI(&desc,"D",0); /* auth flags XXX */
4250 PACKI(&desc,"W",0); /* num logons */
4251 PACKI(&desc,"W",0); /* bad pw count */
4252 PACKI(&desc,"D",0); /* last logon */
4253 PACKI(&desc,"D",-1); /* last logoff */
4254 PACKI(&desc,"D",-1); /* logoff time */
4255 PACKI(&desc,"D",-1); /* kickoff time */
4256 PACKI(&desc,"D",0); /* password age */
4257 PACKI(&desc,"D",0); /* password can change */
4258 PACKI(&desc,"D",-1); /* password must change */
4262 fstrcpy(mypath,"\\\\");
4263 fstrcat(mypath,get_local_machine_name());
4265 PACKS(&desc,"z",mypath); /* computer */
4268 PACKS(&desc,"z",lp_workgroup());/* domain */
4269 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4270 vuser->server_info->sam_account) : ""); /* script path */
4271 PACKI(&desc,"D",0x00000000); /* reserved */
4274 *rdata_len = desc.usedlen;
4276 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4280 SSVALS(*rparam,0,desc.errcode);
4282 SSVAL(*rparam,4,desc.neededlen);
4284 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4289 /****************************************************************************
4290 api_WAccessGetUserPerms
4291 ****************************************************************************/
4293 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4294 char *param, int tpscnt,
4295 char *data, int tdscnt,
4296 int mdrcnt,int mprcnt,
4297 char **rdata,char **rparam,
4298 int *rdata_len,int *rparam_len)
4300 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4301 char *str2 = skip_string(param,tpscnt,str1);
4302 char *user = skip_string(param,tpscnt,str2);
4303 char *resource = skip_string(param,tpscnt,user);
4305 if (!str1 || !str2 || !user || !resource) {
4309 if (skip_string(param,tpscnt,resource) == NULL) {
4312 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4314 /* check it's a supported varient */
4315 if (strcmp(str1,"zzh") != 0) {
4318 if (strcmp(str2,"") != 0) {
4323 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4327 SSVALS(*rparam,0,0); /* errorcode */
4328 SSVAL(*rparam,2,0); /* converter word */
4329 SSVAL(*rparam,4,0x7f); /* permission flags */
4334 /****************************************************************************
4335 api_WPrintJobEnumerate
4336 ****************************************************************************/
4338 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4339 char *param, int tpscnt,
4340 char *data, int tdscnt,
4341 int mdrcnt,int mprcnt,
4342 char **rdata,char **rparam,
4343 int *rdata_len,int *rparam_len)
4345 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4346 char *str2 = skip_string(param,tpscnt,str1);
4347 char *p = skip_string(param,tpscnt,str2);
4351 struct pack_desc desc;
4354 TALLOC_CTX *mem_ctx = talloc_tos();
4357 struct rpc_pipe_client *cli = NULL;
4358 struct policy_handle handle;
4359 struct spoolss_DevmodeContainer devmode_ctr;
4360 union spoolss_JobInfo info;
4362 if (!str1 || !str2 || !p) {
4366 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4368 memset((char *)&desc,'\0',sizeof(desc));
4369 memset((char *)&status,'\0',sizeof(status));
4371 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4373 /* check it's a supported varient */
4374 if (strcmp(str1,"WWrLh") != 0) {
4377 if (!check_printjob_info(&desc,uLevel,str2)) {
4381 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4385 ZERO_STRUCT(handle);
4387 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4388 rpc_spoolss_dispatch, conn->server_info,
4390 if (!NT_STATUS_IS_OK(status)) {
4391 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4392 nt_errstr(status)));
4393 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4397 ZERO_STRUCT(devmode_ctr);
4399 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4403 SEC_FLAG_MAXIMUM_ALLOWED,
4406 if (!NT_STATUS_IS_OK(status)) {
4407 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4410 if (!W_ERROR_IS_OK(werr)) {
4411 desc.errcode = W_ERROR_V(werr);
4415 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4421 if (!W_ERROR_IS_OK(werr)) {
4422 desc.errcode = W_ERROR_V(werr);
4427 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4432 desc.buflen = mdrcnt;
4435 * Don't return data but need to get correct length
4436 * init_package will return wrong size if buflen=0
4438 desc.buflen = getlen(desc.format);
4439 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4442 if (init_package(&desc,1,0)) {
4443 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4444 *rdata_len = desc.usedlen;
4446 desc.errcode = NERR_JobNotFound;
4450 if (cli && is_valid_policy_hnd(&handle)) {
4451 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4455 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4459 SSVALS(*rparam,0,desc.errcode);
4461 SSVAL(*rparam,4,desc.neededlen);
4465 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4470 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4471 char *param, int tpscnt,
4472 char *data, int tdscnt,
4473 int mdrcnt,int mprcnt,
4474 char **rdata,char **rparam,
4475 int *rdata_len,int *rparam_len)
4477 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4478 char *str2 = skip_string(param,tpscnt,str1);
4479 char *p = skip_string(param,tpscnt,str2);
4483 struct pack_desc desc;
4485 TALLOC_CTX *mem_ctx = talloc_tos();
4488 struct rpc_pipe_client *cli = NULL;
4489 struct policy_handle handle;
4490 struct spoolss_DevmodeContainer devmode_ctr;
4492 union spoolss_JobInfo *info;
4494 if (!str1 || !str2 || !p) {
4498 memset((char *)&desc,'\0',sizeof(desc));
4500 p = skip_string(param,tpscnt,p);
4504 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4506 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4508 /* check it's a supported variant */
4509 if (strcmp(str1,"zWrLeh") != 0) {
4514 return False; /* defined only for uLevel 0,1,2 */
4517 if (!check_printjob_info(&desc,uLevel,str2)) {
4521 ZERO_STRUCT(handle);
4523 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4524 rpc_spoolss_dispatch, conn->server_info,
4526 if (!NT_STATUS_IS_OK(status)) {
4527 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4528 nt_errstr(status)));
4529 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4533 ZERO_STRUCT(devmode_ctr);
4535 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4539 SEC_FLAG_MAXIMUM_ALLOWED,
4542 if (!NT_STATUS_IS_OK(status)) {
4543 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4546 if (!W_ERROR_IS_OK(werr)) {
4547 desc.errcode = W_ERROR_V(werr);
4551 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4559 if (!W_ERROR_IS_OK(werr)) {
4560 desc.errcode = W_ERROR_V(werr);
4565 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4571 desc.buflen = mdrcnt;
4573 if (init_package(&desc,count,0)) {
4575 for (i = 0; i < count; i++) {
4576 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4577 if (desc.errcode == NERR_Success) {
4583 if (cli && is_valid_policy_hnd(&handle)) {
4584 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4587 *rdata_len = desc.usedlen;
4590 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4594 SSVALS(*rparam,0,desc.errcode);
4596 SSVAL(*rparam,4,succnt);
4597 SSVAL(*rparam,6,count);
4599 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4604 static int check_printdest_info(struct pack_desc* desc,
4605 int uLevel, char* id)
4607 desc->subformat = NULL;
4610 desc->format = "B9";
4613 desc->format = "B9B21WWzW";
4619 desc->format = "zzzWWzzzWW";
4622 DEBUG(0,("check_printdest_info: invalid level %d\n",
4626 if (id == NULL || strcmp(desc->format,id) != 0) {
4627 DEBUG(0,("check_printdest_info: invalid string %s\n",
4628 id ? id : "<NULL>" ));
4634 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4635 struct pack_desc* desc)
4639 strncpy(buf, info2->printername, sizeof(buf)-1);
4640 buf[sizeof(buf)-1] = 0;
4644 PACKS(desc,"B9",buf); /* szName */
4646 PACKS(desc,"B21",""); /* szUserName */
4647 PACKI(desc,"W",0); /* uJobId */
4648 PACKI(desc,"W",0); /* fsStatus */
4649 PACKS(desc,"z",""); /* pszStatus */
4650 PACKI(desc,"W",0); /* time */
4654 if (uLevel == 2 || uLevel == 3) {
4655 PACKS(desc,"z",buf); /* pszPrinterName */
4657 PACKS(desc,"z",""); /* pszUserName */
4658 PACKS(desc,"z",""); /* pszLogAddr */
4659 PACKI(desc,"W",0); /* uJobId */
4660 PACKI(desc,"W",0); /* fsStatus */
4661 PACKS(desc,"z",""); /* pszStatus */
4662 PACKS(desc,"z",""); /* pszComment */
4663 PACKS(desc,"z","NULL"); /* pszDrivers */
4664 PACKI(desc,"W",0); /* time */
4665 PACKI(desc,"W",0); /* pad1 */
4670 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4671 char *param, int tpscnt,
4672 char *data, int tdscnt,
4673 int mdrcnt,int mprcnt,
4674 char **rdata,char **rparam,
4675 int *rdata_len,int *rparam_len)
4677 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4678 char *str2 = skip_string(param,tpscnt,str1);
4679 char *p = skip_string(param,tpscnt,str2);
4680 char* PrinterName = p;
4682 struct pack_desc desc;
4685 TALLOC_CTX *mem_ctx = talloc_tos();
4688 struct rpc_pipe_client *cli = NULL;
4689 struct policy_handle handle;
4690 struct spoolss_DevmodeContainer devmode_ctr;
4691 union spoolss_PrinterInfo info;
4693 if (!str1 || !str2 || !p) {
4697 memset((char *)&desc,'\0',sizeof(desc));
4699 p = skip_string(param,tpscnt,p);
4703 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4705 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4707 /* check it's a supported varient */
4708 if (strcmp(str1,"zWrLh") != 0) {
4711 if (!check_printdest_info(&desc,uLevel,str2)) {
4715 ZERO_STRUCT(handle);
4717 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4718 rpc_spoolss_dispatch, conn->server_info,
4720 if (!NT_STATUS_IS_OK(status)) {
4721 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4722 nt_errstr(status)));
4723 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4727 ZERO_STRUCT(devmode_ctr);
4729 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4733 SEC_FLAG_MAXIMUM_ALLOWED,
4736 if (!NT_STATUS_IS_OK(status)) {
4738 desc.errcode = NERR_DestNotFound;
4742 if (!W_ERROR_IS_OK(werr)) {
4744 desc.errcode = NERR_DestNotFound;
4749 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4754 if (!W_ERROR_IS_OK(werr)) {
4756 desc.errcode = NERR_DestNotFound;
4762 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4767 desc.buflen = mdrcnt;
4770 * Don't return data but need to get correct length
4771 * init_package will return wrong size if buflen=0
4773 desc.buflen = getlen(desc.format);
4774 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4776 if (init_package(&desc,1,0)) {
4777 fill_printdest_info(&info.info2, uLevel,&desc);
4781 if (cli && is_valid_policy_hnd(&handle)) {
4782 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4785 *rdata_len = desc.usedlen;
4788 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4792 SSVALS(*rparam,0,desc.errcode);
4794 SSVAL(*rparam,4,desc.neededlen);
4796 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4802 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4803 char *param, int tpscnt,
4804 char *data, int tdscnt,
4805 int mdrcnt,int mprcnt,
4806 char **rdata,char **rparam,
4807 int *rdata_len,int *rparam_len)
4809 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4810 char *str2 = skip_string(param,tpscnt,str1);
4811 char *p = skip_string(param,tpscnt,str2);
4815 struct pack_desc desc;
4817 TALLOC_CTX *mem_ctx = talloc_tos();
4820 struct rpc_pipe_client *cli = NULL;
4821 union spoolss_PrinterInfo *info;
4824 if (!str1 || !str2 || !p) {
4828 memset((char *)&desc,'\0',sizeof(desc));
4830 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4832 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4834 /* check it's a supported varient */
4835 if (strcmp(str1,"WrLeh") != 0) {
4838 if (!check_printdest_info(&desc,uLevel,str2)) {
4844 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4845 rpc_spoolss_dispatch, conn->server_info,
4847 if (!NT_STATUS_IS_OK(status)) {
4848 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4849 nt_errstr(status)));
4850 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4854 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4856 cli->srv_name_slash,
4861 if (!W_ERROR_IS_OK(werr)) {
4862 desc.errcode = W_ERROR_V(werr);
4864 desc.errcode = NERR_DestNotFound;
4872 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4879 desc.buflen = mdrcnt;
4880 if (init_package(&desc,queuecnt,0)) {
4883 for (i = 0; i < count; i++) {
4884 fill_printdest_info(&info[i].info2, uLevel,&desc);
4886 if (desc.errcode == NERR_Success) {
4892 *rdata_len = desc.usedlen;
4895 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4899 SSVALS(*rparam,0,desc.errcode);
4901 SSVAL(*rparam,4,succnt);
4902 SSVAL(*rparam,6,queuecnt);
4904 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4909 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4910 char *param, int tpscnt,
4911 char *data, int tdscnt,
4912 int mdrcnt,int mprcnt,
4913 char **rdata,char **rparam,
4914 int *rdata_len,int *rparam_len)
4916 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4917 char *str2 = skip_string(param,tpscnt,str1);
4918 char *p = skip_string(param,tpscnt,str2);
4921 struct pack_desc desc;
4923 if (!str1 || !str2 || !p) {
4927 memset((char *)&desc,'\0',sizeof(desc));
4929 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4931 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4933 /* check it's a supported varient */
4934 if (strcmp(str1,"WrLeh") != 0) {
4937 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4942 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4948 desc.buflen = mdrcnt;
4949 if (init_package(&desc,1,0)) {
4950 PACKS(&desc,"B41","NULL");
4953 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4955 *rdata_len = desc.usedlen;
4958 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4962 SSVALS(*rparam,0,desc.errcode);
4964 SSVAL(*rparam,4,succnt);
4967 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4972 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4973 char *param, int tpscnt,
4974 char *data, int tdscnt,
4975 int mdrcnt,int mprcnt,
4976 char **rdata,char **rparam,
4977 int *rdata_len,int *rparam_len)
4979 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4980 char *str2 = skip_string(param,tpscnt,str1);
4981 char *p = skip_string(param,tpscnt,str2);
4984 struct pack_desc desc;
4986 if (!str1 || !str2 || !p) {
4989 memset((char *)&desc,'\0',sizeof(desc));
4991 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4993 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4995 /* check it's a supported varient */
4996 if (strcmp(str1,"WrLeh") != 0) {
4999 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5004 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5010 desc.buflen = mdrcnt;
5012 if (init_package(&desc,1,0)) {
5013 PACKS(&desc,"B13","lpd");
5016 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5018 *rdata_len = desc.usedlen;
5021 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5025 SSVALS(*rparam,0,desc.errcode);
5027 SSVAL(*rparam,4,succnt);
5030 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5035 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5036 char *param, int tpscnt,
5037 char *data, int tdscnt,
5038 int mdrcnt,int mprcnt,
5039 char **rdata,char **rparam,
5040 int *rdata_len,int *rparam_len)
5042 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5043 char *str2 = skip_string(param,tpscnt,str1);
5044 char *p = skip_string(param,tpscnt,str2);
5047 struct pack_desc desc;
5049 if (!str1 || !str2 || !p) {
5053 memset((char *)&desc,'\0',sizeof(desc));
5055 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5057 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5059 /* check it's a supported varient */
5060 if (strcmp(str1,"WrLeh") != 0) {
5063 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5068 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5073 memset((char *)&desc,'\0',sizeof(desc));
5075 desc.buflen = mdrcnt;
5077 if (init_package(&desc,1,0)) {
5078 PACKS(&desc,"B13","lp0");
5081 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5083 *rdata_len = desc.usedlen;
5086 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5090 SSVALS(*rparam,0,desc.errcode);
5092 SSVAL(*rparam,4,succnt);
5095 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5100 /****************************************************************************
5102 ****************************************************************************/
5104 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5105 char *param, int tpscnt,
5106 char *data, int tdscnt,
5107 int mdrcnt,int mprcnt,
5108 char **rdata,char **rparam,
5109 int *rdata_len,int *rparam_len)
5112 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5113 char *str2 = skip_string(param,tpscnt,str1);
5114 char *p = skip_string(param,tpscnt,str2);
5116 struct pack_desc desc;
5117 struct sessionid *session_list;
5118 int i, num_sessions;
5120 if (!str1 || !str2 || !p) {
5124 memset((char *)&desc,'\0',sizeof(desc));
5126 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5128 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5129 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5130 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5132 /* check it's a supported varient */
5133 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5136 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5140 num_sessions = list_sessions(talloc_tos(), &session_list);
5143 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5148 memset((char *)&desc,'\0',sizeof(desc));
5150 desc.buflen = mdrcnt;
5152 if (!init_package(&desc,num_sessions,0)) {
5156 for(i=0; i<num_sessions; i++) {
5157 PACKS(&desc, "z", session_list[i].remote_machine);
5158 PACKS(&desc, "z", session_list[i].username);
5159 PACKI(&desc, "W", 1); /* num conns */
5160 PACKI(&desc, "W", 0); /* num opens */
5161 PACKI(&desc, "W", 1); /* num users */
5162 PACKI(&desc, "D", 0); /* session time */
5163 PACKI(&desc, "D", 0); /* idle time */
5164 PACKI(&desc, "D", 0); /* flags */
5165 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5168 *rdata_len = desc.usedlen;
5171 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5175 SSVALS(*rparam,0,desc.errcode);
5176 SSVAL(*rparam,2,0); /* converter */
5177 SSVAL(*rparam,4,num_sessions); /* count */
5179 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5185 /****************************************************************************
5186 The buffer was too small.
5187 ****************************************************************************/
5189 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5190 int mdrcnt, int mprcnt,
5191 char **rdata, char **rparam,
5192 int *rdata_len, int *rparam_len)
5194 *rparam_len = MIN(*rparam_len,mprcnt);
5195 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5202 SSVAL(*rparam,0,NERR_BufTooSmall);
5204 DEBUG(3,("Supplied buffer too small in API command\n"));
5209 /****************************************************************************
5210 The request is not supported.
5211 ****************************************************************************/
5213 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5214 char *param, int tpscnt,
5215 char *data, int tdscnt,
5216 int mdrcnt, int mprcnt,
5217 char **rdata, char **rparam,
5218 int *rdata_len, int *rparam_len)
5221 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5228 SSVAL(*rparam,0,NERR_notsupported);
5229 SSVAL(*rparam,2,0); /* converter word */
5231 DEBUG(3,("Unsupported API command\n"));
5236 static const struct {
5239 bool (*fn)(connection_struct *, uint16,
5242 int,int,char **,char **,int *,int *);
5243 bool auth_user; /* Deny anonymous access? */
5244 } api_commands[] = {
5245 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5246 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5247 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5248 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5249 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5250 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5251 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5252 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5253 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5254 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5255 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5256 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5257 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5258 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5259 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5260 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5261 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5262 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5263 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5264 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5265 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5266 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5267 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5268 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5269 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5270 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5271 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5272 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5273 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5274 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5275 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5276 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5277 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5278 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5279 {NULL, -1, api_Unsupported}
5280 /* The following RAP calls are not implemented by Samba:
5282 RAP_WFileEnum2 - anon not OK
5287 /****************************************************************************
5288 Handle remote api calls.
5289 ****************************************************************************/
5291 void api_reply(connection_struct *conn, uint16 vuid,
5292 struct smb_request *req,
5293 char *data, char *params,
5294 int tdscnt, int tpscnt,
5295 int mdrcnt, int mprcnt)
5297 struct smbd_server_connection *sconn = smbd_server_conn;
5300 char *rparam = NULL;
5301 const char *name1 = NULL;
5302 const char *name2 = NULL;
5309 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5310 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5315 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5318 api_command = SVAL(params,0);
5319 /* Is there a string at position params+2 ? */
5320 if (skip_string(params,tpscnt,params+2)) {
5325 name2 = skip_string(params,tpscnt,params+2);
5330 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5334 tdscnt,tpscnt,mdrcnt,mprcnt));
5336 for (i=0;api_commands[i].name;i++) {
5337 if (api_commands[i].id == api_command && api_commands[i].fn) {
5338 DEBUG(3,("Doing %s\n",api_commands[i].name));
5343 /* Check whether this api call can be done anonymously */
5345 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5346 user_struct *user = get_valid_user_struct(sconn, vuid);
5348 if (!user || user->server_info->guest) {
5349 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5354 rdata = (char *)SMB_MALLOC(1024);
5356 memset(rdata,'\0',1024);
5359 rparam = (char *)SMB_MALLOC(1024);
5361 memset(rparam,'\0',1024);
5364 if(!rdata || !rparam) {
5365 DEBUG(0,("api_reply: malloc fail !\n"));
5368 reply_nterror(req, NT_STATUS_NO_MEMORY);
5372 reply = api_commands[i].fn(conn,
5374 params,tpscnt, /* params + length */
5375 data,tdscnt, /* data + length */
5377 &rdata,&rparam,&rdata_len,&rparam_len);
5380 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5381 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5382 &rdata,&rparam,&rdata_len,&rparam_len);
5385 /* if we get False back then it's actually unsupported */
5387 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5388 &rdata,&rparam,&rdata_len,&rparam_len);
5391 /* If api_Unsupported returns false we can't return anything. */
5393 send_trans_reply(conn, req, rparam, rparam_len,
5394 rdata, rdata_len, False);