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)
674 PACKS(desc,"B13", printer_info->printername);
679 PACKS(desc,"z", printer_info->printername);
682 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
686 if (uLevel == 1 || uLevel == 2) {
687 PACKS(desc,"B",""); /* alignment */
688 PACKI(desc,"W",5); /* priority */
689 PACKI(desc,"W",0); /* start time */
690 PACKI(desc,"W",0); /* until time */
691 PACKS(desc,"z",""); /* pSepFile */
692 PACKS(desc,"z","lpd"); /* pPrProc */
693 PACKS(desc,"z", printer_info->printername); /* pDestinations */
694 PACKS(desc,"z",""); /* pParms */
695 if (printer_info->printername == NULL) {
696 PACKS(desc,"z","UNKNOWN PRINTER");
697 PACKI(desc,"W",LPSTAT_ERROR);
699 PACKS(desc,"z", printer_info->comment);
700 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
702 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
705 if (uLevel == 3 || uLevel == 4) {
706 PACKI(desc,"W",5); /* uPriority */
707 PACKI(desc,"W",0); /* uStarttime */
708 PACKI(desc,"W",0); /* uUntiltime */
709 PACKI(desc,"W",5); /* pad1 */
710 PACKS(desc,"z",""); /* pszSepFile */
711 PACKS(desc,"z","WinPrint"); /* pszPrProc */
712 PACKS(desc,"z",NULL); /* pszParms */
713 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
714 /* "don't ask" that it's done this way to fix corrupted
715 Win9X/ME printer comments. */
716 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
717 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
718 PACKS(desc,"z", printer_info->printername); /* pszPrinters */
719 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
720 PackDriverData(desc); /* pDriverData */
723 if (uLevel == 2 || uLevel == 4) {
725 for (i = 0; i < count; i++) {
726 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
731 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
734 /* This function returns the number of files for a given driver */
735 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
739 /* count the number of files */
740 while (driver->dependent_files && *driver->dependent_files[result])
746 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
747 char *param, int tpscnt,
748 char *data, int tdscnt,
749 int mdrcnt,int mprcnt,
750 char **rdata,char **rparam,
751 int *rdata_len,int *rparam_len)
753 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
754 char *str2 = skip_string(param,tpscnt,str1);
755 char *p = skip_string(param,tpscnt,str2);
760 struct pack_desc desc;
763 WERROR werr = WERR_OK;
764 TALLOC_CTX *mem_ctx = talloc_tos();
766 struct rpc_pipe_client *cli = NULL;
767 struct policy_handle handle;
768 struct spoolss_DevmodeContainer devmode_ctr;
769 union spoolss_DriverInfo driver_info;
770 union spoolss_JobInfo *job_info;
771 union spoolss_PrinterInfo printer_info;
773 if (!str1 || !str2 || !p) {
776 memset((char *)&desc,'\0',sizeof(desc));
778 p = skip_string(param,tpscnt,p);
782 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
783 str3 = get_safe_str_ptr(param,tpscnt,p,4);
784 /* str3 may be null here and is checked in check_printq_info(). */
786 /* remove any trailing username */
787 if ((p = strchr_m(QueueName,'%')))
790 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
792 /* check it's a supported varient */
793 if (!prefix_ok(str1,"zWrLh"))
795 if (!check_printq_info(&desc,uLevel,str2,str3)) {
797 * Patch from Scott Moomaw <scott@bridgewater.edu>
798 * to return the 'invalid info level' error if an
799 * unknown level was requested.
803 *rparam = smb_realloc_limit(*rparam,*rparam_len);
807 SSVALS(*rparam,0,ERRunknownlevel);
815 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
816 rpc_spoolss_dispatch, conn->server_info,
818 if (!NT_STATUS_IS_OK(status)) {
819 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
821 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
825 ZERO_STRUCT(devmode_ctr);
827 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
831 SEC_FLAG_MAXIMUM_ALLOWED,
834 if (!NT_STATUS_IS_OK(status)) {
835 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
838 if (!W_ERROR_IS_OK(werr)) {
839 desc.errcode = W_ERROR_V(werr);
844 uint32_t server_major_version;
845 uint32_t server_minor_version;
847 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
855 &server_major_version,
856 &server_minor_version);
857 if (!W_ERROR_IS_OK(werr)) {
858 desc.errcode = W_ERROR_V(werr);
862 count = get_printerdrivernumber(&driver_info.info3);
863 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
866 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
874 if (!W_ERROR_IS_OK(werr)) {
875 desc.errcode = W_ERROR_V(werr);
883 *rdata = smb_realloc_limit(*rdata,mdrcnt);
888 desc.buflen = mdrcnt;
891 * Don't return data but need to get correct length
892 * init_package will return wrong size if buflen=0
894 desc.buflen = getlen(desc.format);
895 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
898 if (init_package(&desc,1,count)) {
899 desc.subcount = count;
900 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
903 *rdata_len = desc.usedlen;
906 * We must set the return code to ERRbuftoosmall
907 * in order to support lanman style printing with Win NT/2k
910 if (!mdrcnt && lp_disable_spoolss())
911 desc.errcode = ERRbuftoosmall;
914 if (is_valid_policy_hnd(&handle)) {
915 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
918 *rdata_len = desc.usedlen;
920 *rparam = smb_realloc_limit(*rparam,*rparam_len);
925 SSVALS(*rparam,0,desc.errcode);
927 SSVAL(*rparam,4,desc.neededlen);
929 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
936 /****************************************************************************
937 View list of all print jobs on all queues.
938 ****************************************************************************/
940 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
941 char *param, int tpscnt,
942 char *data, int tdscnt,
943 int mdrcnt, int mprcnt,
944 char **rdata, char** rparam,
945 int *rdata_len, int *rparam_len)
947 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
948 char *output_format1 = skip_string(param,tpscnt,param_format);
949 char *p = skip_string(param,tpscnt,output_format1);
950 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
951 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
953 struct pack_desc desc;
954 int *subcntarr = NULL;
955 int queuecnt = 0, subcnt = 0, succnt = 0;
957 WERROR werr = WERR_OK;
958 TALLOC_CTX *mem_ctx = talloc_tos();
960 struct rpc_pipe_client *cli = NULL;
961 struct spoolss_DevmodeContainer devmode_ctr;
962 uint32_t num_printers;
963 union spoolss_PrinterInfo *printer_info;
965 if (!param_format || !output_format1 || !p) {
969 memset((char *)&desc,'\0',sizeof(desc));
971 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
973 if (!prefix_ok(param_format,"WrLeh")) {
976 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
978 * Patch from Scott Moomaw <scott@bridgewater.edu>
979 * to return the 'invalid info level' error if an
980 * unknown level was requested.
984 *rparam = smb_realloc_limit(*rparam,*rparam_len);
988 SSVALS(*rparam,0,ERRunknownlevel);
994 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
995 rpc_spoolss_dispatch, conn->server_info,
997 if (!NT_STATUS_IS_OK(status)) {
998 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1000 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1004 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1006 cli->srv_name_slash,
1011 if (!W_ERROR_IS_OK(werr)) {
1012 desc.errcode = W_ERROR_V(werr);
1016 queuecnt = num_printers;
1018 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1019 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1024 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1030 desc.buflen = mdrcnt;
1033 for (i = 0; i < num_printers; i++) {
1036 struct policy_handle handle;
1037 union spoolss_DriverInfo driver_info;
1038 union spoolss_JobInfo *job_info;
1040 ZERO_STRUCT(handle);
1041 ZERO_STRUCT(devmode_ctr);
1043 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1044 printer_info[i].info2.printername,
1047 SEC_FLAG_MAXIMUM_ALLOWED,
1050 if (!NT_STATUS_IS_OK(status)) {
1051 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1054 if (!W_ERROR_IS_OK(werr)) {
1055 desc.errcode = W_ERROR_V(werr);
1059 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1067 if (!W_ERROR_IS_OK(werr)) {
1068 desc.errcode = W_ERROR_V(werr);
1073 uint32_t server_major_version;
1074 uint32_t server_minor_version;
1076 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1084 &server_major_version,
1085 &server_minor_version);
1086 if (!W_ERROR_IS_OK(werr)) {
1087 desc.errcode = W_ERROR_V(werr);
1092 subcntarr[i] = num_jobs;
1093 subcnt += subcntarr[i];
1095 if (init_package(&desc,queuecnt,subcnt)) {
1096 fill_printq_info(uLevel,&desc,subcntarr[i], job_info, &driver_info.info3, &printer_info[i].info2);
1097 if (desc.errcode == NERR_Success) {
1102 if (is_valid_policy_hnd(&handle)) {
1103 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1107 SAFE_FREE(subcntarr);
1109 *rdata_len = desc.usedlen;
1111 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1115 SSVALS(*rparam,0,desc.errcode);
1117 SSVAL(*rparam,4,succnt);
1118 SSVAL(*rparam,6,queuecnt);
1124 SAFE_FREE(subcntarr);
1129 /****************************************************************************
1130 Get info level for a server list query.
1131 ****************************************************************************/
1133 static bool check_server_info(int uLevel, char* id)
1137 if (strcmp(id,"B16") != 0) {
1142 if (strcmp(id,"B16BBDz") != 0) {
1152 struct srv_info_struct {
1160 /*******************************************************************
1161 Get server info lists from the files saved by nmbd. Return the
1163 ******************************************************************/
1165 static int get_server_info(uint32 servertype,
1166 struct srv_info_struct **servers,
1172 bool local_list_only;
1175 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1177 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1181 /* request for everything is code for request all servers */
1182 if (servertype == SV_TYPE_ALL) {
1183 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1186 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1188 DEBUG(4,("Servertype search: %8x\n",servertype));
1190 for (i=0;lines[i];i++) {
1192 struct srv_info_struct *s;
1193 const char *ptr = lines[i];
1195 TALLOC_CTX *frame = NULL;
1202 if (count == alloced) {
1204 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1206 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1210 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1212 s = &(*servers)[count];
1214 frame = talloc_stackframe();
1216 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1220 fstrcpy(s->name, p);
1223 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1229 s->comment[0] = '\0';
1230 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1234 fstrcpy(s->comment, p);
1235 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1237 s->domain[0] = '\0';
1238 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1239 /* this allows us to cope with an old nmbd */
1240 fstrcpy(s->domain,lp_workgroup());
1242 fstrcpy(s->domain, p);
1246 if (sscanf(stype,"%X",&s->type) != 1) {
1247 DEBUG(4,("r:host file "));
1251 /* Filter the servers/domains we return based on what was asked for. */
1253 /* Check to see if we are being asked for a local list only. */
1254 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1255 DEBUG(4,("r: local list only"));
1259 /* doesn't match up: don't want it */
1260 if (!(servertype & s->type)) {
1261 DEBUG(4,("r:serv type "));
1265 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1266 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1267 DEBUG(4,("s: dom mismatch "));
1271 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1275 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1276 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1279 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1280 s->name, s->type, s->comment, s->domain));
1281 s->server_added = True;
1284 DEBUG(4,("%20s %8x %25s %15s\n",
1285 s->name, s->type, s->comment, s->domain));
1293 /*******************************************************************
1294 Fill in a server info structure.
1295 ******************************************************************/
1297 static int fill_srv_info(struct srv_info_struct *service,
1298 int uLevel, char **buf, int *buflen,
1299 char **stringbuf, int *stringspace, char *baseaddr)
1322 len = strlen(service->comment)+1;
1326 *buflen = struct_len;
1328 return struct_len + len;
1333 if (*buflen < struct_len) {
1340 p2 = p + struct_len;
1341 l2 = *buflen - struct_len;
1349 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1353 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1354 SIVAL(p,18,service->type);
1355 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1356 len += CopyAndAdvance(&p2,service->comment,&l2);
1361 *buf = p + struct_len;
1362 *buflen -= struct_len;
1373 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1375 return StrCaseCmp(s1->name,s2->name);
1378 /****************************************************************************
1379 View list of servers available (or possibly domains). The info is
1380 extracted from lists saved by nmbd on the local host.
1381 ****************************************************************************/
1383 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1384 char *param, int tpscnt,
1385 char *data, int tdscnt,
1386 int mdrcnt, int mprcnt, char **rdata,
1387 char **rparam, int *rdata_len, int *rparam_len)
1389 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1390 char *str2 = skip_string(param,tpscnt,str1);
1391 char *p = skip_string(param,tpscnt,str2);
1392 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1393 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1394 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1396 int data_len, fixed_len, string_len;
1397 int f_len = 0, s_len = 0;
1398 struct srv_info_struct *servers=NULL;
1399 int counted=0,total=0;
1402 bool domain_request;
1405 if (!str1 || !str2 || !p) {
1409 /* If someone sets all the bits they don't really mean to set
1410 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1413 if (servertype == SV_TYPE_ALL) {
1414 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1417 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1418 any other bit (they may just set this bit on its own) they
1419 want all the locally seen servers. However this bit can be
1420 set on its own so set the requested servers to be
1421 ALL - DOMAIN_ENUM. */
1423 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1424 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1427 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1428 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1432 if (!prefix_ok(str1,"WrLehD")) {
1435 if (!check_server_info(uLevel,str2)) {
1439 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1440 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1441 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1443 if (strcmp(str1, "WrLehDz") == 0) {
1444 if (skip_string(param,tpscnt,p) == NULL) {
1447 pull_ascii_fstring(domain, p);
1449 fstrcpy(domain, lp_workgroup());
1452 DEBUG(4, ("domain [%s]\n", domain));
1454 if (lp_browse_list()) {
1455 total = get_server_info(servertype,&servers,domain);
1458 data_len = fixed_len = string_len = 0;
1461 TYPESAFE_QSORT(servers, total, srv_comp);
1464 char *lastname=NULL;
1466 for (i=0;i<total;i++) {
1467 struct srv_info_struct *s = &servers[i];
1469 if (lastname && strequal(lastname,s->name)) {
1473 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1474 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1475 i, s->name, s->type, s->comment, s->domain));
1477 if (data_len < buf_len) {
1480 string_len += s_len;
1487 *rdata_len = fixed_len + string_len;
1488 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1493 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1499 char *lastname=NULL;
1500 int count2 = counted;
1502 for (i = 0; i < total && count2;i++) {
1503 struct srv_info_struct *s = &servers[i];
1505 if (lastname && strequal(lastname,s->name)) {
1509 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1510 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1511 i, s->name, s->type, s->comment, s->domain));
1517 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1521 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1523 SSVAL(*rparam,4,counted);
1524 SSVAL(*rparam,6,counted+missed);
1528 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1529 domain,uLevel,counted,counted+missed));
1534 static int srv_name_match(const char *n1, const char *n2)
1537 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1539 * In Windows, FirstNameToReturn need not be an exact match:
1540 * the server will return a list of servers that exist on
1541 * the network greater than or equal to the FirstNameToReturn.
1543 int ret = StrCaseCmp(n1, n2);
1552 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1553 char *param, int tpscnt,
1554 char *data, int tdscnt,
1555 int mdrcnt, int mprcnt, char **rdata,
1556 char **rparam, int *rdata_len, int *rparam_len)
1558 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1559 char *str2 = skip_string(param,tpscnt,str1);
1560 char *p = skip_string(param,tpscnt,str2);
1561 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1562 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1563 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1565 int data_len, fixed_len, string_len;
1566 int f_len = 0, s_len = 0;
1567 struct srv_info_struct *servers=NULL;
1568 int counted=0,first=0,total=0;
1572 bool domain_request;
1575 if (!str1 || !str2 || !p) {
1579 /* If someone sets all the bits they don't really mean to set
1580 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1583 if (servertype == SV_TYPE_ALL) {
1584 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1587 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1588 any other bit (they may just set this bit on its own) they
1589 want all the locally seen servers. However this bit can be
1590 set on its own so set the requested servers to be
1591 ALL - DOMAIN_ENUM. */
1593 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1594 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1597 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1598 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1602 if (strcmp(str1, "WrLehDzz") != 0) {
1605 if (!check_server_info(uLevel,str2)) {
1609 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1610 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1611 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1613 if (skip_string(param,tpscnt,p) == NULL) {
1616 pull_ascii_fstring(domain, p);
1617 if (domain[0] == '\0') {
1618 fstrcpy(domain, lp_workgroup());
1620 p = skip_string(param,tpscnt,p);
1621 if (skip_string(param,tpscnt,p) == NULL) {
1624 pull_ascii_fstring(first_name, p);
1626 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1627 domain, first_name));
1629 if (lp_browse_list()) {
1630 total = get_server_info(servertype,&servers,domain);
1633 data_len = fixed_len = string_len = 0;
1636 TYPESAFE_QSORT(servers, total, srv_comp);
1638 if (first_name[0] != '\0') {
1639 struct srv_info_struct *first_server = NULL;
1641 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1642 srv_name_match, first_server);
1644 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1646 * The binary search may not find the exact match
1647 * so we need to search backward to find the first match
1649 * This implements the strange matching windows
1650 * implements. (see the comment in srv_name_match().
1654 ret = StrCaseCmp(first_name,
1655 servers[first-1].name);
1662 /* we should return no entries */
1668 char *lastname=NULL;
1670 for (i=first;i<total;i++) {
1671 struct srv_info_struct *s = &servers[i];
1673 if (lastname && strequal(lastname,s->name)) {
1677 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1678 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1679 i, s->name, s->type, s->comment, s->domain));
1681 if (data_len < buf_len) {
1684 string_len += s_len;
1691 *rdata_len = fixed_len + string_len;
1692 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1697 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1703 char *lastname=NULL;
1704 int count2 = counted;
1706 for (i = first; i < total && count2;i++) {
1707 struct srv_info_struct *s = &servers[i];
1709 if (lastname && strequal(lastname,s->name)) {
1713 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1714 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1715 i, s->name, s->type, s->comment, s->domain));
1721 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1725 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1727 SSVAL(*rparam,4,counted);
1728 SSVAL(*rparam,6,counted+missed);
1730 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1731 domain,uLevel,first,first_name,
1732 first < total ? servers[first].name : "",
1733 counted,counted+missed));
1740 /****************************************************************************
1741 command 0x34 - suspected of being a "Lookup Names" stub api
1742 ****************************************************************************/
1744 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1745 char *param, int tpscnt,
1746 char *data, int tdscnt,
1747 int mdrcnt, int mprcnt, char **rdata,
1748 char **rparam, int *rdata_len, int *rparam_len)
1750 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1751 char *str2 = skip_string(param,tpscnt,str1);
1752 char *p = skip_string(param,tpscnt,str2);
1753 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1754 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1758 if (!str1 || !str2 || !p) {
1762 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1763 str1, str2, p, uLevel, buf_len));
1765 if (!prefix_ok(str1,"zWrLeh")) {
1772 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1777 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1779 SSVAL(*rparam,4,counted);
1780 SSVAL(*rparam,6,counted+missed);
1785 /****************************************************************************
1786 get info about a share
1787 ****************************************************************************/
1789 static bool check_share_info(int uLevel, char* id)
1793 if (strcmp(id,"B13") != 0) {
1798 /* Level-2 descriptor is allowed (and ignored) */
1799 if (strcmp(id,"B13BWz") != 0 &&
1800 strcmp(id,"B13BWzWWWzB9B") != 0) {
1805 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1810 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1820 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1821 char** buf, int* buflen,
1822 char** stringbuf, int* stringspace, char* baseaddr)
1851 len += StrlenExpanded(conn,snum,lp_comment(snum));
1854 len += strlen(lp_pathname(snum)) + 1;
1857 *buflen = struct_len;
1862 return struct_len + len;
1867 if ((*buflen) < struct_len) {
1875 p2 = p + struct_len;
1876 l2 = (*buflen) - struct_len;
1883 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1889 type = STYPE_DISKTREE;
1890 if (lp_print_ok(snum)) {
1891 type = STYPE_PRINTQ;
1893 if (strequal("IPC",lp_fstype(snum))) {
1896 SSVAL(p,14,type); /* device type */
1897 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1898 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1902 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1903 SSVALS(p,22,-1); /* max uses */
1904 SSVAL(p,24,1); /* current uses */
1905 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1906 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1907 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1911 memset(p+40,0,SHPWLEN+2);
1922 (*buf) = p + struct_len;
1923 (*buflen) -= struct_len;
1925 (*stringspace) = l2;
1934 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1935 char *param, int tpscnt,
1936 char *data, int tdscnt,
1937 int mdrcnt,int mprcnt,
1938 char **rdata,char **rparam,
1939 int *rdata_len,int *rparam_len)
1941 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1942 char *str2 = skip_string(param,tpscnt,str1);
1943 char *netname = skip_string(param,tpscnt,str2);
1944 char *p = skip_string(param,tpscnt,netname);
1945 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1948 if (!str1 || !str2 || !netname || !p) {
1952 snum = find_service(netname);
1957 /* check it's a supported varient */
1958 if (!prefix_ok(str1,"zWrLh")) {
1961 if (!check_share_info(uLevel,str2)) {
1965 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1970 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1971 if (*rdata_len < 0) {
1976 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1980 SSVAL(*rparam,0,NERR_Success);
1981 SSVAL(*rparam,2,0); /* converter word */
1982 SSVAL(*rparam,4,*rdata_len);
1987 /****************************************************************************
1988 View the list of available shares.
1990 This function is the server side of the NetShareEnum() RAP call.
1991 It fills the return buffer with share names and share comments.
1992 Note that the return buffer normally (in all known cases) allows only
1993 twelve byte strings for share names (plus one for a nul terminator).
1994 Share names longer than 12 bytes must be skipped.
1995 ****************************************************************************/
1997 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1998 char *param, int tpscnt,
1999 char *data, int tdscnt,
2007 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2008 char *str2 = skip_string(param,tpscnt,str1);
2009 char *p = skip_string(param,tpscnt,str2);
2010 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2011 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2014 int total=0,counted=0;
2015 bool missed = False;
2017 int data_len, fixed_len, string_len;
2018 int f_len = 0, s_len = 0;
2020 if (!str1 || !str2 || !p) {
2024 if (!prefix_ok(str1,"WrLeh")) {
2027 if (!check_share_info(uLevel,str2)) {
2031 /* Ensure all the usershares are loaded. */
2033 load_registry_shares();
2034 count = load_usershare_shares();
2037 data_len = fixed_len = string_len = 0;
2038 for (i=0;i<count;i++) {
2039 fstring servicename_dos;
2040 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2043 push_ascii_fstring(servicename_dos, lp_servicename(i));
2044 /* Maximum name length = 13. */
2045 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2047 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2048 if (data_len < buf_len) {
2051 string_len += s_len;
2058 *rdata_len = fixed_len + string_len;
2059 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2064 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2069 for( i = 0; i < count; i++ ) {
2070 fstring servicename_dos;
2071 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2075 push_ascii_fstring(servicename_dos, lp_servicename(i));
2076 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2077 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2084 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2088 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2090 SSVAL(*rparam,4,counted);
2091 SSVAL(*rparam,6,total);
2093 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2094 counted,total,uLevel,
2095 buf_len,*rdata_len,mdrcnt));
2100 /****************************************************************************
2102 ****************************************************************************/
2104 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2105 char *param, int tpscnt,
2106 char *data, int tdscnt,
2107 int mdrcnt,int mprcnt,
2108 char **rdata,char **rparam,
2109 int *rdata_len,int *rparam_len)
2111 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2112 char *str2 = skip_string(param,tpscnt,str1);
2113 char *p = skip_string(param,tpscnt,str2);
2114 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2117 char *pathname = NULL;
2118 char *command, *cmdname;
2119 unsigned int offset;
2122 size_t converted_size;
2124 if (!str1 || !str2 || !p) {
2128 /* check it's a supported varient */
2129 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2132 if (!check_share_info(uLevel,str2)) {
2139 /* Do we have a string ? */
2140 if (skip_string(data,mdrcnt,data) == NULL) {
2143 pull_ascii_fstring(sharename,data);
2144 snum = find_service(sharename);
2145 if (snum >= 0) { /* already exists */
2154 /* only support disk share adds */
2155 if (SVAL(data,14)!=STYPE_DISKTREE) {
2159 offset = IVAL(data, 16);
2160 if (offset >= mdrcnt) {
2161 res = ERRinvalidparam;
2165 /* Do we have a string ? */
2166 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2169 pull_ascii_fstring(comment, offset? (data+offset) : "");
2171 offset = IVAL(data, 26);
2173 if (offset >= mdrcnt) {
2174 res = ERRinvalidparam;
2178 /* Do we have a string ? */
2179 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2183 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2184 offset ? (data+offset) : "", &converted_size))
2186 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2194 string_replace(sharename, '"', ' ');
2195 string_replace(pathname, '"', ' ');
2196 string_replace(comment, '"', ' ');
2198 cmdname = lp_add_share_cmd();
2200 if (!cmdname || *cmdname == '\0') {
2204 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2205 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2206 pathname, comment) == -1) {
2210 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2212 if ((res = smbrun(command, NULL)) != 0) {
2213 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2220 message_send_all(smbd_messaging_context(),
2221 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2225 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2229 SSVAL(*rparam,0,NERR_Success);
2230 SSVAL(*rparam,2,0); /* converter word */
2231 SSVAL(*rparam,4,*rdata_len);
2239 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2244 SSVAL(*rparam,0,res);
2249 /****************************************************************************
2250 view list of groups available
2251 ****************************************************************************/
2253 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2254 char *param, int tpscnt,
2255 char *data, int tdscnt,
2256 int mdrcnt,int mprcnt,
2257 char **rdata,char **rparam,
2258 int *rdata_len,int *rparam_len)
2262 int resume_context, cli_buf_size;
2263 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2264 char *str2 = skip_string(param,tpscnt,str1);
2265 char *p = skip_string(param,tpscnt,str2);
2267 uint32_t num_groups;
2268 uint32_t resume_handle;
2269 struct rpc_pipe_client *samr_pipe;
2270 struct policy_handle samr_handle, domain_handle;
2273 if (!str1 || !str2 || !p) {
2277 if (strcmp(str1,"WrLeh") != 0) {
2282 * W-> resume context (number of users to skip)
2283 * r -> return parameter pointer to receive buffer
2284 * L -> length of receive buffer
2285 * e -> return parameter number of entries
2286 * h -> return parameter total number of users
2289 if (strcmp("B21",str2) != 0) {
2293 status = rpc_pipe_open_internal(
2294 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2295 conn->server_info, &samr_pipe);
2296 if (!NT_STATUS_IS_OK(status)) {
2297 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2298 nt_errstr(status)));
2302 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2303 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2306 nt_errstr(status)));
2310 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2311 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2312 get_global_sam_sid(), &domain_handle);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2315 nt_errstr(status)));
2316 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2320 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2321 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2322 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2323 "%d\n", resume_context, cli_buf_size));
2325 *rdata_len = cli_buf_size;
2326 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2333 errflags = NERR_Success;
2338 struct samr_SamArray *sam_entries;
2339 uint32_t num_entries;
2341 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2346 if (!NT_STATUS_IS_OK(status)) {
2347 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2348 "%s\n", nt_errstr(status)));
2352 if (num_entries == 0) {
2353 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2354 "no entries -- done\n"));
2358 for(i=0; i<num_entries; i++) {
2361 name = sam_entries->entries[i].name.string;
2363 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2364 /* set overflow error */
2365 DEBUG(3,("overflow on entry %d group %s\n", i,
2371 /* truncate the name at 21 chars. */
2373 strlcpy(p, name, 21);
2374 DEBUG(10,("adding entry %d group %s\n", i, p));
2376 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2381 if (errflags != NERR_Success) {
2385 TALLOC_FREE(sam_entries);
2388 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2389 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2391 *rdata_len = PTR_DIFF(p,*rdata);
2394 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2398 SSVAL(*rparam, 0, errflags);
2399 SSVAL(*rparam, 2, 0); /* converter word */
2400 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2401 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2406 /*******************************************************************
2407 Get groups that a user is a member of.
2408 ******************************************************************/
2410 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2411 char *param, int tpscnt,
2412 char *data, int tdscnt,
2413 int mdrcnt,int mprcnt,
2414 char **rdata,char **rparam,
2415 int *rdata_len,int *rparam_len)
2417 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2418 char *str2 = skip_string(param,tpscnt,str1);
2419 char *UserName = skip_string(param,tpscnt,str2);
2420 char *p = skip_string(param,tpscnt,UserName);
2421 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2422 const char *level_string;
2428 struct rpc_pipe_client *samr_pipe;
2429 struct policy_handle samr_handle, domain_handle, user_handle;
2430 struct lsa_String name;
2431 struct lsa_Strings names;
2432 struct samr_Ids type, rid;
2433 struct samr_RidWithAttributeArray *rids;
2436 if (!str1 || !str2 || !UserName || !p) {
2441 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2446 /* check it's a supported varient */
2448 if ( strcmp(str1,"zWrLeh") != 0 )
2453 level_string = "B21";
2459 if (strcmp(level_string,str2) != 0)
2462 *rdata_len = mdrcnt + 1024;
2463 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2468 SSVAL(*rparam,0,NERR_Success);
2469 SSVAL(*rparam,2,0); /* converter word */
2472 endp = *rdata + *rdata_len;
2474 status = rpc_pipe_open_internal(
2475 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2476 conn->server_info, &samr_pipe);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2479 nt_errstr(status)));
2483 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2484 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2485 if (!NT_STATUS_IS_OK(status)) {
2486 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2487 nt_errstr(status)));
2491 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2492 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2493 get_global_sam_sid(), &domain_handle);
2494 if (!NT_STATUS_IS_OK(status)) {
2495 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2496 nt_errstr(status)));
2500 name.string = UserName;
2502 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2503 &domain_handle, 1, &name,
2505 if (!NT_STATUS_IS_OK(status)) {
2506 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2507 nt_errstr(status)));
2511 if (type.ids[0] != SID_NAME_USER) {
2512 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2513 sid_type_lookup(type.ids[0])));
2517 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2519 SAMR_USER_ACCESS_GET_GROUPS,
2520 rid.ids[0], &user_handle);
2521 if (!NT_STATUS_IS_OK(status)) {
2522 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2523 nt_errstr(status)));
2527 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2528 &user_handle, &rids);
2529 if (!NT_STATUS_IS_OK(status)) {
2530 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2531 nt_errstr(status)));
2535 for (i=0; i<rids->count; i++) {
2537 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2539 1, &rids->rids[i].rid,
2541 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2542 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2548 *rdata_len = PTR_DIFF(p,*rdata);
2550 SSVAL(*rparam,4,count); /* is this right?? */
2551 SSVAL(*rparam,6,count); /* is this right?? */
2556 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2558 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2560 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2565 /*******************************************************************
2567 ******************************************************************/
2569 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2570 char *param, int tpscnt,
2571 char *data, int tdscnt,
2572 int mdrcnt,int mprcnt,
2573 char **rdata,char **rparam,
2574 int *rdata_len,int *rparam_len)
2579 int i, resume_context, cli_buf_size;
2580 uint32_t resume_handle;
2582 struct rpc_pipe_client *samr_pipe;
2583 struct policy_handle samr_handle, domain_handle;
2586 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2587 char *str2 = skip_string(param,tpscnt,str1);
2588 char *p = skip_string(param,tpscnt,str2);
2591 if (!str1 || !str2 || !p) {
2595 if (strcmp(str1,"WrLeh") != 0)
2598 * W-> resume context (number of users to skip)
2599 * r -> return parameter pointer to receive buffer
2600 * L -> length of receive buffer
2601 * e -> return parameter number of entries
2602 * h -> return parameter total number of users
2605 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2606 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2607 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2608 resume_context, cli_buf_size));
2611 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2616 /* check it's a supported varient */
2617 if (strcmp("B21",str2) != 0)
2620 *rdata_len = cli_buf_size;
2621 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2627 endp = *rdata + *rdata_len;
2629 status = rpc_pipe_open_internal(
2630 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2631 conn->server_info, &samr_pipe);
2632 if (!NT_STATUS_IS_OK(status)) {
2633 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2634 nt_errstr(status)));
2638 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2639 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2640 if (!NT_STATUS_IS_OK(status)) {
2641 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2642 nt_errstr(status)));
2646 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2647 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2648 get_global_sam_sid(), &domain_handle);
2649 if (!NT_STATUS_IS_OK(status)) {
2650 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2651 nt_errstr(status)));
2652 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2656 errflags=NERR_Success;
2661 struct samr_SamArray *sam_entries;
2662 uint32_t num_entries;
2664 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2670 if (!NT_STATUS_IS_OK(status)) {
2671 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2672 "%s\n", nt_errstr(status)));
2676 if (num_entries == 0) {
2677 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2678 "no entries -- done\n"));
2682 for (i=0; i<num_entries; i++) {
2685 name = sam_entries->entries[i].name.string;
2687 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2688 &&(strlen(name)<=21)) {
2689 strlcpy(p,name,PTR_DIFF(endp,p));
2690 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2691 "username %s\n",count_sent,p));
2695 /* set overflow error */
2696 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2697 "username %s\n",count_sent,name));
2703 if (errflags != NERR_Success) {
2707 TALLOC_FREE(sam_entries);
2710 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2711 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2713 *rdata_len = PTR_DIFF(p,*rdata);
2715 SSVAL(*rparam,0,errflags);
2716 SSVAL(*rparam,2,0); /* converter word */
2717 SSVAL(*rparam,4,count_sent); /* is this right?? */
2718 SSVAL(*rparam,6,num_users); /* is this right?? */
2723 /****************************************************************************
2724 Get the time of day info.
2725 ****************************************************************************/
2727 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2728 char *param, int tpscnt,
2729 char *data, int tdscnt,
2730 int mdrcnt,int mprcnt,
2731 char **rdata,char **rparam,
2732 int *rdata_len,int *rparam_len)
2735 time_t unixdate = time(NULL);
2739 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2745 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2750 SSVAL(*rparam,0,NERR_Success);
2751 SSVAL(*rparam,2,0); /* converter word */
2755 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2756 by NT in a "net time" operation,
2757 it seems to ignore the one below */
2759 /* the client expects to get localtime, not GMT, in this bit
2760 (I think, this needs testing) */
2761 t = localtime(&unixdate);
2766 SIVAL(p,4,0); /* msecs ? */
2767 SCVAL(p,8,t->tm_hour);
2768 SCVAL(p,9,t->tm_min);
2769 SCVAL(p,10,t->tm_sec);
2770 SCVAL(p,11,0); /* hundredths of seconds */
2771 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2772 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2773 SCVAL(p,16,t->tm_mday);
2774 SCVAL(p,17,t->tm_mon + 1);
2775 SSVAL(p,18,1900+t->tm_year);
2776 SCVAL(p,20,t->tm_wday);
2781 /****************************************************************************
2782 Set the user password.
2783 *****************************************************************************/
2785 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2786 char *param, int tpscnt,
2787 char *data, int tdscnt,
2788 int mdrcnt,int mprcnt,
2789 char **rdata,char **rparam,
2790 int *rdata_len,int *rparam_len)
2792 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2795 fstring pass1,pass2;
2797 /* Skip 2 strings. */
2798 p = skip_string(param,tpscnt,np);
2799 p = skip_string(param,tpscnt,p);
2805 /* Do we have a string ? */
2806 if (skip_string(param,tpscnt,p) == NULL) {
2809 pull_ascii_fstring(user,p);
2811 p = skip_string(param,tpscnt,p);
2816 memset(pass1,'\0',sizeof(pass1));
2817 memset(pass2,'\0',sizeof(pass2));
2819 * We use 31 here not 32 as we're checking
2820 * the last byte we want to access is safe.
2822 if (!is_offset_safe(param,tpscnt,p,31)) {
2826 memcpy(pass2,p+16,16);
2829 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2836 SSVAL(*rparam,0,NERR_badpass);
2837 SSVAL(*rparam,2,0); /* converter word */
2839 DEBUG(3,("Set password for <%s>\n",user));
2842 * Attempt to verify the old password against smbpasswd entries
2843 * Win98 clients send old and new password in plaintext for this call.
2847 struct auth_serversupplied_info *server_info = NULL;
2848 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2850 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2853 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2854 SSVAL(*rparam,0,NERR_Success);
2858 TALLOC_FREE(server_info);
2860 data_blob_clear_free(&password);
2864 * If the plaintext change failed, attempt
2865 * the old encrypted method. NT will generate this
2866 * after trying the samr method. Note that this
2867 * method is done as a last resort as this
2868 * password change method loses the NT password hash
2869 * and cannot change the UNIX password as no plaintext
2873 if(SVAL(*rparam,0) != NERR_Success) {
2874 struct samu *hnd = NULL;
2876 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2878 if (change_lanman_password(hnd,(uchar *)pass2)) {
2879 SSVAL(*rparam,0,NERR_Success);
2886 memset((char *)pass1,'\0',sizeof(fstring));
2887 memset((char *)pass2,'\0',sizeof(fstring));
2892 /****************************************************************************
2893 Set the user password (SamOEM version - gets plaintext).
2894 ****************************************************************************/
2896 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2897 char *param, int tpscnt,
2898 char *data, int tdscnt,
2899 int mdrcnt,int mprcnt,
2900 char **rdata,char **rparam,
2901 int *rdata_len,int *rparam_len)
2903 struct smbd_server_connection *sconn = smbd_server_conn;
2905 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2907 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2917 SSVAL(*rparam,0,NERR_badpass);
2920 * Check the parameter definition is correct.
2923 /* Do we have a string ? */
2924 if (skip_string(param,tpscnt,p) == 0) {
2927 if(!strequal(p, "zsT")) {
2928 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2931 p = skip_string(param, tpscnt, p);
2936 /* Do we have a string ? */
2937 if (skip_string(param,tpscnt,p) == 0) {
2940 if(!strequal(p, "B516B16")) {
2941 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2944 p = skip_string(param,tpscnt,p);
2948 /* Do we have a string ? */
2949 if (skip_string(param,tpscnt,p) == 0) {
2952 p += pull_ascii_fstring(user,p);
2954 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2957 * Pass the user through the NT -> unix user mapping
2961 (void)map_username(sconn, user);
2963 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2964 SSVAL(*rparam,0,NERR_Success);
2970 /****************************************************************************
2973 ****************************************************************************/
2975 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2976 char *param, int tpscnt,
2977 char *data, int tdscnt,
2978 int mdrcnt,int mprcnt,
2979 char **rdata,char **rparam,
2980 int *rdata_len,int *rparam_len)
2982 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2983 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2984 char *str2 = skip_string(param,tpscnt,str1);
2985 char *p = skip_string(param,tpscnt,str2);
2989 WERROR werr = WERR_OK;
2991 TALLOC_CTX *mem_ctx = talloc_tos();
2993 struct rpc_pipe_client *cli = NULL;
2994 struct policy_handle handle;
2995 struct spoolss_DevmodeContainer devmode_ctr;
2996 enum spoolss_JobControl command;
2998 if (!str1 || !str2 || !p) {
3002 * We use 1 here not 2 as we're checking
3003 * the last byte we want to access is safe.
3005 if (!is_offset_safe(param,tpscnt,p,1)) {
3008 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3011 /* check it's a supported varient */
3012 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3016 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3022 ZERO_STRUCT(handle);
3024 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3025 rpc_spoolss_dispatch, conn->server_info,
3027 if (!NT_STATUS_IS_OK(status)) {
3028 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3029 nt_errstr(status)));
3030 errcode = W_ERROR_V(ntstatus_to_werror(status));
3034 ZERO_STRUCT(devmode_ctr);
3036 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3040 SEC_FLAG_MAXIMUM_ALLOWED,
3043 if (!NT_STATUS_IS_OK(status)) {
3044 errcode = W_ERROR_V(ntstatus_to_werror(status));
3047 if (!W_ERROR_IS_OK(werr)) {
3048 errcode = W_ERROR_V(werr);
3052 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3053 * and NERR_DestNotFound if share did not exist */
3055 errcode = NERR_Success;
3058 case 81: /* delete */
3059 command = SPOOLSS_JOB_CONTROL_DELETE;
3061 case 82: /* pause */
3062 command = SPOOLSS_JOB_CONTROL_PAUSE;
3064 case 83: /* resume */
3065 command = SPOOLSS_JOB_CONTROL_RESUME;
3068 errcode = NERR_notsupported;
3072 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3075 NULL, /* unique ptr ctr */
3078 if (!NT_STATUS_IS_OK(status)) {
3079 errcode = W_ERROR_V(ntstatus_to_werror(status));
3082 if (!W_ERROR_IS_OK(werr)) {
3083 errcode = W_ERROR_V(werr);
3088 if (is_valid_policy_hnd(&handle)) {
3089 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3092 SSVAL(*rparam,0,errcode);
3093 SSVAL(*rparam,2,0); /* converter word */
3098 /****************************************************************************
3099 Purge a print queue - or pause or resume it.
3100 ****************************************************************************/
3102 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3103 char *param, int tpscnt,
3104 char *data, int tdscnt,
3105 int mdrcnt,int mprcnt,
3106 char **rdata,char **rparam,
3107 int *rdata_len,int *rparam_len)
3109 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3110 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3111 char *str2 = skip_string(param,tpscnt,str1);
3112 char *QueueName = skip_string(param,tpscnt,str2);
3113 int errcode = NERR_notsupported;
3114 WERROR werr = WERR_OK;
3117 TALLOC_CTX *mem_ctx = talloc_tos();
3118 struct rpc_pipe_client *cli = NULL;
3119 struct policy_handle handle;
3120 struct spoolss_SetPrinterInfoCtr info_ctr;
3121 struct spoolss_DevmodeContainer devmode_ctr;
3122 struct sec_desc_buf secdesc_ctr;
3123 enum spoolss_PrinterControl command;
3125 if (!str1 || !str2 || !QueueName) {
3129 /* check it's a supported varient */
3130 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3134 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3140 if (skip_string(param,tpscnt,QueueName) == NULL) {
3144 ZERO_STRUCT(handle);
3146 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3147 rpc_spoolss_dispatch, conn->server_info,
3149 if (!NT_STATUS_IS_OK(status)) {
3150 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3151 nt_errstr(status)));
3152 errcode = W_ERROR_V(ntstatus_to_werror(status));
3156 ZERO_STRUCT(devmode_ctr);
3158 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3162 SEC_FLAG_MAXIMUM_ALLOWED,
3165 if (!NT_STATUS_IS_OK(status)) {
3166 errcode = W_ERROR_V(ntstatus_to_werror(status));
3169 if (!W_ERROR_IS_OK(werr)) {
3170 errcode = W_ERROR_V(werr);
3175 case 74: /* Pause queue */
3176 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3178 case 75: /* Resume queue */
3179 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3181 case 103: /* Purge */
3182 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3185 werr = WERR_NOT_SUPPORTED;
3189 if (!W_ERROR_IS_OK(werr)) {
3190 errcode = W_ERROR_V(werr);
3194 ZERO_STRUCT(info_ctr);
3195 ZERO_STRUCT(secdesc_ctr);
3197 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3204 if (!NT_STATUS_IS_OK(status)) {
3205 errcode = W_ERROR_V(ntstatus_to_werror(status));
3208 if (!W_ERROR_IS_OK(werr)) {
3209 errcode = W_ERROR_V(werr);
3213 errcode = W_ERROR_V(werr);
3217 if (is_valid_policy_hnd(&handle)) {
3218 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3221 SSVAL(*rparam,0,errcode);
3222 SSVAL(*rparam,2,0); /* converter word */
3227 /****************************************************************************
3228 set the property of a print job (undocumented?)
3229 ? function = 0xb -> set name of print job
3230 ? function = 0x6 -> move print job up/down
3231 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3232 or <WWsTP> <WB21BB16B10zWWzDDz>
3233 ****************************************************************************/
3235 static int check_printjob_info(struct pack_desc* desc,
3236 int uLevel, char* id)
3238 desc->subformat = NULL;
3240 case 0: desc->format = "W"; break;
3241 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3242 case 2: desc->format = "WWzWWDDzz"; break;
3243 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3244 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3246 DEBUG(0,("check_printjob_info: invalid level %d\n",
3250 if (id == NULL || strcmp(desc->format,id) != 0) {
3251 DEBUG(0,("check_printjob_info: invalid format %s\n",
3252 id ? id : "<NULL>" ));
3258 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3259 char *param, int tpscnt,
3260 char *data, int tdscnt,
3261 int mdrcnt,int mprcnt,
3262 char **rdata,char **rparam,
3263 int *rdata_len,int *rparam_len)
3265 struct pack_desc desc;
3266 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3267 char *str2 = skip_string(param,tpscnt,str1);
3268 char *p = skip_string(param,tpscnt,str2);
3271 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3272 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3275 TALLOC_CTX *mem_ctx = talloc_tos();
3278 struct rpc_pipe_client *cli = NULL;
3279 struct policy_handle handle;
3280 struct spoolss_DevmodeContainer devmode_ctr;
3281 struct spoolss_JobInfoContainer ctr;
3282 union spoolss_JobInfo info;
3283 struct spoolss_SetJobInfo1 info1;
3285 if (!str1 || !str2 || !p) {
3289 * We use 1 here not 2 as we're checking
3290 * the last byte we want to access is safe.
3292 if (!is_offset_safe(param,tpscnt,p,1)) {
3295 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3298 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3303 ZERO_STRUCT(handle);
3305 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3306 rpc_spoolss_dispatch, conn->server_info,
3308 if (!NT_STATUS_IS_OK(status)) {
3309 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3310 nt_errstr(status)));
3311 errcode = W_ERROR_V(ntstatus_to_werror(status));
3315 ZERO_STRUCT(devmode_ctr);
3317 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3321 SEC_FLAG_MAXIMUM_ALLOWED,
3324 if (!NT_STATUS_IS_OK(status)) {
3325 errcode = W_ERROR_V(ntstatus_to_werror(status));
3328 if (!W_ERROR_IS_OK(werr)) {
3329 errcode = W_ERROR_V(werr);
3335 /* check it's a supported varient */
3336 if ((strcmp(str1,"WWsTP")) ||
3337 (!check_printjob_info(&desc,uLevel,str2)))
3340 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3346 if (!W_ERROR_IS_OK(werr)) {
3347 errcode = W_ERROR_V(werr);
3351 errcode = NERR_notsupported;
3355 /* change print job name, data gives the name */
3363 info1.job_id = info.info1.job_id;
3364 info1.printer_name = info.info1.printer_name;
3365 info1.user_name = info.info1.user_name;
3366 info1.document_name = data;
3367 info1.data_type = info.info1.data_type;
3368 info1.text_status = info.info1.text_status;
3369 info1.status = info.info1.status;
3370 info1.priority = info.info1.priority;
3371 info1.position = info.info1.position;
3372 info1.total_pages = info.info1.total_pages;
3373 info1.pages_printed = info.info1.pages_printed;
3374 info1.submitted = info.info1.submitted;
3377 ctr.info.info1 = &info1;
3379 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3385 if (!NT_STATUS_IS_OK(status)) {
3386 errcode = W_ERROR_V(ntstatus_to_werror(status));
3389 if (!W_ERROR_IS_OK(werr)) {
3390 errcode = W_ERROR_V(werr);
3394 errcode = NERR_Success;
3397 if (is_valid_policy_hnd(&handle)) {
3398 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3401 SSVALS(*rparam,0,errcode);
3402 SSVAL(*rparam,2,0); /* converter word */
3408 /****************************************************************************
3409 Get info about the server.
3410 ****************************************************************************/
3412 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3413 char *param, int tpscnt,
3414 char *data, int tdscnt,
3415 int mdrcnt,int mprcnt,
3416 char **rdata,char **rparam,
3417 int *rdata_len,int *rparam_len)
3419 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3420 char *str2 = skip_string(param,tpscnt,str1);
3421 char *p = skip_string(param,tpscnt,str2);
3422 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3426 if (!str1 || !str2 || !p) {
3430 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3432 /* check it's a supported varient */
3433 if (!prefix_ok(str1,"WrLh")) {
3439 if (strcmp(str2,"B16") != 0) {
3445 if (strcmp(str2,"B16BBDz") != 0) {
3451 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3457 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3463 if (strcmp(str2,"DN") != 0) {
3469 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3478 *rdata_len = mdrcnt;
3479 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3485 p2 = p + struct_len;
3487 srvstr_push(NULL, 0, p,global_myname(),16,
3488 STR_ASCII|STR_UPPER|STR_TERMINATE);
3492 struct srv_info_struct *servers=NULL;
3494 char *comment = NULL;
3495 TALLOC_CTX *ctx = talloc_tos();
3496 uint32 servertype= lp_default_server_announce();
3498 comment = talloc_strdup(ctx,lp_serverstring());
3503 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3504 for (i=0;i<count;i++) {
3505 if (strequal(servers[i].name,global_myname())) {
3506 servertype = servers[i].type;
3507 TALLOC_FREE(comment);
3508 comment = talloc_strdup(ctx,
3509 servers[i].comment);
3519 SCVAL(p,0,lp_major_announce_version());
3520 SCVAL(p,1,lp_minor_announce_version());
3521 SIVAL(p,2,servertype);
3523 if (mdrcnt == struct_len) {
3526 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3527 comment = talloc_sub_advanced(
3529 lp_servicename(SNUM(conn)),
3530 conn->server_info->unix_name,
3532 conn->server_info->utok.gid,
3533 conn->server_info->sanitized_username,
3534 pdb_get_domain(conn->server_info->sam_account),
3539 if (mdrcnt - struct_len <= 0) {
3544 MIN(mdrcnt - struct_len,
3545 MAX_SERVER_STRING_LENGTH),
3547 p2 = skip_string(*rdata,*rdata_len,p2);
3555 return False; /* not yet implemented */
3558 *rdata_len = PTR_DIFF(p2,*rdata);
3561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3565 SSVAL(*rparam,0,NERR_Success);
3566 SSVAL(*rparam,2,0); /* converter word */
3567 SSVAL(*rparam,4,*rdata_len);
3572 /****************************************************************************
3573 Get info about the server.
3574 ****************************************************************************/
3576 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3577 char *param, int tpscnt,
3578 char *data, int tdscnt,
3579 int mdrcnt,int mprcnt,
3580 char **rdata,char **rparam,
3581 int *rdata_len,int *rparam_len)
3583 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3584 char *str2 = skip_string(param,tpscnt,str1);
3585 char *p = skip_string(param,tpscnt,str2);
3588 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3590 if (!str1 || !str2 || !p) {
3594 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3597 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3602 /* check it's a supported varient */
3603 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3607 *rdata_len = mdrcnt + 1024;
3608 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3613 SSVAL(*rparam,0,NERR_Success);
3614 SSVAL(*rparam,2,0); /* converter word */
3617 endp = *rdata + *rdata_len;
3619 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3624 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3625 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3627 p2 = skip_string(*rdata,*rdata_len,p2);
3633 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3634 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3635 p2 = skip_string(*rdata,*rdata_len,p2);
3641 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3642 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3644 p2 = skip_string(*rdata,*rdata_len,p2);
3650 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3651 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3654 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3655 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3656 p2 = skip_string(*rdata,*rdata_len,p2);
3662 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3663 strlcpy(p2,"",PTR_DIFF(endp,p2));
3664 p2 = skip_string(*rdata,*rdata_len,p2);
3670 *rdata_len = PTR_DIFF(p2,*rdata);
3672 SSVAL(*rparam,4,*rdata_len);
3677 /****************************************************************************
3678 get info about a user
3680 struct user_info_11 {
3681 char usri11_name[21]; 0-20
3683 char *usri11_comment; 22-25
3684 char *usri11_usr_comment; 26-29
3685 unsigned short usri11_priv; 30-31
3686 unsigned long usri11_auth_flags; 32-35
3687 long usri11_password_age; 36-39
3688 char *usri11_homedir; 40-43
3689 char *usri11_parms; 44-47
3690 long usri11_last_logon; 48-51
3691 long usri11_last_logoff; 52-55
3692 unsigned short usri11_bad_pw_count; 56-57
3693 unsigned short usri11_num_logons; 58-59
3694 char *usri11_logon_server; 60-63
3695 unsigned short usri11_country_code; 64-65
3696 char *usri11_workstations; 66-69
3697 unsigned long usri11_max_storage; 70-73
3698 unsigned short usri11_units_per_week; 74-75
3699 unsigned char *usri11_logon_hours; 76-79
3700 unsigned short usri11_code_page; 80-81
3705 usri11_name specifies the user name for which information is retrieved
3707 usri11_pad aligns the next data structure element to a word boundary
3709 usri11_comment is a null terminated ASCII comment
3711 usri11_user_comment is a null terminated ASCII comment about the user
3713 usri11_priv specifies the level of the privilege assigned to the user.
3714 The possible values are:
3716 Name Value Description
3717 USER_PRIV_GUEST 0 Guest privilege
3718 USER_PRIV_USER 1 User privilege
3719 USER_PRV_ADMIN 2 Administrator privilege
3721 usri11_auth_flags specifies the account operator privileges. The
3722 possible values are:
3724 Name Value Description
3725 AF_OP_PRINT 0 Print operator
3728 Leach, Naik [Page 28]
3732 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3735 AF_OP_COMM 1 Communications operator
3736 AF_OP_SERVER 2 Server operator
3737 AF_OP_ACCOUNTS 3 Accounts operator
3740 usri11_password_age specifies how many seconds have elapsed since the
3741 password was last changed.
3743 usri11_home_dir points to a null terminated ASCII string that contains
3744 the path name of the user's home directory.
3746 usri11_parms points to a null terminated ASCII string that is set
3747 aside for use by applications.
3749 usri11_last_logon specifies the time when the user last logged on.
3750 This value is stored as the number of seconds elapsed since
3751 00:00:00, January 1, 1970.
3753 usri11_last_logoff specifies the time when the user last logged off.
3754 This value is stored as the number of seconds elapsed since
3755 00:00:00, January 1, 1970. A value of 0 means the last logoff
3758 usri11_bad_pw_count specifies the number of incorrect passwords
3759 entered since the last successful logon.
3761 usri11_log1_num_logons specifies the number of times this user has
3762 logged on. A value of -1 means the number of logons is unknown.
3764 usri11_logon_server points to a null terminated ASCII string that
3765 contains the name of the server to which logon requests are sent.
3766 A null string indicates logon requests should be sent to the
3769 usri11_country_code specifies the country code for the user's language
3772 usri11_workstations points to a null terminated ASCII string that
3773 contains the names of workstations the user may log on from.
3774 There may be up to 8 workstations, with the names separated by
3775 commas. A null strings indicates there are no restrictions.
3777 usri11_max_storage specifies the maximum amount of disk space the user
3778 can occupy. A value of 0xffffffff indicates there are no
3781 usri11_units_per_week specifies the equal number of time units into
3782 which a week is divided. This value must be equal to 168.
3784 usri11_logon_hours points to a 21 byte (168 bits) string that
3785 specifies the time during which the user can log on. Each bit
3786 represents one unique hour in a week. The first bit (bit 0, word
3787 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3791 Leach, Naik [Page 29]
3795 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3798 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3799 are no restrictions.
3801 usri11_code_page specifies the code page for the user's language of
3804 All of the pointers in this data structure need to be treated
3805 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3806 to be ignored. The converter word returned in the parameters section
3807 needs to be subtracted from the lower 16 bits to calculate an offset
3808 into the return buffer where this ASCII string resides.
3810 There is no auxiliary data in the response.
3812 ****************************************************************************/
3814 #define usri11_name 0
3815 #define usri11_pad 21
3816 #define usri11_comment 22
3817 #define usri11_usr_comment 26
3818 #define usri11_full_name 30
3819 #define usri11_priv 34
3820 #define usri11_auth_flags 36
3821 #define usri11_password_age 40
3822 #define usri11_homedir 44
3823 #define usri11_parms 48
3824 #define usri11_last_logon 52
3825 #define usri11_last_logoff 56
3826 #define usri11_bad_pw_count 60
3827 #define usri11_num_logons 62
3828 #define usri11_logon_server 64
3829 #define usri11_country_code 68
3830 #define usri11_workstations 70
3831 #define usri11_max_storage 74
3832 #define usri11_units_per_week 78
3833 #define usri11_logon_hours 80
3834 #define usri11_code_page 84
3835 #define usri11_end 86
3837 #define USER_PRIV_GUEST 0
3838 #define USER_PRIV_USER 1
3839 #define USER_PRIV_ADMIN 2
3841 #define AF_OP_PRINT 0
3842 #define AF_OP_COMM 1
3843 #define AF_OP_SERVER 2
3844 #define AF_OP_ACCOUNTS 3
3847 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3848 char *param, int tpscnt,
3849 char *data, int tdscnt,
3850 int mdrcnt,int mprcnt,
3851 char **rdata,char **rparam,
3852 int *rdata_len,int *rparam_len)
3854 struct smbd_server_connection *sconn = smbd_server_conn;
3855 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3856 char *str2 = skip_string(param,tpscnt,str1);
3857 char *UserName = skip_string(param,tpscnt,str2);
3858 char *p = skip_string(param,tpscnt,UserName);
3859 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3862 const char *level_string;
3864 /* get NIS home of a previously validated user - simeon */
3865 /* With share level security vuid will always be zero.
3866 Don't depend on vuser being non-null !!. JRA */
3867 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3869 DEBUG(3,(" Username of UID %d is %s\n",
3870 (int)vuser->server_info->utok.uid,
3871 vuser->server_info->unix_name));
3874 if (!str1 || !str2 || !UserName || !p) {
3879 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3884 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3886 /* check it's a supported variant */
3887 if (strcmp(str1,"zWrLh") != 0) {
3891 case 0: level_string = "B21"; break;
3892 case 1: level_string = "B21BB16DWzzWz"; break;
3893 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3894 case 10: level_string = "B21Bzzz"; break;
3895 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3896 default: return False;
3899 if (strcmp(level_string,str2) != 0) {
3903 *rdata_len = mdrcnt + 1024;
3904 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3909 SSVAL(*rparam,0,NERR_Success);
3910 SSVAL(*rparam,2,0); /* converter word */
3913 endp = *rdata + *rdata_len;
3914 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3920 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3923 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3928 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3929 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3930 p2 = skip_string(*rdata,*rdata_len,p2);
3935 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3936 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3937 p2 = skip_string(*rdata,*rdata_len,p2);
3942 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3943 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3944 strlcpy(p2,((vuser != NULL)
3945 ? pdb_get_fullname(vuser->server_info->sam_account)
3946 : UserName),PTR_DIFF(endp,p2));
3947 p2 = skip_string(*rdata,*rdata_len,p2);
3954 const char *homedir = "";
3955 if (vuser != NULL) {
3956 homedir = pdb_get_homedir(
3957 vuser->server_info->sam_account);
3959 /* modelled after NTAS 3.51 reply */
3960 SSVAL(p,usri11_priv,
3961 (get_current_uid(conn) == sec_initial_uid())?
3962 USER_PRIV_ADMIN:USER_PRIV_USER);
3963 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3964 SIVALS(p,usri11_password_age,-1); /* password age */
3965 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3966 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3967 p2 = skip_string(*rdata,*rdata_len,p2);
3971 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3972 strlcpy(p2,"",PTR_DIFF(endp,p2));
3973 p2 = skip_string(*rdata,*rdata_len,p2);
3977 SIVAL(p,usri11_last_logon,0); /* last logon */
3978 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3979 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3980 SSVALS(p,usri11_num_logons,-1); /* num logons */
3981 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3982 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3983 p2 = skip_string(*rdata,*rdata_len,p2);
3987 SSVAL(p,usri11_country_code,0); /* country code */
3989 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3990 strlcpy(p2,"",PTR_DIFF(endp,p2));
3991 p2 = skip_string(*rdata,*rdata_len,p2);
3996 SIVALS(p,usri11_max_storage,-1); /* max storage */
3997 SSVAL(p,usri11_units_per_week,168); /* units per week */
3998 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4000 /* a simple way to get logon hours at all times. */
4002 SCVAL(p2,21,0); /* fix zero termination */
4003 p2 = skip_string(*rdata,*rdata_len,p2);
4008 SSVAL(p,usri11_code_page,0); /* code page */
4011 if (uLevel == 1 || uLevel == 2) {
4012 memset(p+22,' ',16); /* password */
4013 SIVALS(p,38,-1); /* password age */
4015 (get_current_uid(conn) == sec_initial_uid())?
4016 USER_PRIV_ADMIN:USER_PRIV_USER);
4017 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4018 strlcpy(p2, vuser ? pdb_get_homedir(
4019 vuser->server_info->sam_account) : "",
4021 p2 = skip_string(*rdata,*rdata_len,p2);
4025 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4027 SSVAL(p,52,0); /* flags */
4028 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4029 strlcpy(p2, vuser ? pdb_get_logon_script(
4030 vuser->server_info->sam_account) : "",
4032 p2 = skip_string(*rdata,*rdata_len,p2);
4037 SIVAL(p,60,0); /* auth_flags */
4038 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4039 strlcpy(p2,((vuser != NULL)
4040 ? pdb_get_fullname(vuser->server_info->sam_account)
4041 : UserName),PTR_DIFF(endp,p2));
4042 p2 = skip_string(*rdata,*rdata_len,p2);
4046 SIVAL(p,68,0); /* urs_comment */
4047 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4048 strlcpy(p2,"",PTR_DIFF(endp,p2));
4049 p2 = skip_string(*rdata,*rdata_len,p2);
4053 SIVAL(p,76,0); /* workstations */
4054 SIVAL(p,80,0); /* last_logon */
4055 SIVAL(p,84,0); /* last_logoff */
4056 SIVALS(p,88,-1); /* acct_expires */
4057 SIVALS(p,92,-1); /* max_storage */
4058 SSVAL(p,96,168); /* units_per_week */
4059 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4062 SSVALS(p,102,-1); /* bad_pw_count */
4063 SSVALS(p,104,-1); /* num_logons */
4064 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4066 TALLOC_CTX *ctx = talloc_tos();
4067 int space_rem = *rdata_len - (p2 - *rdata);
4070 if (space_rem <= 0) {
4073 tmp = talloc_strdup(ctx, "\\\\%L");
4077 tmp = talloc_sub_basic(ctx,
4090 p2 = skip_string(*rdata,*rdata_len,p2);
4094 SSVAL(p,110,49); /* country_code */
4095 SSVAL(p,112,860); /* code page */
4099 *rdata_len = PTR_DIFF(p2,*rdata);
4101 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4106 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4107 char *param, int tpscnt,
4108 char *data, int tdscnt,
4109 int mdrcnt,int mprcnt,
4110 char **rdata,char **rparam,
4111 int *rdata_len,int *rparam_len)
4113 struct smbd_server_connection *sconn = smbd_server_conn;
4114 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4115 char *str2 = skip_string(param,tpscnt,str1);
4116 char *p = skip_string(param,tpscnt,str2);
4118 struct pack_desc desc;
4120 /* With share level security vuid will always be zero.
4121 Don't depend on vuser being non-null !!. JRA */
4122 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4124 if (!str1 || !str2 || !p) {
4129 DEBUG(3,(" Username of UID %d is %s\n",
4130 (int)vuser->server_info->utok.uid,
4131 vuser->server_info->unix_name));
4134 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4135 name = get_safe_str_ptr(param,tpscnt,p,2);
4140 memset((char *)&desc,'\0',sizeof(desc));
4142 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4144 /* check it's a supported varient */
4145 if (strcmp(str1,"OOWb54WrLh") != 0) {
4148 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4152 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4159 desc.buflen = mdrcnt;
4160 desc.subformat = NULL;
4163 if (init_package(&desc,1,0)) {
4164 PACKI(&desc,"W",0); /* code */
4165 PACKS(&desc,"B21",name); /* eff. name */
4166 PACKS(&desc,"B",""); /* pad */
4168 (get_current_uid(conn) == sec_initial_uid())?
4169 USER_PRIV_ADMIN:USER_PRIV_USER);
4170 PACKI(&desc,"D",0); /* auth flags XXX */
4171 PACKI(&desc,"W",0); /* num logons */
4172 PACKI(&desc,"W",0); /* bad pw count */
4173 PACKI(&desc,"D",0); /* last logon */
4174 PACKI(&desc,"D",-1); /* last logoff */
4175 PACKI(&desc,"D",-1); /* logoff time */
4176 PACKI(&desc,"D",-1); /* kickoff time */
4177 PACKI(&desc,"D",0); /* password age */
4178 PACKI(&desc,"D",0); /* password can change */
4179 PACKI(&desc,"D",-1); /* password must change */
4183 fstrcpy(mypath,"\\\\");
4184 fstrcat(mypath,get_local_machine_name());
4186 PACKS(&desc,"z",mypath); /* computer */
4189 PACKS(&desc,"z",lp_workgroup());/* domain */
4190 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4191 vuser->server_info->sam_account) : ""); /* script path */
4192 PACKI(&desc,"D",0x00000000); /* reserved */
4195 *rdata_len = desc.usedlen;
4197 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4201 SSVALS(*rparam,0,desc.errcode);
4203 SSVAL(*rparam,4,desc.neededlen);
4205 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4210 /****************************************************************************
4211 api_WAccessGetUserPerms
4212 ****************************************************************************/
4214 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4215 char *param, int tpscnt,
4216 char *data, int tdscnt,
4217 int mdrcnt,int mprcnt,
4218 char **rdata,char **rparam,
4219 int *rdata_len,int *rparam_len)
4221 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4222 char *str2 = skip_string(param,tpscnt,str1);
4223 char *user = skip_string(param,tpscnt,str2);
4224 char *resource = skip_string(param,tpscnt,user);
4226 if (!str1 || !str2 || !user || !resource) {
4230 if (skip_string(param,tpscnt,resource) == NULL) {
4233 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4235 /* check it's a supported varient */
4236 if (strcmp(str1,"zzh") != 0) {
4239 if (strcmp(str2,"") != 0) {
4244 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4248 SSVALS(*rparam,0,0); /* errorcode */
4249 SSVAL(*rparam,2,0); /* converter word */
4250 SSVAL(*rparam,4,0x7f); /* permission flags */
4255 /****************************************************************************
4256 api_WPrintJobEnumerate
4257 ****************************************************************************/
4259 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4260 char *param, int tpscnt,
4261 char *data, int tdscnt,
4262 int mdrcnt,int mprcnt,
4263 char **rdata,char **rparam,
4264 int *rdata_len,int *rparam_len)
4266 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4267 char *str2 = skip_string(param,tpscnt,str1);
4268 char *p = skip_string(param,tpscnt,str2);
4272 struct pack_desc desc;
4275 TALLOC_CTX *mem_ctx = talloc_tos();
4278 struct rpc_pipe_client *cli = NULL;
4279 struct policy_handle handle;
4280 struct spoolss_DevmodeContainer devmode_ctr;
4281 union spoolss_JobInfo info;
4283 if (!str1 || !str2 || !p) {
4287 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4289 memset((char *)&desc,'\0',sizeof(desc));
4290 memset((char *)&status,'\0',sizeof(status));
4292 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4294 /* check it's a supported varient */
4295 if (strcmp(str1,"WWrLh") != 0) {
4298 if (!check_printjob_info(&desc,uLevel,str2)) {
4302 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4306 ZERO_STRUCT(handle);
4308 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4309 rpc_spoolss_dispatch, conn->server_info,
4311 if (!NT_STATUS_IS_OK(status)) {
4312 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4313 nt_errstr(status)));
4314 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4318 ZERO_STRUCT(devmode_ctr);
4320 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4324 SEC_FLAG_MAXIMUM_ALLOWED,
4327 if (!NT_STATUS_IS_OK(status)) {
4328 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4331 if (!W_ERROR_IS_OK(werr)) {
4332 desc.errcode = W_ERROR_V(werr);
4336 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4342 if (!W_ERROR_IS_OK(werr)) {
4343 desc.errcode = W_ERROR_V(werr);
4348 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4353 desc.buflen = mdrcnt;
4356 * Don't return data but need to get correct length
4357 * init_package will return wrong size if buflen=0
4359 desc.buflen = getlen(desc.format);
4360 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4363 if (init_package(&desc,1,0)) {
4364 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4365 *rdata_len = desc.usedlen;
4367 desc.errcode = NERR_JobNotFound;
4371 if (is_valid_policy_hnd(&handle)) {
4372 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4376 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4380 SSVALS(*rparam,0,desc.errcode);
4382 SSVAL(*rparam,4,desc.neededlen);
4386 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4391 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4392 char *param, int tpscnt,
4393 char *data, int tdscnt,
4394 int mdrcnt,int mprcnt,
4395 char **rdata,char **rparam,
4396 int *rdata_len,int *rparam_len)
4398 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4399 char *str2 = skip_string(param,tpscnt,str1);
4400 char *p = skip_string(param,tpscnt,str2);
4404 struct pack_desc desc;
4406 TALLOC_CTX *mem_ctx = talloc_tos();
4409 struct rpc_pipe_client *cli = NULL;
4410 struct policy_handle handle;
4411 struct spoolss_DevmodeContainer devmode_ctr;
4413 union spoolss_JobInfo *info;
4415 if (!str1 || !str2 || !p) {
4419 memset((char *)&desc,'\0',sizeof(desc));
4421 p = skip_string(param,tpscnt,p);
4425 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4427 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4429 /* check it's a supported variant */
4430 if (strcmp(str1,"zWrLeh") != 0) {
4435 return False; /* defined only for uLevel 0,1,2 */
4438 if (!check_printjob_info(&desc,uLevel,str2)) {
4442 ZERO_STRUCT(handle);
4444 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4445 rpc_spoolss_dispatch, conn->server_info,
4447 if (!NT_STATUS_IS_OK(status)) {
4448 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
4449 nt_errstr(status)));
4450 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4454 ZERO_STRUCT(devmode_ctr);
4456 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4460 SEC_FLAG_MAXIMUM_ALLOWED,
4463 if (!NT_STATUS_IS_OK(status)) {
4464 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4467 if (!W_ERROR_IS_OK(werr)) {
4468 desc.errcode = W_ERROR_V(werr);
4472 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4480 if (!W_ERROR_IS_OK(werr)) {
4481 desc.errcode = W_ERROR_V(werr);
4486 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4492 desc.buflen = mdrcnt;
4494 if (init_package(&desc,count,0)) {
4496 for (i = 0; i < count; i++) {
4497 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4498 if (desc.errcode == NERR_Success) {
4504 if (is_valid_policy_hnd(&handle)) {
4505 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4508 *rdata_len = desc.usedlen;
4511 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4515 SSVALS(*rparam,0,desc.errcode);
4517 SSVAL(*rparam,4,succnt);
4518 SSVAL(*rparam,6,count);
4520 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4525 static int check_printdest_info(struct pack_desc* desc,
4526 int uLevel, char* id)
4528 desc->subformat = NULL;
4531 desc->format = "B9";
4534 desc->format = "B9B21WWzW";
4540 desc->format = "zzzWWzzzWW";
4543 DEBUG(0,("check_printdest_info: invalid level %d\n",
4547 if (id == NULL || strcmp(desc->format,id) != 0) {
4548 DEBUG(0,("check_printdest_info: invalid string %s\n",
4549 id ? id : "<NULL>" ));
4555 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4556 struct pack_desc* desc)
4560 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4561 buf[sizeof(buf)-1] = 0;
4565 PACKS(desc,"B9",buf); /* szName */
4567 PACKS(desc,"B21",""); /* szUserName */
4568 PACKI(desc,"W",0); /* uJobId */
4569 PACKI(desc,"W",0); /* fsStatus */
4570 PACKS(desc,"z",""); /* pszStatus */
4571 PACKI(desc,"W",0); /* time */
4575 if (uLevel == 2 || uLevel == 3) {
4576 PACKS(desc,"z",buf); /* pszPrinterName */
4578 PACKS(desc,"z",""); /* pszUserName */
4579 PACKS(desc,"z",""); /* pszLogAddr */
4580 PACKI(desc,"W",0); /* uJobId */
4581 PACKI(desc,"W",0); /* fsStatus */
4582 PACKS(desc,"z",""); /* pszStatus */
4583 PACKS(desc,"z",""); /* pszComment */
4584 PACKS(desc,"z","NULL"); /* pszDrivers */
4585 PACKI(desc,"W",0); /* time */
4586 PACKI(desc,"W",0); /* pad1 */
4591 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4592 char *param, int tpscnt,
4593 char *data, int tdscnt,
4594 int mdrcnt,int mprcnt,
4595 char **rdata,char **rparam,
4596 int *rdata_len,int *rparam_len)
4598 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4599 char *str2 = skip_string(param,tpscnt,str1);
4600 char *p = skip_string(param,tpscnt,str2);
4601 char* PrinterName = p;
4603 struct pack_desc desc;
4607 if (!str1 || !str2 || !p) {
4611 memset((char *)&desc,'\0',sizeof(desc));
4613 p = skip_string(param,tpscnt,p);
4617 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4619 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4621 /* check it's a supported varient */
4622 if (strcmp(str1,"zWrLh") != 0) {
4625 if (!check_printdest_info(&desc,uLevel,str2)) {
4629 snum = find_service(PrinterName);
4630 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4632 desc.errcode = NERR_DestNotFound;
4636 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4641 desc.buflen = mdrcnt;
4644 * Don't return data but need to get correct length
4645 * init_package will return wrong size if buflen=0
4647 desc.buflen = getlen(desc.format);
4648 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4650 if (init_package(&desc,1,0)) {
4651 fill_printdest_info(conn,snum,uLevel,&desc);
4653 *rdata_len = desc.usedlen;
4657 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4661 SSVALS(*rparam,0,desc.errcode);
4663 SSVAL(*rparam,4,desc.neededlen);
4665 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4671 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4672 char *param, int tpscnt,
4673 char *data, int tdscnt,
4674 int mdrcnt,int mprcnt,
4675 char **rdata,char **rparam,
4676 int *rdata_len,int *rparam_len)
4678 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4679 char *str2 = skip_string(param,tpscnt,str1);
4680 char *p = skip_string(param,tpscnt,str2);
4684 struct pack_desc desc;
4685 int services = lp_numservices();
4687 if (!str1 || !str2 || !p) {
4691 memset((char *)&desc,'\0',sizeof(desc));
4693 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4695 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4697 /* check it's a supported varient */
4698 if (strcmp(str1,"WrLeh") != 0) {
4701 if (!check_printdest_info(&desc,uLevel,str2)) {
4706 for (i = 0; i < services; i++) {
4707 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4713 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4720 desc.buflen = mdrcnt;
4721 if (init_package(&desc,queuecnt,0)) {
4724 for (i = 0; i < services; i++) {
4725 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4726 fill_printdest_info(conn,i,uLevel,&desc);
4728 if (desc.errcode == NERR_Success) {
4735 *rdata_len = desc.usedlen;
4738 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4742 SSVALS(*rparam,0,desc.errcode);
4744 SSVAL(*rparam,4,succnt);
4745 SSVAL(*rparam,6,queuecnt);
4747 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4752 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4753 char *param, int tpscnt,
4754 char *data, int tdscnt,
4755 int mdrcnt,int mprcnt,
4756 char **rdata,char **rparam,
4757 int *rdata_len,int *rparam_len)
4759 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4760 char *str2 = skip_string(param,tpscnt,str1);
4761 char *p = skip_string(param,tpscnt,str2);
4764 struct pack_desc desc;
4766 if (!str1 || !str2 || !p) {
4770 memset((char *)&desc,'\0',sizeof(desc));
4772 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4774 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4776 /* check it's a supported varient */
4777 if (strcmp(str1,"WrLeh") != 0) {
4780 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4785 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4791 desc.buflen = mdrcnt;
4792 if (init_package(&desc,1,0)) {
4793 PACKS(&desc,"B41","NULL");
4796 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4798 *rdata_len = desc.usedlen;
4801 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4805 SSVALS(*rparam,0,desc.errcode);
4807 SSVAL(*rparam,4,succnt);
4810 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4815 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4816 char *param, int tpscnt,
4817 char *data, int tdscnt,
4818 int mdrcnt,int mprcnt,
4819 char **rdata,char **rparam,
4820 int *rdata_len,int *rparam_len)
4822 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4823 char *str2 = skip_string(param,tpscnt,str1);
4824 char *p = skip_string(param,tpscnt,str2);
4827 struct pack_desc desc;
4829 if (!str1 || !str2 || !p) {
4832 memset((char *)&desc,'\0',sizeof(desc));
4834 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4836 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4838 /* check it's a supported varient */
4839 if (strcmp(str1,"WrLeh") != 0) {
4842 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4847 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4853 desc.buflen = mdrcnt;
4855 if (init_package(&desc,1,0)) {
4856 PACKS(&desc,"B13","lpd");
4859 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4861 *rdata_len = desc.usedlen;
4864 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4868 SSVALS(*rparam,0,desc.errcode);
4870 SSVAL(*rparam,4,succnt);
4873 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4878 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4879 char *param, int tpscnt,
4880 char *data, int tdscnt,
4881 int mdrcnt,int mprcnt,
4882 char **rdata,char **rparam,
4883 int *rdata_len,int *rparam_len)
4885 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4886 char *str2 = skip_string(param,tpscnt,str1);
4887 char *p = skip_string(param,tpscnt,str2);
4890 struct pack_desc desc;
4892 if (!str1 || !str2 || !p) {
4896 memset((char *)&desc,'\0',sizeof(desc));
4898 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4900 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4902 /* check it's a supported varient */
4903 if (strcmp(str1,"WrLeh") != 0) {
4906 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4911 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4916 memset((char *)&desc,'\0',sizeof(desc));
4918 desc.buflen = mdrcnt;
4920 if (init_package(&desc,1,0)) {
4921 PACKS(&desc,"B13","lp0");
4924 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4926 *rdata_len = desc.usedlen;
4929 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4933 SSVALS(*rparam,0,desc.errcode);
4935 SSVAL(*rparam,4,succnt);
4938 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4943 /****************************************************************************
4945 ****************************************************************************/
4947 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4948 char *param, int tpscnt,
4949 char *data, int tdscnt,
4950 int mdrcnt,int mprcnt,
4951 char **rdata,char **rparam,
4952 int *rdata_len,int *rparam_len)
4955 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4956 char *str2 = skip_string(param,tpscnt,str1);
4957 char *p = skip_string(param,tpscnt,str2);
4959 struct pack_desc desc;
4960 struct sessionid *session_list;
4961 int i, num_sessions;
4963 if (!str1 || !str2 || !p) {
4967 memset((char *)&desc,'\0',sizeof(desc));
4969 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4971 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4972 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4973 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4975 /* check it's a supported varient */
4976 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4979 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4983 num_sessions = list_sessions(talloc_tos(), &session_list);
4986 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4991 memset((char *)&desc,'\0',sizeof(desc));
4993 desc.buflen = mdrcnt;
4995 if (!init_package(&desc,num_sessions,0)) {
4999 for(i=0; i<num_sessions; i++) {
5000 PACKS(&desc, "z", session_list[i].remote_machine);
5001 PACKS(&desc, "z", session_list[i].username);
5002 PACKI(&desc, "W", 1); /* num conns */
5003 PACKI(&desc, "W", 0); /* num opens */
5004 PACKI(&desc, "W", 1); /* num users */
5005 PACKI(&desc, "D", 0); /* session time */
5006 PACKI(&desc, "D", 0); /* idle time */
5007 PACKI(&desc, "D", 0); /* flags */
5008 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5011 *rdata_len = desc.usedlen;
5014 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5018 SSVALS(*rparam,0,desc.errcode);
5019 SSVAL(*rparam,2,0); /* converter */
5020 SSVAL(*rparam,4,num_sessions); /* count */
5022 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5028 /****************************************************************************
5029 The buffer was too small.
5030 ****************************************************************************/
5032 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5033 int mdrcnt, int mprcnt,
5034 char **rdata, char **rparam,
5035 int *rdata_len, int *rparam_len)
5037 *rparam_len = MIN(*rparam_len,mprcnt);
5038 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5045 SSVAL(*rparam,0,NERR_BufTooSmall);
5047 DEBUG(3,("Supplied buffer too small in API command\n"));
5052 /****************************************************************************
5053 The request is not supported.
5054 ****************************************************************************/
5056 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5057 char *param, int tpscnt,
5058 char *data, int tdscnt,
5059 int mdrcnt, int mprcnt,
5060 char **rdata, char **rparam,
5061 int *rdata_len, int *rparam_len)
5064 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5071 SSVAL(*rparam,0,NERR_notsupported);
5072 SSVAL(*rparam,2,0); /* converter word */
5074 DEBUG(3,("Unsupported API command\n"));
5079 static const struct {
5082 bool (*fn)(connection_struct *, uint16,
5085 int,int,char **,char **,int *,int *);
5086 bool auth_user; /* Deny anonymous access? */
5087 } api_commands[] = {
5088 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5089 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5090 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5091 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5092 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5093 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5094 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5095 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5096 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5097 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5098 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5099 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5100 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5101 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5102 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5103 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5104 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5105 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5106 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5107 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5108 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5109 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5110 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5111 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5112 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5113 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5114 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5115 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5116 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5117 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5118 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5119 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5120 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5121 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5122 {NULL, -1, api_Unsupported}
5123 /* The following RAP calls are not implemented by Samba:
5125 RAP_WFileEnum2 - anon not OK
5130 /****************************************************************************
5131 Handle remote api calls.
5132 ****************************************************************************/
5134 void api_reply(connection_struct *conn, uint16 vuid,
5135 struct smb_request *req,
5136 char *data, char *params,
5137 int tdscnt, int tpscnt,
5138 int mdrcnt, int mprcnt)
5140 struct smbd_server_connection *sconn = smbd_server_conn;
5143 char *rparam = NULL;
5144 const char *name1 = NULL;
5145 const char *name2 = NULL;
5152 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5153 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5158 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5161 api_command = SVAL(params,0);
5162 /* Is there a string at position params+2 ? */
5163 if (skip_string(params,tpscnt,params+2)) {
5168 name2 = skip_string(params,tpscnt,params+2);
5173 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5177 tdscnt,tpscnt,mdrcnt,mprcnt));
5179 for (i=0;api_commands[i].name;i++) {
5180 if (api_commands[i].id == api_command && api_commands[i].fn) {
5181 DEBUG(3,("Doing %s\n",api_commands[i].name));
5186 /* Check whether this api call can be done anonymously */
5188 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5189 user_struct *user = get_valid_user_struct(sconn, vuid);
5191 if (!user || user->server_info->guest) {
5192 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5197 rdata = (char *)SMB_MALLOC(1024);
5199 memset(rdata,'\0',1024);
5202 rparam = (char *)SMB_MALLOC(1024);
5204 memset(rparam,'\0',1024);
5207 if(!rdata || !rparam) {
5208 DEBUG(0,("api_reply: malloc fail !\n"));
5211 reply_nterror(req, NT_STATUS_NO_MEMORY);
5215 reply = api_commands[i].fn(conn,
5217 params,tpscnt, /* params + length */
5218 data,tdscnt, /* data + length */
5220 &rdata,&rparam,&rdata_len,&rparam_len);
5223 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5224 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5225 &rdata,&rparam,&rdata_len,&rparam_len);
5228 /* if we get False back then it's actually unsupported */
5230 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5231 &rdata,&rparam,&rdata_len,&rparam_len);
5234 /* If api_Unsupported returns false we can't return anything. */
5236 send_trans_reply(conn, req, rparam, rparam_len,
5237 rdata, rdata_len, False);