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;
664 static void fill_printq_info(int uLevel,
665 struct pack_desc* desc,
667 union spoolss_JobInfo *job_info,
668 struct spoolss_DriverInfo3 *driver_info,
669 struct spoolss_PrinterInfo2 *printer_info)
675 PACKS(desc,"B13", printer_info->printername);
680 PACKS(desc,"z", printer_info->printername);
683 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
687 if (uLevel == 1 || uLevel == 2) {
688 PACKS(desc,"B",""); /* alignment */
689 PACKI(desc,"W",5); /* priority */
690 PACKI(desc,"W",0); /* start time */
691 PACKI(desc,"W",0); /* until time */
692 PACKS(desc,"z",""); /* pSepFile */
693 PACKS(desc,"z","lpd"); /* pPrProc */
694 PACKS(desc,"z", printer_info->printername); /* pDestinations */
695 PACKS(desc,"z",""); /* pParms */
696 if (printer_info->printername == NULL) {
697 PACKS(desc,"z","UNKNOWN PRINTER");
698 PACKI(desc,"W",LPSTAT_ERROR);
700 PACKS(desc,"z", printer_info->comment);
701 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
703 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
706 if (uLevel == 3 || uLevel == 4) {
707 PACKI(desc,"W",5); /* uPriority */
708 PACKI(desc,"W",0); /* uStarttime */
709 PACKI(desc,"W",0); /* uUntiltime */
710 PACKI(desc,"W",5); /* pad1 */
711 PACKS(desc,"z",""); /* pszSepFile */
712 PACKS(desc,"z","WinPrint"); /* pszPrProc */
713 PACKS(desc,"z",NULL); /* pszParms */
714 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
715 /* "don't ask" that it's done this way to fix corrupted
716 Win9X/ME printer comments. */
717 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
718 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
719 PACKS(desc,"z", printer_info->printername); /* pszPrinters */
720 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
721 PackDriverData(desc); /* pDriverData */
724 if (uLevel == 2 || uLevel == 4) {
726 for (i = 0; i < count; i++) {
727 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
732 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
735 /* This function returns the number of files for a given driver */
736 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
740 /* count the number of files */
741 while (driver->dependent_files && *driver->dependent_files[result])
747 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
748 char *param, int tpscnt,
749 char *data, int tdscnt,
750 int mdrcnt,int mprcnt,
751 char **rdata,char **rparam,
752 int *rdata_len,int *rparam_len)
754 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
755 char *str2 = skip_string(param,tpscnt,str1);
756 char *p = skip_string(param,tpscnt,str2);
761 struct pack_desc desc;
764 WERROR werr = WERR_OK;
765 TALLOC_CTX *mem_ctx = talloc_tos();
767 struct rpc_pipe_client *cli = NULL;
768 struct policy_handle handle;
769 struct spoolss_DevmodeContainer devmode_ctr;
770 union spoolss_DriverInfo driver_info;
771 union spoolss_JobInfo *job_info;
772 union spoolss_PrinterInfo printer_info;
774 if (!str1 || !str2 || !p) {
777 memset((char *)&desc,'\0',sizeof(desc));
779 p = skip_string(param,tpscnt,p);
783 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
784 str3 = get_safe_str_ptr(param,tpscnt,p,4);
785 /* str3 may be null here and is checked in check_printq_info(). */
787 /* remove any trailing username */
788 if ((p = strchr_m(QueueName,'%')))
791 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
793 /* check it's a supported varient */
794 if (!prefix_ok(str1,"zWrLh"))
796 if (!check_printq_info(&desc,uLevel,str2,str3)) {
798 * Patch from Scott Moomaw <scott@bridgewater.edu>
799 * to return the 'invalid info level' error if an
800 * unknown level was requested.
804 *rparam = smb_realloc_limit(*rparam,*rparam_len);
808 SSVALS(*rparam,0,ERRunknownlevel);
816 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
817 rpc_spoolss_dispatch, conn->server_info,
819 if (!NT_STATUS_IS_OK(status)) {
820 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
822 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
826 ZERO_STRUCT(devmode_ctr);
828 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
832 SEC_FLAG_MAXIMUM_ALLOWED,
835 if (!NT_STATUS_IS_OK(status)) {
836 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
839 if (!W_ERROR_IS_OK(werr)) {
840 desc.errcode = W_ERROR_V(werr);
845 uint32_t server_major_version;
846 uint32_t server_minor_version;
848 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
856 &server_major_version,
857 &server_minor_version);
858 if (!W_ERROR_IS_OK(werr)) {
859 desc.errcode = W_ERROR_V(werr);
863 count = get_printerdrivernumber(&driver_info.info3);
864 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
867 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
875 if (!W_ERROR_IS_OK(werr)) {
876 desc.errcode = W_ERROR_V(werr);
884 *rdata = smb_realloc_limit(*rdata,mdrcnt);
889 desc.buflen = mdrcnt;
892 * Don't return data but need to get correct length
893 * init_package will return wrong size if buflen=0
895 desc.buflen = getlen(desc.format);
896 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
899 if (init_package(&desc,1,count)) {
900 desc.subcount = count;
901 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
904 *rdata_len = desc.usedlen;
907 * We must set the return code to ERRbuftoosmall
908 * in order to support lanman style printing with Win NT/2k
911 if (!mdrcnt && lp_disable_spoolss())
912 desc.errcode = ERRbuftoosmall;
915 if (is_valid_policy_hnd(&handle)) {
916 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
919 *rdata_len = desc.usedlen;
921 *rparam = smb_realloc_limit(*rparam,*rparam_len);
926 SSVALS(*rparam,0,desc.errcode);
928 SSVAL(*rparam,4,desc.neededlen);
930 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
937 /****************************************************************************
938 View list of all print jobs on all queues.
939 ****************************************************************************/
941 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
942 char *param, int tpscnt,
943 char *data, int tdscnt,
944 int mdrcnt, int mprcnt,
945 char **rdata, char** rparam,
946 int *rdata_len, int *rparam_len)
948 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
949 char *output_format1 = skip_string(param,tpscnt,param_format);
950 char *p = skip_string(param,tpscnt,output_format1);
951 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
952 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
954 struct pack_desc desc;
955 int *subcntarr = NULL;
956 int queuecnt = 0, subcnt = 0, succnt = 0;
958 WERROR werr = WERR_OK;
959 TALLOC_CTX *mem_ctx = talloc_tos();
961 struct rpc_pipe_client *cli = NULL;
962 struct spoolss_DevmodeContainer devmode_ctr;
963 uint32_t num_printers;
964 union spoolss_PrinterInfo *printer_info;
965 union spoolss_DriverInfo *driver_info;
966 union spoolss_JobInfo **job_info;
968 if (!param_format || !output_format1 || !p) {
972 memset((char *)&desc,'\0',sizeof(desc));
974 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
976 if (!prefix_ok(param_format,"WrLeh")) {
979 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
981 * Patch from Scott Moomaw <scott@bridgewater.edu>
982 * to return the 'invalid info level' error if an
983 * unknown level was requested.
987 *rparam = smb_realloc_limit(*rparam,*rparam_len);
991 SSVALS(*rparam,0,ERRunknownlevel);
997 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
998 rpc_spoolss_dispatch, conn->server_info,
1000 if (!NT_STATUS_IS_OK(status)) {
1001 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1002 nt_errstr(status)));
1003 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1007 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1009 cli->srv_name_slash,
1014 if (!W_ERROR_IS_OK(werr)) {
1015 desc.errcode = W_ERROR_V(werr);
1019 queuecnt = num_printers;
1021 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1022 if (job_info == NULL) {
1026 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1027 if (driver_info == NULL) {
1031 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1032 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1037 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1043 desc.buflen = mdrcnt;
1046 for (i = 0; i < num_printers; i++) {
1049 struct policy_handle handle;
1051 ZERO_STRUCT(handle);
1052 ZERO_STRUCT(devmode_ctr);
1054 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1055 printer_info[i].info2.printername,
1058 SEC_FLAG_MAXIMUM_ALLOWED,
1061 if (!NT_STATUS_IS_OK(status)) {
1062 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1065 if (!W_ERROR_IS_OK(werr)) {
1066 desc.errcode = W_ERROR_V(werr);
1070 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1078 if (!W_ERROR_IS_OK(werr)) {
1079 desc.errcode = W_ERROR_V(werr);
1084 uint32_t server_major_version;
1085 uint32_t server_minor_version;
1087 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1095 &server_major_version,
1096 &server_minor_version);
1097 if (!W_ERROR_IS_OK(werr)) {
1098 desc.errcode = W_ERROR_V(werr);
1103 subcntarr[i] = num_jobs;
1104 subcnt += subcntarr[i];
1106 if (is_valid_policy_hnd(&handle)) {
1107 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1111 if (init_package(&desc,queuecnt,subcnt)) {
1112 for (i = 0; i < num_printers; i++) {
1113 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1114 if (desc.errcode == NERR_Success) {
1120 SAFE_FREE(subcntarr);
1122 *rdata_len = desc.usedlen;
1124 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1128 SSVALS(*rparam,0,desc.errcode);
1130 SSVAL(*rparam,4,succnt);
1131 SSVAL(*rparam,6,queuecnt);
1137 SAFE_FREE(subcntarr);
1142 /****************************************************************************
1143 Get info level for a server list query.
1144 ****************************************************************************/
1146 static bool check_server_info(int uLevel, char* id)
1150 if (strcmp(id,"B16") != 0) {
1155 if (strcmp(id,"B16BBDz") != 0) {
1165 struct srv_info_struct {
1173 /*******************************************************************
1174 Get server info lists from the files saved by nmbd. Return the
1176 ******************************************************************/
1178 static int get_server_info(uint32 servertype,
1179 struct srv_info_struct **servers,
1185 bool local_list_only;
1188 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1190 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1194 /* request for everything is code for request all servers */
1195 if (servertype == SV_TYPE_ALL) {
1196 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1199 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1201 DEBUG(4,("Servertype search: %8x\n",servertype));
1203 for (i=0;lines[i];i++) {
1205 struct srv_info_struct *s;
1206 const char *ptr = lines[i];
1208 TALLOC_CTX *frame = NULL;
1215 if (count == alloced) {
1217 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1219 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1223 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1225 s = &(*servers)[count];
1227 frame = talloc_stackframe();
1229 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1233 fstrcpy(s->name, p);
1236 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1242 s->comment[0] = '\0';
1243 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1247 fstrcpy(s->comment, p);
1248 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1250 s->domain[0] = '\0';
1251 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1252 /* this allows us to cope with an old nmbd */
1253 fstrcpy(s->domain,lp_workgroup());
1255 fstrcpy(s->domain, p);
1259 if (sscanf(stype,"%X",&s->type) != 1) {
1260 DEBUG(4,("r:host file "));
1264 /* Filter the servers/domains we return based on what was asked for. */
1266 /* Check to see if we are being asked for a local list only. */
1267 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1268 DEBUG(4,("r: local list only"));
1272 /* doesn't match up: don't want it */
1273 if (!(servertype & s->type)) {
1274 DEBUG(4,("r:serv type "));
1278 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1279 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1280 DEBUG(4,("s: dom mismatch "));
1284 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1288 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1289 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1292 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1293 s->name, s->type, s->comment, s->domain));
1294 s->server_added = True;
1297 DEBUG(4,("%20s %8x %25s %15s\n",
1298 s->name, s->type, s->comment, s->domain));
1306 /*******************************************************************
1307 Fill in a server info structure.
1308 ******************************************************************/
1310 static int fill_srv_info(struct srv_info_struct *service,
1311 int uLevel, char **buf, int *buflen,
1312 char **stringbuf, int *stringspace, char *baseaddr)
1335 len = strlen(service->comment)+1;
1339 *buflen = struct_len;
1341 return struct_len + len;
1346 if (*buflen < struct_len) {
1353 p2 = p + struct_len;
1354 l2 = *buflen - struct_len;
1362 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1366 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1367 SIVAL(p,18,service->type);
1368 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1369 len += CopyAndAdvance(&p2,service->comment,&l2);
1374 *buf = p + struct_len;
1375 *buflen -= struct_len;
1386 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1388 return StrCaseCmp(s1->name,s2->name);
1391 /****************************************************************************
1392 View list of servers available (or possibly domains). The info is
1393 extracted from lists saved by nmbd on the local host.
1394 ****************************************************************************/
1396 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1397 char *param, int tpscnt,
1398 char *data, int tdscnt,
1399 int mdrcnt, int mprcnt, char **rdata,
1400 char **rparam, int *rdata_len, int *rparam_len)
1402 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1403 char *str2 = skip_string(param,tpscnt,str1);
1404 char *p = skip_string(param,tpscnt,str2);
1405 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1406 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1407 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1409 int data_len, fixed_len, string_len;
1410 int f_len = 0, s_len = 0;
1411 struct srv_info_struct *servers=NULL;
1412 int counted=0,total=0;
1415 bool domain_request;
1418 if (!str1 || !str2 || !p) {
1422 /* If someone sets all the bits they don't really mean to set
1423 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1426 if (servertype == SV_TYPE_ALL) {
1427 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1430 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1431 any other bit (they may just set this bit on its own) they
1432 want all the locally seen servers. However this bit can be
1433 set on its own so set the requested servers to be
1434 ALL - DOMAIN_ENUM. */
1436 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1437 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1440 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1441 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1445 if (!prefix_ok(str1,"WrLehD")) {
1448 if (!check_server_info(uLevel,str2)) {
1452 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1453 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1454 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1456 if (strcmp(str1, "WrLehDz") == 0) {
1457 if (skip_string(param,tpscnt,p) == NULL) {
1460 pull_ascii_fstring(domain, p);
1462 fstrcpy(domain, lp_workgroup());
1465 DEBUG(4, ("domain [%s]\n", domain));
1467 if (lp_browse_list()) {
1468 total = get_server_info(servertype,&servers,domain);
1471 data_len = fixed_len = string_len = 0;
1474 TYPESAFE_QSORT(servers, total, srv_comp);
1477 char *lastname=NULL;
1479 for (i=0;i<total;i++) {
1480 struct srv_info_struct *s = &servers[i];
1482 if (lastname && strequal(lastname,s->name)) {
1486 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1487 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1488 i, s->name, s->type, s->comment, s->domain));
1490 if (data_len < buf_len) {
1493 string_len += s_len;
1500 *rdata_len = fixed_len + string_len;
1501 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1506 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1512 char *lastname=NULL;
1513 int count2 = counted;
1515 for (i = 0; i < total && count2;i++) {
1516 struct srv_info_struct *s = &servers[i];
1518 if (lastname && strequal(lastname,s->name)) {
1522 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1523 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1524 i, s->name, s->type, s->comment, s->domain));
1530 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1534 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1536 SSVAL(*rparam,4,counted);
1537 SSVAL(*rparam,6,counted+missed);
1541 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1542 domain,uLevel,counted,counted+missed));
1547 static int srv_name_match(const char *n1, const char *n2)
1550 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1552 * In Windows, FirstNameToReturn need not be an exact match:
1553 * the server will return a list of servers that exist on
1554 * the network greater than or equal to the FirstNameToReturn.
1556 int ret = StrCaseCmp(n1, n2);
1565 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1566 char *param, int tpscnt,
1567 char *data, int tdscnt,
1568 int mdrcnt, int mprcnt, char **rdata,
1569 char **rparam, int *rdata_len, int *rparam_len)
1571 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1572 char *str2 = skip_string(param,tpscnt,str1);
1573 char *p = skip_string(param,tpscnt,str2);
1574 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1575 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1576 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1578 int data_len, fixed_len, string_len;
1579 int f_len = 0, s_len = 0;
1580 struct srv_info_struct *servers=NULL;
1581 int counted=0,first=0,total=0;
1585 bool domain_request;
1588 if (!str1 || !str2 || !p) {
1592 /* If someone sets all the bits they don't really mean to set
1593 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1596 if (servertype == SV_TYPE_ALL) {
1597 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1600 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1601 any other bit (they may just set this bit on its own) they
1602 want all the locally seen servers. However this bit can be
1603 set on its own so set the requested servers to be
1604 ALL - DOMAIN_ENUM. */
1606 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1607 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1610 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1611 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1615 if (strcmp(str1, "WrLehDzz") != 0) {
1618 if (!check_server_info(uLevel,str2)) {
1622 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1623 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1624 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1626 if (skip_string(param,tpscnt,p) == NULL) {
1629 pull_ascii_fstring(domain, p);
1630 if (domain[0] == '\0') {
1631 fstrcpy(domain, lp_workgroup());
1633 p = skip_string(param,tpscnt,p);
1634 if (skip_string(param,tpscnt,p) == NULL) {
1637 pull_ascii_fstring(first_name, p);
1639 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1640 domain, first_name));
1642 if (lp_browse_list()) {
1643 total = get_server_info(servertype,&servers,domain);
1646 data_len = fixed_len = string_len = 0;
1649 TYPESAFE_QSORT(servers, total, srv_comp);
1651 if (first_name[0] != '\0') {
1652 struct srv_info_struct *first_server = NULL;
1654 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1655 srv_name_match, first_server);
1657 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1659 * The binary search may not find the exact match
1660 * so we need to search backward to find the first match
1662 * This implements the strange matching windows
1663 * implements. (see the comment in srv_name_match().
1667 ret = StrCaseCmp(first_name,
1668 servers[first-1].name);
1675 /* we should return no entries */
1681 char *lastname=NULL;
1683 for (i=first;i<total;i++) {
1684 struct srv_info_struct *s = &servers[i];
1686 if (lastname && strequal(lastname,s->name)) {
1690 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1691 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1692 i, s->name, s->type, s->comment, s->domain));
1694 if (data_len < buf_len) {
1697 string_len += s_len;
1704 *rdata_len = fixed_len + string_len;
1705 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1710 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1716 char *lastname=NULL;
1717 int count2 = counted;
1719 for (i = first; i < total && count2;i++) {
1720 struct srv_info_struct *s = &servers[i];
1722 if (lastname && strequal(lastname,s->name)) {
1726 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1727 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1728 i, s->name, s->type, s->comment, s->domain));
1734 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1738 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1740 SSVAL(*rparam,4,counted);
1741 SSVAL(*rparam,6,counted+missed);
1743 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1744 domain,uLevel,first,first_name,
1745 first < total ? servers[first].name : "",
1746 counted,counted+missed));
1753 /****************************************************************************
1754 command 0x34 - suspected of being a "Lookup Names" stub api
1755 ****************************************************************************/
1757 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1758 char *param, int tpscnt,
1759 char *data, int tdscnt,
1760 int mdrcnt, int mprcnt, char **rdata,
1761 char **rparam, int *rdata_len, int *rparam_len)
1763 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1764 char *str2 = skip_string(param,tpscnt,str1);
1765 char *p = skip_string(param,tpscnt,str2);
1766 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1767 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1771 if (!str1 || !str2 || !p) {
1775 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1776 str1, str2, p, uLevel, buf_len));
1778 if (!prefix_ok(str1,"zWrLeh")) {
1785 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1790 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1792 SSVAL(*rparam,4,counted);
1793 SSVAL(*rparam,6,counted+missed);
1798 /****************************************************************************
1799 get info about a share
1800 ****************************************************************************/
1802 static bool check_share_info(int uLevel, char* id)
1806 if (strcmp(id,"B13") != 0) {
1811 /* Level-2 descriptor is allowed (and ignored) */
1812 if (strcmp(id,"B13BWz") != 0 &&
1813 strcmp(id,"B13BWzWWWzB9B") != 0) {
1818 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1823 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1833 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1834 char** buf, int* buflen,
1835 char** stringbuf, int* stringspace, char* baseaddr)
1864 len += StrlenExpanded(conn,snum,lp_comment(snum));
1867 len += strlen(lp_pathname(snum)) + 1;
1870 *buflen = struct_len;
1875 return struct_len + len;
1880 if ((*buflen) < struct_len) {
1888 p2 = p + struct_len;
1889 l2 = (*buflen) - struct_len;
1896 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1902 type = STYPE_DISKTREE;
1903 if (lp_print_ok(snum)) {
1904 type = STYPE_PRINTQ;
1906 if (strequal("IPC",lp_fstype(snum))) {
1909 SSVAL(p,14,type); /* device type */
1910 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1911 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1915 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1916 SSVALS(p,22,-1); /* max uses */
1917 SSVAL(p,24,1); /* current uses */
1918 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1919 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1920 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1924 memset(p+40,0,SHPWLEN+2);
1935 (*buf) = p + struct_len;
1936 (*buflen) -= struct_len;
1938 (*stringspace) = l2;
1947 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1948 char *param, int tpscnt,
1949 char *data, int tdscnt,
1950 int mdrcnt,int mprcnt,
1951 char **rdata,char **rparam,
1952 int *rdata_len,int *rparam_len)
1954 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1955 char *str2 = skip_string(param,tpscnt,str1);
1956 char *netname = skip_string(param,tpscnt,str2);
1957 char *p = skip_string(param,tpscnt,netname);
1958 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1961 if (!str1 || !str2 || !netname || !p) {
1965 snum = find_service(netname);
1970 /* check it's a supported varient */
1971 if (!prefix_ok(str1,"zWrLh")) {
1974 if (!check_share_info(uLevel,str2)) {
1978 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1983 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1984 if (*rdata_len < 0) {
1989 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1993 SSVAL(*rparam,0,NERR_Success);
1994 SSVAL(*rparam,2,0); /* converter word */
1995 SSVAL(*rparam,4,*rdata_len);
2000 /****************************************************************************
2001 View the list of available shares.
2003 This function is the server side of the NetShareEnum() RAP call.
2004 It fills the return buffer with share names and share comments.
2005 Note that the return buffer normally (in all known cases) allows only
2006 twelve byte strings for share names (plus one for a nul terminator).
2007 Share names longer than 12 bytes must be skipped.
2008 ****************************************************************************/
2010 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2011 char *param, int tpscnt,
2012 char *data, int tdscnt,
2020 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2021 char *str2 = skip_string(param,tpscnt,str1);
2022 char *p = skip_string(param,tpscnt,str2);
2023 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2024 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2027 int total=0,counted=0;
2028 bool missed = False;
2030 int data_len, fixed_len, string_len;
2031 int f_len = 0, s_len = 0;
2033 if (!str1 || !str2 || !p) {
2037 if (!prefix_ok(str1,"WrLeh")) {
2040 if (!check_share_info(uLevel,str2)) {
2044 /* Ensure all the usershares are loaded. */
2046 load_registry_shares();
2047 count = load_usershare_shares();
2050 data_len = fixed_len = string_len = 0;
2051 for (i=0;i<count;i++) {
2052 fstring servicename_dos;
2053 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2056 push_ascii_fstring(servicename_dos, lp_servicename(i));
2057 /* Maximum name length = 13. */
2058 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2060 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2061 if (data_len < buf_len) {
2064 string_len += s_len;
2071 *rdata_len = fixed_len + string_len;
2072 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2077 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2082 for( i = 0; i < count; i++ ) {
2083 fstring servicename_dos;
2084 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2088 push_ascii_fstring(servicename_dos, lp_servicename(i));
2089 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2090 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2097 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2101 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2103 SSVAL(*rparam,4,counted);
2104 SSVAL(*rparam,6,total);
2106 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2107 counted,total,uLevel,
2108 buf_len,*rdata_len,mdrcnt));
2113 /****************************************************************************
2115 ****************************************************************************/
2117 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2118 char *param, int tpscnt,
2119 char *data, int tdscnt,
2120 int mdrcnt,int mprcnt,
2121 char **rdata,char **rparam,
2122 int *rdata_len,int *rparam_len)
2124 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2125 char *str2 = skip_string(param,tpscnt,str1);
2126 char *p = skip_string(param,tpscnt,str2);
2127 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2130 char *pathname = NULL;
2131 char *command, *cmdname;
2132 unsigned int offset;
2135 size_t converted_size;
2137 if (!str1 || !str2 || !p) {
2141 /* check it's a supported varient */
2142 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2145 if (!check_share_info(uLevel,str2)) {
2152 /* Do we have a string ? */
2153 if (skip_string(data,mdrcnt,data) == NULL) {
2156 pull_ascii_fstring(sharename,data);
2157 snum = find_service(sharename);
2158 if (snum >= 0) { /* already exists */
2167 /* only support disk share adds */
2168 if (SVAL(data,14)!=STYPE_DISKTREE) {
2172 offset = IVAL(data, 16);
2173 if (offset >= mdrcnt) {
2174 res = ERRinvalidparam;
2178 /* Do we have a string ? */
2179 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2182 pull_ascii_fstring(comment, offset? (data+offset) : "");
2184 offset = IVAL(data, 26);
2186 if (offset >= mdrcnt) {
2187 res = ERRinvalidparam;
2191 /* Do we have a string ? */
2192 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2196 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2197 offset ? (data+offset) : "", &converted_size))
2199 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2207 string_replace(sharename, '"', ' ');
2208 string_replace(pathname, '"', ' ');
2209 string_replace(comment, '"', ' ');
2211 cmdname = lp_add_share_cmd();
2213 if (!cmdname || *cmdname == '\0') {
2217 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2218 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2219 pathname, comment) == -1) {
2223 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2225 if ((res = smbrun(command, NULL)) != 0) {
2226 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2233 message_send_all(smbd_messaging_context(),
2234 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2238 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2242 SSVAL(*rparam,0,NERR_Success);
2243 SSVAL(*rparam,2,0); /* converter word */
2244 SSVAL(*rparam,4,*rdata_len);
2252 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2257 SSVAL(*rparam,0,res);
2262 /****************************************************************************
2263 view list of groups available
2264 ****************************************************************************/
2266 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2267 char *param, int tpscnt,
2268 char *data, int tdscnt,
2269 int mdrcnt,int mprcnt,
2270 char **rdata,char **rparam,
2271 int *rdata_len,int *rparam_len)
2275 int resume_context, cli_buf_size;
2276 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2277 char *str2 = skip_string(param,tpscnt,str1);
2278 char *p = skip_string(param,tpscnt,str2);
2280 uint32_t num_groups;
2281 uint32_t resume_handle;
2282 struct rpc_pipe_client *samr_pipe;
2283 struct policy_handle samr_handle, domain_handle;
2286 if (!str1 || !str2 || !p) {
2290 if (strcmp(str1,"WrLeh") != 0) {
2295 * W-> resume context (number of users to skip)
2296 * r -> return parameter pointer to receive buffer
2297 * L -> length of receive buffer
2298 * e -> return parameter number of entries
2299 * h -> return parameter total number of users
2302 if (strcmp("B21",str2) != 0) {
2306 status = rpc_pipe_open_internal(
2307 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2308 conn->server_info, &samr_pipe);
2309 if (!NT_STATUS_IS_OK(status)) {
2310 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2311 nt_errstr(status)));
2315 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2316 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2317 if (!NT_STATUS_IS_OK(status)) {
2318 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2319 nt_errstr(status)));
2323 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2324 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2325 get_global_sam_sid(), &domain_handle);
2326 if (!NT_STATUS_IS_OK(status)) {
2327 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2328 nt_errstr(status)));
2329 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2333 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2334 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2335 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2336 "%d\n", resume_context, cli_buf_size));
2338 *rdata_len = cli_buf_size;
2339 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2346 errflags = NERR_Success;
2351 struct samr_SamArray *sam_entries;
2352 uint32_t num_entries;
2354 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2359 if (!NT_STATUS_IS_OK(status)) {
2360 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2361 "%s\n", nt_errstr(status)));
2365 if (num_entries == 0) {
2366 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2367 "no entries -- done\n"));
2371 for(i=0; i<num_entries; i++) {
2374 name = sam_entries->entries[i].name.string;
2376 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2377 /* set overflow error */
2378 DEBUG(3,("overflow on entry %d group %s\n", i,
2384 /* truncate the name at 21 chars. */
2386 strlcpy(p, name, 21);
2387 DEBUG(10,("adding entry %d group %s\n", i, p));
2389 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2394 if (errflags != NERR_Success) {
2398 TALLOC_FREE(sam_entries);
2401 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2402 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2404 *rdata_len = PTR_DIFF(p,*rdata);
2407 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2411 SSVAL(*rparam, 0, errflags);
2412 SSVAL(*rparam, 2, 0); /* converter word */
2413 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2414 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2419 /*******************************************************************
2420 Get groups that a user is a member of.
2421 ******************************************************************/
2423 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2424 char *param, int tpscnt,
2425 char *data, int tdscnt,
2426 int mdrcnt,int mprcnt,
2427 char **rdata,char **rparam,
2428 int *rdata_len,int *rparam_len)
2430 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2431 char *str2 = skip_string(param,tpscnt,str1);
2432 char *UserName = skip_string(param,tpscnt,str2);
2433 char *p = skip_string(param,tpscnt,UserName);
2434 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2435 const char *level_string;
2441 struct rpc_pipe_client *samr_pipe;
2442 struct policy_handle samr_handle, domain_handle, user_handle;
2443 struct lsa_String name;
2444 struct lsa_Strings names;
2445 struct samr_Ids type, rid;
2446 struct samr_RidWithAttributeArray *rids;
2449 if (!str1 || !str2 || !UserName || !p) {
2454 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2459 /* check it's a supported varient */
2461 if ( strcmp(str1,"zWrLeh") != 0 )
2466 level_string = "B21";
2472 if (strcmp(level_string,str2) != 0)
2475 *rdata_len = mdrcnt + 1024;
2476 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2481 SSVAL(*rparam,0,NERR_Success);
2482 SSVAL(*rparam,2,0); /* converter word */
2485 endp = *rdata + *rdata_len;
2487 status = rpc_pipe_open_internal(
2488 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2489 conn->server_info, &samr_pipe);
2490 if (!NT_STATUS_IS_OK(status)) {
2491 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2492 nt_errstr(status)));
2496 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2497 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2498 if (!NT_STATUS_IS_OK(status)) {
2499 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2500 nt_errstr(status)));
2504 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2505 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2506 get_global_sam_sid(), &domain_handle);
2507 if (!NT_STATUS_IS_OK(status)) {
2508 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2509 nt_errstr(status)));
2513 name.string = UserName;
2515 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2516 &domain_handle, 1, &name,
2518 if (!NT_STATUS_IS_OK(status)) {
2519 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2520 nt_errstr(status)));
2524 if (type.ids[0] != SID_NAME_USER) {
2525 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2526 sid_type_lookup(type.ids[0])));
2530 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2532 SAMR_USER_ACCESS_GET_GROUPS,
2533 rid.ids[0], &user_handle);
2534 if (!NT_STATUS_IS_OK(status)) {
2535 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2536 nt_errstr(status)));
2540 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2541 &user_handle, &rids);
2542 if (!NT_STATUS_IS_OK(status)) {
2543 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2544 nt_errstr(status)));
2548 for (i=0; i<rids->count; i++) {
2550 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2552 1, &rids->rids[i].rid,
2554 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2555 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2561 *rdata_len = PTR_DIFF(p,*rdata);
2563 SSVAL(*rparam,4,count); /* is this right?? */
2564 SSVAL(*rparam,6,count); /* is this right?? */
2569 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2571 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2573 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2578 /*******************************************************************
2580 ******************************************************************/
2582 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2583 char *param, int tpscnt,
2584 char *data, int tdscnt,
2585 int mdrcnt,int mprcnt,
2586 char **rdata,char **rparam,
2587 int *rdata_len,int *rparam_len)
2592 int i, resume_context, cli_buf_size;
2593 uint32_t resume_handle;
2595 struct rpc_pipe_client *samr_pipe;
2596 struct policy_handle samr_handle, domain_handle;
2599 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2600 char *str2 = skip_string(param,tpscnt,str1);
2601 char *p = skip_string(param,tpscnt,str2);
2604 if (!str1 || !str2 || !p) {
2608 if (strcmp(str1,"WrLeh") != 0)
2611 * W-> resume context (number of users to skip)
2612 * r -> return parameter pointer to receive buffer
2613 * L -> length of receive buffer
2614 * e -> return parameter number of entries
2615 * h -> return parameter total number of users
2618 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2619 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2620 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2621 resume_context, cli_buf_size));
2624 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2629 /* check it's a supported varient */
2630 if (strcmp("B21",str2) != 0)
2633 *rdata_len = cli_buf_size;
2634 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2640 endp = *rdata + *rdata_len;
2642 status = rpc_pipe_open_internal(
2643 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2644 conn->server_info, &samr_pipe);
2645 if (!NT_STATUS_IS_OK(status)) {
2646 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2647 nt_errstr(status)));
2651 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2652 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2653 if (!NT_STATUS_IS_OK(status)) {
2654 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2655 nt_errstr(status)));
2659 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2660 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2661 get_global_sam_sid(), &domain_handle);
2662 if (!NT_STATUS_IS_OK(status)) {
2663 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2664 nt_errstr(status)));
2665 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2669 errflags=NERR_Success;
2674 struct samr_SamArray *sam_entries;
2675 uint32_t num_entries;
2677 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2683 if (!NT_STATUS_IS_OK(status)) {
2684 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2685 "%s\n", nt_errstr(status)));
2689 if (num_entries == 0) {
2690 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2691 "no entries -- done\n"));
2695 for (i=0; i<num_entries; i++) {
2698 name = sam_entries->entries[i].name.string;
2700 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2701 &&(strlen(name)<=21)) {
2702 strlcpy(p,name,PTR_DIFF(endp,p));
2703 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2704 "username %s\n",count_sent,p));
2708 /* set overflow error */
2709 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2710 "username %s\n",count_sent,name));
2716 if (errflags != NERR_Success) {
2720 TALLOC_FREE(sam_entries);
2723 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2724 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2726 *rdata_len = PTR_DIFF(p,*rdata);
2728 SSVAL(*rparam,0,errflags);
2729 SSVAL(*rparam,2,0); /* converter word */
2730 SSVAL(*rparam,4,count_sent); /* is this right?? */
2731 SSVAL(*rparam,6,num_users); /* is this right?? */
2736 /****************************************************************************
2737 Get the time of day info.
2738 ****************************************************************************/
2740 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2741 char *param, int tpscnt,
2742 char *data, int tdscnt,
2743 int mdrcnt,int mprcnt,
2744 char **rdata,char **rparam,
2745 int *rdata_len,int *rparam_len)
2748 time_t unixdate = time(NULL);
2752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2758 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2763 SSVAL(*rparam,0,NERR_Success);
2764 SSVAL(*rparam,2,0); /* converter word */
2768 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2769 by NT in a "net time" operation,
2770 it seems to ignore the one below */
2772 /* the client expects to get localtime, not GMT, in this bit
2773 (I think, this needs testing) */
2774 t = localtime(&unixdate);
2779 SIVAL(p,4,0); /* msecs ? */
2780 SCVAL(p,8,t->tm_hour);
2781 SCVAL(p,9,t->tm_min);
2782 SCVAL(p,10,t->tm_sec);
2783 SCVAL(p,11,0); /* hundredths of seconds */
2784 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2785 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2786 SCVAL(p,16,t->tm_mday);
2787 SCVAL(p,17,t->tm_mon + 1);
2788 SSVAL(p,18,1900+t->tm_year);
2789 SCVAL(p,20,t->tm_wday);
2794 /****************************************************************************
2795 Set the user password.
2796 *****************************************************************************/
2798 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2799 char *param, int tpscnt,
2800 char *data, int tdscnt,
2801 int mdrcnt,int mprcnt,
2802 char **rdata,char **rparam,
2803 int *rdata_len,int *rparam_len)
2805 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2808 fstring pass1,pass2;
2810 /* Skip 2 strings. */
2811 p = skip_string(param,tpscnt,np);
2812 p = skip_string(param,tpscnt,p);
2818 /* Do we have a string ? */
2819 if (skip_string(param,tpscnt,p) == NULL) {
2822 pull_ascii_fstring(user,p);
2824 p = skip_string(param,tpscnt,p);
2829 memset(pass1,'\0',sizeof(pass1));
2830 memset(pass2,'\0',sizeof(pass2));
2832 * We use 31 here not 32 as we're checking
2833 * the last byte we want to access is safe.
2835 if (!is_offset_safe(param,tpscnt,p,31)) {
2839 memcpy(pass2,p+16,16);
2842 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2849 SSVAL(*rparam,0,NERR_badpass);
2850 SSVAL(*rparam,2,0); /* converter word */
2852 DEBUG(3,("Set password for <%s>\n",user));
2855 * Attempt to verify the old password against smbpasswd entries
2856 * Win98 clients send old and new password in plaintext for this call.
2860 struct auth_serversupplied_info *server_info = NULL;
2861 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2863 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2866 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2867 SSVAL(*rparam,0,NERR_Success);
2871 TALLOC_FREE(server_info);
2873 data_blob_clear_free(&password);
2877 * If the plaintext change failed, attempt
2878 * the old encrypted method. NT will generate this
2879 * after trying the samr method. Note that this
2880 * method is done as a last resort as this
2881 * password change method loses the NT password hash
2882 * and cannot change the UNIX password as no plaintext
2886 if(SVAL(*rparam,0) != NERR_Success) {
2887 struct samu *hnd = NULL;
2889 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2891 if (change_lanman_password(hnd,(uchar *)pass2)) {
2892 SSVAL(*rparam,0,NERR_Success);
2899 memset((char *)pass1,'\0',sizeof(fstring));
2900 memset((char *)pass2,'\0',sizeof(fstring));
2905 /****************************************************************************
2906 Set the user password (SamOEM version - gets plaintext).
2907 ****************************************************************************/
2909 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2910 char *param, int tpscnt,
2911 char *data, int tdscnt,
2912 int mdrcnt,int mprcnt,
2913 char **rdata,char **rparam,
2914 int *rdata_len,int *rparam_len)
2916 struct smbd_server_connection *sconn = smbd_server_conn;
2918 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2920 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2930 SSVAL(*rparam,0,NERR_badpass);
2933 * Check the parameter definition is correct.
2936 /* Do we have a string ? */
2937 if (skip_string(param,tpscnt,p) == 0) {
2940 if(!strequal(p, "zsT")) {
2941 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2944 p = skip_string(param, tpscnt, p);
2949 /* Do we have a string ? */
2950 if (skip_string(param,tpscnt,p) == 0) {
2953 if(!strequal(p, "B516B16")) {
2954 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2957 p = skip_string(param,tpscnt,p);
2961 /* Do we have a string ? */
2962 if (skip_string(param,tpscnt,p) == 0) {
2965 p += pull_ascii_fstring(user,p);
2967 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2970 * Pass the user through the NT -> unix user mapping
2974 (void)map_username(sconn, user);
2976 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2977 SSVAL(*rparam,0,NERR_Success);
2983 /****************************************************************************
2986 ****************************************************************************/
2988 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2989 char *param, int tpscnt,
2990 char *data, int tdscnt,
2991 int mdrcnt,int mprcnt,
2992 char **rdata,char **rparam,
2993 int *rdata_len,int *rparam_len)
2995 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2996 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2997 char *str2 = skip_string(param,tpscnt,str1);
2998 char *p = skip_string(param,tpscnt,str2);
3002 WERROR werr = WERR_OK;
3004 TALLOC_CTX *mem_ctx = talloc_tos();
3006 struct rpc_pipe_client *cli = NULL;
3007 struct policy_handle handle;
3008 struct spoolss_DevmodeContainer devmode_ctr;
3009 enum spoolss_JobControl command;
3011 if (!str1 || !str2 || !p) {
3015 * We use 1 here not 2 as we're checking
3016 * the last byte we want to access is safe.
3018 if (!is_offset_safe(param,tpscnt,p,1)) {
3021 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3024 /* check it's a supported varient */
3025 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3029 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3035 ZERO_STRUCT(handle);
3037 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3038 rpc_spoolss_dispatch, conn->server_info,
3040 if (!NT_STATUS_IS_OK(status)) {
3041 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3042 nt_errstr(status)));
3043 errcode = W_ERROR_V(ntstatus_to_werror(status));
3047 ZERO_STRUCT(devmode_ctr);
3049 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3053 SEC_FLAG_MAXIMUM_ALLOWED,
3056 if (!NT_STATUS_IS_OK(status)) {
3057 errcode = W_ERROR_V(ntstatus_to_werror(status));
3060 if (!W_ERROR_IS_OK(werr)) {
3061 errcode = W_ERROR_V(werr);
3065 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3066 * and NERR_DestNotFound if share did not exist */
3068 errcode = NERR_Success;
3071 case 81: /* delete */
3072 command = SPOOLSS_JOB_CONTROL_DELETE;
3074 case 82: /* pause */
3075 command = SPOOLSS_JOB_CONTROL_PAUSE;
3077 case 83: /* resume */
3078 command = SPOOLSS_JOB_CONTROL_RESUME;
3081 errcode = NERR_notsupported;
3085 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3088 NULL, /* unique ptr ctr */
3091 if (!NT_STATUS_IS_OK(status)) {
3092 errcode = W_ERROR_V(ntstatus_to_werror(status));
3095 if (!W_ERROR_IS_OK(werr)) {
3096 errcode = W_ERROR_V(werr);
3101 if (is_valid_policy_hnd(&handle)) {
3102 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3105 SSVAL(*rparam,0,errcode);
3106 SSVAL(*rparam,2,0); /* converter word */
3111 /****************************************************************************
3112 Purge a print queue - or pause or resume it.
3113 ****************************************************************************/
3115 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3116 char *param, int tpscnt,
3117 char *data, int tdscnt,
3118 int mdrcnt,int mprcnt,
3119 char **rdata,char **rparam,
3120 int *rdata_len,int *rparam_len)
3122 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3123 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3124 char *str2 = skip_string(param,tpscnt,str1);
3125 char *QueueName = skip_string(param,tpscnt,str2);
3126 int errcode = NERR_notsupported;
3127 WERROR werr = WERR_OK;
3130 TALLOC_CTX *mem_ctx = talloc_tos();
3131 struct rpc_pipe_client *cli = NULL;
3132 struct policy_handle handle;
3133 struct spoolss_SetPrinterInfoCtr info_ctr;
3134 struct spoolss_DevmodeContainer devmode_ctr;
3135 struct sec_desc_buf secdesc_ctr;
3136 enum spoolss_PrinterControl command;
3138 if (!str1 || !str2 || !QueueName) {
3142 /* check it's a supported varient */
3143 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3147 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3153 if (skip_string(param,tpscnt,QueueName) == NULL) {
3157 ZERO_STRUCT(handle);
3159 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3160 rpc_spoolss_dispatch, conn->server_info,
3162 if (!NT_STATUS_IS_OK(status)) {
3163 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3164 nt_errstr(status)));
3165 errcode = W_ERROR_V(ntstatus_to_werror(status));
3169 ZERO_STRUCT(devmode_ctr);
3171 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3175 SEC_FLAG_MAXIMUM_ALLOWED,
3178 if (!NT_STATUS_IS_OK(status)) {
3179 errcode = W_ERROR_V(ntstatus_to_werror(status));
3182 if (!W_ERROR_IS_OK(werr)) {
3183 errcode = W_ERROR_V(werr);
3188 case 74: /* Pause queue */
3189 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3191 case 75: /* Resume queue */
3192 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3194 case 103: /* Purge */
3195 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3198 werr = WERR_NOT_SUPPORTED;
3202 if (!W_ERROR_IS_OK(werr)) {
3203 errcode = W_ERROR_V(werr);
3207 ZERO_STRUCT(info_ctr);
3208 ZERO_STRUCT(secdesc_ctr);
3210 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3217 if (!NT_STATUS_IS_OK(status)) {
3218 errcode = W_ERROR_V(ntstatus_to_werror(status));
3221 if (!W_ERROR_IS_OK(werr)) {
3222 errcode = W_ERROR_V(werr);
3226 errcode = W_ERROR_V(werr);
3230 if (is_valid_policy_hnd(&handle)) {
3231 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3234 SSVAL(*rparam,0,errcode);
3235 SSVAL(*rparam,2,0); /* converter word */
3240 /****************************************************************************
3241 set the property of a print job (undocumented?)
3242 ? function = 0xb -> set name of print job
3243 ? function = 0x6 -> move print job up/down
3244 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3245 or <WWsTP> <WB21BB16B10zWWzDDz>
3246 ****************************************************************************/
3248 static int check_printjob_info(struct pack_desc* desc,
3249 int uLevel, char* id)
3251 desc->subformat = NULL;
3253 case 0: desc->format = "W"; break;
3254 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3255 case 2: desc->format = "WWzWWDDzz"; break;
3256 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3257 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3259 DEBUG(0,("check_printjob_info: invalid level %d\n",
3263 if (id == NULL || strcmp(desc->format,id) != 0) {
3264 DEBUG(0,("check_printjob_info: invalid format %s\n",
3265 id ? id : "<NULL>" ));
3271 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3272 char *param, int tpscnt,
3273 char *data, int tdscnt,
3274 int mdrcnt,int mprcnt,
3275 char **rdata,char **rparam,
3276 int *rdata_len,int *rparam_len)
3278 struct pack_desc desc;
3279 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3280 char *str2 = skip_string(param,tpscnt,str1);
3281 char *p = skip_string(param,tpscnt,str2);
3284 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3285 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3288 TALLOC_CTX *mem_ctx = talloc_tos();
3291 struct rpc_pipe_client *cli = NULL;
3292 struct policy_handle handle;
3293 struct spoolss_DevmodeContainer devmode_ctr;
3294 struct spoolss_JobInfoContainer ctr;
3295 union spoolss_JobInfo info;
3296 struct spoolss_SetJobInfo1 info1;
3298 if (!str1 || !str2 || !p) {
3302 * We use 1 here not 2 as we're checking
3303 * the last byte we want to access is safe.
3305 if (!is_offset_safe(param,tpscnt,p,1)) {
3308 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3311 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3316 ZERO_STRUCT(handle);
3318 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3319 rpc_spoolss_dispatch, conn->server_info,
3321 if (!NT_STATUS_IS_OK(status)) {
3322 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3323 nt_errstr(status)));
3324 errcode = W_ERROR_V(ntstatus_to_werror(status));
3328 ZERO_STRUCT(devmode_ctr);
3330 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3334 SEC_FLAG_MAXIMUM_ALLOWED,
3337 if (!NT_STATUS_IS_OK(status)) {
3338 errcode = W_ERROR_V(ntstatus_to_werror(status));
3341 if (!W_ERROR_IS_OK(werr)) {
3342 errcode = W_ERROR_V(werr);
3348 /* check it's a supported varient */
3349 if ((strcmp(str1,"WWsTP")) ||
3350 (!check_printjob_info(&desc,uLevel,str2)))
3353 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3359 if (!W_ERROR_IS_OK(werr)) {
3360 errcode = W_ERROR_V(werr);
3364 errcode = NERR_notsupported;
3368 /* change print job name, data gives the name */
3376 info1.job_id = info.info1.job_id;
3377 info1.printer_name = info.info1.printer_name;
3378 info1.user_name = info.info1.user_name;
3379 info1.document_name = data;
3380 info1.data_type = info.info1.data_type;
3381 info1.text_status = info.info1.text_status;
3382 info1.status = info.info1.status;
3383 info1.priority = info.info1.priority;
3384 info1.position = info.info1.position;
3385 info1.total_pages = info.info1.total_pages;
3386 info1.pages_printed = info.info1.pages_printed;
3387 info1.submitted = info.info1.submitted;
3390 ctr.info.info1 = &info1;
3392 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3398 if (!NT_STATUS_IS_OK(status)) {
3399 errcode = W_ERROR_V(ntstatus_to_werror(status));
3402 if (!W_ERROR_IS_OK(werr)) {
3403 errcode = W_ERROR_V(werr);
3407 errcode = NERR_Success;
3410 if (is_valid_policy_hnd(&handle)) {
3411 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3414 SSVALS(*rparam,0,errcode);
3415 SSVAL(*rparam,2,0); /* converter word */
3421 /****************************************************************************
3422 Get info about the server.
3423 ****************************************************************************/
3425 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3426 char *param, int tpscnt,
3427 char *data, int tdscnt,
3428 int mdrcnt,int mprcnt,
3429 char **rdata,char **rparam,
3430 int *rdata_len,int *rparam_len)
3432 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3433 char *str2 = skip_string(param,tpscnt,str1);
3434 char *p = skip_string(param,tpscnt,str2);
3435 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3439 if (!str1 || !str2 || !p) {
3443 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3445 /* check it's a supported varient */
3446 if (!prefix_ok(str1,"WrLh")) {
3452 if (strcmp(str2,"B16") != 0) {
3458 if (strcmp(str2,"B16BBDz") != 0) {
3464 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3470 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3476 if (strcmp(str2,"DN") != 0) {
3482 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3491 *rdata_len = mdrcnt;
3492 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3498 p2 = p + struct_len;
3500 srvstr_push(NULL, 0, p,global_myname(),16,
3501 STR_ASCII|STR_UPPER|STR_TERMINATE);
3505 struct srv_info_struct *servers=NULL;
3507 char *comment = NULL;
3508 TALLOC_CTX *ctx = talloc_tos();
3509 uint32 servertype= lp_default_server_announce();
3511 comment = talloc_strdup(ctx,lp_serverstring());
3516 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3517 for (i=0;i<count;i++) {
3518 if (strequal(servers[i].name,global_myname())) {
3519 servertype = servers[i].type;
3520 TALLOC_FREE(comment);
3521 comment = talloc_strdup(ctx,
3522 servers[i].comment);
3532 SCVAL(p,0,lp_major_announce_version());
3533 SCVAL(p,1,lp_minor_announce_version());
3534 SIVAL(p,2,servertype);
3536 if (mdrcnt == struct_len) {
3539 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3540 comment = talloc_sub_advanced(
3542 lp_servicename(SNUM(conn)),
3543 conn->server_info->unix_name,
3545 conn->server_info->utok.gid,
3546 conn->server_info->sanitized_username,
3547 pdb_get_domain(conn->server_info->sam_account),
3552 if (mdrcnt - struct_len <= 0) {
3557 MIN(mdrcnt - struct_len,
3558 MAX_SERVER_STRING_LENGTH),
3560 p2 = skip_string(*rdata,*rdata_len,p2);
3568 return False; /* not yet implemented */
3571 *rdata_len = PTR_DIFF(p2,*rdata);
3574 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3578 SSVAL(*rparam,0,NERR_Success);
3579 SSVAL(*rparam,2,0); /* converter word */
3580 SSVAL(*rparam,4,*rdata_len);
3585 /****************************************************************************
3586 Get info about the server.
3587 ****************************************************************************/
3589 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3590 char *param, int tpscnt,
3591 char *data, int tdscnt,
3592 int mdrcnt,int mprcnt,
3593 char **rdata,char **rparam,
3594 int *rdata_len,int *rparam_len)
3596 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3597 char *str2 = skip_string(param,tpscnt,str1);
3598 char *p = skip_string(param,tpscnt,str2);
3601 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3603 if (!str1 || !str2 || !p) {
3607 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3610 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3615 /* check it's a supported varient */
3616 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3620 *rdata_len = mdrcnt + 1024;
3621 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3626 SSVAL(*rparam,0,NERR_Success);
3627 SSVAL(*rparam,2,0); /* converter word */
3630 endp = *rdata + *rdata_len;
3632 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3637 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3638 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3640 p2 = skip_string(*rdata,*rdata_len,p2);
3646 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3647 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3648 p2 = skip_string(*rdata,*rdata_len,p2);
3654 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3655 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3657 p2 = skip_string(*rdata,*rdata_len,p2);
3663 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3664 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3667 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3668 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3669 p2 = skip_string(*rdata,*rdata_len,p2);
3675 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3676 strlcpy(p2,"",PTR_DIFF(endp,p2));
3677 p2 = skip_string(*rdata,*rdata_len,p2);
3683 *rdata_len = PTR_DIFF(p2,*rdata);
3685 SSVAL(*rparam,4,*rdata_len);
3690 /****************************************************************************
3691 get info about a user
3693 struct user_info_11 {
3694 char usri11_name[21]; 0-20
3696 char *usri11_comment; 22-25
3697 char *usri11_usr_comment; 26-29
3698 unsigned short usri11_priv; 30-31
3699 unsigned long usri11_auth_flags; 32-35
3700 long usri11_password_age; 36-39
3701 char *usri11_homedir; 40-43
3702 char *usri11_parms; 44-47
3703 long usri11_last_logon; 48-51
3704 long usri11_last_logoff; 52-55
3705 unsigned short usri11_bad_pw_count; 56-57
3706 unsigned short usri11_num_logons; 58-59
3707 char *usri11_logon_server; 60-63
3708 unsigned short usri11_country_code; 64-65
3709 char *usri11_workstations; 66-69
3710 unsigned long usri11_max_storage; 70-73
3711 unsigned short usri11_units_per_week; 74-75
3712 unsigned char *usri11_logon_hours; 76-79
3713 unsigned short usri11_code_page; 80-81
3718 usri11_name specifies the user name for which information is retrieved
3720 usri11_pad aligns the next data structure element to a word boundary
3722 usri11_comment is a null terminated ASCII comment
3724 usri11_user_comment is a null terminated ASCII comment about the user
3726 usri11_priv specifies the level of the privilege assigned to the user.
3727 The possible values are:
3729 Name Value Description
3730 USER_PRIV_GUEST 0 Guest privilege
3731 USER_PRIV_USER 1 User privilege
3732 USER_PRV_ADMIN 2 Administrator privilege
3734 usri11_auth_flags specifies the account operator privileges. The
3735 possible values are:
3737 Name Value Description
3738 AF_OP_PRINT 0 Print operator
3741 Leach, Naik [Page 28]
3745 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3748 AF_OP_COMM 1 Communications operator
3749 AF_OP_SERVER 2 Server operator
3750 AF_OP_ACCOUNTS 3 Accounts operator
3753 usri11_password_age specifies how many seconds have elapsed since the
3754 password was last changed.
3756 usri11_home_dir points to a null terminated ASCII string that contains
3757 the path name of the user's home directory.
3759 usri11_parms points to a null terminated ASCII string that is set
3760 aside for use by applications.
3762 usri11_last_logon specifies the time when the user last logged on.
3763 This value is stored as the number of seconds elapsed since
3764 00:00:00, January 1, 1970.
3766 usri11_last_logoff specifies the time when the user last logged off.
3767 This value is stored as the number of seconds elapsed since
3768 00:00:00, January 1, 1970. A value of 0 means the last logoff
3771 usri11_bad_pw_count specifies the number of incorrect passwords
3772 entered since the last successful logon.
3774 usri11_log1_num_logons specifies the number of times this user has
3775 logged on. A value of -1 means the number of logons is unknown.
3777 usri11_logon_server points to a null terminated ASCII string that
3778 contains the name of the server to which logon requests are sent.
3779 A null string indicates logon requests should be sent to the
3782 usri11_country_code specifies the country code for the user's language
3785 usri11_workstations points to a null terminated ASCII string that
3786 contains the names of workstations the user may log on from.
3787 There may be up to 8 workstations, with the names separated by
3788 commas. A null strings indicates there are no restrictions.
3790 usri11_max_storage specifies the maximum amount of disk space the user
3791 can occupy. A value of 0xffffffff indicates there are no
3794 usri11_units_per_week specifies the equal number of time units into
3795 which a week is divided. This value must be equal to 168.
3797 usri11_logon_hours points to a 21 byte (168 bits) string that
3798 specifies the time during which the user can log on. Each bit
3799 represents one unique hour in a week. The first bit (bit 0, word
3800 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3804 Leach, Naik [Page 29]
3808 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3811 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3812 are no restrictions.
3814 usri11_code_page specifies the code page for the user's language of
3817 All of the pointers in this data structure need to be treated
3818 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3819 to be ignored. The converter word returned in the parameters section
3820 needs to be subtracted from the lower 16 bits to calculate an offset
3821 into the return buffer where this ASCII string resides.
3823 There is no auxiliary data in the response.
3825 ****************************************************************************/
3827 #define usri11_name 0
3828 #define usri11_pad 21
3829 #define usri11_comment 22
3830 #define usri11_usr_comment 26
3831 #define usri11_full_name 30
3832 #define usri11_priv 34
3833 #define usri11_auth_flags 36
3834 #define usri11_password_age 40
3835 #define usri11_homedir 44
3836 #define usri11_parms 48
3837 #define usri11_last_logon 52
3838 #define usri11_last_logoff 56
3839 #define usri11_bad_pw_count 60
3840 #define usri11_num_logons 62
3841 #define usri11_logon_server 64
3842 #define usri11_country_code 68
3843 #define usri11_workstations 70
3844 #define usri11_max_storage 74
3845 #define usri11_units_per_week 78
3846 #define usri11_logon_hours 80
3847 #define usri11_code_page 84
3848 #define usri11_end 86
3850 #define USER_PRIV_GUEST 0
3851 #define USER_PRIV_USER 1
3852 #define USER_PRIV_ADMIN 2
3854 #define AF_OP_PRINT 0
3855 #define AF_OP_COMM 1
3856 #define AF_OP_SERVER 2
3857 #define AF_OP_ACCOUNTS 3
3860 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3861 char *param, int tpscnt,
3862 char *data, int tdscnt,
3863 int mdrcnt,int mprcnt,
3864 char **rdata,char **rparam,
3865 int *rdata_len,int *rparam_len)
3867 struct smbd_server_connection *sconn = smbd_server_conn;
3868 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3869 char *str2 = skip_string(param,tpscnt,str1);
3870 char *UserName = skip_string(param,tpscnt,str2);
3871 char *p = skip_string(param,tpscnt,UserName);
3872 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3875 const char *level_string;
3877 /* get NIS home of a previously validated user - simeon */
3878 /* With share level security vuid will always be zero.
3879 Don't depend on vuser being non-null !!. JRA */
3880 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3882 DEBUG(3,(" Username of UID %d is %s\n",
3883 (int)vuser->server_info->utok.uid,
3884 vuser->server_info->unix_name));
3887 if (!str1 || !str2 || !UserName || !p) {
3892 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3897 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3899 /* check it's a supported variant */
3900 if (strcmp(str1,"zWrLh") != 0) {
3904 case 0: level_string = "B21"; break;
3905 case 1: level_string = "B21BB16DWzzWz"; break;
3906 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3907 case 10: level_string = "B21Bzzz"; break;
3908 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3909 default: return False;
3912 if (strcmp(level_string,str2) != 0) {
3916 *rdata_len = mdrcnt + 1024;
3917 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3922 SSVAL(*rparam,0,NERR_Success);
3923 SSVAL(*rparam,2,0); /* converter word */
3926 endp = *rdata + *rdata_len;
3927 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3933 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3936 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3941 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3942 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3943 p2 = skip_string(*rdata,*rdata_len,p2);
3948 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3949 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3950 p2 = skip_string(*rdata,*rdata_len,p2);
3955 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3956 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3957 strlcpy(p2,((vuser != NULL)
3958 ? pdb_get_fullname(vuser->server_info->sam_account)
3959 : UserName),PTR_DIFF(endp,p2));
3960 p2 = skip_string(*rdata,*rdata_len,p2);
3967 const char *homedir = "";
3968 if (vuser != NULL) {
3969 homedir = pdb_get_homedir(
3970 vuser->server_info->sam_account);
3972 /* modelled after NTAS 3.51 reply */
3973 SSVAL(p,usri11_priv,
3974 (get_current_uid(conn) == sec_initial_uid())?
3975 USER_PRIV_ADMIN:USER_PRIV_USER);
3976 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3977 SIVALS(p,usri11_password_age,-1); /* password age */
3978 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3979 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3980 p2 = skip_string(*rdata,*rdata_len,p2);
3984 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3985 strlcpy(p2,"",PTR_DIFF(endp,p2));
3986 p2 = skip_string(*rdata,*rdata_len,p2);
3990 SIVAL(p,usri11_last_logon,0); /* last logon */
3991 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3992 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3993 SSVALS(p,usri11_num_logons,-1); /* num logons */
3994 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3995 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3996 p2 = skip_string(*rdata,*rdata_len,p2);
4000 SSVAL(p,usri11_country_code,0); /* country code */
4002 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4003 strlcpy(p2,"",PTR_DIFF(endp,p2));
4004 p2 = skip_string(*rdata,*rdata_len,p2);
4009 SIVALS(p,usri11_max_storage,-1); /* max storage */
4010 SSVAL(p,usri11_units_per_week,168); /* units per week */
4011 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4013 /* a simple way to get logon hours at all times. */
4015 SCVAL(p2,21,0); /* fix zero termination */
4016 p2 = skip_string(*rdata,*rdata_len,p2);
4021 SSVAL(p,usri11_code_page,0); /* code page */
4024 if (uLevel == 1 || uLevel == 2) {
4025 memset(p+22,' ',16); /* password */
4026 SIVALS(p,38,-1); /* password age */
4028 (get_current_uid(conn) == sec_initial_uid())?
4029 USER_PRIV_ADMIN:USER_PRIV_USER);
4030 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4031 strlcpy(p2, vuser ? pdb_get_homedir(
4032 vuser->server_info->sam_account) : "",
4034 p2 = skip_string(*rdata,*rdata_len,p2);
4038 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4040 SSVAL(p,52,0); /* flags */
4041 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4042 strlcpy(p2, vuser ? pdb_get_logon_script(
4043 vuser->server_info->sam_account) : "",
4045 p2 = skip_string(*rdata,*rdata_len,p2);
4050 SIVAL(p,60,0); /* auth_flags */
4051 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4052 strlcpy(p2,((vuser != NULL)
4053 ? pdb_get_fullname(vuser->server_info->sam_account)
4054 : UserName),PTR_DIFF(endp,p2));
4055 p2 = skip_string(*rdata,*rdata_len,p2);
4059 SIVAL(p,68,0); /* urs_comment */
4060 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4061 strlcpy(p2,"",PTR_DIFF(endp,p2));
4062 p2 = skip_string(*rdata,*rdata_len,p2);
4066 SIVAL(p,76,0); /* workstations */
4067 SIVAL(p,80,0); /* last_logon */
4068 SIVAL(p,84,0); /* last_logoff */
4069 SIVALS(p,88,-1); /* acct_expires */
4070 SIVALS(p,92,-1); /* max_storage */
4071 SSVAL(p,96,168); /* units_per_week */
4072 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4075 SSVALS(p,102,-1); /* bad_pw_count */
4076 SSVALS(p,104,-1); /* num_logons */
4077 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4079 TALLOC_CTX *ctx = talloc_tos();
4080 int space_rem = *rdata_len - (p2 - *rdata);
4083 if (space_rem <= 0) {
4086 tmp = talloc_strdup(ctx, "\\\\%L");
4090 tmp = talloc_sub_basic(ctx,
4103 p2 = skip_string(*rdata,*rdata_len,p2);
4107 SSVAL(p,110,49); /* country_code */
4108 SSVAL(p,112,860); /* code page */
4112 *rdata_len = PTR_DIFF(p2,*rdata);
4114 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4119 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4120 char *param, int tpscnt,
4121 char *data, int tdscnt,
4122 int mdrcnt,int mprcnt,
4123 char **rdata,char **rparam,
4124 int *rdata_len,int *rparam_len)
4126 struct smbd_server_connection *sconn = smbd_server_conn;
4127 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4128 char *str2 = skip_string(param,tpscnt,str1);
4129 char *p = skip_string(param,tpscnt,str2);
4131 struct pack_desc desc;
4133 /* With share level security vuid will always be zero.
4134 Don't depend on vuser being non-null !!. JRA */
4135 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4137 if (!str1 || !str2 || !p) {
4142 DEBUG(3,(" Username of UID %d is %s\n",
4143 (int)vuser->server_info->utok.uid,
4144 vuser->server_info->unix_name));
4147 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4148 name = get_safe_str_ptr(param,tpscnt,p,2);
4153 memset((char *)&desc,'\0',sizeof(desc));
4155 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4157 /* check it's a supported varient */
4158 if (strcmp(str1,"OOWb54WrLh") != 0) {
4161 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4165 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4172 desc.buflen = mdrcnt;
4173 desc.subformat = NULL;
4176 if (init_package(&desc,1,0)) {
4177 PACKI(&desc,"W",0); /* code */
4178 PACKS(&desc,"B21",name); /* eff. name */
4179 PACKS(&desc,"B",""); /* pad */
4181 (get_current_uid(conn) == sec_initial_uid())?
4182 USER_PRIV_ADMIN:USER_PRIV_USER);
4183 PACKI(&desc,"D",0); /* auth flags XXX */
4184 PACKI(&desc,"W",0); /* num logons */
4185 PACKI(&desc,"W",0); /* bad pw count */
4186 PACKI(&desc,"D",0); /* last logon */
4187 PACKI(&desc,"D",-1); /* last logoff */
4188 PACKI(&desc,"D",-1); /* logoff time */
4189 PACKI(&desc,"D",-1); /* kickoff time */
4190 PACKI(&desc,"D",0); /* password age */
4191 PACKI(&desc,"D",0); /* password can change */
4192 PACKI(&desc,"D",-1); /* password must change */
4196 fstrcpy(mypath,"\\\\");
4197 fstrcat(mypath,get_local_machine_name());
4199 PACKS(&desc,"z",mypath); /* computer */
4202 PACKS(&desc,"z",lp_workgroup());/* domain */
4203 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4204 vuser->server_info->sam_account) : ""); /* script path */
4205 PACKI(&desc,"D",0x00000000); /* reserved */
4208 *rdata_len = desc.usedlen;
4210 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4214 SSVALS(*rparam,0,desc.errcode);
4216 SSVAL(*rparam,4,desc.neededlen);
4218 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4223 /****************************************************************************
4224 api_WAccessGetUserPerms
4225 ****************************************************************************/
4227 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4228 char *param, int tpscnt,
4229 char *data, int tdscnt,
4230 int mdrcnt,int mprcnt,
4231 char **rdata,char **rparam,
4232 int *rdata_len,int *rparam_len)
4234 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4235 char *str2 = skip_string(param,tpscnt,str1);
4236 char *user = skip_string(param,tpscnt,str2);
4237 char *resource = skip_string(param,tpscnt,user);
4239 if (!str1 || !str2 || !user || !resource) {
4243 if (skip_string(param,tpscnt,resource) == NULL) {
4246 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4248 /* check it's a supported varient */
4249 if (strcmp(str1,"zzh") != 0) {
4252 if (strcmp(str2,"") != 0) {
4257 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4261 SSVALS(*rparam,0,0); /* errorcode */
4262 SSVAL(*rparam,2,0); /* converter word */
4263 SSVAL(*rparam,4,0x7f); /* permission flags */
4268 /****************************************************************************
4269 api_WPrintJobEnumerate
4270 ****************************************************************************/
4272 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4273 char *param, int tpscnt,
4274 char *data, int tdscnt,
4275 int mdrcnt,int mprcnt,
4276 char **rdata,char **rparam,
4277 int *rdata_len,int *rparam_len)
4279 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4280 char *str2 = skip_string(param,tpscnt,str1);
4281 char *p = skip_string(param,tpscnt,str2);
4285 struct pack_desc desc;
4288 TALLOC_CTX *mem_ctx = talloc_tos();
4291 struct rpc_pipe_client *cli = NULL;
4292 struct policy_handle handle;
4293 struct spoolss_DevmodeContainer devmode_ctr;
4294 union spoolss_JobInfo info;
4296 if (!str1 || !str2 || !p) {
4300 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4302 memset((char *)&desc,'\0',sizeof(desc));
4303 memset((char *)&status,'\0',sizeof(status));
4305 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4307 /* check it's a supported varient */
4308 if (strcmp(str1,"WWrLh") != 0) {
4311 if (!check_printjob_info(&desc,uLevel,str2)) {
4315 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4319 ZERO_STRUCT(handle);
4321 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4322 rpc_spoolss_dispatch, conn->server_info,
4324 if (!NT_STATUS_IS_OK(status)) {
4325 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4326 nt_errstr(status)));
4327 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4331 ZERO_STRUCT(devmode_ctr);
4333 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4337 SEC_FLAG_MAXIMUM_ALLOWED,
4340 if (!NT_STATUS_IS_OK(status)) {
4341 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4344 if (!W_ERROR_IS_OK(werr)) {
4345 desc.errcode = W_ERROR_V(werr);
4349 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4355 if (!W_ERROR_IS_OK(werr)) {
4356 desc.errcode = W_ERROR_V(werr);
4361 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4366 desc.buflen = mdrcnt;
4369 * Don't return data but need to get correct length
4370 * init_package will return wrong size if buflen=0
4372 desc.buflen = getlen(desc.format);
4373 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4376 if (init_package(&desc,1,0)) {
4377 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4378 *rdata_len = desc.usedlen;
4380 desc.errcode = NERR_JobNotFound;
4384 if (is_valid_policy_hnd(&handle)) {
4385 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4389 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4393 SSVALS(*rparam,0,desc.errcode);
4395 SSVAL(*rparam,4,desc.neededlen);
4399 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4404 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4405 char *param, int tpscnt,
4406 char *data, int tdscnt,
4407 int mdrcnt,int mprcnt,
4408 char **rdata,char **rparam,
4409 int *rdata_len,int *rparam_len)
4411 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4412 char *str2 = skip_string(param,tpscnt,str1);
4413 char *p = skip_string(param,tpscnt,str2);
4417 struct pack_desc desc;
4419 TALLOC_CTX *mem_ctx = talloc_tos();
4422 struct rpc_pipe_client *cli = NULL;
4423 struct policy_handle handle;
4424 struct spoolss_DevmodeContainer devmode_ctr;
4426 union spoolss_JobInfo *info;
4428 if (!str1 || !str2 || !p) {
4432 memset((char *)&desc,'\0',sizeof(desc));
4434 p = skip_string(param,tpscnt,p);
4438 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4440 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4442 /* check it's a supported variant */
4443 if (strcmp(str1,"zWrLeh") != 0) {
4448 return False; /* defined only for uLevel 0,1,2 */
4451 if (!check_printjob_info(&desc,uLevel,str2)) {
4455 ZERO_STRUCT(handle);
4457 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4458 rpc_spoolss_dispatch, conn->server_info,
4460 if (!NT_STATUS_IS_OK(status)) {
4461 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4462 nt_errstr(status)));
4463 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4467 ZERO_STRUCT(devmode_ctr);
4469 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4473 SEC_FLAG_MAXIMUM_ALLOWED,
4476 if (!NT_STATUS_IS_OK(status)) {
4477 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4480 if (!W_ERROR_IS_OK(werr)) {
4481 desc.errcode = W_ERROR_V(werr);
4485 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4493 if (!W_ERROR_IS_OK(werr)) {
4494 desc.errcode = W_ERROR_V(werr);
4499 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4505 desc.buflen = mdrcnt;
4507 if (init_package(&desc,count,0)) {
4509 for (i = 0; i < count; i++) {
4510 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4511 if (desc.errcode == NERR_Success) {
4517 if (is_valid_policy_hnd(&handle)) {
4518 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4521 *rdata_len = desc.usedlen;
4524 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4528 SSVALS(*rparam,0,desc.errcode);
4530 SSVAL(*rparam,4,succnt);
4531 SSVAL(*rparam,6,count);
4533 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4538 static int check_printdest_info(struct pack_desc* desc,
4539 int uLevel, char* id)
4541 desc->subformat = NULL;
4544 desc->format = "B9";
4547 desc->format = "B9B21WWzW";
4553 desc->format = "zzzWWzzzWW";
4556 DEBUG(0,("check_printdest_info: invalid level %d\n",
4560 if (id == NULL || strcmp(desc->format,id) != 0) {
4561 DEBUG(0,("check_printdest_info: invalid string %s\n",
4562 id ? id : "<NULL>" ));
4568 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4569 struct pack_desc* desc)
4573 strncpy(buf, info2->printername, sizeof(buf)-1);
4574 buf[sizeof(buf)-1] = 0;
4578 PACKS(desc,"B9",buf); /* szName */
4580 PACKS(desc,"B21",""); /* szUserName */
4581 PACKI(desc,"W",0); /* uJobId */
4582 PACKI(desc,"W",0); /* fsStatus */
4583 PACKS(desc,"z",""); /* pszStatus */
4584 PACKI(desc,"W",0); /* time */
4588 if (uLevel == 2 || uLevel == 3) {
4589 PACKS(desc,"z",buf); /* pszPrinterName */
4591 PACKS(desc,"z",""); /* pszUserName */
4592 PACKS(desc,"z",""); /* pszLogAddr */
4593 PACKI(desc,"W",0); /* uJobId */
4594 PACKI(desc,"W",0); /* fsStatus */
4595 PACKS(desc,"z",""); /* pszStatus */
4596 PACKS(desc,"z",""); /* pszComment */
4597 PACKS(desc,"z","NULL"); /* pszDrivers */
4598 PACKI(desc,"W",0); /* time */
4599 PACKI(desc,"W",0); /* pad1 */
4604 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4605 char *param, int tpscnt,
4606 char *data, int tdscnt,
4607 int mdrcnt,int mprcnt,
4608 char **rdata,char **rparam,
4609 int *rdata_len,int *rparam_len)
4611 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4612 char *str2 = skip_string(param,tpscnt,str1);
4613 char *p = skip_string(param,tpscnt,str2);
4614 char* PrinterName = p;
4616 struct pack_desc desc;
4619 TALLOC_CTX *mem_ctx = talloc_tos();
4622 struct rpc_pipe_client *cli = NULL;
4623 struct policy_handle handle;
4624 struct spoolss_DevmodeContainer devmode_ctr;
4625 union spoolss_PrinterInfo info;
4627 if (!str1 || !str2 || !p) {
4631 memset((char *)&desc,'\0',sizeof(desc));
4633 p = skip_string(param,tpscnt,p);
4637 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4639 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4641 /* check it's a supported varient */
4642 if (strcmp(str1,"zWrLh") != 0) {
4645 if (!check_printdest_info(&desc,uLevel,str2)) {
4649 ZERO_STRUCT(handle);
4651 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4652 rpc_spoolss_dispatch, conn->server_info,
4654 if (!NT_STATUS_IS_OK(status)) {
4655 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4656 nt_errstr(status)));
4657 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4661 ZERO_STRUCT(devmode_ctr);
4663 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4667 SEC_FLAG_MAXIMUM_ALLOWED,
4670 if (!NT_STATUS_IS_OK(status)) {
4672 desc.errcode = NERR_DestNotFound;
4676 if (!W_ERROR_IS_OK(werr)) {
4678 desc.errcode = NERR_DestNotFound;
4683 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4688 if (!W_ERROR_IS_OK(werr)) {
4690 desc.errcode = NERR_DestNotFound;
4696 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4701 desc.buflen = mdrcnt;
4704 * Don't return data but need to get correct length
4705 * init_package will return wrong size if buflen=0
4707 desc.buflen = getlen(desc.format);
4708 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4710 if (init_package(&desc,1,0)) {
4711 fill_printdest_info(&info.info2, uLevel,&desc);
4715 if (is_valid_policy_hnd(&handle)) {
4716 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4719 *rdata_len = desc.usedlen;
4722 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4726 SSVALS(*rparam,0,desc.errcode);
4728 SSVAL(*rparam,4,desc.neededlen);
4730 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4736 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4737 char *param, int tpscnt,
4738 char *data, int tdscnt,
4739 int mdrcnt,int mprcnt,
4740 char **rdata,char **rparam,
4741 int *rdata_len,int *rparam_len)
4743 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4744 char *str2 = skip_string(param,tpscnt,str1);
4745 char *p = skip_string(param,tpscnt,str2);
4749 struct pack_desc desc;
4751 TALLOC_CTX *mem_ctx = talloc_tos();
4754 struct rpc_pipe_client *cli = NULL;
4755 union spoolss_PrinterInfo *info;
4758 if (!str1 || !str2 || !p) {
4762 memset((char *)&desc,'\0',sizeof(desc));
4764 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4766 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4768 /* check it's a supported varient */
4769 if (strcmp(str1,"WrLeh") != 0) {
4772 if (!check_printdest_info(&desc,uLevel,str2)) {
4778 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4779 rpc_spoolss_dispatch, conn->server_info,
4781 if (!NT_STATUS_IS_OK(status)) {
4782 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4783 nt_errstr(status)));
4784 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4788 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4790 cli->srv_name_slash,
4795 if (!W_ERROR_IS_OK(werr)) {
4796 desc.errcode = W_ERROR_V(werr);
4798 desc.errcode = NERR_DestNotFound;
4806 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4813 desc.buflen = mdrcnt;
4814 if (init_package(&desc,queuecnt,0)) {
4817 for (i = 0; i < count; i++) {
4818 fill_printdest_info(&info[i].info2, uLevel,&desc);
4820 if (desc.errcode == NERR_Success) {
4826 *rdata_len = desc.usedlen;
4829 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4833 SSVALS(*rparam,0,desc.errcode);
4835 SSVAL(*rparam,4,succnt);
4836 SSVAL(*rparam,6,queuecnt);
4838 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4843 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4844 char *param, int tpscnt,
4845 char *data, int tdscnt,
4846 int mdrcnt,int mprcnt,
4847 char **rdata,char **rparam,
4848 int *rdata_len,int *rparam_len)
4850 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4851 char *str2 = skip_string(param,tpscnt,str1);
4852 char *p = skip_string(param,tpscnt,str2);
4855 struct pack_desc desc;
4857 if (!str1 || !str2 || !p) {
4861 memset((char *)&desc,'\0',sizeof(desc));
4863 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4865 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4867 /* check it's a supported varient */
4868 if (strcmp(str1,"WrLeh") != 0) {
4871 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4876 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4882 desc.buflen = mdrcnt;
4883 if (init_package(&desc,1,0)) {
4884 PACKS(&desc,"B41","NULL");
4887 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4889 *rdata_len = desc.usedlen;
4892 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4896 SSVALS(*rparam,0,desc.errcode);
4898 SSVAL(*rparam,4,succnt);
4901 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4906 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4907 char *param, int tpscnt,
4908 char *data, int tdscnt,
4909 int mdrcnt,int mprcnt,
4910 char **rdata,char **rparam,
4911 int *rdata_len,int *rparam_len)
4913 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4914 char *str2 = skip_string(param,tpscnt,str1);
4915 char *p = skip_string(param,tpscnt,str2);
4918 struct pack_desc desc;
4920 if (!str1 || !str2 || !p) {
4923 memset((char *)&desc,'\0',sizeof(desc));
4925 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4927 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4929 /* check it's a supported varient */
4930 if (strcmp(str1,"WrLeh") != 0) {
4933 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4938 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4944 desc.buflen = mdrcnt;
4946 if (init_package(&desc,1,0)) {
4947 PACKS(&desc,"B13","lpd");
4950 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4952 *rdata_len = desc.usedlen;
4955 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4959 SSVALS(*rparam,0,desc.errcode);
4961 SSVAL(*rparam,4,succnt);
4964 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4969 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4970 char *param, int tpscnt,
4971 char *data, int tdscnt,
4972 int mdrcnt,int mprcnt,
4973 char **rdata,char **rparam,
4974 int *rdata_len,int *rparam_len)
4976 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4977 char *str2 = skip_string(param,tpscnt,str1);
4978 char *p = skip_string(param,tpscnt,str2);
4981 struct pack_desc desc;
4983 if (!str1 || !str2 || !p) {
4987 memset((char *)&desc,'\0',sizeof(desc));
4989 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4991 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4993 /* check it's a supported varient */
4994 if (strcmp(str1,"WrLeh") != 0) {
4997 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5002 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5007 memset((char *)&desc,'\0',sizeof(desc));
5009 desc.buflen = mdrcnt;
5011 if (init_package(&desc,1,0)) {
5012 PACKS(&desc,"B13","lp0");
5015 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5017 *rdata_len = desc.usedlen;
5020 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5024 SSVALS(*rparam,0,desc.errcode);
5026 SSVAL(*rparam,4,succnt);
5029 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5034 /****************************************************************************
5036 ****************************************************************************/
5038 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5039 char *param, int tpscnt,
5040 char *data, int tdscnt,
5041 int mdrcnt,int mprcnt,
5042 char **rdata,char **rparam,
5043 int *rdata_len,int *rparam_len)
5046 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5047 char *str2 = skip_string(param,tpscnt,str1);
5048 char *p = skip_string(param,tpscnt,str2);
5050 struct pack_desc desc;
5051 struct sessionid *session_list;
5052 int i, num_sessions;
5054 if (!str1 || !str2 || !p) {
5058 memset((char *)&desc,'\0',sizeof(desc));
5060 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5062 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5063 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5064 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5066 /* check it's a supported varient */
5067 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5070 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5074 num_sessions = list_sessions(talloc_tos(), &session_list);
5077 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5082 memset((char *)&desc,'\0',sizeof(desc));
5084 desc.buflen = mdrcnt;
5086 if (!init_package(&desc,num_sessions,0)) {
5090 for(i=0; i<num_sessions; i++) {
5091 PACKS(&desc, "z", session_list[i].remote_machine);
5092 PACKS(&desc, "z", session_list[i].username);
5093 PACKI(&desc, "W", 1); /* num conns */
5094 PACKI(&desc, "W", 0); /* num opens */
5095 PACKI(&desc, "W", 1); /* num users */
5096 PACKI(&desc, "D", 0); /* session time */
5097 PACKI(&desc, "D", 0); /* idle time */
5098 PACKI(&desc, "D", 0); /* flags */
5099 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5102 *rdata_len = desc.usedlen;
5105 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5109 SSVALS(*rparam,0,desc.errcode);
5110 SSVAL(*rparam,2,0); /* converter */
5111 SSVAL(*rparam,4,num_sessions); /* count */
5113 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5119 /****************************************************************************
5120 The buffer was too small.
5121 ****************************************************************************/
5123 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5124 int mdrcnt, int mprcnt,
5125 char **rdata, char **rparam,
5126 int *rdata_len, int *rparam_len)
5128 *rparam_len = MIN(*rparam_len,mprcnt);
5129 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5136 SSVAL(*rparam,0,NERR_BufTooSmall);
5138 DEBUG(3,("Supplied buffer too small in API command\n"));
5143 /****************************************************************************
5144 The request is not supported.
5145 ****************************************************************************/
5147 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5148 char *param, int tpscnt,
5149 char *data, int tdscnt,
5150 int mdrcnt, int mprcnt,
5151 char **rdata, char **rparam,
5152 int *rdata_len, int *rparam_len)
5155 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5162 SSVAL(*rparam,0,NERR_notsupported);
5163 SSVAL(*rparam,2,0); /* converter word */
5165 DEBUG(3,("Unsupported API command\n"));
5170 static const struct {
5173 bool (*fn)(connection_struct *, uint16,
5176 int,int,char **,char **,int *,int *);
5177 bool auth_user; /* Deny anonymous access? */
5178 } api_commands[] = {
5179 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5180 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5181 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5182 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5183 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5184 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5185 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5186 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5187 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5188 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5189 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5190 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5191 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5192 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5193 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5194 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5195 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5196 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5197 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5198 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5199 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5200 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5201 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5202 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5203 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5204 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5205 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5206 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5207 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5208 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5209 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5210 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5211 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5212 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5213 {NULL, -1, api_Unsupported}
5214 /* The following RAP calls are not implemented by Samba:
5216 RAP_WFileEnum2 - anon not OK
5221 /****************************************************************************
5222 Handle remote api calls.
5223 ****************************************************************************/
5225 void api_reply(connection_struct *conn, uint16 vuid,
5226 struct smb_request *req,
5227 char *data, char *params,
5228 int tdscnt, int tpscnt,
5229 int mdrcnt, int mprcnt)
5231 struct smbd_server_connection *sconn = smbd_server_conn;
5234 char *rparam = NULL;
5235 const char *name1 = NULL;
5236 const char *name2 = NULL;
5243 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5244 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5249 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5252 api_command = SVAL(params,0);
5253 /* Is there a string at position params+2 ? */
5254 if (skip_string(params,tpscnt,params+2)) {
5259 name2 = skip_string(params,tpscnt,params+2);
5264 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5268 tdscnt,tpscnt,mdrcnt,mprcnt));
5270 for (i=0;api_commands[i].name;i++) {
5271 if (api_commands[i].id == api_command && api_commands[i].fn) {
5272 DEBUG(3,("Doing %s\n",api_commands[i].name));
5277 /* Check whether this api call can be done anonymously */
5279 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5280 user_struct *user = get_valid_user_struct(sconn, vuid);
5282 if (!user || user->server_info->guest) {
5283 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5288 rdata = (char *)SMB_MALLOC(1024);
5290 memset(rdata,'\0',1024);
5293 rparam = (char *)SMB_MALLOC(1024);
5295 memset(rparam,'\0',1024);
5298 if(!rdata || !rparam) {
5299 DEBUG(0,("api_reply: malloc fail !\n"));
5302 reply_nterror(req, NT_STATUS_NO_MEMORY);
5306 reply = api_commands[i].fn(conn,
5308 params,tpscnt, /* params + length */
5309 data,tdscnt, /* data + length */
5311 &rdata,&rparam,&rdata_len,&rparam_len);
5314 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5315 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5316 &rdata,&rparam,&rdata_len,&rparam_len);
5319 /* if we get False back then it's actually unsupported */
5321 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5322 &rdata,&rparam,&rdata_len,&rparam_len);
5325 /* If api_Unsupported returns false we can't return anything. */
5327 send_trans_reply(conn, req, rparam, rparam_len,
5328 rdata, rdata_len, False);