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;
966 if (!param_format || !output_format1 || !p) {
970 memset((char *)&desc,'\0',sizeof(desc));
972 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
974 if (!prefix_ok(param_format,"WrLeh")) {
977 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
979 * Patch from Scott Moomaw <scott@bridgewater.edu>
980 * to return the 'invalid info level' error if an
981 * unknown level was requested.
985 *rparam = smb_realloc_limit(*rparam,*rparam_len);
989 SSVALS(*rparam,0,ERRunknownlevel);
995 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
996 rpc_spoolss_dispatch, conn->server_info,
998 if (!NT_STATUS_IS_OK(status)) {
999 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1000 nt_errstr(status)));
1001 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1005 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1007 cli->srv_name_slash,
1012 if (!W_ERROR_IS_OK(werr)) {
1013 desc.errcode = W_ERROR_V(werr);
1017 queuecnt = num_printers;
1019 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1020 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1025 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1031 desc.buflen = mdrcnt;
1034 for (i = 0; i < num_printers; i++) {
1037 struct policy_handle handle;
1038 union spoolss_DriverInfo driver_info;
1039 union spoolss_JobInfo *job_info;
1041 ZERO_STRUCT(handle);
1042 ZERO_STRUCT(devmode_ctr);
1044 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1045 printer_info[i].info2.printername,
1048 SEC_FLAG_MAXIMUM_ALLOWED,
1051 if (!NT_STATUS_IS_OK(status)) {
1052 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1055 if (!W_ERROR_IS_OK(werr)) {
1056 desc.errcode = W_ERROR_V(werr);
1060 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1068 if (!W_ERROR_IS_OK(werr)) {
1069 desc.errcode = W_ERROR_V(werr);
1074 uint32_t server_major_version;
1075 uint32_t server_minor_version;
1077 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1085 &server_major_version,
1086 &server_minor_version);
1087 if (!W_ERROR_IS_OK(werr)) {
1088 desc.errcode = W_ERROR_V(werr);
1093 subcntarr[i] = num_jobs;
1094 subcnt += subcntarr[i];
1096 if (init_package(&desc,queuecnt,subcnt)) {
1097 fill_printq_info(uLevel,&desc,subcntarr[i], job_info, &driver_info.info3, &printer_info[i].info2);
1098 if (desc.errcode == NERR_Success) {
1103 if (is_valid_policy_hnd(&handle)) {
1104 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1108 SAFE_FREE(subcntarr);
1110 *rdata_len = desc.usedlen;
1112 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1116 SSVALS(*rparam,0,desc.errcode);
1118 SSVAL(*rparam,4,succnt);
1119 SSVAL(*rparam,6,queuecnt);
1125 SAFE_FREE(subcntarr);
1130 /****************************************************************************
1131 Get info level for a server list query.
1132 ****************************************************************************/
1134 static bool check_server_info(int uLevel, char* id)
1138 if (strcmp(id,"B16") != 0) {
1143 if (strcmp(id,"B16BBDz") != 0) {
1153 struct srv_info_struct {
1161 /*******************************************************************
1162 Get server info lists from the files saved by nmbd. Return the
1164 ******************************************************************/
1166 static int get_server_info(uint32 servertype,
1167 struct srv_info_struct **servers,
1173 bool local_list_only;
1176 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1178 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1182 /* request for everything is code for request all servers */
1183 if (servertype == SV_TYPE_ALL) {
1184 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1187 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1189 DEBUG(4,("Servertype search: %8x\n",servertype));
1191 for (i=0;lines[i];i++) {
1193 struct srv_info_struct *s;
1194 const char *ptr = lines[i];
1196 TALLOC_CTX *frame = NULL;
1203 if (count == alloced) {
1205 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1207 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1211 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1213 s = &(*servers)[count];
1215 frame = talloc_stackframe();
1217 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1221 fstrcpy(s->name, p);
1224 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1230 s->comment[0] = '\0';
1231 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1235 fstrcpy(s->comment, p);
1236 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1238 s->domain[0] = '\0';
1239 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1240 /* this allows us to cope with an old nmbd */
1241 fstrcpy(s->domain,lp_workgroup());
1243 fstrcpy(s->domain, p);
1247 if (sscanf(stype,"%X",&s->type) != 1) {
1248 DEBUG(4,("r:host file "));
1252 /* Filter the servers/domains we return based on what was asked for. */
1254 /* Check to see if we are being asked for a local list only. */
1255 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1256 DEBUG(4,("r: local list only"));
1260 /* doesn't match up: don't want it */
1261 if (!(servertype & s->type)) {
1262 DEBUG(4,("r:serv type "));
1266 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1267 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1268 DEBUG(4,("s: dom mismatch "));
1272 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1276 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1277 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1280 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1281 s->name, s->type, s->comment, s->domain));
1282 s->server_added = True;
1285 DEBUG(4,("%20s %8x %25s %15s\n",
1286 s->name, s->type, s->comment, s->domain));
1294 /*******************************************************************
1295 Fill in a server info structure.
1296 ******************************************************************/
1298 static int fill_srv_info(struct srv_info_struct *service,
1299 int uLevel, char **buf, int *buflen,
1300 char **stringbuf, int *stringspace, char *baseaddr)
1323 len = strlen(service->comment)+1;
1327 *buflen = struct_len;
1329 return struct_len + len;
1334 if (*buflen < struct_len) {
1341 p2 = p + struct_len;
1342 l2 = *buflen - struct_len;
1350 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1354 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1355 SIVAL(p,18,service->type);
1356 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1357 len += CopyAndAdvance(&p2,service->comment,&l2);
1362 *buf = p + struct_len;
1363 *buflen -= struct_len;
1374 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1376 return StrCaseCmp(s1->name,s2->name);
1379 /****************************************************************************
1380 View list of servers available (or possibly domains). The info is
1381 extracted from lists saved by nmbd on the local host.
1382 ****************************************************************************/
1384 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1385 char *param, int tpscnt,
1386 char *data, int tdscnt,
1387 int mdrcnt, int mprcnt, char **rdata,
1388 char **rparam, int *rdata_len, int *rparam_len)
1390 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1391 char *str2 = skip_string(param,tpscnt,str1);
1392 char *p = skip_string(param,tpscnt,str2);
1393 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1394 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1395 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1397 int data_len, fixed_len, string_len;
1398 int f_len = 0, s_len = 0;
1399 struct srv_info_struct *servers=NULL;
1400 int counted=0,total=0;
1403 bool domain_request;
1406 if (!str1 || !str2 || !p) {
1410 /* If someone sets all the bits they don't really mean to set
1411 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1414 if (servertype == SV_TYPE_ALL) {
1415 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1418 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1419 any other bit (they may just set this bit on its own) they
1420 want all the locally seen servers. However this bit can be
1421 set on its own so set the requested servers to be
1422 ALL - DOMAIN_ENUM. */
1424 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1425 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1428 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1429 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1433 if (!prefix_ok(str1,"WrLehD")) {
1436 if (!check_server_info(uLevel,str2)) {
1440 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1441 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1442 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1444 if (strcmp(str1, "WrLehDz") == 0) {
1445 if (skip_string(param,tpscnt,p) == NULL) {
1448 pull_ascii_fstring(domain, p);
1450 fstrcpy(domain, lp_workgroup());
1453 DEBUG(4, ("domain [%s]\n", domain));
1455 if (lp_browse_list()) {
1456 total = get_server_info(servertype,&servers,domain);
1459 data_len = fixed_len = string_len = 0;
1462 TYPESAFE_QSORT(servers, total, srv_comp);
1465 char *lastname=NULL;
1467 for (i=0;i<total;i++) {
1468 struct srv_info_struct *s = &servers[i];
1470 if (lastname && strequal(lastname,s->name)) {
1474 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1475 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1476 i, s->name, s->type, s->comment, s->domain));
1478 if (data_len < buf_len) {
1481 string_len += s_len;
1488 *rdata_len = fixed_len + string_len;
1489 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1494 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1500 char *lastname=NULL;
1501 int count2 = counted;
1503 for (i = 0; i < total && count2;i++) {
1504 struct srv_info_struct *s = &servers[i];
1506 if (lastname && strequal(lastname,s->name)) {
1510 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1511 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1512 i, s->name, s->type, s->comment, s->domain));
1518 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1522 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1524 SSVAL(*rparam,4,counted);
1525 SSVAL(*rparam,6,counted+missed);
1529 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1530 domain,uLevel,counted,counted+missed));
1535 static int srv_name_match(const char *n1, const char *n2)
1538 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1540 * In Windows, FirstNameToReturn need not be an exact match:
1541 * the server will return a list of servers that exist on
1542 * the network greater than or equal to the FirstNameToReturn.
1544 int ret = StrCaseCmp(n1, n2);
1553 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1554 char *param, int tpscnt,
1555 char *data, int tdscnt,
1556 int mdrcnt, int mprcnt, char **rdata,
1557 char **rparam, int *rdata_len, int *rparam_len)
1559 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1560 char *str2 = skip_string(param,tpscnt,str1);
1561 char *p = skip_string(param,tpscnt,str2);
1562 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1563 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1564 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1566 int data_len, fixed_len, string_len;
1567 int f_len = 0, s_len = 0;
1568 struct srv_info_struct *servers=NULL;
1569 int counted=0,first=0,total=0;
1573 bool domain_request;
1576 if (!str1 || !str2 || !p) {
1580 /* If someone sets all the bits they don't really mean to set
1581 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1584 if (servertype == SV_TYPE_ALL) {
1585 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1588 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1589 any other bit (they may just set this bit on its own) they
1590 want all the locally seen servers. However this bit can be
1591 set on its own so set the requested servers to be
1592 ALL - DOMAIN_ENUM. */
1594 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1595 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1598 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1599 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1603 if (strcmp(str1, "WrLehDzz") != 0) {
1606 if (!check_server_info(uLevel,str2)) {
1610 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1611 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1612 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1614 if (skip_string(param,tpscnt,p) == NULL) {
1617 pull_ascii_fstring(domain, p);
1618 if (domain[0] == '\0') {
1619 fstrcpy(domain, lp_workgroup());
1621 p = skip_string(param,tpscnt,p);
1622 if (skip_string(param,tpscnt,p) == NULL) {
1625 pull_ascii_fstring(first_name, p);
1627 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1628 domain, first_name));
1630 if (lp_browse_list()) {
1631 total = get_server_info(servertype,&servers,domain);
1634 data_len = fixed_len = string_len = 0;
1637 TYPESAFE_QSORT(servers, total, srv_comp);
1639 if (first_name[0] != '\0') {
1640 struct srv_info_struct *first_server = NULL;
1642 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1643 srv_name_match, first_server);
1645 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1647 * The binary search may not find the exact match
1648 * so we need to search backward to find the first match
1650 * This implements the strange matching windows
1651 * implements. (see the comment in srv_name_match().
1655 ret = StrCaseCmp(first_name,
1656 servers[first-1].name);
1663 /* we should return no entries */
1669 char *lastname=NULL;
1671 for (i=first;i<total;i++) {
1672 struct srv_info_struct *s = &servers[i];
1674 if (lastname && strequal(lastname,s->name)) {
1678 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1679 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1680 i, s->name, s->type, s->comment, s->domain));
1682 if (data_len < buf_len) {
1685 string_len += s_len;
1692 *rdata_len = fixed_len + string_len;
1693 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1698 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1704 char *lastname=NULL;
1705 int count2 = counted;
1707 for (i = first; i < total && count2;i++) {
1708 struct srv_info_struct *s = &servers[i];
1710 if (lastname && strequal(lastname,s->name)) {
1714 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1715 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1716 i, s->name, s->type, s->comment, s->domain));
1722 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1726 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1728 SSVAL(*rparam,4,counted);
1729 SSVAL(*rparam,6,counted+missed);
1731 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1732 domain,uLevel,first,first_name,
1733 first < total ? servers[first].name : "",
1734 counted,counted+missed));
1741 /****************************************************************************
1742 command 0x34 - suspected of being a "Lookup Names" stub api
1743 ****************************************************************************/
1745 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1746 char *param, int tpscnt,
1747 char *data, int tdscnt,
1748 int mdrcnt, int mprcnt, char **rdata,
1749 char **rparam, int *rdata_len, int *rparam_len)
1751 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1752 char *str2 = skip_string(param,tpscnt,str1);
1753 char *p = skip_string(param,tpscnt,str2);
1754 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1755 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1759 if (!str1 || !str2 || !p) {
1763 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1764 str1, str2, p, uLevel, buf_len));
1766 if (!prefix_ok(str1,"zWrLeh")) {
1773 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1778 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1780 SSVAL(*rparam,4,counted);
1781 SSVAL(*rparam,6,counted+missed);
1786 /****************************************************************************
1787 get info about a share
1788 ****************************************************************************/
1790 static bool check_share_info(int uLevel, char* id)
1794 if (strcmp(id,"B13") != 0) {
1799 /* Level-2 descriptor is allowed (and ignored) */
1800 if (strcmp(id,"B13BWz") != 0 &&
1801 strcmp(id,"B13BWzWWWzB9B") != 0) {
1806 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1811 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1821 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1822 char** buf, int* buflen,
1823 char** stringbuf, int* stringspace, char* baseaddr)
1852 len += StrlenExpanded(conn,snum,lp_comment(snum));
1855 len += strlen(lp_pathname(snum)) + 1;
1858 *buflen = struct_len;
1863 return struct_len + len;
1868 if ((*buflen) < struct_len) {
1876 p2 = p + struct_len;
1877 l2 = (*buflen) - struct_len;
1884 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1890 type = STYPE_DISKTREE;
1891 if (lp_print_ok(snum)) {
1892 type = STYPE_PRINTQ;
1894 if (strequal("IPC",lp_fstype(snum))) {
1897 SSVAL(p,14,type); /* device type */
1898 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1899 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1903 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1904 SSVALS(p,22,-1); /* max uses */
1905 SSVAL(p,24,1); /* current uses */
1906 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1907 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1908 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1912 memset(p+40,0,SHPWLEN+2);
1923 (*buf) = p + struct_len;
1924 (*buflen) -= struct_len;
1926 (*stringspace) = l2;
1935 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1936 char *param, int tpscnt,
1937 char *data, int tdscnt,
1938 int mdrcnt,int mprcnt,
1939 char **rdata,char **rparam,
1940 int *rdata_len,int *rparam_len)
1942 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1943 char *str2 = skip_string(param,tpscnt,str1);
1944 char *netname = skip_string(param,tpscnt,str2);
1945 char *p = skip_string(param,tpscnt,netname);
1946 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1949 if (!str1 || !str2 || !netname || !p) {
1953 snum = find_service(netname);
1958 /* check it's a supported varient */
1959 if (!prefix_ok(str1,"zWrLh")) {
1962 if (!check_share_info(uLevel,str2)) {
1966 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1971 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1972 if (*rdata_len < 0) {
1977 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1981 SSVAL(*rparam,0,NERR_Success);
1982 SSVAL(*rparam,2,0); /* converter word */
1983 SSVAL(*rparam,4,*rdata_len);
1988 /****************************************************************************
1989 View the list of available shares.
1991 This function is the server side of the NetShareEnum() RAP call.
1992 It fills the return buffer with share names and share comments.
1993 Note that the return buffer normally (in all known cases) allows only
1994 twelve byte strings for share names (plus one for a nul terminator).
1995 Share names longer than 12 bytes must be skipped.
1996 ****************************************************************************/
1998 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1999 char *param, int tpscnt,
2000 char *data, int tdscnt,
2008 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2009 char *str2 = skip_string(param,tpscnt,str1);
2010 char *p = skip_string(param,tpscnt,str2);
2011 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2012 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2015 int total=0,counted=0;
2016 bool missed = False;
2018 int data_len, fixed_len, string_len;
2019 int f_len = 0, s_len = 0;
2021 if (!str1 || !str2 || !p) {
2025 if (!prefix_ok(str1,"WrLeh")) {
2028 if (!check_share_info(uLevel,str2)) {
2032 /* Ensure all the usershares are loaded. */
2034 load_registry_shares();
2035 count = load_usershare_shares();
2038 data_len = fixed_len = string_len = 0;
2039 for (i=0;i<count;i++) {
2040 fstring servicename_dos;
2041 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2044 push_ascii_fstring(servicename_dos, lp_servicename(i));
2045 /* Maximum name length = 13. */
2046 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2048 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2049 if (data_len < buf_len) {
2052 string_len += s_len;
2059 *rdata_len = fixed_len + string_len;
2060 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2065 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2070 for( i = 0; i < count; i++ ) {
2071 fstring servicename_dos;
2072 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2076 push_ascii_fstring(servicename_dos, lp_servicename(i));
2077 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2078 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2085 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2089 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2091 SSVAL(*rparam,4,counted);
2092 SSVAL(*rparam,6,total);
2094 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2095 counted,total,uLevel,
2096 buf_len,*rdata_len,mdrcnt));
2101 /****************************************************************************
2103 ****************************************************************************/
2105 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2106 char *param, int tpscnt,
2107 char *data, int tdscnt,
2108 int mdrcnt,int mprcnt,
2109 char **rdata,char **rparam,
2110 int *rdata_len,int *rparam_len)
2112 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2113 char *str2 = skip_string(param,tpscnt,str1);
2114 char *p = skip_string(param,tpscnt,str2);
2115 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2118 char *pathname = NULL;
2119 char *command, *cmdname;
2120 unsigned int offset;
2123 size_t converted_size;
2125 if (!str1 || !str2 || !p) {
2129 /* check it's a supported varient */
2130 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2133 if (!check_share_info(uLevel,str2)) {
2140 /* Do we have a string ? */
2141 if (skip_string(data,mdrcnt,data) == NULL) {
2144 pull_ascii_fstring(sharename,data);
2145 snum = find_service(sharename);
2146 if (snum >= 0) { /* already exists */
2155 /* only support disk share adds */
2156 if (SVAL(data,14)!=STYPE_DISKTREE) {
2160 offset = IVAL(data, 16);
2161 if (offset >= mdrcnt) {
2162 res = ERRinvalidparam;
2166 /* Do we have a string ? */
2167 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2170 pull_ascii_fstring(comment, offset? (data+offset) : "");
2172 offset = IVAL(data, 26);
2174 if (offset >= mdrcnt) {
2175 res = ERRinvalidparam;
2179 /* Do we have a string ? */
2180 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2184 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2185 offset ? (data+offset) : "", &converted_size))
2187 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2195 string_replace(sharename, '"', ' ');
2196 string_replace(pathname, '"', ' ');
2197 string_replace(comment, '"', ' ');
2199 cmdname = lp_add_share_cmd();
2201 if (!cmdname || *cmdname == '\0') {
2205 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2206 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2207 pathname, comment) == -1) {
2211 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2213 if ((res = smbrun(command, NULL)) != 0) {
2214 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2221 message_send_all(smbd_messaging_context(),
2222 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2226 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2230 SSVAL(*rparam,0,NERR_Success);
2231 SSVAL(*rparam,2,0); /* converter word */
2232 SSVAL(*rparam,4,*rdata_len);
2240 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2245 SSVAL(*rparam,0,res);
2250 /****************************************************************************
2251 view list of groups available
2252 ****************************************************************************/
2254 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2255 char *param, int tpscnt,
2256 char *data, int tdscnt,
2257 int mdrcnt,int mprcnt,
2258 char **rdata,char **rparam,
2259 int *rdata_len,int *rparam_len)
2263 int resume_context, cli_buf_size;
2264 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2265 char *str2 = skip_string(param,tpscnt,str1);
2266 char *p = skip_string(param,tpscnt,str2);
2268 uint32_t num_groups;
2269 uint32_t resume_handle;
2270 struct rpc_pipe_client *samr_pipe;
2271 struct policy_handle samr_handle, domain_handle;
2274 if (!str1 || !str2 || !p) {
2278 if (strcmp(str1,"WrLeh") != 0) {
2283 * W-> resume context (number of users to skip)
2284 * r -> return parameter pointer to receive buffer
2285 * L -> length of receive buffer
2286 * e -> return parameter number of entries
2287 * h -> return parameter total number of users
2290 if (strcmp("B21",str2) != 0) {
2294 status = rpc_pipe_open_internal(
2295 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2296 conn->server_info, &samr_pipe);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2299 nt_errstr(status)));
2303 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2304 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2305 if (!NT_STATUS_IS_OK(status)) {
2306 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2307 nt_errstr(status)));
2311 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2312 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2313 get_global_sam_sid(), &domain_handle);
2314 if (!NT_STATUS_IS_OK(status)) {
2315 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2316 nt_errstr(status)));
2317 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2321 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2322 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2323 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2324 "%d\n", resume_context, cli_buf_size));
2326 *rdata_len = cli_buf_size;
2327 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2334 errflags = NERR_Success;
2339 struct samr_SamArray *sam_entries;
2340 uint32_t num_entries;
2342 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2347 if (!NT_STATUS_IS_OK(status)) {
2348 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2349 "%s\n", nt_errstr(status)));
2353 if (num_entries == 0) {
2354 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2355 "no entries -- done\n"));
2359 for(i=0; i<num_entries; i++) {
2362 name = sam_entries->entries[i].name.string;
2364 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2365 /* set overflow error */
2366 DEBUG(3,("overflow on entry %d group %s\n", i,
2372 /* truncate the name at 21 chars. */
2374 strlcpy(p, name, 21);
2375 DEBUG(10,("adding entry %d group %s\n", i, p));
2377 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2382 if (errflags != NERR_Success) {
2386 TALLOC_FREE(sam_entries);
2389 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2390 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2392 *rdata_len = PTR_DIFF(p,*rdata);
2395 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2399 SSVAL(*rparam, 0, errflags);
2400 SSVAL(*rparam, 2, 0); /* converter word */
2401 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2402 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2407 /*******************************************************************
2408 Get groups that a user is a member of.
2409 ******************************************************************/
2411 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2412 char *param, int tpscnt,
2413 char *data, int tdscnt,
2414 int mdrcnt,int mprcnt,
2415 char **rdata,char **rparam,
2416 int *rdata_len,int *rparam_len)
2418 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2419 char *str2 = skip_string(param,tpscnt,str1);
2420 char *UserName = skip_string(param,tpscnt,str2);
2421 char *p = skip_string(param,tpscnt,UserName);
2422 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2423 const char *level_string;
2429 struct rpc_pipe_client *samr_pipe;
2430 struct policy_handle samr_handle, domain_handle, user_handle;
2431 struct lsa_String name;
2432 struct lsa_Strings names;
2433 struct samr_Ids type, rid;
2434 struct samr_RidWithAttributeArray *rids;
2437 if (!str1 || !str2 || !UserName || !p) {
2442 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2447 /* check it's a supported varient */
2449 if ( strcmp(str1,"zWrLeh") != 0 )
2454 level_string = "B21";
2460 if (strcmp(level_string,str2) != 0)
2463 *rdata_len = mdrcnt + 1024;
2464 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2469 SSVAL(*rparam,0,NERR_Success);
2470 SSVAL(*rparam,2,0); /* converter word */
2473 endp = *rdata + *rdata_len;
2475 status = rpc_pipe_open_internal(
2476 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2477 conn->server_info, &samr_pipe);
2478 if (!NT_STATUS_IS_OK(status)) {
2479 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2480 nt_errstr(status)));
2484 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2485 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2486 if (!NT_STATUS_IS_OK(status)) {
2487 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2488 nt_errstr(status)));
2492 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2493 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2494 get_global_sam_sid(), &domain_handle);
2495 if (!NT_STATUS_IS_OK(status)) {
2496 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2497 nt_errstr(status)));
2501 name.string = UserName;
2503 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2504 &domain_handle, 1, &name,
2506 if (!NT_STATUS_IS_OK(status)) {
2507 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2508 nt_errstr(status)));
2512 if (type.ids[0] != SID_NAME_USER) {
2513 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2514 sid_type_lookup(type.ids[0])));
2518 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2520 SAMR_USER_ACCESS_GET_GROUPS,
2521 rid.ids[0], &user_handle);
2522 if (!NT_STATUS_IS_OK(status)) {
2523 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2524 nt_errstr(status)));
2528 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2529 &user_handle, &rids);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2532 nt_errstr(status)));
2536 for (i=0; i<rids->count; i++) {
2538 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2540 1, &rids->rids[i].rid,
2542 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2543 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2549 *rdata_len = PTR_DIFF(p,*rdata);
2551 SSVAL(*rparam,4,count); /* is this right?? */
2552 SSVAL(*rparam,6,count); /* is this right?? */
2557 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2559 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2561 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2566 /*******************************************************************
2568 ******************************************************************/
2570 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2571 char *param, int tpscnt,
2572 char *data, int tdscnt,
2573 int mdrcnt,int mprcnt,
2574 char **rdata,char **rparam,
2575 int *rdata_len,int *rparam_len)
2580 int i, resume_context, cli_buf_size;
2581 uint32_t resume_handle;
2583 struct rpc_pipe_client *samr_pipe;
2584 struct policy_handle samr_handle, domain_handle;
2587 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2588 char *str2 = skip_string(param,tpscnt,str1);
2589 char *p = skip_string(param,tpscnt,str2);
2592 if (!str1 || !str2 || !p) {
2596 if (strcmp(str1,"WrLeh") != 0)
2599 * W-> resume context (number of users to skip)
2600 * r -> return parameter pointer to receive buffer
2601 * L -> length of receive buffer
2602 * e -> return parameter number of entries
2603 * h -> return parameter total number of users
2606 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2607 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2608 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2609 resume_context, cli_buf_size));
2612 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2617 /* check it's a supported varient */
2618 if (strcmp("B21",str2) != 0)
2621 *rdata_len = cli_buf_size;
2622 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2628 endp = *rdata + *rdata_len;
2630 status = rpc_pipe_open_internal(
2631 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2632 conn->server_info, &samr_pipe);
2633 if (!NT_STATUS_IS_OK(status)) {
2634 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2635 nt_errstr(status)));
2639 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2640 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2641 if (!NT_STATUS_IS_OK(status)) {
2642 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2643 nt_errstr(status)));
2647 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2648 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2649 get_global_sam_sid(), &domain_handle);
2650 if (!NT_STATUS_IS_OK(status)) {
2651 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2652 nt_errstr(status)));
2653 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2657 errflags=NERR_Success;
2662 struct samr_SamArray *sam_entries;
2663 uint32_t num_entries;
2665 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2671 if (!NT_STATUS_IS_OK(status)) {
2672 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2673 "%s\n", nt_errstr(status)));
2677 if (num_entries == 0) {
2678 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2679 "no entries -- done\n"));
2683 for (i=0; i<num_entries; i++) {
2686 name = sam_entries->entries[i].name.string;
2688 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2689 &&(strlen(name)<=21)) {
2690 strlcpy(p,name,PTR_DIFF(endp,p));
2691 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2692 "username %s\n",count_sent,p));
2696 /* set overflow error */
2697 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2698 "username %s\n",count_sent,name));
2704 if (errflags != NERR_Success) {
2708 TALLOC_FREE(sam_entries);
2711 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2712 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2714 *rdata_len = PTR_DIFF(p,*rdata);
2716 SSVAL(*rparam,0,errflags);
2717 SSVAL(*rparam,2,0); /* converter word */
2718 SSVAL(*rparam,4,count_sent); /* is this right?? */
2719 SSVAL(*rparam,6,num_users); /* is this right?? */
2724 /****************************************************************************
2725 Get the time of day info.
2726 ****************************************************************************/
2728 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2729 char *param, int tpscnt,
2730 char *data, int tdscnt,
2731 int mdrcnt,int mprcnt,
2732 char **rdata,char **rparam,
2733 int *rdata_len,int *rparam_len)
2736 time_t unixdate = time(NULL);
2740 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2746 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2751 SSVAL(*rparam,0,NERR_Success);
2752 SSVAL(*rparam,2,0); /* converter word */
2756 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2757 by NT in a "net time" operation,
2758 it seems to ignore the one below */
2760 /* the client expects to get localtime, not GMT, in this bit
2761 (I think, this needs testing) */
2762 t = localtime(&unixdate);
2767 SIVAL(p,4,0); /* msecs ? */
2768 SCVAL(p,8,t->tm_hour);
2769 SCVAL(p,9,t->tm_min);
2770 SCVAL(p,10,t->tm_sec);
2771 SCVAL(p,11,0); /* hundredths of seconds */
2772 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2773 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2774 SCVAL(p,16,t->tm_mday);
2775 SCVAL(p,17,t->tm_mon + 1);
2776 SSVAL(p,18,1900+t->tm_year);
2777 SCVAL(p,20,t->tm_wday);
2782 /****************************************************************************
2783 Set the user password.
2784 *****************************************************************************/
2786 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2787 char *param, int tpscnt,
2788 char *data, int tdscnt,
2789 int mdrcnt,int mprcnt,
2790 char **rdata,char **rparam,
2791 int *rdata_len,int *rparam_len)
2793 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2796 fstring pass1,pass2;
2798 /* Skip 2 strings. */
2799 p = skip_string(param,tpscnt,np);
2800 p = skip_string(param,tpscnt,p);
2806 /* Do we have a string ? */
2807 if (skip_string(param,tpscnt,p) == NULL) {
2810 pull_ascii_fstring(user,p);
2812 p = skip_string(param,tpscnt,p);
2817 memset(pass1,'\0',sizeof(pass1));
2818 memset(pass2,'\0',sizeof(pass2));
2820 * We use 31 here not 32 as we're checking
2821 * the last byte we want to access is safe.
2823 if (!is_offset_safe(param,tpscnt,p,31)) {
2827 memcpy(pass2,p+16,16);
2830 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2837 SSVAL(*rparam,0,NERR_badpass);
2838 SSVAL(*rparam,2,0); /* converter word */
2840 DEBUG(3,("Set password for <%s>\n",user));
2843 * Attempt to verify the old password against smbpasswd entries
2844 * Win98 clients send old and new password in plaintext for this call.
2848 struct auth_serversupplied_info *server_info = NULL;
2849 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2851 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2854 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2855 SSVAL(*rparam,0,NERR_Success);
2859 TALLOC_FREE(server_info);
2861 data_blob_clear_free(&password);
2865 * If the plaintext change failed, attempt
2866 * the old encrypted method. NT will generate this
2867 * after trying the samr method. Note that this
2868 * method is done as a last resort as this
2869 * password change method loses the NT password hash
2870 * and cannot change the UNIX password as no plaintext
2874 if(SVAL(*rparam,0) != NERR_Success) {
2875 struct samu *hnd = NULL;
2877 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2879 if (change_lanman_password(hnd,(uchar *)pass2)) {
2880 SSVAL(*rparam,0,NERR_Success);
2887 memset((char *)pass1,'\0',sizeof(fstring));
2888 memset((char *)pass2,'\0',sizeof(fstring));
2893 /****************************************************************************
2894 Set the user password (SamOEM version - gets plaintext).
2895 ****************************************************************************/
2897 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2898 char *param, int tpscnt,
2899 char *data, int tdscnt,
2900 int mdrcnt,int mprcnt,
2901 char **rdata,char **rparam,
2902 int *rdata_len,int *rparam_len)
2904 struct smbd_server_connection *sconn = smbd_server_conn;
2906 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2908 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2918 SSVAL(*rparam,0,NERR_badpass);
2921 * Check the parameter definition is correct.
2924 /* Do we have a string ? */
2925 if (skip_string(param,tpscnt,p) == 0) {
2928 if(!strequal(p, "zsT")) {
2929 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2932 p = skip_string(param, tpscnt, p);
2937 /* Do we have a string ? */
2938 if (skip_string(param,tpscnt,p) == 0) {
2941 if(!strequal(p, "B516B16")) {
2942 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2945 p = skip_string(param,tpscnt,p);
2949 /* Do we have a string ? */
2950 if (skip_string(param,tpscnt,p) == 0) {
2953 p += pull_ascii_fstring(user,p);
2955 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2958 * Pass the user through the NT -> unix user mapping
2962 (void)map_username(sconn, user);
2964 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2965 SSVAL(*rparam,0,NERR_Success);
2971 /****************************************************************************
2974 ****************************************************************************/
2976 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2977 char *param, int tpscnt,
2978 char *data, int tdscnt,
2979 int mdrcnt,int mprcnt,
2980 char **rdata,char **rparam,
2981 int *rdata_len,int *rparam_len)
2983 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2984 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2985 char *str2 = skip_string(param,tpscnt,str1);
2986 char *p = skip_string(param,tpscnt,str2);
2990 WERROR werr = WERR_OK;
2992 TALLOC_CTX *mem_ctx = talloc_tos();
2994 struct rpc_pipe_client *cli = NULL;
2995 struct policy_handle handle;
2996 struct spoolss_DevmodeContainer devmode_ctr;
2997 enum spoolss_JobControl command;
2999 if (!str1 || !str2 || !p) {
3003 * We use 1 here not 2 as we're checking
3004 * the last byte we want to access is safe.
3006 if (!is_offset_safe(param,tpscnt,p,1)) {
3009 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3012 /* check it's a supported varient */
3013 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3017 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3023 ZERO_STRUCT(handle);
3025 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3026 rpc_spoolss_dispatch, conn->server_info,
3028 if (!NT_STATUS_IS_OK(status)) {
3029 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3030 nt_errstr(status)));
3031 errcode = W_ERROR_V(ntstatus_to_werror(status));
3035 ZERO_STRUCT(devmode_ctr);
3037 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3041 SEC_FLAG_MAXIMUM_ALLOWED,
3044 if (!NT_STATUS_IS_OK(status)) {
3045 errcode = W_ERROR_V(ntstatus_to_werror(status));
3048 if (!W_ERROR_IS_OK(werr)) {
3049 errcode = W_ERROR_V(werr);
3053 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3054 * and NERR_DestNotFound if share did not exist */
3056 errcode = NERR_Success;
3059 case 81: /* delete */
3060 command = SPOOLSS_JOB_CONTROL_DELETE;
3062 case 82: /* pause */
3063 command = SPOOLSS_JOB_CONTROL_PAUSE;
3065 case 83: /* resume */
3066 command = SPOOLSS_JOB_CONTROL_RESUME;
3069 errcode = NERR_notsupported;
3073 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3076 NULL, /* unique ptr ctr */
3079 if (!NT_STATUS_IS_OK(status)) {
3080 errcode = W_ERROR_V(ntstatus_to_werror(status));
3083 if (!W_ERROR_IS_OK(werr)) {
3084 errcode = W_ERROR_V(werr);
3089 if (is_valid_policy_hnd(&handle)) {
3090 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3093 SSVAL(*rparam,0,errcode);
3094 SSVAL(*rparam,2,0); /* converter word */
3099 /****************************************************************************
3100 Purge a print queue - or pause or resume it.
3101 ****************************************************************************/
3103 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3104 char *param, int tpscnt,
3105 char *data, int tdscnt,
3106 int mdrcnt,int mprcnt,
3107 char **rdata,char **rparam,
3108 int *rdata_len,int *rparam_len)
3110 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3111 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3112 char *str2 = skip_string(param,tpscnt,str1);
3113 char *QueueName = skip_string(param,tpscnt,str2);
3114 int errcode = NERR_notsupported;
3115 WERROR werr = WERR_OK;
3118 TALLOC_CTX *mem_ctx = talloc_tos();
3119 struct rpc_pipe_client *cli = NULL;
3120 struct policy_handle handle;
3121 struct spoolss_SetPrinterInfoCtr info_ctr;
3122 struct spoolss_DevmodeContainer devmode_ctr;
3123 struct sec_desc_buf secdesc_ctr;
3124 enum spoolss_PrinterControl command;
3126 if (!str1 || !str2 || !QueueName) {
3130 /* check it's a supported varient */
3131 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3135 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3141 if (skip_string(param,tpscnt,QueueName) == NULL) {
3145 ZERO_STRUCT(handle);
3147 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3148 rpc_spoolss_dispatch, conn->server_info,
3150 if (!NT_STATUS_IS_OK(status)) {
3151 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3152 nt_errstr(status)));
3153 errcode = W_ERROR_V(ntstatus_to_werror(status));
3157 ZERO_STRUCT(devmode_ctr);
3159 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3163 SEC_FLAG_MAXIMUM_ALLOWED,
3166 if (!NT_STATUS_IS_OK(status)) {
3167 errcode = W_ERROR_V(ntstatus_to_werror(status));
3170 if (!W_ERROR_IS_OK(werr)) {
3171 errcode = W_ERROR_V(werr);
3176 case 74: /* Pause queue */
3177 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3179 case 75: /* Resume queue */
3180 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3182 case 103: /* Purge */
3183 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3186 werr = WERR_NOT_SUPPORTED;
3190 if (!W_ERROR_IS_OK(werr)) {
3191 errcode = W_ERROR_V(werr);
3195 ZERO_STRUCT(info_ctr);
3196 ZERO_STRUCT(secdesc_ctr);
3198 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3205 if (!NT_STATUS_IS_OK(status)) {
3206 errcode = W_ERROR_V(ntstatus_to_werror(status));
3209 if (!W_ERROR_IS_OK(werr)) {
3210 errcode = W_ERROR_V(werr);
3214 errcode = W_ERROR_V(werr);
3218 if (is_valid_policy_hnd(&handle)) {
3219 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3222 SSVAL(*rparam,0,errcode);
3223 SSVAL(*rparam,2,0); /* converter word */
3228 /****************************************************************************
3229 set the property of a print job (undocumented?)
3230 ? function = 0xb -> set name of print job
3231 ? function = 0x6 -> move print job up/down
3232 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3233 or <WWsTP> <WB21BB16B10zWWzDDz>
3234 ****************************************************************************/
3236 static int check_printjob_info(struct pack_desc* desc,
3237 int uLevel, char* id)
3239 desc->subformat = NULL;
3241 case 0: desc->format = "W"; break;
3242 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3243 case 2: desc->format = "WWzWWDDzz"; break;
3244 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3245 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3247 DEBUG(0,("check_printjob_info: invalid level %d\n",
3251 if (id == NULL || strcmp(desc->format,id) != 0) {
3252 DEBUG(0,("check_printjob_info: invalid format %s\n",
3253 id ? id : "<NULL>" ));
3259 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3260 char *param, int tpscnt,
3261 char *data, int tdscnt,
3262 int mdrcnt,int mprcnt,
3263 char **rdata,char **rparam,
3264 int *rdata_len,int *rparam_len)
3266 struct pack_desc desc;
3267 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3268 char *str2 = skip_string(param,tpscnt,str1);
3269 char *p = skip_string(param,tpscnt,str2);
3272 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3273 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3276 TALLOC_CTX *mem_ctx = talloc_tos();
3279 struct rpc_pipe_client *cli = NULL;
3280 struct policy_handle handle;
3281 struct spoolss_DevmodeContainer devmode_ctr;
3282 struct spoolss_JobInfoContainer ctr;
3283 union spoolss_JobInfo info;
3284 struct spoolss_SetJobInfo1 info1;
3286 if (!str1 || !str2 || !p) {
3290 * We use 1 here not 2 as we're checking
3291 * the last byte we want to access is safe.
3293 if (!is_offset_safe(param,tpscnt,p,1)) {
3296 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3299 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3304 ZERO_STRUCT(handle);
3306 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3307 rpc_spoolss_dispatch, conn->server_info,
3309 if (!NT_STATUS_IS_OK(status)) {
3310 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3311 nt_errstr(status)));
3312 errcode = W_ERROR_V(ntstatus_to_werror(status));
3316 ZERO_STRUCT(devmode_ctr);
3318 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3322 SEC_FLAG_MAXIMUM_ALLOWED,
3325 if (!NT_STATUS_IS_OK(status)) {
3326 errcode = W_ERROR_V(ntstatus_to_werror(status));
3329 if (!W_ERROR_IS_OK(werr)) {
3330 errcode = W_ERROR_V(werr);
3336 /* check it's a supported varient */
3337 if ((strcmp(str1,"WWsTP")) ||
3338 (!check_printjob_info(&desc,uLevel,str2)))
3341 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3347 if (!W_ERROR_IS_OK(werr)) {
3348 errcode = W_ERROR_V(werr);
3352 errcode = NERR_notsupported;
3356 /* change print job name, data gives the name */
3364 info1.job_id = info.info1.job_id;
3365 info1.printer_name = info.info1.printer_name;
3366 info1.user_name = info.info1.user_name;
3367 info1.document_name = data;
3368 info1.data_type = info.info1.data_type;
3369 info1.text_status = info.info1.text_status;
3370 info1.status = info.info1.status;
3371 info1.priority = info.info1.priority;
3372 info1.position = info.info1.position;
3373 info1.total_pages = info.info1.total_pages;
3374 info1.pages_printed = info.info1.pages_printed;
3375 info1.submitted = info.info1.submitted;
3378 ctr.info.info1 = &info1;
3380 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3386 if (!NT_STATUS_IS_OK(status)) {
3387 errcode = W_ERROR_V(ntstatus_to_werror(status));
3390 if (!W_ERROR_IS_OK(werr)) {
3391 errcode = W_ERROR_V(werr);
3395 errcode = NERR_Success;
3398 if (is_valid_policy_hnd(&handle)) {
3399 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3402 SSVALS(*rparam,0,errcode);
3403 SSVAL(*rparam,2,0); /* converter word */
3409 /****************************************************************************
3410 Get info about the server.
3411 ****************************************************************************/
3413 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3414 char *param, int tpscnt,
3415 char *data, int tdscnt,
3416 int mdrcnt,int mprcnt,
3417 char **rdata,char **rparam,
3418 int *rdata_len,int *rparam_len)
3420 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3421 char *str2 = skip_string(param,tpscnt,str1);
3422 char *p = skip_string(param,tpscnt,str2);
3423 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3427 if (!str1 || !str2 || !p) {
3431 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3433 /* check it's a supported varient */
3434 if (!prefix_ok(str1,"WrLh")) {
3440 if (strcmp(str2,"B16") != 0) {
3446 if (strcmp(str2,"B16BBDz") != 0) {
3452 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3458 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3464 if (strcmp(str2,"DN") != 0) {
3470 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3479 *rdata_len = mdrcnt;
3480 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3486 p2 = p + struct_len;
3488 srvstr_push(NULL, 0, p,global_myname(),16,
3489 STR_ASCII|STR_UPPER|STR_TERMINATE);
3493 struct srv_info_struct *servers=NULL;
3495 char *comment = NULL;
3496 TALLOC_CTX *ctx = talloc_tos();
3497 uint32 servertype= lp_default_server_announce();
3499 comment = talloc_strdup(ctx,lp_serverstring());
3504 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3505 for (i=0;i<count;i++) {
3506 if (strequal(servers[i].name,global_myname())) {
3507 servertype = servers[i].type;
3508 TALLOC_FREE(comment);
3509 comment = talloc_strdup(ctx,
3510 servers[i].comment);
3520 SCVAL(p,0,lp_major_announce_version());
3521 SCVAL(p,1,lp_minor_announce_version());
3522 SIVAL(p,2,servertype);
3524 if (mdrcnt == struct_len) {
3527 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3528 comment = talloc_sub_advanced(
3530 lp_servicename(SNUM(conn)),
3531 conn->server_info->unix_name,
3533 conn->server_info->utok.gid,
3534 conn->server_info->sanitized_username,
3535 pdb_get_domain(conn->server_info->sam_account),
3540 if (mdrcnt - struct_len <= 0) {
3545 MIN(mdrcnt - struct_len,
3546 MAX_SERVER_STRING_LENGTH),
3548 p2 = skip_string(*rdata,*rdata_len,p2);
3556 return False; /* not yet implemented */
3559 *rdata_len = PTR_DIFF(p2,*rdata);
3562 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3566 SSVAL(*rparam,0,NERR_Success);
3567 SSVAL(*rparam,2,0); /* converter word */
3568 SSVAL(*rparam,4,*rdata_len);
3573 /****************************************************************************
3574 Get info about the server.
3575 ****************************************************************************/
3577 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3578 char *param, int tpscnt,
3579 char *data, int tdscnt,
3580 int mdrcnt,int mprcnt,
3581 char **rdata,char **rparam,
3582 int *rdata_len,int *rparam_len)
3584 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3585 char *str2 = skip_string(param,tpscnt,str1);
3586 char *p = skip_string(param,tpscnt,str2);
3589 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3591 if (!str1 || !str2 || !p) {
3595 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3598 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3603 /* check it's a supported varient */
3604 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3608 *rdata_len = mdrcnt + 1024;
3609 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3614 SSVAL(*rparam,0,NERR_Success);
3615 SSVAL(*rparam,2,0); /* converter word */
3618 endp = *rdata + *rdata_len;
3620 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3625 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3626 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3628 p2 = skip_string(*rdata,*rdata_len,p2);
3634 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3635 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3636 p2 = skip_string(*rdata,*rdata_len,p2);
3642 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3643 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3645 p2 = skip_string(*rdata,*rdata_len,p2);
3651 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3652 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3655 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3656 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3657 p2 = skip_string(*rdata,*rdata_len,p2);
3663 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3664 strlcpy(p2,"",PTR_DIFF(endp,p2));
3665 p2 = skip_string(*rdata,*rdata_len,p2);
3671 *rdata_len = PTR_DIFF(p2,*rdata);
3673 SSVAL(*rparam,4,*rdata_len);
3678 /****************************************************************************
3679 get info about a user
3681 struct user_info_11 {
3682 char usri11_name[21]; 0-20
3684 char *usri11_comment; 22-25
3685 char *usri11_usr_comment; 26-29
3686 unsigned short usri11_priv; 30-31
3687 unsigned long usri11_auth_flags; 32-35
3688 long usri11_password_age; 36-39
3689 char *usri11_homedir; 40-43
3690 char *usri11_parms; 44-47
3691 long usri11_last_logon; 48-51
3692 long usri11_last_logoff; 52-55
3693 unsigned short usri11_bad_pw_count; 56-57
3694 unsigned short usri11_num_logons; 58-59
3695 char *usri11_logon_server; 60-63
3696 unsigned short usri11_country_code; 64-65
3697 char *usri11_workstations; 66-69
3698 unsigned long usri11_max_storage; 70-73
3699 unsigned short usri11_units_per_week; 74-75
3700 unsigned char *usri11_logon_hours; 76-79
3701 unsigned short usri11_code_page; 80-81
3706 usri11_name specifies the user name for which information is retrieved
3708 usri11_pad aligns the next data structure element to a word boundary
3710 usri11_comment is a null terminated ASCII comment
3712 usri11_user_comment is a null terminated ASCII comment about the user
3714 usri11_priv specifies the level of the privilege assigned to the user.
3715 The possible values are:
3717 Name Value Description
3718 USER_PRIV_GUEST 0 Guest privilege
3719 USER_PRIV_USER 1 User privilege
3720 USER_PRV_ADMIN 2 Administrator privilege
3722 usri11_auth_flags specifies the account operator privileges. The
3723 possible values are:
3725 Name Value Description
3726 AF_OP_PRINT 0 Print operator
3729 Leach, Naik [Page 28]
3733 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3736 AF_OP_COMM 1 Communications operator
3737 AF_OP_SERVER 2 Server operator
3738 AF_OP_ACCOUNTS 3 Accounts operator
3741 usri11_password_age specifies how many seconds have elapsed since the
3742 password was last changed.
3744 usri11_home_dir points to a null terminated ASCII string that contains
3745 the path name of the user's home directory.
3747 usri11_parms points to a null terminated ASCII string that is set
3748 aside for use by applications.
3750 usri11_last_logon specifies the time when the user last logged on.
3751 This value is stored as the number of seconds elapsed since
3752 00:00:00, January 1, 1970.
3754 usri11_last_logoff specifies the time when the user last logged off.
3755 This value is stored as the number of seconds elapsed since
3756 00:00:00, January 1, 1970. A value of 0 means the last logoff
3759 usri11_bad_pw_count specifies the number of incorrect passwords
3760 entered since the last successful logon.
3762 usri11_log1_num_logons specifies the number of times this user has
3763 logged on. A value of -1 means the number of logons is unknown.
3765 usri11_logon_server points to a null terminated ASCII string that
3766 contains the name of the server to which logon requests are sent.
3767 A null string indicates logon requests should be sent to the
3770 usri11_country_code specifies the country code for the user's language
3773 usri11_workstations points to a null terminated ASCII string that
3774 contains the names of workstations the user may log on from.
3775 There may be up to 8 workstations, with the names separated by
3776 commas. A null strings indicates there are no restrictions.
3778 usri11_max_storage specifies the maximum amount of disk space the user
3779 can occupy. A value of 0xffffffff indicates there are no
3782 usri11_units_per_week specifies the equal number of time units into
3783 which a week is divided. This value must be equal to 168.
3785 usri11_logon_hours points to a 21 byte (168 bits) string that
3786 specifies the time during which the user can log on. Each bit
3787 represents one unique hour in a week. The first bit (bit 0, word
3788 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3792 Leach, Naik [Page 29]
3796 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3799 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3800 are no restrictions.
3802 usri11_code_page specifies the code page for the user's language of
3805 All of the pointers in this data structure need to be treated
3806 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3807 to be ignored. The converter word returned in the parameters section
3808 needs to be subtracted from the lower 16 bits to calculate an offset
3809 into the return buffer where this ASCII string resides.
3811 There is no auxiliary data in the response.
3813 ****************************************************************************/
3815 #define usri11_name 0
3816 #define usri11_pad 21
3817 #define usri11_comment 22
3818 #define usri11_usr_comment 26
3819 #define usri11_full_name 30
3820 #define usri11_priv 34
3821 #define usri11_auth_flags 36
3822 #define usri11_password_age 40
3823 #define usri11_homedir 44
3824 #define usri11_parms 48
3825 #define usri11_last_logon 52
3826 #define usri11_last_logoff 56
3827 #define usri11_bad_pw_count 60
3828 #define usri11_num_logons 62
3829 #define usri11_logon_server 64
3830 #define usri11_country_code 68
3831 #define usri11_workstations 70
3832 #define usri11_max_storage 74
3833 #define usri11_units_per_week 78
3834 #define usri11_logon_hours 80
3835 #define usri11_code_page 84
3836 #define usri11_end 86
3838 #define USER_PRIV_GUEST 0
3839 #define USER_PRIV_USER 1
3840 #define USER_PRIV_ADMIN 2
3842 #define AF_OP_PRINT 0
3843 #define AF_OP_COMM 1
3844 #define AF_OP_SERVER 2
3845 #define AF_OP_ACCOUNTS 3
3848 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3849 char *param, int tpscnt,
3850 char *data, int tdscnt,
3851 int mdrcnt,int mprcnt,
3852 char **rdata,char **rparam,
3853 int *rdata_len,int *rparam_len)
3855 struct smbd_server_connection *sconn = smbd_server_conn;
3856 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3857 char *str2 = skip_string(param,tpscnt,str1);
3858 char *UserName = skip_string(param,tpscnt,str2);
3859 char *p = skip_string(param,tpscnt,UserName);
3860 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3863 const char *level_string;
3865 /* get NIS home of a previously validated user - simeon */
3866 /* With share level security vuid will always be zero.
3867 Don't depend on vuser being non-null !!. JRA */
3868 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3870 DEBUG(3,(" Username of UID %d is %s\n",
3871 (int)vuser->server_info->utok.uid,
3872 vuser->server_info->unix_name));
3875 if (!str1 || !str2 || !UserName || !p) {
3880 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3885 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3887 /* check it's a supported variant */
3888 if (strcmp(str1,"zWrLh") != 0) {
3892 case 0: level_string = "B21"; break;
3893 case 1: level_string = "B21BB16DWzzWz"; break;
3894 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3895 case 10: level_string = "B21Bzzz"; break;
3896 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3897 default: return False;
3900 if (strcmp(level_string,str2) != 0) {
3904 *rdata_len = mdrcnt + 1024;
3905 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3910 SSVAL(*rparam,0,NERR_Success);
3911 SSVAL(*rparam,2,0); /* converter word */
3914 endp = *rdata + *rdata_len;
3915 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3921 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3924 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3929 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3930 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3931 p2 = skip_string(*rdata,*rdata_len,p2);
3936 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3937 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3938 p2 = skip_string(*rdata,*rdata_len,p2);
3943 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3944 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3945 strlcpy(p2,((vuser != NULL)
3946 ? pdb_get_fullname(vuser->server_info->sam_account)
3947 : UserName),PTR_DIFF(endp,p2));
3948 p2 = skip_string(*rdata,*rdata_len,p2);
3955 const char *homedir = "";
3956 if (vuser != NULL) {
3957 homedir = pdb_get_homedir(
3958 vuser->server_info->sam_account);
3960 /* modelled after NTAS 3.51 reply */
3961 SSVAL(p,usri11_priv,
3962 (get_current_uid(conn) == sec_initial_uid())?
3963 USER_PRIV_ADMIN:USER_PRIV_USER);
3964 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3965 SIVALS(p,usri11_password_age,-1); /* password age */
3966 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3967 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3968 p2 = skip_string(*rdata,*rdata_len,p2);
3972 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3973 strlcpy(p2,"",PTR_DIFF(endp,p2));
3974 p2 = skip_string(*rdata,*rdata_len,p2);
3978 SIVAL(p,usri11_last_logon,0); /* last logon */
3979 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3980 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3981 SSVALS(p,usri11_num_logons,-1); /* num logons */
3982 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3983 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3984 p2 = skip_string(*rdata,*rdata_len,p2);
3988 SSVAL(p,usri11_country_code,0); /* country code */
3990 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3991 strlcpy(p2,"",PTR_DIFF(endp,p2));
3992 p2 = skip_string(*rdata,*rdata_len,p2);
3997 SIVALS(p,usri11_max_storage,-1); /* max storage */
3998 SSVAL(p,usri11_units_per_week,168); /* units per week */
3999 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4001 /* a simple way to get logon hours at all times. */
4003 SCVAL(p2,21,0); /* fix zero termination */
4004 p2 = skip_string(*rdata,*rdata_len,p2);
4009 SSVAL(p,usri11_code_page,0); /* code page */
4012 if (uLevel == 1 || uLevel == 2) {
4013 memset(p+22,' ',16); /* password */
4014 SIVALS(p,38,-1); /* password age */
4016 (get_current_uid(conn) == sec_initial_uid())?
4017 USER_PRIV_ADMIN:USER_PRIV_USER);
4018 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4019 strlcpy(p2, vuser ? pdb_get_homedir(
4020 vuser->server_info->sam_account) : "",
4022 p2 = skip_string(*rdata,*rdata_len,p2);
4026 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4028 SSVAL(p,52,0); /* flags */
4029 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4030 strlcpy(p2, vuser ? pdb_get_logon_script(
4031 vuser->server_info->sam_account) : "",
4033 p2 = skip_string(*rdata,*rdata_len,p2);
4038 SIVAL(p,60,0); /* auth_flags */
4039 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4040 strlcpy(p2,((vuser != NULL)
4041 ? pdb_get_fullname(vuser->server_info->sam_account)
4042 : UserName),PTR_DIFF(endp,p2));
4043 p2 = skip_string(*rdata,*rdata_len,p2);
4047 SIVAL(p,68,0); /* urs_comment */
4048 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4049 strlcpy(p2,"",PTR_DIFF(endp,p2));
4050 p2 = skip_string(*rdata,*rdata_len,p2);
4054 SIVAL(p,76,0); /* workstations */
4055 SIVAL(p,80,0); /* last_logon */
4056 SIVAL(p,84,0); /* last_logoff */
4057 SIVALS(p,88,-1); /* acct_expires */
4058 SIVALS(p,92,-1); /* max_storage */
4059 SSVAL(p,96,168); /* units_per_week */
4060 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4063 SSVALS(p,102,-1); /* bad_pw_count */
4064 SSVALS(p,104,-1); /* num_logons */
4065 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4067 TALLOC_CTX *ctx = talloc_tos();
4068 int space_rem = *rdata_len - (p2 - *rdata);
4071 if (space_rem <= 0) {
4074 tmp = talloc_strdup(ctx, "\\\\%L");
4078 tmp = talloc_sub_basic(ctx,
4091 p2 = skip_string(*rdata,*rdata_len,p2);
4095 SSVAL(p,110,49); /* country_code */
4096 SSVAL(p,112,860); /* code page */
4100 *rdata_len = PTR_DIFF(p2,*rdata);
4102 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4107 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4108 char *param, int tpscnt,
4109 char *data, int tdscnt,
4110 int mdrcnt,int mprcnt,
4111 char **rdata,char **rparam,
4112 int *rdata_len,int *rparam_len)
4114 struct smbd_server_connection *sconn = smbd_server_conn;
4115 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4116 char *str2 = skip_string(param,tpscnt,str1);
4117 char *p = skip_string(param,tpscnt,str2);
4119 struct pack_desc desc;
4121 /* With share level security vuid will always be zero.
4122 Don't depend on vuser being non-null !!. JRA */
4123 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4125 if (!str1 || !str2 || !p) {
4130 DEBUG(3,(" Username of UID %d is %s\n",
4131 (int)vuser->server_info->utok.uid,
4132 vuser->server_info->unix_name));
4135 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4136 name = get_safe_str_ptr(param,tpscnt,p,2);
4141 memset((char *)&desc,'\0',sizeof(desc));
4143 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4145 /* check it's a supported varient */
4146 if (strcmp(str1,"OOWb54WrLh") != 0) {
4149 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4153 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4160 desc.buflen = mdrcnt;
4161 desc.subformat = NULL;
4164 if (init_package(&desc,1,0)) {
4165 PACKI(&desc,"W",0); /* code */
4166 PACKS(&desc,"B21",name); /* eff. name */
4167 PACKS(&desc,"B",""); /* pad */
4169 (get_current_uid(conn) == sec_initial_uid())?
4170 USER_PRIV_ADMIN:USER_PRIV_USER);
4171 PACKI(&desc,"D",0); /* auth flags XXX */
4172 PACKI(&desc,"W",0); /* num logons */
4173 PACKI(&desc,"W",0); /* bad pw count */
4174 PACKI(&desc,"D",0); /* last logon */
4175 PACKI(&desc,"D",-1); /* last logoff */
4176 PACKI(&desc,"D",-1); /* logoff time */
4177 PACKI(&desc,"D",-1); /* kickoff time */
4178 PACKI(&desc,"D",0); /* password age */
4179 PACKI(&desc,"D",0); /* password can change */
4180 PACKI(&desc,"D",-1); /* password must change */
4184 fstrcpy(mypath,"\\\\");
4185 fstrcat(mypath,get_local_machine_name());
4187 PACKS(&desc,"z",mypath); /* computer */
4190 PACKS(&desc,"z",lp_workgroup());/* domain */
4191 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4192 vuser->server_info->sam_account) : ""); /* script path */
4193 PACKI(&desc,"D",0x00000000); /* reserved */
4196 *rdata_len = desc.usedlen;
4198 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4202 SSVALS(*rparam,0,desc.errcode);
4204 SSVAL(*rparam,4,desc.neededlen);
4206 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4211 /****************************************************************************
4212 api_WAccessGetUserPerms
4213 ****************************************************************************/
4215 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4216 char *param, int tpscnt,
4217 char *data, int tdscnt,
4218 int mdrcnt,int mprcnt,
4219 char **rdata,char **rparam,
4220 int *rdata_len,int *rparam_len)
4222 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4223 char *str2 = skip_string(param,tpscnt,str1);
4224 char *user = skip_string(param,tpscnt,str2);
4225 char *resource = skip_string(param,tpscnt,user);
4227 if (!str1 || !str2 || !user || !resource) {
4231 if (skip_string(param,tpscnt,resource) == NULL) {
4234 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4236 /* check it's a supported varient */
4237 if (strcmp(str1,"zzh") != 0) {
4240 if (strcmp(str2,"") != 0) {
4245 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4249 SSVALS(*rparam,0,0); /* errorcode */
4250 SSVAL(*rparam,2,0); /* converter word */
4251 SSVAL(*rparam,4,0x7f); /* permission flags */
4256 /****************************************************************************
4257 api_WPrintJobEnumerate
4258 ****************************************************************************/
4260 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4261 char *param, int tpscnt,
4262 char *data, int tdscnt,
4263 int mdrcnt,int mprcnt,
4264 char **rdata,char **rparam,
4265 int *rdata_len,int *rparam_len)
4267 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4268 char *str2 = skip_string(param,tpscnt,str1);
4269 char *p = skip_string(param,tpscnt,str2);
4273 struct pack_desc desc;
4276 TALLOC_CTX *mem_ctx = talloc_tos();
4279 struct rpc_pipe_client *cli = NULL;
4280 struct policy_handle handle;
4281 struct spoolss_DevmodeContainer devmode_ctr;
4282 union spoolss_JobInfo info;
4284 if (!str1 || !str2 || !p) {
4288 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4290 memset((char *)&desc,'\0',sizeof(desc));
4291 memset((char *)&status,'\0',sizeof(status));
4293 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4295 /* check it's a supported varient */
4296 if (strcmp(str1,"WWrLh") != 0) {
4299 if (!check_printjob_info(&desc,uLevel,str2)) {
4303 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4307 ZERO_STRUCT(handle);
4309 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4310 rpc_spoolss_dispatch, conn->server_info,
4312 if (!NT_STATUS_IS_OK(status)) {
4313 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4314 nt_errstr(status)));
4315 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4319 ZERO_STRUCT(devmode_ctr);
4321 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4325 SEC_FLAG_MAXIMUM_ALLOWED,
4328 if (!NT_STATUS_IS_OK(status)) {
4329 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4332 if (!W_ERROR_IS_OK(werr)) {
4333 desc.errcode = W_ERROR_V(werr);
4337 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4343 if (!W_ERROR_IS_OK(werr)) {
4344 desc.errcode = W_ERROR_V(werr);
4349 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4354 desc.buflen = mdrcnt;
4357 * Don't return data but need to get correct length
4358 * init_package will return wrong size if buflen=0
4360 desc.buflen = getlen(desc.format);
4361 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4364 if (init_package(&desc,1,0)) {
4365 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4366 *rdata_len = desc.usedlen;
4368 desc.errcode = NERR_JobNotFound;
4372 if (is_valid_policy_hnd(&handle)) {
4373 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4377 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4381 SSVALS(*rparam,0,desc.errcode);
4383 SSVAL(*rparam,4,desc.neededlen);
4387 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4392 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4393 char *param, int tpscnt,
4394 char *data, int tdscnt,
4395 int mdrcnt,int mprcnt,
4396 char **rdata,char **rparam,
4397 int *rdata_len,int *rparam_len)
4399 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4400 char *str2 = skip_string(param,tpscnt,str1);
4401 char *p = skip_string(param,tpscnt,str2);
4405 struct pack_desc desc;
4407 TALLOC_CTX *mem_ctx = talloc_tos();
4410 struct rpc_pipe_client *cli = NULL;
4411 struct policy_handle handle;
4412 struct spoolss_DevmodeContainer devmode_ctr;
4414 union spoolss_JobInfo *info;
4416 if (!str1 || !str2 || !p) {
4420 memset((char *)&desc,'\0',sizeof(desc));
4422 p = skip_string(param,tpscnt,p);
4426 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4428 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4430 /* check it's a supported variant */
4431 if (strcmp(str1,"zWrLeh") != 0) {
4436 return False; /* defined only for uLevel 0,1,2 */
4439 if (!check_printjob_info(&desc,uLevel,str2)) {
4443 ZERO_STRUCT(handle);
4445 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4446 rpc_spoolss_dispatch, conn->server_info,
4448 if (!NT_STATUS_IS_OK(status)) {
4449 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4450 nt_errstr(status)));
4451 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4455 ZERO_STRUCT(devmode_ctr);
4457 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4461 SEC_FLAG_MAXIMUM_ALLOWED,
4464 if (!NT_STATUS_IS_OK(status)) {
4465 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4468 if (!W_ERROR_IS_OK(werr)) {
4469 desc.errcode = W_ERROR_V(werr);
4473 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4481 if (!W_ERROR_IS_OK(werr)) {
4482 desc.errcode = W_ERROR_V(werr);
4487 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4493 desc.buflen = mdrcnt;
4495 if (init_package(&desc,count,0)) {
4497 for (i = 0; i < count; i++) {
4498 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4499 if (desc.errcode == NERR_Success) {
4505 if (is_valid_policy_hnd(&handle)) {
4506 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4509 *rdata_len = desc.usedlen;
4512 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4516 SSVALS(*rparam,0,desc.errcode);
4518 SSVAL(*rparam,4,succnt);
4519 SSVAL(*rparam,6,count);
4521 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4526 static int check_printdest_info(struct pack_desc* desc,
4527 int uLevel, char* id)
4529 desc->subformat = NULL;
4532 desc->format = "B9";
4535 desc->format = "B9B21WWzW";
4541 desc->format = "zzzWWzzzWW";
4544 DEBUG(0,("check_printdest_info: invalid level %d\n",
4548 if (id == NULL || strcmp(desc->format,id) != 0) {
4549 DEBUG(0,("check_printdest_info: invalid string %s\n",
4550 id ? id : "<NULL>" ));
4556 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4557 struct pack_desc* desc)
4561 strncpy(buf, info2->printername, sizeof(buf)-1);
4562 buf[sizeof(buf)-1] = 0;
4566 PACKS(desc,"B9",buf); /* szName */
4568 PACKS(desc,"B21",""); /* szUserName */
4569 PACKI(desc,"W",0); /* uJobId */
4570 PACKI(desc,"W",0); /* fsStatus */
4571 PACKS(desc,"z",""); /* pszStatus */
4572 PACKI(desc,"W",0); /* time */
4576 if (uLevel == 2 || uLevel == 3) {
4577 PACKS(desc,"z",buf); /* pszPrinterName */
4579 PACKS(desc,"z",""); /* pszUserName */
4580 PACKS(desc,"z",""); /* pszLogAddr */
4581 PACKI(desc,"W",0); /* uJobId */
4582 PACKI(desc,"W",0); /* fsStatus */
4583 PACKS(desc,"z",""); /* pszStatus */
4584 PACKS(desc,"z",""); /* pszComment */
4585 PACKS(desc,"z","NULL"); /* pszDrivers */
4586 PACKI(desc,"W",0); /* time */
4587 PACKI(desc,"W",0); /* pad1 */
4592 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4593 char *param, int tpscnt,
4594 char *data, int tdscnt,
4595 int mdrcnt,int mprcnt,
4596 char **rdata,char **rparam,
4597 int *rdata_len,int *rparam_len)
4599 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4600 char *str2 = skip_string(param,tpscnt,str1);
4601 char *p = skip_string(param,tpscnt,str2);
4602 char* PrinterName = p;
4604 struct pack_desc desc;
4607 TALLOC_CTX *mem_ctx = talloc_tos();
4610 struct rpc_pipe_client *cli = NULL;
4611 struct policy_handle handle;
4612 struct spoolss_DevmodeContainer devmode_ctr;
4613 union spoolss_PrinterInfo info;
4615 if (!str1 || !str2 || !p) {
4619 memset((char *)&desc,'\0',sizeof(desc));
4621 p = skip_string(param,tpscnt,p);
4625 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4627 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4629 /* check it's a supported varient */
4630 if (strcmp(str1,"zWrLh") != 0) {
4633 if (!check_printdest_info(&desc,uLevel,str2)) {
4637 ZERO_STRUCT(handle);
4639 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4640 rpc_spoolss_dispatch, conn->server_info,
4642 if (!NT_STATUS_IS_OK(status)) {
4643 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4644 nt_errstr(status)));
4645 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4649 ZERO_STRUCT(devmode_ctr);
4651 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4655 SEC_FLAG_MAXIMUM_ALLOWED,
4658 if (!NT_STATUS_IS_OK(status)) {
4660 desc.errcode = NERR_DestNotFound;
4664 if (!W_ERROR_IS_OK(werr)) {
4666 desc.errcode = NERR_DestNotFound;
4671 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4676 if (!W_ERROR_IS_OK(werr)) {
4678 desc.errcode = NERR_DestNotFound;
4684 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4689 desc.buflen = mdrcnt;
4692 * Don't return data but need to get correct length
4693 * init_package will return wrong size if buflen=0
4695 desc.buflen = getlen(desc.format);
4696 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4698 if (init_package(&desc,1,0)) {
4699 fill_printdest_info(&info.info2, uLevel,&desc);
4703 if (is_valid_policy_hnd(&handle)) {
4704 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4707 *rdata_len = desc.usedlen;
4710 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4714 SSVALS(*rparam,0,desc.errcode);
4716 SSVAL(*rparam,4,desc.neededlen);
4718 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4724 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4725 char *param, int tpscnt,
4726 char *data, int tdscnt,
4727 int mdrcnt,int mprcnt,
4728 char **rdata,char **rparam,
4729 int *rdata_len,int *rparam_len)
4731 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4732 char *str2 = skip_string(param,tpscnt,str1);
4733 char *p = skip_string(param,tpscnt,str2);
4737 struct pack_desc desc;
4739 TALLOC_CTX *mem_ctx = talloc_tos();
4742 struct rpc_pipe_client *cli = NULL;
4743 union spoolss_PrinterInfo *info;
4746 if (!str1 || !str2 || !p) {
4750 memset((char *)&desc,'\0',sizeof(desc));
4752 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4754 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4756 /* check it's a supported varient */
4757 if (strcmp(str1,"WrLeh") != 0) {
4760 if (!check_printdest_info(&desc,uLevel,str2)) {
4766 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4767 rpc_spoolss_dispatch, conn->server_info,
4769 if (!NT_STATUS_IS_OK(status)) {
4770 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4771 nt_errstr(status)));
4772 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4776 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4778 cli->srv_name_slash,
4783 if (!W_ERROR_IS_OK(werr)) {
4784 desc.errcode = W_ERROR_V(werr);
4786 desc.errcode = NERR_DestNotFound;
4794 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4801 desc.buflen = mdrcnt;
4802 if (init_package(&desc,queuecnt,0)) {
4805 for (i = 0; i < count; i++) {
4806 fill_printdest_info(&info[i].info2, uLevel,&desc);
4808 if (desc.errcode == NERR_Success) {
4814 *rdata_len = desc.usedlen;
4817 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4821 SSVALS(*rparam,0,desc.errcode);
4823 SSVAL(*rparam,4,succnt);
4824 SSVAL(*rparam,6,queuecnt);
4826 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4831 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4832 char *param, int tpscnt,
4833 char *data, int tdscnt,
4834 int mdrcnt,int mprcnt,
4835 char **rdata,char **rparam,
4836 int *rdata_len,int *rparam_len)
4838 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4839 char *str2 = skip_string(param,tpscnt,str1);
4840 char *p = skip_string(param,tpscnt,str2);
4843 struct pack_desc desc;
4845 if (!str1 || !str2 || !p) {
4849 memset((char *)&desc,'\0',sizeof(desc));
4851 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4853 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4855 /* check it's a supported varient */
4856 if (strcmp(str1,"WrLeh") != 0) {
4859 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4864 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4870 desc.buflen = mdrcnt;
4871 if (init_package(&desc,1,0)) {
4872 PACKS(&desc,"B41","NULL");
4875 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4877 *rdata_len = desc.usedlen;
4880 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4884 SSVALS(*rparam,0,desc.errcode);
4886 SSVAL(*rparam,4,succnt);
4889 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4894 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4895 char *param, int tpscnt,
4896 char *data, int tdscnt,
4897 int mdrcnt,int mprcnt,
4898 char **rdata,char **rparam,
4899 int *rdata_len,int *rparam_len)
4901 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4902 char *str2 = skip_string(param,tpscnt,str1);
4903 char *p = skip_string(param,tpscnt,str2);
4906 struct pack_desc desc;
4908 if (!str1 || !str2 || !p) {
4911 memset((char *)&desc,'\0',sizeof(desc));
4913 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4915 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4917 /* check it's a supported varient */
4918 if (strcmp(str1,"WrLeh") != 0) {
4921 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4926 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4932 desc.buflen = mdrcnt;
4934 if (init_package(&desc,1,0)) {
4935 PACKS(&desc,"B13","lpd");
4938 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4940 *rdata_len = desc.usedlen;
4943 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4947 SSVALS(*rparam,0,desc.errcode);
4949 SSVAL(*rparam,4,succnt);
4952 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4957 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4958 char *param, int tpscnt,
4959 char *data, int tdscnt,
4960 int mdrcnt,int mprcnt,
4961 char **rdata,char **rparam,
4962 int *rdata_len,int *rparam_len)
4964 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4965 char *str2 = skip_string(param,tpscnt,str1);
4966 char *p = skip_string(param,tpscnt,str2);
4969 struct pack_desc desc;
4971 if (!str1 || !str2 || !p) {
4975 memset((char *)&desc,'\0',sizeof(desc));
4977 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4979 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4981 /* check it's a supported varient */
4982 if (strcmp(str1,"WrLeh") != 0) {
4985 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4990 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4995 memset((char *)&desc,'\0',sizeof(desc));
4997 desc.buflen = mdrcnt;
4999 if (init_package(&desc,1,0)) {
5000 PACKS(&desc,"B13","lp0");
5003 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5005 *rdata_len = desc.usedlen;
5008 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5012 SSVALS(*rparam,0,desc.errcode);
5014 SSVAL(*rparam,4,succnt);
5017 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5022 /****************************************************************************
5024 ****************************************************************************/
5026 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5027 char *param, int tpscnt,
5028 char *data, int tdscnt,
5029 int mdrcnt,int mprcnt,
5030 char **rdata,char **rparam,
5031 int *rdata_len,int *rparam_len)
5034 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5035 char *str2 = skip_string(param,tpscnt,str1);
5036 char *p = skip_string(param,tpscnt,str2);
5038 struct pack_desc desc;
5039 struct sessionid *session_list;
5040 int i, num_sessions;
5042 if (!str1 || !str2 || !p) {
5046 memset((char *)&desc,'\0',sizeof(desc));
5048 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5050 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5051 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5052 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5054 /* check it's a supported varient */
5055 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5058 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5062 num_sessions = list_sessions(talloc_tos(), &session_list);
5065 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5070 memset((char *)&desc,'\0',sizeof(desc));
5072 desc.buflen = mdrcnt;
5074 if (!init_package(&desc,num_sessions,0)) {
5078 for(i=0; i<num_sessions; i++) {
5079 PACKS(&desc, "z", session_list[i].remote_machine);
5080 PACKS(&desc, "z", session_list[i].username);
5081 PACKI(&desc, "W", 1); /* num conns */
5082 PACKI(&desc, "W", 0); /* num opens */
5083 PACKI(&desc, "W", 1); /* num users */
5084 PACKI(&desc, "D", 0); /* session time */
5085 PACKI(&desc, "D", 0); /* idle time */
5086 PACKI(&desc, "D", 0); /* flags */
5087 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5090 *rdata_len = desc.usedlen;
5093 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5097 SSVALS(*rparam,0,desc.errcode);
5098 SSVAL(*rparam,2,0); /* converter */
5099 SSVAL(*rparam,4,num_sessions); /* count */
5101 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5107 /****************************************************************************
5108 The buffer was too small.
5109 ****************************************************************************/
5111 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5112 int mdrcnt, int mprcnt,
5113 char **rdata, char **rparam,
5114 int *rdata_len, int *rparam_len)
5116 *rparam_len = MIN(*rparam_len,mprcnt);
5117 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5124 SSVAL(*rparam,0,NERR_BufTooSmall);
5126 DEBUG(3,("Supplied buffer too small in API command\n"));
5131 /****************************************************************************
5132 The request is not supported.
5133 ****************************************************************************/
5135 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5136 char *param, int tpscnt,
5137 char *data, int tdscnt,
5138 int mdrcnt, int mprcnt,
5139 char **rdata, char **rparam,
5140 int *rdata_len, int *rparam_len)
5143 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5150 SSVAL(*rparam,0,NERR_notsupported);
5151 SSVAL(*rparam,2,0); /* converter word */
5153 DEBUG(3,("Unsupported API command\n"));
5158 static const struct {
5161 bool (*fn)(connection_struct *, uint16,
5164 int,int,char **,char **,int *,int *);
5165 bool auth_user; /* Deny anonymous access? */
5166 } api_commands[] = {
5167 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5168 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5169 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5170 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5171 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5172 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5173 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5174 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5175 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5176 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5177 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5178 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5179 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5180 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5181 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5182 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5183 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5184 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5185 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5186 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5187 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5188 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5189 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5190 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5191 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5192 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5193 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5194 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5195 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5196 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5197 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5198 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5199 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5200 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5201 {NULL, -1, api_Unsupported}
5202 /* The following RAP calls are not implemented by Samba:
5204 RAP_WFileEnum2 - anon not OK
5209 /****************************************************************************
5210 Handle remote api calls.
5211 ****************************************************************************/
5213 void api_reply(connection_struct *conn, uint16 vuid,
5214 struct smb_request *req,
5215 char *data, char *params,
5216 int tdscnt, int tpscnt,
5217 int mdrcnt, int mprcnt)
5219 struct smbd_server_connection *sconn = smbd_server_conn;
5222 char *rparam = NULL;
5223 const char *name1 = NULL;
5224 const char *name2 = NULL;
5231 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5232 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5237 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5240 api_command = SVAL(params,0);
5241 /* Is there a string at position params+2 ? */
5242 if (skip_string(params,tpscnt,params+2)) {
5247 name2 = skip_string(params,tpscnt,params+2);
5252 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5256 tdscnt,tpscnt,mdrcnt,mprcnt));
5258 for (i=0;api_commands[i].name;i++) {
5259 if (api_commands[i].id == api_command && api_commands[i].fn) {
5260 DEBUG(3,("Doing %s\n",api_commands[i].name));
5265 /* Check whether this api call can be done anonymously */
5267 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5268 user_struct *user = get_valid_user_struct(sconn, vuid);
5270 if (!user || user->server_info->guest) {
5271 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5276 rdata = (char *)SMB_MALLOC(1024);
5278 memset(rdata,'\0',1024);
5281 rparam = (char *)SMB_MALLOC(1024);
5283 memset(rparam,'\0',1024);
5286 if(!rdata || !rparam) {
5287 DEBUG(0,("api_reply: malloc fail !\n"));
5290 reply_nterror(req, NT_STATUS_NO_MEMORY);
5294 reply = api_commands[i].fn(conn,
5296 params,tpscnt, /* params + length */
5297 data,tdscnt, /* data + length */
5299 &rdata,&rparam,&rdata_len,&rparam_len);
5302 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5303 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5304 &rdata,&rparam,&rdata_len,&rparam_len);
5307 /* if we get False back then it's actually unsupported */
5309 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5310 &rdata,&rparam,&rdata_len,&rparam_len);
5313 /* If api_Unsupported returns false we can't return anything. */
5315 send_trans_reply(conn, req, rparam, rparam_len,
5316 rdata, rdata_len, False);