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 "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/cli_srvsvc.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_spoolss.h"
37 #include "../librpc/gen_ndr/srv_srvsvc.h"
38 #include "../librpc/gen_ndr/rap.h"
39 #include "../lib/util/binsearch.h"
46 #define NERR_Success 0
47 #define NERR_badpass 86
48 #define NERR_notsupported 50
50 #define NERR_BASE (2100)
51 #define NERR_BufTooSmall (NERR_BASE+23)
52 #define NERR_JobNotFound (NERR_BASE+51)
53 #define NERR_DestNotFound (NERR_BASE+52)
55 #define ACCESS_READ 0x01
56 #define ACCESS_WRITE 0x02
57 #define ACCESS_CREATE 0x04
59 #define SHPWLEN 8 /* share password length */
61 /* Limit size of ipc replies */
63 static char *smb_realloc_limit(void *ptr, size_t size)
67 size = MAX((size),4*1024);
68 val = (char *)SMB_REALLOC(ptr,size);
70 memset(val,'\0',size);
75 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
76 char *param, int tpscnt,
77 char *data, int tdscnt,
78 int mdrcnt, int mprcnt,
79 char **rdata, char **rparam,
80 int *rdata_len, int *rparam_len);
82 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
83 int mdrcnt, int mprcnt,
84 char **rdata, char **rparam,
85 int *rdata_len, int *rparam_len);
88 static int CopyExpanded(connection_struct *conn,
89 int snum, char **dst, char *src, int *p_space_remaining)
91 TALLOC_CTX *ctx = talloc_tos();
95 if (!src || !dst || !p_space_remaining || !(*dst) ||
96 *p_space_remaining <= 0) {
100 buf = talloc_strdup(ctx, src);
102 *p_space_remaining = 0;
105 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
107 *p_space_remaining = 0;
110 buf = talloc_sub_advanced(ctx,
111 lp_servicename(SNUM(conn)),
112 conn->server_info->unix_name,
114 conn->server_info->utok.gid,
115 conn->server_info->sanitized_username,
116 pdb_get_domain(conn->server_info->sam_account),
119 *p_space_remaining = 0;
122 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
127 (*p_space_remaining) -= l;
131 static int CopyAndAdvance(char **dst, char *src, int *n)
134 if (!src || !dst || !n || !(*dst)) {
137 l = push_ascii(*dst,src,*n, STR_TERMINATE);
146 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
148 TALLOC_CTX *ctx = talloc_tos();
153 buf = talloc_strdup(ctx,s);
157 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
161 buf = talloc_sub_advanced(ctx,
162 lp_servicename(SNUM(conn)),
163 conn->server_info->unix_name,
165 conn->server_info->utok.gid,
166 conn->server_info->sanitized_username,
167 pdb_get_domain(conn->server_info->sam_account),
172 return strlen(buf) + 1;
175 /*******************************************************************
176 Check a API string for validity when we only need to check the prefix.
177 ******************************************************************/
179 static bool prefix_ok(const char *str, const char *prefix)
181 return(strncmp(str,prefix,strlen(prefix)) == 0);
185 const char *format; /* formatstring for structure */
186 const char *subformat; /* subformat for structure */
187 char *base; /* baseaddress of buffer */
188 int buflen; /* remaining size for fixed part; on init: length of base */
189 int subcount; /* count of substructures */
190 char *structbuf; /* pointer into buffer for remaining fixed part */
191 int stringlen; /* remaining size for variable part */
192 char *stringbuf; /* pointer into buffer for remaining variable part */
193 int neededlen; /* total needed size */
194 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
195 const char *curpos; /* current position; pointer into format or subformat */
199 static int get_counter(const char **p)
205 if (!isdigit((int)**p)) {
211 n = 10 * n + (i - '0');
219 static int getlen(const char *p)
228 case 'W': /* word (2 byte) */
231 case 'K': /* status word? (2 byte) */
234 case 'N': /* count of substructures (word) at end */
237 case 'D': /* double word (4 byte) */
238 case 'z': /* offset to zero terminated string (4 byte) */
239 case 'l': /* offset to user data (4 byte) */
242 case 'b': /* offset to data (with counter) (4 byte) */
246 case 'B': /* byte (with optional counter) */
247 n += get_counter(&p);
254 static bool init_package(struct pack_desc *p, int count, int subcount)
259 if (!p->format || !p->base) {
263 i = count * getlen(p->format);
265 i += subcount * getlen(p->subformat);
267 p->structbuf = p->base;
271 p->curpos = p->format;
277 * This is the old error code we used. Aparently
278 * WinNT/2k systems return ERRbuftoosmall (2123) and
279 * OS/2 needs this. I'm leaving this here so we can revert
282 p->errcode = ERRmoredata;
284 p->errcode = ERRbuftoosmall;
287 p->errcode = NERR_Success;
291 p->stringbuf = p->base + i;
293 return (p->errcode == NERR_Success);
296 static int package(struct pack_desc *p, ...)
299 int needed=0, stringneeded;
300 const char *str=NULL;
301 int is_string=0, stringused;
308 p->curpos = p->format;
310 p->curpos = p->subformat;
315 str = va_arg(args,char*);
316 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
325 switch( *p->curpos++ ) {
326 case 'W': /* word (2 byte) */
328 temp = va_arg(args,int);
329 if (p->buflen >= needed) {
330 SSVAL(p->structbuf,0,temp);
333 case 'K': /* status word? (2 byte) */
335 temp = va_arg(args,int);
336 if (p->buflen >= needed) {
337 SSVAL(p->structbuf,0,temp);
340 case 'N': /* count of substructures (word) at end */
342 p->subcount = va_arg(args,int);
343 if (p->buflen >= needed) {
344 SSVAL(p->structbuf,0,p->subcount);
347 case 'D': /* double word (4 byte) */
349 temp = va_arg(args,int);
350 if (p->buflen >= needed) {
351 SIVAL(p->structbuf,0,temp);
354 case 'B': /* byte (with optional counter) */
355 needed = get_counter(&p->curpos);
357 char *s = va_arg(args,char*);
358 if (p->buflen >= needed) {
359 StrnCpy(p->structbuf,s?s:"",needed-1);
363 case 'z': /* offset to zero terminated string (4 byte) */
364 str = va_arg(args,char*);
365 stringneeded = (str ? strlen(str)+1 : 0);
368 case 'l': /* offset to user data (4 byte) */
369 str = va_arg(args,char*);
370 stringneeded = va_arg(args,int);
373 case 'b': /* offset to data (with counter) (4 byte) */
374 str = va_arg(args,char*);
375 stringneeded = get_counter(&p->curpos);
381 if (stringneeded >= 0) {
383 if (p->buflen >= needed) {
384 stringused = stringneeded;
385 if (stringused > p->stringlen) {
386 stringused = (is_string ? p->stringlen : 0);
387 if (p->errcode == NERR_Success) {
388 p->errcode = ERRmoredata;
392 SIVAL(p->structbuf,0,0);
394 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
395 memcpy(p->stringbuf,str?str:"",stringused);
397 p->stringbuf[stringused-1] = '\0';
399 p->stringbuf += stringused;
400 p->stringlen -= stringused;
401 p->usedlen += stringused;
404 p->neededlen += stringneeded;
407 p->neededlen += needed;
408 if (p->buflen >= needed) {
409 p->structbuf += needed;
411 p->usedlen += needed;
413 if (p->errcode == NERR_Success) {
414 p->errcode = ERRmoredata;
421 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
422 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
424 #define PACK(desc,t,v) package(desc,v)
425 #define PACKl(desc,t,v,l) package(desc,v,l)
428 static void PACKI(struct pack_desc* desc, const char *t,int v)
433 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
438 /****************************************************************************
440 ****************************************************************************/
442 static void PackDriverData(struct pack_desc* desc)
444 char drivdata[4+4+32];
445 SIVAL(drivdata,0,sizeof drivdata); /* cb */
446 SIVAL(drivdata,4,1000); /* lVersion */
447 memset(drivdata+8,0,32); /* szDeviceName */
448 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
449 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
452 static int check_printq_info(struct pack_desc* desc,
453 unsigned int uLevel, char *id1, char *id2)
455 desc->subformat = NULL;
458 desc->format = "B13";
461 desc->format = "B13BWWWzzzzzWW";
464 desc->format = "B13BWWWzzzzzWN";
465 desc->subformat = "WB21BB16B10zWWzDDz";
468 desc->format = "zWWWWzzzzWWzzl";
471 desc->format = "zWWWWzzzzWNzzl";
472 desc->subformat = "WWzWWDDzz";
481 desc->format = "WzzzzzzzzN";
482 desc->subformat = "z";
485 DEBUG(0,("check_printq_info: invalid level %d\n",
489 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
490 DEBUG(0,("check_printq_info: invalid format %s\n",
491 id1 ? id1 : "<NULL>" ));
494 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
495 DEBUG(0,("check_printq_info: invalid subformat %s\n",
496 id2 ? id2 : "<NULL>" ));
503 #define RAP_JOB_STATUS_QUEUED 0
504 #define RAP_JOB_STATUS_PAUSED 1
505 #define RAP_JOB_STATUS_SPOOLING 2
506 #define RAP_JOB_STATUS_PRINTING 3
507 #define RAP_JOB_STATUS_PRINTED 4
509 #define RAP_QUEUE_STATUS_PAUSED 1
510 #define RAP_QUEUE_STATUS_ERROR 2
512 /* turn a print job status into a on the wire status
514 static int printj_spoolss_status(int v)
516 if (v == JOB_STATUS_QUEUED)
517 return RAP_JOB_STATUS_QUEUED;
518 if (v & JOB_STATUS_PAUSED)
519 return RAP_JOB_STATUS_PAUSED;
520 if (v & JOB_STATUS_SPOOLING)
521 return RAP_JOB_STATUS_SPOOLING;
522 if (v & JOB_STATUS_PRINTING)
523 return RAP_JOB_STATUS_PRINTING;
527 /* turn a print queue status into a on the wire status
529 static int printq_spoolss_status(int v)
531 if (v == PRINTER_STATUS_OK)
533 if (v & PRINTER_STATUS_PAUSED)
534 return RAP_QUEUE_STATUS_PAUSED;
535 return RAP_QUEUE_STATUS_ERROR;
538 static void fill_spoolss_printjob_info(int uLevel,
539 struct pack_desc *desc,
540 struct spoolss_JobInfo2 *info2,
543 time_t t = spoolss_Time_to_time_t(&info2->submitted);
545 /* the client expects localtime */
546 t -= get_time_zone(t);
548 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
550 PACKS(desc,"B21", info2->user_name); /* szUserName */
551 PACKS(desc,"B",""); /* pad */
552 PACKS(desc,"B16",""); /* szNotifyName */
553 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
554 PACKS(desc,"z",""); /* pszParms */
555 PACKI(desc,"W",n+1); /* uPosition */
556 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
557 PACKS(desc,"z",""); /* pszStatus */
558 PACKI(desc,"D", t); /* ulSubmitted */
559 PACKI(desc,"D", info2->size); /* ulSize */
560 PACKS(desc,"z", info2->document_name); /* pszComment */
562 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
563 PACKI(desc,"W", info2->priority); /* uPriority */
564 PACKS(desc,"z", info2->user_name); /* pszUserName */
565 PACKI(desc,"W",n+1); /* uPosition */
566 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
567 PACKI(desc,"D",t); /* ulSubmitted */
568 PACKI(desc,"D", info2->size); /* ulSize */
569 PACKS(desc,"z","Samba"); /* pszComment */
570 PACKS(desc,"z", info2->document_name); /* pszDocument */
572 PACKS(desc,"z",""); /* pszNotifyName */
573 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
574 PACKS(desc,"z",""); /* pszParms */
575 PACKS(desc,"z",""); /* pszStatus */
576 PACKS(desc,"z", info2->printer_name); /* pszQueue */
577 PACKS(desc,"z","lpd"); /* pszQProcName */
578 PACKS(desc,"z",""); /* pszQProcParms */
579 PACKS(desc,"z","NULL"); /* pszDriverName */
580 PackDriverData(desc); /* pDriverData */
581 PACKS(desc,"z",""); /* pszPrinterName */
582 } else if (uLevel == 4) { /* OS2 */
583 PACKS(desc,"z",""); /* pszSpoolFileName */
584 PACKS(desc,"z",""); /* pszPortName */
585 PACKS(desc,"z",""); /* pszStatus */
586 PACKI(desc,"D",0); /* ulPagesSpooled */
587 PACKI(desc,"D",0); /* ulPagesSent */
588 PACKI(desc,"D",0); /* ulPagesPrinted */
589 PACKI(desc,"D",0); /* ulTimePrinted */
590 PACKI(desc,"D",0); /* ulExtendJobStatus */
591 PACKI(desc,"D",0); /* ulStartPage */
592 PACKI(desc,"D",0); /* ulEndPage */
597 /********************************************************************
598 Respond to the DosPrintQInfo command with a level of 52
599 This is used to get printer driver information for Win9x clients
600 ********************************************************************/
601 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
602 struct pack_desc* desc, int count,
603 const char *printer_name)
607 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
608 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
609 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
611 PACKI(desc, "W", 0x0400); /* don't know */
612 PACKS(desc, "z", driver->driver_name); /* long printer name */
613 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
614 PACKS(desc, "z", driver->data_file); /* Datafile name */
615 PACKS(desc, "z", driver->monitor_name); /* language monitor */
617 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
618 standard_sub_basic( "", "", location, sizeof(location)-1 );
619 PACKS(desc,"z", location); /* share to retrieve files */
621 PACKS(desc,"z", driver->default_datatype); /* default data type */
622 PACKS(desc,"z", driver->help_file); /* helpfile name */
623 PACKS(desc,"z", driver->driver_path); /* driver name */
625 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
626 DEBUG(3,("Driver: %s:\n",driver->driver_path));
627 DEBUG(3,("Data File: %s:\n",driver->data_file));
628 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
629 DEBUG(3,("Driver Location: %s:\n",location));
630 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
631 DEBUG(3,("Help File: %s:\n",driver->help_file));
632 PACKI(desc,"N",count); /* number of files to copy */
634 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
636 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
637 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
638 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
643 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
646 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
648 desc->errcode=NERR_Success;
652 static const char *strip_unc(const char *unc)
660 if ((p = strrchr(unc, '\\')) != NULL) {
667 static void fill_printq_info(int uLevel,
668 struct pack_desc* desc,
670 union spoolss_JobInfo *job_info,
671 struct spoolss_DriverInfo3 *driver_info,
672 struct spoolss_PrinterInfo2 *printer_info)
678 PACKS(desc,"B13", strip_unc(printer_info->printername));
683 PACKS(desc,"z", strip_unc(printer_info->printername));
686 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
690 if (uLevel == 1 || uLevel == 2) {
691 PACKS(desc,"B",""); /* alignment */
692 PACKI(desc,"W",5); /* priority */
693 PACKI(desc,"W",0); /* start time */
694 PACKI(desc,"W",0); /* until time */
695 PACKS(desc,"z",""); /* pSepFile */
696 PACKS(desc,"z","lpd"); /* pPrProc */
697 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
698 PACKS(desc,"z",""); /* pParms */
699 if (printer_info->printername == NULL) {
700 PACKS(desc,"z","UNKNOWN PRINTER");
701 PACKI(desc,"W",LPSTAT_ERROR);
703 PACKS(desc,"z", printer_info->comment);
704 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
706 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
709 if (uLevel == 3 || uLevel == 4) {
710 PACKI(desc,"W",5); /* uPriority */
711 PACKI(desc,"W",0); /* uStarttime */
712 PACKI(desc,"W",0); /* uUntiltime */
713 PACKI(desc,"W",5); /* pad1 */
714 PACKS(desc,"z",""); /* pszSepFile */
715 PACKS(desc,"z","WinPrint"); /* pszPrProc */
716 PACKS(desc,"z",NULL); /* pszParms */
717 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
718 /* "don't ask" that it's done this way to fix corrupted
719 Win9X/ME printer comments. */
720 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
721 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
722 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
723 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
724 PackDriverData(desc); /* pDriverData */
727 if (uLevel == 2 || uLevel == 4) {
729 for (i = 0; i < count; i++) {
730 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
735 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
738 /* This function returns the number of files for a given driver */
739 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
743 /* count the number of files */
744 while (driver->dependent_files && *driver->dependent_files[result])
750 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
751 char *param, int tpscnt,
752 char *data, int tdscnt,
753 int mdrcnt,int mprcnt,
754 char **rdata,char **rparam,
755 int *rdata_len,int *rparam_len)
757 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
758 char *str2 = skip_string(param,tpscnt,str1);
759 char *p = skip_string(param,tpscnt,str2);
764 struct pack_desc desc;
767 WERROR werr = WERR_OK;
768 TALLOC_CTX *mem_ctx = talloc_tos();
770 struct rpc_pipe_client *cli = NULL;
771 struct policy_handle handle;
772 struct spoolss_DevmodeContainer devmode_ctr;
773 union spoolss_DriverInfo driver_info;
774 union spoolss_JobInfo *job_info;
775 union spoolss_PrinterInfo printer_info;
777 if (!str1 || !str2 || !p) {
780 memset((char *)&desc,'\0',sizeof(desc));
782 p = skip_string(param,tpscnt,p);
786 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
787 str3 = get_safe_str_ptr(param,tpscnt,p,4);
788 /* str3 may be null here and is checked in check_printq_info(). */
790 /* remove any trailing username */
791 if ((p = strchr_m(QueueName,'%')))
794 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
796 /* check it's a supported varient */
797 if (!prefix_ok(str1,"zWrLh"))
799 if (!check_printq_info(&desc,uLevel,str2,str3)) {
801 * Patch from Scott Moomaw <scott@bridgewater.edu>
802 * to return the 'invalid info level' error if an
803 * unknown level was requested.
807 *rparam = smb_realloc_limit(*rparam,*rparam_len);
811 SSVALS(*rparam,0,ERRunknownlevel);
819 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
820 rpc_spoolss_dispatch, conn->server_info,
822 if (!NT_STATUS_IS_OK(status)) {
823 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
825 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
829 ZERO_STRUCT(devmode_ctr);
831 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
838 if (!NT_STATUS_IS_OK(status)) {
839 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
842 if (!W_ERROR_IS_OK(werr)) {
843 desc.errcode = W_ERROR_V(werr);
847 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
852 if (!W_ERROR_IS_OK(werr)) {
853 desc.errcode = W_ERROR_V(werr);
858 uint32_t server_major_version;
859 uint32_t server_minor_version;
861 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
869 &server_major_version,
870 &server_minor_version);
871 if (!W_ERROR_IS_OK(werr)) {
872 desc.errcode = W_ERROR_V(werr);
876 count = get_printerdrivernumber(&driver_info.info3);
877 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
880 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
888 if (!W_ERROR_IS_OK(werr)) {
889 desc.errcode = W_ERROR_V(werr);
897 *rdata = smb_realloc_limit(*rdata,mdrcnt);
902 desc.buflen = mdrcnt;
905 * Don't return data but need to get correct length
906 * init_package will return wrong size if buflen=0
908 desc.buflen = getlen(desc.format);
909 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
912 if (init_package(&desc,1,count)) {
913 desc.subcount = count;
914 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
917 *rdata_len = desc.usedlen;
920 * We must set the return code to ERRbuftoosmall
921 * in order to support lanman style printing with Win NT/2k
924 if (!mdrcnt && lp_disable_spoolss())
925 desc.errcode = ERRbuftoosmall;
928 if (cli && is_valid_policy_hnd(&handle)) {
929 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
932 *rdata_len = desc.usedlen;
934 *rparam = smb_realloc_limit(*rparam,*rparam_len);
939 SSVALS(*rparam,0,desc.errcode);
941 SSVAL(*rparam,4,desc.neededlen);
943 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
950 /****************************************************************************
951 View list of all print jobs on all queues.
952 ****************************************************************************/
954 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
955 char *param, int tpscnt,
956 char *data, int tdscnt,
957 int mdrcnt, int mprcnt,
958 char **rdata, char** rparam,
959 int *rdata_len, int *rparam_len)
961 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
962 char *output_format1 = skip_string(param,tpscnt,param_format);
963 char *p = skip_string(param,tpscnt,output_format1);
964 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
965 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
967 struct pack_desc desc;
968 int *subcntarr = NULL;
969 int queuecnt = 0, subcnt = 0, succnt = 0;
971 WERROR werr = WERR_OK;
972 TALLOC_CTX *mem_ctx = talloc_tos();
974 struct rpc_pipe_client *cli = NULL;
975 struct spoolss_DevmodeContainer devmode_ctr;
976 uint32_t num_printers;
977 union spoolss_PrinterInfo *printer_info;
978 union spoolss_DriverInfo *driver_info;
979 union spoolss_JobInfo **job_info;
981 if (!param_format || !output_format1 || !p) {
985 memset((char *)&desc,'\0',sizeof(desc));
987 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
989 if (!prefix_ok(param_format,"WrLeh")) {
992 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
994 * Patch from Scott Moomaw <scott@bridgewater.edu>
995 * to return the 'invalid info level' error if an
996 * unknown level was requested.
1000 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1004 SSVALS(*rparam,0,ERRunknownlevel);
1010 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1011 rpc_spoolss_dispatch, conn->server_info,
1013 if (!NT_STATUS_IS_OK(status)) {
1014 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1015 nt_errstr(status)));
1016 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1020 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1022 cli->srv_name_slash,
1027 if (!W_ERROR_IS_OK(werr)) {
1028 desc.errcode = W_ERROR_V(werr);
1032 queuecnt = num_printers;
1034 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1035 if (job_info == NULL) {
1039 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1040 if (driver_info == NULL) {
1044 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1045 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1050 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1056 desc.buflen = mdrcnt;
1059 for (i = 0; i < num_printers; i++) {
1062 struct policy_handle handle;
1063 const char *printername;
1065 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1066 if (printername == NULL) {
1070 ZERO_STRUCT(handle);
1071 ZERO_STRUCT(devmode_ctr);
1073 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1080 if (!NT_STATUS_IS_OK(status)) {
1081 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1084 if (!W_ERROR_IS_OK(werr)) {
1085 desc.errcode = W_ERROR_V(werr);
1089 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1097 if (!W_ERROR_IS_OK(werr)) {
1098 desc.errcode = W_ERROR_V(werr);
1103 uint32_t server_major_version;
1104 uint32_t server_minor_version;
1106 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1114 &server_major_version,
1115 &server_minor_version);
1116 if (!W_ERROR_IS_OK(werr)) {
1117 desc.errcode = W_ERROR_V(werr);
1122 subcntarr[i] = num_jobs;
1123 subcnt += subcntarr[i];
1125 if (cli && is_valid_policy_hnd(&handle)) {
1126 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1130 if (init_package(&desc,queuecnt,subcnt)) {
1131 for (i = 0; i < num_printers; i++) {
1132 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1133 if (desc.errcode == NERR_Success) {
1139 SAFE_FREE(subcntarr);
1141 *rdata_len = desc.usedlen;
1143 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1147 SSVALS(*rparam,0,desc.errcode);
1149 SSVAL(*rparam,4,succnt);
1150 SSVAL(*rparam,6,queuecnt);
1156 SAFE_FREE(subcntarr);
1161 /****************************************************************************
1162 Get info level for a server list query.
1163 ****************************************************************************/
1165 static bool check_server_info(int uLevel, char* id)
1169 if (strcmp(id,"B16") != 0) {
1174 if (strcmp(id,"B16BBDz") != 0) {
1184 struct srv_info_struct {
1192 /*******************************************************************
1193 Get server info lists from the files saved by nmbd. Return the
1195 ******************************************************************/
1197 static int get_server_info(uint32 servertype,
1198 struct srv_info_struct **servers,
1204 bool local_list_only;
1207 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1209 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1213 /* request for everything is code for request all servers */
1214 if (servertype == SV_TYPE_ALL) {
1215 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1218 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1220 DEBUG(4,("Servertype search: %8x\n",servertype));
1222 for (i=0;lines[i];i++) {
1224 struct srv_info_struct *s;
1225 const char *ptr = lines[i];
1227 TALLOC_CTX *frame = NULL;
1234 if (count == alloced) {
1236 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1238 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1242 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1244 s = &(*servers)[count];
1246 frame = talloc_stackframe();
1248 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1252 fstrcpy(s->name, p);
1255 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1261 s->comment[0] = '\0';
1262 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1266 fstrcpy(s->comment, p);
1267 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1269 s->domain[0] = '\0';
1270 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1271 /* this allows us to cope with an old nmbd */
1272 fstrcpy(s->domain,lp_workgroup());
1274 fstrcpy(s->domain, p);
1278 if (sscanf(stype,"%X",&s->type) != 1) {
1279 DEBUG(4,("r:host file "));
1283 /* Filter the servers/domains we return based on what was asked for. */
1285 /* Check to see if we are being asked for a local list only. */
1286 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1287 DEBUG(4,("r: local list only"));
1291 /* doesn't match up: don't want it */
1292 if (!(servertype & s->type)) {
1293 DEBUG(4,("r:serv type "));
1297 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1298 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1299 DEBUG(4,("s: dom mismatch "));
1303 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1307 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1308 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1311 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1312 s->name, s->type, s->comment, s->domain));
1313 s->server_added = True;
1316 DEBUG(4,("%20s %8x %25s %15s\n",
1317 s->name, s->type, s->comment, s->domain));
1325 /*******************************************************************
1326 Fill in a server info structure.
1327 ******************************************************************/
1329 static int fill_srv_info(struct srv_info_struct *service,
1330 int uLevel, char **buf, int *buflen,
1331 char **stringbuf, int *stringspace, char *baseaddr)
1354 len = strlen(service->comment)+1;
1358 *buflen = struct_len;
1360 return struct_len + len;
1365 if (*buflen < struct_len) {
1372 p2 = p + struct_len;
1373 l2 = *buflen - struct_len;
1381 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1385 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1386 SIVAL(p,18,service->type);
1387 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1388 len += CopyAndAdvance(&p2,service->comment,&l2);
1393 *buf = p + struct_len;
1394 *buflen -= struct_len;
1405 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1407 return StrCaseCmp(s1->name,s2->name);
1410 /****************************************************************************
1411 View list of servers available (or possibly domains). The info is
1412 extracted from lists saved by nmbd on the local host.
1413 ****************************************************************************/
1415 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1416 char *param, int tpscnt,
1417 char *data, int tdscnt,
1418 int mdrcnt, int mprcnt, char **rdata,
1419 char **rparam, int *rdata_len, int *rparam_len)
1421 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1422 char *str2 = skip_string(param,tpscnt,str1);
1423 char *p = skip_string(param,tpscnt,str2);
1424 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1425 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1426 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1428 int data_len, fixed_len, string_len;
1429 int f_len = 0, s_len = 0;
1430 struct srv_info_struct *servers=NULL;
1431 int counted=0,total=0;
1434 bool domain_request;
1437 if (!str1 || !str2 || !p) {
1441 /* If someone sets all the bits they don't really mean to set
1442 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1445 if (servertype == SV_TYPE_ALL) {
1446 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1449 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1450 any other bit (they may just set this bit on its own) they
1451 want all the locally seen servers. However this bit can be
1452 set on its own so set the requested servers to be
1453 ALL - DOMAIN_ENUM. */
1455 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1456 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1459 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1460 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1464 if (!prefix_ok(str1,"WrLehD")) {
1467 if (!check_server_info(uLevel,str2)) {
1471 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1472 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1473 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1475 if (strcmp(str1, "WrLehDz") == 0) {
1476 if (skip_string(param,tpscnt,p) == NULL) {
1479 pull_ascii_fstring(domain, p);
1481 fstrcpy(domain, lp_workgroup());
1484 DEBUG(4, ("domain [%s]\n", domain));
1486 if (lp_browse_list()) {
1487 total = get_server_info(servertype,&servers,domain);
1490 data_len = fixed_len = string_len = 0;
1493 TYPESAFE_QSORT(servers, total, srv_comp);
1496 char *lastname=NULL;
1498 for (i=0;i<total;i++) {
1499 struct srv_info_struct *s = &servers[i];
1501 if (lastname && strequal(lastname,s->name)) {
1505 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1506 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1507 i, s->name, s->type, s->comment, s->domain));
1509 if (data_len < buf_len) {
1512 string_len += s_len;
1519 *rdata_len = fixed_len + string_len;
1520 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1525 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1531 char *lastname=NULL;
1532 int count2 = counted;
1534 for (i = 0; i < total && count2;i++) {
1535 struct srv_info_struct *s = &servers[i];
1537 if (lastname && strequal(lastname,s->name)) {
1541 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1542 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1543 i, s->name, s->type, s->comment, s->domain));
1549 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1553 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1555 SSVAL(*rparam,4,counted);
1556 SSVAL(*rparam,6,counted+missed);
1560 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1561 domain,uLevel,counted,counted+missed));
1566 static int srv_name_match(const char *n1, const char *n2)
1569 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1571 * In Windows, FirstNameToReturn need not be an exact match:
1572 * the server will return a list of servers that exist on
1573 * the network greater than or equal to the FirstNameToReturn.
1575 int ret = StrCaseCmp(n1, n2);
1584 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1585 char *param, int tpscnt,
1586 char *data, int tdscnt,
1587 int mdrcnt, int mprcnt, char **rdata,
1588 char **rparam, int *rdata_len, int *rparam_len)
1590 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1591 char *str2 = skip_string(param,tpscnt,str1);
1592 char *p = skip_string(param,tpscnt,str2);
1593 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1594 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1595 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1597 int data_len, fixed_len, string_len;
1598 int f_len = 0, s_len = 0;
1599 struct srv_info_struct *servers=NULL;
1600 int counted=0,first=0,total=0;
1604 bool domain_request;
1607 if (!str1 || !str2 || !p) {
1611 /* If someone sets all the bits they don't really mean to set
1612 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1615 if (servertype == SV_TYPE_ALL) {
1616 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1619 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1620 any other bit (they may just set this bit on its own) they
1621 want all the locally seen servers. However this bit can be
1622 set on its own so set the requested servers to be
1623 ALL - DOMAIN_ENUM. */
1625 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1626 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1629 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1630 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1634 if (strcmp(str1, "WrLehDzz") != 0) {
1637 if (!check_server_info(uLevel,str2)) {
1641 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1642 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1643 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1645 if (skip_string(param,tpscnt,p) == NULL) {
1648 pull_ascii_fstring(domain, p);
1649 if (domain[0] == '\0') {
1650 fstrcpy(domain, lp_workgroup());
1652 p = skip_string(param,tpscnt,p);
1653 if (skip_string(param,tpscnt,p) == NULL) {
1656 pull_ascii_fstring(first_name, p);
1658 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1659 domain, first_name));
1661 if (lp_browse_list()) {
1662 total = get_server_info(servertype,&servers,domain);
1665 data_len = fixed_len = string_len = 0;
1668 TYPESAFE_QSORT(servers, total, srv_comp);
1670 if (first_name[0] != '\0') {
1671 struct srv_info_struct *first_server = NULL;
1673 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1674 srv_name_match, first_server);
1676 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1678 * The binary search may not find the exact match
1679 * so we need to search backward to find the first match
1681 * This implements the strange matching windows
1682 * implements. (see the comment in srv_name_match().
1686 ret = StrCaseCmp(first_name,
1687 servers[first-1].name);
1694 /* we should return no entries */
1700 char *lastname=NULL;
1702 for (i=first;i<total;i++) {
1703 struct srv_info_struct *s = &servers[i];
1705 if (lastname && strequal(lastname,s->name)) {
1709 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1710 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1711 i, s->name, s->type, s->comment, s->domain));
1713 if (data_len < buf_len) {
1716 string_len += s_len;
1723 *rdata_len = fixed_len + string_len;
1724 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1729 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1735 char *lastname=NULL;
1736 int count2 = counted;
1738 for (i = first; i < total && count2;i++) {
1739 struct srv_info_struct *s = &servers[i];
1741 if (lastname && strequal(lastname,s->name)) {
1745 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1746 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1747 i, s->name, s->type, s->comment, s->domain));
1753 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1757 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1759 SSVAL(*rparam,4,counted);
1760 SSVAL(*rparam,6,counted+missed);
1762 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1763 domain,uLevel,first,first_name,
1764 first < total ? servers[first].name : "",
1765 counted,counted+missed));
1772 /****************************************************************************
1773 command 0x34 - suspected of being a "Lookup Names" stub api
1774 ****************************************************************************/
1776 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1777 char *param, int tpscnt,
1778 char *data, int tdscnt,
1779 int mdrcnt, int mprcnt, char **rdata,
1780 char **rparam, int *rdata_len, int *rparam_len)
1782 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1783 char *str2 = skip_string(param,tpscnt,str1);
1784 char *p = skip_string(param,tpscnt,str2);
1785 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1786 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1790 if (!str1 || !str2 || !p) {
1794 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1795 str1, str2, p, uLevel, buf_len));
1797 if (!prefix_ok(str1,"zWrLeh")) {
1804 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1809 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1811 SSVAL(*rparam,4,counted);
1812 SSVAL(*rparam,6,counted+missed);
1817 /****************************************************************************
1818 get info about a share
1819 ****************************************************************************/
1821 static bool check_share_info(int uLevel, char* id)
1825 if (strcmp(id,"B13") != 0) {
1830 /* Level-2 descriptor is allowed (and ignored) */
1831 if (strcmp(id,"B13BWz") != 0 &&
1832 strcmp(id,"B13BWzWWWzB9B") != 0) {
1837 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1842 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1852 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1853 char** buf, int* buflen,
1854 char** stringbuf, int* stringspace, char* baseaddr)
1883 len += StrlenExpanded(conn,snum,lp_comment(snum));
1886 len += strlen(lp_pathname(snum)) + 1;
1889 *buflen = struct_len;
1894 return struct_len + len;
1899 if ((*buflen) < struct_len) {
1907 p2 = p + struct_len;
1908 l2 = (*buflen) - struct_len;
1915 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1921 type = STYPE_DISKTREE;
1922 if (lp_print_ok(snum)) {
1923 type = STYPE_PRINTQ;
1925 if (strequal("IPC",lp_fstype(snum))) {
1928 SSVAL(p,14,type); /* device type */
1929 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1930 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1934 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1935 SSVALS(p,22,-1); /* max uses */
1936 SSVAL(p,24,1); /* current uses */
1937 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1938 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1939 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1943 memset(p+40,0,SHPWLEN+2);
1954 (*buf) = p + struct_len;
1955 (*buflen) -= struct_len;
1957 (*stringspace) = l2;
1966 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1967 char *param, int tpscnt,
1968 char *data, int tdscnt,
1969 int mdrcnt,int mprcnt,
1970 char **rdata,char **rparam,
1971 int *rdata_len,int *rparam_len)
1973 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1974 char *str2 = skip_string(param,tpscnt,str1);
1975 char *netname = skip_string(param,tpscnt,str2);
1976 char *p = skip_string(param,tpscnt,netname);
1977 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1980 if (!str1 || !str2 || !netname || !p) {
1984 snum = find_service(netname);
1989 /* check it's a supported varient */
1990 if (!prefix_ok(str1,"zWrLh")) {
1993 if (!check_share_info(uLevel,str2)) {
1997 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2002 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2003 if (*rdata_len < 0) {
2008 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2012 SSVAL(*rparam,0,NERR_Success);
2013 SSVAL(*rparam,2,0); /* converter word */
2014 SSVAL(*rparam,4,*rdata_len);
2019 /****************************************************************************
2020 View the list of available shares.
2022 This function is the server side of the NetShareEnum() RAP call.
2023 It fills the return buffer with share names and share comments.
2024 Note that the return buffer normally (in all known cases) allows only
2025 twelve byte strings for share names (plus one for a nul terminator).
2026 Share names longer than 12 bytes must be skipped.
2027 ****************************************************************************/
2029 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2030 char *param, int tpscnt,
2031 char *data, int tdscnt,
2039 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2040 char *str2 = skip_string(param,tpscnt,str1);
2041 char *p = skip_string(param,tpscnt,str2);
2042 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2043 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2046 int total=0,counted=0;
2047 bool missed = False;
2049 int data_len, fixed_len, string_len;
2050 int f_len = 0, s_len = 0;
2052 if (!str1 || !str2 || !p) {
2056 if (!prefix_ok(str1,"WrLeh")) {
2059 if (!check_share_info(uLevel,str2)) {
2063 /* Ensure all the usershares are loaded. */
2065 load_registry_shares();
2066 count = load_usershare_shares();
2069 data_len = fixed_len = string_len = 0;
2070 for (i=0;i<count;i++) {
2071 fstring servicename_dos;
2072 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2075 push_ascii_fstring(servicename_dos, lp_servicename(i));
2076 /* Maximum name length = 13. */
2077 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2079 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2080 if (data_len < buf_len) {
2083 string_len += s_len;
2090 *rdata_len = fixed_len + string_len;
2091 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2096 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2101 for( i = 0; i < count; i++ ) {
2102 fstring servicename_dos;
2103 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2107 push_ascii_fstring(servicename_dos, lp_servicename(i));
2108 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2109 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2116 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2120 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2122 SSVAL(*rparam,4,counted);
2123 SSVAL(*rparam,6,total);
2125 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2126 counted,total,uLevel,
2127 buf_len,*rdata_len,mdrcnt));
2132 /****************************************************************************
2134 ****************************************************************************/
2136 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2137 char *param, int tpscnt,
2138 char *data, int tdscnt,
2139 int mdrcnt,int mprcnt,
2140 char **rdata,char **rparam,
2141 int *rdata_len,int *rparam_len)
2143 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2144 char *str2 = skip_string(param,tpscnt,str1);
2145 char *p = skip_string(param,tpscnt,str2);
2146 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2149 char *pathname = NULL;
2150 unsigned int offset;
2152 size_t converted_size;
2154 WERROR werr = WERR_OK;
2155 TALLOC_CTX *mem_ctx = talloc_tos();
2157 struct rpc_pipe_client *cli = NULL;
2158 union srvsvc_NetShareInfo info;
2159 struct srvsvc_NetShareInfo2 info2;
2161 if (!str1 || !str2 || !p) {
2165 /* check it's a supported varient */
2166 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2169 if (!check_share_info(uLevel,str2)) {
2176 /* Do we have a string ? */
2177 if (skip_string(data,mdrcnt,data) == NULL) {
2180 pull_ascii_fstring(sharename,data);
2186 /* only support disk share adds */
2187 if (SVAL(data,14)!=STYPE_DISKTREE) {
2191 offset = IVAL(data, 16);
2192 if (offset >= mdrcnt) {
2193 res = ERRinvalidparam;
2197 /* Do we have a string ? */
2198 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2201 pull_ascii_fstring(comment, offset? (data+offset) : "");
2203 offset = IVAL(data, 26);
2205 if (offset >= mdrcnt) {
2206 res = ERRinvalidparam;
2210 /* Do we have a string ? */
2211 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2215 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2216 offset ? (data+offset) : "", &converted_size))
2218 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2226 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2227 rpc_srvsvc_dispatch, conn->server_info,
2229 if (!NT_STATUS_IS_OK(status)) {
2230 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2231 nt_errstr(status)));
2232 res = W_ERROR_V(ntstatus_to_werror(status));
2236 info2.name = sharename;
2237 info2.type = STYPE_DISKTREE;
2238 info2.comment = comment;
2239 info2.permissions = 0;
2240 info2.max_users = 0;
2241 info2.current_users = 0;
2242 info2.path = pathname;
2243 info2.password = NULL;
2245 info.info2 = &info2;
2247 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2248 cli->srv_name_slash,
2253 if (!NT_STATUS_IS_OK(status)) {
2254 res = W_ERROR_V(ntstatus_to_werror(status));
2257 if (!W_ERROR_IS_OK(werr)) {
2258 res = W_ERROR_V(werr);
2263 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2267 SSVAL(*rparam,0,NERR_Success);
2268 SSVAL(*rparam,2,0); /* converter word */
2269 SSVAL(*rparam,4,*rdata_len);
2277 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2282 SSVAL(*rparam,0,res);
2287 /****************************************************************************
2288 view list of groups available
2289 ****************************************************************************/
2291 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2292 char *param, int tpscnt,
2293 char *data, int tdscnt,
2294 int mdrcnt,int mprcnt,
2295 char **rdata,char **rparam,
2296 int *rdata_len,int *rparam_len)
2300 int resume_context, cli_buf_size;
2301 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2302 char *str2 = skip_string(param,tpscnt,str1);
2303 char *p = skip_string(param,tpscnt,str2);
2305 uint32_t num_groups;
2306 uint32_t resume_handle;
2307 struct rpc_pipe_client *samr_pipe;
2308 struct policy_handle samr_handle, domain_handle;
2311 if (!str1 || !str2 || !p) {
2315 if (strcmp(str1,"WrLeh") != 0) {
2320 * W-> resume context (number of users to skip)
2321 * r -> return parameter pointer to receive buffer
2322 * L -> length of receive buffer
2323 * e -> return parameter number of entries
2324 * h -> return parameter total number of users
2327 if (strcmp("B21",str2) != 0) {
2331 status = rpc_pipe_open_internal(
2332 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2333 conn->server_info, &samr_pipe);
2334 if (!NT_STATUS_IS_OK(status)) {
2335 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2336 nt_errstr(status)));
2340 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2341 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2342 if (!NT_STATUS_IS_OK(status)) {
2343 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2344 nt_errstr(status)));
2348 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2349 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2350 get_global_sam_sid(), &domain_handle);
2351 if (!NT_STATUS_IS_OK(status)) {
2352 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2353 nt_errstr(status)));
2354 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2358 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2359 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2360 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2361 "%d\n", resume_context, cli_buf_size));
2363 *rdata_len = cli_buf_size;
2364 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2371 errflags = NERR_Success;
2376 struct samr_SamArray *sam_entries;
2377 uint32_t num_entries;
2379 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2384 if (!NT_STATUS_IS_OK(status)) {
2385 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2386 "%s\n", nt_errstr(status)));
2390 if (num_entries == 0) {
2391 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2392 "no entries -- done\n"));
2396 for(i=0; i<num_entries; i++) {
2399 name = sam_entries->entries[i].name.string;
2401 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2402 /* set overflow error */
2403 DEBUG(3,("overflow on entry %d group %s\n", i,
2409 /* truncate the name at 21 chars. */
2411 strlcpy(p, name, 21);
2412 DEBUG(10,("adding entry %d group %s\n", i, p));
2414 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2419 if (errflags != NERR_Success) {
2423 TALLOC_FREE(sam_entries);
2426 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2427 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2429 *rdata_len = PTR_DIFF(p,*rdata);
2432 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2436 SSVAL(*rparam, 0, errflags);
2437 SSVAL(*rparam, 2, 0); /* converter word */
2438 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2439 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2444 /*******************************************************************
2445 Get groups that a user is a member of.
2446 ******************************************************************/
2448 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2449 char *param, int tpscnt,
2450 char *data, int tdscnt,
2451 int mdrcnt,int mprcnt,
2452 char **rdata,char **rparam,
2453 int *rdata_len,int *rparam_len)
2455 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2456 char *str2 = skip_string(param,tpscnt,str1);
2457 char *UserName = skip_string(param,tpscnt,str2);
2458 char *p = skip_string(param,tpscnt,UserName);
2459 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2460 const char *level_string;
2466 struct rpc_pipe_client *samr_pipe;
2467 struct policy_handle samr_handle, domain_handle, user_handle;
2468 struct lsa_String name;
2469 struct lsa_Strings names;
2470 struct samr_Ids type, rid;
2471 struct samr_RidWithAttributeArray *rids;
2474 if (!str1 || !str2 || !UserName || !p) {
2479 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2484 /* check it's a supported varient */
2486 if ( strcmp(str1,"zWrLeh") != 0 )
2491 level_string = "B21";
2497 if (strcmp(level_string,str2) != 0)
2500 *rdata_len = mdrcnt + 1024;
2501 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2506 SSVAL(*rparam,0,NERR_Success);
2507 SSVAL(*rparam,2,0); /* converter word */
2510 endp = *rdata + *rdata_len;
2512 status = rpc_pipe_open_internal(
2513 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2514 conn->server_info, &samr_pipe);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2517 nt_errstr(status)));
2521 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2522 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2523 if (!NT_STATUS_IS_OK(status)) {
2524 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2525 nt_errstr(status)));
2529 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2530 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2531 get_global_sam_sid(), &domain_handle);
2532 if (!NT_STATUS_IS_OK(status)) {
2533 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2534 nt_errstr(status)));
2538 name.string = UserName;
2540 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2541 &domain_handle, 1, &name,
2543 if (!NT_STATUS_IS_OK(status)) {
2544 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2545 nt_errstr(status)));
2549 if (type.ids[0] != SID_NAME_USER) {
2550 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2551 sid_type_lookup(type.ids[0])));
2555 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2557 SAMR_USER_ACCESS_GET_GROUPS,
2558 rid.ids[0], &user_handle);
2559 if (!NT_STATUS_IS_OK(status)) {
2560 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2561 nt_errstr(status)));
2565 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2566 &user_handle, &rids);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2569 nt_errstr(status)));
2573 for (i=0; i<rids->count; i++) {
2575 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2577 1, &rids->rids[i].rid,
2579 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2580 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2586 *rdata_len = PTR_DIFF(p,*rdata);
2588 SSVAL(*rparam,4,count); /* is this right?? */
2589 SSVAL(*rparam,6,count); /* is this right?? */
2594 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2596 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2598 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2603 /*******************************************************************
2605 ******************************************************************/
2607 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2608 char *param, int tpscnt,
2609 char *data, int tdscnt,
2610 int mdrcnt,int mprcnt,
2611 char **rdata,char **rparam,
2612 int *rdata_len,int *rparam_len)
2617 int i, resume_context, cli_buf_size;
2618 uint32_t resume_handle;
2620 struct rpc_pipe_client *samr_pipe;
2621 struct policy_handle samr_handle, domain_handle;
2624 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2625 char *str2 = skip_string(param,tpscnt,str1);
2626 char *p = skip_string(param,tpscnt,str2);
2629 if (!str1 || !str2 || !p) {
2633 if (strcmp(str1,"WrLeh") != 0)
2636 * W-> resume context (number of users to skip)
2637 * r -> return parameter pointer to receive buffer
2638 * L -> length of receive buffer
2639 * e -> return parameter number of entries
2640 * h -> return parameter total number of users
2643 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2644 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2645 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2646 resume_context, cli_buf_size));
2649 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2654 /* check it's a supported varient */
2655 if (strcmp("B21",str2) != 0)
2658 *rdata_len = cli_buf_size;
2659 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2665 endp = *rdata + *rdata_len;
2667 status = rpc_pipe_open_internal(
2668 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2669 conn->server_info, &samr_pipe);
2670 if (!NT_STATUS_IS_OK(status)) {
2671 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2672 nt_errstr(status)));
2676 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2677 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2678 if (!NT_STATUS_IS_OK(status)) {
2679 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2680 nt_errstr(status)));
2684 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2685 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2686 get_global_sam_sid(), &domain_handle);
2687 if (!NT_STATUS_IS_OK(status)) {
2688 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2689 nt_errstr(status)));
2690 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2694 errflags=NERR_Success;
2699 struct samr_SamArray *sam_entries;
2700 uint32_t num_entries;
2702 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2708 if (!NT_STATUS_IS_OK(status)) {
2709 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2710 "%s\n", nt_errstr(status)));
2714 if (num_entries == 0) {
2715 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2716 "no entries -- done\n"));
2720 for (i=0; i<num_entries; i++) {
2723 name = sam_entries->entries[i].name.string;
2725 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2726 &&(strlen(name)<=21)) {
2727 strlcpy(p,name,PTR_DIFF(endp,p));
2728 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2729 "username %s\n",count_sent,p));
2733 /* set overflow error */
2734 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2735 "username %s\n",count_sent,name));
2741 if (errflags != NERR_Success) {
2745 TALLOC_FREE(sam_entries);
2748 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2749 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2751 *rdata_len = PTR_DIFF(p,*rdata);
2753 SSVAL(*rparam,0,errflags);
2754 SSVAL(*rparam,2,0); /* converter word */
2755 SSVAL(*rparam,4,count_sent); /* is this right?? */
2756 SSVAL(*rparam,6,num_users); /* is this right?? */
2761 /****************************************************************************
2762 Get the time of day info.
2763 ****************************************************************************/
2765 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2766 char *param, int tpscnt,
2767 char *data, int tdscnt,
2768 int mdrcnt,int mprcnt,
2769 char **rdata,char **rparam,
2770 int *rdata_len,int *rparam_len)
2773 time_t unixdate = time(NULL);
2777 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2783 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2788 SSVAL(*rparam,0,NERR_Success);
2789 SSVAL(*rparam,2,0); /* converter word */
2793 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2794 by NT in a "net time" operation,
2795 it seems to ignore the one below */
2797 /* the client expects to get localtime, not GMT, in this bit
2798 (I think, this needs testing) */
2799 t = localtime(&unixdate);
2804 SIVAL(p,4,0); /* msecs ? */
2805 SCVAL(p,8,t->tm_hour);
2806 SCVAL(p,9,t->tm_min);
2807 SCVAL(p,10,t->tm_sec);
2808 SCVAL(p,11,0); /* hundredths of seconds */
2809 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2810 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2811 SCVAL(p,16,t->tm_mday);
2812 SCVAL(p,17,t->tm_mon + 1);
2813 SSVAL(p,18,1900+t->tm_year);
2814 SCVAL(p,20,t->tm_wday);
2819 /****************************************************************************
2820 Set the user password.
2821 *****************************************************************************/
2823 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2824 char *param, int tpscnt,
2825 char *data, int tdscnt,
2826 int mdrcnt,int mprcnt,
2827 char **rdata,char **rparam,
2828 int *rdata_len,int *rparam_len)
2830 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2833 fstring pass1,pass2;
2835 /* Skip 2 strings. */
2836 p = skip_string(param,tpscnt,np);
2837 p = skip_string(param,tpscnt,p);
2843 /* Do we have a string ? */
2844 if (skip_string(param,tpscnt,p) == NULL) {
2847 pull_ascii_fstring(user,p);
2849 p = skip_string(param,tpscnt,p);
2854 memset(pass1,'\0',sizeof(pass1));
2855 memset(pass2,'\0',sizeof(pass2));
2857 * We use 31 here not 32 as we're checking
2858 * the last byte we want to access is safe.
2860 if (!is_offset_safe(param,tpscnt,p,31)) {
2864 memcpy(pass2,p+16,16);
2867 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2874 SSVAL(*rparam,0,NERR_badpass);
2875 SSVAL(*rparam,2,0); /* converter word */
2877 DEBUG(3,("Set password for <%s>\n",user));
2880 * Attempt to verify the old password against smbpasswd entries
2881 * Win98 clients send old and new password in plaintext for this call.
2885 struct auth_serversupplied_info *server_info = NULL;
2886 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2888 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2891 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2892 SSVAL(*rparam,0,NERR_Success);
2896 TALLOC_FREE(server_info);
2898 data_blob_clear_free(&password);
2902 * If the plaintext change failed, attempt
2903 * the old encrypted method. NT will generate this
2904 * after trying the samr method. Note that this
2905 * method is done as a last resort as this
2906 * password change method loses the NT password hash
2907 * and cannot change the UNIX password as no plaintext
2911 if(SVAL(*rparam,0) != NERR_Success) {
2912 struct samu *hnd = NULL;
2914 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2916 if (change_lanman_password(hnd,(uchar *)pass2)) {
2917 SSVAL(*rparam,0,NERR_Success);
2924 memset((char *)pass1,'\0',sizeof(fstring));
2925 memset((char *)pass2,'\0',sizeof(fstring));
2930 /****************************************************************************
2931 Set the user password (SamOEM version - gets plaintext).
2932 ****************************************************************************/
2934 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2935 char *param, int tpscnt,
2936 char *data, int tdscnt,
2937 int mdrcnt,int mprcnt,
2938 char **rdata,char **rparam,
2939 int *rdata_len,int *rparam_len)
2942 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2944 TALLOC_CTX *mem_ctx = talloc_tos();
2946 struct rpc_pipe_client *cli = NULL;
2947 struct lsa_AsciiString server, account;
2948 struct samr_CryptPassword password;
2949 struct samr_Password hash;
2950 int errcode = NERR_badpass;
2954 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2964 SSVAL(*rparam,0,NERR_badpass);
2967 * Check the parameter definition is correct.
2970 /* Do we have a string ? */
2971 if (skip_string(param,tpscnt,p) == 0) {
2974 if(!strequal(p, "zsT")) {
2975 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2978 p = skip_string(param, tpscnt, p);
2983 /* Do we have a string ? */
2984 if (skip_string(param,tpscnt,p) == 0) {
2987 if(!strequal(p, "B516B16")) {
2988 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2991 p = skip_string(param,tpscnt,p);
2995 /* Do we have a string ? */
2996 if (skip_string(param,tpscnt,p) == 0) {
2999 p += pull_ascii_fstring(user,p);
3001 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3003 if (tdscnt != 532) {
3004 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3008 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3009 if (bufsize != 532) {
3010 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3014 memcpy(password.data, data, 516);
3015 memcpy(hash.hash, data+516, 16);
3017 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3018 rpc_samr_dispatch, conn->server_info,
3020 if (!NT_STATUS_IS_OK(status)) {
3021 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3022 nt_errstr(status)));
3023 errcode = W_ERROR_V(ntstatus_to_werror(status));
3027 init_lsa_AsciiString(&server, global_myname());
3028 init_lsa_AsciiString(&account, user);
3030 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3035 if (!NT_STATUS_IS_OK(status)) {
3036 errcode = W_ERROR_V(ntstatus_to_werror(status));
3040 errcode = NERR_Success;
3042 SSVAL(*rparam,0,errcode);
3043 SSVAL(*rparam,2,0); /* converter word */
3048 /****************************************************************************
3051 ****************************************************************************/
3053 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3054 char *param, int tpscnt,
3055 char *data, int tdscnt,
3056 int mdrcnt,int mprcnt,
3057 char **rdata,char **rparam,
3058 int *rdata_len,int *rparam_len)
3060 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3061 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3062 char *str2 = skip_string(param,tpscnt,str1);
3063 char *p = skip_string(param,tpscnt,str2);
3067 WERROR werr = WERR_OK;
3069 TALLOC_CTX *mem_ctx = talloc_tos();
3071 struct rpc_pipe_client *cli = NULL;
3072 struct policy_handle handle;
3073 struct spoolss_DevmodeContainer devmode_ctr;
3074 enum spoolss_JobControl command;
3076 if (!str1 || !str2 || !p) {
3080 * We use 1 here not 2 as we're checking
3081 * the last byte we want to access is safe.
3083 if (!is_offset_safe(param,tpscnt,p,1)) {
3086 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3089 /* check it's a supported varient */
3090 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3094 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3100 ZERO_STRUCT(handle);
3102 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3103 rpc_spoolss_dispatch, conn->server_info,
3105 if (!NT_STATUS_IS_OK(status)) {
3106 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3107 nt_errstr(status)));
3108 errcode = W_ERROR_V(ntstatus_to_werror(status));
3112 ZERO_STRUCT(devmode_ctr);
3114 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3118 JOB_ACCESS_ADMINISTER,
3121 if (!NT_STATUS_IS_OK(status)) {
3122 errcode = W_ERROR_V(ntstatus_to_werror(status));
3125 if (!W_ERROR_IS_OK(werr)) {
3126 errcode = W_ERROR_V(werr);
3130 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3131 * and NERR_DestNotFound if share did not exist */
3133 errcode = NERR_Success;
3136 case 81: /* delete */
3137 command = SPOOLSS_JOB_CONTROL_DELETE;
3139 case 82: /* pause */
3140 command = SPOOLSS_JOB_CONTROL_PAUSE;
3142 case 83: /* resume */
3143 command = SPOOLSS_JOB_CONTROL_RESUME;
3146 errcode = NERR_notsupported;
3150 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3153 NULL, /* unique ptr ctr */
3156 if (!NT_STATUS_IS_OK(status)) {
3157 errcode = W_ERROR_V(ntstatus_to_werror(status));
3160 if (!W_ERROR_IS_OK(werr)) {
3161 errcode = W_ERROR_V(werr);
3166 if (cli && is_valid_policy_hnd(&handle)) {
3167 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3170 SSVAL(*rparam,0,errcode);
3171 SSVAL(*rparam,2,0); /* converter word */
3176 /****************************************************************************
3177 Purge a print queue - or pause or resume it.
3178 ****************************************************************************/
3180 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3181 char *param, int tpscnt,
3182 char *data, int tdscnt,
3183 int mdrcnt,int mprcnt,
3184 char **rdata,char **rparam,
3185 int *rdata_len,int *rparam_len)
3187 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3188 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3189 char *str2 = skip_string(param,tpscnt,str1);
3190 char *QueueName = skip_string(param,tpscnt,str2);
3191 int errcode = NERR_notsupported;
3192 WERROR werr = WERR_OK;
3195 TALLOC_CTX *mem_ctx = talloc_tos();
3196 struct rpc_pipe_client *cli = NULL;
3197 struct policy_handle handle;
3198 struct spoolss_SetPrinterInfoCtr info_ctr;
3199 struct spoolss_DevmodeContainer devmode_ctr;
3200 struct sec_desc_buf secdesc_ctr;
3201 enum spoolss_PrinterControl command;
3203 if (!str1 || !str2 || !QueueName) {
3207 /* check it's a supported varient */
3208 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3212 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3218 if (skip_string(param,tpscnt,QueueName) == NULL) {
3222 ZERO_STRUCT(handle);
3224 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3225 rpc_spoolss_dispatch, conn->server_info,
3227 if (!NT_STATUS_IS_OK(status)) {
3228 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3229 nt_errstr(status)));
3230 errcode = W_ERROR_V(ntstatus_to_werror(status));
3234 ZERO_STRUCT(devmode_ctr);
3236 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3240 SEC_FLAG_MAXIMUM_ALLOWED,
3243 if (!NT_STATUS_IS_OK(status)) {
3244 errcode = W_ERROR_V(ntstatus_to_werror(status));
3247 if (!W_ERROR_IS_OK(werr)) {
3248 errcode = W_ERROR_V(werr);
3253 case 74: /* Pause queue */
3254 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3256 case 75: /* Resume queue */
3257 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3259 case 103: /* Purge */
3260 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3263 werr = WERR_NOT_SUPPORTED;
3267 if (!W_ERROR_IS_OK(werr)) {
3268 errcode = W_ERROR_V(werr);
3272 ZERO_STRUCT(info_ctr);
3273 ZERO_STRUCT(secdesc_ctr);
3275 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3282 if (!NT_STATUS_IS_OK(status)) {
3283 errcode = W_ERROR_V(ntstatus_to_werror(status));
3286 if (!W_ERROR_IS_OK(werr)) {
3287 errcode = W_ERROR_V(werr);
3291 errcode = W_ERROR_V(werr);
3295 if (cli && is_valid_policy_hnd(&handle)) {
3296 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3299 SSVAL(*rparam,0,errcode);
3300 SSVAL(*rparam,2,0); /* converter word */
3305 /****************************************************************************
3306 set the property of a print job (undocumented?)
3307 ? function = 0xb -> set name of print job
3308 ? function = 0x6 -> move print job up/down
3309 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3310 or <WWsTP> <WB21BB16B10zWWzDDz>
3311 ****************************************************************************/
3313 static int check_printjob_info(struct pack_desc* desc,
3314 int uLevel, char* id)
3316 desc->subformat = NULL;
3318 case 0: desc->format = "W"; break;
3319 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3320 case 2: desc->format = "WWzWWDDzz"; break;
3321 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3322 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3324 DEBUG(0,("check_printjob_info: invalid level %d\n",
3328 if (id == NULL || strcmp(desc->format,id) != 0) {
3329 DEBUG(0,("check_printjob_info: invalid format %s\n",
3330 id ? id : "<NULL>" ));
3336 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3337 char *param, int tpscnt,
3338 char *data, int tdscnt,
3339 int mdrcnt,int mprcnt,
3340 char **rdata,char **rparam,
3341 int *rdata_len,int *rparam_len)
3343 struct pack_desc desc;
3344 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3345 char *str2 = skip_string(param,tpscnt,str1);
3346 char *p = skip_string(param,tpscnt,str2);
3349 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3350 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3353 TALLOC_CTX *mem_ctx = talloc_tos();
3356 struct rpc_pipe_client *cli = NULL;
3357 struct policy_handle handle;
3358 struct spoolss_DevmodeContainer devmode_ctr;
3359 struct spoolss_JobInfoContainer ctr;
3360 union spoolss_JobInfo info;
3361 struct spoolss_SetJobInfo1 info1;
3363 if (!str1 || !str2 || !p) {
3367 * We use 1 here not 2 as we're checking
3368 * the last byte we want to access is safe.
3370 if (!is_offset_safe(param,tpscnt,p,1)) {
3373 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3376 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3383 /* check it's a supported varient */
3384 if ((strcmp(str1,"WWsTP")) ||
3385 (!check_printjob_info(&desc,uLevel,str2)))
3388 errcode = NERR_notsupported;
3392 /* change print job name, data gives the name */
3398 ZERO_STRUCT(handle);
3400 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3401 rpc_spoolss_dispatch, conn->server_info,
3403 if (!NT_STATUS_IS_OK(status)) {
3404 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3405 nt_errstr(status)));
3406 errcode = W_ERROR_V(ntstatus_to_werror(status));
3410 ZERO_STRUCT(devmode_ctr);
3412 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3419 if (!NT_STATUS_IS_OK(status)) {
3420 errcode = W_ERROR_V(ntstatus_to_werror(status));
3423 if (!W_ERROR_IS_OK(werr)) {
3424 errcode = W_ERROR_V(werr);
3428 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3434 if (!W_ERROR_IS_OK(werr)) {
3435 errcode = W_ERROR_V(werr);
3441 info1.job_id = info.info1.job_id;
3442 info1.printer_name = info.info1.printer_name;
3443 info1.user_name = info.info1.user_name;
3444 info1.document_name = data;
3445 info1.data_type = info.info1.data_type;
3446 info1.text_status = info.info1.text_status;
3447 info1.status = info.info1.status;
3448 info1.priority = info.info1.priority;
3449 info1.position = info.info1.position;
3450 info1.total_pages = info.info1.total_pages;
3451 info1.pages_printed = info.info1.pages_printed;
3452 info1.submitted = info.info1.submitted;
3455 ctr.info.info1 = &info1;
3457 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3463 if (!NT_STATUS_IS_OK(status)) {
3464 errcode = W_ERROR_V(ntstatus_to_werror(status));
3467 if (!W_ERROR_IS_OK(werr)) {
3468 errcode = W_ERROR_V(werr);
3472 errcode = NERR_Success;
3475 if (cli && is_valid_policy_hnd(&handle)) {
3476 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3479 SSVALS(*rparam,0,errcode);
3480 SSVAL(*rparam,2,0); /* converter word */
3486 /****************************************************************************
3487 Get info about the server.
3488 ****************************************************************************/
3490 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3491 char *param, int tpscnt,
3492 char *data, int tdscnt,
3493 int mdrcnt,int mprcnt,
3494 char **rdata,char **rparam,
3495 int *rdata_len,int *rparam_len)
3497 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3498 char *str2 = skip_string(param,tpscnt,str1);
3499 char *p = skip_string(param,tpscnt,str2);
3500 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3506 TALLOC_CTX *mem_ctx = talloc_tos();
3507 struct rpc_pipe_client *cli = NULL;
3508 union srvsvc_NetSrvInfo info;
3511 if (!str1 || !str2 || !p) {
3515 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3517 /* check it's a supported varient */
3518 if (!prefix_ok(str1,"WrLh")) {
3524 if (strcmp(str2,"B16") != 0) {
3530 if (strcmp(str2,"B16BBDz") != 0) {
3536 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3542 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3548 if (strcmp(str2,"DN") != 0) {
3554 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3563 *rdata_len = mdrcnt;
3564 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3570 p2 = p + struct_len;
3572 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3573 rpc_srvsvc_dispatch, conn->server_info,
3575 if (!NT_STATUS_IS_OK(status)) {
3576 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3577 nt_errstr(status)));
3578 errcode = W_ERROR_V(ntstatus_to_werror(status));
3582 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3587 if (!NT_STATUS_IS_OK(status)) {
3588 errcode = W_ERROR_V(ntstatus_to_werror(status));
3591 if (!W_ERROR_IS_OK(werr)) {
3592 errcode = W_ERROR_V(werr);
3596 if (info.info101 == NULL) {
3597 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3602 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3603 STR_ASCII|STR_UPPER|STR_TERMINATE);
3607 SCVAL(p,0,info.info101->version_major);
3608 SCVAL(p,1,info.info101->version_minor);
3609 SIVAL(p,2,info.info101->server_type);
3611 if (mdrcnt == struct_len) {
3614 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3615 if (mdrcnt - struct_len <= 0) {
3619 info.info101->comment,
3620 MIN(mdrcnt - struct_len,
3621 MAX_SERVER_STRING_LENGTH),
3623 p2 = skip_string(*rdata,*rdata_len,p2);
3631 return False; /* not yet implemented */
3634 errcode = NERR_Success;
3638 *rdata_len = PTR_DIFF(p2,*rdata);
3641 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3645 SSVAL(*rparam,0,errcode);
3646 SSVAL(*rparam,2,0); /* converter word */
3647 SSVAL(*rparam,4,*rdata_len);
3652 /****************************************************************************
3653 Get info about the server.
3654 ****************************************************************************/
3656 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3657 char *param, int tpscnt,
3658 char *data, int tdscnt,
3659 int mdrcnt,int mprcnt,
3660 char **rdata,char **rparam,
3661 int *rdata_len,int *rparam_len)
3663 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3664 char *str2 = skip_string(param,tpscnt,str1);
3665 char *p = skip_string(param,tpscnt,str2);
3668 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3670 if (!str1 || !str2 || !p) {
3674 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3677 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3682 /* check it's a supported varient */
3683 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3687 *rdata_len = mdrcnt + 1024;
3688 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3693 SSVAL(*rparam,0,NERR_Success);
3694 SSVAL(*rparam,2,0); /* converter word */
3697 endp = *rdata + *rdata_len;
3699 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3704 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3705 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3707 p2 = skip_string(*rdata,*rdata_len,p2);
3713 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3714 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3715 p2 = skip_string(*rdata,*rdata_len,p2);
3721 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3722 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3724 p2 = skip_string(*rdata,*rdata_len,p2);
3730 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3731 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3734 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3735 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3736 p2 = skip_string(*rdata,*rdata_len,p2);
3742 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3743 strlcpy(p2,"",PTR_DIFF(endp,p2));
3744 p2 = skip_string(*rdata,*rdata_len,p2);
3750 *rdata_len = PTR_DIFF(p2,*rdata);
3752 SSVAL(*rparam,4,*rdata_len);
3757 /****************************************************************************
3758 get info about a user
3760 struct user_info_11 {
3761 char usri11_name[21]; 0-20
3763 char *usri11_comment; 22-25
3764 char *usri11_usr_comment; 26-29
3765 unsigned short usri11_priv; 30-31
3766 unsigned long usri11_auth_flags; 32-35
3767 long usri11_password_age; 36-39
3768 char *usri11_homedir; 40-43
3769 char *usri11_parms; 44-47
3770 long usri11_last_logon; 48-51
3771 long usri11_last_logoff; 52-55
3772 unsigned short usri11_bad_pw_count; 56-57
3773 unsigned short usri11_num_logons; 58-59
3774 char *usri11_logon_server; 60-63
3775 unsigned short usri11_country_code; 64-65
3776 char *usri11_workstations; 66-69
3777 unsigned long usri11_max_storage; 70-73
3778 unsigned short usri11_units_per_week; 74-75
3779 unsigned char *usri11_logon_hours; 76-79
3780 unsigned short usri11_code_page; 80-81
3785 usri11_name specifies the user name for which information is retrieved
3787 usri11_pad aligns the next data structure element to a word boundary
3789 usri11_comment is a null terminated ASCII comment
3791 usri11_user_comment is a null terminated ASCII comment about the user
3793 usri11_priv specifies the level of the privilege assigned to the user.
3794 The possible values are:
3796 Name Value Description
3797 USER_PRIV_GUEST 0 Guest privilege
3798 USER_PRIV_USER 1 User privilege
3799 USER_PRV_ADMIN 2 Administrator privilege
3801 usri11_auth_flags specifies the account operator privileges. The
3802 possible values are:
3804 Name Value Description
3805 AF_OP_PRINT 0 Print operator
3808 Leach, Naik [Page 28]
3812 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3815 AF_OP_COMM 1 Communications operator
3816 AF_OP_SERVER 2 Server operator
3817 AF_OP_ACCOUNTS 3 Accounts operator
3820 usri11_password_age specifies how many seconds have elapsed since the
3821 password was last changed.
3823 usri11_home_dir points to a null terminated ASCII string that contains
3824 the path name of the user's home directory.
3826 usri11_parms points to a null terminated ASCII string that is set
3827 aside for use by applications.
3829 usri11_last_logon specifies the time when the user last logged on.
3830 This value is stored as the number of seconds elapsed since
3831 00:00:00, January 1, 1970.
3833 usri11_last_logoff specifies the time when the user last logged off.
3834 This value is stored as the number of seconds elapsed since
3835 00:00:00, January 1, 1970. A value of 0 means the last logoff
3838 usri11_bad_pw_count specifies the number of incorrect passwords
3839 entered since the last successful logon.
3841 usri11_log1_num_logons specifies the number of times this user has
3842 logged on. A value of -1 means the number of logons is unknown.
3844 usri11_logon_server points to a null terminated ASCII string that
3845 contains the name of the server to which logon requests are sent.
3846 A null string indicates logon requests should be sent to the
3849 usri11_country_code specifies the country code for the user's language
3852 usri11_workstations points to a null terminated ASCII string that
3853 contains the names of workstations the user may log on from.
3854 There may be up to 8 workstations, with the names separated by
3855 commas. A null strings indicates there are no restrictions.
3857 usri11_max_storage specifies the maximum amount of disk space the user
3858 can occupy. A value of 0xffffffff indicates there are no
3861 usri11_units_per_week specifies the equal number of time units into
3862 which a week is divided. This value must be equal to 168.
3864 usri11_logon_hours points to a 21 byte (168 bits) string that
3865 specifies the time during which the user can log on. Each bit
3866 represents one unique hour in a week. The first bit (bit 0, word
3867 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3871 Leach, Naik [Page 29]
3875 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3878 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3879 are no restrictions.
3881 usri11_code_page specifies the code page for the user's language of
3884 All of the pointers in this data structure need to be treated
3885 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3886 to be ignored. The converter word returned in the parameters section
3887 needs to be subtracted from the lower 16 bits to calculate an offset
3888 into the return buffer where this ASCII string resides.
3890 There is no auxiliary data in the response.
3892 ****************************************************************************/
3894 #define usri11_name 0
3895 #define usri11_pad 21
3896 #define usri11_comment 22
3897 #define usri11_usr_comment 26
3898 #define usri11_full_name 30
3899 #define usri11_priv 34
3900 #define usri11_auth_flags 36
3901 #define usri11_password_age 40
3902 #define usri11_homedir 44
3903 #define usri11_parms 48
3904 #define usri11_last_logon 52
3905 #define usri11_last_logoff 56
3906 #define usri11_bad_pw_count 60
3907 #define usri11_num_logons 62
3908 #define usri11_logon_server 64
3909 #define usri11_country_code 68
3910 #define usri11_workstations 70
3911 #define usri11_max_storage 74
3912 #define usri11_units_per_week 78
3913 #define usri11_logon_hours 80
3914 #define usri11_code_page 84
3915 #define usri11_end 86
3917 #define USER_PRIV_GUEST 0
3918 #define USER_PRIV_USER 1
3919 #define USER_PRIV_ADMIN 2
3921 #define AF_OP_PRINT 0
3922 #define AF_OP_COMM 1
3923 #define AF_OP_SERVER 2
3924 #define AF_OP_ACCOUNTS 3
3927 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3928 char *param, int tpscnt,
3929 char *data, int tdscnt,
3930 int mdrcnt,int mprcnt,
3931 char **rdata,char **rparam,
3932 int *rdata_len,int *rparam_len)
3934 struct smbd_server_connection *sconn = smbd_server_conn;
3935 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3936 char *str2 = skip_string(param,tpscnt,str1);
3937 char *UserName = skip_string(param,tpscnt,str2);
3938 char *p = skip_string(param,tpscnt,UserName);
3939 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3942 const char *level_string;
3944 /* get NIS home of a previously validated user - simeon */
3945 /* With share level security vuid will always be zero.
3946 Don't depend on vuser being non-null !!. JRA */
3947 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3949 DEBUG(3,(" Username of UID %d is %s\n",
3950 (int)vuser->server_info->utok.uid,
3951 vuser->server_info->unix_name));
3954 if (!str1 || !str2 || !UserName || !p) {
3959 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3964 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3966 /* check it's a supported variant */
3967 if (strcmp(str1,"zWrLh") != 0) {
3971 case 0: level_string = "B21"; break;
3972 case 1: level_string = "B21BB16DWzzWz"; break;
3973 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3974 case 10: level_string = "B21Bzzz"; break;
3975 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3976 default: return False;
3979 if (strcmp(level_string,str2) != 0) {
3983 *rdata_len = mdrcnt + 1024;
3984 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3989 SSVAL(*rparam,0,NERR_Success);
3990 SSVAL(*rparam,2,0); /* converter word */
3993 endp = *rdata + *rdata_len;
3994 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4000 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4003 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4008 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4009 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4010 p2 = skip_string(*rdata,*rdata_len,p2);
4015 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4016 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4017 p2 = skip_string(*rdata,*rdata_len,p2);
4022 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4023 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4024 strlcpy(p2,((vuser != NULL)
4025 ? pdb_get_fullname(vuser->server_info->sam_account)
4026 : UserName),PTR_DIFF(endp,p2));
4027 p2 = skip_string(*rdata,*rdata_len,p2);
4034 const char *homedir = "";
4035 if (vuser != NULL) {
4036 homedir = pdb_get_homedir(
4037 vuser->server_info->sam_account);
4039 /* modelled after NTAS 3.51 reply */
4040 SSVAL(p,usri11_priv,
4041 (get_current_uid(conn) == sec_initial_uid())?
4042 USER_PRIV_ADMIN:USER_PRIV_USER);
4043 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4044 SIVALS(p,usri11_password_age,-1); /* password age */
4045 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4046 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4047 p2 = skip_string(*rdata,*rdata_len,p2);
4051 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4052 strlcpy(p2,"",PTR_DIFF(endp,p2));
4053 p2 = skip_string(*rdata,*rdata_len,p2);
4057 SIVAL(p,usri11_last_logon,0); /* last logon */
4058 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4059 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4060 SSVALS(p,usri11_num_logons,-1); /* num logons */
4061 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4062 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4063 p2 = skip_string(*rdata,*rdata_len,p2);
4067 SSVAL(p,usri11_country_code,0); /* country code */
4069 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4070 strlcpy(p2,"",PTR_DIFF(endp,p2));
4071 p2 = skip_string(*rdata,*rdata_len,p2);
4076 SIVALS(p,usri11_max_storage,-1); /* max storage */
4077 SSVAL(p,usri11_units_per_week,168); /* units per week */
4078 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4080 /* a simple way to get logon hours at all times. */
4082 SCVAL(p2,21,0); /* fix zero termination */
4083 p2 = skip_string(*rdata,*rdata_len,p2);
4088 SSVAL(p,usri11_code_page,0); /* code page */
4091 if (uLevel == 1 || uLevel == 2) {
4092 memset(p+22,' ',16); /* password */
4093 SIVALS(p,38,-1); /* password age */
4095 (get_current_uid(conn) == sec_initial_uid())?
4096 USER_PRIV_ADMIN:USER_PRIV_USER);
4097 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4098 strlcpy(p2, vuser ? pdb_get_homedir(
4099 vuser->server_info->sam_account) : "",
4101 p2 = skip_string(*rdata,*rdata_len,p2);
4105 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4107 SSVAL(p,52,0); /* flags */
4108 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4109 strlcpy(p2, vuser ? pdb_get_logon_script(
4110 vuser->server_info->sam_account) : "",
4112 p2 = skip_string(*rdata,*rdata_len,p2);
4117 SIVAL(p,60,0); /* auth_flags */
4118 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4119 strlcpy(p2,((vuser != NULL)
4120 ? pdb_get_fullname(vuser->server_info->sam_account)
4121 : UserName),PTR_DIFF(endp,p2));
4122 p2 = skip_string(*rdata,*rdata_len,p2);
4126 SIVAL(p,68,0); /* urs_comment */
4127 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4128 strlcpy(p2,"",PTR_DIFF(endp,p2));
4129 p2 = skip_string(*rdata,*rdata_len,p2);
4133 SIVAL(p,76,0); /* workstations */
4134 SIVAL(p,80,0); /* last_logon */
4135 SIVAL(p,84,0); /* last_logoff */
4136 SIVALS(p,88,-1); /* acct_expires */
4137 SIVALS(p,92,-1); /* max_storage */
4138 SSVAL(p,96,168); /* units_per_week */
4139 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4142 SSVALS(p,102,-1); /* bad_pw_count */
4143 SSVALS(p,104,-1); /* num_logons */
4144 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4146 TALLOC_CTX *ctx = talloc_tos();
4147 int space_rem = *rdata_len - (p2 - *rdata);
4150 if (space_rem <= 0) {
4153 tmp = talloc_strdup(ctx, "\\\\%L");
4157 tmp = talloc_sub_basic(ctx,
4170 p2 = skip_string(*rdata,*rdata_len,p2);
4174 SSVAL(p,110,49); /* country_code */
4175 SSVAL(p,112,860); /* code page */
4179 *rdata_len = PTR_DIFF(p2,*rdata);
4181 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4186 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4187 char *param, int tpscnt,
4188 char *data, int tdscnt,
4189 int mdrcnt,int mprcnt,
4190 char **rdata,char **rparam,
4191 int *rdata_len,int *rparam_len)
4193 struct smbd_server_connection *sconn = smbd_server_conn;
4194 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4195 char *str2 = skip_string(param,tpscnt,str1);
4196 char *p = skip_string(param,tpscnt,str2);
4198 struct pack_desc desc;
4200 /* With share level security vuid will always be zero.
4201 Don't depend on vuser being non-null !!. JRA */
4202 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4204 if (!str1 || !str2 || !p) {
4209 DEBUG(3,(" Username of UID %d is %s\n",
4210 (int)vuser->server_info->utok.uid,
4211 vuser->server_info->unix_name));
4214 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4215 name = get_safe_str_ptr(param,tpscnt,p,2);
4220 memset((char *)&desc,'\0',sizeof(desc));
4222 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4224 /* check it's a supported varient */
4225 if (strcmp(str1,"OOWb54WrLh") != 0) {
4228 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4232 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4239 desc.buflen = mdrcnt;
4240 desc.subformat = NULL;
4243 if (init_package(&desc,1,0)) {
4244 PACKI(&desc,"W",0); /* code */
4245 PACKS(&desc,"B21",name); /* eff. name */
4246 PACKS(&desc,"B",""); /* pad */
4248 (get_current_uid(conn) == sec_initial_uid())?
4249 USER_PRIV_ADMIN:USER_PRIV_USER);
4250 PACKI(&desc,"D",0); /* auth flags XXX */
4251 PACKI(&desc,"W",0); /* num logons */
4252 PACKI(&desc,"W",0); /* bad pw count */
4253 PACKI(&desc,"D",0); /* last logon */
4254 PACKI(&desc,"D",-1); /* last logoff */
4255 PACKI(&desc,"D",-1); /* logoff time */
4256 PACKI(&desc,"D",-1); /* kickoff time */
4257 PACKI(&desc,"D",0); /* password age */
4258 PACKI(&desc,"D",0); /* password can change */
4259 PACKI(&desc,"D",-1); /* password must change */
4263 fstrcpy(mypath,"\\\\");
4264 fstrcat(mypath,get_local_machine_name());
4266 PACKS(&desc,"z",mypath); /* computer */
4269 PACKS(&desc,"z",lp_workgroup());/* domain */
4270 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4271 vuser->server_info->sam_account) : ""); /* script path */
4272 PACKI(&desc,"D",0x00000000); /* reserved */
4275 *rdata_len = desc.usedlen;
4277 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4281 SSVALS(*rparam,0,desc.errcode);
4283 SSVAL(*rparam,4,desc.neededlen);
4285 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4290 /****************************************************************************
4291 api_WAccessGetUserPerms
4292 ****************************************************************************/
4294 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4295 char *param, int tpscnt,
4296 char *data, int tdscnt,
4297 int mdrcnt,int mprcnt,
4298 char **rdata,char **rparam,
4299 int *rdata_len,int *rparam_len)
4301 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4302 char *str2 = skip_string(param,tpscnt,str1);
4303 char *user = skip_string(param,tpscnt,str2);
4304 char *resource = skip_string(param,tpscnt,user);
4306 if (!str1 || !str2 || !user || !resource) {
4310 if (skip_string(param,tpscnt,resource) == NULL) {
4313 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4315 /* check it's a supported varient */
4316 if (strcmp(str1,"zzh") != 0) {
4319 if (strcmp(str2,"") != 0) {
4324 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4328 SSVALS(*rparam,0,0); /* errorcode */
4329 SSVAL(*rparam,2,0); /* converter word */
4330 SSVAL(*rparam,4,0x7f); /* permission flags */
4335 /****************************************************************************
4336 api_WPrintJobEnumerate
4337 ****************************************************************************/
4339 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4340 char *param, int tpscnt,
4341 char *data, int tdscnt,
4342 int mdrcnt,int mprcnt,
4343 char **rdata,char **rparam,
4344 int *rdata_len,int *rparam_len)
4346 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4347 char *str2 = skip_string(param,tpscnt,str1);
4348 char *p = skip_string(param,tpscnt,str2);
4352 struct pack_desc desc;
4355 TALLOC_CTX *mem_ctx = talloc_tos();
4358 struct rpc_pipe_client *cli = NULL;
4359 struct policy_handle handle;
4360 struct spoolss_DevmodeContainer devmode_ctr;
4361 union spoolss_JobInfo info;
4363 if (!str1 || !str2 || !p) {
4367 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4369 memset((char *)&desc,'\0',sizeof(desc));
4370 memset((char *)&status,'\0',sizeof(status));
4372 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4374 /* check it's a supported varient */
4375 if (strcmp(str1,"WWrLh") != 0) {
4378 if (!check_printjob_info(&desc,uLevel,str2)) {
4382 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4386 ZERO_STRUCT(handle);
4388 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4389 rpc_spoolss_dispatch, conn->server_info,
4391 if (!NT_STATUS_IS_OK(status)) {
4392 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4393 nt_errstr(status)));
4394 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4398 ZERO_STRUCT(devmode_ctr);
4400 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4407 if (!NT_STATUS_IS_OK(status)) {
4408 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4411 if (!W_ERROR_IS_OK(werr)) {
4412 desc.errcode = W_ERROR_V(werr);
4416 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4422 if (!W_ERROR_IS_OK(werr)) {
4423 desc.errcode = W_ERROR_V(werr);
4428 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4433 desc.buflen = mdrcnt;
4436 * Don't return data but need to get correct length
4437 * init_package will return wrong size if buflen=0
4439 desc.buflen = getlen(desc.format);
4440 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4443 if (init_package(&desc,1,0)) {
4444 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4445 *rdata_len = desc.usedlen;
4447 desc.errcode = NERR_JobNotFound;
4451 if (cli && is_valid_policy_hnd(&handle)) {
4452 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4456 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4460 SSVALS(*rparam,0,desc.errcode);
4462 SSVAL(*rparam,4,desc.neededlen);
4466 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4471 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4472 char *param, int tpscnt,
4473 char *data, int tdscnt,
4474 int mdrcnt,int mprcnt,
4475 char **rdata,char **rparam,
4476 int *rdata_len,int *rparam_len)
4478 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4479 char *str2 = skip_string(param,tpscnt,str1);
4480 char *p = skip_string(param,tpscnt,str2);
4484 struct pack_desc desc;
4486 TALLOC_CTX *mem_ctx = talloc_tos();
4489 struct rpc_pipe_client *cli = NULL;
4490 struct policy_handle handle;
4491 struct spoolss_DevmodeContainer devmode_ctr;
4493 union spoolss_JobInfo *info;
4495 if (!str1 || !str2 || !p) {
4499 memset((char *)&desc,'\0',sizeof(desc));
4501 p = skip_string(param,tpscnt,p);
4505 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4507 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4509 /* check it's a supported variant */
4510 if (strcmp(str1,"zWrLeh") != 0) {
4515 return False; /* defined only for uLevel 0,1,2 */
4518 if (!check_printjob_info(&desc,uLevel,str2)) {
4522 ZERO_STRUCT(handle);
4524 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4525 rpc_spoolss_dispatch, conn->server_info,
4527 if (!NT_STATUS_IS_OK(status)) {
4528 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4529 nt_errstr(status)));
4530 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4534 ZERO_STRUCT(devmode_ctr);
4536 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4540 SEC_FLAG_MAXIMUM_ALLOWED,
4543 if (!NT_STATUS_IS_OK(status)) {
4544 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4547 if (!W_ERROR_IS_OK(werr)) {
4548 desc.errcode = W_ERROR_V(werr);
4552 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4560 if (!W_ERROR_IS_OK(werr)) {
4561 desc.errcode = W_ERROR_V(werr);
4566 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4572 desc.buflen = mdrcnt;
4574 if (init_package(&desc,count,0)) {
4576 for (i = 0; i < count; i++) {
4577 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4578 if (desc.errcode == NERR_Success) {
4584 if (cli && is_valid_policy_hnd(&handle)) {
4585 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4588 *rdata_len = desc.usedlen;
4591 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4595 SSVALS(*rparam,0,desc.errcode);
4597 SSVAL(*rparam,4,succnt);
4598 SSVAL(*rparam,6,count);
4600 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4605 static int check_printdest_info(struct pack_desc* desc,
4606 int uLevel, char* id)
4608 desc->subformat = NULL;
4611 desc->format = "B9";
4614 desc->format = "B9B21WWzW";
4620 desc->format = "zzzWWzzzWW";
4623 DEBUG(0,("check_printdest_info: invalid level %d\n",
4627 if (id == NULL || strcmp(desc->format,id) != 0) {
4628 DEBUG(0,("check_printdest_info: invalid string %s\n",
4629 id ? id : "<NULL>" ));
4635 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4636 struct pack_desc* desc)
4640 strncpy(buf, info2->printername, sizeof(buf)-1);
4641 buf[sizeof(buf)-1] = 0;
4645 PACKS(desc,"B9",buf); /* szName */
4647 PACKS(desc,"B21",""); /* szUserName */
4648 PACKI(desc,"W",0); /* uJobId */
4649 PACKI(desc,"W",0); /* fsStatus */
4650 PACKS(desc,"z",""); /* pszStatus */
4651 PACKI(desc,"W",0); /* time */
4655 if (uLevel == 2 || uLevel == 3) {
4656 PACKS(desc,"z",buf); /* pszPrinterName */
4658 PACKS(desc,"z",""); /* pszUserName */
4659 PACKS(desc,"z",""); /* pszLogAddr */
4660 PACKI(desc,"W",0); /* uJobId */
4661 PACKI(desc,"W",0); /* fsStatus */
4662 PACKS(desc,"z",""); /* pszStatus */
4663 PACKS(desc,"z",""); /* pszComment */
4664 PACKS(desc,"z","NULL"); /* pszDrivers */
4665 PACKI(desc,"W",0); /* time */
4666 PACKI(desc,"W",0); /* pad1 */
4671 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4672 char *param, int tpscnt,
4673 char *data, int tdscnt,
4674 int mdrcnt,int mprcnt,
4675 char **rdata,char **rparam,
4676 int *rdata_len,int *rparam_len)
4678 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4679 char *str2 = skip_string(param,tpscnt,str1);
4680 char *p = skip_string(param,tpscnt,str2);
4681 char* PrinterName = p;
4683 struct pack_desc desc;
4686 TALLOC_CTX *mem_ctx = talloc_tos();
4689 struct rpc_pipe_client *cli = NULL;
4690 struct policy_handle handle;
4691 struct spoolss_DevmodeContainer devmode_ctr;
4692 union spoolss_PrinterInfo info;
4694 if (!str1 || !str2 || !p) {
4698 memset((char *)&desc,'\0',sizeof(desc));
4700 p = skip_string(param,tpscnt,p);
4704 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4706 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4708 /* check it's a supported varient */
4709 if (strcmp(str1,"zWrLh") != 0) {
4712 if (!check_printdest_info(&desc,uLevel,str2)) {
4716 ZERO_STRUCT(handle);
4718 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4719 rpc_spoolss_dispatch, conn->server_info,
4721 if (!NT_STATUS_IS_OK(status)) {
4722 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4723 nt_errstr(status)));
4724 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4728 ZERO_STRUCT(devmode_ctr);
4730 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4734 SEC_FLAG_MAXIMUM_ALLOWED,
4737 if (!NT_STATUS_IS_OK(status)) {
4739 desc.errcode = NERR_DestNotFound;
4743 if (!W_ERROR_IS_OK(werr)) {
4745 desc.errcode = NERR_DestNotFound;
4750 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4755 if (!W_ERROR_IS_OK(werr)) {
4757 desc.errcode = NERR_DestNotFound;
4763 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4768 desc.buflen = mdrcnt;
4771 * Don't return data but need to get correct length
4772 * init_package will return wrong size if buflen=0
4774 desc.buflen = getlen(desc.format);
4775 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4777 if (init_package(&desc,1,0)) {
4778 fill_printdest_info(&info.info2, uLevel,&desc);
4782 if (cli && is_valid_policy_hnd(&handle)) {
4783 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4786 *rdata_len = desc.usedlen;
4789 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4793 SSVALS(*rparam,0,desc.errcode);
4795 SSVAL(*rparam,4,desc.neededlen);
4797 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4803 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4804 char *param, int tpscnt,
4805 char *data, int tdscnt,
4806 int mdrcnt,int mprcnt,
4807 char **rdata,char **rparam,
4808 int *rdata_len,int *rparam_len)
4810 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4811 char *str2 = skip_string(param,tpscnt,str1);
4812 char *p = skip_string(param,tpscnt,str2);
4816 struct pack_desc desc;
4818 TALLOC_CTX *mem_ctx = talloc_tos();
4821 struct rpc_pipe_client *cli = NULL;
4822 union spoolss_PrinterInfo *info;
4825 if (!str1 || !str2 || !p) {
4829 memset((char *)&desc,'\0',sizeof(desc));
4831 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4833 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4835 /* check it's a supported varient */
4836 if (strcmp(str1,"WrLeh") != 0) {
4839 if (!check_printdest_info(&desc,uLevel,str2)) {
4845 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4846 rpc_spoolss_dispatch, conn->server_info,
4848 if (!NT_STATUS_IS_OK(status)) {
4849 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4850 nt_errstr(status)));
4851 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4855 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4857 cli->srv_name_slash,
4862 if (!W_ERROR_IS_OK(werr)) {
4863 desc.errcode = W_ERROR_V(werr);
4865 desc.errcode = NERR_DestNotFound;
4873 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4880 desc.buflen = mdrcnt;
4881 if (init_package(&desc,queuecnt,0)) {
4884 for (i = 0; i < count; i++) {
4885 fill_printdest_info(&info[i].info2, uLevel,&desc);
4887 if (desc.errcode == NERR_Success) {
4893 *rdata_len = desc.usedlen;
4896 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4900 SSVALS(*rparam,0,desc.errcode);
4902 SSVAL(*rparam,4,succnt);
4903 SSVAL(*rparam,6,queuecnt);
4905 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4910 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4911 char *param, int tpscnt,
4912 char *data, int tdscnt,
4913 int mdrcnt,int mprcnt,
4914 char **rdata,char **rparam,
4915 int *rdata_len,int *rparam_len)
4917 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4918 char *str2 = skip_string(param,tpscnt,str1);
4919 char *p = skip_string(param,tpscnt,str2);
4922 struct pack_desc desc;
4924 if (!str1 || !str2 || !p) {
4928 memset((char *)&desc,'\0',sizeof(desc));
4930 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4932 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4934 /* check it's a supported varient */
4935 if (strcmp(str1,"WrLeh") != 0) {
4938 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4943 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4949 desc.buflen = mdrcnt;
4950 if (init_package(&desc,1,0)) {
4951 PACKS(&desc,"B41","NULL");
4954 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4956 *rdata_len = desc.usedlen;
4959 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4963 SSVALS(*rparam,0,desc.errcode);
4965 SSVAL(*rparam,4,succnt);
4968 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4973 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4974 char *param, int tpscnt,
4975 char *data, int tdscnt,
4976 int mdrcnt,int mprcnt,
4977 char **rdata,char **rparam,
4978 int *rdata_len,int *rparam_len)
4980 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4981 char *str2 = skip_string(param,tpscnt,str1);
4982 char *p = skip_string(param,tpscnt,str2);
4985 struct pack_desc desc;
4987 if (!str1 || !str2 || !p) {
4990 memset((char *)&desc,'\0',sizeof(desc));
4992 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4994 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4996 /* check it's a supported varient */
4997 if (strcmp(str1,"WrLeh") != 0) {
5000 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5005 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5011 desc.buflen = mdrcnt;
5013 if (init_package(&desc,1,0)) {
5014 PACKS(&desc,"B13","lpd");
5017 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5019 *rdata_len = desc.usedlen;
5022 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5026 SSVALS(*rparam,0,desc.errcode);
5028 SSVAL(*rparam,4,succnt);
5031 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5036 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5037 char *param, int tpscnt,
5038 char *data, int tdscnt,
5039 int mdrcnt,int mprcnt,
5040 char **rdata,char **rparam,
5041 int *rdata_len,int *rparam_len)
5043 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5044 char *str2 = skip_string(param,tpscnt,str1);
5045 char *p = skip_string(param,tpscnt,str2);
5048 struct pack_desc desc;
5050 if (!str1 || !str2 || !p) {
5054 memset((char *)&desc,'\0',sizeof(desc));
5056 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5058 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5060 /* check it's a supported varient */
5061 if (strcmp(str1,"WrLeh") != 0) {
5064 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5069 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5074 memset((char *)&desc,'\0',sizeof(desc));
5076 desc.buflen = mdrcnt;
5078 if (init_package(&desc,1,0)) {
5079 PACKS(&desc,"B13","lp0");
5082 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5084 *rdata_len = desc.usedlen;
5087 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5091 SSVALS(*rparam,0,desc.errcode);
5093 SSVAL(*rparam,4,succnt);
5096 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5101 /****************************************************************************
5103 ****************************************************************************/
5105 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5106 char *param, int tpscnt,
5107 char *data, int tdscnt,
5108 int mdrcnt,int mprcnt,
5109 char **rdata,char **rparam,
5110 int *rdata_len,int *rparam_len)
5113 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5114 char *str2 = skip_string(param,tpscnt,str1);
5115 char *p = skip_string(param,tpscnt,str2);
5117 struct pack_desc desc;
5118 struct sessionid *session_list;
5119 int i, num_sessions;
5121 if (!str1 || !str2 || !p) {
5125 memset((char *)&desc,'\0',sizeof(desc));
5127 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5129 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5130 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5131 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5133 /* check it's a supported varient */
5134 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5137 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5141 num_sessions = list_sessions(talloc_tos(), &session_list);
5144 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5149 memset((char *)&desc,'\0',sizeof(desc));
5151 desc.buflen = mdrcnt;
5153 if (!init_package(&desc,num_sessions,0)) {
5157 for(i=0; i<num_sessions; i++) {
5158 PACKS(&desc, "z", session_list[i].remote_machine);
5159 PACKS(&desc, "z", session_list[i].username);
5160 PACKI(&desc, "W", 1); /* num conns */
5161 PACKI(&desc, "W", 0); /* num opens */
5162 PACKI(&desc, "W", 1); /* num users */
5163 PACKI(&desc, "D", 0); /* session time */
5164 PACKI(&desc, "D", 0); /* idle time */
5165 PACKI(&desc, "D", 0); /* flags */
5166 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5169 *rdata_len = desc.usedlen;
5172 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5176 SSVALS(*rparam,0,desc.errcode);
5177 SSVAL(*rparam,2,0); /* converter */
5178 SSVAL(*rparam,4,num_sessions); /* count */
5180 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5186 /****************************************************************************
5187 The buffer was too small.
5188 ****************************************************************************/
5190 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5191 int mdrcnt, int mprcnt,
5192 char **rdata, char **rparam,
5193 int *rdata_len, int *rparam_len)
5195 *rparam_len = MIN(*rparam_len,mprcnt);
5196 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5203 SSVAL(*rparam,0,NERR_BufTooSmall);
5205 DEBUG(3,("Supplied buffer too small in API command\n"));
5210 /****************************************************************************
5211 The request is not supported.
5212 ****************************************************************************/
5214 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5215 char *param, int tpscnt,
5216 char *data, int tdscnt,
5217 int mdrcnt, int mprcnt,
5218 char **rdata, char **rparam,
5219 int *rdata_len, int *rparam_len)
5222 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5229 SSVAL(*rparam,0,NERR_notsupported);
5230 SSVAL(*rparam,2,0); /* converter word */
5232 DEBUG(3,("Unsupported API command\n"));
5237 static const struct {
5240 bool (*fn)(connection_struct *, uint16,
5243 int,int,char **,char **,int *,int *);
5244 bool auth_user; /* Deny anonymous access? */
5245 } api_commands[] = {
5246 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5247 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5248 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5249 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5250 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5251 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5252 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5253 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5254 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5255 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5256 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5257 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5258 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5259 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5260 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5261 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5262 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5263 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5264 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5265 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5266 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5267 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5268 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5269 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5270 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5271 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5272 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5273 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5274 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5275 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5276 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5277 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5278 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5279 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5280 {NULL, -1, api_Unsupported}
5281 /* The following RAP calls are not implemented by Samba:
5283 RAP_WFileEnum2 - anon not OK
5288 /****************************************************************************
5289 Handle remote api calls.
5290 ****************************************************************************/
5292 void api_reply(connection_struct *conn, uint16 vuid,
5293 struct smb_request *req,
5294 char *data, char *params,
5295 int tdscnt, int tpscnt,
5296 int mdrcnt, int mprcnt)
5298 struct smbd_server_connection *sconn = smbd_server_conn;
5301 char *rparam = NULL;
5302 const char *name1 = NULL;
5303 const char *name2 = NULL;
5310 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5311 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5316 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5319 api_command = SVAL(params,0);
5320 /* Is there a string at position params+2 ? */
5321 if (skip_string(params,tpscnt,params+2)) {
5326 name2 = skip_string(params,tpscnt,params+2);
5331 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5335 tdscnt,tpscnt,mdrcnt,mprcnt));
5337 for (i=0;api_commands[i].name;i++) {
5338 if (api_commands[i].id == api_command && api_commands[i].fn) {
5339 DEBUG(3,("Doing %s\n",api_commands[i].name));
5344 /* Check whether this api call can be done anonymously */
5346 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5347 user_struct *user = get_valid_user_struct(sconn, vuid);
5349 if (!user || user->server_info->guest) {
5350 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5355 rdata = (char *)SMB_MALLOC(1024);
5357 memset(rdata,'\0',1024);
5360 rparam = (char *)SMB_MALLOC(1024);
5362 memset(rparam,'\0',1024);
5365 if(!rdata || !rparam) {
5366 DEBUG(0,("api_reply: malloc fail !\n"));
5369 reply_nterror(req, NT_STATUS_NO_MEMORY);
5373 reply = api_commands[i].fn(conn,
5375 params,tpscnt, /* params + length */
5376 data,tdscnt, /* data + length */
5378 &rdata,&rparam,&rdata_len,&rparam_len);
5381 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5382 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5383 &rdata,&rparam,&rdata_len,&rparam_len);
5386 /* if we get False back then it's actually unsupported */
5388 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5389 &rdata,&rparam,&rdata_len,&rparam_len);
5392 /* If api_Unsupported returns false we can't return anything. */
5394 send_trans_reply(conn, req, rparam, rparam_len,
5395 rdata, rdata_len, False);