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 "../librpc/gen_ndr/cli_srvsvc.h"
33 #include "../librpc/gen_ndr/srv_samr.h"
34 #include "../librpc/gen_ndr/srv_spoolss.h"
35 #include "../librpc/gen_ndr/srv_srvsvc.h"
36 #include "../librpc/gen_ndr/rap.h"
37 #include "../lib/util/binsearch.h"
44 #define NERR_Success 0
45 #define NERR_badpass 86
46 #define NERR_notsupported 50
48 #define NERR_BASE (2100)
49 #define NERR_BufTooSmall (NERR_BASE+23)
50 #define NERR_JobNotFound (NERR_BASE+51)
51 #define NERR_DestNotFound (NERR_BASE+52)
53 #define ACCESS_READ 0x01
54 #define ACCESS_WRITE 0x02
55 #define ACCESS_CREATE 0x04
57 #define SHPWLEN 8 /* share password length */
59 /* Limit size of ipc replies */
61 static char *smb_realloc_limit(void *ptr, size_t size)
65 size = MAX((size),4*1024);
66 val = (char *)SMB_REALLOC(ptr,size);
68 memset(val,'\0',size);
73 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
74 char *param, int tpscnt,
75 char *data, int tdscnt,
76 int mdrcnt, int mprcnt,
77 char **rdata, char **rparam,
78 int *rdata_len, int *rparam_len);
80 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
81 int mdrcnt, int mprcnt,
82 char **rdata, char **rparam,
83 int *rdata_len, int *rparam_len);
86 static int CopyExpanded(connection_struct *conn,
87 int snum, char **dst, char *src, int *p_space_remaining)
89 TALLOC_CTX *ctx = talloc_tos();
93 if (!src || !dst || !p_space_remaining || !(*dst) ||
94 *p_space_remaining <= 0) {
98 buf = talloc_strdup(ctx, src);
100 *p_space_remaining = 0;
103 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
105 *p_space_remaining = 0;
108 buf = talloc_sub_advanced(ctx,
109 lp_servicename(SNUM(conn)),
110 conn->server_info->unix_name,
112 conn->server_info->utok.gid,
113 conn->server_info->sanitized_username,
114 pdb_get_domain(conn->server_info->sam_account),
117 *p_space_remaining = 0;
120 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
125 (*p_space_remaining) -= l;
129 static int CopyAndAdvance(char **dst, char *src, int *n)
132 if (!src || !dst || !n || !(*dst)) {
135 l = push_ascii(*dst,src,*n, STR_TERMINATE);
144 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
146 TALLOC_CTX *ctx = talloc_tos();
151 buf = talloc_strdup(ctx,s);
155 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
159 buf = talloc_sub_advanced(ctx,
160 lp_servicename(SNUM(conn)),
161 conn->server_info->unix_name,
163 conn->server_info->utok.gid,
164 conn->server_info->sanitized_username,
165 pdb_get_domain(conn->server_info->sam_account),
170 return strlen(buf) + 1;
173 /*******************************************************************
174 Check a API string for validity when we only need to check the prefix.
175 ******************************************************************/
177 static bool prefix_ok(const char *str, const char *prefix)
179 return(strncmp(str,prefix,strlen(prefix)) == 0);
183 const char *format; /* formatstring for structure */
184 const char *subformat; /* subformat for structure */
185 char *base; /* baseaddress of buffer */
186 int buflen; /* remaining size for fixed part; on init: length of base */
187 int subcount; /* count of substructures */
188 char *structbuf; /* pointer into buffer for remaining fixed part */
189 int stringlen; /* remaining size for variable part */
190 char *stringbuf; /* pointer into buffer for remaining variable part */
191 int neededlen; /* total needed size */
192 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
193 const char *curpos; /* current position; pointer into format or subformat */
197 static int get_counter(const char **p)
203 if (!isdigit((int)**p)) {
209 n = 10 * n + (i - '0');
217 static int getlen(const char *p)
226 case 'W': /* word (2 byte) */
229 case 'K': /* status word? (2 byte) */
232 case 'N': /* count of substructures (word) at end */
235 case 'D': /* double word (4 byte) */
236 case 'z': /* offset to zero terminated string (4 byte) */
237 case 'l': /* offset to user data (4 byte) */
240 case 'b': /* offset to data (with counter) (4 byte) */
244 case 'B': /* byte (with optional counter) */
245 n += get_counter(&p);
252 static bool init_package(struct pack_desc *p, int count, int subcount)
257 if (!p->format || !p->base) {
261 i = count * getlen(p->format);
263 i += subcount * getlen(p->subformat);
265 p->structbuf = p->base;
269 p->curpos = p->format;
275 * This is the old error code we used. Aparently
276 * WinNT/2k systems return ERRbuftoosmall (2123) and
277 * OS/2 needs this. I'm leaving this here so we can revert
280 p->errcode = ERRmoredata;
282 p->errcode = ERRbuftoosmall;
285 p->errcode = NERR_Success;
289 p->stringbuf = p->base + i;
291 return (p->errcode == NERR_Success);
294 static int package(struct pack_desc *p, ...)
297 int needed=0, stringneeded;
298 const char *str=NULL;
299 int is_string=0, stringused;
306 p->curpos = p->format;
308 p->curpos = p->subformat;
313 str = va_arg(args,char*);
314 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
323 switch( *p->curpos++ ) {
324 case 'W': /* word (2 byte) */
326 temp = va_arg(args,int);
327 if (p->buflen >= needed) {
328 SSVAL(p->structbuf,0,temp);
331 case 'K': /* status word? (2 byte) */
333 temp = va_arg(args,int);
334 if (p->buflen >= needed) {
335 SSVAL(p->structbuf,0,temp);
338 case 'N': /* count of substructures (word) at end */
340 p->subcount = va_arg(args,int);
341 if (p->buflen >= needed) {
342 SSVAL(p->structbuf,0,p->subcount);
345 case 'D': /* double word (4 byte) */
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SIVAL(p->structbuf,0,temp);
352 case 'B': /* byte (with optional counter) */
353 needed = get_counter(&p->curpos);
355 char *s = va_arg(args,char*);
356 if (p->buflen >= needed) {
357 StrnCpy(p->structbuf,s?s:"",needed-1);
361 case 'z': /* offset to zero terminated string (4 byte) */
362 str = va_arg(args,char*);
363 stringneeded = (str ? strlen(str)+1 : 0);
366 case 'l': /* offset to user data (4 byte) */
367 str = va_arg(args,char*);
368 stringneeded = va_arg(args,int);
371 case 'b': /* offset to data (with counter) (4 byte) */
372 str = va_arg(args,char*);
373 stringneeded = get_counter(&p->curpos);
379 if (stringneeded >= 0) {
381 if (p->buflen >= needed) {
382 stringused = stringneeded;
383 if (stringused > p->stringlen) {
384 stringused = (is_string ? p->stringlen : 0);
385 if (p->errcode == NERR_Success) {
386 p->errcode = ERRmoredata;
390 SIVAL(p->structbuf,0,0);
392 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
393 memcpy(p->stringbuf,str?str:"",stringused);
395 p->stringbuf[stringused-1] = '\0';
397 p->stringbuf += stringused;
398 p->stringlen -= stringused;
399 p->usedlen += stringused;
402 p->neededlen += stringneeded;
405 p->neededlen += needed;
406 if (p->buflen >= needed) {
407 p->structbuf += needed;
409 p->usedlen += needed;
411 if (p->errcode == NERR_Success) {
412 p->errcode = ERRmoredata;
419 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
420 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
422 #define PACK(desc,t,v) package(desc,v)
423 #define PACKl(desc,t,v,l) package(desc,v,l)
426 static void PACKI(struct pack_desc* desc, const char *t,int v)
431 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
436 /****************************************************************************
438 ****************************************************************************/
440 static void PackDriverData(struct pack_desc* desc)
442 char drivdata[4+4+32];
443 SIVAL(drivdata,0,sizeof drivdata); /* cb */
444 SIVAL(drivdata,4,1000); /* lVersion */
445 memset(drivdata+8,0,32); /* szDeviceName */
446 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
447 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
450 static int check_printq_info(struct pack_desc* desc,
451 unsigned int uLevel, char *id1, char *id2)
453 desc->subformat = NULL;
456 desc->format = "B13";
459 desc->format = "B13BWWWzzzzzWW";
462 desc->format = "B13BWWWzzzzzWN";
463 desc->subformat = "WB21BB16B10zWWzDDz";
466 desc->format = "zWWWWzzzzWWzzl";
469 desc->format = "zWWWWzzzzWNzzl";
470 desc->subformat = "WWzWWDDzz";
479 desc->format = "WzzzzzzzzN";
480 desc->subformat = "z";
483 DEBUG(0,("check_printq_info: invalid level %d\n",
487 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
488 DEBUG(0,("check_printq_info: invalid format %s\n",
489 id1 ? id1 : "<NULL>" ));
492 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
493 DEBUG(0,("check_printq_info: invalid subformat %s\n",
494 id2 ? id2 : "<NULL>" ));
501 #define RAP_JOB_STATUS_QUEUED 0
502 #define RAP_JOB_STATUS_PAUSED 1
503 #define RAP_JOB_STATUS_SPOOLING 2
504 #define RAP_JOB_STATUS_PRINTING 3
505 #define RAP_JOB_STATUS_PRINTED 4
507 #define RAP_QUEUE_STATUS_PAUSED 1
508 #define RAP_QUEUE_STATUS_ERROR 2
510 /* turn a print job status into a on the wire status
512 static int printj_spoolss_status(int v)
514 if (v == JOB_STATUS_QUEUED)
515 return RAP_JOB_STATUS_QUEUED;
516 if (v & JOB_STATUS_PAUSED)
517 return RAP_JOB_STATUS_PAUSED;
518 if (v & JOB_STATUS_SPOOLING)
519 return RAP_JOB_STATUS_SPOOLING;
520 if (v & JOB_STATUS_PRINTING)
521 return RAP_JOB_STATUS_PRINTING;
525 /* turn a print queue status into a on the wire status
527 static int printq_spoolss_status(int v)
529 if (v == PRINTER_STATUS_OK)
531 if (v & PRINTER_STATUS_PAUSED)
532 return RAP_QUEUE_STATUS_PAUSED;
533 return RAP_QUEUE_STATUS_ERROR;
536 static time_t spoolss_Time_to_time_t(const struct spoolss_Time *r)
540 unixtime.tm_year = r->year - 1900;
541 unixtime.tm_mon = r->month - 1;
542 unixtime.tm_wday = r->day_of_week;
543 unixtime.tm_mday = r->day;
544 unixtime.tm_hour = r->hour;
545 unixtime.tm_min = r->minute;
546 unixtime.tm_sec = r->second;
548 return mktime(&unixtime);
551 static void fill_spoolss_printjob_info(int uLevel,
552 struct pack_desc *desc,
553 struct spoolss_JobInfo2 *info2,
556 time_t t = spoolss_Time_to_time_t(&info2->submitted);
558 /* the client expects localtime */
559 t -= get_time_zone(t);
561 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
563 PACKS(desc,"B21", info2->user_name); /* szUserName */
564 PACKS(desc,"B",""); /* pad */
565 PACKS(desc,"B16",""); /* szNotifyName */
566 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
567 PACKS(desc,"z",""); /* pszParms */
568 PACKI(desc,"W",n+1); /* uPosition */
569 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
570 PACKS(desc,"z",""); /* pszStatus */
571 PACKI(desc,"D", t); /* ulSubmitted */
572 PACKI(desc,"D", info2->size); /* ulSize */
573 PACKS(desc,"z", info2->document_name); /* pszComment */
575 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
576 PACKI(desc,"W", info2->priority); /* uPriority */
577 PACKS(desc,"z", info2->user_name); /* pszUserName */
578 PACKI(desc,"W",n+1); /* uPosition */
579 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
580 PACKI(desc,"D",t); /* ulSubmitted */
581 PACKI(desc,"D", info2->size); /* ulSize */
582 PACKS(desc,"z","Samba"); /* pszComment */
583 PACKS(desc,"z", info2->document_name); /* pszDocument */
585 PACKS(desc,"z",""); /* pszNotifyName */
586 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
587 PACKS(desc,"z",""); /* pszParms */
588 PACKS(desc,"z",""); /* pszStatus */
589 PACKS(desc,"z", info2->printer_name); /* pszQueue */
590 PACKS(desc,"z","lpd"); /* pszQProcName */
591 PACKS(desc,"z",""); /* pszQProcParms */
592 PACKS(desc,"z","NULL"); /* pszDriverName */
593 PackDriverData(desc); /* pDriverData */
594 PACKS(desc,"z",""); /* pszPrinterName */
595 } else if (uLevel == 4) { /* OS2 */
596 PACKS(desc,"z",""); /* pszSpoolFileName */
597 PACKS(desc,"z",""); /* pszPortName */
598 PACKS(desc,"z",""); /* pszStatus */
599 PACKI(desc,"D",0); /* ulPagesSpooled */
600 PACKI(desc,"D",0); /* ulPagesSent */
601 PACKI(desc,"D",0); /* ulPagesPrinted */
602 PACKI(desc,"D",0); /* ulTimePrinted */
603 PACKI(desc,"D",0); /* ulExtendJobStatus */
604 PACKI(desc,"D",0); /* ulStartPage */
605 PACKI(desc,"D",0); /* ulEndPage */
610 /********************************************************************
611 Respond to the DosPrintQInfo command with a level of 52
612 This is used to get printer driver information for Win9x clients
613 ********************************************************************/
614 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
615 struct pack_desc* desc, int count,
616 const char *printer_name)
620 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
621 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
622 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
624 PACKI(desc, "W", 0x0400); /* don't know */
625 PACKS(desc, "z", driver->driver_name); /* long printer name */
626 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
627 PACKS(desc, "z", driver->data_file); /* Datafile name */
628 PACKS(desc, "z", driver->monitor_name); /* language monitor */
630 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
631 standard_sub_basic( "", "", location, sizeof(location)-1 );
632 PACKS(desc,"z", location); /* share to retrieve files */
634 PACKS(desc,"z", driver->default_datatype); /* default data type */
635 PACKS(desc,"z", driver->help_file); /* helpfile name */
636 PACKS(desc,"z", driver->driver_path); /* driver name */
638 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
639 DEBUG(3,("Driver: %s:\n",driver->driver_path));
640 DEBUG(3,("Data File: %s:\n",driver->data_file));
641 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
642 DEBUG(3,("Driver Location: %s:\n",location));
643 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
644 DEBUG(3,("Help File: %s:\n",driver->help_file));
645 PACKI(desc,"N",count); /* number of files to copy */
647 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
649 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
650 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
651 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
656 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
659 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
661 desc->errcode=NERR_Success;
665 static const char *strip_unc(const char *unc)
673 if ((p = strrchr(unc, '\\')) != NULL) {
680 static void fill_printq_info(int uLevel,
681 struct pack_desc* desc,
683 union spoolss_JobInfo *job_info,
684 struct spoolss_DriverInfo3 *driver_info,
685 struct spoolss_PrinterInfo2 *printer_info)
691 PACKS(desc,"B13", strip_unc(printer_info->printername));
696 PACKS(desc,"z", strip_unc(printer_info->printername));
699 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
703 if (uLevel == 1 || uLevel == 2) {
704 PACKS(desc,"B",""); /* alignment */
705 PACKI(desc,"W",5); /* priority */
706 PACKI(desc,"W",0); /* start time */
707 PACKI(desc,"W",0); /* until time */
708 PACKS(desc,"z",""); /* pSepFile */
709 PACKS(desc,"z","lpd"); /* pPrProc */
710 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
711 PACKS(desc,"z",""); /* pParms */
712 if (printer_info->printername == NULL) {
713 PACKS(desc,"z","UNKNOWN PRINTER");
714 PACKI(desc,"W",LPSTAT_ERROR);
716 PACKS(desc,"z", printer_info->comment);
717 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
719 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
722 if (uLevel == 3 || uLevel == 4) {
723 PACKI(desc,"W",5); /* uPriority */
724 PACKI(desc,"W",0); /* uStarttime */
725 PACKI(desc,"W",0); /* uUntiltime */
726 PACKI(desc,"W",5); /* pad1 */
727 PACKS(desc,"z",""); /* pszSepFile */
728 PACKS(desc,"z","WinPrint"); /* pszPrProc */
729 PACKS(desc,"z",NULL); /* pszParms */
730 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
731 /* "don't ask" that it's done this way to fix corrupted
732 Win9X/ME printer comments. */
733 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
734 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
735 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
736 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
737 PackDriverData(desc); /* pDriverData */
740 if (uLevel == 2 || uLevel == 4) {
742 for (i = 0; i < count; i++) {
743 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
748 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
751 /* This function returns the number of files for a given driver */
752 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
756 /* count the number of files */
757 while (driver->dependent_files && *driver->dependent_files[result])
763 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
764 char *param, int tpscnt,
765 char *data, int tdscnt,
766 int mdrcnt,int mprcnt,
767 char **rdata,char **rparam,
768 int *rdata_len,int *rparam_len)
770 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
771 char *str2 = skip_string(param,tpscnt,str1);
772 char *p = skip_string(param,tpscnt,str2);
777 struct pack_desc desc;
780 WERROR werr = WERR_OK;
781 TALLOC_CTX *mem_ctx = talloc_tos();
783 struct rpc_pipe_client *cli = NULL;
784 struct policy_handle handle;
785 struct spoolss_DevmodeContainer devmode_ctr;
786 union spoolss_DriverInfo driver_info;
787 union spoolss_JobInfo *job_info;
788 union spoolss_PrinterInfo printer_info;
790 if (!str1 || !str2 || !p) {
793 memset((char *)&desc,'\0',sizeof(desc));
795 p = skip_string(param,tpscnt,p);
799 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
800 str3 = get_safe_str_ptr(param,tpscnt,p,4);
801 /* str3 may be null here and is checked in check_printq_info(). */
803 /* remove any trailing username */
804 if ((p = strchr_m(QueueName,'%')))
807 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
809 /* check it's a supported varient */
810 if (!prefix_ok(str1,"zWrLh"))
812 if (!check_printq_info(&desc,uLevel,str2,str3)) {
814 * Patch from Scott Moomaw <scott@bridgewater.edu>
815 * to return the 'invalid info level' error if an
816 * unknown level was requested.
820 *rparam = smb_realloc_limit(*rparam,*rparam_len);
824 SSVALS(*rparam,0,ERRunknownlevel);
832 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
833 rpc_spoolss_dispatch, conn->server_info,
835 if (!NT_STATUS_IS_OK(status)) {
836 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
838 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
842 ZERO_STRUCT(devmode_ctr);
844 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
848 SEC_FLAG_MAXIMUM_ALLOWED,
851 if (!NT_STATUS_IS_OK(status)) {
852 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
855 if (!W_ERROR_IS_OK(werr)) {
856 desc.errcode = W_ERROR_V(werr);
860 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
865 if (!W_ERROR_IS_OK(werr)) {
866 desc.errcode = W_ERROR_V(werr);
871 uint32_t server_major_version;
872 uint32_t server_minor_version;
874 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
882 &server_major_version,
883 &server_minor_version);
884 if (!W_ERROR_IS_OK(werr)) {
885 desc.errcode = W_ERROR_V(werr);
889 count = get_printerdrivernumber(&driver_info.info3);
890 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
893 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
901 if (!W_ERROR_IS_OK(werr)) {
902 desc.errcode = W_ERROR_V(werr);
910 *rdata = smb_realloc_limit(*rdata,mdrcnt);
915 desc.buflen = mdrcnt;
918 * Don't return data but need to get correct length
919 * init_package will return wrong size if buflen=0
921 desc.buflen = getlen(desc.format);
922 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
925 if (init_package(&desc,1,count)) {
926 desc.subcount = count;
927 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
930 *rdata_len = desc.usedlen;
933 * We must set the return code to ERRbuftoosmall
934 * in order to support lanman style printing with Win NT/2k
937 if (!mdrcnt && lp_disable_spoolss())
938 desc.errcode = ERRbuftoosmall;
941 if (cli && is_valid_policy_hnd(&handle)) {
942 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
945 *rdata_len = desc.usedlen;
947 *rparam = smb_realloc_limit(*rparam,*rparam_len);
952 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,4,desc.neededlen);
956 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
963 /****************************************************************************
964 View list of all print jobs on all queues.
965 ****************************************************************************/
967 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
968 char *param, int tpscnt,
969 char *data, int tdscnt,
970 int mdrcnt, int mprcnt,
971 char **rdata, char** rparam,
972 int *rdata_len, int *rparam_len)
974 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
975 char *output_format1 = skip_string(param,tpscnt,param_format);
976 char *p = skip_string(param,tpscnt,output_format1);
977 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
978 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
980 struct pack_desc desc;
981 int *subcntarr = NULL;
982 int queuecnt = 0, subcnt = 0, succnt = 0;
984 WERROR werr = WERR_OK;
985 TALLOC_CTX *mem_ctx = talloc_tos();
987 struct rpc_pipe_client *cli = NULL;
988 struct spoolss_DevmodeContainer devmode_ctr;
989 uint32_t num_printers;
990 union spoolss_PrinterInfo *printer_info;
991 union spoolss_DriverInfo *driver_info;
992 union spoolss_JobInfo **job_info;
994 if (!param_format || !output_format1 || !p) {
998 memset((char *)&desc,'\0',sizeof(desc));
1000 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1002 if (!prefix_ok(param_format,"WrLeh")) {
1005 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1007 * Patch from Scott Moomaw <scott@bridgewater.edu>
1008 * to return the 'invalid info level' error if an
1009 * unknown level was requested.
1013 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1017 SSVALS(*rparam,0,ERRunknownlevel);
1023 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1024 rpc_spoolss_dispatch, conn->server_info,
1026 if (!NT_STATUS_IS_OK(status)) {
1027 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1028 nt_errstr(status)));
1029 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1033 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1035 cli->srv_name_slash,
1040 if (!W_ERROR_IS_OK(werr)) {
1041 desc.errcode = W_ERROR_V(werr);
1045 queuecnt = num_printers;
1047 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1048 if (job_info == NULL) {
1052 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1053 if (driver_info == NULL) {
1057 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1058 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1063 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1069 desc.buflen = mdrcnt;
1072 for (i = 0; i < num_printers; i++) {
1075 struct policy_handle handle;
1076 const char *printername;
1078 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1079 if (printername == NULL) {
1083 ZERO_STRUCT(handle);
1084 ZERO_STRUCT(devmode_ctr);
1086 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1090 SEC_FLAG_MAXIMUM_ALLOWED,
1093 if (!NT_STATUS_IS_OK(status)) {
1094 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1097 if (!W_ERROR_IS_OK(werr)) {
1098 desc.errcode = W_ERROR_V(werr);
1102 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1110 if (!W_ERROR_IS_OK(werr)) {
1111 desc.errcode = W_ERROR_V(werr);
1116 uint32_t server_major_version;
1117 uint32_t server_minor_version;
1119 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1127 &server_major_version,
1128 &server_minor_version);
1129 if (!W_ERROR_IS_OK(werr)) {
1130 desc.errcode = W_ERROR_V(werr);
1135 subcntarr[i] = num_jobs;
1136 subcnt += subcntarr[i];
1138 if (cli && is_valid_policy_hnd(&handle)) {
1139 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1143 if (init_package(&desc,queuecnt,subcnt)) {
1144 for (i = 0; i < num_printers; i++) {
1145 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1146 if (desc.errcode == NERR_Success) {
1152 SAFE_FREE(subcntarr);
1154 *rdata_len = desc.usedlen;
1156 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1160 SSVALS(*rparam,0,desc.errcode);
1162 SSVAL(*rparam,4,succnt);
1163 SSVAL(*rparam,6,queuecnt);
1169 SAFE_FREE(subcntarr);
1174 /****************************************************************************
1175 Get info level for a server list query.
1176 ****************************************************************************/
1178 static bool check_server_info(int uLevel, char* id)
1182 if (strcmp(id,"B16") != 0) {
1187 if (strcmp(id,"B16BBDz") != 0) {
1197 struct srv_info_struct {
1205 /*******************************************************************
1206 Get server info lists from the files saved by nmbd. Return the
1208 ******************************************************************/
1210 static int get_server_info(uint32 servertype,
1211 struct srv_info_struct **servers,
1217 bool local_list_only;
1220 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1222 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1226 /* request for everything is code for request all servers */
1227 if (servertype == SV_TYPE_ALL) {
1228 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1231 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1233 DEBUG(4,("Servertype search: %8x\n",servertype));
1235 for (i=0;lines[i];i++) {
1237 struct srv_info_struct *s;
1238 const char *ptr = lines[i];
1240 TALLOC_CTX *frame = NULL;
1247 if (count == alloced) {
1249 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1251 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1255 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1257 s = &(*servers)[count];
1259 frame = talloc_stackframe();
1261 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1265 fstrcpy(s->name, p);
1268 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1274 s->comment[0] = '\0';
1275 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1279 fstrcpy(s->comment, p);
1280 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1282 s->domain[0] = '\0';
1283 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1284 /* this allows us to cope with an old nmbd */
1285 fstrcpy(s->domain,lp_workgroup());
1287 fstrcpy(s->domain, p);
1291 if (sscanf(stype,"%X",&s->type) != 1) {
1292 DEBUG(4,("r:host file "));
1296 /* Filter the servers/domains we return based on what was asked for. */
1298 /* Check to see if we are being asked for a local list only. */
1299 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1300 DEBUG(4,("r: local list only"));
1304 /* doesn't match up: don't want it */
1305 if (!(servertype & s->type)) {
1306 DEBUG(4,("r:serv type "));
1310 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1311 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1312 DEBUG(4,("s: dom mismatch "));
1316 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1320 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1321 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1324 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1325 s->name, s->type, s->comment, s->domain));
1326 s->server_added = True;
1329 DEBUG(4,("%20s %8x %25s %15s\n",
1330 s->name, s->type, s->comment, s->domain));
1338 /*******************************************************************
1339 Fill in a server info structure.
1340 ******************************************************************/
1342 static int fill_srv_info(struct srv_info_struct *service,
1343 int uLevel, char **buf, int *buflen,
1344 char **stringbuf, int *stringspace, char *baseaddr)
1367 len = strlen(service->comment)+1;
1371 *buflen = struct_len;
1373 return struct_len + len;
1378 if (*buflen < struct_len) {
1385 p2 = p + struct_len;
1386 l2 = *buflen - struct_len;
1394 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1398 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1399 SIVAL(p,18,service->type);
1400 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1401 len += CopyAndAdvance(&p2,service->comment,&l2);
1406 *buf = p + struct_len;
1407 *buflen -= struct_len;
1418 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1420 return StrCaseCmp(s1->name,s2->name);
1423 /****************************************************************************
1424 View list of servers available (or possibly domains). The info is
1425 extracted from lists saved by nmbd on the local host.
1426 ****************************************************************************/
1428 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1429 char *param, int tpscnt,
1430 char *data, int tdscnt,
1431 int mdrcnt, int mprcnt, char **rdata,
1432 char **rparam, int *rdata_len, int *rparam_len)
1434 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1435 char *str2 = skip_string(param,tpscnt,str1);
1436 char *p = skip_string(param,tpscnt,str2);
1437 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1438 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1439 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1441 int data_len, fixed_len, string_len;
1442 int f_len = 0, s_len = 0;
1443 struct srv_info_struct *servers=NULL;
1444 int counted=0,total=0;
1447 bool domain_request;
1450 if (!str1 || !str2 || !p) {
1454 /* If someone sets all the bits they don't really mean to set
1455 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1458 if (servertype == SV_TYPE_ALL) {
1459 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1462 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1463 any other bit (they may just set this bit on its own) they
1464 want all the locally seen servers. However this bit can be
1465 set on its own so set the requested servers to be
1466 ALL - DOMAIN_ENUM. */
1468 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1469 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1472 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1473 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1477 if (!prefix_ok(str1,"WrLehD")) {
1480 if (!check_server_info(uLevel,str2)) {
1484 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1485 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1486 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1488 if (strcmp(str1, "WrLehDz") == 0) {
1489 if (skip_string(param,tpscnt,p) == NULL) {
1492 pull_ascii_fstring(domain, p);
1494 fstrcpy(domain, lp_workgroup());
1497 DEBUG(4, ("domain [%s]\n", domain));
1499 if (lp_browse_list()) {
1500 total = get_server_info(servertype,&servers,domain);
1503 data_len = fixed_len = string_len = 0;
1506 TYPESAFE_QSORT(servers, total, srv_comp);
1509 char *lastname=NULL;
1511 for (i=0;i<total;i++) {
1512 struct srv_info_struct *s = &servers[i];
1514 if (lastname && strequal(lastname,s->name)) {
1518 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1519 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1520 i, s->name, s->type, s->comment, s->domain));
1522 if (data_len < buf_len) {
1525 string_len += s_len;
1532 *rdata_len = fixed_len + string_len;
1533 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1538 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1544 char *lastname=NULL;
1545 int count2 = counted;
1547 for (i = 0; i < total && count2;i++) {
1548 struct srv_info_struct *s = &servers[i];
1550 if (lastname && strequal(lastname,s->name)) {
1554 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1555 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1556 i, s->name, s->type, s->comment, s->domain));
1562 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1566 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1568 SSVAL(*rparam,4,counted);
1569 SSVAL(*rparam,6,counted+missed);
1573 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1574 domain,uLevel,counted,counted+missed));
1579 static int srv_name_match(const char *n1, const char *n2)
1582 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1584 * In Windows, FirstNameToReturn need not be an exact match:
1585 * the server will return a list of servers that exist on
1586 * the network greater than or equal to the FirstNameToReturn.
1588 int ret = StrCaseCmp(n1, n2);
1597 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1598 char *param, int tpscnt,
1599 char *data, int tdscnt,
1600 int mdrcnt, int mprcnt, char **rdata,
1601 char **rparam, int *rdata_len, int *rparam_len)
1603 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1604 char *str2 = skip_string(param,tpscnt,str1);
1605 char *p = skip_string(param,tpscnt,str2);
1606 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1607 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1608 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1610 int data_len, fixed_len, string_len;
1611 int f_len = 0, s_len = 0;
1612 struct srv_info_struct *servers=NULL;
1613 int counted=0,first=0,total=0;
1617 bool domain_request;
1620 if (!str1 || !str2 || !p) {
1624 /* If someone sets all the bits they don't really mean to set
1625 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1628 if (servertype == SV_TYPE_ALL) {
1629 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1632 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1633 any other bit (they may just set this bit on its own) they
1634 want all the locally seen servers. However this bit can be
1635 set on its own so set the requested servers to be
1636 ALL - DOMAIN_ENUM. */
1638 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1639 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1642 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1643 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1647 if (strcmp(str1, "WrLehDzz") != 0) {
1650 if (!check_server_info(uLevel,str2)) {
1654 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1655 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1656 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1658 if (skip_string(param,tpscnt,p) == NULL) {
1661 pull_ascii_fstring(domain, p);
1662 if (domain[0] == '\0') {
1663 fstrcpy(domain, lp_workgroup());
1665 p = skip_string(param,tpscnt,p);
1666 if (skip_string(param,tpscnt,p) == NULL) {
1669 pull_ascii_fstring(first_name, p);
1671 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1672 domain, first_name));
1674 if (lp_browse_list()) {
1675 total = get_server_info(servertype,&servers,domain);
1678 data_len = fixed_len = string_len = 0;
1681 TYPESAFE_QSORT(servers, total, srv_comp);
1683 if (first_name[0] != '\0') {
1684 struct srv_info_struct *first_server = NULL;
1686 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1687 srv_name_match, first_server);
1689 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1691 * The binary search may not find the exact match
1692 * so we need to search backward to find the first match
1694 * This implements the strange matching windows
1695 * implements. (see the comment in srv_name_match().
1699 ret = StrCaseCmp(first_name,
1700 servers[first-1].name);
1707 /* we should return no entries */
1713 char *lastname=NULL;
1715 for (i=first;i<total;i++) {
1716 struct srv_info_struct *s = &servers[i];
1718 if (lastname && strequal(lastname,s->name)) {
1722 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1723 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1724 i, s->name, s->type, s->comment, s->domain));
1726 if (data_len < buf_len) {
1729 string_len += s_len;
1736 *rdata_len = fixed_len + string_len;
1737 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1742 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1748 char *lastname=NULL;
1749 int count2 = counted;
1751 for (i = first; i < total && count2;i++) {
1752 struct srv_info_struct *s = &servers[i];
1754 if (lastname && strequal(lastname,s->name)) {
1758 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1759 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1760 i, s->name, s->type, s->comment, s->domain));
1766 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1770 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1772 SSVAL(*rparam,4,counted);
1773 SSVAL(*rparam,6,counted+missed);
1775 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1776 domain,uLevel,first,first_name,
1777 first < total ? servers[first].name : "",
1778 counted,counted+missed));
1785 /****************************************************************************
1786 command 0x34 - suspected of being a "Lookup Names" stub api
1787 ****************************************************************************/
1789 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1790 char *param, int tpscnt,
1791 char *data, int tdscnt,
1792 int mdrcnt, int mprcnt, char **rdata,
1793 char **rparam, int *rdata_len, int *rparam_len)
1795 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1796 char *str2 = skip_string(param,tpscnt,str1);
1797 char *p = skip_string(param,tpscnt,str2);
1798 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1799 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1803 if (!str1 || !str2 || !p) {
1807 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1808 str1, str2, p, uLevel, buf_len));
1810 if (!prefix_ok(str1,"zWrLeh")) {
1817 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1822 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1824 SSVAL(*rparam,4,counted);
1825 SSVAL(*rparam,6,counted+missed);
1830 /****************************************************************************
1831 get info about a share
1832 ****************************************************************************/
1834 static bool check_share_info(int uLevel, char* id)
1838 if (strcmp(id,"B13") != 0) {
1843 /* Level-2 descriptor is allowed (and ignored) */
1844 if (strcmp(id,"B13BWz") != 0 &&
1845 strcmp(id,"B13BWzWWWzB9B") != 0) {
1850 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1855 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1865 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1866 char** buf, int* buflen,
1867 char** stringbuf, int* stringspace, char* baseaddr)
1896 len += StrlenExpanded(conn,snum,lp_comment(snum));
1899 len += strlen(lp_pathname(snum)) + 1;
1902 *buflen = struct_len;
1907 return struct_len + len;
1912 if ((*buflen) < struct_len) {
1920 p2 = p + struct_len;
1921 l2 = (*buflen) - struct_len;
1928 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1934 type = STYPE_DISKTREE;
1935 if (lp_print_ok(snum)) {
1936 type = STYPE_PRINTQ;
1938 if (strequal("IPC",lp_fstype(snum))) {
1941 SSVAL(p,14,type); /* device type */
1942 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1943 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1947 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1948 SSVALS(p,22,-1); /* max uses */
1949 SSVAL(p,24,1); /* current uses */
1950 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1951 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1952 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1956 memset(p+40,0,SHPWLEN+2);
1967 (*buf) = p + struct_len;
1968 (*buflen) -= struct_len;
1970 (*stringspace) = l2;
1979 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1980 char *param, int tpscnt,
1981 char *data, int tdscnt,
1982 int mdrcnt,int mprcnt,
1983 char **rdata,char **rparam,
1984 int *rdata_len,int *rparam_len)
1986 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1987 char *str2 = skip_string(param,tpscnt,str1);
1988 char *netname = skip_string(param,tpscnt,str2);
1989 char *p = skip_string(param,tpscnt,netname);
1990 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1993 if (!str1 || !str2 || !netname || !p) {
1997 snum = find_service(netname);
2002 /* check it's a supported varient */
2003 if (!prefix_ok(str1,"zWrLh")) {
2006 if (!check_share_info(uLevel,str2)) {
2010 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2015 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2016 if (*rdata_len < 0) {
2021 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2025 SSVAL(*rparam,0,NERR_Success);
2026 SSVAL(*rparam,2,0); /* converter word */
2027 SSVAL(*rparam,4,*rdata_len);
2032 /****************************************************************************
2033 View the list of available shares.
2035 This function is the server side of the NetShareEnum() RAP call.
2036 It fills the return buffer with share names and share comments.
2037 Note that the return buffer normally (in all known cases) allows only
2038 twelve byte strings for share names (plus one for a nul terminator).
2039 Share names longer than 12 bytes must be skipped.
2040 ****************************************************************************/
2042 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2043 char *param, int tpscnt,
2044 char *data, int tdscnt,
2052 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2053 char *str2 = skip_string(param,tpscnt,str1);
2054 char *p = skip_string(param,tpscnt,str2);
2055 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2056 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2059 int total=0,counted=0;
2060 bool missed = False;
2062 int data_len, fixed_len, string_len;
2063 int f_len = 0, s_len = 0;
2065 if (!str1 || !str2 || !p) {
2069 if (!prefix_ok(str1,"WrLeh")) {
2072 if (!check_share_info(uLevel,str2)) {
2076 /* Ensure all the usershares are loaded. */
2078 load_registry_shares();
2079 count = load_usershare_shares();
2082 data_len = fixed_len = string_len = 0;
2083 for (i=0;i<count;i++) {
2084 fstring servicename_dos;
2085 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2088 push_ascii_fstring(servicename_dos, lp_servicename(i));
2089 /* Maximum name length = 13. */
2090 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2092 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2093 if (data_len < buf_len) {
2096 string_len += s_len;
2103 *rdata_len = fixed_len + string_len;
2104 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2109 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2114 for( i = 0; i < count; i++ ) {
2115 fstring servicename_dos;
2116 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2120 push_ascii_fstring(servicename_dos, lp_servicename(i));
2121 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2122 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2129 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2133 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2135 SSVAL(*rparam,4,counted);
2136 SSVAL(*rparam,6,total);
2138 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2139 counted,total,uLevel,
2140 buf_len,*rdata_len,mdrcnt));
2145 /****************************************************************************
2147 ****************************************************************************/
2149 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2150 char *param, int tpscnt,
2151 char *data, int tdscnt,
2152 int mdrcnt,int mprcnt,
2153 char **rdata,char **rparam,
2154 int *rdata_len,int *rparam_len)
2156 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2157 char *str2 = skip_string(param,tpscnt,str1);
2158 char *p = skip_string(param,tpscnt,str2);
2159 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2162 char *pathname = NULL;
2163 unsigned int offset;
2165 size_t converted_size;
2167 WERROR werr = WERR_OK;
2168 TALLOC_CTX *mem_ctx = talloc_tos();
2170 struct rpc_pipe_client *cli = NULL;
2171 union srvsvc_NetShareInfo info;
2172 struct srvsvc_NetShareInfo2 info2;
2174 if (!str1 || !str2 || !p) {
2178 /* check it's a supported varient */
2179 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2182 if (!check_share_info(uLevel,str2)) {
2189 /* Do we have a string ? */
2190 if (skip_string(data,mdrcnt,data) == NULL) {
2193 pull_ascii_fstring(sharename,data);
2199 /* only support disk share adds */
2200 if (SVAL(data,14)!=STYPE_DISKTREE) {
2204 offset = IVAL(data, 16);
2205 if (offset >= mdrcnt) {
2206 res = ERRinvalidparam;
2210 /* Do we have a string ? */
2211 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2214 pull_ascii_fstring(comment, offset? (data+offset) : "");
2216 offset = IVAL(data, 26);
2218 if (offset >= mdrcnt) {
2219 res = ERRinvalidparam;
2223 /* Do we have a string ? */
2224 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2228 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2229 offset ? (data+offset) : "", &converted_size))
2231 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2239 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2240 rpc_srvsvc_dispatch, conn->server_info,
2242 if (!NT_STATUS_IS_OK(status)) {
2243 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2244 nt_errstr(status)));
2245 res = W_ERROR_V(ntstatus_to_werror(status));
2249 info2.name = sharename;
2250 info2.type = STYPE_DISKTREE;
2251 info2.comment = comment;
2252 info2.permissions = 0;
2253 info2.max_users = 0;
2254 info2.current_users = 0;
2255 info2.path = pathname;
2256 info2.password = NULL;
2258 info.info2 = &info2;
2260 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2261 cli->srv_name_slash,
2266 if (!NT_STATUS_IS_OK(status)) {
2267 res = W_ERROR_V(ntstatus_to_werror(status));
2270 if (!W_ERROR_IS_OK(werr)) {
2271 res = W_ERROR_V(werr);
2276 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2280 SSVAL(*rparam,0,NERR_Success);
2281 SSVAL(*rparam,2,0); /* converter word */
2282 SSVAL(*rparam,4,*rdata_len);
2290 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2295 SSVAL(*rparam,0,res);
2300 /****************************************************************************
2301 view list of groups available
2302 ****************************************************************************/
2304 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2305 char *param, int tpscnt,
2306 char *data, int tdscnt,
2307 int mdrcnt,int mprcnt,
2308 char **rdata,char **rparam,
2309 int *rdata_len,int *rparam_len)
2313 int resume_context, cli_buf_size;
2314 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2315 char *str2 = skip_string(param,tpscnt,str1);
2316 char *p = skip_string(param,tpscnt,str2);
2318 uint32_t num_groups;
2319 uint32_t resume_handle;
2320 struct rpc_pipe_client *samr_pipe;
2321 struct policy_handle samr_handle, domain_handle;
2324 if (!str1 || !str2 || !p) {
2328 if (strcmp(str1,"WrLeh") != 0) {
2333 * W-> resume context (number of users to skip)
2334 * r -> return parameter pointer to receive buffer
2335 * L -> length of receive buffer
2336 * e -> return parameter number of entries
2337 * h -> return parameter total number of users
2340 if (strcmp("B21",str2) != 0) {
2344 status = rpc_pipe_open_internal(
2345 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2346 conn->server_info, &samr_pipe);
2347 if (!NT_STATUS_IS_OK(status)) {
2348 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2349 nt_errstr(status)));
2353 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2354 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2355 if (!NT_STATUS_IS_OK(status)) {
2356 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2357 nt_errstr(status)));
2361 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2362 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2363 get_global_sam_sid(), &domain_handle);
2364 if (!NT_STATUS_IS_OK(status)) {
2365 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2366 nt_errstr(status)));
2367 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2371 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2372 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2373 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2374 "%d\n", resume_context, cli_buf_size));
2376 *rdata_len = cli_buf_size;
2377 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2384 errflags = NERR_Success;
2389 struct samr_SamArray *sam_entries;
2390 uint32_t num_entries;
2392 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2397 if (!NT_STATUS_IS_OK(status)) {
2398 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2399 "%s\n", nt_errstr(status)));
2403 if (num_entries == 0) {
2404 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2405 "no entries -- done\n"));
2409 for(i=0; i<num_entries; i++) {
2412 name = sam_entries->entries[i].name.string;
2414 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2415 /* set overflow error */
2416 DEBUG(3,("overflow on entry %d group %s\n", i,
2422 /* truncate the name at 21 chars. */
2424 strlcpy(p, name, 21);
2425 DEBUG(10,("adding entry %d group %s\n", i, p));
2427 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2432 if (errflags != NERR_Success) {
2436 TALLOC_FREE(sam_entries);
2439 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2440 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2442 *rdata_len = PTR_DIFF(p,*rdata);
2445 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2449 SSVAL(*rparam, 0, errflags);
2450 SSVAL(*rparam, 2, 0); /* converter word */
2451 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2452 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2457 /*******************************************************************
2458 Get groups that a user is a member of.
2459 ******************************************************************/
2461 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2462 char *param, int tpscnt,
2463 char *data, int tdscnt,
2464 int mdrcnt,int mprcnt,
2465 char **rdata,char **rparam,
2466 int *rdata_len,int *rparam_len)
2468 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2469 char *str2 = skip_string(param,tpscnt,str1);
2470 char *UserName = skip_string(param,tpscnt,str2);
2471 char *p = skip_string(param,tpscnt,UserName);
2472 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2473 const char *level_string;
2479 struct rpc_pipe_client *samr_pipe;
2480 struct policy_handle samr_handle, domain_handle, user_handle;
2481 struct lsa_String name;
2482 struct lsa_Strings names;
2483 struct samr_Ids type, rid;
2484 struct samr_RidWithAttributeArray *rids;
2487 if (!str1 || !str2 || !UserName || !p) {
2492 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2497 /* check it's a supported varient */
2499 if ( strcmp(str1,"zWrLeh") != 0 )
2504 level_string = "B21";
2510 if (strcmp(level_string,str2) != 0)
2513 *rdata_len = mdrcnt + 1024;
2514 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2519 SSVAL(*rparam,0,NERR_Success);
2520 SSVAL(*rparam,2,0); /* converter word */
2523 endp = *rdata + *rdata_len;
2525 status = rpc_pipe_open_internal(
2526 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2527 conn->server_info, &samr_pipe);
2528 if (!NT_STATUS_IS_OK(status)) {
2529 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2530 nt_errstr(status)));
2534 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2535 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2536 if (!NT_STATUS_IS_OK(status)) {
2537 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2538 nt_errstr(status)));
2542 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2543 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2544 get_global_sam_sid(), &domain_handle);
2545 if (!NT_STATUS_IS_OK(status)) {
2546 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2547 nt_errstr(status)));
2551 name.string = UserName;
2553 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2554 &domain_handle, 1, &name,
2556 if (!NT_STATUS_IS_OK(status)) {
2557 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2558 nt_errstr(status)));
2562 if (type.ids[0] != SID_NAME_USER) {
2563 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2564 sid_type_lookup(type.ids[0])));
2568 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2570 SAMR_USER_ACCESS_GET_GROUPS,
2571 rid.ids[0], &user_handle);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2574 nt_errstr(status)));
2578 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2579 &user_handle, &rids);
2580 if (!NT_STATUS_IS_OK(status)) {
2581 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2582 nt_errstr(status)));
2586 for (i=0; i<rids->count; i++) {
2588 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2590 1, &rids->rids[i].rid,
2592 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2593 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2599 *rdata_len = PTR_DIFF(p,*rdata);
2601 SSVAL(*rparam,4,count); /* is this right?? */
2602 SSVAL(*rparam,6,count); /* is this right?? */
2607 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2609 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2611 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2616 /*******************************************************************
2618 ******************************************************************/
2620 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2621 char *param, int tpscnt,
2622 char *data, int tdscnt,
2623 int mdrcnt,int mprcnt,
2624 char **rdata,char **rparam,
2625 int *rdata_len,int *rparam_len)
2630 int i, resume_context, cli_buf_size;
2631 uint32_t resume_handle;
2633 struct rpc_pipe_client *samr_pipe;
2634 struct policy_handle samr_handle, domain_handle;
2637 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2638 char *str2 = skip_string(param,tpscnt,str1);
2639 char *p = skip_string(param,tpscnt,str2);
2642 if (!str1 || !str2 || !p) {
2646 if (strcmp(str1,"WrLeh") != 0)
2649 * W-> resume context (number of users to skip)
2650 * r -> return parameter pointer to receive buffer
2651 * L -> length of receive buffer
2652 * e -> return parameter number of entries
2653 * h -> return parameter total number of users
2656 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2657 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2658 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2659 resume_context, cli_buf_size));
2662 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2667 /* check it's a supported varient */
2668 if (strcmp("B21",str2) != 0)
2671 *rdata_len = cli_buf_size;
2672 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2678 endp = *rdata + *rdata_len;
2680 status = rpc_pipe_open_internal(
2681 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2682 conn->server_info, &samr_pipe);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2685 nt_errstr(status)));
2689 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2690 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2691 if (!NT_STATUS_IS_OK(status)) {
2692 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2693 nt_errstr(status)));
2697 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2698 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2699 get_global_sam_sid(), &domain_handle);
2700 if (!NT_STATUS_IS_OK(status)) {
2701 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2702 nt_errstr(status)));
2703 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2707 errflags=NERR_Success;
2712 struct samr_SamArray *sam_entries;
2713 uint32_t num_entries;
2715 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2721 if (!NT_STATUS_IS_OK(status)) {
2722 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2723 "%s\n", nt_errstr(status)));
2727 if (num_entries == 0) {
2728 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2729 "no entries -- done\n"));
2733 for (i=0; i<num_entries; i++) {
2736 name = sam_entries->entries[i].name.string;
2738 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2739 &&(strlen(name)<=21)) {
2740 strlcpy(p,name,PTR_DIFF(endp,p));
2741 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2742 "username %s\n",count_sent,p));
2746 /* set overflow error */
2747 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2748 "username %s\n",count_sent,name));
2754 if (errflags != NERR_Success) {
2758 TALLOC_FREE(sam_entries);
2761 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2762 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2764 *rdata_len = PTR_DIFF(p,*rdata);
2766 SSVAL(*rparam,0,errflags);
2767 SSVAL(*rparam,2,0); /* converter word */
2768 SSVAL(*rparam,4,count_sent); /* is this right?? */
2769 SSVAL(*rparam,6,num_users); /* is this right?? */
2774 /****************************************************************************
2775 Get the time of day info.
2776 ****************************************************************************/
2778 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2779 char *param, int tpscnt,
2780 char *data, int tdscnt,
2781 int mdrcnt,int mprcnt,
2782 char **rdata,char **rparam,
2783 int *rdata_len,int *rparam_len)
2786 time_t unixdate = time(NULL);
2790 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2796 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2801 SSVAL(*rparam,0,NERR_Success);
2802 SSVAL(*rparam,2,0); /* converter word */
2806 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2807 by NT in a "net time" operation,
2808 it seems to ignore the one below */
2810 /* the client expects to get localtime, not GMT, in this bit
2811 (I think, this needs testing) */
2812 t = localtime(&unixdate);
2817 SIVAL(p,4,0); /* msecs ? */
2818 SCVAL(p,8,t->tm_hour);
2819 SCVAL(p,9,t->tm_min);
2820 SCVAL(p,10,t->tm_sec);
2821 SCVAL(p,11,0); /* hundredths of seconds */
2822 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2823 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2824 SCVAL(p,16,t->tm_mday);
2825 SCVAL(p,17,t->tm_mon + 1);
2826 SSVAL(p,18,1900+t->tm_year);
2827 SCVAL(p,20,t->tm_wday);
2832 /****************************************************************************
2833 Set the user password.
2834 *****************************************************************************/
2836 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2837 char *param, int tpscnt,
2838 char *data, int tdscnt,
2839 int mdrcnt,int mprcnt,
2840 char **rdata,char **rparam,
2841 int *rdata_len,int *rparam_len)
2843 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2846 fstring pass1,pass2;
2848 /* Skip 2 strings. */
2849 p = skip_string(param,tpscnt,np);
2850 p = skip_string(param,tpscnt,p);
2856 /* Do we have a string ? */
2857 if (skip_string(param,tpscnt,p) == NULL) {
2860 pull_ascii_fstring(user,p);
2862 p = skip_string(param,tpscnt,p);
2867 memset(pass1,'\0',sizeof(pass1));
2868 memset(pass2,'\0',sizeof(pass2));
2870 * We use 31 here not 32 as we're checking
2871 * the last byte we want to access is safe.
2873 if (!is_offset_safe(param,tpscnt,p,31)) {
2877 memcpy(pass2,p+16,16);
2880 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2887 SSVAL(*rparam,0,NERR_badpass);
2888 SSVAL(*rparam,2,0); /* converter word */
2890 DEBUG(3,("Set password for <%s>\n",user));
2893 * Attempt to verify the old password against smbpasswd entries
2894 * Win98 clients send old and new password in plaintext for this call.
2898 struct auth_serversupplied_info *server_info = NULL;
2899 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2901 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2904 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2905 SSVAL(*rparam,0,NERR_Success);
2909 TALLOC_FREE(server_info);
2911 data_blob_clear_free(&password);
2915 * If the plaintext change failed, attempt
2916 * the old encrypted method. NT will generate this
2917 * after trying the samr method. Note that this
2918 * method is done as a last resort as this
2919 * password change method loses the NT password hash
2920 * and cannot change the UNIX password as no plaintext
2924 if(SVAL(*rparam,0) != NERR_Success) {
2925 struct samu *hnd = NULL;
2927 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2929 if (change_lanman_password(hnd,(uchar *)pass2)) {
2930 SSVAL(*rparam,0,NERR_Success);
2937 memset((char *)pass1,'\0',sizeof(fstring));
2938 memset((char *)pass2,'\0',sizeof(fstring));
2943 /****************************************************************************
2944 Set the user password (SamOEM version - gets plaintext).
2945 ****************************************************************************/
2947 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2948 char *param, int tpscnt,
2949 char *data, int tdscnt,
2950 int mdrcnt,int mprcnt,
2951 char **rdata,char **rparam,
2952 int *rdata_len,int *rparam_len)
2954 struct smbd_server_connection *sconn = smbd_server_conn;
2956 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2958 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2968 SSVAL(*rparam,0,NERR_badpass);
2971 * Check the parameter definition is correct.
2974 /* Do we have a string ? */
2975 if (skip_string(param,tpscnt,p) == 0) {
2978 if(!strequal(p, "zsT")) {
2979 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2982 p = skip_string(param, tpscnt, p);
2987 /* Do we have a string ? */
2988 if (skip_string(param,tpscnt,p) == 0) {
2991 if(!strequal(p, "B516B16")) {
2992 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2995 p = skip_string(param,tpscnt,p);
2999 /* Do we have a string ? */
3000 if (skip_string(param,tpscnt,p) == 0) {
3003 p += pull_ascii_fstring(user,p);
3005 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3008 * Pass the user through the NT -> unix user mapping
3012 (void)map_username(sconn, user);
3014 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
3015 SSVAL(*rparam,0,NERR_Success);
3021 /****************************************************************************
3024 ****************************************************************************/
3026 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3027 char *param, int tpscnt,
3028 char *data, int tdscnt,
3029 int mdrcnt,int mprcnt,
3030 char **rdata,char **rparam,
3031 int *rdata_len,int *rparam_len)
3033 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3034 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3035 char *str2 = skip_string(param,tpscnt,str1);
3036 char *p = skip_string(param,tpscnt,str2);
3040 WERROR werr = WERR_OK;
3042 TALLOC_CTX *mem_ctx = talloc_tos();
3044 struct rpc_pipe_client *cli = NULL;
3045 struct policy_handle handle;
3046 struct spoolss_DevmodeContainer devmode_ctr;
3047 enum spoolss_JobControl command;
3049 if (!str1 || !str2 || !p) {
3053 * We use 1 here not 2 as we're checking
3054 * the last byte we want to access is safe.
3056 if (!is_offset_safe(param,tpscnt,p,1)) {
3059 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3062 /* check it's a supported varient */
3063 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3067 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3073 ZERO_STRUCT(handle);
3075 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3076 rpc_spoolss_dispatch, conn->server_info,
3078 if (!NT_STATUS_IS_OK(status)) {
3079 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3080 nt_errstr(status)));
3081 errcode = W_ERROR_V(ntstatus_to_werror(status));
3085 ZERO_STRUCT(devmode_ctr);
3087 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3091 SEC_FLAG_MAXIMUM_ALLOWED,
3094 if (!NT_STATUS_IS_OK(status)) {
3095 errcode = W_ERROR_V(ntstatus_to_werror(status));
3098 if (!W_ERROR_IS_OK(werr)) {
3099 errcode = W_ERROR_V(werr);
3103 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3104 * and NERR_DestNotFound if share did not exist */
3106 errcode = NERR_Success;
3109 case 81: /* delete */
3110 command = SPOOLSS_JOB_CONTROL_DELETE;
3112 case 82: /* pause */
3113 command = SPOOLSS_JOB_CONTROL_PAUSE;
3115 case 83: /* resume */
3116 command = SPOOLSS_JOB_CONTROL_RESUME;
3119 errcode = NERR_notsupported;
3123 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3126 NULL, /* unique ptr ctr */
3129 if (!NT_STATUS_IS_OK(status)) {
3130 errcode = W_ERROR_V(ntstatus_to_werror(status));
3133 if (!W_ERROR_IS_OK(werr)) {
3134 errcode = W_ERROR_V(werr);
3139 if (cli && is_valid_policy_hnd(&handle)) {
3140 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3143 SSVAL(*rparam,0,errcode);
3144 SSVAL(*rparam,2,0); /* converter word */
3149 /****************************************************************************
3150 Purge a print queue - or pause or resume it.
3151 ****************************************************************************/
3153 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3154 char *param, int tpscnt,
3155 char *data, int tdscnt,
3156 int mdrcnt,int mprcnt,
3157 char **rdata,char **rparam,
3158 int *rdata_len,int *rparam_len)
3160 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3161 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3162 char *str2 = skip_string(param,tpscnt,str1);
3163 char *QueueName = skip_string(param,tpscnt,str2);
3164 int errcode = NERR_notsupported;
3165 WERROR werr = WERR_OK;
3168 TALLOC_CTX *mem_ctx = talloc_tos();
3169 struct rpc_pipe_client *cli = NULL;
3170 struct policy_handle handle;
3171 struct spoolss_SetPrinterInfoCtr info_ctr;
3172 struct spoolss_DevmodeContainer devmode_ctr;
3173 struct sec_desc_buf secdesc_ctr;
3174 enum spoolss_PrinterControl command;
3176 if (!str1 || !str2 || !QueueName) {
3180 /* check it's a supported varient */
3181 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3185 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3191 if (skip_string(param,tpscnt,QueueName) == NULL) {
3195 ZERO_STRUCT(handle);
3197 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3198 rpc_spoolss_dispatch, conn->server_info,
3200 if (!NT_STATUS_IS_OK(status)) {
3201 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3202 nt_errstr(status)));
3203 errcode = W_ERROR_V(ntstatus_to_werror(status));
3207 ZERO_STRUCT(devmode_ctr);
3209 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3213 SEC_FLAG_MAXIMUM_ALLOWED,
3216 if (!NT_STATUS_IS_OK(status)) {
3217 errcode = W_ERROR_V(ntstatus_to_werror(status));
3220 if (!W_ERROR_IS_OK(werr)) {
3221 errcode = W_ERROR_V(werr);
3226 case 74: /* Pause queue */
3227 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3229 case 75: /* Resume queue */
3230 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3232 case 103: /* Purge */
3233 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3236 werr = WERR_NOT_SUPPORTED;
3240 if (!W_ERROR_IS_OK(werr)) {
3241 errcode = W_ERROR_V(werr);
3245 ZERO_STRUCT(info_ctr);
3246 ZERO_STRUCT(secdesc_ctr);
3248 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3255 if (!NT_STATUS_IS_OK(status)) {
3256 errcode = W_ERROR_V(ntstatus_to_werror(status));
3259 if (!W_ERROR_IS_OK(werr)) {
3260 errcode = W_ERROR_V(werr);
3264 errcode = W_ERROR_V(werr);
3268 if (cli && is_valid_policy_hnd(&handle)) {
3269 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3272 SSVAL(*rparam,0,errcode);
3273 SSVAL(*rparam,2,0); /* converter word */
3278 /****************************************************************************
3279 set the property of a print job (undocumented?)
3280 ? function = 0xb -> set name of print job
3281 ? function = 0x6 -> move print job up/down
3282 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3283 or <WWsTP> <WB21BB16B10zWWzDDz>
3284 ****************************************************************************/
3286 static int check_printjob_info(struct pack_desc* desc,
3287 int uLevel, char* id)
3289 desc->subformat = NULL;
3291 case 0: desc->format = "W"; break;
3292 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3293 case 2: desc->format = "WWzWWDDzz"; break;
3294 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3295 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3297 DEBUG(0,("check_printjob_info: invalid level %d\n",
3301 if (id == NULL || strcmp(desc->format,id) != 0) {
3302 DEBUG(0,("check_printjob_info: invalid format %s\n",
3303 id ? id : "<NULL>" ));
3309 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3310 char *param, int tpscnt,
3311 char *data, int tdscnt,
3312 int mdrcnt,int mprcnt,
3313 char **rdata,char **rparam,
3314 int *rdata_len,int *rparam_len)
3316 struct pack_desc desc;
3317 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3318 char *str2 = skip_string(param,tpscnt,str1);
3319 char *p = skip_string(param,tpscnt,str2);
3322 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3323 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3326 TALLOC_CTX *mem_ctx = talloc_tos();
3329 struct rpc_pipe_client *cli = NULL;
3330 struct policy_handle handle;
3331 struct spoolss_DevmodeContainer devmode_ctr;
3332 struct spoolss_JobInfoContainer ctr;
3333 union spoolss_JobInfo info;
3334 struct spoolss_SetJobInfo1 info1;
3336 if (!str1 || !str2 || !p) {
3340 * We use 1 here not 2 as we're checking
3341 * the last byte we want to access is safe.
3343 if (!is_offset_safe(param,tpscnt,p,1)) {
3346 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3349 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3356 /* check it's a supported varient */
3357 if ((strcmp(str1,"WWsTP")) ||
3358 (!check_printjob_info(&desc,uLevel,str2)))
3361 errcode = NERR_notsupported;
3365 /* change print job name, data gives the name */
3371 ZERO_STRUCT(handle);
3373 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3374 rpc_spoolss_dispatch, conn->server_info,
3376 if (!NT_STATUS_IS_OK(status)) {
3377 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3378 nt_errstr(status)));
3379 errcode = W_ERROR_V(ntstatus_to_werror(status));
3383 ZERO_STRUCT(devmode_ctr);
3385 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3389 SEC_FLAG_MAXIMUM_ALLOWED,
3392 if (!NT_STATUS_IS_OK(status)) {
3393 errcode = W_ERROR_V(ntstatus_to_werror(status));
3396 if (!W_ERROR_IS_OK(werr)) {
3397 errcode = W_ERROR_V(werr);
3401 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3407 if (!W_ERROR_IS_OK(werr)) {
3408 errcode = W_ERROR_V(werr);
3414 info1.job_id = info.info1.job_id;
3415 info1.printer_name = info.info1.printer_name;
3416 info1.user_name = info.info1.user_name;
3417 info1.document_name = data;
3418 info1.data_type = info.info1.data_type;
3419 info1.text_status = info.info1.text_status;
3420 info1.status = info.info1.status;
3421 info1.priority = info.info1.priority;
3422 info1.position = info.info1.position;
3423 info1.total_pages = info.info1.total_pages;
3424 info1.pages_printed = info.info1.pages_printed;
3425 info1.submitted = info.info1.submitted;
3428 ctr.info.info1 = &info1;
3430 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3436 if (!NT_STATUS_IS_OK(status)) {
3437 errcode = W_ERROR_V(ntstatus_to_werror(status));
3440 if (!W_ERROR_IS_OK(werr)) {
3441 errcode = W_ERROR_V(werr);
3445 errcode = NERR_Success;
3448 if (cli && is_valid_policy_hnd(&handle)) {
3449 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3452 SSVALS(*rparam,0,errcode);
3453 SSVAL(*rparam,2,0); /* converter word */
3459 /****************************************************************************
3460 Get info about the server.
3461 ****************************************************************************/
3463 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3464 char *param, int tpscnt,
3465 char *data, int tdscnt,
3466 int mdrcnt,int mprcnt,
3467 char **rdata,char **rparam,
3468 int *rdata_len,int *rparam_len)
3470 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3471 char *str2 = skip_string(param,tpscnt,str1);
3472 char *p = skip_string(param,tpscnt,str2);
3473 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3477 if (!str1 || !str2 || !p) {
3481 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3483 /* check it's a supported varient */
3484 if (!prefix_ok(str1,"WrLh")) {
3490 if (strcmp(str2,"B16") != 0) {
3496 if (strcmp(str2,"B16BBDz") != 0) {
3502 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3508 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3514 if (strcmp(str2,"DN") != 0) {
3520 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3529 *rdata_len = mdrcnt;
3530 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3536 p2 = p + struct_len;
3538 srvstr_push(NULL, 0, p,global_myname(),16,
3539 STR_ASCII|STR_UPPER|STR_TERMINATE);
3543 struct srv_info_struct *servers=NULL;
3545 char *comment = NULL;
3546 TALLOC_CTX *ctx = talloc_tos();
3547 uint32 servertype= lp_default_server_announce();
3549 comment = talloc_strdup(ctx,lp_serverstring());
3554 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3555 for (i=0;i<count;i++) {
3556 if (strequal(servers[i].name,global_myname())) {
3557 servertype = servers[i].type;
3558 TALLOC_FREE(comment);
3559 comment = talloc_strdup(ctx,
3560 servers[i].comment);
3570 SCVAL(p,0,lp_major_announce_version());
3571 SCVAL(p,1,lp_minor_announce_version());
3572 SIVAL(p,2,servertype);
3574 if (mdrcnt == struct_len) {
3577 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3578 comment = talloc_sub_advanced(
3580 lp_servicename(SNUM(conn)),
3581 conn->server_info->unix_name,
3583 conn->server_info->utok.gid,
3584 conn->server_info->sanitized_username,
3585 pdb_get_domain(conn->server_info->sam_account),
3590 if (mdrcnt - struct_len <= 0) {
3595 MIN(mdrcnt - struct_len,
3596 MAX_SERVER_STRING_LENGTH),
3598 p2 = skip_string(*rdata,*rdata_len,p2);
3606 return False; /* not yet implemented */
3609 *rdata_len = PTR_DIFF(p2,*rdata);
3612 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3616 SSVAL(*rparam,0,NERR_Success);
3617 SSVAL(*rparam,2,0); /* converter word */
3618 SSVAL(*rparam,4,*rdata_len);
3623 /****************************************************************************
3624 Get info about the server.
3625 ****************************************************************************/
3627 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3628 char *param, int tpscnt,
3629 char *data, int tdscnt,
3630 int mdrcnt,int mprcnt,
3631 char **rdata,char **rparam,
3632 int *rdata_len,int *rparam_len)
3634 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3635 char *str2 = skip_string(param,tpscnt,str1);
3636 char *p = skip_string(param,tpscnt,str2);
3639 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3641 if (!str1 || !str2 || !p) {
3645 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3648 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3653 /* check it's a supported varient */
3654 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3658 *rdata_len = mdrcnt + 1024;
3659 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3664 SSVAL(*rparam,0,NERR_Success);
3665 SSVAL(*rparam,2,0); /* converter word */
3668 endp = *rdata + *rdata_len;
3670 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3675 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3676 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3678 p2 = skip_string(*rdata,*rdata_len,p2);
3684 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3685 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3686 p2 = skip_string(*rdata,*rdata_len,p2);
3692 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3693 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3695 p2 = skip_string(*rdata,*rdata_len,p2);
3701 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3702 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3705 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3706 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3707 p2 = skip_string(*rdata,*rdata_len,p2);
3713 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3714 strlcpy(p2,"",PTR_DIFF(endp,p2));
3715 p2 = skip_string(*rdata,*rdata_len,p2);
3721 *rdata_len = PTR_DIFF(p2,*rdata);
3723 SSVAL(*rparam,4,*rdata_len);
3728 /****************************************************************************
3729 get info about a user
3731 struct user_info_11 {
3732 char usri11_name[21]; 0-20
3734 char *usri11_comment; 22-25
3735 char *usri11_usr_comment; 26-29
3736 unsigned short usri11_priv; 30-31
3737 unsigned long usri11_auth_flags; 32-35
3738 long usri11_password_age; 36-39
3739 char *usri11_homedir; 40-43
3740 char *usri11_parms; 44-47
3741 long usri11_last_logon; 48-51
3742 long usri11_last_logoff; 52-55
3743 unsigned short usri11_bad_pw_count; 56-57
3744 unsigned short usri11_num_logons; 58-59
3745 char *usri11_logon_server; 60-63
3746 unsigned short usri11_country_code; 64-65
3747 char *usri11_workstations; 66-69
3748 unsigned long usri11_max_storage; 70-73
3749 unsigned short usri11_units_per_week; 74-75
3750 unsigned char *usri11_logon_hours; 76-79
3751 unsigned short usri11_code_page; 80-81
3756 usri11_name specifies the user name for which information is retrieved
3758 usri11_pad aligns the next data structure element to a word boundary
3760 usri11_comment is a null terminated ASCII comment
3762 usri11_user_comment is a null terminated ASCII comment about the user
3764 usri11_priv specifies the level of the privilege assigned to the user.
3765 The possible values are:
3767 Name Value Description
3768 USER_PRIV_GUEST 0 Guest privilege
3769 USER_PRIV_USER 1 User privilege
3770 USER_PRV_ADMIN 2 Administrator privilege
3772 usri11_auth_flags specifies the account operator privileges. The
3773 possible values are:
3775 Name Value Description
3776 AF_OP_PRINT 0 Print operator
3779 Leach, Naik [Page 28]
3783 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3786 AF_OP_COMM 1 Communications operator
3787 AF_OP_SERVER 2 Server operator
3788 AF_OP_ACCOUNTS 3 Accounts operator
3791 usri11_password_age specifies how many seconds have elapsed since the
3792 password was last changed.
3794 usri11_home_dir points to a null terminated ASCII string that contains
3795 the path name of the user's home directory.
3797 usri11_parms points to a null terminated ASCII string that is set
3798 aside for use by applications.
3800 usri11_last_logon specifies the time when the user last logged on.
3801 This value is stored as the number of seconds elapsed since
3802 00:00:00, January 1, 1970.
3804 usri11_last_logoff specifies the time when the user last logged off.
3805 This value is stored as the number of seconds elapsed since
3806 00:00:00, January 1, 1970. A value of 0 means the last logoff
3809 usri11_bad_pw_count specifies the number of incorrect passwords
3810 entered since the last successful logon.
3812 usri11_log1_num_logons specifies the number of times this user has
3813 logged on. A value of -1 means the number of logons is unknown.
3815 usri11_logon_server points to a null terminated ASCII string that
3816 contains the name of the server to which logon requests are sent.
3817 A null string indicates logon requests should be sent to the
3820 usri11_country_code specifies the country code for the user's language
3823 usri11_workstations points to a null terminated ASCII string that
3824 contains the names of workstations the user may log on from.
3825 There may be up to 8 workstations, with the names separated by
3826 commas. A null strings indicates there are no restrictions.
3828 usri11_max_storage specifies the maximum amount of disk space the user
3829 can occupy. A value of 0xffffffff indicates there are no
3832 usri11_units_per_week specifies the equal number of time units into
3833 which a week is divided. This value must be equal to 168.
3835 usri11_logon_hours points to a 21 byte (168 bits) string that
3836 specifies the time during which the user can log on. Each bit
3837 represents one unique hour in a week. The first bit (bit 0, word
3838 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3842 Leach, Naik [Page 29]
3846 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3849 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3850 are no restrictions.
3852 usri11_code_page specifies the code page for the user's language of
3855 All of the pointers in this data structure need to be treated
3856 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3857 to be ignored. The converter word returned in the parameters section
3858 needs to be subtracted from the lower 16 bits to calculate an offset
3859 into the return buffer where this ASCII string resides.
3861 There is no auxiliary data in the response.
3863 ****************************************************************************/
3865 #define usri11_name 0
3866 #define usri11_pad 21
3867 #define usri11_comment 22
3868 #define usri11_usr_comment 26
3869 #define usri11_full_name 30
3870 #define usri11_priv 34
3871 #define usri11_auth_flags 36
3872 #define usri11_password_age 40
3873 #define usri11_homedir 44
3874 #define usri11_parms 48
3875 #define usri11_last_logon 52
3876 #define usri11_last_logoff 56
3877 #define usri11_bad_pw_count 60
3878 #define usri11_num_logons 62
3879 #define usri11_logon_server 64
3880 #define usri11_country_code 68
3881 #define usri11_workstations 70
3882 #define usri11_max_storage 74
3883 #define usri11_units_per_week 78
3884 #define usri11_logon_hours 80
3885 #define usri11_code_page 84
3886 #define usri11_end 86
3888 #define USER_PRIV_GUEST 0
3889 #define USER_PRIV_USER 1
3890 #define USER_PRIV_ADMIN 2
3892 #define AF_OP_PRINT 0
3893 #define AF_OP_COMM 1
3894 #define AF_OP_SERVER 2
3895 #define AF_OP_ACCOUNTS 3
3898 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3899 char *param, int tpscnt,
3900 char *data, int tdscnt,
3901 int mdrcnt,int mprcnt,
3902 char **rdata,char **rparam,
3903 int *rdata_len,int *rparam_len)
3905 struct smbd_server_connection *sconn = smbd_server_conn;
3906 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3907 char *str2 = skip_string(param,tpscnt,str1);
3908 char *UserName = skip_string(param,tpscnt,str2);
3909 char *p = skip_string(param,tpscnt,UserName);
3910 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3913 const char *level_string;
3915 /* get NIS home of a previously validated user - simeon */
3916 /* With share level security vuid will always be zero.
3917 Don't depend on vuser being non-null !!. JRA */
3918 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3920 DEBUG(3,(" Username of UID %d is %s\n",
3921 (int)vuser->server_info->utok.uid,
3922 vuser->server_info->unix_name));
3925 if (!str1 || !str2 || !UserName || !p) {
3930 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3935 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3937 /* check it's a supported variant */
3938 if (strcmp(str1,"zWrLh") != 0) {
3942 case 0: level_string = "B21"; break;
3943 case 1: level_string = "B21BB16DWzzWz"; break;
3944 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3945 case 10: level_string = "B21Bzzz"; break;
3946 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3947 default: return False;
3950 if (strcmp(level_string,str2) != 0) {
3954 *rdata_len = mdrcnt + 1024;
3955 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3960 SSVAL(*rparam,0,NERR_Success);
3961 SSVAL(*rparam,2,0); /* converter word */
3964 endp = *rdata + *rdata_len;
3965 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3971 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3974 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3979 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3980 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3981 p2 = skip_string(*rdata,*rdata_len,p2);
3986 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3987 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3988 p2 = skip_string(*rdata,*rdata_len,p2);
3993 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3994 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3995 strlcpy(p2,((vuser != NULL)
3996 ? pdb_get_fullname(vuser->server_info->sam_account)
3997 : UserName),PTR_DIFF(endp,p2));
3998 p2 = skip_string(*rdata,*rdata_len,p2);
4005 const char *homedir = "";
4006 if (vuser != NULL) {
4007 homedir = pdb_get_homedir(
4008 vuser->server_info->sam_account);
4010 /* modelled after NTAS 3.51 reply */
4011 SSVAL(p,usri11_priv,
4012 (get_current_uid(conn) == sec_initial_uid())?
4013 USER_PRIV_ADMIN:USER_PRIV_USER);
4014 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4015 SIVALS(p,usri11_password_age,-1); /* password age */
4016 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4017 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4018 p2 = skip_string(*rdata,*rdata_len,p2);
4022 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4023 strlcpy(p2,"",PTR_DIFF(endp,p2));
4024 p2 = skip_string(*rdata,*rdata_len,p2);
4028 SIVAL(p,usri11_last_logon,0); /* last logon */
4029 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4030 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4031 SSVALS(p,usri11_num_logons,-1); /* num logons */
4032 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4033 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4034 p2 = skip_string(*rdata,*rdata_len,p2);
4038 SSVAL(p,usri11_country_code,0); /* country code */
4040 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4041 strlcpy(p2,"",PTR_DIFF(endp,p2));
4042 p2 = skip_string(*rdata,*rdata_len,p2);
4047 SIVALS(p,usri11_max_storage,-1); /* max storage */
4048 SSVAL(p,usri11_units_per_week,168); /* units per week */
4049 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4051 /* a simple way to get logon hours at all times. */
4053 SCVAL(p2,21,0); /* fix zero termination */
4054 p2 = skip_string(*rdata,*rdata_len,p2);
4059 SSVAL(p,usri11_code_page,0); /* code page */
4062 if (uLevel == 1 || uLevel == 2) {
4063 memset(p+22,' ',16); /* password */
4064 SIVALS(p,38,-1); /* password age */
4066 (get_current_uid(conn) == sec_initial_uid())?
4067 USER_PRIV_ADMIN:USER_PRIV_USER);
4068 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4069 strlcpy(p2, vuser ? pdb_get_homedir(
4070 vuser->server_info->sam_account) : "",
4072 p2 = skip_string(*rdata,*rdata_len,p2);
4076 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4078 SSVAL(p,52,0); /* flags */
4079 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4080 strlcpy(p2, vuser ? pdb_get_logon_script(
4081 vuser->server_info->sam_account) : "",
4083 p2 = skip_string(*rdata,*rdata_len,p2);
4088 SIVAL(p,60,0); /* auth_flags */
4089 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4090 strlcpy(p2,((vuser != NULL)
4091 ? pdb_get_fullname(vuser->server_info->sam_account)
4092 : UserName),PTR_DIFF(endp,p2));
4093 p2 = skip_string(*rdata,*rdata_len,p2);
4097 SIVAL(p,68,0); /* urs_comment */
4098 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4099 strlcpy(p2,"",PTR_DIFF(endp,p2));
4100 p2 = skip_string(*rdata,*rdata_len,p2);
4104 SIVAL(p,76,0); /* workstations */
4105 SIVAL(p,80,0); /* last_logon */
4106 SIVAL(p,84,0); /* last_logoff */
4107 SIVALS(p,88,-1); /* acct_expires */
4108 SIVALS(p,92,-1); /* max_storage */
4109 SSVAL(p,96,168); /* units_per_week */
4110 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4113 SSVALS(p,102,-1); /* bad_pw_count */
4114 SSVALS(p,104,-1); /* num_logons */
4115 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4117 TALLOC_CTX *ctx = talloc_tos();
4118 int space_rem = *rdata_len - (p2 - *rdata);
4121 if (space_rem <= 0) {
4124 tmp = talloc_strdup(ctx, "\\\\%L");
4128 tmp = talloc_sub_basic(ctx,
4141 p2 = skip_string(*rdata,*rdata_len,p2);
4145 SSVAL(p,110,49); /* country_code */
4146 SSVAL(p,112,860); /* code page */
4150 *rdata_len = PTR_DIFF(p2,*rdata);
4152 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4157 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4158 char *param, int tpscnt,
4159 char *data, int tdscnt,
4160 int mdrcnt,int mprcnt,
4161 char **rdata,char **rparam,
4162 int *rdata_len,int *rparam_len)
4164 struct smbd_server_connection *sconn = smbd_server_conn;
4165 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4166 char *str2 = skip_string(param,tpscnt,str1);
4167 char *p = skip_string(param,tpscnt,str2);
4169 struct pack_desc desc;
4171 /* With share level security vuid will always be zero.
4172 Don't depend on vuser being non-null !!. JRA */
4173 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4175 if (!str1 || !str2 || !p) {
4180 DEBUG(3,(" Username of UID %d is %s\n",
4181 (int)vuser->server_info->utok.uid,
4182 vuser->server_info->unix_name));
4185 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4186 name = get_safe_str_ptr(param,tpscnt,p,2);
4191 memset((char *)&desc,'\0',sizeof(desc));
4193 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4195 /* check it's a supported varient */
4196 if (strcmp(str1,"OOWb54WrLh") != 0) {
4199 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4203 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4210 desc.buflen = mdrcnt;
4211 desc.subformat = NULL;
4214 if (init_package(&desc,1,0)) {
4215 PACKI(&desc,"W",0); /* code */
4216 PACKS(&desc,"B21",name); /* eff. name */
4217 PACKS(&desc,"B",""); /* pad */
4219 (get_current_uid(conn) == sec_initial_uid())?
4220 USER_PRIV_ADMIN:USER_PRIV_USER);
4221 PACKI(&desc,"D",0); /* auth flags XXX */
4222 PACKI(&desc,"W",0); /* num logons */
4223 PACKI(&desc,"W",0); /* bad pw count */
4224 PACKI(&desc,"D",0); /* last logon */
4225 PACKI(&desc,"D",-1); /* last logoff */
4226 PACKI(&desc,"D",-1); /* logoff time */
4227 PACKI(&desc,"D",-1); /* kickoff time */
4228 PACKI(&desc,"D",0); /* password age */
4229 PACKI(&desc,"D",0); /* password can change */
4230 PACKI(&desc,"D",-1); /* password must change */
4234 fstrcpy(mypath,"\\\\");
4235 fstrcat(mypath,get_local_machine_name());
4237 PACKS(&desc,"z",mypath); /* computer */
4240 PACKS(&desc,"z",lp_workgroup());/* domain */
4241 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4242 vuser->server_info->sam_account) : ""); /* script path */
4243 PACKI(&desc,"D",0x00000000); /* reserved */
4246 *rdata_len = desc.usedlen;
4248 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4252 SSVALS(*rparam,0,desc.errcode);
4254 SSVAL(*rparam,4,desc.neededlen);
4256 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4261 /****************************************************************************
4262 api_WAccessGetUserPerms
4263 ****************************************************************************/
4265 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4266 char *param, int tpscnt,
4267 char *data, int tdscnt,
4268 int mdrcnt,int mprcnt,
4269 char **rdata,char **rparam,
4270 int *rdata_len,int *rparam_len)
4272 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4273 char *str2 = skip_string(param,tpscnt,str1);
4274 char *user = skip_string(param,tpscnt,str2);
4275 char *resource = skip_string(param,tpscnt,user);
4277 if (!str1 || !str2 || !user || !resource) {
4281 if (skip_string(param,tpscnt,resource) == NULL) {
4284 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4286 /* check it's a supported varient */
4287 if (strcmp(str1,"zzh") != 0) {
4290 if (strcmp(str2,"") != 0) {
4295 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4299 SSVALS(*rparam,0,0); /* errorcode */
4300 SSVAL(*rparam,2,0); /* converter word */
4301 SSVAL(*rparam,4,0x7f); /* permission flags */
4306 /****************************************************************************
4307 api_WPrintJobEnumerate
4308 ****************************************************************************/
4310 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4311 char *param, int tpscnt,
4312 char *data, int tdscnt,
4313 int mdrcnt,int mprcnt,
4314 char **rdata,char **rparam,
4315 int *rdata_len,int *rparam_len)
4317 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4318 char *str2 = skip_string(param,tpscnt,str1);
4319 char *p = skip_string(param,tpscnt,str2);
4323 struct pack_desc desc;
4326 TALLOC_CTX *mem_ctx = talloc_tos();
4329 struct rpc_pipe_client *cli = NULL;
4330 struct policy_handle handle;
4331 struct spoolss_DevmodeContainer devmode_ctr;
4332 union spoolss_JobInfo info;
4334 if (!str1 || !str2 || !p) {
4338 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4340 memset((char *)&desc,'\0',sizeof(desc));
4341 memset((char *)&status,'\0',sizeof(status));
4343 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4345 /* check it's a supported varient */
4346 if (strcmp(str1,"WWrLh") != 0) {
4349 if (!check_printjob_info(&desc,uLevel,str2)) {
4353 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4357 ZERO_STRUCT(handle);
4359 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4360 rpc_spoolss_dispatch, conn->server_info,
4362 if (!NT_STATUS_IS_OK(status)) {
4363 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4364 nt_errstr(status)));
4365 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4369 ZERO_STRUCT(devmode_ctr);
4371 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4375 SEC_FLAG_MAXIMUM_ALLOWED,
4378 if (!NT_STATUS_IS_OK(status)) {
4379 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4382 if (!W_ERROR_IS_OK(werr)) {
4383 desc.errcode = W_ERROR_V(werr);
4387 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4393 if (!W_ERROR_IS_OK(werr)) {
4394 desc.errcode = W_ERROR_V(werr);
4399 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4404 desc.buflen = mdrcnt;
4407 * Don't return data but need to get correct length
4408 * init_package will return wrong size if buflen=0
4410 desc.buflen = getlen(desc.format);
4411 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4414 if (init_package(&desc,1,0)) {
4415 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4416 *rdata_len = desc.usedlen;
4418 desc.errcode = NERR_JobNotFound;
4422 if (cli && is_valid_policy_hnd(&handle)) {
4423 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4427 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4431 SSVALS(*rparam,0,desc.errcode);
4433 SSVAL(*rparam,4,desc.neededlen);
4437 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4442 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4443 char *param, int tpscnt,
4444 char *data, int tdscnt,
4445 int mdrcnt,int mprcnt,
4446 char **rdata,char **rparam,
4447 int *rdata_len,int *rparam_len)
4449 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4450 char *str2 = skip_string(param,tpscnt,str1);
4451 char *p = skip_string(param,tpscnt,str2);
4455 struct pack_desc desc;
4457 TALLOC_CTX *mem_ctx = talloc_tos();
4460 struct rpc_pipe_client *cli = NULL;
4461 struct policy_handle handle;
4462 struct spoolss_DevmodeContainer devmode_ctr;
4464 union spoolss_JobInfo *info;
4466 if (!str1 || !str2 || !p) {
4470 memset((char *)&desc,'\0',sizeof(desc));
4472 p = skip_string(param,tpscnt,p);
4476 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4478 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4480 /* check it's a supported variant */
4481 if (strcmp(str1,"zWrLeh") != 0) {
4486 return False; /* defined only for uLevel 0,1,2 */
4489 if (!check_printjob_info(&desc,uLevel,str2)) {
4493 ZERO_STRUCT(handle);
4495 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4496 rpc_spoolss_dispatch, conn->server_info,
4498 if (!NT_STATUS_IS_OK(status)) {
4499 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4500 nt_errstr(status)));
4501 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4505 ZERO_STRUCT(devmode_ctr);
4507 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4511 SEC_FLAG_MAXIMUM_ALLOWED,
4514 if (!NT_STATUS_IS_OK(status)) {
4515 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4518 if (!W_ERROR_IS_OK(werr)) {
4519 desc.errcode = W_ERROR_V(werr);
4523 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4531 if (!W_ERROR_IS_OK(werr)) {
4532 desc.errcode = W_ERROR_V(werr);
4537 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4543 desc.buflen = mdrcnt;
4545 if (init_package(&desc,count,0)) {
4547 for (i = 0; i < count; i++) {
4548 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4549 if (desc.errcode == NERR_Success) {
4555 if (cli && is_valid_policy_hnd(&handle)) {
4556 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4559 *rdata_len = desc.usedlen;
4562 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4566 SSVALS(*rparam,0,desc.errcode);
4568 SSVAL(*rparam,4,succnt);
4569 SSVAL(*rparam,6,count);
4571 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4576 static int check_printdest_info(struct pack_desc* desc,
4577 int uLevel, char* id)
4579 desc->subformat = NULL;
4582 desc->format = "B9";
4585 desc->format = "B9B21WWzW";
4591 desc->format = "zzzWWzzzWW";
4594 DEBUG(0,("check_printdest_info: invalid level %d\n",
4598 if (id == NULL || strcmp(desc->format,id) != 0) {
4599 DEBUG(0,("check_printdest_info: invalid string %s\n",
4600 id ? id : "<NULL>" ));
4606 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4607 struct pack_desc* desc)
4611 strncpy(buf, info2->printername, sizeof(buf)-1);
4612 buf[sizeof(buf)-1] = 0;
4616 PACKS(desc,"B9",buf); /* szName */
4618 PACKS(desc,"B21",""); /* szUserName */
4619 PACKI(desc,"W",0); /* uJobId */
4620 PACKI(desc,"W",0); /* fsStatus */
4621 PACKS(desc,"z",""); /* pszStatus */
4622 PACKI(desc,"W",0); /* time */
4626 if (uLevel == 2 || uLevel == 3) {
4627 PACKS(desc,"z",buf); /* pszPrinterName */
4629 PACKS(desc,"z",""); /* pszUserName */
4630 PACKS(desc,"z",""); /* pszLogAddr */
4631 PACKI(desc,"W",0); /* uJobId */
4632 PACKI(desc,"W",0); /* fsStatus */
4633 PACKS(desc,"z",""); /* pszStatus */
4634 PACKS(desc,"z",""); /* pszComment */
4635 PACKS(desc,"z","NULL"); /* pszDrivers */
4636 PACKI(desc,"W",0); /* time */
4637 PACKI(desc,"W",0); /* pad1 */
4642 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4643 char *param, int tpscnt,
4644 char *data, int tdscnt,
4645 int mdrcnt,int mprcnt,
4646 char **rdata,char **rparam,
4647 int *rdata_len,int *rparam_len)
4649 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4650 char *str2 = skip_string(param,tpscnt,str1);
4651 char *p = skip_string(param,tpscnt,str2);
4652 char* PrinterName = p;
4654 struct pack_desc desc;
4657 TALLOC_CTX *mem_ctx = talloc_tos();
4660 struct rpc_pipe_client *cli = NULL;
4661 struct policy_handle handle;
4662 struct spoolss_DevmodeContainer devmode_ctr;
4663 union spoolss_PrinterInfo info;
4665 if (!str1 || !str2 || !p) {
4669 memset((char *)&desc,'\0',sizeof(desc));
4671 p = skip_string(param,tpscnt,p);
4675 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4677 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4679 /* check it's a supported varient */
4680 if (strcmp(str1,"zWrLh") != 0) {
4683 if (!check_printdest_info(&desc,uLevel,str2)) {
4687 ZERO_STRUCT(handle);
4689 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4690 rpc_spoolss_dispatch, conn->server_info,
4692 if (!NT_STATUS_IS_OK(status)) {
4693 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4694 nt_errstr(status)));
4695 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4699 ZERO_STRUCT(devmode_ctr);
4701 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4705 SEC_FLAG_MAXIMUM_ALLOWED,
4708 if (!NT_STATUS_IS_OK(status)) {
4710 desc.errcode = NERR_DestNotFound;
4714 if (!W_ERROR_IS_OK(werr)) {
4716 desc.errcode = NERR_DestNotFound;
4721 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4726 if (!W_ERROR_IS_OK(werr)) {
4728 desc.errcode = NERR_DestNotFound;
4734 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4739 desc.buflen = mdrcnt;
4742 * Don't return data but need to get correct length
4743 * init_package will return wrong size if buflen=0
4745 desc.buflen = getlen(desc.format);
4746 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4748 if (init_package(&desc,1,0)) {
4749 fill_printdest_info(&info.info2, uLevel,&desc);
4753 if (cli && is_valid_policy_hnd(&handle)) {
4754 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4757 *rdata_len = desc.usedlen;
4760 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4764 SSVALS(*rparam,0,desc.errcode);
4766 SSVAL(*rparam,4,desc.neededlen);
4768 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4774 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4775 char *param, int tpscnt,
4776 char *data, int tdscnt,
4777 int mdrcnt,int mprcnt,
4778 char **rdata,char **rparam,
4779 int *rdata_len,int *rparam_len)
4781 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4782 char *str2 = skip_string(param,tpscnt,str1);
4783 char *p = skip_string(param,tpscnt,str2);
4787 struct pack_desc desc;
4789 TALLOC_CTX *mem_ctx = talloc_tos();
4792 struct rpc_pipe_client *cli = NULL;
4793 union spoolss_PrinterInfo *info;
4796 if (!str1 || !str2 || !p) {
4800 memset((char *)&desc,'\0',sizeof(desc));
4802 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4804 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4806 /* check it's a supported varient */
4807 if (strcmp(str1,"WrLeh") != 0) {
4810 if (!check_printdest_info(&desc,uLevel,str2)) {
4816 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4817 rpc_spoolss_dispatch, conn->server_info,
4819 if (!NT_STATUS_IS_OK(status)) {
4820 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4821 nt_errstr(status)));
4822 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4826 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4828 cli->srv_name_slash,
4833 if (!W_ERROR_IS_OK(werr)) {
4834 desc.errcode = W_ERROR_V(werr);
4836 desc.errcode = NERR_DestNotFound;
4844 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4851 desc.buflen = mdrcnt;
4852 if (init_package(&desc,queuecnt,0)) {
4855 for (i = 0; i < count; i++) {
4856 fill_printdest_info(&info[i].info2, uLevel,&desc);
4858 if (desc.errcode == NERR_Success) {
4864 *rdata_len = desc.usedlen;
4867 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4871 SSVALS(*rparam,0,desc.errcode);
4873 SSVAL(*rparam,4,succnt);
4874 SSVAL(*rparam,6,queuecnt);
4876 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4881 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4882 char *param, int tpscnt,
4883 char *data, int tdscnt,
4884 int mdrcnt,int mprcnt,
4885 char **rdata,char **rparam,
4886 int *rdata_len,int *rparam_len)
4888 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4889 char *str2 = skip_string(param,tpscnt,str1);
4890 char *p = skip_string(param,tpscnt,str2);
4893 struct pack_desc desc;
4895 if (!str1 || !str2 || !p) {
4899 memset((char *)&desc,'\0',sizeof(desc));
4901 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4903 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4905 /* check it's a supported varient */
4906 if (strcmp(str1,"WrLeh") != 0) {
4909 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4914 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4920 desc.buflen = mdrcnt;
4921 if (init_package(&desc,1,0)) {
4922 PACKS(&desc,"B41","NULL");
4925 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4927 *rdata_len = desc.usedlen;
4930 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4934 SSVALS(*rparam,0,desc.errcode);
4936 SSVAL(*rparam,4,succnt);
4939 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4944 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4945 char *param, int tpscnt,
4946 char *data, int tdscnt,
4947 int mdrcnt,int mprcnt,
4948 char **rdata,char **rparam,
4949 int *rdata_len,int *rparam_len)
4951 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4952 char *str2 = skip_string(param,tpscnt,str1);
4953 char *p = skip_string(param,tpscnt,str2);
4956 struct pack_desc desc;
4958 if (!str1 || !str2 || !p) {
4961 memset((char *)&desc,'\0',sizeof(desc));
4963 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4965 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4967 /* check it's a supported varient */
4968 if (strcmp(str1,"WrLeh") != 0) {
4971 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4976 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4982 desc.buflen = mdrcnt;
4984 if (init_package(&desc,1,0)) {
4985 PACKS(&desc,"B13","lpd");
4988 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4990 *rdata_len = desc.usedlen;
4993 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4997 SSVALS(*rparam,0,desc.errcode);
4999 SSVAL(*rparam,4,succnt);
5002 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5007 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5008 char *param, int tpscnt,
5009 char *data, int tdscnt,
5010 int mdrcnt,int mprcnt,
5011 char **rdata,char **rparam,
5012 int *rdata_len,int *rparam_len)
5014 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5015 char *str2 = skip_string(param,tpscnt,str1);
5016 char *p = skip_string(param,tpscnt,str2);
5019 struct pack_desc desc;
5021 if (!str1 || !str2 || !p) {
5025 memset((char *)&desc,'\0',sizeof(desc));
5027 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5029 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5031 /* check it's a supported varient */
5032 if (strcmp(str1,"WrLeh") != 0) {
5035 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5040 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5045 memset((char *)&desc,'\0',sizeof(desc));
5047 desc.buflen = mdrcnt;
5049 if (init_package(&desc,1,0)) {
5050 PACKS(&desc,"B13","lp0");
5053 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5055 *rdata_len = desc.usedlen;
5058 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5062 SSVALS(*rparam,0,desc.errcode);
5064 SSVAL(*rparam,4,succnt);
5067 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5072 /****************************************************************************
5074 ****************************************************************************/
5076 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5077 char *param, int tpscnt,
5078 char *data, int tdscnt,
5079 int mdrcnt,int mprcnt,
5080 char **rdata,char **rparam,
5081 int *rdata_len,int *rparam_len)
5084 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5085 char *str2 = skip_string(param,tpscnt,str1);
5086 char *p = skip_string(param,tpscnt,str2);
5088 struct pack_desc desc;
5089 struct sessionid *session_list;
5090 int i, num_sessions;
5092 if (!str1 || !str2 || !p) {
5096 memset((char *)&desc,'\0',sizeof(desc));
5098 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5100 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5101 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5102 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5104 /* check it's a supported varient */
5105 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5108 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5112 num_sessions = list_sessions(talloc_tos(), &session_list);
5115 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5120 memset((char *)&desc,'\0',sizeof(desc));
5122 desc.buflen = mdrcnt;
5124 if (!init_package(&desc,num_sessions,0)) {
5128 for(i=0; i<num_sessions; i++) {
5129 PACKS(&desc, "z", session_list[i].remote_machine);
5130 PACKS(&desc, "z", session_list[i].username);
5131 PACKI(&desc, "W", 1); /* num conns */
5132 PACKI(&desc, "W", 0); /* num opens */
5133 PACKI(&desc, "W", 1); /* num users */
5134 PACKI(&desc, "D", 0); /* session time */
5135 PACKI(&desc, "D", 0); /* idle time */
5136 PACKI(&desc, "D", 0); /* flags */
5137 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5140 *rdata_len = desc.usedlen;
5143 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5147 SSVALS(*rparam,0,desc.errcode);
5148 SSVAL(*rparam,2,0); /* converter */
5149 SSVAL(*rparam,4,num_sessions); /* count */
5151 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5157 /****************************************************************************
5158 The buffer was too small.
5159 ****************************************************************************/
5161 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5162 int mdrcnt, int mprcnt,
5163 char **rdata, char **rparam,
5164 int *rdata_len, int *rparam_len)
5166 *rparam_len = MIN(*rparam_len,mprcnt);
5167 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5174 SSVAL(*rparam,0,NERR_BufTooSmall);
5176 DEBUG(3,("Supplied buffer too small in API command\n"));
5181 /****************************************************************************
5182 The request is not supported.
5183 ****************************************************************************/
5185 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5186 char *param, int tpscnt,
5187 char *data, int tdscnt,
5188 int mdrcnt, int mprcnt,
5189 char **rdata, char **rparam,
5190 int *rdata_len, int *rparam_len)
5193 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5200 SSVAL(*rparam,0,NERR_notsupported);
5201 SSVAL(*rparam,2,0); /* converter word */
5203 DEBUG(3,("Unsupported API command\n"));
5208 static const struct {
5211 bool (*fn)(connection_struct *, uint16,
5214 int,int,char **,char **,int *,int *);
5215 bool auth_user; /* Deny anonymous access? */
5216 } api_commands[] = {
5217 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5218 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5219 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5220 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5221 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5222 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5223 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5224 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5225 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5226 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5227 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5228 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5229 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5230 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5231 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5232 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5233 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5234 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5235 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5236 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5237 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5238 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5239 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5240 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5241 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5242 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5243 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5244 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5245 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5246 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5247 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5248 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5249 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5250 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5251 {NULL, -1, api_Unsupported}
5252 /* The following RAP calls are not implemented by Samba:
5254 RAP_WFileEnum2 - anon not OK
5259 /****************************************************************************
5260 Handle remote api calls.
5261 ****************************************************************************/
5263 void api_reply(connection_struct *conn, uint16 vuid,
5264 struct smb_request *req,
5265 char *data, char *params,
5266 int tdscnt, int tpscnt,
5267 int mdrcnt, int mprcnt)
5269 struct smbd_server_connection *sconn = smbd_server_conn;
5272 char *rparam = NULL;
5273 const char *name1 = NULL;
5274 const char *name2 = NULL;
5281 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5282 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5287 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5290 api_command = SVAL(params,0);
5291 /* Is there a string at position params+2 ? */
5292 if (skip_string(params,tpscnt,params+2)) {
5297 name2 = skip_string(params,tpscnt,params+2);
5302 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5306 tdscnt,tpscnt,mdrcnt,mprcnt));
5308 for (i=0;api_commands[i].name;i++) {
5309 if (api_commands[i].id == api_command && api_commands[i].fn) {
5310 DEBUG(3,("Doing %s\n",api_commands[i].name));
5315 /* Check whether this api call can be done anonymously */
5317 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5318 user_struct *user = get_valid_user_struct(sconn, vuid);
5320 if (!user || user->server_info->guest) {
5321 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5326 rdata = (char *)SMB_MALLOC(1024);
5328 memset(rdata,'\0',1024);
5331 rparam = (char *)SMB_MALLOC(1024);
5333 memset(rparam,'\0',1024);
5336 if(!rdata || !rparam) {
5337 DEBUG(0,("api_reply: malloc fail !\n"));
5340 reply_nterror(req, NT_STATUS_NO_MEMORY);
5344 reply = api_commands[i].fn(conn,
5346 params,tpscnt, /* params + length */
5347 data,tdscnt, /* data + length */
5349 &rdata,&rparam,&rdata_len,&rparam_len);
5352 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5353 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5354 &rdata,&rparam,&rdata_len,&rparam_len);
5357 /* if we get False back then it's actually unsupported */
5359 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5360 &rdata,&rparam,&rdata_len,&rparam_len);
5363 /* If api_Unsupported returns false we can't return anything. */
5365 send_trans_reply(conn, req, rparam, rparam_len,
5366 rdata, rdata_len, False);