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 void fill_spoolss_printjob_info(int uLevel,
537 struct pack_desc *desc,
538 struct spoolss_JobInfo2 *info2,
541 time_t t = spoolss_Time_to_time_t(&info2->submitted);
543 /* the client expects localtime */
544 t -= get_time_zone(t);
546 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
548 PACKS(desc,"B21", info2->user_name); /* szUserName */
549 PACKS(desc,"B",""); /* pad */
550 PACKS(desc,"B16",""); /* szNotifyName */
551 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
552 PACKS(desc,"z",""); /* pszParms */
553 PACKI(desc,"W",n+1); /* uPosition */
554 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
555 PACKS(desc,"z",""); /* pszStatus */
556 PACKI(desc,"D", t); /* ulSubmitted */
557 PACKI(desc,"D", info2->size); /* ulSize */
558 PACKS(desc,"z", info2->document_name); /* pszComment */
560 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
561 PACKI(desc,"W", info2->priority); /* uPriority */
562 PACKS(desc,"z", info2->user_name); /* pszUserName */
563 PACKI(desc,"W",n+1); /* uPosition */
564 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
565 PACKI(desc,"D",t); /* ulSubmitted */
566 PACKI(desc,"D", info2->size); /* ulSize */
567 PACKS(desc,"z","Samba"); /* pszComment */
568 PACKS(desc,"z", info2->document_name); /* pszDocument */
570 PACKS(desc,"z",""); /* pszNotifyName */
571 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
572 PACKS(desc,"z",""); /* pszParms */
573 PACKS(desc,"z",""); /* pszStatus */
574 PACKS(desc,"z", info2->printer_name); /* pszQueue */
575 PACKS(desc,"z","lpd"); /* pszQProcName */
576 PACKS(desc,"z",""); /* pszQProcParms */
577 PACKS(desc,"z","NULL"); /* pszDriverName */
578 PackDriverData(desc); /* pDriverData */
579 PACKS(desc,"z",""); /* pszPrinterName */
580 } else if (uLevel == 4) { /* OS2 */
581 PACKS(desc,"z",""); /* pszSpoolFileName */
582 PACKS(desc,"z",""); /* pszPortName */
583 PACKS(desc,"z",""); /* pszStatus */
584 PACKI(desc,"D",0); /* ulPagesSpooled */
585 PACKI(desc,"D",0); /* ulPagesSent */
586 PACKI(desc,"D",0); /* ulPagesPrinted */
587 PACKI(desc,"D",0); /* ulTimePrinted */
588 PACKI(desc,"D",0); /* ulExtendJobStatus */
589 PACKI(desc,"D",0); /* ulStartPage */
590 PACKI(desc,"D",0); /* ulEndPage */
595 /********************************************************************
596 Respond to the DosPrintQInfo command with a level of 52
597 This is used to get printer driver information for Win9x clients
598 ********************************************************************/
599 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
600 struct pack_desc* desc, int count,
601 const char *printer_name)
605 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
606 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
607 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
609 PACKI(desc, "W", 0x0400); /* don't know */
610 PACKS(desc, "z", driver->driver_name); /* long printer name */
611 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
612 PACKS(desc, "z", driver->data_file); /* Datafile name */
613 PACKS(desc, "z", driver->monitor_name); /* language monitor */
615 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
616 standard_sub_basic( "", "", location, sizeof(location)-1 );
617 PACKS(desc,"z", location); /* share to retrieve files */
619 PACKS(desc,"z", driver->default_datatype); /* default data type */
620 PACKS(desc,"z", driver->help_file); /* helpfile name */
621 PACKS(desc,"z", driver->driver_path); /* driver name */
623 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
624 DEBUG(3,("Driver: %s:\n",driver->driver_path));
625 DEBUG(3,("Data File: %s:\n",driver->data_file));
626 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
627 DEBUG(3,("Driver Location: %s:\n",location));
628 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
629 DEBUG(3,("Help File: %s:\n",driver->help_file));
630 PACKI(desc,"N",count); /* number of files to copy */
632 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
634 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
635 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
636 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
641 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
644 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
646 desc->errcode=NERR_Success;
650 static const char *strip_unc(const char *unc)
658 if ((p = strrchr(unc, '\\')) != NULL) {
665 static void fill_printq_info(int uLevel,
666 struct pack_desc* desc,
668 union spoolss_JobInfo *job_info,
669 struct spoolss_DriverInfo3 *driver_info,
670 struct spoolss_PrinterInfo2 *printer_info)
676 PACKS(desc,"B13", strip_unc(printer_info->printername));
681 PACKS(desc,"z", strip_unc(printer_info->printername));
684 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
688 if (uLevel == 1 || uLevel == 2) {
689 PACKS(desc,"B",""); /* alignment */
690 PACKI(desc,"W",5); /* priority */
691 PACKI(desc,"W",0); /* start time */
692 PACKI(desc,"W",0); /* until time */
693 PACKS(desc,"z",""); /* pSepFile */
694 PACKS(desc,"z","lpd"); /* pPrProc */
695 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
696 PACKS(desc,"z",""); /* pParms */
697 if (printer_info->printername == NULL) {
698 PACKS(desc,"z","UNKNOWN PRINTER");
699 PACKI(desc,"W",LPSTAT_ERROR);
701 PACKS(desc,"z", printer_info->comment);
702 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
704 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
707 if (uLevel == 3 || uLevel == 4) {
708 PACKI(desc,"W",5); /* uPriority */
709 PACKI(desc,"W",0); /* uStarttime */
710 PACKI(desc,"W",0); /* uUntiltime */
711 PACKI(desc,"W",5); /* pad1 */
712 PACKS(desc,"z",""); /* pszSepFile */
713 PACKS(desc,"z","WinPrint"); /* pszPrProc */
714 PACKS(desc,"z",NULL); /* pszParms */
715 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
716 /* "don't ask" that it's done this way to fix corrupted
717 Win9X/ME printer comments. */
718 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
719 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
720 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
721 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
722 PackDriverData(desc); /* pDriverData */
725 if (uLevel == 2 || uLevel == 4) {
727 for (i = 0; i < count; i++) {
728 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
733 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
736 /* This function returns the number of files for a given driver */
737 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
741 /* count the number of files */
742 while (driver->dependent_files && *driver->dependent_files[result])
748 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
749 char *param, int tpscnt,
750 char *data, int tdscnt,
751 int mdrcnt,int mprcnt,
752 char **rdata,char **rparam,
753 int *rdata_len,int *rparam_len)
755 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
756 char *str2 = skip_string(param,tpscnt,str1);
757 char *p = skip_string(param,tpscnt,str2);
762 struct pack_desc desc;
765 WERROR werr = WERR_OK;
766 TALLOC_CTX *mem_ctx = talloc_tos();
768 struct rpc_pipe_client *cli = NULL;
769 struct policy_handle handle;
770 struct spoolss_DevmodeContainer devmode_ctr;
771 union spoolss_DriverInfo driver_info;
772 union spoolss_JobInfo *job_info;
773 union spoolss_PrinterInfo printer_info;
775 if (!str1 || !str2 || !p) {
778 memset((char *)&desc,'\0',sizeof(desc));
780 p = skip_string(param,tpscnt,p);
784 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
785 str3 = get_safe_str_ptr(param,tpscnt,p,4);
786 /* str3 may be null here and is checked in check_printq_info(). */
788 /* remove any trailing username */
789 if ((p = strchr_m(QueueName,'%')))
792 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
794 /* check it's a supported varient */
795 if (!prefix_ok(str1,"zWrLh"))
797 if (!check_printq_info(&desc,uLevel,str2,str3)) {
799 * Patch from Scott Moomaw <scott@bridgewater.edu>
800 * to return the 'invalid info level' error if an
801 * unknown level was requested.
805 *rparam = smb_realloc_limit(*rparam,*rparam_len);
809 SSVALS(*rparam,0,ERRunknownlevel);
817 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
818 rpc_spoolss_dispatch, conn->server_info,
820 if (!NT_STATUS_IS_OK(status)) {
821 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
823 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
827 ZERO_STRUCT(devmode_ctr);
829 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
833 SEC_FLAG_MAXIMUM_ALLOWED,
836 if (!NT_STATUS_IS_OK(status)) {
837 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
840 if (!W_ERROR_IS_OK(werr)) {
841 desc.errcode = W_ERROR_V(werr);
845 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
850 if (!W_ERROR_IS_OK(werr)) {
851 desc.errcode = W_ERROR_V(werr);
856 uint32_t server_major_version;
857 uint32_t server_minor_version;
859 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
867 &server_major_version,
868 &server_minor_version);
869 if (!W_ERROR_IS_OK(werr)) {
870 desc.errcode = W_ERROR_V(werr);
874 count = get_printerdrivernumber(&driver_info.info3);
875 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
878 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
886 if (!W_ERROR_IS_OK(werr)) {
887 desc.errcode = W_ERROR_V(werr);
895 *rdata = smb_realloc_limit(*rdata,mdrcnt);
900 desc.buflen = mdrcnt;
903 * Don't return data but need to get correct length
904 * init_package will return wrong size if buflen=0
906 desc.buflen = getlen(desc.format);
907 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
910 if (init_package(&desc,1,count)) {
911 desc.subcount = count;
912 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
915 *rdata_len = desc.usedlen;
918 * We must set the return code to ERRbuftoosmall
919 * in order to support lanman style printing with Win NT/2k
922 if (!mdrcnt && lp_disable_spoolss())
923 desc.errcode = ERRbuftoosmall;
926 if (cli && is_valid_policy_hnd(&handle)) {
927 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
930 *rdata_len = desc.usedlen;
932 *rparam = smb_realloc_limit(*rparam,*rparam_len);
937 SSVALS(*rparam,0,desc.errcode);
939 SSVAL(*rparam,4,desc.neededlen);
941 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
948 /****************************************************************************
949 View list of all print jobs on all queues.
950 ****************************************************************************/
952 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
953 char *param, int tpscnt,
954 char *data, int tdscnt,
955 int mdrcnt, int mprcnt,
956 char **rdata, char** rparam,
957 int *rdata_len, int *rparam_len)
959 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
960 char *output_format1 = skip_string(param,tpscnt,param_format);
961 char *p = skip_string(param,tpscnt,output_format1);
962 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
963 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
965 struct pack_desc desc;
966 int *subcntarr = NULL;
967 int queuecnt = 0, subcnt = 0, succnt = 0;
969 WERROR werr = WERR_OK;
970 TALLOC_CTX *mem_ctx = talloc_tos();
972 struct rpc_pipe_client *cli = NULL;
973 struct spoolss_DevmodeContainer devmode_ctr;
974 uint32_t num_printers;
975 union spoolss_PrinterInfo *printer_info;
976 union spoolss_DriverInfo *driver_info;
977 union spoolss_JobInfo **job_info;
979 if (!param_format || !output_format1 || !p) {
983 memset((char *)&desc,'\0',sizeof(desc));
985 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
987 if (!prefix_ok(param_format,"WrLeh")) {
990 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
992 * Patch from Scott Moomaw <scott@bridgewater.edu>
993 * to return the 'invalid info level' error if an
994 * unknown level was requested.
998 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1002 SSVALS(*rparam,0,ERRunknownlevel);
1008 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1009 rpc_spoolss_dispatch, conn->server_info,
1011 if (!NT_STATUS_IS_OK(status)) {
1012 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1013 nt_errstr(status)));
1014 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1018 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1020 cli->srv_name_slash,
1025 if (!W_ERROR_IS_OK(werr)) {
1026 desc.errcode = W_ERROR_V(werr);
1030 queuecnt = num_printers;
1032 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1033 if (job_info == NULL) {
1037 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1038 if (driver_info == NULL) {
1042 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1043 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1048 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1054 desc.buflen = mdrcnt;
1057 for (i = 0; i < num_printers; i++) {
1060 struct policy_handle handle;
1061 const char *printername;
1063 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1064 if (printername == NULL) {
1068 ZERO_STRUCT(handle);
1069 ZERO_STRUCT(devmode_ctr);
1071 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1075 SEC_FLAG_MAXIMUM_ALLOWED,
1078 if (!NT_STATUS_IS_OK(status)) {
1079 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1082 if (!W_ERROR_IS_OK(werr)) {
1083 desc.errcode = W_ERROR_V(werr);
1087 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1095 if (!W_ERROR_IS_OK(werr)) {
1096 desc.errcode = W_ERROR_V(werr);
1101 uint32_t server_major_version;
1102 uint32_t server_minor_version;
1104 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1112 &server_major_version,
1113 &server_minor_version);
1114 if (!W_ERROR_IS_OK(werr)) {
1115 desc.errcode = W_ERROR_V(werr);
1120 subcntarr[i] = num_jobs;
1121 subcnt += subcntarr[i];
1123 if (cli && is_valid_policy_hnd(&handle)) {
1124 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1128 if (init_package(&desc,queuecnt,subcnt)) {
1129 for (i = 0; i < num_printers; i++) {
1130 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1131 if (desc.errcode == NERR_Success) {
1137 SAFE_FREE(subcntarr);
1139 *rdata_len = desc.usedlen;
1141 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1145 SSVALS(*rparam,0,desc.errcode);
1147 SSVAL(*rparam,4,succnt);
1148 SSVAL(*rparam,6,queuecnt);
1154 SAFE_FREE(subcntarr);
1159 /****************************************************************************
1160 Get info level for a server list query.
1161 ****************************************************************************/
1163 static bool check_server_info(int uLevel, char* id)
1167 if (strcmp(id,"B16") != 0) {
1172 if (strcmp(id,"B16BBDz") != 0) {
1182 struct srv_info_struct {
1190 /*******************************************************************
1191 Get server info lists from the files saved by nmbd. Return the
1193 ******************************************************************/
1195 static int get_server_info(uint32 servertype,
1196 struct srv_info_struct **servers,
1202 bool local_list_only;
1205 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1207 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1211 /* request for everything is code for request all servers */
1212 if (servertype == SV_TYPE_ALL) {
1213 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1216 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1218 DEBUG(4,("Servertype search: %8x\n",servertype));
1220 for (i=0;lines[i];i++) {
1222 struct srv_info_struct *s;
1223 const char *ptr = lines[i];
1225 TALLOC_CTX *frame = NULL;
1232 if (count == alloced) {
1234 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1236 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1240 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1242 s = &(*servers)[count];
1244 frame = talloc_stackframe();
1246 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1250 fstrcpy(s->name, p);
1253 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1259 s->comment[0] = '\0';
1260 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1264 fstrcpy(s->comment, p);
1265 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1267 s->domain[0] = '\0';
1268 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1269 /* this allows us to cope with an old nmbd */
1270 fstrcpy(s->domain,lp_workgroup());
1272 fstrcpy(s->domain, p);
1276 if (sscanf(stype,"%X",&s->type) != 1) {
1277 DEBUG(4,("r:host file "));
1281 /* Filter the servers/domains we return based on what was asked for. */
1283 /* Check to see if we are being asked for a local list only. */
1284 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1285 DEBUG(4,("r: local list only"));
1289 /* doesn't match up: don't want it */
1290 if (!(servertype & s->type)) {
1291 DEBUG(4,("r:serv type "));
1295 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1296 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1297 DEBUG(4,("s: dom mismatch "));
1301 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1305 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1306 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1309 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1310 s->name, s->type, s->comment, s->domain));
1311 s->server_added = True;
1314 DEBUG(4,("%20s %8x %25s %15s\n",
1315 s->name, s->type, s->comment, s->domain));
1323 /*******************************************************************
1324 Fill in a server info structure.
1325 ******************************************************************/
1327 static int fill_srv_info(struct srv_info_struct *service,
1328 int uLevel, char **buf, int *buflen,
1329 char **stringbuf, int *stringspace, char *baseaddr)
1352 len = strlen(service->comment)+1;
1356 *buflen = struct_len;
1358 return struct_len + len;
1363 if (*buflen < struct_len) {
1370 p2 = p + struct_len;
1371 l2 = *buflen - struct_len;
1379 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1383 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1384 SIVAL(p,18,service->type);
1385 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1386 len += CopyAndAdvance(&p2,service->comment,&l2);
1391 *buf = p + struct_len;
1392 *buflen -= struct_len;
1403 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1405 return StrCaseCmp(s1->name,s2->name);
1408 /****************************************************************************
1409 View list of servers available (or possibly domains). The info is
1410 extracted from lists saved by nmbd on the local host.
1411 ****************************************************************************/
1413 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1414 char *param, int tpscnt,
1415 char *data, int tdscnt,
1416 int mdrcnt, int mprcnt, char **rdata,
1417 char **rparam, int *rdata_len, int *rparam_len)
1419 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1420 char *str2 = skip_string(param,tpscnt,str1);
1421 char *p = skip_string(param,tpscnt,str2);
1422 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1423 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1424 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1426 int data_len, fixed_len, string_len;
1427 int f_len = 0, s_len = 0;
1428 struct srv_info_struct *servers=NULL;
1429 int counted=0,total=0;
1432 bool domain_request;
1435 if (!str1 || !str2 || !p) {
1439 /* If someone sets all the bits they don't really mean to set
1440 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1443 if (servertype == SV_TYPE_ALL) {
1444 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1447 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1448 any other bit (they may just set this bit on its own) they
1449 want all the locally seen servers. However this bit can be
1450 set on its own so set the requested servers to be
1451 ALL - DOMAIN_ENUM. */
1453 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1454 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1457 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1458 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1462 if (!prefix_ok(str1,"WrLehD")) {
1465 if (!check_server_info(uLevel,str2)) {
1469 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1470 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1471 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1473 if (strcmp(str1, "WrLehDz") == 0) {
1474 if (skip_string(param,tpscnt,p) == NULL) {
1477 pull_ascii_fstring(domain, p);
1479 fstrcpy(domain, lp_workgroup());
1482 DEBUG(4, ("domain [%s]\n", domain));
1484 if (lp_browse_list()) {
1485 total = get_server_info(servertype,&servers,domain);
1488 data_len = fixed_len = string_len = 0;
1491 TYPESAFE_QSORT(servers, total, srv_comp);
1494 char *lastname=NULL;
1496 for (i=0;i<total;i++) {
1497 struct srv_info_struct *s = &servers[i];
1499 if (lastname && strequal(lastname,s->name)) {
1503 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1504 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1505 i, s->name, s->type, s->comment, s->domain));
1507 if (data_len < buf_len) {
1510 string_len += s_len;
1517 *rdata_len = fixed_len + string_len;
1518 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1523 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1529 char *lastname=NULL;
1530 int count2 = counted;
1532 for (i = 0; i < total && count2;i++) {
1533 struct srv_info_struct *s = &servers[i];
1535 if (lastname && strequal(lastname,s->name)) {
1539 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1540 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1541 i, s->name, s->type, s->comment, s->domain));
1547 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1551 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1553 SSVAL(*rparam,4,counted);
1554 SSVAL(*rparam,6,counted+missed);
1558 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1559 domain,uLevel,counted,counted+missed));
1564 static int srv_name_match(const char *n1, const char *n2)
1567 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1569 * In Windows, FirstNameToReturn need not be an exact match:
1570 * the server will return a list of servers that exist on
1571 * the network greater than or equal to the FirstNameToReturn.
1573 int ret = StrCaseCmp(n1, n2);
1582 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1583 char *param, int tpscnt,
1584 char *data, int tdscnt,
1585 int mdrcnt, int mprcnt, char **rdata,
1586 char **rparam, int *rdata_len, int *rparam_len)
1588 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1589 char *str2 = skip_string(param,tpscnt,str1);
1590 char *p = skip_string(param,tpscnt,str2);
1591 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1592 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1593 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1595 int data_len, fixed_len, string_len;
1596 int f_len = 0, s_len = 0;
1597 struct srv_info_struct *servers=NULL;
1598 int counted=0,first=0,total=0;
1602 bool domain_request;
1605 if (!str1 || !str2 || !p) {
1609 /* If someone sets all the bits they don't really mean to set
1610 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1613 if (servertype == SV_TYPE_ALL) {
1614 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1617 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1618 any other bit (they may just set this bit on its own) they
1619 want all the locally seen servers. However this bit can be
1620 set on its own so set the requested servers to be
1621 ALL - DOMAIN_ENUM. */
1623 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1624 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1627 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1628 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1632 if (strcmp(str1, "WrLehDzz") != 0) {
1635 if (!check_server_info(uLevel,str2)) {
1639 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1640 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1641 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1643 if (skip_string(param,tpscnt,p) == NULL) {
1646 pull_ascii_fstring(domain, p);
1647 if (domain[0] == '\0') {
1648 fstrcpy(domain, lp_workgroup());
1650 p = skip_string(param,tpscnt,p);
1651 if (skip_string(param,tpscnt,p) == NULL) {
1654 pull_ascii_fstring(first_name, p);
1656 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1657 domain, first_name));
1659 if (lp_browse_list()) {
1660 total = get_server_info(servertype,&servers,domain);
1663 data_len = fixed_len = string_len = 0;
1666 TYPESAFE_QSORT(servers, total, srv_comp);
1668 if (first_name[0] != '\0') {
1669 struct srv_info_struct *first_server = NULL;
1671 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1672 srv_name_match, first_server);
1674 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1676 * The binary search may not find the exact match
1677 * so we need to search backward to find the first match
1679 * This implements the strange matching windows
1680 * implements. (see the comment in srv_name_match().
1684 ret = StrCaseCmp(first_name,
1685 servers[first-1].name);
1692 /* we should return no entries */
1698 char *lastname=NULL;
1700 for (i=first;i<total;i++) {
1701 struct srv_info_struct *s = &servers[i];
1703 if (lastname && strequal(lastname,s->name)) {
1707 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1708 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1709 i, s->name, s->type, s->comment, s->domain));
1711 if (data_len < buf_len) {
1714 string_len += s_len;
1721 *rdata_len = fixed_len + string_len;
1722 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1727 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1733 char *lastname=NULL;
1734 int count2 = counted;
1736 for (i = first; i < total && count2;i++) {
1737 struct srv_info_struct *s = &servers[i];
1739 if (lastname && strequal(lastname,s->name)) {
1743 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1744 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1745 i, s->name, s->type, s->comment, s->domain));
1751 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1755 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1757 SSVAL(*rparam,4,counted);
1758 SSVAL(*rparam,6,counted+missed);
1760 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1761 domain,uLevel,first,first_name,
1762 first < total ? servers[first].name : "",
1763 counted,counted+missed));
1770 /****************************************************************************
1771 command 0x34 - suspected of being a "Lookup Names" stub api
1772 ****************************************************************************/
1774 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1775 char *param, int tpscnt,
1776 char *data, int tdscnt,
1777 int mdrcnt, int mprcnt, char **rdata,
1778 char **rparam, int *rdata_len, int *rparam_len)
1780 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1781 char *str2 = skip_string(param,tpscnt,str1);
1782 char *p = skip_string(param,tpscnt,str2);
1783 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1784 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1788 if (!str1 || !str2 || !p) {
1792 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1793 str1, str2, p, uLevel, buf_len));
1795 if (!prefix_ok(str1,"zWrLeh")) {
1802 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1807 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1809 SSVAL(*rparam,4,counted);
1810 SSVAL(*rparam,6,counted+missed);
1815 /****************************************************************************
1816 get info about a share
1817 ****************************************************************************/
1819 static bool check_share_info(int uLevel, char* id)
1823 if (strcmp(id,"B13") != 0) {
1828 /* Level-2 descriptor is allowed (and ignored) */
1829 if (strcmp(id,"B13BWz") != 0 &&
1830 strcmp(id,"B13BWzWWWzB9B") != 0) {
1835 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1840 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1850 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1851 char** buf, int* buflen,
1852 char** stringbuf, int* stringspace, char* baseaddr)
1881 len += StrlenExpanded(conn,snum,lp_comment(snum));
1884 len += strlen(lp_pathname(snum)) + 1;
1887 *buflen = struct_len;
1892 return struct_len + len;
1897 if ((*buflen) < struct_len) {
1905 p2 = p + struct_len;
1906 l2 = (*buflen) - struct_len;
1913 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1919 type = STYPE_DISKTREE;
1920 if (lp_print_ok(snum)) {
1921 type = STYPE_PRINTQ;
1923 if (strequal("IPC",lp_fstype(snum))) {
1926 SSVAL(p,14,type); /* device type */
1927 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1928 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1932 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1933 SSVALS(p,22,-1); /* max uses */
1934 SSVAL(p,24,1); /* current uses */
1935 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1936 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1937 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1941 memset(p+40,0,SHPWLEN+2);
1952 (*buf) = p + struct_len;
1953 (*buflen) -= struct_len;
1955 (*stringspace) = l2;
1964 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1965 char *param, int tpscnt,
1966 char *data, int tdscnt,
1967 int mdrcnt,int mprcnt,
1968 char **rdata,char **rparam,
1969 int *rdata_len,int *rparam_len)
1971 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1972 char *str2 = skip_string(param,tpscnt,str1);
1973 char *netname = skip_string(param,tpscnt,str2);
1974 char *p = skip_string(param,tpscnt,netname);
1975 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1978 if (!str1 || !str2 || !netname || !p) {
1982 snum = find_service(netname);
1987 /* check it's a supported varient */
1988 if (!prefix_ok(str1,"zWrLh")) {
1991 if (!check_share_info(uLevel,str2)) {
1995 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2000 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2001 if (*rdata_len < 0) {
2006 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2010 SSVAL(*rparam,0,NERR_Success);
2011 SSVAL(*rparam,2,0); /* converter word */
2012 SSVAL(*rparam,4,*rdata_len);
2017 /****************************************************************************
2018 View the list of available shares.
2020 This function is the server side of the NetShareEnum() RAP call.
2021 It fills the return buffer with share names and share comments.
2022 Note that the return buffer normally (in all known cases) allows only
2023 twelve byte strings for share names (plus one for a nul terminator).
2024 Share names longer than 12 bytes must be skipped.
2025 ****************************************************************************/
2027 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2028 char *param, int tpscnt,
2029 char *data, int tdscnt,
2037 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2038 char *str2 = skip_string(param,tpscnt,str1);
2039 char *p = skip_string(param,tpscnt,str2);
2040 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2041 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2044 int total=0,counted=0;
2045 bool missed = False;
2047 int data_len, fixed_len, string_len;
2048 int f_len = 0, s_len = 0;
2050 if (!str1 || !str2 || !p) {
2054 if (!prefix_ok(str1,"WrLeh")) {
2057 if (!check_share_info(uLevel,str2)) {
2061 /* Ensure all the usershares are loaded. */
2063 load_registry_shares();
2064 count = load_usershare_shares();
2067 data_len = fixed_len = string_len = 0;
2068 for (i=0;i<count;i++) {
2069 fstring servicename_dos;
2070 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2073 push_ascii_fstring(servicename_dos, lp_servicename(i));
2074 /* Maximum name length = 13. */
2075 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2077 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2078 if (data_len < buf_len) {
2081 string_len += s_len;
2088 *rdata_len = fixed_len + string_len;
2089 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2094 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2099 for( i = 0; i < count; i++ ) {
2100 fstring servicename_dos;
2101 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2105 push_ascii_fstring(servicename_dos, lp_servicename(i));
2106 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2107 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2114 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2118 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2120 SSVAL(*rparam,4,counted);
2121 SSVAL(*rparam,6,total);
2123 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2124 counted,total,uLevel,
2125 buf_len,*rdata_len,mdrcnt));
2130 /****************************************************************************
2132 ****************************************************************************/
2134 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2135 char *param, int tpscnt,
2136 char *data, int tdscnt,
2137 int mdrcnt,int mprcnt,
2138 char **rdata,char **rparam,
2139 int *rdata_len,int *rparam_len)
2141 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2142 char *str2 = skip_string(param,tpscnt,str1);
2143 char *p = skip_string(param,tpscnt,str2);
2144 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2147 char *pathname = NULL;
2148 unsigned int offset;
2150 size_t converted_size;
2152 WERROR werr = WERR_OK;
2153 TALLOC_CTX *mem_ctx = talloc_tos();
2155 struct rpc_pipe_client *cli = NULL;
2156 union srvsvc_NetShareInfo info;
2157 struct srvsvc_NetShareInfo2 info2;
2159 if (!str1 || !str2 || !p) {
2163 /* check it's a supported varient */
2164 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2167 if (!check_share_info(uLevel,str2)) {
2174 /* Do we have a string ? */
2175 if (skip_string(data,mdrcnt,data) == NULL) {
2178 pull_ascii_fstring(sharename,data);
2184 /* only support disk share adds */
2185 if (SVAL(data,14)!=STYPE_DISKTREE) {
2189 offset = IVAL(data, 16);
2190 if (offset >= mdrcnt) {
2191 res = ERRinvalidparam;
2195 /* Do we have a string ? */
2196 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2199 pull_ascii_fstring(comment, offset? (data+offset) : "");
2201 offset = IVAL(data, 26);
2203 if (offset >= mdrcnt) {
2204 res = ERRinvalidparam;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2213 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2214 offset ? (data+offset) : "", &converted_size))
2216 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2224 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2225 rpc_srvsvc_dispatch, conn->server_info,
2227 if (!NT_STATUS_IS_OK(status)) {
2228 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2229 nt_errstr(status)));
2230 res = W_ERROR_V(ntstatus_to_werror(status));
2234 info2.name = sharename;
2235 info2.type = STYPE_DISKTREE;
2236 info2.comment = comment;
2237 info2.permissions = 0;
2238 info2.max_users = 0;
2239 info2.current_users = 0;
2240 info2.path = pathname;
2241 info2.password = NULL;
2243 info.info2 = &info2;
2245 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2246 cli->srv_name_slash,
2251 if (!NT_STATUS_IS_OK(status)) {
2252 res = W_ERROR_V(ntstatus_to_werror(status));
2255 if (!W_ERROR_IS_OK(werr)) {
2256 res = W_ERROR_V(werr);
2261 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2265 SSVAL(*rparam,0,NERR_Success);
2266 SSVAL(*rparam,2,0); /* converter word */
2267 SSVAL(*rparam,4,*rdata_len);
2275 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2280 SSVAL(*rparam,0,res);
2285 /****************************************************************************
2286 view list of groups available
2287 ****************************************************************************/
2289 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2290 char *param, int tpscnt,
2291 char *data, int tdscnt,
2292 int mdrcnt,int mprcnt,
2293 char **rdata,char **rparam,
2294 int *rdata_len,int *rparam_len)
2298 int resume_context, cli_buf_size;
2299 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2300 char *str2 = skip_string(param,tpscnt,str1);
2301 char *p = skip_string(param,tpscnt,str2);
2303 uint32_t num_groups;
2304 uint32_t resume_handle;
2305 struct rpc_pipe_client *samr_pipe;
2306 struct policy_handle samr_handle, domain_handle;
2309 if (!str1 || !str2 || !p) {
2313 if (strcmp(str1,"WrLeh") != 0) {
2318 * W-> resume context (number of users to skip)
2319 * r -> return parameter pointer to receive buffer
2320 * L -> length of receive buffer
2321 * e -> return parameter number of entries
2322 * h -> return parameter total number of users
2325 if (strcmp("B21",str2) != 0) {
2329 status = rpc_pipe_open_internal(
2330 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2331 conn->server_info, &samr_pipe);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2334 nt_errstr(status)));
2338 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2339 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2340 if (!NT_STATUS_IS_OK(status)) {
2341 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2342 nt_errstr(status)));
2346 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2347 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2348 get_global_sam_sid(), &domain_handle);
2349 if (!NT_STATUS_IS_OK(status)) {
2350 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2351 nt_errstr(status)));
2352 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2356 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2357 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2358 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2359 "%d\n", resume_context, cli_buf_size));
2361 *rdata_len = cli_buf_size;
2362 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2369 errflags = NERR_Success;
2374 struct samr_SamArray *sam_entries;
2375 uint32_t num_entries;
2377 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2382 if (!NT_STATUS_IS_OK(status)) {
2383 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2384 "%s\n", nt_errstr(status)));
2388 if (num_entries == 0) {
2389 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2390 "no entries -- done\n"));
2394 for(i=0; i<num_entries; i++) {
2397 name = sam_entries->entries[i].name.string;
2399 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2400 /* set overflow error */
2401 DEBUG(3,("overflow on entry %d group %s\n", i,
2407 /* truncate the name at 21 chars. */
2409 strlcpy(p, name, 21);
2410 DEBUG(10,("adding entry %d group %s\n", i, p));
2412 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2417 if (errflags != NERR_Success) {
2421 TALLOC_FREE(sam_entries);
2424 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2425 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2427 *rdata_len = PTR_DIFF(p,*rdata);
2430 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2434 SSVAL(*rparam, 0, errflags);
2435 SSVAL(*rparam, 2, 0); /* converter word */
2436 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2437 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2442 /*******************************************************************
2443 Get groups that a user is a member of.
2444 ******************************************************************/
2446 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2447 char *param, int tpscnt,
2448 char *data, int tdscnt,
2449 int mdrcnt,int mprcnt,
2450 char **rdata,char **rparam,
2451 int *rdata_len,int *rparam_len)
2453 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2454 char *str2 = skip_string(param,tpscnt,str1);
2455 char *UserName = skip_string(param,tpscnt,str2);
2456 char *p = skip_string(param,tpscnt,UserName);
2457 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2458 const char *level_string;
2464 struct rpc_pipe_client *samr_pipe;
2465 struct policy_handle samr_handle, domain_handle, user_handle;
2466 struct lsa_String name;
2467 struct lsa_Strings names;
2468 struct samr_Ids type, rid;
2469 struct samr_RidWithAttributeArray *rids;
2472 if (!str1 || !str2 || !UserName || !p) {
2477 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2482 /* check it's a supported varient */
2484 if ( strcmp(str1,"zWrLeh") != 0 )
2489 level_string = "B21";
2495 if (strcmp(level_string,str2) != 0)
2498 *rdata_len = mdrcnt + 1024;
2499 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2504 SSVAL(*rparam,0,NERR_Success);
2505 SSVAL(*rparam,2,0); /* converter word */
2508 endp = *rdata + *rdata_len;
2510 status = rpc_pipe_open_internal(
2511 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2512 conn->server_info, &samr_pipe);
2513 if (!NT_STATUS_IS_OK(status)) {
2514 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2515 nt_errstr(status)));
2519 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2520 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2521 if (!NT_STATUS_IS_OK(status)) {
2522 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2523 nt_errstr(status)));
2527 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2528 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2529 get_global_sam_sid(), &domain_handle);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2532 nt_errstr(status)));
2536 name.string = UserName;
2538 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2539 &domain_handle, 1, &name,
2541 if (!NT_STATUS_IS_OK(status)) {
2542 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2543 nt_errstr(status)));
2547 if (type.ids[0] != SID_NAME_USER) {
2548 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2549 sid_type_lookup(type.ids[0])));
2553 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2555 SAMR_USER_ACCESS_GET_GROUPS,
2556 rid.ids[0], &user_handle);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2559 nt_errstr(status)));
2563 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2564 &user_handle, &rids);
2565 if (!NT_STATUS_IS_OK(status)) {
2566 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2567 nt_errstr(status)));
2571 for (i=0; i<rids->count; i++) {
2573 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2575 1, &rids->rids[i].rid,
2577 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2578 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2584 *rdata_len = PTR_DIFF(p,*rdata);
2586 SSVAL(*rparam,4,count); /* is this right?? */
2587 SSVAL(*rparam,6,count); /* is this right?? */
2592 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2594 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2596 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2601 /*******************************************************************
2603 ******************************************************************/
2605 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2606 char *param, int tpscnt,
2607 char *data, int tdscnt,
2608 int mdrcnt,int mprcnt,
2609 char **rdata,char **rparam,
2610 int *rdata_len,int *rparam_len)
2615 int i, resume_context, cli_buf_size;
2616 uint32_t resume_handle;
2618 struct rpc_pipe_client *samr_pipe;
2619 struct policy_handle samr_handle, domain_handle;
2622 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2623 char *str2 = skip_string(param,tpscnt,str1);
2624 char *p = skip_string(param,tpscnt,str2);
2627 if (!str1 || !str2 || !p) {
2631 if (strcmp(str1,"WrLeh") != 0)
2634 * W-> resume context (number of users to skip)
2635 * r -> return parameter pointer to receive buffer
2636 * L -> length of receive buffer
2637 * e -> return parameter number of entries
2638 * h -> return parameter total number of users
2641 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2642 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2643 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2644 resume_context, cli_buf_size));
2647 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2652 /* check it's a supported varient */
2653 if (strcmp("B21",str2) != 0)
2656 *rdata_len = cli_buf_size;
2657 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2663 endp = *rdata + *rdata_len;
2665 status = rpc_pipe_open_internal(
2666 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2667 conn->server_info, &samr_pipe);
2668 if (!NT_STATUS_IS_OK(status)) {
2669 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2670 nt_errstr(status)));
2674 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2675 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2676 if (!NT_STATUS_IS_OK(status)) {
2677 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2678 nt_errstr(status)));
2682 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2683 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2684 get_global_sam_sid(), &domain_handle);
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2687 nt_errstr(status)));
2688 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2692 errflags=NERR_Success;
2697 struct samr_SamArray *sam_entries;
2698 uint32_t num_entries;
2700 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2706 if (!NT_STATUS_IS_OK(status)) {
2707 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2708 "%s\n", nt_errstr(status)));
2712 if (num_entries == 0) {
2713 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2714 "no entries -- done\n"));
2718 for (i=0; i<num_entries; i++) {
2721 name = sam_entries->entries[i].name.string;
2723 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2724 &&(strlen(name)<=21)) {
2725 strlcpy(p,name,PTR_DIFF(endp,p));
2726 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2727 "username %s\n",count_sent,p));
2731 /* set overflow error */
2732 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2733 "username %s\n",count_sent,name));
2739 if (errflags != NERR_Success) {
2743 TALLOC_FREE(sam_entries);
2746 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2747 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2749 *rdata_len = PTR_DIFF(p,*rdata);
2751 SSVAL(*rparam,0,errflags);
2752 SSVAL(*rparam,2,0); /* converter word */
2753 SSVAL(*rparam,4,count_sent); /* is this right?? */
2754 SSVAL(*rparam,6,num_users); /* is this right?? */
2759 /****************************************************************************
2760 Get the time of day info.
2761 ****************************************************************************/
2763 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2764 char *param, int tpscnt,
2765 char *data, int tdscnt,
2766 int mdrcnt,int mprcnt,
2767 char **rdata,char **rparam,
2768 int *rdata_len,int *rparam_len)
2771 time_t unixdate = time(NULL);
2775 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2781 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2786 SSVAL(*rparam,0,NERR_Success);
2787 SSVAL(*rparam,2,0); /* converter word */
2791 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2792 by NT in a "net time" operation,
2793 it seems to ignore the one below */
2795 /* the client expects to get localtime, not GMT, in this bit
2796 (I think, this needs testing) */
2797 t = localtime(&unixdate);
2802 SIVAL(p,4,0); /* msecs ? */
2803 SCVAL(p,8,t->tm_hour);
2804 SCVAL(p,9,t->tm_min);
2805 SCVAL(p,10,t->tm_sec);
2806 SCVAL(p,11,0); /* hundredths of seconds */
2807 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2808 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2809 SCVAL(p,16,t->tm_mday);
2810 SCVAL(p,17,t->tm_mon + 1);
2811 SSVAL(p,18,1900+t->tm_year);
2812 SCVAL(p,20,t->tm_wday);
2817 /****************************************************************************
2818 Set the user password.
2819 *****************************************************************************/
2821 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2822 char *param, int tpscnt,
2823 char *data, int tdscnt,
2824 int mdrcnt,int mprcnt,
2825 char **rdata,char **rparam,
2826 int *rdata_len,int *rparam_len)
2828 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2831 fstring pass1,pass2;
2833 /* Skip 2 strings. */
2834 p = skip_string(param,tpscnt,np);
2835 p = skip_string(param,tpscnt,p);
2841 /* Do we have a string ? */
2842 if (skip_string(param,tpscnt,p) == NULL) {
2845 pull_ascii_fstring(user,p);
2847 p = skip_string(param,tpscnt,p);
2852 memset(pass1,'\0',sizeof(pass1));
2853 memset(pass2,'\0',sizeof(pass2));
2855 * We use 31 here not 32 as we're checking
2856 * the last byte we want to access is safe.
2858 if (!is_offset_safe(param,tpscnt,p,31)) {
2862 memcpy(pass2,p+16,16);
2865 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2872 SSVAL(*rparam,0,NERR_badpass);
2873 SSVAL(*rparam,2,0); /* converter word */
2875 DEBUG(3,("Set password for <%s>\n",user));
2878 * Attempt to verify the old password against smbpasswd entries
2879 * Win98 clients send old and new password in plaintext for this call.
2883 struct auth_serversupplied_info *server_info = NULL;
2884 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2886 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2889 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2890 SSVAL(*rparam,0,NERR_Success);
2894 TALLOC_FREE(server_info);
2896 data_blob_clear_free(&password);
2900 * If the plaintext change failed, attempt
2901 * the old encrypted method. NT will generate this
2902 * after trying the samr method. Note that this
2903 * method is done as a last resort as this
2904 * password change method loses the NT password hash
2905 * and cannot change the UNIX password as no plaintext
2909 if(SVAL(*rparam,0) != NERR_Success) {
2910 struct samu *hnd = NULL;
2912 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2914 if (change_lanman_password(hnd,(uchar *)pass2)) {
2915 SSVAL(*rparam,0,NERR_Success);
2922 memset((char *)pass1,'\0',sizeof(fstring));
2923 memset((char *)pass2,'\0',sizeof(fstring));
2928 /****************************************************************************
2929 Set the user password (SamOEM version - gets plaintext).
2930 ****************************************************************************/
2932 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2933 char *param, int tpscnt,
2934 char *data, int tdscnt,
2935 int mdrcnt,int mprcnt,
2936 char **rdata,char **rparam,
2937 int *rdata_len,int *rparam_len)
2939 struct smbd_server_connection *sconn = smbd_server_conn;
2941 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2943 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2953 SSVAL(*rparam,0,NERR_badpass);
2956 * Check the parameter definition is correct.
2959 /* Do we have a string ? */
2960 if (skip_string(param,tpscnt,p) == 0) {
2963 if(!strequal(p, "zsT")) {
2964 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2967 p = skip_string(param, tpscnt, p);
2972 /* Do we have a string ? */
2973 if (skip_string(param,tpscnt,p) == 0) {
2976 if(!strequal(p, "B516B16")) {
2977 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2980 p = skip_string(param,tpscnt,p);
2984 /* Do we have a string ? */
2985 if (skip_string(param,tpscnt,p) == 0) {
2988 p += pull_ascii_fstring(user,p);
2990 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2993 * Pass the user through the NT -> unix user mapping
2997 (void)map_username(sconn, user);
2999 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
3000 SSVAL(*rparam,0,NERR_Success);
3006 /****************************************************************************
3009 ****************************************************************************/
3011 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3012 char *param, int tpscnt,
3013 char *data, int tdscnt,
3014 int mdrcnt,int mprcnt,
3015 char **rdata,char **rparam,
3016 int *rdata_len,int *rparam_len)
3018 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3019 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3020 char *str2 = skip_string(param,tpscnt,str1);
3021 char *p = skip_string(param,tpscnt,str2);
3025 WERROR werr = WERR_OK;
3027 TALLOC_CTX *mem_ctx = talloc_tos();
3029 struct rpc_pipe_client *cli = NULL;
3030 struct policy_handle handle;
3031 struct spoolss_DevmodeContainer devmode_ctr;
3032 enum spoolss_JobControl command;
3034 if (!str1 || !str2 || !p) {
3038 * We use 1 here not 2 as we're checking
3039 * the last byte we want to access is safe.
3041 if (!is_offset_safe(param,tpscnt,p,1)) {
3044 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3047 /* check it's a supported varient */
3048 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3052 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3058 ZERO_STRUCT(handle);
3060 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3061 rpc_spoolss_dispatch, conn->server_info,
3063 if (!NT_STATUS_IS_OK(status)) {
3064 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3065 nt_errstr(status)));
3066 errcode = W_ERROR_V(ntstatus_to_werror(status));
3070 ZERO_STRUCT(devmode_ctr);
3072 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3076 SEC_FLAG_MAXIMUM_ALLOWED,
3079 if (!NT_STATUS_IS_OK(status)) {
3080 errcode = W_ERROR_V(ntstatus_to_werror(status));
3083 if (!W_ERROR_IS_OK(werr)) {
3084 errcode = W_ERROR_V(werr);
3088 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3089 * and NERR_DestNotFound if share did not exist */
3091 errcode = NERR_Success;
3094 case 81: /* delete */
3095 command = SPOOLSS_JOB_CONTROL_DELETE;
3097 case 82: /* pause */
3098 command = SPOOLSS_JOB_CONTROL_PAUSE;
3100 case 83: /* resume */
3101 command = SPOOLSS_JOB_CONTROL_RESUME;
3104 errcode = NERR_notsupported;
3108 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3111 NULL, /* unique ptr ctr */
3114 if (!NT_STATUS_IS_OK(status)) {
3115 errcode = W_ERROR_V(ntstatus_to_werror(status));
3118 if (!W_ERROR_IS_OK(werr)) {
3119 errcode = W_ERROR_V(werr);
3124 if (cli && is_valid_policy_hnd(&handle)) {
3125 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3128 SSVAL(*rparam,0,errcode);
3129 SSVAL(*rparam,2,0); /* converter word */
3134 /****************************************************************************
3135 Purge a print queue - or pause or resume it.
3136 ****************************************************************************/
3138 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3139 char *param, int tpscnt,
3140 char *data, int tdscnt,
3141 int mdrcnt,int mprcnt,
3142 char **rdata,char **rparam,
3143 int *rdata_len,int *rparam_len)
3145 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3146 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3147 char *str2 = skip_string(param,tpscnt,str1);
3148 char *QueueName = skip_string(param,tpscnt,str2);
3149 int errcode = NERR_notsupported;
3150 WERROR werr = WERR_OK;
3153 TALLOC_CTX *mem_ctx = talloc_tos();
3154 struct rpc_pipe_client *cli = NULL;
3155 struct policy_handle handle;
3156 struct spoolss_SetPrinterInfoCtr info_ctr;
3157 struct spoolss_DevmodeContainer devmode_ctr;
3158 struct sec_desc_buf secdesc_ctr;
3159 enum spoolss_PrinterControl command;
3161 if (!str1 || !str2 || !QueueName) {
3165 /* check it's a supported varient */
3166 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3170 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3176 if (skip_string(param,tpscnt,QueueName) == NULL) {
3180 ZERO_STRUCT(handle);
3182 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3183 rpc_spoolss_dispatch, conn->server_info,
3185 if (!NT_STATUS_IS_OK(status)) {
3186 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3187 nt_errstr(status)));
3188 errcode = W_ERROR_V(ntstatus_to_werror(status));
3192 ZERO_STRUCT(devmode_ctr);
3194 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3198 SEC_FLAG_MAXIMUM_ALLOWED,
3201 if (!NT_STATUS_IS_OK(status)) {
3202 errcode = W_ERROR_V(ntstatus_to_werror(status));
3205 if (!W_ERROR_IS_OK(werr)) {
3206 errcode = W_ERROR_V(werr);
3211 case 74: /* Pause queue */
3212 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3214 case 75: /* Resume queue */
3215 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3217 case 103: /* Purge */
3218 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3221 werr = WERR_NOT_SUPPORTED;
3225 if (!W_ERROR_IS_OK(werr)) {
3226 errcode = W_ERROR_V(werr);
3230 ZERO_STRUCT(info_ctr);
3231 ZERO_STRUCT(secdesc_ctr);
3233 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3240 if (!NT_STATUS_IS_OK(status)) {
3241 errcode = W_ERROR_V(ntstatus_to_werror(status));
3244 if (!W_ERROR_IS_OK(werr)) {
3245 errcode = W_ERROR_V(werr);
3249 errcode = W_ERROR_V(werr);
3253 if (cli && is_valid_policy_hnd(&handle)) {
3254 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3257 SSVAL(*rparam,0,errcode);
3258 SSVAL(*rparam,2,0); /* converter word */
3263 /****************************************************************************
3264 set the property of a print job (undocumented?)
3265 ? function = 0xb -> set name of print job
3266 ? function = 0x6 -> move print job up/down
3267 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3268 or <WWsTP> <WB21BB16B10zWWzDDz>
3269 ****************************************************************************/
3271 static int check_printjob_info(struct pack_desc* desc,
3272 int uLevel, char* id)
3274 desc->subformat = NULL;
3276 case 0: desc->format = "W"; break;
3277 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3278 case 2: desc->format = "WWzWWDDzz"; break;
3279 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3280 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3282 DEBUG(0,("check_printjob_info: invalid level %d\n",
3286 if (id == NULL || strcmp(desc->format,id) != 0) {
3287 DEBUG(0,("check_printjob_info: invalid format %s\n",
3288 id ? id : "<NULL>" ));
3294 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3295 char *param, int tpscnt,
3296 char *data, int tdscnt,
3297 int mdrcnt,int mprcnt,
3298 char **rdata,char **rparam,
3299 int *rdata_len,int *rparam_len)
3301 struct pack_desc desc;
3302 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3303 char *str2 = skip_string(param,tpscnt,str1);
3304 char *p = skip_string(param,tpscnt,str2);
3307 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3308 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3311 TALLOC_CTX *mem_ctx = talloc_tos();
3314 struct rpc_pipe_client *cli = NULL;
3315 struct policy_handle handle;
3316 struct spoolss_DevmodeContainer devmode_ctr;
3317 struct spoolss_JobInfoContainer ctr;
3318 union spoolss_JobInfo info;
3319 struct spoolss_SetJobInfo1 info1;
3321 if (!str1 || !str2 || !p) {
3325 * We use 1 here not 2 as we're checking
3326 * the last byte we want to access is safe.
3328 if (!is_offset_safe(param,tpscnt,p,1)) {
3331 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3334 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3341 /* check it's a supported varient */
3342 if ((strcmp(str1,"WWsTP")) ||
3343 (!check_printjob_info(&desc,uLevel,str2)))
3346 errcode = NERR_notsupported;
3350 /* change print job name, data gives the name */
3356 ZERO_STRUCT(handle);
3358 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3359 rpc_spoolss_dispatch, conn->server_info,
3361 if (!NT_STATUS_IS_OK(status)) {
3362 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3363 nt_errstr(status)));
3364 errcode = W_ERROR_V(ntstatus_to_werror(status));
3368 ZERO_STRUCT(devmode_ctr);
3370 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3374 SEC_FLAG_MAXIMUM_ALLOWED,
3377 if (!NT_STATUS_IS_OK(status)) {
3378 errcode = W_ERROR_V(ntstatus_to_werror(status));
3381 if (!W_ERROR_IS_OK(werr)) {
3382 errcode = W_ERROR_V(werr);
3386 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3392 if (!W_ERROR_IS_OK(werr)) {
3393 errcode = W_ERROR_V(werr);
3399 info1.job_id = info.info1.job_id;
3400 info1.printer_name = info.info1.printer_name;
3401 info1.user_name = info.info1.user_name;
3402 info1.document_name = data;
3403 info1.data_type = info.info1.data_type;
3404 info1.text_status = info.info1.text_status;
3405 info1.status = info.info1.status;
3406 info1.priority = info.info1.priority;
3407 info1.position = info.info1.position;
3408 info1.total_pages = info.info1.total_pages;
3409 info1.pages_printed = info.info1.pages_printed;
3410 info1.submitted = info.info1.submitted;
3413 ctr.info.info1 = &info1;
3415 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3421 if (!NT_STATUS_IS_OK(status)) {
3422 errcode = W_ERROR_V(ntstatus_to_werror(status));
3425 if (!W_ERROR_IS_OK(werr)) {
3426 errcode = W_ERROR_V(werr);
3430 errcode = NERR_Success;
3433 if (cli && is_valid_policy_hnd(&handle)) {
3434 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3437 SSVALS(*rparam,0,errcode);
3438 SSVAL(*rparam,2,0); /* converter word */
3444 /****************************************************************************
3445 Get info about the server.
3446 ****************************************************************************/
3448 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3449 char *param, int tpscnt,
3450 char *data, int tdscnt,
3451 int mdrcnt,int mprcnt,
3452 char **rdata,char **rparam,
3453 int *rdata_len,int *rparam_len)
3455 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3456 char *str2 = skip_string(param,tpscnt,str1);
3457 char *p = skip_string(param,tpscnt,str2);
3458 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3464 TALLOC_CTX *mem_ctx = talloc_tos();
3465 struct rpc_pipe_client *cli = NULL;
3466 union srvsvc_NetSrvInfo info;
3469 if (!str1 || !str2 || !p) {
3473 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3475 /* check it's a supported varient */
3476 if (!prefix_ok(str1,"WrLh")) {
3482 if (strcmp(str2,"B16") != 0) {
3488 if (strcmp(str2,"B16BBDz") != 0) {
3494 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3500 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3506 if (strcmp(str2,"DN") != 0) {
3512 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3521 *rdata_len = mdrcnt;
3522 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3528 p2 = p + struct_len;
3530 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3531 rpc_srvsvc_dispatch, conn->server_info,
3533 if (!NT_STATUS_IS_OK(status)) {
3534 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3535 nt_errstr(status)));
3536 errcode = W_ERROR_V(ntstatus_to_werror(status));
3540 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3545 if (!NT_STATUS_IS_OK(status)) {
3546 errcode = W_ERROR_V(ntstatus_to_werror(status));
3549 if (!W_ERROR_IS_OK(werr)) {
3550 errcode = W_ERROR_V(werr);
3554 if (info.info101 == NULL) {
3555 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3560 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3561 STR_ASCII|STR_UPPER|STR_TERMINATE);
3565 SCVAL(p,0,info.info101->version_major);
3566 SCVAL(p,1,info.info101->version_minor);
3567 SIVAL(p,2,info.info101->server_type);
3569 if (mdrcnt == struct_len) {
3572 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3573 if (mdrcnt - struct_len <= 0) {
3577 info.info101->comment,
3578 MIN(mdrcnt - struct_len,
3579 MAX_SERVER_STRING_LENGTH),
3581 p2 = skip_string(*rdata,*rdata_len,p2);
3589 return False; /* not yet implemented */
3592 errcode = NERR_Success;
3596 *rdata_len = PTR_DIFF(p2,*rdata);
3599 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3603 SSVAL(*rparam,0,errcode);
3604 SSVAL(*rparam,2,0); /* converter word */
3605 SSVAL(*rparam,4,*rdata_len);
3610 /****************************************************************************
3611 Get info about the server.
3612 ****************************************************************************/
3614 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3615 char *param, int tpscnt,
3616 char *data, int tdscnt,
3617 int mdrcnt,int mprcnt,
3618 char **rdata,char **rparam,
3619 int *rdata_len,int *rparam_len)
3621 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3622 char *str2 = skip_string(param,tpscnt,str1);
3623 char *p = skip_string(param,tpscnt,str2);
3626 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3628 if (!str1 || !str2 || !p) {
3632 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3635 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3640 /* check it's a supported varient */
3641 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3645 *rdata_len = mdrcnt + 1024;
3646 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3651 SSVAL(*rparam,0,NERR_Success);
3652 SSVAL(*rparam,2,0); /* converter word */
3655 endp = *rdata + *rdata_len;
3657 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3662 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3663 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3665 p2 = skip_string(*rdata,*rdata_len,p2);
3671 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3672 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3673 p2 = skip_string(*rdata,*rdata_len,p2);
3679 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3680 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3682 p2 = skip_string(*rdata,*rdata_len,p2);
3688 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3689 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3692 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3693 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3694 p2 = skip_string(*rdata,*rdata_len,p2);
3700 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3701 strlcpy(p2,"",PTR_DIFF(endp,p2));
3702 p2 = skip_string(*rdata,*rdata_len,p2);
3708 *rdata_len = PTR_DIFF(p2,*rdata);
3710 SSVAL(*rparam,4,*rdata_len);
3715 /****************************************************************************
3716 get info about a user
3718 struct user_info_11 {
3719 char usri11_name[21]; 0-20
3721 char *usri11_comment; 22-25
3722 char *usri11_usr_comment; 26-29
3723 unsigned short usri11_priv; 30-31
3724 unsigned long usri11_auth_flags; 32-35
3725 long usri11_password_age; 36-39
3726 char *usri11_homedir; 40-43
3727 char *usri11_parms; 44-47
3728 long usri11_last_logon; 48-51
3729 long usri11_last_logoff; 52-55
3730 unsigned short usri11_bad_pw_count; 56-57
3731 unsigned short usri11_num_logons; 58-59
3732 char *usri11_logon_server; 60-63
3733 unsigned short usri11_country_code; 64-65
3734 char *usri11_workstations; 66-69
3735 unsigned long usri11_max_storage; 70-73
3736 unsigned short usri11_units_per_week; 74-75
3737 unsigned char *usri11_logon_hours; 76-79
3738 unsigned short usri11_code_page; 80-81
3743 usri11_name specifies the user name for which information is retrieved
3745 usri11_pad aligns the next data structure element to a word boundary
3747 usri11_comment is a null terminated ASCII comment
3749 usri11_user_comment is a null terminated ASCII comment about the user
3751 usri11_priv specifies the level of the privilege assigned to the user.
3752 The possible values are:
3754 Name Value Description
3755 USER_PRIV_GUEST 0 Guest privilege
3756 USER_PRIV_USER 1 User privilege
3757 USER_PRV_ADMIN 2 Administrator privilege
3759 usri11_auth_flags specifies the account operator privileges. The
3760 possible values are:
3762 Name Value Description
3763 AF_OP_PRINT 0 Print operator
3766 Leach, Naik [Page 28]
3770 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3773 AF_OP_COMM 1 Communications operator
3774 AF_OP_SERVER 2 Server operator
3775 AF_OP_ACCOUNTS 3 Accounts operator
3778 usri11_password_age specifies how many seconds have elapsed since the
3779 password was last changed.
3781 usri11_home_dir points to a null terminated ASCII string that contains
3782 the path name of the user's home directory.
3784 usri11_parms points to a null terminated ASCII string that is set
3785 aside for use by applications.
3787 usri11_last_logon specifies the time when the user last logged on.
3788 This value is stored as the number of seconds elapsed since
3789 00:00:00, January 1, 1970.
3791 usri11_last_logoff specifies the time when the user last logged off.
3792 This value is stored as the number of seconds elapsed since
3793 00:00:00, January 1, 1970. A value of 0 means the last logoff
3796 usri11_bad_pw_count specifies the number of incorrect passwords
3797 entered since the last successful logon.
3799 usri11_log1_num_logons specifies the number of times this user has
3800 logged on. A value of -1 means the number of logons is unknown.
3802 usri11_logon_server points to a null terminated ASCII string that
3803 contains the name of the server to which logon requests are sent.
3804 A null string indicates logon requests should be sent to the
3807 usri11_country_code specifies the country code for the user's language
3810 usri11_workstations points to a null terminated ASCII string that
3811 contains the names of workstations the user may log on from.
3812 There may be up to 8 workstations, with the names separated by
3813 commas. A null strings indicates there are no restrictions.
3815 usri11_max_storage specifies the maximum amount of disk space the user
3816 can occupy. A value of 0xffffffff indicates there are no
3819 usri11_units_per_week specifies the equal number of time units into
3820 which a week is divided. This value must be equal to 168.
3822 usri11_logon_hours points to a 21 byte (168 bits) string that
3823 specifies the time during which the user can log on. Each bit
3824 represents one unique hour in a week. The first bit (bit 0, word
3825 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3829 Leach, Naik [Page 29]
3833 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3836 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3837 are no restrictions.
3839 usri11_code_page specifies the code page for the user's language of
3842 All of the pointers in this data structure need to be treated
3843 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3844 to be ignored. The converter word returned in the parameters section
3845 needs to be subtracted from the lower 16 bits to calculate an offset
3846 into the return buffer where this ASCII string resides.
3848 There is no auxiliary data in the response.
3850 ****************************************************************************/
3852 #define usri11_name 0
3853 #define usri11_pad 21
3854 #define usri11_comment 22
3855 #define usri11_usr_comment 26
3856 #define usri11_full_name 30
3857 #define usri11_priv 34
3858 #define usri11_auth_flags 36
3859 #define usri11_password_age 40
3860 #define usri11_homedir 44
3861 #define usri11_parms 48
3862 #define usri11_last_logon 52
3863 #define usri11_last_logoff 56
3864 #define usri11_bad_pw_count 60
3865 #define usri11_num_logons 62
3866 #define usri11_logon_server 64
3867 #define usri11_country_code 68
3868 #define usri11_workstations 70
3869 #define usri11_max_storage 74
3870 #define usri11_units_per_week 78
3871 #define usri11_logon_hours 80
3872 #define usri11_code_page 84
3873 #define usri11_end 86
3875 #define USER_PRIV_GUEST 0
3876 #define USER_PRIV_USER 1
3877 #define USER_PRIV_ADMIN 2
3879 #define AF_OP_PRINT 0
3880 #define AF_OP_COMM 1
3881 #define AF_OP_SERVER 2
3882 #define AF_OP_ACCOUNTS 3
3885 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3886 char *param, int tpscnt,
3887 char *data, int tdscnt,
3888 int mdrcnt,int mprcnt,
3889 char **rdata,char **rparam,
3890 int *rdata_len,int *rparam_len)
3892 struct smbd_server_connection *sconn = smbd_server_conn;
3893 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3894 char *str2 = skip_string(param,tpscnt,str1);
3895 char *UserName = skip_string(param,tpscnt,str2);
3896 char *p = skip_string(param,tpscnt,UserName);
3897 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3900 const char *level_string;
3902 /* get NIS home of a previously validated user - simeon */
3903 /* With share level security vuid will always be zero.
3904 Don't depend on vuser being non-null !!. JRA */
3905 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3907 DEBUG(3,(" Username of UID %d is %s\n",
3908 (int)vuser->server_info->utok.uid,
3909 vuser->server_info->unix_name));
3912 if (!str1 || !str2 || !UserName || !p) {
3917 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3922 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3924 /* check it's a supported variant */
3925 if (strcmp(str1,"zWrLh") != 0) {
3929 case 0: level_string = "B21"; break;
3930 case 1: level_string = "B21BB16DWzzWz"; break;
3931 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3932 case 10: level_string = "B21Bzzz"; break;
3933 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3934 default: return False;
3937 if (strcmp(level_string,str2) != 0) {
3941 *rdata_len = mdrcnt + 1024;
3942 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3947 SSVAL(*rparam,0,NERR_Success);
3948 SSVAL(*rparam,2,0); /* converter word */
3951 endp = *rdata + *rdata_len;
3952 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3958 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3961 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3966 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3967 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3968 p2 = skip_string(*rdata,*rdata_len,p2);
3973 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3974 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3975 p2 = skip_string(*rdata,*rdata_len,p2);
3980 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3981 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3982 strlcpy(p2,((vuser != NULL)
3983 ? pdb_get_fullname(vuser->server_info->sam_account)
3984 : UserName),PTR_DIFF(endp,p2));
3985 p2 = skip_string(*rdata,*rdata_len,p2);
3992 const char *homedir = "";
3993 if (vuser != NULL) {
3994 homedir = pdb_get_homedir(
3995 vuser->server_info->sam_account);
3997 /* modelled after NTAS 3.51 reply */
3998 SSVAL(p,usri11_priv,
3999 (get_current_uid(conn) == sec_initial_uid())?
4000 USER_PRIV_ADMIN:USER_PRIV_USER);
4001 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4002 SIVALS(p,usri11_password_age,-1); /* password age */
4003 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4004 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4005 p2 = skip_string(*rdata,*rdata_len,p2);
4009 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4010 strlcpy(p2,"",PTR_DIFF(endp,p2));
4011 p2 = skip_string(*rdata,*rdata_len,p2);
4015 SIVAL(p,usri11_last_logon,0); /* last logon */
4016 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4017 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4018 SSVALS(p,usri11_num_logons,-1); /* num logons */
4019 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4020 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4021 p2 = skip_string(*rdata,*rdata_len,p2);
4025 SSVAL(p,usri11_country_code,0); /* country code */
4027 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4028 strlcpy(p2,"",PTR_DIFF(endp,p2));
4029 p2 = skip_string(*rdata,*rdata_len,p2);
4034 SIVALS(p,usri11_max_storage,-1); /* max storage */
4035 SSVAL(p,usri11_units_per_week,168); /* units per week */
4036 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4038 /* a simple way to get logon hours at all times. */
4040 SCVAL(p2,21,0); /* fix zero termination */
4041 p2 = skip_string(*rdata,*rdata_len,p2);
4046 SSVAL(p,usri11_code_page,0); /* code page */
4049 if (uLevel == 1 || uLevel == 2) {
4050 memset(p+22,' ',16); /* password */
4051 SIVALS(p,38,-1); /* password age */
4053 (get_current_uid(conn) == sec_initial_uid())?
4054 USER_PRIV_ADMIN:USER_PRIV_USER);
4055 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4056 strlcpy(p2, vuser ? pdb_get_homedir(
4057 vuser->server_info->sam_account) : "",
4059 p2 = skip_string(*rdata,*rdata_len,p2);
4063 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4065 SSVAL(p,52,0); /* flags */
4066 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4067 strlcpy(p2, vuser ? pdb_get_logon_script(
4068 vuser->server_info->sam_account) : "",
4070 p2 = skip_string(*rdata,*rdata_len,p2);
4075 SIVAL(p,60,0); /* auth_flags */
4076 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4077 strlcpy(p2,((vuser != NULL)
4078 ? pdb_get_fullname(vuser->server_info->sam_account)
4079 : UserName),PTR_DIFF(endp,p2));
4080 p2 = skip_string(*rdata,*rdata_len,p2);
4084 SIVAL(p,68,0); /* urs_comment */
4085 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4086 strlcpy(p2,"",PTR_DIFF(endp,p2));
4087 p2 = skip_string(*rdata,*rdata_len,p2);
4091 SIVAL(p,76,0); /* workstations */
4092 SIVAL(p,80,0); /* last_logon */
4093 SIVAL(p,84,0); /* last_logoff */
4094 SIVALS(p,88,-1); /* acct_expires */
4095 SIVALS(p,92,-1); /* max_storage */
4096 SSVAL(p,96,168); /* units_per_week */
4097 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4100 SSVALS(p,102,-1); /* bad_pw_count */
4101 SSVALS(p,104,-1); /* num_logons */
4102 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4104 TALLOC_CTX *ctx = talloc_tos();
4105 int space_rem = *rdata_len - (p2 - *rdata);
4108 if (space_rem <= 0) {
4111 tmp = talloc_strdup(ctx, "\\\\%L");
4115 tmp = talloc_sub_basic(ctx,
4128 p2 = skip_string(*rdata,*rdata_len,p2);
4132 SSVAL(p,110,49); /* country_code */
4133 SSVAL(p,112,860); /* code page */
4137 *rdata_len = PTR_DIFF(p2,*rdata);
4139 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4144 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4145 char *param, int tpscnt,
4146 char *data, int tdscnt,
4147 int mdrcnt,int mprcnt,
4148 char **rdata,char **rparam,
4149 int *rdata_len,int *rparam_len)
4151 struct smbd_server_connection *sconn = smbd_server_conn;
4152 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4153 char *str2 = skip_string(param,tpscnt,str1);
4154 char *p = skip_string(param,tpscnt,str2);
4156 struct pack_desc desc;
4158 /* With share level security vuid will always be zero.
4159 Don't depend on vuser being non-null !!. JRA */
4160 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4162 if (!str1 || !str2 || !p) {
4167 DEBUG(3,(" Username of UID %d is %s\n",
4168 (int)vuser->server_info->utok.uid,
4169 vuser->server_info->unix_name));
4172 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4173 name = get_safe_str_ptr(param,tpscnt,p,2);
4178 memset((char *)&desc,'\0',sizeof(desc));
4180 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4182 /* check it's a supported varient */
4183 if (strcmp(str1,"OOWb54WrLh") != 0) {
4186 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4190 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4197 desc.buflen = mdrcnt;
4198 desc.subformat = NULL;
4201 if (init_package(&desc,1,0)) {
4202 PACKI(&desc,"W",0); /* code */
4203 PACKS(&desc,"B21",name); /* eff. name */
4204 PACKS(&desc,"B",""); /* pad */
4206 (get_current_uid(conn) == sec_initial_uid())?
4207 USER_PRIV_ADMIN:USER_PRIV_USER);
4208 PACKI(&desc,"D",0); /* auth flags XXX */
4209 PACKI(&desc,"W",0); /* num logons */
4210 PACKI(&desc,"W",0); /* bad pw count */
4211 PACKI(&desc,"D",0); /* last logon */
4212 PACKI(&desc,"D",-1); /* last logoff */
4213 PACKI(&desc,"D",-1); /* logoff time */
4214 PACKI(&desc,"D",-1); /* kickoff time */
4215 PACKI(&desc,"D",0); /* password age */
4216 PACKI(&desc,"D",0); /* password can change */
4217 PACKI(&desc,"D",-1); /* password must change */
4221 fstrcpy(mypath,"\\\\");
4222 fstrcat(mypath,get_local_machine_name());
4224 PACKS(&desc,"z",mypath); /* computer */
4227 PACKS(&desc,"z",lp_workgroup());/* domain */
4228 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4229 vuser->server_info->sam_account) : ""); /* script path */
4230 PACKI(&desc,"D",0x00000000); /* reserved */
4233 *rdata_len = desc.usedlen;
4235 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4239 SSVALS(*rparam,0,desc.errcode);
4241 SSVAL(*rparam,4,desc.neededlen);
4243 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4248 /****************************************************************************
4249 api_WAccessGetUserPerms
4250 ****************************************************************************/
4252 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4253 char *param, int tpscnt,
4254 char *data, int tdscnt,
4255 int mdrcnt,int mprcnt,
4256 char **rdata,char **rparam,
4257 int *rdata_len,int *rparam_len)
4259 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4260 char *str2 = skip_string(param,tpscnt,str1);
4261 char *user = skip_string(param,tpscnt,str2);
4262 char *resource = skip_string(param,tpscnt,user);
4264 if (!str1 || !str2 || !user || !resource) {
4268 if (skip_string(param,tpscnt,resource) == NULL) {
4271 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4273 /* check it's a supported varient */
4274 if (strcmp(str1,"zzh") != 0) {
4277 if (strcmp(str2,"") != 0) {
4282 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4286 SSVALS(*rparam,0,0); /* errorcode */
4287 SSVAL(*rparam,2,0); /* converter word */
4288 SSVAL(*rparam,4,0x7f); /* permission flags */
4293 /****************************************************************************
4294 api_WPrintJobEnumerate
4295 ****************************************************************************/
4297 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4298 char *param, int tpscnt,
4299 char *data, int tdscnt,
4300 int mdrcnt,int mprcnt,
4301 char **rdata,char **rparam,
4302 int *rdata_len,int *rparam_len)
4304 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4305 char *str2 = skip_string(param,tpscnt,str1);
4306 char *p = skip_string(param,tpscnt,str2);
4310 struct pack_desc desc;
4313 TALLOC_CTX *mem_ctx = talloc_tos();
4316 struct rpc_pipe_client *cli = NULL;
4317 struct policy_handle handle;
4318 struct spoolss_DevmodeContainer devmode_ctr;
4319 union spoolss_JobInfo info;
4321 if (!str1 || !str2 || !p) {
4325 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4327 memset((char *)&desc,'\0',sizeof(desc));
4328 memset((char *)&status,'\0',sizeof(status));
4330 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4332 /* check it's a supported varient */
4333 if (strcmp(str1,"WWrLh") != 0) {
4336 if (!check_printjob_info(&desc,uLevel,str2)) {
4340 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4344 ZERO_STRUCT(handle);
4346 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4347 rpc_spoolss_dispatch, conn->server_info,
4349 if (!NT_STATUS_IS_OK(status)) {
4350 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4351 nt_errstr(status)));
4352 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4356 ZERO_STRUCT(devmode_ctr);
4358 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4362 SEC_FLAG_MAXIMUM_ALLOWED,
4365 if (!NT_STATUS_IS_OK(status)) {
4366 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4369 if (!W_ERROR_IS_OK(werr)) {
4370 desc.errcode = W_ERROR_V(werr);
4374 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4380 if (!W_ERROR_IS_OK(werr)) {
4381 desc.errcode = W_ERROR_V(werr);
4386 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4391 desc.buflen = mdrcnt;
4394 * Don't return data but need to get correct length
4395 * init_package will return wrong size if buflen=0
4397 desc.buflen = getlen(desc.format);
4398 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4401 if (init_package(&desc,1,0)) {
4402 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4403 *rdata_len = desc.usedlen;
4405 desc.errcode = NERR_JobNotFound;
4409 if (cli && is_valid_policy_hnd(&handle)) {
4410 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4414 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4418 SSVALS(*rparam,0,desc.errcode);
4420 SSVAL(*rparam,4,desc.neededlen);
4424 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4429 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4430 char *param, int tpscnt,
4431 char *data, int tdscnt,
4432 int mdrcnt,int mprcnt,
4433 char **rdata,char **rparam,
4434 int *rdata_len,int *rparam_len)
4436 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4437 char *str2 = skip_string(param,tpscnt,str1);
4438 char *p = skip_string(param,tpscnt,str2);
4442 struct pack_desc desc;
4444 TALLOC_CTX *mem_ctx = talloc_tos();
4447 struct rpc_pipe_client *cli = NULL;
4448 struct policy_handle handle;
4449 struct spoolss_DevmodeContainer devmode_ctr;
4451 union spoolss_JobInfo *info;
4453 if (!str1 || !str2 || !p) {
4457 memset((char *)&desc,'\0',sizeof(desc));
4459 p = skip_string(param,tpscnt,p);
4463 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4465 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4467 /* check it's a supported variant */
4468 if (strcmp(str1,"zWrLeh") != 0) {
4473 return False; /* defined only for uLevel 0,1,2 */
4476 if (!check_printjob_info(&desc,uLevel,str2)) {
4480 ZERO_STRUCT(handle);
4482 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4483 rpc_spoolss_dispatch, conn->server_info,
4485 if (!NT_STATUS_IS_OK(status)) {
4486 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4487 nt_errstr(status)));
4488 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4492 ZERO_STRUCT(devmode_ctr);
4494 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4498 SEC_FLAG_MAXIMUM_ALLOWED,
4501 if (!NT_STATUS_IS_OK(status)) {
4502 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4505 if (!W_ERROR_IS_OK(werr)) {
4506 desc.errcode = W_ERROR_V(werr);
4510 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4518 if (!W_ERROR_IS_OK(werr)) {
4519 desc.errcode = W_ERROR_V(werr);
4524 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4530 desc.buflen = mdrcnt;
4532 if (init_package(&desc,count,0)) {
4534 for (i = 0; i < count; i++) {
4535 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4536 if (desc.errcode == NERR_Success) {
4542 if (cli && is_valid_policy_hnd(&handle)) {
4543 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4546 *rdata_len = desc.usedlen;
4549 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4553 SSVALS(*rparam,0,desc.errcode);
4555 SSVAL(*rparam,4,succnt);
4556 SSVAL(*rparam,6,count);
4558 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4563 static int check_printdest_info(struct pack_desc* desc,
4564 int uLevel, char* id)
4566 desc->subformat = NULL;
4569 desc->format = "B9";
4572 desc->format = "B9B21WWzW";
4578 desc->format = "zzzWWzzzWW";
4581 DEBUG(0,("check_printdest_info: invalid level %d\n",
4585 if (id == NULL || strcmp(desc->format,id) != 0) {
4586 DEBUG(0,("check_printdest_info: invalid string %s\n",
4587 id ? id : "<NULL>" ));
4593 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4594 struct pack_desc* desc)
4598 strncpy(buf, info2->printername, sizeof(buf)-1);
4599 buf[sizeof(buf)-1] = 0;
4603 PACKS(desc,"B9",buf); /* szName */
4605 PACKS(desc,"B21",""); /* szUserName */
4606 PACKI(desc,"W",0); /* uJobId */
4607 PACKI(desc,"W",0); /* fsStatus */
4608 PACKS(desc,"z",""); /* pszStatus */
4609 PACKI(desc,"W",0); /* time */
4613 if (uLevel == 2 || uLevel == 3) {
4614 PACKS(desc,"z",buf); /* pszPrinterName */
4616 PACKS(desc,"z",""); /* pszUserName */
4617 PACKS(desc,"z",""); /* pszLogAddr */
4618 PACKI(desc,"W",0); /* uJobId */
4619 PACKI(desc,"W",0); /* fsStatus */
4620 PACKS(desc,"z",""); /* pszStatus */
4621 PACKS(desc,"z",""); /* pszComment */
4622 PACKS(desc,"z","NULL"); /* pszDrivers */
4623 PACKI(desc,"W",0); /* time */
4624 PACKI(desc,"W",0); /* pad1 */
4629 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4630 char *param, int tpscnt,
4631 char *data, int tdscnt,
4632 int mdrcnt,int mprcnt,
4633 char **rdata,char **rparam,
4634 int *rdata_len,int *rparam_len)
4636 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4637 char *str2 = skip_string(param,tpscnt,str1);
4638 char *p = skip_string(param,tpscnt,str2);
4639 char* PrinterName = p;
4641 struct pack_desc desc;
4644 TALLOC_CTX *mem_ctx = talloc_tos();
4647 struct rpc_pipe_client *cli = NULL;
4648 struct policy_handle handle;
4649 struct spoolss_DevmodeContainer devmode_ctr;
4650 union spoolss_PrinterInfo info;
4652 if (!str1 || !str2 || !p) {
4656 memset((char *)&desc,'\0',sizeof(desc));
4658 p = skip_string(param,tpscnt,p);
4662 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4664 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4666 /* check it's a supported varient */
4667 if (strcmp(str1,"zWrLh") != 0) {
4670 if (!check_printdest_info(&desc,uLevel,str2)) {
4674 ZERO_STRUCT(handle);
4676 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4677 rpc_spoolss_dispatch, conn->server_info,
4679 if (!NT_STATUS_IS_OK(status)) {
4680 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4681 nt_errstr(status)));
4682 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4686 ZERO_STRUCT(devmode_ctr);
4688 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4692 SEC_FLAG_MAXIMUM_ALLOWED,
4695 if (!NT_STATUS_IS_OK(status)) {
4697 desc.errcode = NERR_DestNotFound;
4701 if (!W_ERROR_IS_OK(werr)) {
4703 desc.errcode = NERR_DestNotFound;
4708 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4713 if (!W_ERROR_IS_OK(werr)) {
4715 desc.errcode = NERR_DestNotFound;
4721 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4726 desc.buflen = mdrcnt;
4729 * Don't return data but need to get correct length
4730 * init_package will return wrong size if buflen=0
4732 desc.buflen = getlen(desc.format);
4733 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4735 if (init_package(&desc,1,0)) {
4736 fill_printdest_info(&info.info2, uLevel,&desc);
4740 if (cli && is_valid_policy_hnd(&handle)) {
4741 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4744 *rdata_len = desc.usedlen;
4747 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4751 SSVALS(*rparam,0,desc.errcode);
4753 SSVAL(*rparam,4,desc.neededlen);
4755 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4761 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4762 char *param, int tpscnt,
4763 char *data, int tdscnt,
4764 int mdrcnt,int mprcnt,
4765 char **rdata,char **rparam,
4766 int *rdata_len,int *rparam_len)
4768 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4769 char *str2 = skip_string(param,tpscnt,str1);
4770 char *p = skip_string(param,tpscnt,str2);
4774 struct pack_desc desc;
4776 TALLOC_CTX *mem_ctx = talloc_tos();
4779 struct rpc_pipe_client *cli = NULL;
4780 union spoolss_PrinterInfo *info;
4783 if (!str1 || !str2 || !p) {
4787 memset((char *)&desc,'\0',sizeof(desc));
4789 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4791 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4793 /* check it's a supported varient */
4794 if (strcmp(str1,"WrLeh") != 0) {
4797 if (!check_printdest_info(&desc,uLevel,str2)) {
4803 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4804 rpc_spoolss_dispatch, conn->server_info,
4806 if (!NT_STATUS_IS_OK(status)) {
4807 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4808 nt_errstr(status)));
4809 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4813 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4815 cli->srv_name_slash,
4820 if (!W_ERROR_IS_OK(werr)) {
4821 desc.errcode = W_ERROR_V(werr);
4823 desc.errcode = NERR_DestNotFound;
4831 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4838 desc.buflen = mdrcnt;
4839 if (init_package(&desc,queuecnt,0)) {
4842 for (i = 0; i < count; i++) {
4843 fill_printdest_info(&info[i].info2, uLevel,&desc);
4845 if (desc.errcode == NERR_Success) {
4851 *rdata_len = desc.usedlen;
4854 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4858 SSVALS(*rparam,0,desc.errcode);
4860 SSVAL(*rparam,4,succnt);
4861 SSVAL(*rparam,6,queuecnt);
4863 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4868 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4869 char *param, int tpscnt,
4870 char *data, int tdscnt,
4871 int mdrcnt,int mprcnt,
4872 char **rdata,char **rparam,
4873 int *rdata_len,int *rparam_len)
4875 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4876 char *str2 = skip_string(param,tpscnt,str1);
4877 char *p = skip_string(param,tpscnt,str2);
4880 struct pack_desc desc;
4882 if (!str1 || !str2 || !p) {
4886 memset((char *)&desc,'\0',sizeof(desc));
4888 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4890 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4892 /* check it's a supported varient */
4893 if (strcmp(str1,"WrLeh") != 0) {
4896 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4901 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4907 desc.buflen = mdrcnt;
4908 if (init_package(&desc,1,0)) {
4909 PACKS(&desc,"B41","NULL");
4912 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4914 *rdata_len = desc.usedlen;
4917 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4921 SSVALS(*rparam,0,desc.errcode);
4923 SSVAL(*rparam,4,succnt);
4926 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4931 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4932 char *param, int tpscnt,
4933 char *data, int tdscnt,
4934 int mdrcnt,int mprcnt,
4935 char **rdata,char **rparam,
4936 int *rdata_len,int *rparam_len)
4938 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4939 char *str2 = skip_string(param,tpscnt,str1);
4940 char *p = skip_string(param,tpscnt,str2);
4943 struct pack_desc desc;
4945 if (!str1 || !str2 || !p) {
4948 memset((char *)&desc,'\0',sizeof(desc));
4950 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4952 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4954 /* check it's a supported varient */
4955 if (strcmp(str1,"WrLeh") != 0) {
4958 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4963 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4969 desc.buflen = mdrcnt;
4971 if (init_package(&desc,1,0)) {
4972 PACKS(&desc,"B13","lpd");
4975 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4977 *rdata_len = desc.usedlen;
4980 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4984 SSVALS(*rparam,0,desc.errcode);
4986 SSVAL(*rparam,4,succnt);
4989 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4994 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4995 char *param, int tpscnt,
4996 char *data, int tdscnt,
4997 int mdrcnt,int mprcnt,
4998 char **rdata,char **rparam,
4999 int *rdata_len,int *rparam_len)
5001 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5002 char *str2 = skip_string(param,tpscnt,str1);
5003 char *p = skip_string(param,tpscnt,str2);
5006 struct pack_desc desc;
5008 if (!str1 || !str2 || !p) {
5012 memset((char *)&desc,'\0',sizeof(desc));
5014 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5016 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5018 /* check it's a supported varient */
5019 if (strcmp(str1,"WrLeh") != 0) {
5022 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5027 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5032 memset((char *)&desc,'\0',sizeof(desc));
5034 desc.buflen = mdrcnt;
5036 if (init_package(&desc,1,0)) {
5037 PACKS(&desc,"B13","lp0");
5040 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5042 *rdata_len = desc.usedlen;
5045 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5049 SSVALS(*rparam,0,desc.errcode);
5051 SSVAL(*rparam,4,succnt);
5054 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5059 /****************************************************************************
5061 ****************************************************************************/
5063 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5064 char *param, int tpscnt,
5065 char *data, int tdscnt,
5066 int mdrcnt,int mprcnt,
5067 char **rdata,char **rparam,
5068 int *rdata_len,int *rparam_len)
5071 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5072 char *str2 = skip_string(param,tpscnt,str1);
5073 char *p = skip_string(param,tpscnt,str2);
5075 struct pack_desc desc;
5076 struct sessionid *session_list;
5077 int i, num_sessions;
5079 if (!str1 || !str2 || !p) {
5083 memset((char *)&desc,'\0',sizeof(desc));
5085 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5087 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5088 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5089 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5091 /* check it's a supported varient */
5092 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5095 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5099 num_sessions = list_sessions(talloc_tos(), &session_list);
5102 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5107 memset((char *)&desc,'\0',sizeof(desc));
5109 desc.buflen = mdrcnt;
5111 if (!init_package(&desc,num_sessions,0)) {
5115 for(i=0; i<num_sessions; i++) {
5116 PACKS(&desc, "z", session_list[i].remote_machine);
5117 PACKS(&desc, "z", session_list[i].username);
5118 PACKI(&desc, "W", 1); /* num conns */
5119 PACKI(&desc, "W", 0); /* num opens */
5120 PACKI(&desc, "W", 1); /* num users */
5121 PACKI(&desc, "D", 0); /* session time */
5122 PACKI(&desc, "D", 0); /* idle time */
5123 PACKI(&desc, "D", 0); /* flags */
5124 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5127 *rdata_len = desc.usedlen;
5130 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5134 SSVALS(*rparam,0,desc.errcode);
5135 SSVAL(*rparam,2,0); /* converter */
5136 SSVAL(*rparam,4,num_sessions); /* count */
5138 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5144 /****************************************************************************
5145 The buffer was too small.
5146 ****************************************************************************/
5148 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5149 int mdrcnt, int mprcnt,
5150 char **rdata, char **rparam,
5151 int *rdata_len, int *rparam_len)
5153 *rparam_len = MIN(*rparam_len,mprcnt);
5154 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5161 SSVAL(*rparam,0,NERR_BufTooSmall);
5163 DEBUG(3,("Supplied buffer too small in API command\n"));
5168 /****************************************************************************
5169 The request is not supported.
5170 ****************************************************************************/
5172 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5173 char *param, int tpscnt,
5174 char *data, int tdscnt,
5175 int mdrcnt, int mprcnt,
5176 char **rdata, char **rparam,
5177 int *rdata_len, int *rparam_len)
5180 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5187 SSVAL(*rparam,0,NERR_notsupported);
5188 SSVAL(*rparam,2,0); /* converter word */
5190 DEBUG(3,("Unsupported API command\n"));
5195 static const struct {
5198 bool (*fn)(connection_struct *, uint16,
5201 int,int,char **,char **,int *,int *);
5202 bool auth_user; /* Deny anonymous access? */
5203 } api_commands[] = {
5204 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5205 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5206 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5207 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5208 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5209 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5210 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5211 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5212 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5213 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5214 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5215 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5216 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5217 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5218 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5219 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5220 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5221 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5222 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5223 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5224 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5225 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5226 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5227 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5228 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5229 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5230 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5231 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5232 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5233 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5234 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5235 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5236 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5237 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5238 {NULL, -1, api_Unsupported}
5239 /* The following RAP calls are not implemented by Samba:
5241 RAP_WFileEnum2 - anon not OK
5246 /****************************************************************************
5247 Handle remote api calls.
5248 ****************************************************************************/
5250 void api_reply(connection_struct *conn, uint16 vuid,
5251 struct smb_request *req,
5252 char *data, char *params,
5253 int tdscnt, int tpscnt,
5254 int mdrcnt, int mprcnt)
5256 struct smbd_server_connection *sconn = smbd_server_conn;
5259 char *rparam = NULL;
5260 const char *name1 = NULL;
5261 const char *name2 = NULL;
5268 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5269 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5274 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5277 api_command = SVAL(params,0);
5278 /* Is there a string at position params+2 ? */
5279 if (skip_string(params,tpscnt,params+2)) {
5284 name2 = skip_string(params,tpscnt,params+2);
5289 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5293 tdscnt,tpscnt,mdrcnt,mprcnt));
5295 for (i=0;api_commands[i].name;i++) {
5296 if (api_commands[i].id == api_command && api_commands[i].fn) {
5297 DEBUG(3,("Doing %s\n",api_commands[i].name));
5302 /* Check whether this api call can be done anonymously */
5304 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5305 user_struct *user = get_valid_user_struct(sconn, vuid);
5307 if (!user || user->server_info->guest) {
5308 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5313 rdata = (char *)SMB_MALLOC(1024);
5315 memset(rdata,'\0',1024);
5318 rparam = (char *)SMB_MALLOC(1024);
5320 memset(rparam,'\0',1024);
5323 if(!rdata || !rparam) {
5324 DEBUG(0,("api_reply: malloc fail !\n"));
5327 reply_nterror(req, NT_STATUS_NO_MEMORY);
5331 reply = api_commands[i].fn(conn,
5333 params,tpscnt, /* params + length */
5334 data,tdscnt, /* data + length */
5336 &rdata,&rparam,&rdata_len,&rparam_len);
5339 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5340 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5341 &rdata,&rparam,&rdata_len,&rparam_len);
5344 /* if we get False back then it's actually unsupported */
5346 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5347 &rdata,&rparam,&rdata_len,&rparam_len);
5350 /* If api_Unsupported returns false we can't return anything. */
5352 send_trans_reply(conn, req, rparam, rparam_len,
5353 rdata, rdata_len, False);