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/srv_samr.h"
33 #include "../librpc/gen_ndr/srv_spoolss.h"
34 #include "../librpc/gen_ndr/rap.h"
35 #include "../lib/util/binsearch.h"
42 #define NERR_Success 0
43 #define NERR_badpass 86
44 #define NERR_notsupported 50
46 #define NERR_BASE (2100)
47 #define NERR_BufTooSmall (NERR_BASE+23)
48 #define NERR_JobNotFound (NERR_BASE+51)
49 #define NERR_DestNotFound (NERR_BASE+52)
51 #define ACCESS_READ 0x01
52 #define ACCESS_WRITE 0x02
53 #define ACCESS_CREATE 0x04
55 #define SHPWLEN 8 /* share password length */
57 /* Limit size of ipc replies */
59 static char *smb_realloc_limit(void *ptr, size_t size)
63 size = MAX((size),4*1024);
64 val = (char *)SMB_REALLOC(ptr,size);
66 memset(val,'\0',size);
71 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
72 char *param, int tpscnt,
73 char *data, int tdscnt,
74 int mdrcnt, int mprcnt,
75 char **rdata, char **rparam,
76 int *rdata_len, int *rparam_len);
78 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
79 int mdrcnt, int mprcnt,
80 char **rdata, char **rparam,
81 int *rdata_len, int *rparam_len);
84 static int CopyExpanded(connection_struct *conn,
85 int snum, char **dst, char *src, int *p_space_remaining)
87 TALLOC_CTX *ctx = talloc_tos();
91 if (!src || !dst || !p_space_remaining || !(*dst) ||
92 *p_space_remaining <= 0) {
96 buf = talloc_strdup(ctx, src);
98 *p_space_remaining = 0;
101 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
103 *p_space_remaining = 0;
106 buf = talloc_sub_advanced(ctx,
107 lp_servicename(SNUM(conn)),
108 conn->server_info->unix_name,
110 conn->server_info->utok.gid,
111 conn->server_info->sanitized_username,
112 pdb_get_domain(conn->server_info->sam_account),
115 *p_space_remaining = 0;
118 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
123 (*p_space_remaining) -= l;
127 static int CopyAndAdvance(char **dst, char *src, int *n)
130 if (!src || !dst || !n || !(*dst)) {
133 l = push_ascii(*dst,src,*n, STR_TERMINATE);
142 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
144 TALLOC_CTX *ctx = talloc_tos();
149 buf = talloc_strdup(ctx,s);
153 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
157 buf = talloc_sub_advanced(ctx,
158 lp_servicename(SNUM(conn)),
159 conn->server_info->unix_name,
161 conn->server_info->utok.gid,
162 conn->server_info->sanitized_username,
163 pdb_get_domain(conn->server_info->sam_account),
168 return strlen(buf) + 1;
171 /*******************************************************************
172 Check a API string for validity when we only need to check the prefix.
173 ******************************************************************/
175 static bool prefix_ok(const char *str, const char *prefix)
177 return(strncmp(str,prefix,strlen(prefix)) == 0);
181 const char *format; /* formatstring for structure */
182 const char *subformat; /* subformat for structure */
183 char *base; /* baseaddress of buffer */
184 int buflen; /* remaining size for fixed part; on init: length of base */
185 int subcount; /* count of substructures */
186 char *structbuf; /* pointer into buffer for remaining fixed part */
187 int stringlen; /* remaining size for variable part */
188 char *stringbuf; /* pointer into buffer for remaining variable part */
189 int neededlen; /* total needed size */
190 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
191 const char *curpos; /* current position; pointer into format or subformat */
195 static int get_counter(const char **p)
201 if (!isdigit((int)**p)) {
207 n = 10 * n + (i - '0');
215 static int getlen(const char *p)
224 case 'W': /* word (2 byte) */
227 case 'K': /* status word? (2 byte) */
230 case 'N': /* count of substructures (word) at end */
233 case 'D': /* double word (4 byte) */
234 case 'z': /* offset to zero terminated string (4 byte) */
235 case 'l': /* offset to user data (4 byte) */
238 case 'b': /* offset to data (with counter) (4 byte) */
242 case 'B': /* byte (with optional counter) */
243 n += get_counter(&p);
250 static bool init_package(struct pack_desc *p, int count, int subcount)
255 if (!p->format || !p->base) {
259 i = count * getlen(p->format);
261 i += subcount * getlen(p->subformat);
263 p->structbuf = p->base;
267 p->curpos = p->format;
273 * This is the old error code we used. Aparently
274 * WinNT/2k systems return ERRbuftoosmall (2123) and
275 * OS/2 needs this. I'm leaving this here so we can revert
278 p->errcode = ERRmoredata;
280 p->errcode = ERRbuftoosmall;
283 p->errcode = NERR_Success;
287 p->stringbuf = p->base + i;
289 return (p->errcode == NERR_Success);
292 static int package(struct pack_desc *p, ...)
295 int needed=0, stringneeded;
296 const char *str=NULL;
297 int is_string=0, stringused;
304 p->curpos = p->format;
306 p->curpos = p->subformat;
311 str = va_arg(args,char*);
312 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
321 switch( *p->curpos++ ) {
322 case 'W': /* word (2 byte) */
324 temp = va_arg(args,int);
325 if (p->buflen >= needed) {
326 SSVAL(p->structbuf,0,temp);
329 case 'K': /* status word? (2 byte) */
331 temp = va_arg(args,int);
332 if (p->buflen >= needed) {
333 SSVAL(p->structbuf,0,temp);
336 case 'N': /* count of substructures (word) at end */
338 p->subcount = va_arg(args,int);
339 if (p->buflen >= needed) {
340 SSVAL(p->structbuf,0,p->subcount);
343 case 'D': /* double word (4 byte) */
345 temp = va_arg(args,int);
346 if (p->buflen >= needed) {
347 SIVAL(p->structbuf,0,temp);
350 case 'B': /* byte (with optional counter) */
351 needed = get_counter(&p->curpos);
353 char *s = va_arg(args,char*);
354 if (p->buflen >= needed) {
355 StrnCpy(p->structbuf,s?s:"",needed-1);
359 case 'z': /* offset to zero terminated string (4 byte) */
360 str = va_arg(args,char*);
361 stringneeded = (str ? strlen(str)+1 : 0);
364 case 'l': /* offset to user data (4 byte) */
365 str = va_arg(args,char*);
366 stringneeded = va_arg(args,int);
369 case 'b': /* offset to data (with counter) (4 byte) */
370 str = va_arg(args,char*);
371 stringneeded = get_counter(&p->curpos);
377 if (stringneeded >= 0) {
379 if (p->buflen >= needed) {
380 stringused = stringneeded;
381 if (stringused > p->stringlen) {
382 stringused = (is_string ? p->stringlen : 0);
383 if (p->errcode == NERR_Success) {
384 p->errcode = ERRmoredata;
388 SIVAL(p->structbuf,0,0);
390 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
391 memcpy(p->stringbuf,str?str:"",stringused);
393 p->stringbuf[stringused-1] = '\0';
395 p->stringbuf += stringused;
396 p->stringlen -= stringused;
397 p->usedlen += stringused;
400 p->neededlen += stringneeded;
403 p->neededlen += needed;
404 if (p->buflen >= needed) {
405 p->structbuf += needed;
407 p->usedlen += needed;
409 if (p->errcode == NERR_Success) {
410 p->errcode = ERRmoredata;
417 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
418 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
420 #define PACK(desc,t,v) package(desc,v)
421 #define PACKl(desc,t,v,l) package(desc,v,l)
424 static void PACKI(struct pack_desc* desc, const char *t,int v)
429 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
434 /****************************************************************************
436 ****************************************************************************/
438 static void PackDriverData(struct pack_desc* desc)
440 char drivdata[4+4+32];
441 SIVAL(drivdata,0,sizeof drivdata); /* cb */
442 SIVAL(drivdata,4,1000); /* lVersion */
443 memset(drivdata+8,0,32); /* szDeviceName */
444 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
445 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
448 static int check_printq_info(struct pack_desc* desc,
449 unsigned int uLevel, char *id1, char *id2)
451 desc->subformat = NULL;
454 desc->format = "B13";
457 desc->format = "B13BWWWzzzzzWW";
460 desc->format = "B13BWWWzzzzzWN";
461 desc->subformat = "WB21BB16B10zWWzDDz";
464 desc->format = "zWWWWzzzzWWzzl";
467 desc->format = "zWWWWzzzzWNzzl";
468 desc->subformat = "WWzWWDDzz";
477 desc->format = "WzzzzzzzzN";
478 desc->subformat = "z";
481 DEBUG(0,("check_printq_info: invalid level %d\n",
485 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
486 DEBUG(0,("check_printq_info: invalid format %s\n",
487 id1 ? id1 : "<NULL>" ));
490 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
491 DEBUG(0,("check_printq_info: invalid subformat %s\n",
492 id2 ? id2 : "<NULL>" ));
499 #define RAP_JOB_STATUS_QUEUED 0
500 #define RAP_JOB_STATUS_PAUSED 1
501 #define RAP_JOB_STATUS_SPOOLING 2
502 #define RAP_JOB_STATUS_PRINTING 3
503 #define RAP_JOB_STATUS_PRINTED 4
505 #define RAP_QUEUE_STATUS_PAUSED 1
506 #define RAP_QUEUE_STATUS_ERROR 2
508 /* turn a print job status into a on the wire status
510 static int printj_spoolss_status(int v)
512 if (v == JOB_STATUS_QUEUED)
513 return RAP_JOB_STATUS_QUEUED;
514 if (v & JOB_STATUS_PAUSED)
515 return RAP_JOB_STATUS_PAUSED;
516 if (v & JOB_STATUS_SPOOLING)
517 return RAP_JOB_STATUS_SPOOLING;
518 if (v & JOB_STATUS_PRINTING)
519 return RAP_JOB_STATUS_PRINTING;
523 /* turn a print queue status into a on the wire status
525 static int printq_spoolss_status(int v)
527 if (v == PRINTER_STATUS_OK)
529 if (v & PRINTER_STATUS_PAUSED)
530 return RAP_QUEUE_STATUS_PAUSED;
531 return RAP_QUEUE_STATUS_ERROR;
534 static time_t spoolss_Time_to_time_t(const struct spoolss_Time *r)
538 unixtime.tm_year = r->year - 1900;
539 unixtime.tm_mon = r->month - 1;
540 unixtime.tm_wday = r->day_of_week;
541 unixtime.tm_mday = r->day;
542 unixtime.tm_hour = r->hour;
543 unixtime.tm_min = r->minute;
544 unixtime.tm_sec = r->second;
546 return mktime(&unixtime);
549 static void fill_spoolss_printjob_info(int uLevel,
550 struct pack_desc *desc,
551 struct spoolss_JobInfo2 *info2,
554 time_t t = spoolss_Time_to_time_t(&info2->submitted);
556 /* the client expects localtime */
557 t -= get_time_zone(t);
559 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
561 PACKS(desc,"B21", info2->user_name); /* szUserName */
562 PACKS(desc,"B",""); /* pad */
563 PACKS(desc,"B16",""); /* szNotifyName */
564 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
565 PACKS(desc,"z",""); /* pszParms */
566 PACKI(desc,"W",n+1); /* uPosition */
567 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
568 PACKS(desc,"z",""); /* pszStatus */
569 PACKI(desc,"D", t); /* ulSubmitted */
570 PACKI(desc,"D", info2->size); /* ulSize */
571 PACKS(desc,"z", info2->document_name); /* pszComment */
573 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
574 PACKI(desc,"W", info2->priority); /* uPriority */
575 PACKS(desc,"z", info2->user_name); /* pszUserName */
576 PACKI(desc,"W",n+1); /* uPosition */
577 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
578 PACKI(desc,"D",t); /* ulSubmitted */
579 PACKI(desc,"D", info2->size); /* ulSize */
580 PACKS(desc,"z","Samba"); /* pszComment */
581 PACKS(desc,"z", info2->document_name); /* pszDocument */
583 PACKS(desc,"z",""); /* pszNotifyName */
584 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
585 PACKS(desc,"z",""); /* pszParms */
586 PACKS(desc,"z",""); /* pszStatus */
587 PACKS(desc,"z", info2->printer_name); /* pszQueue */
588 PACKS(desc,"z","lpd"); /* pszQProcName */
589 PACKS(desc,"z",""); /* pszQProcParms */
590 PACKS(desc,"z","NULL"); /* pszDriverName */
591 PackDriverData(desc); /* pDriverData */
592 PACKS(desc,"z",""); /* pszPrinterName */
593 } else if (uLevel == 4) { /* OS2 */
594 PACKS(desc,"z",""); /* pszSpoolFileName */
595 PACKS(desc,"z",""); /* pszPortName */
596 PACKS(desc,"z",""); /* pszStatus */
597 PACKI(desc,"D",0); /* ulPagesSpooled */
598 PACKI(desc,"D",0); /* ulPagesSent */
599 PACKI(desc,"D",0); /* ulPagesPrinted */
600 PACKI(desc,"D",0); /* ulTimePrinted */
601 PACKI(desc,"D",0); /* ulExtendJobStatus */
602 PACKI(desc,"D",0); /* ulStartPage */
603 PACKI(desc,"D",0); /* ulEndPage */
608 /********************************************************************
609 Respond to the DosPrintQInfo command with a level of 52
610 This is used to get printer driver information for Win9x clients
611 ********************************************************************/
612 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
613 struct pack_desc* desc, int count,
614 const char *printer_name)
618 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
619 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
620 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
622 PACKI(desc, "W", 0x0400); /* don't know */
623 PACKS(desc, "z", driver->driver_name); /* long printer name */
624 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
625 PACKS(desc, "z", driver->data_file); /* Datafile name */
626 PACKS(desc, "z", driver->monitor_name); /* language monitor */
628 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
629 standard_sub_basic( "", "", location, sizeof(location)-1 );
630 PACKS(desc,"z", location); /* share to retrieve files */
632 PACKS(desc,"z", driver->default_datatype); /* default data type */
633 PACKS(desc,"z", driver->help_file); /* helpfile name */
634 PACKS(desc,"z", driver->driver_path); /* driver name */
636 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
637 DEBUG(3,("Driver: %s:\n",driver->driver_path));
638 DEBUG(3,("Data File: %s:\n",driver->data_file));
639 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
640 DEBUG(3,("Driver Location: %s:\n",location));
641 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
642 DEBUG(3,("Help File: %s:\n",driver->help_file));
643 PACKI(desc,"N",count); /* number of files to copy */
645 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
647 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
648 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
649 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
654 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
657 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
659 desc->errcode=NERR_Success;
663 static const char *strip_unc(const char *unc)
671 if ((p = strrchr(unc, '\\')) != NULL) {
678 static void fill_printq_info(int uLevel,
679 struct pack_desc* desc,
681 union spoolss_JobInfo *job_info,
682 struct spoolss_DriverInfo3 *driver_info,
683 struct spoolss_PrinterInfo2 *printer_info)
689 PACKS(desc,"B13", strip_unc(printer_info->printername));
694 PACKS(desc,"z", strip_unc(printer_info->printername));
697 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
701 if (uLevel == 1 || uLevel == 2) {
702 PACKS(desc,"B",""); /* alignment */
703 PACKI(desc,"W",5); /* priority */
704 PACKI(desc,"W",0); /* start time */
705 PACKI(desc,"W",0); /* until time */
706 PACKS(desc,"z",""); /* pSepFile */
707 PACKS(desc,"z","lpd"); /* pPrProc */
708 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
709 PACKS(desc,"z",""); /* pParms */
710 if (printer_info->printername == NULL) {
711 PACKS(desc,"z","UNKNOWN PRINTER");
712 PACKI(desc,"W",LPSTAT_ERROR);
714 PACKS(desc,"z", printer_info->comment);
715 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
717 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
720 if (uLevel == 3 || uLevel == 4) {
721 PACKI(desc,"W",5); /* uPriority */
722 PACKI(desc,"W",0); /* uStarttime */
723 PACKI(desc,"W",0); /* uUntiltime */
724 PACKI(desc,"W",5); /* pad1 */
725 PACKS(desc,"z",""); /* pszSepFile */
726 PACKS(desc,"z","WinPrint"); /* pszPrProc */
727 PACKS(desc,"z",NULL); /* pszParms */
728 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
729 /* "don't ask" that it's done this way to fix corrupted
730 Win9X/ME printer comments. */
731 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
732 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
733 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
734 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
735 PackDriverData(desc); /* pDriverData */
738 if (uLevel == 2 || uLevel == 4) {
740 for (i = 0; i < count; i++) {
741 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
746 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
749 /* This function returns the number of files for a given driver */
750 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
754 /* count the number of files */
755 while (driver->dependent_files && *driver->dependent_files[result])
761 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
762 char *param, int tpscnt,
763 char *data, int tdscnt,
764 int mdrcnt,int mprcnt,
765 char **rdata,char **rparam,
766 int *rdata_len,int *rparam_len)
768 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
769 char *str2 = skip_string(param,tpscnt,str1);
770 char *p = skip_string(param,tpscnt,str2);
775 struct pack_desc desc;
778 WERROR werr = WERR_OK;
779 TALLOC_CTX *mem_ctx = talloc_tos();
781 struct rpc_pipe_client *cli = NULL;
782 struct policy_handle handle;
783 struct spoolss_DevmodeContainer devmode_ctr;
784 union spoolss_DriverInfo driver_info;
785 union spoolss_JobInfo *job_info;
786 union spoolss_PrinterInfo printer_info;
788 if (!str1 || !str2 || !p) {
791 memset((char *)&desc,'\0',sizeof(desc));
793 p = skip_string(param,tpscnt,p);
797 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
798 str3 = get_safe_str_ptr(param,tpscnt,p,4);
799 /* str3 may be null here and is checked in check_printq_info(). */
801 /* remove any trailing username */
802 if ((p = strchr_m(QueueName,'%')))
805 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
807 /* check it's a supported varient */
808 if (!prefix_ok(str1,"zWrLh"))
810 if (!check_printq_info(&desc,uLevel,str2,str3)) {
812 * Patch from Scott Moomaw <scott@bridgewater.edu>
813 * to return the 'invalid info level' error if an
814 * unknown level was requested.
818 *rparam = smb_realloc_limit(*rparam,*rparam_len);
822 SSVALS(*rparam,0,ERRunknownlevel);
830 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
831 rpc_spoolss_dispatch, conn->server_info,
833 if (!NT_STATUS_IS_OK(status)) {
834 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
836 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
840 ZERO_STRUCT(devmode_ctr);
842 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
846 SEC_FLAG_MAXIMUM_ALLOWED,
849 if (!NT_STATUS_IS_OK(status)) {
850 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
853 if (!W_ERROR_IS_OK(werr)) {
854 desc.errcode = W_ERROR_V(werr);
858 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
863 if (!W_ERROR_IS_OK(werr)) {
864 desc.errcode = W_ERROR_V(werr);
869 uint32_t server_major_version;
870 uint32_t server_minor_version;
872 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
880 &server_major_version,
881 &server_minor_version);
882 if (!W_ERROR_IS_OK(werr)) {
883 desc.errcode = W_ERROR_V(werr);
887 count = get_printerdrivernumber(&driver_info.info3);
888 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
891 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
899 if (!W_ERROR_IS_OK(werr)) {
900 desc.errcode = W_ERROR_V(werr);
908 *rdata = smb_realloc_limit(*rdata,mdrcnt);
913 desc.buflen = mdrcnt;
916 * Don't return data but need to get correct length
917 * init_package will return wrong size if buflen=0
919 desc.buflen = getlen(desc.format);
920 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
923 if (init_package(&desc,1,count)) {
924 desc.subcount = count;
925 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
928 *rdata_len = desc.usedlen;
931 * We must set the return code to ERRbuftoosmall
932 * in order to support lanman style printing with Win NT/2k
935 if (!mdrcnt && lp_disable_spoolss())
936 desc.errcode = ERRbuftoosmall;
939 if (cli && is_valid_policy_hnd(&handle)) {
940 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
943 *rdata_len = desc.usedlen;
945 *rparam = smb_realloc_limit(*rparam,*rparam_len);
950 SSVALS(*rparam,0,desc.errcode);
952 SSVAL(*rparam,4,desc.neededlen);
954 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
961 /****************************************************************************
962 View list of all print jobs on all queues.
963 ****************************************************************************/
965 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
966 char *param, int tpscnt,
967 char *data, int tdscnt,
968 int mdrcnt, int mprcnt,
969 char **rdata, char** rparam,
970 int *rdata_len, int *rparam_len)
972 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
973 char *output_format1 = skip_string(param,tpscnt,param_format);
974 char *p = skip_string(param,tpscnt,output_format1);
975 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
976 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
978 struct pack_desc desc;
979 int *subcntarr = NULL;
980 int queuecnt = 0, subcnt = 0, succnt = 0;
982 WERROR werr = WERR_OK;
983 TALLOC_CTX *mem_ctx = talloc_tos();
985 struct rpc_pipe_client *cli = NULL;
986 struct spoolss_DevmodeContainer devmode_ctr;
987 uint32_t num_printers;
988 union spoolss_PrinterInfo *printer_info;
989 union spoolss_DriverInfo *driver_info;
990 union spoolss_JobInfo **job_info;
992 if (!param_format || !output_format1 || !p) {
996 memset((char *)&desc,'\0',sizeof(desc));
998 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1000 if (!prefix_ok(param_format,"WrLeh")) {
1003 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1005 * Patch from Scott Moomaw <scott@bridgewater.edu>
1006 * to return the 'invalid info level' error if an
1007 * unknown level was requested.
1011 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1015 SSVALS(*rparam,0,ERRunknownlevel);
1021 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1022 rpc_spoolss_dispatch, conn->server_info,
1024 if (!NT_STATUS_IS_OK(status)) {
1025 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1026 nt_errstr(status)));
1027 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1031 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1033 cli->srv_name_slash,
1038 if (!W_ERROR_IS_OK(werr)) {
1039 desc.errcode = W_ERROR_V(werr);
1043 queuecnt = num_printers;
1045 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1046 if (job_info == NULL) {
1050 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1051 if (driver_info == NULL) {
1055 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1056 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1061 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1067 desc.buflen = mdrcnt;
1070 for (i = 0; i < num_printers; i++) {
1073 struct policy_handle handle;
1074 const char *printername;
1076 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1077 if (printername == NULL) {
1081 ZERO_STRUCT(handle);
1082 ZERO_STRUCT(devmode_ctr);
1084 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1088 SEC_FLAG_MAXIMUM_ALLOWED,
1091 if (!NT_STATUS_IS_OK(status)) {
1092 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1095 if (!W_ERROR_IS_OK(werr)) {
1096 desc.errcode = W_ERROR_V(werr);
1100 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1108 if (!W_ERROR_IS_OK(werr)) {
1109 desc.errcode = W_ERROR_V(werr);
1114 uint32_t server_major_version;
1115 uint32_t server_minor_version;
1117 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1125 &server_major_version,
1126 &server_minor_version);
1127 if (!W_ERROR_IS_OK(werr)) {
1128 desc.errcode = W_ERROR_V(werr);
1133 subcntarr[i] = num_jobs;
1134 subcnt += subcntarr[i];
1136 if (cli && is_valid_policy_hnd(&handle)) {
1137 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1141 if (init_package(&desc,queuecnt,subcnt)) {
1142 for (i = 0; i < num_printers; i++) {
1143 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1144 if (desc.errcode == NERR_Success) {
1150 SAFE_FREE(subcntarr);
1152 *rdata_len = desc.usedlen;
1154 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1158 SSVALS(*rparam,0,desc.errcode);
1160 SSVAL(*rparam,4,succnt);
1161 SSVAL(*rparam,6,queuecnt);
1167 SAFE_FREE(subcntarr);
1172 /****************************************************************************
1173 Get info level for a server list query.
1174 ****************************************************************************/
1176 static bool check_server_info(int uLevel, char* id)
1180 if (strcmp(id,"B16") != 0) {
1185 if (strcmp(id,"B16BBDz") != 0) {
1195 struct srv_info_struct {
1203 /*******************************************************************
1204 Get server info lists from the files saved by nmbd. Return the
1206 ******************************************************************/
1208 static int get_server_info(uint32 servertype,
1209 struct srv_info_struct **servers,
1215 bool local_list_only;
1218 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1220 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1224 /* request for everything is code for request all servers */
1225 if (servertype == SV_TYPE_ALL) {
1226 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1229 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1231 DEBUG(4,("Servertype search: %8x\n",servertype));
1233 for (i=0;lines[i];i++) {
1235 struct srv_info_struct *s;
1236 const char *ptr = lines[i];
1238 TALLOC_CTX *frame = NULL;
1245 if (count == alloced) {
1247 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1249 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1253 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1255 s = &(*servers)[count];
1257 frame = talloc_stackframe();
1259 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1263 fstrcpy(s->name, p);
1266 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1272 s->comment[0] = '\0';
1273 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1277 fstrcpy(s->comment, p);
1278 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1280 s->domain[0] = '\0';
1281 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1282 /* this allows us to cope with an old nmbd */
1283 fstrcpy(s->domain,lp_workgroup());
1285 fstrcpy(s->domain, p);
1289 if (sscanf(stype,"%X",&s->type) != 1) {
1290 DEBUG(4,("r:host file "));
1294 /* Filter the servers/domains we return based on what was asked for. */
1296 /* Check to see if we are being asked for a local list only. */
1297 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1298 DEBUG(4,("r: local list only"));
1302 /* doesn't match up: don't want it */
1303 if (!(servertype & s->type)) {
1304 DEBUG(4,("r:serv type "));
1308 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1309 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1310 DEBUG(4,("s: dom mismatch "));
1314 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1318 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1319 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1322 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1323 s->name, s->type, s->comment, s->domain));
1324 s->server_added = True;
1327 DEBUG(4,("%20s %8x %25s %15s\n",
1328 s->name, s->type, s->comment, s->domain));
1336 /*******************************************************************
1337 Fill in a server info structure.
1338 ******************************************************************/
1340 static int fill_srv_info(struct srv_info_struct *service,
1341 int uLevel, char **buf, int *buflen,
1342 char **stringbuf, int *stringspace, char *baseaddr)
1365 len = strlen(service->comment)+1;
1369 *buflen = struct_len;
1371 return struct_len + len;
1376 if (*buflen < struct_len) {
1383 p2 = p + struct_len;
1384 l2 = *buflen - struct_len;
1392 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1396 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1397 SIVAL(p,18,service->type);
1398 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1399 len += CopyAndAdvance(&p2,service->comment,&l2);
1404 *buf = p + struct_len;
1405 *buflen -= struct_len;
1416 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1418 return StrCaseCmp(s1->name,s2->name);
1421 /****************************************************************************
1422 View list of servers available (or possibly domains). The info is
1423 extracted from lists saved by nmbd on the local host.
1424 ****************************************************************************/
1426 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1427 char *param, int tpscnt,
1428 char *data, int tdscnt,
1429 int mdrcnt, int mprcnt, char **rdata,
1430 char **rparam, int *rdata_len, int *rparam_len)
1432 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1433 char *str2 = skip_string(param,tpscnt,str1);
1434 char *p = skip_string(param,tpscnt,str2);
1435 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1436 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1437 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1439 int data_len, fixed_len, string_len;
1440 int f_len = 0, s_len = 0;
1441 struct srv_info_struct *servers=NULL;
1442 int counted=0,total=0;
1445 bool domain_request;
1448 if (!str1 || !str2 || !p) {
1452 /* If someone sets all the bits they don't really mean to set
1453 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1456 if (servertype == SV_TYPE_ALL) {
1457 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1460 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1461 any other bit (they may just set this bit on its own) they
1462 want all the locally seen servers. However this bit can be
1463 set on its own so set the requested servers to be
1464 ALL - DOMAIN_ENUM. */
1466 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1467 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1470 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1471 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1475 if (!prefix_ok(str1,"WrLehD")) {
1478 if (!check_server_info(uLevel,str2)) {
1482 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1483 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1484 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1486 if (strcmp(str1, "WrLehDz") == 0) {
1487 if (skip_string(param,tpscnt,p) == NULL) {
1490 pull_ascii_fstring(domain, p);
1492 fstrcpy(domain, lp_workgroup());
1495 DEBUG(4, ("domain [%s]\n", domain));
1497 if (lp_browse_list()) {
1498 total = get_server_info(servertype,&servers,domain);
1501 data_len = fixed_len = string_len = 0;
1504 TYPESAFE_QSORT(servers, total, srv_comp);
1507 char *lastname=NULL;
1509 for (i=0;i<total;i++) {
1510 struct srv_info_struct *s = &servers[i];
1512 if (lastname && strequal(lastname,s->name)) {
1516 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1517 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1518 i, s->name, s->type, s->comment, s->domain));
1520 if (data_len < buf_len) {
1523 string_len += s_len;
1530 *rdata_len = fixed_len + string_len;
1531 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1536 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1542 char *lastname=NULL;
1543 int count2 = counted;
1545 for (i = 0; i < total && count2;i++) {
1546 struct srv_info_struct *s = &servers[i];
1548 if (lastname && strequal(lastname,s->name)) {
1552 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1553 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1554 i, s->name, s->type, s->comment, s->domain));
1560 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1564 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1566 SSVAL(*rparam,4,counted);
1567 SSVAL(*rparam,6,counted+missed);
1571 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1572 domain,uLevel,counted,counted+missed));
1577 static int srv_name_match(const char *n1, const char *n2)
1580 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1582 * In Windows, FirstNameToReturn need not be an exact match:
1583 * the server will return a list of servers that exist on
1584 * the network greater than or equal to the FirstNameToReturn.
1586 int ret = StrCaseCmp(n1, n2);
1595 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1596 char *param, int tpscnt,
1597 char *data, int tdscnt,
1598 int mdrcnt, int mprcnt, char **rdata,
1599 char **rparam, int *rdata_len, int *rparam_len)
1601 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1602 char *str2 = skip_string(param,tpscnt,str1);
1603 char *p = skip_string(param,tpscnt,str2);
1604 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1605 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1606 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1608 int data_len, fixed_len, string_len;
1609 int f_len = 0, s_len = 0;
1610 struct srv_info_struct *servers=NULL;
1611 int counted=0,first=0,total=0;
1615 bool domain_request;
1618 if (!str1 || !str2 || !p) {
1622 /* If someone sets all the bits they don't really mean to set
1623 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1626 if (servertype == SV_TYPE_ALL) {
1627 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1630 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1631 any other bit (they may just set this bit on its own) they
1632 want all the locally seen servers. However this bit can be
1633 set on its own so set the requested servers to be
1634 ALL - DOMAIN_ENUM. */
1636 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1637 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1640 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1641 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1645 if (strcmp(str1, "WrLehDzz") != 0) {
1648 if (!check_server_info(uLevel,str2)) {
1652 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1653 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1654 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1656 if (skip_string(param,tpscnt,p) == NULL) {
1659 pull_ascii_fstring(domain, p);
1660 if (domain[0] == '\0') {
1661 fstrcpy(domain, lp_workgroup());
1663 p = skip_string(param,tpscnt,p);
1664 if (skip_string(param,tpscnt,p) == NULL) {
1667 pull_ascii_fstring(first_name, p);
1669 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1670 domain, first_name));
1672 if (lp_browse_list()) {
1673 total = get_server_info(servertype,&servers,domain);
1676 data_len = fixed_len = string_len = 0;
1679 TYPESAFE_QSORT(servers, total, srv_comp);
1681 if (first_name[0] != '\0') {
1682 struct srv_info_struct *first_server = NULL;
1684 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1685 srv_name_match, first_server);
1687 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1689 * The binary search may not find the exact match
1690 * so we need to search backward to find the first match
1692 * This implements the strange matching windows
1693 * implements. (see the comment in srv_name_match().
1697 ret = StrCaseCmp(first_name,
1698 servers[first-1].name);
1705 /* we should return no entries */
1711 char *lastname=NULL;
1713 for (i=first;i<total;i++) {
1714 struct srv_info_struct *s = &servers[i];
1716 if (lastname && strequal(lastname,s->name)) {
1720 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1721 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1722 i, s->name, s->type, s->comment, s->domain));
1724 if (data_len < buf_len) {
1727 string_len += s_len;
1734 *rdata_len = fixed_len + string_len;
1735 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1740 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1746 char *lastname=NULL;
1747 int count2 = counted;
1749 for (i = first; i < total && count2;i++) {
1750 struct srv_info_struct *s = &servers[i];
1752 if (lastname && strequal(lastname,s->name)) {
1756 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1757 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1758 i, s->name, s->type, s->comment, s->domain));
1764 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1768 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1770 SSVAL(*rparam,4,counted);
1771 SSVAL(*rparam,6,counted+missed);
1773 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1774 domain,uLevel,first,first_name,
1775 first < total ? servers[first].name : "",
1776 counted,counted+missed));
1783 /****************************************************************************
1784 command 0x34 - suspected of being a "Lookup Names" stub api
1785 ****************************************************************************/
1787 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1788 char *param, int tpscnt,
1789 char *data, int tdscnt,
1790 int mdrcnt, int mprcnt, char **rdata,
1791 char **rparam, int *rdata_len, int *rparam_len)
1793 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1794 char *str2 = skip_string(param,tpscnt,str1);
1795 char *p = skip_string(param,tpscnt,str2);
1796 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1797 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1801 if (!str1 || !str2 || !p) {
1805 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1806 str1, str2, p, uLevel, buf_len));
1808 if (!prefix_ok(str1,"zWrLeh")) {
1815 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1820 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1822 SSVAL(*rparam,4,counted);
1823 SSVAL(*rparam,6,counted+missed);
1828 /****************************************************************************
1829 get info about a share
1830 ****************************************************************************/
1832 static bool check_share_info(int uLevel, char* id)
1836 if (strcmp(id,"B13") != 0) {
1841 /* Level-2 descriptor is allowed (and ignored) */
1842 if (strcmp(id,"B13BWz") != 0 &&
1843 strcmp(id,"B13BWzWWWzB9B") != 0) {
1848 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1853 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1863 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1864 char** buf, int* buflen,
1865 char** stringbuf, int* stringspace, char* baseaddr)
1894 len += StrlenExpanded(conn,snum,lp_comment(snum));
1897 len += strlen(lp_pathname(snum)) + 1;
1900 *buflen = struct_len;
1905 return struct_len + len;
1910 if ((*buflen) < struct_len) {
1918 p2 = p + struct_len;
1919 l2 = (*buflen) - struct_len;
1926 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1932 type = STYPE_DISKTREE;
1933 if (lp_print_ok(snum)) {
1934 type = STYPE_PRINTQ;
1936 if (strequal("IPC",lp_fstype(snum))) {
1939 SSVAL(p,14,type); /* device type */
1940 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1941 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1945 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1946 SSVALS(p,22,-1); /* max uses */
1947 SSVAL(p,24,1); /* current uses */
1948 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1949 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1950 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1954 memset(p+40,0,SHPWLEN+2);
1965 (*buf) = p + struct_len;
1966 (*buflen) -= struct_len;
1968 (*stringspace) = l2;
1977 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1978 char *param, int tpscnt,
1979 char *data, int tdscnt,
1980 int mdrcnt,int mprcnt,
1981 char **rdata,char **rparam,
1982 int *rdata_len,int *rparam_len)
1984 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1985 char *str2 = skip_string(param,tpscnt,str1);
1986 char *netname = skip_string(param,tpscnt,str2);
1987 char *p = skip_string(param,tpscnt,netname);
1988 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1991 if (!str1 || !str2 || !netname || !p) {
1995 snum = find_service(netname);
2000 /* check it's a supported varient */
2001 if (!prefix_ok(str1,"zWrLh")) {
2004 if (!check_share_info(uLevel,str2)) {
2008 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2013 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2014 if (*rdata_len < 0) {
2019 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2023 SSVAL(*rparam,0,NERR_Success);
2024 SSVAL(*rparam,2,0); /* converter word */
2025 SSVAL(*rparam,4,*rdata_len);
2030 /****************************************************************************
2031 View the list of available shares.
2033 This function is the server side of the NetShareEnum() RAP call.
2034 It fills the return buffer with share names and share comments.
2035 Note that the return buffer normally (in all known cases) allows only
2036 twelve byte strings for share names (plus one for a nul terminator).
2037 Share names longer than 12 bytes must be skipped.
2038 ****************************************************************************/
2040 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2041 char *param, int tpscnt,
2042 char *data, int tdscnt,
2050 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2051 char *str2 = skip_string(param,tpscnt,str1);
2052 char *p = skip_string(param,tpscnt,str2);
2053 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2054 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2057 int total=0,counted=0;
2058 bool missed = False;
2060 int data_len, fixed_len, string_len;
2061 int f_len = 0, s_len = 0;
2063 if (!str1 || !str2 || !p) {
2067 if (!prefix_ok(str1,"WrLeh")) {
2070 if (!check_share_info(uLevel,str2)) {
2074 /* Ensure all the usershares are loaded. */
2076 load_registry_shares();
2077 count = load_usershare_shares();
2080 data_len = fixed_len = string_len = 0;
2081 for (i=0;i<count;i++) {
2082 fstring servicename_dos;
2083 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2086 push_ascii_fstring(servicename_dos, lp_servicename(i));
2087 /* Maximum name length = 13. */
2088 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2090 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2091 if (data_len < buf_len) {
2094 string_len += s_len;
2101 *rdata_len = fixed_len + string_len;
2102 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2107 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2112 for( i = 0; i < count; i++ ) {
2113 fstring servicename_dos;
2114 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2118 push_ascii_fstring(servicename_dos, lp_servicename(i));
2119 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2120 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2127 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2131 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2133 SSVAL(*rparam,4,counted);
2134 SSVAL(*rparam,6,total);
2136 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2137 counted,total,uLevel,
2138 buf_len,*rdata_len,mdrcnt));
2143 /****************************************************************************
2145 ****************************************************************************/
2147 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2148 char *param, int tpscnt,
2149 char *data, int tdscnt,
2150 int mdrcnt,int mprcnt,
2151 char **rdata,char **rparam,
2152 int *rdata_len,int *rparam_len)
2154 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2155 char *str2 = skip_string(param,tpscnt,str1);
2156 char *p = skip_string(param,tpscnt,str2);
2157 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2160 char *pathname = NULL;
2161 char *command, *cmdname;
2162 unsigned int offset;
2165 size_t converted_size;
2167 if (!str1 || !str2 || !p) {
2171 /* check it's a supported varient */
2172 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2175 if (!check_share_info(uLevel,str2)) {
2182 /* Do we have a string ? */
2183 if (skip_string(data,mdrcnt,data) == NULL) {
2186 pull_ascii_fstring(sharename,data);
2187 snum = find_service(sharename);
2188 if (snum >= 0) { /* already exists */
2197 /* only support disk share adds */
2198 if (SVAL(data,14)!=STYPE_DISKTREE) {
2202 offset = IVAL(data, 16);
2203 if (offset >= mdrcnt) {
2204 res = ERRinvalidparam;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2212 pull_ascii_fstring(comment, offset? (data+offset) : "");
2214 offset = IVAL(data, 26);
2216 if (offset >= mdrcnt) {
2217 res = ERRinvalidparam;
2221 /* Do we have a string ? */
2222 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2226 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2227 offset ? (data+offset) : "", &converted_size))
2229 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2237 string_replace(sharename, '"', ' ');
2238 string_replace(pathname, '"', ' ');
2239 string_replace(comment, '"', ' ');
2241 cmdname = lp_add_share_cmd();
2243 if (!cmdname || *cmdname == '\0') {
2247 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2248 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2249 pathname, comment) == -1) {
2253 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2255 if ((res = smbrun(command, NULL)) != 0) {
2256 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2263 message_send_all(smbd_messaging_context(),
2264 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2268 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2272 SSVAL(*rparam,0,NERR_Success);
2273 SSVAL(*rparam,2,0); /* converter word */
2274 SSVAL(*rparam,4,*rdata_len);
2282 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2287 SSVAL(*rparam,0,res);
2292 /****************************************************************************
2293 view list of groups available
2294 ****************************************************************************/
2296 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2297 char *param, int tpscnt,
2298 char *data, int tdscnt,
2299 int mdrcnt,int mprcnt,
2300 char **rdata,char **rparam,
2301 int *rdata_len,int *rparam_len)
2305 int resume_context, cli_buf_size;
2306 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2307 char *str2 = skip_string(param,tpscnt,str1);
2308 char *p = skip_string(param,tpscnt,str2);
2310 uint32_t num_groups;
2311 uint32_t resume_handle;
2312 struct rpc_pipe_client *samr_pipe;
2313 struct policy_handle samr_handle, domain_handle;
2316 if (!str1 || !str2 || !p) {
2320 if (strcmp(str1,"WrLeh") != 0) {
2325 * W-> resume context (number of users to skip)
2326 * r -> return parameter pointer to receive buffer
2327 * L -> length of receive buffer
2328 * e -> return parameter number of entries
2329 * h -> return parameter total number of users
2332 if (strcmp("B21",str2) != 0) {
2336 status = rpc_pipe_open_internal(
2337 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2338 conn->server_info, &samr_pipe);
2339 if (!NT_STATUS_IS_OK(status)) {
2340 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2341 nt_errstr(status)));
2345 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2346 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2347 if (!NT_STATUS_IS_OK(status)) {
2348 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2349 nt_errstr(status)));
2353 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2354 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2355 get_global_sam_sid(), &domain_handle);
2356 if (!NT_STATUS_IS_OK(status)) {
2357 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2358 nt_errstr(status)));
2359 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2363 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2364 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2365 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2366 "%d\n", resume_context, cli_buf_size));
2368 *rdata_len = cli_buf_size;
2369 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2376 errflags = NERR_Success;
2381 struct samr_SamArray *sam_entries;
2382 uint32_t num_entries;
2384 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2389 if (!NT_STATUS_IS_OK(status)) {
2390 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2391 "%s\n", nt_errstr(status)));
2395 if (num_entries == 0) {
2396 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2397 "no entries -- done\n"));
2401 for(i=0; i<num_entries; i++) {
2404 name = sam_entries->entries[i].name.string;
2406 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2407 /* set overflow error */
2408 DEBUG(3,("overflow on entry %d group %s\n", i,
2414 /* truncate the name at 21 chars. */
2416 strlcpy(p, name, 21);
2417 DEBUG(10,("adding entry %d group %s\n", i, p));
2419 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2424 if (errflags != NERR_Success) {
2428 TALLOC_FREE(sam_entries);
2431 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2432 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2434 *rdata_len = PTR_DIFF(p,*rdata);
2437 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2441 SSVAL(*rparam, 0, errflags);
2442 SSVAL(*rparam, 2, 0); /* converter word */
2443 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2444 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2449 /*******************************************************************
2450 Get groups that a user is a member of.
2451 ******************************************************************/
2453 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2454 char *param, int tpscnt,
2455 char *data, int tdscnt,
2456 int mdrcnt,int mprcnt,
2457 char **rdata,char **rparam,
2458 int *rdata_len,int *rparam_len)
2460 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2461 char *str2 = skip_string(param,tpscnt,str1);
2462 char *UserName = skip_string(param,tpscnt,str2);
2463 char *p = skip_string(param,tpscnt,UserName);
2464 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2465 const char *level_string;
2471 struct rpc_pipe_client *samr_pipe;
2472 struct policy_handle samr_handle, domain_handle, user_handle;
2473 struct lsa_String name;
2474 struct lsa_Strings names;
2475 struct samr_Ids type, rid;
2476 struct samr_RidWithAttributeArray *rids;
2479 if (!str1 || !str2 || !UserName || !p) {
2484 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2489 /* check it's a supported varient */
2491 if ( strcmp(str1,"zWrLeh") != 0 )
2496 level_string = "B21";
2502 if (strcmp(level_string,str2) != 0)
2505 *rdata_len = mdrcnt + 1024;
2506 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2511 SSVAL(*rparam,0,NERR_Success);
2512 SSVAL(*rparam,2,0); /* converter word */
2515 endp = *rdata + *rdata_len;
2517 status = rpc_pipe_open_internal(
2518 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2519 conn->server_info, &samr_pipe);
2520 if (!NT_STATUS_IS_OK(status)) {
2521 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2522 nt_errstr(status)));
2526 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2527 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2528 if (!NT_STATUS_IS_OK(status)) {
2529 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2530 nt_errstr(status)));
2534 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2535 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2536 get_global_sam_sid(), &domain_handle);
2537 if (!NT_STATUS_IS_OK(status)) {
2538 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2539 nt_errstr(status)));
2543 name.string = UserName;
2545 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2546 &domain_handle, 1, &name,
2548 if (!NT_STATUS_IS_OK(status)) {
2549 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2550 nt_errstr(status)));
2554 if (type.ids[0] != SID_NAME_USER) {
2555 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2556 sid_type_lookup(type.ids[0])));
2560 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2562 SAMR_USER_ACCESS_GET_GROUPS,
2563 rid.ids[0], &user_handle);
2564 if (!NT_STATUS_IS_OK(status)) {
2565 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2566 nt_errstr(status)));
2570 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2571 &user_handle, &rids);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2574 nt_errstr(status)));
2578 for (i=0; i<rids->count; i++) {
2580 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2582 1, &rids->rids[i].rid,
2584 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2585 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2591 *rdata_len = PTR_DIFF(p,*rdata);
2593 SSVAL(*rparam,4,count); /* is this right?? */
2594 SSVAL(*rparam,6,count); /* is this right?? */
2599 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2601 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2603 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2608 /*******************************************************************
2610 ******************************************************************/
2612 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2613 char *param, int tpscnt,
2614 char *data, int tdscnt,
2615 int mdrcnt,int mprcnt,
2616 char **rdata,char **rparam,
2617 int *rdata_len,int *rparam_len)
2622 int i, resume_context, cli_buf_size;
2623 uint32_t resume_handle;
2625 struct rpc_pipe_client *samr_pipe;
2626 struct policy_handle samr_handle, domain_handle;
2629 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2630 char *str2 = skip_string(param,tpscnt,str1);
2631 char *p = skip_string(param,tpscnt,str2);
2634 if (!str1 || !str2 || !p) {
2638 if (strcmp(str1,"WrLeh") != 0)
2641 * W-> resume context (number of users to skip)
2642 * r -> return parameter pointer to receive buffer
2643 * L -> length of receive buffer
2644 * e -> return parameter number of entries
2645 * h -> return parameter total number of users
2648 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2649 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2650 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2651 resume_context, cli_buf_size));
2654 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2659 /* check it's a supported varient */
2660 if (strcmp("B21",str2) != 0)
2663 *rdata_len = cli_buf_size;
2664 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2670 endp = *rdata + *rdata_len;
2672 status = rpc_pipe_open_internal(
2673 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2674 conn->server_info, &samr_pipe);
2675 if (!NT_STATUS_IS_OK(status)) {
2676 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2677 nt_errstr(status)));
2681 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2682 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2685 nt_errstr(status)));
2689 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2690 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2691 get_global_sam_sid(), &domain_handle);
2692 if (!NT_STATUS_IS_OK(status)) {
2693 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2694 nt_errstr(status)));
2695 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2699 errflags=NERR_Success;
2704 struct samr_SamArray *sam_entries;
2705 uint32_t num_entries;
2707 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2713 if (!NT_STATUS_IS_OK(status)) {
2714 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2715 "%s\n", nt_errstr(status)));
2719 if (num_entries == 0) {
2720 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2721 "no entries -- done\n"));
2725 for (i=0; i<num_entries; i++) {
2728 name = sam_entries->entries[i].name.string;
2730 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2731 &&(strlen(name)<=21)) {
2732 strlcpy(p,name,PTR_DIFF(endp,p));
2733 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2734 "username %s\n",count_sent,p));
2738 /* set overflow error */
2739 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2740 "username %s\n",count_sent,name));
2746 if (errflags != NERR_Success) {
2750 TALLOC_FREE(sam_entries);
2753 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2754 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2756 *rdata_len = PTR_DIFF(p,*rdata);
2758 SSVAL(*rparam,0,errflags);
2759 SSVAL(*rparam,2,0); /* converter word */
2760 SSVAL(*rparam,4,count_sent); /* is this right?? */
2761 SSVAL(*rparam,6,num_users); /* is this right?? */
2766 /****************************************************************************
2767 Get the time of day info.
2768 ****************************************************************************/
2770 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2771 char *param, int tpscnt,
2772 char *data, int tdscnt,
2773 int mdrcnt,int mprcnt,
2774 char **rdata,char **rparam,
2775 int *rdata_len,int *rparam_len)
2778 time_t unixdate = time(NULL);
2782 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2788 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2793 SSVAL(*rparam,0,NERR_Success);
2794 SSVAL(*rparam,2,0); /* converter word */
2798 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2799 by NT in a "net time" operation,
2800 it seems to ignore the one below */
2802 /* the client expects to get localtime, not GMT, in this bit
2803 (I think, this needs testing) */
2804 t = localtime(&unixdate);
2809 SIVAL(p,4,0); /* msecs ? */
2810 SCVAL(p,8,t->tm_hour);
2811 SCVAL(p,9,t->tm_min);
2812 SCVAL(p,10,t->tm_sec);
2813 SCVAL(p,11,0); /* hundredths of seconds */
2814 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2815 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2816 SCVAL(p,16,t->tm_mday);
2817 SCVAL(p,17,t->tm_mon + 1);
2818 SSVAL(p,18,1900+t->tm_year);
2819 SCVAL(p,20,t->tm_wday);
2824 /****************************************************************************
2825 Set the user password.
2826 *****************************************************************************/
2828 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2829 char *param, int tpscnt,
2830 char *data, int tdscnt,
2831 int mdrcnt,int mprcnt,
2832 char **rdata,char **rparam,
2833 int *rdata_len,int *rparam_len)
2835 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2838 fstring pass1,pass2;
2840 /* Skip 2 strings. */
2841 p = skip_string(param,tpscnt,np);
2842 p = skip_string(param,tpscnt,p);
2848 /* Do we have a string ? */
2849 if (skip_string(param,tpscnt,p) == NULL) {
2852 pull_ascii_fstring(user,p);
2854 p = skip_string(param,tpscnt,p);
2859 memset(pass1,'\0',sizeof(pass1));
2860 memset(pass2,'\0',sizeof(pass2));
2862 * We use 31 here not 32 as we're checking
2863 * the last byte we want to access is safe.
2865 if (!is_offset_safe(param,tpscnt,p,31)) {
2869 memcpy(pass2,p+16,16);
2872 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2879 SSVAL(*rparam,0,NERR_badpass);
2880 SSVAL(*rparam,2,0); /* converter word */
2882 DEBUG(3,("Set password for <%s>\n",user));
2885 * Attempt to verify the old password against smbpasswd entries
2886 * Win98 clients send old and new password in plaintext for this call.
2890 struct auth_serversupplied_info *server_info = NULL;
2891 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2893 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2896 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2897 SSVAL(*rparam,0,NERR_Success);
2901 TALLOC_FREE(server_info);
2903 data_blob_clear_free(&password);
2907 * If the plaintext change failed, attempt
2908 * the old encrypted method. NT will generate this
2909 * after trying the samr method. Note that this
2910 * method is done as a last resort as this
2911 * password change method loses the NT password hash
2912 * and cannot change the UNIX password as no plaintext
2916 if(SVAL(*rparam,0) != NERR_Success) {
2917 struct samu *hnd = NULL;
2919 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2921 if (change_lanman_password(hnd,(uchar *)pass2)) {
2922 SSVAL(*rparam,0,NERR_Success);
2929 memset((char *)pass1,'\0',sizeof(fstring));
2930 memset((char *)pass2,'\0',sizeof(fstring));
2935 /****************************************************************************
2936 Set the user password (SamOEM version - gets plaintext).
2937 ****************************************************************************/
2939 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2940 char *param, int tpscnt,
2941 char *data, int tdscnt,
2942 int mdrcnt,int mprcnt,
2943 char **rdata,char **rparam,
2944 int *rdata_len,int *rparam_len)
2946 struct smbd_server_connection *sconn = smbd_server_conn;
2948 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2950 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2960 SSVAL(*rparam,0,NERR_badpass);
2963 * Check the parameter definition is correct.
2966 /* Do we have a string ? */
2967 if (skip_string(param,tpscnt,p) == 0) {
2970 if(!strequal(p, "zsT")) {
2971 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2974 p = skip_string(param, tpscnt, p);
2979 /* Do we have a string ? */
2980 if (skip_string(param,tpscnt,p) == 0) {
2983 if(!strequal(p, "B516B16")) {
2984 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2987 p = skip_string(param,tpscnt,p);
2991 /* Do we have a string ? */
2992 if (skip_string(param,tpscnt,p) == 0) {
2995 p += pull_ascii_fstring(user,p);
2997 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3000 * Pass the user through the NT -> unix user mapping
3004 (void)map_username(sconn, user);
3006 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
3007 SSVAL(*rparam,0,NERR_Success);
3013 /****************************************************************************
3016 ****************************************************************************/
3018 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3019 char *param, int tpscnt,
3020 char *data, int tdscnt,
3021 int mdrcnt,int mprcnt,
3022 char **rdata,char **rparam,
3023 int *rdata_len,int *rparam_len)
3025 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3026 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3027 char *str2 = skip_string(param,tpscnt,str1);
3028 char *p = skip_string(param,tpscnt,str2);
3032 WERROR werr = WERR_OK;
3034 TALLOC_CTX *mem_ctx = talloc_tos();
3036 struct rpc_pipe_client *cli = NULL;
3037 struct policy_handle handle;
3038 struct spoolss_DevmodeContainer devmode_ctr;
3039 enum spoolss_JobControl command;
3041 if (!str1 || !str2 || !p) {
3045 * We use 1 here not 2 as we're checking
3046 * the last byte we want to access is safe.
3048 if (!is_offset_safe(param,tpscnt,p,1)) {
3051 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3054 /* check it's a supported varient */
3055 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3059 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3065 ZERO_STRUCT(handle);
3067 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3068 rpc_spoolss_dispatch, conn->server_info,
3070 if (!NT_STATUS_IS_OK(status)) {
3071 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3072 nt_errstr(status)));
3073 errcode = W_ERROR_V(ntstatus_to_werror(status));
3077 ZERO_STRUCT(devmode_ctr);
3079 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3083 SEC_FLAG_MAXIMUM_ALLOWED,
3086 if (!NT_STATUS_IS_OK(status)) {
3087 errcode = W_ERROR_V(ntstatus_to_werror(status));
3090 if (!W_ERROR_IS_OK(werr)) {
3091 errcode = W_ERROR_V(werr);
3095 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3096 * and NERR_DestNotFound if share did not exist */
3098 errcode = NERR_Success;
3101 case 81: /* delete */
3102 command = SPOOLSS_JOB_CONTROL_DELETE;
3104 case 82: /* pause */
3105 command = SPOOLSS_JOB_CONTROL_PAUSE;
3107 case 83: /* resume */
3108 command = SPOOLSS_JOB_CONTROL_RESUME;
3111 errcode = NERR_notsupported;
3115 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3118 NULL, /* unique ptr ctr */
3121 if (!NT_STATUS_IS_OK(status)) {
3122 errcode = W_ERROR_V(ntstatus_to_werror(status));
3125 if (!W_ERROR_IS_OK(werr)) {
3126 errcode = W_ERROR_V(werr);
3131 if (cli && is_valid_policy_hnd(&handle)) {
3132 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3135 SSVAL(*rparam,0,errcode);
3136 SSVAL(*rparam,2,0); /* converter word */
3141 /****************************************************************************
3142 Purge a print queue - or pause or resume it.
3143 ****************************************************************************/
3145 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3146 char *param, int tpscnt,
3147 char *data, int tdscnt,
3148 int mdrcnt,int mprcnt,
3149 char **rdata,char **rparam,
3150 int *rdata_len,int *rparam_len)
3152 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3153 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3154 char *str2 = skip_string(param,tpscnt,str1);
3155 char *QueueName = skip_string(param,tpscnt,str2);
3156 int errcode = NERR_notsupported;
3157 WERROR werr = WERR_OK;
3160 TALLOC_CTX *mem_ctx = talloc_tos();
3161 struct rpc_pipe_client *cli = NULL;
3162 struct policy_handle handle;
3163 struct spoolss_SetPrinterInfoCtr info_ctr;
3164 struct spoolss_DevmodeContainer devmode_ctr;
3165 struct sec_desc_buf secdesc_ctr;
3166 enum spoolss_PrinterControl command;
3168 if (!str1 || !str2 || !QueueName) {
3172 /* check it's a supported varient */
3173 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3177 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3183 if (skip_string(param,tpscnt,QueueName) == NULL) {
3187 ZERO_STRUCT(handle);
3189 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3190 rpc_spoolss_dispatch, conn->server_info,
3192 if (!NT_STATUS_IS_OK(status)) {
3193 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3194 nt_errstr(status)));
3195 errcode = W_ERROR_V(ntstatus_to_werror(status));
3199 ZERO_STRUCT(devmode_ctr);
3201 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3205 SEC_FLAG_MAXIMUM_ALLOWED,
3208 if (!NT_STATUS_IS_OK(status)) {
3209 errcode = W_ERROR_V(ntstatus_to_werror(status));
3212 if (!W_ERROR_IS_OK(werr)) {
3213 errcode = W_ERROR_V(werr);
3218 case 74: /* Pause queue */
3219 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3221 case 75: /* Resume queue */
3222 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3224 case 103: /* Purge */
3225 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3228 werr = WERR_NOT_SUPPORTED;
3232 if (!W_ERROR_IS_OK(werr)) {
3233 errcode = W_ERROR_V(werr);
3237 ZERO_STRUCT(info_ctr);
3238 ZERO_STRUCT(secdesc_ctr);
3240 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3247 if (!NT_STATUS_IS_OK(status)) {
3248 errcode = W_ERROR_V(ntstatus_to_werror(status));
3251 if (!W_ERROR_IS_OK(werr)) {
3252 errcode = W_ERROR_V(werr);
3256 errcode = W_ERROR_V(werr);
3260 if (cli && is_valid_policy_hnd(&handle)) {
3261 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3264 SSVAL(*rparam,0,errcode);
3265 SSVAL(*rparam,2,0); /* converter word */
3270 /****************************************************************************
3271 set the property of a print job (undocumented?)
3272 ? function = 0xb -> set name of print job
3273 ? function = 0x6 -> move print job up/down
3274 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3275 or <WWsTP> <WB21BB16B10zWWzDDz>
3276 ****************************************************************************/
3278 static int check_printjob_info(struct pack_desc* desc,
3279 int uLevel, char* id)
3281 desc->subformat = NULL;
3283 case 0: desc->format = "W"; break;
3284 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3285 case 2: desc->format = "WWzWWDDzz"; break;
3286 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3287 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3289 DEBUG(0,("check_printjob_info: invalid level %d\n",
3293 if (id == NULL || strcmp(desc->format,id) != 0) {
3294 DEBUG(0,("check_printjob_info: invalid format %s\n",
3295 id ? id : "<NULL>" ));
3301 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3302 char *param, int tpscnt,
3303 char *data, int tdscnt,
3304 int mdrcnt,int mprcnt,
3305 char **rdata,char **rparam,
3306 int *rdata_len,int *rparam_len)
3308 struct pack_desc desc;
3309 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3310 char *str2 = skip_string(param,tpscnt,str1);
3311 char *p = skip_string(param,tpscnt,str2);
3314 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3315 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3318 TALLOC_CTX *mem_ctx = talloc_tos();
3321 struct rpc_pipe_client *cli = NULL;
3322 struct policy_handle handle;
3323 struct spoolss_DevmodeContainer devmode_ctr;
3324 struct spoolss_JobInfoContainer ctr;
3325 union spoolss_JobInfo info;
3326 struct spoolss_SetJobInfo1 info1;
3328 if (!str1 || !str2 || !p) {
3332 * We use 1 here not 2 as we're checking
3333 * the last byte we want to access is safe.
3335 if (!is_offset_safe(param,tpscnt,p,1)) {
3338 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3341 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3348 /* check it's a supported varient */
3349 if ((strcmp(str1,"WWsTP")) ||
3350 (!check_printjob_info(&desc,uLevel,str2)))
3353 errcode = NERR_notsupported;
3357 /* change print job name, data gives the name */
3363 ZERO_STRUCT(handle);
3365 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3366 rpc_spoolss_dispatch, conn->server_info,
3368 if (!NT_STATUS_IS_OK(status)) {
3369 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3370 nt_errstr(status)));
3371 errcode = W_ERROR_V(ntstatus_to_werror(status));
3375 ZERO_STRUCT(devmode_ctr);
3377 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3381 SEC_FLAG_MAXIMUM_ALLOWED,
3384 if (!NT_STATUS_IS_OK(status)) {
3385 errcode = W_ERROR_V(ntstatus_to_werror(status));
3388 if (!W_ERROR_IS_OK(werr)) {
3389 errcode = W_ERROR_V(werr);
3393 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3399 if (!W_ERROR_IS_OK(werr)) {
3400 errcode = W_ERROR_V(werr);
3406 info1.job_id = info.info1.job_id;
3407 info1.printer_name = info.info1.printer_name;
3408 info1.user_name = info.info1.user_name;
3409 info1.document_name = data;
3410 info1.data_type = info.info1.data_type;
3411 info1.text_status = info.info1.text_status;
3412 info1.status = info.info1.status;
3413 info1.priority = info.info1.priority;
3414 info1.position = info.info1.position;
3415 info1.total_pages = info.info1.total_pages;
3416 info1.pages_printed = info.info1.pages_printed;
3417 info1.submitted = info.info1.submitted;
3420 ctr.info.info1 = &info1;
3422 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3428 if (!NT_STATUS_IS_OK(status)) {
3429 errcode = W_ERROR_V(ntstatus_to_werror(status));
3432 if (!W_ERROR_IS_OK(werr)) {
3433 errcode = W_ERROR_V(werr);
3437 errcode = NERR_Success;
3440 if (cli && is_valid_policy_hnd(&handle)) {
3441 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3444 SSVALS(*rparam,0,errcode);
3445 SSVAL(*rparam,2,0); /* converter word */
3451 /****************************************************************************
3452 Get info about the server.
3453 ****************************************************************************/
3455 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3456 char *param, int tpscnt,
3457 char *data, int tdscnt,
3458 int mdrcnt,int mprcnt,
3459 char **rdata,char **rparam,
3460 int *rdata_len,int *rparam_len)
3462 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3463 char *str2 = skip_string(param,tpscnt,str1);
3464 char *p = skip_string(param,tpscnt,str2);
3465 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
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 srvstr_push(NULL, 0, p,global_myname(),16,
3531 STR_ASCII|STR_UPPER|STR_TERMINATE);
3535 struct srv_info_struct *servers=NULL;
3537 char *comment = NULL;
3538 TALLOC_CTX *ctx = talloc_tos();
3539 uint32 servertype= lp_default_server_announce();
3541 comment = talloc_strdup(ctx,lp_serverstring());
3546 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3547 for (i=0;i<count;i++) {
3548 if (strequal(servers[i].name,global_myname())) {
3549 servertype = servers[i].type;
3550 TALLOC_FREE(comment);
3551 comment = talloc_strdup(ctx,
3552 servers[i].comment);
3562 SCVAL(p,0,lp_major_announce_version());
3563 SCVAL(p,1,lp_minor_announce_version());
3564 SIVAL(p,2,servertype);
3566 if (mdrcnt == struct_len) {
3569 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3570 comment = talloc_sub_advanced(
3572 lp_servicename(SNUM(conn)),
3573 conn->server_info->unix_name,
3575 conn->server_info->utok.gid,
3576 conn->server_info->sanitized_username,
3577 pdb_get_domain(conn->server_info->sam_account),
3582 if (mdrcnt - struct_len <= 0) {
3587 MIN(mdrcnt - struct_len,
3588 MAX_SERVER_STRING_LENGTH),
3590 p2 = skip_string(*rdata,*rdata_len,p2);
3598 return False; /* not yet implemented */
3601 *rdata_len = PTR_DIFF(p2,*rdata);
3604 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3608 SSVAL(*rparam,0,NERR_Success);
3609 SSVAL(*rparam,2,0); /* converter word */
3610 SSVAL(*rparam,4,*rdata_len);
3615 /****************************************************************************
3616 Get info about the server.
3617 ****************************************************************************/
3619 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3620 char *param, int tpscnt,
3621 char *data, int tdscnt,
3622 int mdrcnt,int mprcnt,
3623 char **rdata,char **rparam,
3624 int *rdata_len,int *rparam_len)
3626 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3627 char *str2 = skip_string(param,tpscnt,str1);
3628 char *p = skip_string(param,tpscnt,str2);
3631 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3633 if (!str1 || !str2 || !p) {
3637 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3640 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3645 /* check it's a supported varient */
3646 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3650 *rdata_len = mdrcnt + 1024;
3651 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3656 SSVAL(*rparam,0,NERR_Success);
3657 SSVAL(*rparam,2,0); /* converter word */
3660 endp = *rdata + *rdata_len;
3662 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3667 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3668 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3670 p2 = skip_string(*rdata,*rdata_len,p2);
3676 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3677 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3678 p2 = skip_string(*rdata,*rdata_len,p2);
3684 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3685 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3687 p2 = skip_string(*rdata,*rdata_len,p2);
3693 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3694 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3697 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3698 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3699 p2 = skip_string(*rdata,*rdata_len,p2);
3705 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3706 strlcpy(p2,"",PTR_DIFF(endp,p2));
3707 p2 = skip_string(*rdata,*rdata_len,p2);
3713 *rdata_len = PTR_DIFF(p2,*rdata);
3715 SSVAL(*rparam,4,*rdata_len);
3720 /****************************************************************************
3721 get info about a user
3723 struct user_info_11 {
3724 char usri11_name[21]; 0-20
3726 char *usri11_comment; 22-25
3727 char *usri11_usr_comment; 26-29
3728 unsigned short usri11_priv; 30-31
3729 unsigned long usri11_auth_flags; 32-35
3730 long usri11_password_age; 36-39
3731 char *usri11_homedir; 40-43
3732 char *usri11_parms; 44-47
3733 long usri11_last_logon; 48-51
3734 long usri11_last_logoff; 52-55
3735 unsigned short usri11_bad_pw_count; 56-57
3736 unsigned short usri11_num_logons; 58-59
3737 char *usri11_logon_server; 60-63
3738 unsigned short usri11_country_code; 64-65
3739 char *usri11_workstations; 66-69
3740 unsigned long usri11_max_storage; 70-73
3741 unsigned short usri11_units_per_week; 74-75
3742 unsigned char *usri11_logon_hours; 76-79
3743 unsigned short usri11_code_page; 80-81
3748 usri11_name specifies the user name for which information is retrieved
3750 usri11_pad aligns the next data structure element to a word boundary
3752 usri11_comment is a null terminated ASCII comment
3754 usri11_user_comment is a null terminated ASCII comment about the user
3756 usri11_priv specifies the level of the privilege assigned to the user.
3757 The possible values are:
3759 Name Value Description
3760 USER_PRIV_GUEST 0 Guest privilege
3761 USER_PRIV_USER 1 User privilege
3762 USER_PRV_ADMIN 2 Administrator privilege
3764 usri11_auth_flags specifies the account operator privileges. The
3765 possible values are:
3767 Name Value Description
3768 AF_OP_PRINT 0 Print operator
3771 Leach, Naik [Page 28]
3775 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3778 AF_OP_COMM 1 Communications operator
3779 AF_OP_SERVER 2 Server operator
3780 AF_OP_ACCOUNTS 3 Accounts operator
3783 usri11_password_age specifies how many seconds have elapsed since the
3784 password was last changed.
3786 usri11_home_dir points to a null terminated ASCII string that contains
3787 the path name of the user's home directory.
3789 usri11_parms points to a null terminated ASCII string that is set
3790 aside for use by applications.
3792 usri11_last_logon specifies the time when the user last logged on.
3793 This value is stored as the number of seconds elapsed since
3794 00:00:00, January 1, 1970.
3796 usri11_last_logoff specifies the time when the user last logged off.
3797 This value is stored as the number of seconds elapsed since
3798 00:00:00, January 1, 1970. A value of 0 means the last logoff
3801 usri11_bad_pw_count specifies the number of incorrect passwords
3802 entered since the last successful logon.
3804 usri11_log1_num_logons specifies the number of times this user has
3805 logged on. A value of -1 means the number of logons is unknown.
3807 usri11_logon_server points to a null terminated ASCII string that
3808 contains the name of the server to which logon requests are sent.
3809 A null string indicates logon requests should be sent to the
3812 usri11_country_code specifies the country code for the user's language
3815 usri11_workstations points to a null terminated ASCII string that
3816 contains the names of workstations the user may log on from.
3817 There may be up to 8 workstations, with the names separated by
3818 commas. A null strings indicates there are no restrictions.
3820 usri11_max_storage specifies the maximum amount of disk space the user
3821 can occupy. A value of 0xffffffff indicates there are no
3824 usri11_units_per_week specifies the equal number of time units into
3825 which a week is divided. This value must be equal to 168.
3827 usri11_logon_hours points to a 21 byte (168 bits) string that
3828 specifies the time during which the user can log on. Each bit
3829 represents one unique hour in a week. The first bit (bit 0, word
3830 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3834 Leach, Naik [Page 29]
3838 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3841 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3842 are no restrictions.
3844 usri11_code_page specifies the code page for the user's language of
3847 All of the pointers in this data structure need to be treated
3848 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3849 to be ignored. The converter word returned in the parameters section
3850 needs to be subtracted from the lower 16 bits to calculate an offset
3851 into the return buffer where this ASCII string resides.
3853 There is no auxiliary data in the response.
3855 ****************************************************************************/
3857 #define usri11_name 0
3858 #define usri11_pad 21
3859 #define usri11_comment 22
3860 #define usri11_usr_comment 26
3861 #define usri11_full_name 30
3862 #define usri11_priv 34
3863 #define usri11_auth_flags 36
3864 #define usri11_password_age 40
3865 #define usri11_homedir 44
3866 #define usri11_parms 48
3867 #define usri11_last_logon 52
3868 #define usri11_last_logoff 56
3869 #define usri11_bad_pw_count 60
3870 #define usri11_num_logons 62
3871 #define usri11_logon_server 64
3872 #define usri11_country_code 68
3873 #define usri11_workstations 70
3874 #define usri11_max_storage 74
3875 #define usri11_units_per_week 78
3876 #define usri11_logon_hours 80
3877 #define usri11_code_page 84
3878 #define usri11_end 86
3880 #define USER_PRIV_GUEST 0
3881 #define USER_PRIV_USER 1
3882 #define USER_PRIV_ADMIN 2
3884 #define AF_OP_PRINT 0
3885 #define AF_OP_COMM 1
3886 #define AF_OP_SERVER 2
3887 #define AF_OP_ACCOUNTS 3
3890 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3891 char *param, int tpscnt,
3892 char *data, int tdscnt,
3893 int mdrcnt,int mprcnt,
3894 char **rdata,char **rparam,
3895 int *rdata_len,int *rparam_len)
3897 struct smbd_server_connection *sconn = smbd_server_conn;
3898 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3899 char *str2 = skip_string(param,tpscnt,str1);
3900 char *UserName = skip_string(param,tpscnt,str2);
3901 char *p = skip_string(param,tpscnt,UserName);
3902 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3905 const char *level_string;
3907 /* get NIS home of a previously validated user - simeon */
3908 /* With share level security vuid will always be zero.
3909 Don't depend on vuser being non-null !!. JRA */
3910 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3912 DEBUG(3,(" Username of UID %d is %s\n",
3913 (int)vuser->server_info->utok.uid,
3914 vuser->server_info->unix_name));
3917 if (!str1 || !str2 || !UserName || !p) {
3922 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3927 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3929 /* check it's a supported variant */
3930 if (strcmp(str1,"zWrLh") != 0) {
3934 case 0: level_string = "B21"; break;
3935 case 1: level_string = "B21BB16DWzzWz"; break;
3936 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3937 case 10: level_string = "B21Bzzz"; break;
3938 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3939 default: return False;
3942 if (strcmp(level_string,str2) != 0) {
3946 *rdata_len = mdrcnt + 1024;
3947 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3952 SSVAL(*rparam,0,NERR_Success);
3953 SSVAL(*rparam,2,0); /* converter word */
3956 endp = *rdata + *rdata_len;
3957 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3963 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3966 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3971 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3972 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3973 p2 = skip_string(*rdata,*rdata_len,p2);
3978 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3979 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3980 p2 = skip_string(*rdata,*rdata_len,p2);
3985 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3986 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3987 strlcpy(p2,((vuser != NULL)
3988 ? pdb_get_fullname(vuser->server_info->sam_account)
3989 : UserName),PTR_DIFF(endp,p2));
3990 p2 = skip_string(*rdata,*rdata_len,p2);
3997 const char *homedir = "";
3998 if (vuser != NULL) {
3999 homedir = pdb_get_homedir(
4000 vuser->server_info->sam_account);
4002 /* modelled after NTAS 3.51 reply */
4003 SSVAL(p,usri11_priv,
4004 (get_current_uid(conn) == sec_initial_uid())?
4005 USER_PRIV_ADMIN:USER_PRIV_USER);
4006 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4007 SIVALS(p,usri11_password_age,-1); /* password age */
4008 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4009 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4010 p2 = skip_string(*rdata,*rdata_len,p2);
4014 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4015 strlcpy(p2,"",PTR_DIFF(endp,p2));
4016 p2 = skip_string(*rdata,*rdata_len,p2);
4020 SIVAL(p,usri11_last_logon,0); /* last logon */
4021 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4022 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4023 SSVALS(p,usri11_num_logons,-1); /* num logons */
4024 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4025 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4026 p2 = skip_string(*rdata,*rdata_len,p2);
4030 SSVAL(p,usri11_country_code,0); /* country code */
4032 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4033 strlcpy(p2,"",PTR_DIFF(endp,p2));
4034 p2 = skip_string(*rdata,*rdata_len,p2);
4039 SIVALS(p,usri11_max_storage,-1); /* max storage */
4040 SSVAL(p,usri11_units_per_week,168); /* units per week */
4041 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4043 /* a simple way to get logon hours at all times. */
4045 SCVAL(p2,21,0); /* fix zero termination */
4046 p2 = skip_string(*rdata,*rdata_len,p2);
4051 SSVAL(p,usri11_code_page,0); /* code page */
4054 if (uLevel == 1 || uLevel == 2) {
4055 memset(p+22,' ',16); /* password */
4056 SIVALS(p,38,-1); /* password age */
4058 (get_current_uid(conn) == sec_initial_uid())?
4059 USER_PRIV_ADMIN:USER_PRIV_USER);
4060 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4061 strlcpy(p2, vuser ? pdb_get_homedir(
4062 vuser->server_info->sam_account) : "",
4064 p2 = skip_string(*rdata,*rdata_len,p2);
4068 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4070 SSVAL(p,52,0); /* flags */
4071 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4072 strlcpy(p2, vuser ? pdb_get_logon_script(
4073 vuser->server_info->sam_account) : "",
4075 p2 = skip_string(*rdata,*rdata_len,p2);
4080 SIVAL(p,60,0); /* auth_flags */
4081 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4082 strlcpy(p2,((vuser != NULL)
4083 ? pdb_get_fullname(vuser->server_info->sam_account)
4084 : UserName),PTR_DIFF(endp,p2));
4085 p2 = skip_string(*rdata,*rdata_len,p2);
4089 SIVAL(p,68,0); /* urs_comment */
4090 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4091 strlcpy(p2,"",PTR_DIFF(endp,p2));
4092 p2 = skip_string(*rdata,*rdata_len,p2);
4096 SIVAL(p,76,0); /* workstations */
4097 SIVAL(p,80,0); /* last_logon */
4098 SIVAL(p,84,0); /* last_logoff */
4099 SIVALS(p,88,-1); /* acct_expires */
4100 SIVALS(p,92,-1); /* max_storage */
4101 SSVAL(p,96,168); /* units_per_week */
4102 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4105 SSVALS(p,102,-1); /* bad_pw_count */
4106 SSVALS(p,104,-1); /* num_logons */
4107 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4109 TALLOC_CTX *ctx = talloc_tos();
4110 int space_rem = *rdata_len - (p2 - *rdata);
4113 if (space_rem <= 0) {
4116 tmp = talloc_strdup(ctx, "\\\\%L");
4120 tmp = talloc_sub_basic(ctx,
4133 p2 = skip_string(*rdata,*rdata_len,p2);
4137 SSVAL(p,110,49); /* country_code */
4138 SSVAL(p,112,860); /* code page */
4142 *rdata_len = PTR_DIFF(p2,*rdata);
4144 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4149 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4150 char *param, int tpscnt,
4151 char *data, int tdscnt,
4152 int mdrcnt,int mprcnt,
4153 char **rdata,char **rparam,
4154 int *rdata_len,int *rparam_len)
4156 struct smbd_server_connection *sconn = smbd_server_conn;
4157 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4158 char *str2 = skip_string(param,tpscnt,str1);
4159 char *p = skip_string(param,tpscnt,str2);
4161 struct pack_desc desc;
4163 /* With share level security vuid will always be zero.
4164 Don't depend on vuser being non-null !!. JRA */
4165 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4167 if (!str1 || !str2 || !p) {
4172 DEBUG(3,(" Username of UID %d is %s\n",
4173 (int)vuser->server_info->utok.uid,
4174 vuser->server_info->unix_name));
4177 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4178 name = get_safe_str_ptr(param,tpscnt,p,2);
4183 memset((char *)&desc,'\0',sizeof(desc));
4185 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4187 /* check it's a supported varient */
4188 if (strcmp(str1,"OOWb54WrLh") != 0) {
4191 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4195 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4202 desc.buflen = mdrcnt;
4203 desc.subformat = NULL;
4206 if (init_package(&desc,1,0)) {
4207 PACKI(&desc,"W",0); /* code */
4208 PACKS(&desc,"B21",name); /* eff. name */
4209 PACKS(&desc,"B",""); /* pad */
4211 (get_current_uid(conn) == sec_initial_uid())?
4212 USER_PRIV_ADMIN:USER_PRIV_USER);
4213 PACKI(&desc,"D",0); /* auth flags XXX */
4214 PACKI(&desc,"W",0); /* num logons */
4215 PACKI(&desc,"W",0); /* bad pw count */
4216 PACKI(&desc,"D",0); /* last logon */
4217 PACKI(&desc,"D",-1); /* last logoff */
4218 PACKI(&desc,"D",-1); /* logoff time */
4219 PACKI(&desc,"D",-1); /* kickoff time */
4220 PACKI(&desc,"D",0); /* password age */
4221 PACKI(&desc,"D",0); /* password can change */
4222 PACKI(&desc,"D",-1); /* password must change */
4226 fstrcpy(mypath,"\\\\");
4227 fstrcat(mypath,get_local_machine_name());
4229 PACKS(&desc,"z",mypath); /* computer */
4232 PACKS(&desc,"z",lp_workgroup());/* domain */
4233 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4234 vuser->server_info->sam_account) : ""); /* script path */
4235 PACKI(&desc,"D",0x00000000); /* reserved */
4238 *rdata_len = desc.usedlen;
4240 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4244 SSVALS(*rparam,0,desc.errcode);
4246 SSVAL(*rparam,4,desc.neededlen);
4248 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4253 /****************************************************************************
4254 api_WAccessGetUserPerms
4255 ****************************************************************************/
4257 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4258 char *param, int tpscnt,
4259 char *data, int tdscnt,
4260 int mdrcnt,int mprcnt,
4261 char **rdata,char **rparam,
4262 int *rdata_len,int *rparam_len)
4264 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4265 char *str2 = skip_string(param,tpscnt,str1);
4266 char *user = skip_string(param,tpscnt,str2);
4267 char *resource = skip_string(param,tpscnt,user);
4269 if (!str1 || !str2 || !user || !resource) {
4273 if (skip_string(param,tpscnt,resource) == NULL) {
4276 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4278 /* check it's a supported varient */
4279 if (strcmp(str1,"zzh") != 0) {
4282 if (strcmp(str2,"") != 0) {
4287 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4291 SSVALS(*rparam,0,0); /* errorcode */
4292 SSVAL(*rparam,2,0); /* converter word */
4293 SSVAL(*rparam,4,0x7f); /* permission flags */
4298 /****************************************************************************
4299 api_WPrintJobEnumerate
4300 ****************************************************************************/
4302 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4303 char *param, int tpscnt,
4304 char *data, int tdscnt,
4305 int mdrcnt,int mprcnt,
4306 char **rdata,char **rparam,
4307 int *rdata_len,int *rparam_len)
4309 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4310 char *str2 = skip_string(param,tpscnt,str1);
4311 char *p = skip_string(param,tpscnt,str2);
4315 struct pack_desc desc;
4318 TALLOC_CTX *mem_ctx = talloc_tos();
4321 struct rpc_pipe_client *cli = NULL;
4322 struct policy_handle handle;
4323 struct spoolss_DevmodeContainer devmode_ctr;
4324 union spoolss_JobInfo info;
4326 if (!str1 || !str2 || !p) {
4330 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4332 memset((char *)&desc,'\0',sizeof(desc));
4333 memset((char *)&status,'\0',sizeof(status));
4335 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4337 /* check it's a supported varient */
4338 if (strcmp(str1,"WWrLh") != 0) {
4341 if (!check_printjob_info(&desc,uLevel,str2)) {
4345 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4349 ZERO_STRUCT(handle);
4351 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4352 rpc_spoolss_dispatch, conn->server_info,
4354 if (!NT_STATUS_IS_OK(status)) {
4355 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4356 nt_errstr(status)));
4357 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4361 ZERO_STRUCT(devmode_ctr);
4363 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4367 SEC_FLAG_MAXIMUM_ALLOWED,
4370 if (!NT_STATUS_IS_OK(status)) {
4371 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4374 if (!W_ERROR_IS_OK(werr)) {
4375 desc.errcode = W_ERROR_V(werr);
4379 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4385 if (!W_ERROR_IS_OK(werr)) {
4386 desc.errcode = W_ERROR_V(werr);
4391 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4396 desc.buflen = mdrcnt;
4399 * Don't return data but need to get correct length
4400 * init_package will return wrong size if buflen=0
4402 desc.buflen = getlen(desc.format);
4403 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4406 if (init_package(&desc,1,0)) {
4407 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4408 *rdata_len = desc.usedlen;
4410 desc.errcode = NERR_JobNotFound;
4414 if (cli && is_valid_policy_hnd(&handle)) {
4415 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4419 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4423 SSVALS(*rparam,0,desc.errcode);
4425 SSVAL(*rparam,4,desc.neededlen);
4429 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4434 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4435 char *param, int tpscnt,
4436 char *data, int tdscnt,
4437 int mdrcnt,int mprcnt,
4438 char **rdata,char **rparam,
4439 int *rdata_len,int *rparam_len)
4441 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4442 char *str2 = skip_string(param,tpscnt,str1);
4443 char *p = skip_string(param,tpscnt,str2);
4447 struct pack_desc desc;
4449 TALLOC_CTX *mem_ctx = talloc_tos();
4452 struct rpc_pipe_client *cli = NULL;
4453 struct policy_handle handle;
4454 struct spoolss_DevmodeContainer devmode_ctr;
4456 union spoolss_JobInfo *info;
4458 if (!str1 || !str2 || !p) {
4462 memset((char *)&desc,'\0',sizeof(desc));
4464 p = skip_string(param,tpscnt,p);
4468 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4470 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4472 /* check it's a supported variant */
4473 if (strcmp(str1,"zWrLeh") != 0) {
4478 return False; /* defined only for uLevel 0,1,2 */
4481 if (!check_printjob_info(&desc,uLevel,str2)) {
4485 ZERO_STRUCT(handle);
4487 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4488 rpc_spoolss_dispatch, conn->server_info,
4490 if (!NT_STATUS_IS_OK(status)) {
4491 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4492 nt_errstr(status)));
4493 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4497 ZERO_STRUCT(devmode_ctr);
4499 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4503 SEC_FLAG_MAXIMUM_ALLOWED,
4506 if (!NT_STATUS_IS_OK(status)) {
4507 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4510 if (!W_ERROR_IS_OK(werr)) {
4511 desc.errcode = W_ERROR_V(werr);
4515 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4523 if (!W_ERROR_IS_OK(werr)) {
4524 desc.errcode = W_ERROR_V(werr);
4529 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4535 desc.buflen = mdrcnt;
4537 if (init_package(&desc,count,0)) {
4539 for (i = 0; i < count; i++) {
4540 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4541 if (desc.errcode == NERR_Success) {
4547 if (cli && is_valid_policy_hnd(&handle)) {
4548 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4551 *rdata_len = desc.usedlen;
4554 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4558 SSVALS(*rparam,0,desc.errcode);
4560 SSVAL(*rparam,4,succnt);
4561 SSVAL(*rparam,6,count);
4563 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4568 static int check_printdest_info(struct pack_desc* desc,
4569 int uLevel, char* id)
4571 desc->subformat = NULL;
4574 desc->format = "B9";
4577 desc->format = "B9B21WWzW";
4583 desc->format = "zzzWWzzzWW";
4586 DEBUG(0,("check_printdest_info: invalid level %d\n",
4590 if (id == NULL || strcmp(desc->format,id) != 0) {
4591 DEBUG(0,("check_printdest_info: invalid string %s\n",
4592 id ? id : "<NULL>" ));
4598 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4599 struct pack_desc* desc)
4603 strncpy(buf, info2->printername, sizeof(buf)-1);
4604 buf[sizeof(buf)-1] = 0;
4608 PACKS(desc,"B9",buf); /* szName */
4610 PACKS(desc,"B21",""); /* szUserName */
4611 PACKI(desc,"W",0); /* uJobId */
4612 PACKI(desc,"W",0); /* fsStatus */
4613 PACKS(desc,"z",""); /* pszStatus */
4614 PACKI(desc,"W",0); /* time */
4618 if (uLevel == 2 || uLevel == 3) {
4619 PACKS(desc,"z",buf); /* pszPrinterName */
4621 PACKS(desc,"z",""); /* pszUserName */
4622 PACKS(desc,"z",""); /* pszLogAddr */
4623 PACKI(desc,"W",0); /* uJobId */
4624 PACKI(desc,"W",0); /* fsStatus */
4625 PACKS(desc,"z",""); /* pszStatus */
4626 PACKS(desc,"z",""); /* pszComment */
4627 PACKS(desc,"z","NULL"); /* pszDrivers */
4628 PACKI(desc,"W",0); /* time */
4629 PACKI(desc,"W",0); /* pad1 */
4634 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4635 char *param, int tpscnt,
4636 char *data, int tdscnt,
4637 int mdrcnt,int mprcnt,
4638 char **rdata,char **rparam,
4639 int *rdata_len,int *rparam_len)
4641 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4642 char *str2 = skip_string(param,tpscnt,str1);
4643 char *p = skip_string(param,tpscnt,str2);
4644 char* PrinterName = p;
4646 struct pack_desc desc;
4649 TALLOC_CTX *mem_ctx = talloc_tos();
4652 struct rpc_pipe_client *cli = NULL;
4653 struct policy_handle handle;
4654 struct spoolss_DevmodeContainer devmode_ctr;
4655 union spoolss_PrinterInfo info;
4657 if (!str1 || !str2 || !p) {
4661 memset((char *)&desc,'\0',sizeof(desc));
4663 p = skip_string(param,tpscnt,p);
4667 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4669 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4671 /* check it's a supported varient */
4672 if (strcmp(str1,"zWrLh") != 0) {
4675 if (!check_printdest_info(&desc,uLevel,str2)) {
4679 ZERO_STRUCT(handle);
4681 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4682 rpc_spoolss_dispatch, conn->server_info,
4684 if (!NT_STATUS_IS_OK(status)) {
4685 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4686 nt_errstr(status)));
4687 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4691 ZERO_STRUCT(devmode_ctr);
4693 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4697 SEC_FLAG_MAXIMUM_ALLOWED,
4700 if (!NT_STATUS_IS_OK(status)) {
4702 desc.errcode = NERR_DestNotFound;
4706 if (!W_ERROR_IS_OK(werr)) {
4708 desc.errcode = NERR_DestNotFound;
4713 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4718 if (!W_ERROR_IS_OK(werr)) {
4720 desc.errcode = NERR_DestNotFound;
4726 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4731 desc.buflen = mdrcnt;
4734 * Don't return data but need to get correct length
4735 * init_package will return wrong size if buflen=0
4737 desc.buflen = getlen(desc.format);
4738 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4740 if (init_package(&desc,1,0)) {
4741 fill_printdest_info(&info.info2, uLevel,&desc);
4745 if (cli && is_valid_policy_hnd(&handle)) {
4746 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4749 *rdata_len = desc.usedlen;
4752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4756 SSVALS(*rparam,0,desc.errcode);
4758 SSVAL(*rparam,4,desc.neededlen);
4760 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4766 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4767 char *param, int tpscnt,
4768 char *data, int tdscnt,
4769 int mdrcnt,int mprcnt,
4770 char **rdata,char **rparam,
4771 int *rdata_len,int *rparam_len)
4773 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4774 char *str2 = skip_string(param,tpscnt,str1);
4775 char *p = skip_string(param,tpscnt,str2);
4779 struct pack_desc desc;
4781 TALLOC_CTX *mem_ctx = talloc_tos();
4784 struct rpc_pipe_client *cli = NULL;
4785 union spoolss_PrinterInfo *info;
4788 if (!str1 || !str2 || !p) {
4792 memset((char *)&desc,'\0',sizeof(desc));
4794 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4796 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4798 /* check it's a supported varient */
4799 if (strcmp(str1,"WrLeh") != 0) {
4802 if (!check_printdest_info(&desc,uLevel,str2)) {
4808 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4809 rpc_spoolss_dispatch, conn->server_info,
4811 if (!NT_STATUS_IS_OK(status)) {
4812 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4813 nt_errstr(status)));
4814 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4818 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4820 cli->srv_name_slash,
4825 if (!W_ERROR_IS_OK(werr)) {
4826 desc.errcode = W_ERROR_V(werr);
4828 desc.errcode = NERR_DestNotFound;
4836 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4843 desc.buflen = mdrcnt;
4844 if (init_package(&desc,queuecnt,0)) {
4847 for (i = 0; i < count; i++) {
4848 fill_printdest_info(&info[i].info2, uLevel,&desc);
4850 if (desc.errcode == NERR_Success) {
4856 *rdata_len = desc.usedlen;
4859 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4863 SSVALS(*rparam,0,desc.errcode);
4865 SSVAL(*rparam,4,succnt);
4866 SSVAL(*rparam,6,queuecnt);
4868 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4873 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4874 char *param, int tpscnt,
4875 char *data, int tdscnt,
4876 int mdrcnt,int mprcnt,
4877 char **rdata,char **rparam,
4878 int *rdata_len,int *rparam_len)
4880 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4881 char *str2 = skip_string(param,tpscnt,str1);
4882 char *p = skip_string(param,tpscnt,str2);
4885 struct pack_desc desc;
4887 if (!str1 || !str2 || !p) {
4891 memset((char *)&desc,'\0',sizeof(desc));
4893 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4895 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4897 /* check it's a supported varient */
4898 if (strcmp(str1,"WrLeh") != 0) {
4901 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4906 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4912 desc.buflen = mdrcnt;
4913 if (init_package(&desc,1,0)) {
4914 PACKS(&desc,"B41","NULL");
4917 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4919 *rdata_len = desc.usedlen;
4922 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4926 SSVALS(*rparam,0,desc.errcode);
4928 SSVAL(*rparam,4,succnt);
4931 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4936 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4937 char *param, int tpscnt,
4938 char *data, int tdscnt,
4939 int mdrcnt,int mprcnt,
4940 char **rdata,char **rparam,
4941 int *rdata_len,int *rparam_len)
4943 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4944 char *str2 = skip_string(param,tpscnt,str1);
4945 char *p = skip_string(param,tpscnt,str2);
4948 struct pack_desc desc;
4950 if (!str1 || !str2 || !p) {
4953 memset((char *)&desc,'\0',sizeof(desc));
4955 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4957 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4959 /* check it's a supported varient */
4960 if (strcmp(str1,"WrLeh") != 0) {
4963 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4968 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4974 desc.buflen = mdrcnt;
4976 if (init_package(&desc,1,0)) {
4977 PACKS(&desc,"B13","lpd");
4980 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4982 *rdata_len = desc.usedlen;
4985 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4989 SSVALS(*rparam,0,desc.errcode);
4991 SSVAL(*rparam,4,succnt);
4994 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4999 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5000 char *param, int tpscnt,
5001 char *data, int tdscnt,
5002 int mdrcnt,int mprcnt,
5003 char **rdata,char **rparam,
5004 int *rdata_len,int *rparam_len)
5006 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5007 char *str2 = skip_string(param,tpscnt,str1);
5008 char *p = skip_string(param,tpscnt,str2);
5011 struct pack_desc desc;
5013 if (!str1 || !str2 || !p) {
5017 memset((char *)&desc,'\0',sizeof(desc));
5019 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5021 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5023 /* check it's a supported varient */
5024 if (strcmp(str1,"WrLeh") != 0) {
5027 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5032 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5037 memset((char *)&desc,'\0',sizeof(desc));
5039 desc.buflen = mdrcnt;
5041 if (init_package(&desc,1,0)) {
5042 PACKS(&desc,"B13","lp0");
5045 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5047 *rdata_len = desc.usedlen;
5050 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5054 SSVALS(*rparam,0,desc.errcode);
5056 SSVAL(*rparam,4,succnt);
5059 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5064 /****************************************************************************
5066 ****************************************************************************/
5068 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5069 char *param, int tpscnt,
5070 char *data, int tdscnt,
5071 int mdrcnt,int mprcnt,
5072 char **rdata,char **rparam,
5073 int *rdata_len,int *rparam_len)
5076 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5077 char *str2 = skip_string(param,tpscnt,str1);
5078 char *p = skip_string(param,tpscnt,str2);
5080 struct pack_desc desc;
5081 struct sessionid *session_list;
5082 int i, num_sessions;
5084 if (!str1 || !str2 || !p) {
5088 memset((char *)&desc,'\0',sizeof(desc));
5090 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5092 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5093 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5094 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5096 /* check it's a supported varient */
5097 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5100 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5104 num_sessions = list_sessions(talloc_tos(), &session_list);
5107 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5112 memset((char *)&desc,'\0',sizeof(desc));
5114 desc.buflen = mdrcnt;
5116 if (!init_package(&desc,num_sessions,0)) {
5120 for(i=0; i<num_sessions; i++) {
5121 PACKS(&desc, "z", session_list[i].remote_machine);
5122 PACKS(&desc, "z", session_list[i].username);
5123 PACKI(&desc, "W", 1); /* num conns */
5124 PACKI(&desc, "W", 0); /* num opens */
5125 PACKI(&desc, "W", 1); /* num users */
5126 PACKI(&desc, "D", 0); /* session time */
5127 PACKI(&desc, "D", 0); /* idle time */
5128 PACKI(&desc, "D", 0); /* flags */
5129 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5132 *rdata_len = desc.usedlen;
5135 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5139 SSVALS(*rparam,0,desc.errcode);
5140 SSVAL(*rparam,2,0); /* converter */
5141 SSVAL(*rparam,4,num_sessions); /* count */
5143 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5149 /****************************************************************************
5150 The buffer was too small.
5151 ****************************************************************************/
5153 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5154 int mdrcnt, int mprcnt,
5155 char **rdata, char **rparam,
5156 int *rdata_len, int *rparam_len)
5158 *rparam_len = MIN(*rparam_len,mprcnt);
5159 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5166 SSVAL(*rparam,0,NERR_BufTooSmall);
5168 DEBUG(3,("Supplied buffer too small in API command\n"));
5173 /****************************************************************************
5174 The request is not supported.
5175 ****************************************************************************/
5177 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5178 char *param, int tpscnt,
5179 char *data, int tdscnt,
5180 int mdrcnt, int mprcnt,
5181 char **rdata, char **rparam,
5182 int *rdata_len, int *rparam_len)
5185 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5192 SSVAL(*rparam,0,NERR_notsupported);
5193 SSVAL(*rparam,2,0); /* converter word */
5195 DEBUG(3,("Unsupported API command\n"));
5200 static const struct {
5203 bool (*fn)(connection_struct *, uint16,
5206 int,int,char **,char **,int *,int *);
5207 bool auth_user; /* Deny anonymous access? */
5208 } api_commands[] = {
5209 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5210 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5211 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5212 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5213 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5214 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5215 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5216 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5217 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5218 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5219 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5220 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5221 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5222 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5223 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5224 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5225 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5226 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5227 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5228 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5229 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5230 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5231 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5232 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5233 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5234 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5235 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5236 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5237 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5238 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5239 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5240 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5241 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5242 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5243 {NULL, -1, api_Unsupported}
5244 /* The following RAP calls are not implemented by Samba:
5246 RAP_WFileEnum2 - anon not OK
5251 /****************************************************************************
5252 Handle remote api calls.
5253 ****************************************************************************/
5255 void api_reply(connection_struct *conn, uint16 vuid,
5256 struct smb_request *req,
5257 char *data, char *params,
5258 int tdscnt, int tpscnt,
5259 int mdrcnt, int mprcnt)
5261 struct smbd_server_connection *sconn = smbd_server_conn;
5264 char *rparam = NULL;
5265 const char *name1 = NULL;
5266 const char *name2 = NULL;
5273 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5274 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5279 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5282 api_command = SVAL(params,0);
5283 /* Is there a string at position params+2 ? */
5284 if (skip_string(params,tpscnt,params+2)) {
5289 name2 = skip_string(params,tpscnt,params+2);
5294 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5298 tdscnt,tpscnt,mdrcnt,mprcnt));
5300 for (i=0;api_commands[i].name;i++) {
5301 if (api_commands[i].id == api_command && api_commands[i].fn) {
5302 DEBUG(3,("Doing %s\n",api_commands[i].name));
5307 /* Check whether this api call can be done anonymously */
5309 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5310 user_struct *user = get_valid_user_struct(sconn, vuid);
5312 if (!user || user->server_info->guest) {
5313 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5318 rdata = (char *)SMB_MALLOC(1024);
5320 memset(rdata,'\0',1024);
5323 rparam = (char *)SMB_MALLOC(1024);
5325 memset(rparam,'\0',1024);
5328 if(!rdata || !rparam) {
5329 DEBUG(0,("api_reply: malloc fail !\n"));
5332 reply_nterror(req, NT_STATUS_NO_MEMORY);
5336 reply = api_commands[i].fn(conn,
5338 params,tpscnt, /* params + length */
5339 data,tdscnt, /* data + length */
5341 &rdata,&rparam,&rdata_len,&rparam_len);
5344 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5345 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5346 &rdata,&rparam,&rdata_len,&rparam_len);
5349 /* if we get False back then it's actually unsupported */
5351 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5352 &rdata,&rparam,&rdata_len,&rparam_len);
5355 /* If api_Unsupported returns false we can't return anything. */
5357 send_trans_reply(conn, req, rparam, rparam_len,
5358 rdata, rdata_len, False);