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 static char *Expand(connection_struct *conn, int snum, char *s)
173 TALLOC_CTX *ctx = talloc_tos();
179 buf = talloc_strdup(ctx,s);
183 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
187 return talloc_sub_advanced(ctx,
188 lp_servicename(SNUM(conn)),
189 conn->server_info->unix_name,
191 conn->server_info->utok.gid,
192 conn->server_info->sanitized_username,
193 pdb_get_domain(conn->server_info->sam_account),
197 /*******************************************************************
198 Check a API string for validity when we only need to check the prefix.
199 ******************************************************************/
201 static bool prefix_ok(const char *str, const char *prefix)
203 return(strncmp(str,prefix,strlen(prefix)) == 0);
207 const char *format; /* formatstring for structure */
208 const char *subformat; /* subformat for structure */
209 char *base; /* baseaddress of buffer */
210 int buflen; /* remaining size for fixed part; on init: length of base */
211 int subcount; /* count of substructures */
212 char *structbuf; /* pointer into buffer for remaining fixed part */
213 int stringlen; /* remaining size for variable part */
214 char *stringbuf; /* pointer into buffer for remaining variable part */
215 int neededlen; /* total needed size */
216 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
217 const char *curpos; /* current position; pointer into format or subformat */
221 static int get_counter(const char **p)
227 if (!isdigit((int)**p)) {
233 n = 10 * n + (i - '0');
241 static int getlen(const char *p)
250 case 'W': /* word (2 byte) */
253 case 'K': /* status word? (2 byte) */
256 case 'N': /* count of substructures (word) at end */
259 case 'D': /* double word (4 byte) */
260 case 'z': /* offset to zero terminated string (4 byte) */
261 case 'l': /* offset to user data (4 byte) */
264 case 'b': /* offset to data (with counter) (4 byte) */
268 case 'B': /* byte (with optional counter) */
269 n += get_counter(&p);
276 static bool init_package(struct pack_desc *p, int count, int subcount)
281 if (!p->format || !p->base) {
285 i = count * getlen(p->format);
287 i += subcount * getlen(p->subformat);
289 p->structbuf = p->base;
293 p->curpos = p->format;
299 * This is the old error code we used. Aparently
300 * WinNT/2k systems return ERRbuftoosmall (2123) and
301 * OS/2 needs this. I'm leaving this here so we can revert
304 p->errcode = ERRmoredata;
306 p->errcode = ERRbuftoosmall;
309 p->errcode = NERR_Success;
313 p->stringbuf = p->base + i;
315 return (p->errcode == NERR_Success);
318 static int package(struct pack_desc *p, ...)
321 int needed=0, stringneeded;
322 const char *str=NULL;
323 int is_string=0, stringused;
330 p->curpos = p->format;
332 p->curpos = p->subformat;
337 str = va_arg(args,char*);
338 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
347 switch( *p->curpos++ ) {
348 case 'W': /* word (2 byte) */
350 temp = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,temp);
355 case 'K': /* status word? (2 byte) */
357 temp = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SSVAL(p->structbuf,0,temp);
362 case 'N': /* count of substructures (word) at end */
364 p->subcount = va_arg(args,int);
365 if (p->buflen >= needed) {
366 SSVAL(p->structbuf,0,p->subcount);
369 case 'D': /* double word (4 byte) */
371 temp = va_arg(args,int);
372 if (p->buflen >= needed) {
373 SIVAL(p->structbuf,0,temp);
376 case 'B': /* byte (with optional counter) */
377 needed = get_counter(&p->curpos);
379 char *s = va_arg(args,char*);
380 if (p->buflen >= needed) {
381 StrnCpy(p->structbuf,s?s:"",needed-1);
385 case 'z': /* offset to zero terminated string (4 byte) */
386 str = va_arg(args,char*);
387 stringneeded = (str ? strlen(str)+1 : 0);
390 case 'l': /* offset to user data (4 byte) */
391 str = va_arg(args,char*);
392 stringneeded = va_arg(args,int);
395 case 'b': /* offset to data (with counter) (4 byte) */
396 str = va_arg(args,char*);
397 stringneeded = get_counter(&p->curpos);
403 if (stringneeded >= 0) {
405 if (p->buflen >= needed) {
406 stringused = stringneeded;
407 if (stringused > p->stringlen) {
408 stringused = (is_string ? p->stringlen : 0);
409 if (p->errcode == NERR_Success) {
410 p->errcode = ERRmoredata;
414 SIVAL(p->structbuf,0,0);
416 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
417 memcpy(p->stringbuf,str?str:"",stringused);
419 p->stringbuf[stringused-1] = '\0';
421 p->stringbuf += stringused;
422 p->stringlen -= stringused;
423 p->usedlen += stringused;
426 p->neededlen += stringneeded;
429 p->neededlen += needed;
430 if (p->buflen >= needed) {
431 p->structbuf += needed;
433 p->usedlen += needed;
435 if (p->errcode == NERR_Success) {
436 p->errcode = ERRmoredata;
443 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
444 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
446 #define PACK(desc,t,v) package(desc,v)
447 #define PACKl(desc,t,v,l) package(desc,v,l)
450 static void PACKI(struct pack_desc* desc, const char *t,int v)
455 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
460 /****************************************************************************
462 ****************************************************************************/
464 static void PackDriverData(struct pack_desc* desc)
466 char drivdata[4+4+32];
467 SIVAL(drivdata,0,sizeof drivdata); /* cb */
468 SIVAL(drivdata,4,1000); /* lVersion */
469 memset(drivdata+8,0,32); /* szDeviceName */
470 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
471 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
474 static int check_printq_info(struct pack_desc* desc,
475 unsigned int uLevel, char *id1, char *id2)
477 desc->subformat = NULL;
480 desc->format = "B13";
483 desc->format = "B13BWWWzzzzzWW";
486 desc->format = "B13BWWWzzzzzWN";
487 desc->subformat = "WB21BB16B10zWWzDDz";
490 desc->format = "zWWWWzzzzWWzzl";
493 desc->format = "zWWWWzzzzWNzzl";
494 desc->subformat = "WWzWWDDzz";
503 desc->format = "WzzzzzzzzN";
504 desc->subformat = "z";
507 DEBUG(0,("check_printq_info: invalid level %d\n",
511 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
512 DEBUG(0,("check_printq_info: invalid format %s\n",
513 id1 ? id1 : "<NULL>" ));
516 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
517 DEBUG(0,("check_printq_info: invalid subformat %s\n",
518 id2 ? id2 : "<NULL>" ));
525 #define RAP_JOB_STATUS_QUEUED 0
526 #define RAP_JOB_STATUS_PAUSED 1
527 #define RAP_JOB_STATUS_SPOOLING 2
528 #define RAP_JOB_STATUS_PRINTING 3
529 #define RAP_JOB_STATUS_PRINTED 4
531 #define RAP_QUEUE_STATUS_PAUSED 1
532 #define RAP_QUEUE_STATUS_ERROR 2
534 /* turn a print job status into a on the wire status
536 static int printj_status(int v)
540 return RAP_JOB_STATUS_QUEUED;
542 return RAP_JOB_STATUS_PAUSED;
544 return RAP_JOB_STATUS_SPOOLING;
546 return RAP_JOB_STATUS_PRINTING;
551 static int printj_spoolss_status(int v)
553 if (v == JOB_STATUS_QUEUED)
554 return RAP_JOB_STATUS_QUEUED;
555 if (v & JOB_STATUS_PAUSED)
556 return RAP_JOB_STATUS_PAUSED;
557 if (v & JOB_STATUS_SPOOLING)
558 return RAP_JOB_STATUS_SPOOLING;
559 if (v & JOB_STATUS_PRINTING)
560 return RAP_JOB_STATUS_PRINTING;
564 /* turn a print queue status into a on the wire status
566 static int printq_status(int v)
572 return RAP_QUEUE_STATUS_PAUSED;
574 return RAP_QUEUE_STATUS_ERROR;
577 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
578 struct pack_desc *desc,
579 print_queue_struct *queue, int n)
581 time_t t = queue->time;
583 /* the client expects localtime */
584 t -= get_time_zone(t);
586 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
588 PACKS(desc,"B21",queue->fs_user); /* szUserName */
589 PACKS(desc,"B",""); /* pad */
590 PACKS(desc,"B16",""); /* szNotifyName */
591 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
592 PACKS(desc,"z",""); /* pszParms */
593 PACKI(desc,"W",n+1); /* uPosition */
594 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
595 PACKS(desc,"z",""); /* pszStatus */
596 PACKI(desc,"D",t); /* ulSubmitted */
597 PACKI(desc,"D",queue->size); /* ulSize */
598 PACKS(desc,"z",queue->fs_file); /* pszComment */
600 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
601 PACKI(desc,"W",queue->priority); /* uPriority */
602 PACKS(desc,"z",queue->fs_user); /* pszUserName */
603 PACKI(desc,"W",n+1); /* uPosition */
604 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
605 PACKI(desc,"D",t); /* ulSubmitted */
606 PACKI(desc,"D",queue->size); /* ulSize */
607 PACKS(desc,"z","Samba"); /* pszComment */
608 PACKS(desc,"z",queue->fs_file); /* pszDocument */
610 PACKS(desc,"z",""); /* pszNotifyName */
611 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
612 PACKS(desc,"z",""); /* pszParms */
613 PACKS(desc,"z",""); /* pszStatus */
614 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
615 PACKS(desc,"z","lpd"); /* pszQProcName */
616 PACKS(desc,"z",""); /* pszQProcParms */
617 PACKS(desc,"z","NULL"); /* pszDriverName */
618 PackDriverData(desc); /* pDriverData */
619 PACKS(desc,"z",""); /* pszPrinterName */
620 } else if (uLevel == 4) { /* OS2 */
621 PACKS(desc,"z",""); /* pszSpoolFileName */
622 PACKS(desc,"z",""); /* pszPortName */
623 PACKS(desc,"z",""); /* pszStatus */
624 PACKI(desc,"D",0); /* ulPagesSpooled */
625 PACKI(desc,"D",0); /* ulPagesSent */
626 PACKI(desc,"D",0); /* ulPagesPrinted */
627 PACKI(desc,"D",0); /* ulTimePrinted */
628 PACKI(desc,"D",0); /* ulExtendJobStatus */
629 PACKI(desc,"D",0); /* ulStartPage */
630 PACKI(desc,"D",0); /* ulEndPage */
635 static time_t spoolss_Time_to_time_t(const struct spoolss_Time *r)
639 unixtime.tm_year = r->year - 1900;
640 unixtime.tm_mon = r->month - 1;
641 unixtime.tm_wday = r->day_of_week;
642 unixtime.tm_mday = r->day;
643 unixtime.tm_hour = r->hour;
644 unixtime.tm_min = r->minute;
645 unixtime.tm_sec = r->second;
647 return mktime(&unixtime);
650 static void fill_spoolss_printjob_info(int uLevel,
651 struct pack_desc *desc,
652 struct spoolss_JobInfo2 *info2,
655 time_t t = spoolss_Time_to_time_t(&info2->submitted);
657 /* the client expects localtime */
658 t -= get_time_zone(t);
660 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
662 PACKS(desc,"B21", info2->user_name); /* szUserName */
663 PACKS(desc,"B",""); /* pad */
664 PACKS(desc,"B16",""); /* szNotifyName */
665 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
666 PACKS(desc,"z",""); /* pszParms */
667 PACKI(desc,"W",n+1); /* uPosition */
668 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
669 PACKS(desc,"z",""); /* pszStatus */
670 PACKI(desc,"D", t); /* ulSubmitted */
671 PACKI(desc,"D", info2->size); /* ulSize */
672 PACKS(desc,"z", info2->document_name); /* pszComment */
674 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
675 PACKI(desc,"W", info2->priority); /* uPriority */
676 PACKS(desc,"z", info2->user_name); /* pszUserName */
677 PACKI(desc,"W",n+1); /* uPosition */
678 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
679 PACKI(desc,"D",t); /* ulSubmitted */
680 PACKI(desc,"D", info2->size); /* ulSize */
681 PACKS(desc,"z","Samba"); /* pszComment */
682 PACKS(desc,"z", info2->document_name); /* pszDocument */
684 PACKS(desc,"z",""); /* pszNotifyName */
685 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
686 PACKS(desc,"z",""); /* pszParms */
687 PACKS(desc,"z",""); /* pszStatus */
688 PACKS(desc,"z", info2->printer_name); /* pszQueue */
689 PACKS(desc,"z","lpd"); /* pszQProcName */
690 PACKS(desc,"z",""); /* pszQProcParms */
691 PACKS(desc,"z","NULL"); /* pszDriverName */
692 PackDriverData(desc); /* pDriverData */
693 PACKS(desc,"z",""); /* pszPrinterName */
694 } else if (uLevel == 4) { /* OS2 */
695 PACKS(desc,"z",""); /* pszSpoolFileName */
696 PACKS(desc,"z",""); /* pszPortName */
697 PACKS(desc,"z",""); /* pszStatus */
698 PACKI(desc,"D",0); /* ulPagesSpooled */
699 PACKI(desc,"D",0); /* ulPagesSent */
700 PACKI(desc,"D",0); /* ulPagesPrinted */
701 PACKI(desc,"D",0); /* ulTimePrinted */
702 PACKI(desc,"D",0); /* ulExtendJobStatus */
703 PACKI(desc,"D",0); /* ulStartPage */
704 PACKI(desc,"D",0); /* ulEndPage */
709 /********************************************************************
710 Return a driver name given an snum.
711 Returns True if from tdb, False otherwise.
712 ********************************************************************/
714 static bool get_driver_name(int snum, char **pp_drivername)
716 NT_PRINTER_INFO_LEVEL *info = NULL;
719 get_a_printer (NULL, &info, 2, lp_servicename(snum));
721 *pp_drivername = talloc_strdup(talloc_tos(),
722 info->info_2->drivername);
724 free_a_printer(&info, 2);
725 if (!*pp_drivername) {
733 /********************************************************************
734 Respond to the DosPrintQInfo command with a level of 52
735 This is used to get printer driver information for Win9x clients
736 ********************************************************************/
737 static void fill_printq_info_52(connection_struct *conn, int snum,
738 struct pack_desc* desc, int count )
742 struct spoolss_DriverInfo8 *driver = NULL;
743 NT_PRINTER_INFO_LEVEL *printer = NULL;
745 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
746 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
747 lp_servicename(snum)));
751 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
754 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
755 printer->info_2->drivername));
759 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
760 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
761 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
763 PACKI(desc, "W", 0x0400); /* don't know */
764 PACKS(desc, "z", driver->driver_name); /* long printer name */
765 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
766 PACKS(desc, "z", driver->data_file); /* Datafile name */
767 PACKS(desc, "z", driver->monitor_name); /* language monitor */
769 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
770 standard_sub_basic( "", "", location, sizeof(location)-1 );
771 PACKS(desc,"z", location); /* share to retrieve files */
773 PACKS(desc,"z", driver->default_datatype); /* default data type */
774 PACKS(desc,"z", driver->help_file); /* helpfile name */
775 PACKS(desc,"z", driver->driver_path); /* driver name */
777 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
778 DEBUG(3,("Driver: %s:\n",driver->driver_path));
779 DEBUG(3,("Data File: %s:\n",driver->data_file));
780 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
781 DEBUG(3,("Driver Location: %s:\n",location));
782 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
783 DEBUG(3,("Help File: %s:\n",driver->help_file));
784 PACKI(desc,"N",count); /* number of files to copy */
786 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
788 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
789 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
790 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
795 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
798 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
800 desc->errcode=NERR_Success;
804 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
805 desc->errcode=NERR_notsupported;
809 free_a_printer( &printer, 2 );
811 free_a_printer_driver(driver);
815 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
816 struct pack_desc* desc,
817 int count, print_queue_struct* queue,
818 print_status_struct* status)
823 PACKS(desc,"B13",SERVICE(snum));
828 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
831 PACKI(desc,"K",printq_status(status->status));
835 if (uLevel == 1 || uLevel == 2) {
836 PACKS(desc,"B",""); /* alignment */
837 PACKI(desc,"W",5); /* priority */
838 PACKI(desc,"W",0); /* start time */
839 PACKI(desc,"W",0); /* until time */
840 PACKS(desc,"z",""); /* pSepFile */
841 PACKS(desc,"z","lpd"); /* pPrProc */
842 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
843 PACKS(desc,"z",""); /* pParms */
845 PACKS(desc,"z","UNKNOWN PRINTER");
846 PACKI(desc,"W",LPSTAT_ERROR);
848 else if (!status || !status->message[0]) {
849 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
850 PACKI(desc,"W",LPSTAT_OK); /* status */
852 PACKS(desc,"z",status->message);
853 PACKI(desc,"W",printq_status(status->status)); /* status */
855 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
858 if (uLevel == 3 || uLevel == 4) {
859 char *drivername = NULL;
861 PACKI(desc,"W",5); /* uPriority */
862 PACKI(desc,"W",0); /* uStarttime */
863 PACKI(desc,"W",0); /* uUntiltime */
864 PACKI(desc,"W",5); /* pad1 */
865 PACKS(desc,"z",""); /* pszSepFile */
866 PACKS(desc,"z","WinPrint"); /* pszPrProc */
867 PACKS(desc,"z",NULL); /* pszParms */
868 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
869 /* "don't ask" that it's done this way to fix corrupted
870 Win9X/ME printer comments. */
872 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
874 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
876 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
877 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
878 get_driver_name(snum,&drivername);
882 PACKS(desc,"z",drivername); /* pszDriverName */
883 PackDriverData(desc); /* pDriverData */
886 if (uLevel == 2 || uLevel == 4) {
888 for (i=0;i<count;i++)
889 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
893 fill_printq_info_52( conn, snum, desc, count );
896 /* This function returns the number of files for a given driver */
897 static int get_printerdrivernumber(int snum)
900 struct spoolss_DriverInfo8 *driver;
901 NT_PRINTER_INFO_LEVEL *printer = NULL;
905 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
906 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
907 lp_servicename(snum)));
911 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
914 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
915 printer->info_2->drivername));
919 /* count the number of files */
920 while (driver->dependent_files && *driver->dependent_files[result])
924 free_a_printer( &printer, 2 );
926 free_a_printer_driver(driver);
931 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
932 char *param, int tpscnt,
933 char *data, int tdscnt,
934 int mdrcnt,int mprcnt,
935 char **rdata,char **rparam,
936 int *rdata_len,int *rparam_len)
938 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
939 char *str2 = skip_string(param,tpscnt,str1);
940 char *p = skip_string(param,tpscnt,str2);
946 struct pack_desc desc;
947 print_queue_struct *queue=NULL;
948 print_status_struct status;
951 if (!str1 || !str2 || !p) {
954 memset((char *)&status,'\0',sizeof(status));
955 memset((char *)&desc,'\0',sizeof(desc));
957 p = skip_string(param,tpscnt,p);
961 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
962 str3 = get_safe_str_ptr(param,tpscnt,p,4);
963 /* str3 may be null here and is checked in check_printq_info(). */
965 /* remove any trailing username */
966 if ((p = strchr_m(QueueName,'%')))
969 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
971 /* check it's a supported varient */
972 if (!prefix_ok(str1,"zWrLh"))
974 if (!check_printq_info(&desc,uLevel,str2,str3)) {
976 * Patch from Scott Moomaw <scott@bridgewater.edu>
977 * to return the 'invalid info level' error if an
978 * unknown level was requested.
982 *rparam = smb_realloc_limit(*rparam,*rparam_len);
986 SSVALS(*rparam,0,ERRunknownlevel);
992 snum = find_service(QueueName);
993 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
997 count = get_printerdrivernumber(snum);
998 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
1000 count = print_queue_status(snum, &queue,&status);
1004 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1010 desc.buflen = mdrcnt;
1013 * Don't return data but need to get correct length
1014 * init_package will return wrong size if buflen=0
1016 desc.buflen = getlen(desc.format);
1017 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
1020 if (init_package(&desc,1,count)) {
1021 desc.subcount = count;
1022 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
1025 *rdata_len = desc.usedlen;
1028 * We must set the return code to ERRbuftoosmall
1029 * in order to support lanman style printing with Win NT/2k
1032 if (!mdrcnt && lp_disable_spoolss())
1033 desc.errcode = ERRbuftoosmall;
1035 *rdata_len = desc.usedlen;
1037 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1043 SSVALS(*rparam,0,desc.errcode);
1045 SSVAL(*rparam,4,desc.neededlen);
1047 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
1055 /****************************************************************************
1056 View list of all print jobs on all queues.
1057 ****************************************************************************/
1059 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
1060 char *param, int tpscnt,
1061 char *data, int tdscnt,
1062 int mdrcnt, int mprcnt,
1063 char **rdata, char** rparam,
1064 int *rdata_len, int *rparam_len)
1066 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
1067 char *output_format1 = skip_string(param,tpscnt,param_format);
1068 char *p = skip_string(param,tpscnt,output_format1);
1069 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1070 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
1071 int services = lp_numservices();
1073 struct pack_desc desc;
1074 print_queue_struct **queue = NULL;
1075 print_status_struct *status = NULL;
1076 int *subcntarr = NULL;
1077 int queuecnt = 0, subcnt = 0, succnt = 0;
1079 if (!param_format || !output_format1 || !p) {
1083 memset((char *)&desc,'\0',sizeof(desc));
1085 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1087 if (!prefix_ok(param_format,"WrLeh")) {
1090 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1092 * Patch from Scott Moomaw <scott@bridgewater.edu>
1093 * to return the 'invalid info level' error if an
1094 * unknown level was requested.
1098 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1102 SSVALS(*rparam,0,ERRunknownlevel);
1108 for (i = 0; i < services; i++) {
1109 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1114 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1115 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1118 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1119 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1120 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1123 memset(status,0,queuecnt*sizeof(print_status_struct));
1124 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1125 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1131 for (i = 0; i < services; i++) {
1132 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1133 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1134 subcnt += subcntarr[n];
1140 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1146 desc.buflen = mdrcnt;
1148 if (init_package(&desc,queuecnt,subcnt)) {
1151 for (i = 0; i < services; i++) {
1152 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1153 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1155 if (desc.errcode == NERR_Success) {
1162 SAFE_FREE(subcntarr);
1164 *rdata_len = desc.usedlen;
1166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1170 SSVALS(*rparam,0,desc.errcode);
1172 SSVAL(*rparam,4,succnt);
1173 SSVAL(*rparam,6,queuecnt);
1175 for (i = 0; i < queuecnt; i++) {
1177 SAFE_FREE(queue[i]);
1188 SAFE_FREE(subcntarr);
1189 for (i = 0; i < queuecnt; i++) {
1191 SAFE_FREE(queue[i]);
1200 /****************************************************************************
1201 Get info level for a server list query.
1202 ****************************************************************************/
1204 static bool check_server_info(int uLevel, char* id)
1208 if (strcmp(id,"B16") != 0) {
1213 if (strcmp(id,"B16BBDz") != 0) {
1223 struct srv_info_struct {
1231 /*******************************************************************
1232 Get server info lists from the files saved by nmbd. Return the
1234 ******************************************************************/
1236 static int get_server_info(uint32 servertype,
1237 struct srv_info_struct **servers,
1243 bool local_list_only;
1246 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1248 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1252 /* request for everything is code for request all servers */
1253 if (servertype == SV_TYPE_ALL) {
1254 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1257 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1259 DEBUG(4,("Servertype search: %8x\n",servertype));
1261 for (i=0;lines[i];i++) {
1263 struct srv_info_struct *s;
1264 const char *ptr = lines[i];
1266 TALLOC_CTX *frame = NULL;
1273 if (count == alloced) {
1275 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1277 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1281 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1283 s = &(*servers)[count];
1285 frame = talloc_stackframe();
1287 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1291 fstrcpy(s->name, p);
1294 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1300 s->comment[0] = '\0';
1301 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1305 fstrcpy(s->comment, p);
1306 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1308 s->domain[0] = '\0';
1309 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1310 /* this allows us to cope with an old nmbd */
1311 fstrcpy(s->domain,lp_workgroup());
1313 fstrcpy(s->domain, p);
1317 if (sscanf(stype,"%X",&s->type) != 1) {
1318 DEBUG(4,("r:host file "));
1322 /* Filter the servers/domains we return based on what was asked for. */
1324 /* Check to see if we are being asked for a local list only. */
1325 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1326 DEBUG(4,("r: local list only"));
1330 /* doesn't match up: don't want it */
1331 if (!(servertype & s->type)) {
1332 DEBUG(4,("r:serv type "));
1336 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1337 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1338 DEBUG(4,("s: dom mismatch "));
1342 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1346 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1347 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1350 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1351 s->name, s->type, s->comment, s->domain));
1352 s->server_added = True;
1355 DEBUG(4,("%20s %8x %25s %15s\n",
1356 s->name, s->type, s->comment, s->domain));
1364 /*******************************************************************
1365 Fill in a server info structure.
1366 ******************************************************************/
1368 static int fill_srv_info(struct srv_info_struct *service,
1369 int uLevel, char **buf, int *buflen,
1370 char **stringbuf, int *stringspace, char *baseaddr)
1393 len = strlen(service->comment)+1;
1397 *buflen = struct_len;
1399 return struct_len + len;
1404 if (*buflen < struct_len) {
1411 p2 = p + struct_len;
1412 l2 = *buflen - struct_len;
1420 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1424 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1425 SIVAL(p,18,service->type);
1426 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1427 len += CopyAndAdvance(&p2,service->comment,&l2);
1432 *buf = p + struct_len;
1433 *buflen -= struct_len;
1444 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1446 return StrCaseCmp(s1->name,s2->name);
1449 /****************************************************************************
1450 View list of servers available (or possibly domains). The info is
1451 extracted from lists saved by nmbd on the local host.
1452 ****************************************************************************/
1454 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1455 char *param, int tpscnt,
1456 char *data, int tdscnt,
1457 int mdrcnt, int mprcnt, char **rdata,
1458 char **rparam, int *rdata_len, int *rparam_len)
1460 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1461 char *str2 = skip_string(param,tpscnt,str1);
1462 char *p = skip_string(param,tpscnt,str2);
1463 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1464 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1465 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1467 int data_len, fixed_len, string_len;
1468 int f_len = 0, s_len = 0;
1469 struct srv_info_struct *servers=NULL;
1470 int counted=0,total=0;
1473 bool domain_request;
1476 if (!str1 || !str2 || !p) {
1480 /* If someone sets all the bits they don't really mean to set
1481 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1484 if (servertype == SV_TYPE_ALL) {
1485 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1488 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1489 any other bit (they may just set this bit on its own) they
1490 want all the locally seen servers. However this bit can be
1491 set on its own so set the requested servers to be
1492 ALL - DOMAIN_ENUM. */
1494 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1495 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1498 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1499 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1503 if (!prefix_ok(str1,"WrLehD")) {
1506 if (!check_server_info(uLevel,str2)) {
1510 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1511 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1512 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1514 if (strcmp(str1, "WrLehDz") == 0) {
1515 if (skip_string(param,tpscnt,p) == NULL) {
1518 pull_ascii_fstring(domain, p);
1520 fstrcpy(domain, lp_workgroup());
1523 DEBUG(4, ("domain [%s]\n", domain));
1525 if (lp_browse_list()) {
1526 total = get_server_info(servertype,&servers,domain);
1529 data_len = fixed_len = string_len = 0;
1532 TYPESAFE_QSORT(servers, total, srv_comp);
1535 char *lastname=NULL;
1537 for (i=0;i<total;i++) {
1538 struct srv_info_struct *s = &servers[i];
1540 if (lastname && strequal(lastname,s->name)) {
1544 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1545 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1546 i, s->name, s->type, s->comment, s->domain));
1548 if (data_len < buf_len) {
1551 string_len += s_len;
1558 *rdata_len = fixed_len + string_len;
1559 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1564 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1570 char *lastname=NULL;
1571 int count2 = counted;
1573 for (i = 0; i < total && count2;i++) {
1574 struct srv_info_struct *s = &servers[i];
1576 if (lastname && strequal(lastname,s->name)) {
1580 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1581 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1582 i, s->name, s->type, s->comment, s->domain));
1588 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1592 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1594 SSVAL(*rparam,4,counted);
1595 SSVAL(*rparam,6,counted+missed);
1599 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1600 domain,uLevel,counted,counted+missed));
1605 static int srv_name_match(const char *n1, const char *n2)
1608 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1610 * In Windows, FirstNameToReturn need not be an exact match:
1611 * the server will return a list of servers that exist on
1612 * the network greater than or equal to the FirstNameToReturn.
1614 int ret = StrCaseCmp(n1, n2);
1623 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1624 char *param, int tpscnt,
1625 char *data, int tdscnt,
1626 int mdrcnt, int mprcnt, char **rdata,
1627 char **rparam, int *rdata_len, int *rparam_len)
1629 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1630 char *str2 = skip_string(param,tpscnt,str1);
1631 char *p = skip_string(param,tpscnt,str2);
1632 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1633 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1634 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1636 int data_len, fixed_len, string_len;
1637 int f_len = 0, s_len = 0;
1638 struct srv_info_struct *servers=NULL;
1639 int counted=0,first=0,total=0;
1643 bool domain_request;
1646 if (!str1 || !str2 || !p) {
1650 /* If someone sets all the bits they don't really mean to set
1651 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1654 if (servertype == SV_TYPE_ALL) {
1655 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1658 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1659 any other bit (they may just set this bit on its own) they
1660 want all the locally seen servers. However this bit can be
1661 set on its own so set the requested servers to be
1662 ALL - DOMAIN_ENUM. */
1664 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1665 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1668 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1669 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1673 if (strcmp(str1, "WrLehDzz") != 0) {
1676 if (!check_server_info(uLevel,str2)) {
1680 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1681 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1682 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1684 if (skip_string(param,tpscnt,p) == NULL) {
1687 pull_ascii_fstring(domain, p);
1688 if (domain[0] == '\0') {
1689 fstrcpy(domain, lp_workgroup());
1691 p = skip_string(param,tpscnt,p);
1692 if (skip_string(param,tpscnt,p) == NULL) {
1695 pull_ascii_fstring(first_name, p);
1697 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1698 domain, first_name));
1700 if (lp_browse_list()) {
1701 total = get_server_info(servertype,&servers,domain);
1704 data_len = fixed_len = string_len = 0;
1707 TYPESAFE_QSORT(servers, total, srv_comp);
1709 if (first_name[0] != '\0') {
1710 struct srv_info_struct *first_server = NULL;
1712 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1713 srv_name_match, first_server);
1715 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1717 * The binary search may not find the exact match
1718 * so we need to search backward to find the first match
1720 * This implements the strange matching windows
1721 * implements. (see the comment in srv_name_match().
1725 ret = StrCaseCmp(first_name,
1726 servers[first-1].name);
1733 /* we should return no entries */
1739 char *lastname=NULL;
1741 for (i=first;i<total;i++) {
1742 struct srv_info_struct *s = &servers[i];
1744 if (lastname && strequal(lastname,s->name)) {
1748 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1749 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1750 i, s->name, s->type, s->comment, s->domain));
1752 if (data_len < buf_len) {
1755 string_len += s_len;
1762 *rdata_len = fixed_len + string_len;
1763 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1768 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1774 char *lastname=NULL;
1775 int count2 = counted;
1777 for (i = first; i < total && count2;i++) {
1778 struct srv_info_struct *s = &servers[i];
1780 if (lastname && strequal(lastname,s->name)) {
1784 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1785 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1786 i, s->name, s->type, s->comment, s->domain));
1792 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1796 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1798 SSVAL(*rparam,4,counted);
1799 SSVAL(*rparam,6,counted+missed);
1801 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1802 domain,uLevel,first,first_name,
1803 first < total ? servers[first].name : "",
1804 counted,counted+missed));
1811 /****************************************************************************
1812 command 0x34 - suspected of being a "Lookup Names" stub api
1813 ****************************************************************************/
1815 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1816 char *param, int tpscnt,
1817 char *data, int tdscnt,
1818 int mdrcnt, int mprcnt, char **rdata,
1819 char **rparam, int *rdata_len, int *rparam_len)
1821 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1822 char *str2 = skip_string(param,tpscnt,str1);
1823 char *p = skip_string(param,tpscnt,str2);
1824 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1825 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1829 if (!str1 || !str2 || !p) {
1833 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1834 str1, str2, p, uLevel, buf_len));
1836 if (!prefix_ok(str1,"zWrLeh")) {
1843 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1848 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1850 SSVAL(*rparam,4,counted);
1851 SSVAL(*rparam,6,counted+missed);
1856 /****************************************************************************
1857 get info about a share
1858 ****************************************************************************/
1860 static bool check_share_info(int uLevel, char* id)
1864 if (strcmp(id,"B13") != 0) {
1869 /* Level-2 descriptor is allowed (and ignored) */
1870 if (strcmp(id,"B13BWz") != 0 &&
1871 strcmp(id,"B13BWzWWWzB9B") != 0) {
1876 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1881 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1891 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1892 char** buf, int* buflen,
1893 char** stringbuf, int* stringspace, char* baseaddr)
1922 len += StrlenExpanded(conn,snum,lp_comment(snum));
1925 len += strlen(lp_pathname(snum)) + 1;
1928 *buflen = struct_len;
1933 return struct_len + len;
1938 if ((*buflen) < struct_len) {
1946 p2 = p + struct_len;
1947 l2 = (*buflen) - struct_len;
1954 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1960 type = STYPE_DISKTREE;
1961 if (lp_print_ok(snum)) {
1962 type = STYPE_PRINTQ;
1964 if (strequal("IPC",lp_fstype(snum))) {
1967 SSVAL(p,14,type); /* device type */
1968 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1969 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1973 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1974 SSVALS(p,22,-1); /* max uses */
1975 SSVAL(p,24,1); /* current uses */
1976 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1977 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1978 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1982 memset(p+40,0,SHPWLEN+2);
1993 (*buf) = p + struct_len;
1994 (*buflen) -= struct_len;
1996 (*stringspace) = l2;
2005 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
2006 char *param, int tpscnt,
2007 char *data, int tdscnt,
2008 int mdrcnt,int mprcnt,
2009 char **rdata,char **rparam,
2010 int *rdata_len,int *rparam_len)
2012 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2013 char *str2 = skip_string(param,tpscnt,str1);
2014 char *netname = skip_string(param,tpscnt,str2);
2015 char *p = skip_string(param,tpscnt,netname);
2016 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2019 if (!str1 || !str2 || !netname || !p) {
2023 snum = find_service(netname);
2028 /* check it's a supported varient */
2029 if (!prefix_ok(str1,"zWrLh")) {
2032 if (!check_share_info(uLevel,str2)) {
2036 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2041 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2042 if (*rdata_len < 0) {
2047 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2051 SSVAL(*rparam,0,NERR_Success);
2052 SSVAL(*rparam,2,0); /* converter word */
2053 SSVAL(*rparam,4,*rdata_len);
2058 /****************************************************************************
2059 View the list of available shares.
2061 This function is the server side of the NetShareEnum() RAP call.
2062 It fills the return buffer with share names and share comments.
2063 Note that the return buffer normally (in all known cases) allows only
2064 twelve byte strings for share names (plus one for a nul terminator).
2065 Share names longer than 12 bytes must be skipped.
2066 ****************************************************************************/
2068 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2069 char *param, int tpscnt,
2070 char *data, int tdscnt,
2078 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2079 char *str2 = skip_string(param,tpscnt,str1);
2080 char *p = skip_string(param,tpscnt,str2);
2081 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2082 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2085 int total=0,counted=0;
2086 bool missed = False;
2088 int data_len, fixed_len, string_len;
2089 int f_len = 0, s_len = 0;
2091 if (!str1 || !str2 || !p) {
2095 if (!prefix_ok(str1,"WrLeh")) {
2098 if (!check_share_info(uLevel,str2)) {
2102 /* Ensure all the usershares are loaded. */
2104 load_registry_shares();
2105 count = load_usershare_shares();
2108 data_len = fixed_len = string_len = 0;
2109 for (i=0;i<count;i++) {
2110 fstring servicename_dos;
2111 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2114 push_ascii_fstring(servicename_dos, lp_servicename(i));
2115 /* Maximum name length = 13. */
2116 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2118 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2119 if (data_len < buf_len) {
2122 string_len += s_len;
2129 *rdata_len = fixed_len + string_len;
2130 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2135 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2140 for( i = 0; i < count; i++ ) {
2141 fstring servicename_dos;
2142 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2146 push_ascii_fstring(servicename_dos, lp_servicename(i));
2147 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2148 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2155 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2159 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2161 SSVAL(*rparam,4,counted);
2162 SSVAL(*rparam,6,total);
2164 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2165 counted,total,uLevel,
2166 buf_len,*rdata_len,mdrcnt));
2171 /****************************************************************************
2173 ****************************************************************************/
2175 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2176 char *param, int tpscnt,
2177 char *data, int tdscnt,
2178 int mdrcnt,int mprcnt,
2179 char **rdata,char **rparam,
2180 int *rdata_len,int *rparam_len)
2182 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2183 char *str2 = skip_string(param,tpscnt,str1);
2184 char *p = skip_string(param,tpscnt,str2);
2185 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2188 char *pathname = NULL;
2189 char *command, *cmdname;
2190 unsigned int offset;
2193 size_t converted_size;
2195 if (!str1 || !str2 || !p) {
2199 /* check it's a supported varient */
2200 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2203 if (!check_share_info(uLevel,str2)) {
2210 /* Do we have a string ? */
2211 if (skip_string(data,mdrcnt,data) == NULL) {
2214 pull_ascii_fstring(sharename,data);
2215 snum = find_service(sharename);
2216 if (snum >= 0) { /* already exists */
2225 /* only support disk share adds */
2226 if (SVAL(data,14)!=STYPE_DISKTREE) {
2230 offset = IVAL(data, 16);
2231 if (offset >= mdrcnt) {
2232 res = ERRinvalidparam;
2236 /* Do we have a string ? */
2237 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2240 pull_ascii_fstring(comment, offset? (data+offset) : "");
2242 offset = IVAL(data, 26);
2244 if (offset >= mdrcnt) {
2245 res = ERRinvalidparam;
2249 /* Do we have a string ? */
2250 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2254 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2255 offset ? (data+offset) : "", &converted_size))
2257 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2265 string_replace(sharename, '"', ' ');
2266 string_replace(pathname, '"', ' ');
2267 string_replace(comment, '"', ' ');
2269 cmdname = lp_add_share_cmd();
2271 if (!cmdname || *cmdname == '\0') {
2275 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2276 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2277 pathname, comment) == -1) {
2281 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2283 if ((res = smbrun(command, NULL)) != 0) {
2284 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2291 message_send_all(smbd_messaging_context(),
2292 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2296 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2300 SSVAL(*rparam,0,NERR_Success);
2301 SSVAL(*rparam,2,0); /* converter word */
2302 SSVAL(*rparam,4,*rdata_len);
2310 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2315 SSVAL(*rparam,0,res);
2320 /****************************************************************************
2321 view list of groups available
2322 ****************************************************************************/
2324 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2325 char *param, int tpscnt,
2326 char *data, int tdscnt,
2327 int mdrcnt,int mprcnt,
2328 char **rdata,char **rparam,
2329 int *rdata_len,int *rparam_len)
2333 int resume_context, cli_buf_size;
2334 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2335 char *str2 = skip_string(param,tpscnt,str1);
2336 char *p = skip_string(param,tpscnt,str2);
2338 uint32_t num_groups;
2339 uint32_t resume_handle;
2340 struct rpc_pipe_client *samr_pipe;
2341 struct policy_handle samr_handle, domain_handle;
2344 if (!str1 || !str2 || !p) {
2348 if (strcmp(str1,"WrLeh") != 0) {
2353 * W-> resume context (number of users to skip)
2354 * r -> return parameter pointer to receive buffer
2355 * L -> length of receive buffer
2356 * e -> return parameter number of entries
2357 * h -> return parameter total number of users
2360 if (strcmp("B21",str2) != 0) {
2364 status = rpc_pipe_open_internal(
2365 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2366 conn->server_info, &samr_pipe);
2367 if (!NT_STATUS_IS_OK(status)) {
2368 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2369 nt_errstr(status)));
2373 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2374 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2375 if (!NT_STATUS_IS_OK(status)) {
2376 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2377 nt_errstr(status)));
2381 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2382 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2383 get_global_sam_sid(), &domain_handle);
2384 if (!NT_STATUS_IS_OK(status)) {
2385 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2386 nt_errstr(status)));
2387 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2391 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2392 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2393 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2394 "%d\n", resume_context, cli_buf_size));
2396 *rdata_len = cli_buf_size;
2397 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2404 errflags = NERR_Success;
2409 struct samr_SamArray *sam_entries;
2410 uint32_t num_entries;
2412 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2417 if (!NT_STATUS_IS_OK(status)) {
2418 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2419 "%s\n", nt_errstr(status)));
2423 if (num_entries == 0) {
2424 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2425 "no entries -- done\n"));
2429 for(i=0; i<num_entries; i++) {
2432 name = sam_entries->entries[i].name.string;
2434 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2435 /* set overflow error */
2436 DEBUG(3,("overflow on entry %d group %s\n", i,
2442 /* truncate the name at 21 chars. */
2444 strlcpy(p, name, 21);
2445 DEBUG(10,("adding entry %d group %s\n", i, p));
2447 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2452 if (errflags != NERR_Success) {
2456 TALLOC_FREE(sam_entries);
2459 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2460 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2462 *rdata_len = PTR_DIFF(p,*rdata);
2465 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2469 SSVAL(*rparam, 0, errflags);
2470 SSVAL(*rparam, 2, 0); /* converter word */
2471 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2472 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2477 /*******************************************************************
2478 Get groups that a user is a member of.
2479 ******************************************************************/
2481 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2482 char *param, int tpscnt,
2483 char *data, int tdscnt,
2484 int mdrcnt,int mprcnt,
2485 char **rdata,char **rparam,
2486 int *rdata_len,int *rparam_len)
2488 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2489 char *str2 = skip_string(param,tpscnt,str1);
2490 char *UserName = skip_string(param,tpscnt,str2);
2491 char *p = skip_string(param,tpscnt,UserName);
2492 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2493 const char *level_string;
2499 struct rpc_pipe_client *samr_pipe;
2500 struct policy_handle samr_handle, domain_handle, user_handle;
2501 struct lsa_String name;
2502 struct lsa_Strings names;
2503 struct samr_Ids type, rid;
2504 struct samr_RidWithAttributeArray *rids;
2507 if (!str1 || !str2 || !UserName || !p) {
2512 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2517 /* check it's a supported varient */
2519 if ( strcmp(str1,"zWrLeh") != 0 )
2524 level_string = "B21";
2530 if (strcmp(level_string,str2) != 0)
2533 *rdata_len = mdrcnt + 1024;
2534 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2539 SSVAL(*rparam,0,NERR_Success);
2540 SSVAL(*rparam,2,0); /* converter word */
2543 endp = *rdata + *rdata_len;
2545 status = rpc_pipe_open_internal(
2546 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2547 conn->server_info, &samr_pipe);
2548 if (!NT_STATUS_IS_OK(status)) {
2549 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2550 nt_errstr(status)));
2554 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2555 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2556 if (!NT_STATUS_IS_OK(status)) {
2557 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2558 nt_errstr(status)));
2562 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2563 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2564 get_global_sam_sid(), &domain_handle);
2565 if (!NT_STATUS_IS_OK(status)) {
2566 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2567 nt_errstr(status)));
2571 name.string = UserName;
2573 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2574 &domain_handle, 1, &name,
2576 if (!NT_STATUS_IS_OK(status)) {
2577 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2578 nt_errstr(status)));
2582 if (type.ids[0] != SID_NAME_USER) {
2583 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2584 sid_type_lookup(type.ids[0])));
2588 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2590 SAMR_USER_ACCESS_GET_GROUPS,
2591 rid.ids[0], &user_handle);
2592 if (!NT_STATUS_IS_OK(status)) {
2593 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2594 nt_errstr(status)));
2598 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2599 &user_handle, &rids);
2600 if (!NT_STATUS_IS_OK(status)) {
2601 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2602 nt_errstr(status)));
2606 for (i=0; i<rids->count; i++) {
2608 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2610 1, &rids->rids[i].rid,
2612 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2613 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2619 *rdata_len = PTR_DIFF(p,*rdata);
2621 SSVAL(*rparam,4,count); /* is this right?? */
2622 SSVAL(*rparam,6,count); /* is this right?? */
2627 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2629 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2631 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2636 /*******************************************************************
2638 ******************************************************************/
2640 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2641 char *param, int tpscnt,
2642 char *data, int tdscnt,
2643 int mdrcnt,int mprcnt,
2644 char **rdata,char **rparam,
2645 int *rdata_len,int *rparam_len)
2650 int i, resume_context, cli_buf_size;
2651 uint32_t resume_handle;
2653 struct rpc_pipe_client *samr_pipe;
2654 struct policy_handle samr_handle, domain_handle;
2657 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2658 char *str2 = skip_string(param,tpscnt,str1);
2659 char *p = skip_string(param,tpscnt,str2);
2662 if (!str1 || !str2 || !p) {
2666 if (strcmp(str1,"WrLeh") != 0)
2669 * W-> resume context (number of users to skip)
2670 * r -> return parameter pointer to receive buffer
2671 * L -> length of receive buffer
2672 * e -> return parameter number of entries
2673 * h -> return parameter total number of users
2676 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2677 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2678 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2679 resume_context, cli_buf_size));
2682 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2687 /* check it's a supported varient */
2688 if (strcmp("B21",str2) != 0)
2691 *rdata_len = cli_buf_size;
2692 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2698 endp = *rdata + *rdata_len;
2700 status = rpc_pipe_open_internal(
2701 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2702 conn->server_info, &samr_pipe);
2703 if (!NT_STATUS_IS_OK(status)) {
2704 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2705 nt_errstr(status)));
2709 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2710 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2711 if (!NT_STATUS_IS_OK(status)) {
2712 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2713 nt_errstr(status)));
2717 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2718 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2719 get_global_sam_sid(), &domain_handle);
2720 if (!NT_STATUS_IS_OK(status)) {
2721 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2722 nt_errstr(status)));
2723 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2727 errflags=NERR_Success;
2732 struct samr_SamArray *sam_entries;
2733 uint32_t num_entries;
2735 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2741 if (!NT_STATUS_IS_OK(status)) {
2742 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2743 "%s\n", nt_errstr(status)));
2747 if (num_entries == 0) {
2748 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2749 "no entries -- done\n"));
2753 for (i=0; i<num_entries; i++) {
2756 name = sam_entries->entries[i].name.string;
2758 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2759 &&(strlen(name)<=21)) {
2760 strlcpy(p,name,PTR_DIFF(endp,p));
2761 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2762 "username %s\n",count_sent,p));
2766 /* set overflow error */
2767 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2768 "username %s\n",count_sent,name));
2774 if (errflags != NERR_Success) {
2778 TALLOC_FREE(sam_entries);
2781 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2782 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2784 *rdata_len = PTR_DIFF(p,*rdata);
2786 SSVAL(*rparam,0,errflags);
2787 SSVAL(*rparam,2,0); /* converter word */
2788 SSVAL(*rparam,4,count_sent); /* is this right?? */
2789 SSVAL(*rparam,6,num_users); /* is this right?? */
2794 /****************************************************************************
2795 Get the time of day info.
2796 ****************************************************************************/
2798 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2799 char *param, int tpscnt,
2800 char *data, int tdscnt,
2801 int mdrcnt,int mprcnt,
2802 char **rdata,char **rparam,
2803 int *rdata_len,int *rparam_len)
2806 time_t unixdate = time(NULL);
2810 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2816 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2821 SSVAL(*rparam,0,NERR_Success);
2822 SSVAL(*rparam,2,0); /* converter word */
2826 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2827 by NT in a "net time" operation,
2828 it seems to ignore the one below */
2830 /* the client expects to get localtime, not GMT, in this bit
2831 (I think, this needs testing) */
2832 t = localtime(&unixdate);
2837 SIVAL(p,4,0); /* msecs ? */
2838 SCVAL(p,8,t->tm_hour);
2839 SCVAL(p,9,t->tm_min);
2840 SCVAL(p,10,t->tm_sec);
2841 SCVAL(p,11,0); /* hundredths of seconds */
2842 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2843 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2844 SCVAL(p,16,t->tm_mday);
2845 SCVAL(p,17,t->tm_mon + 1);
2846 SSVAL(p,18,1900+t->tm_year);
2847 SCVAL(p,20,t->tm_wday);
2852 /****************************************************************************
2853 Set the user password.
2854 *****************************************************************************/
2856 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2857 char *param, int tpscnt,
2858 char *data, int tdscnt,
2859 int mdrcnt,int mprcnt,
2860 char **rdata,char **rparam,
2861 int *rdata_len,int *rparam_len)
2863 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2866 fstring pass1,pass2;
2868 /* Skip 2 strings. */
2869 p = skip_string(param,tpscnt,np);
2870 p = skip_string(param,tpscnt,p);
2876 /* Do we have a string ? */
2877 if (skip_string(param,tpscnt,p) == NULL) {
2880 pull_ascii_fstring(user,p);
2882 p = skip_string(param,tpscnt,p);
2887 memset(pass1,'\0',sizeof(pass1));
2888 memset(pass2,'\0',sizeof(pass2));
2890 * We use 31 here not 32 as we're checking
2891 * the last byte we want to access is safe.
2893 if (!is_offset_safe(param,tpscnt,p,31)) {
2897 memcpy(pass2,p+16,16);
2900 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2907 SSVAL(*rparam,0,NERR_badpass);
2908 SSVAL(*rparam,2,0); /* converter word */
2910 DEBUG(3,("Set password for <%s>\n",user));
2913 * Attempt to verify the old password against smbpasswd entries
2914 * Win98 clients send old and new password in plaintext for this call.
2918 struct auth_serversupplied_info *server_info = NULL;
2919 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2921 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2924 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2925 SSVAL(*rparam,0,NERR_Success);
2929 TALLOC_FREE(server_info);
2931 data_blob_clear_free(&password);
2935 * If the plaintext change failed, attempt
2936 * the old encrypted method. NT will generate this
2937 * after trying the samr method. Note that this
2938 * method is done as a last resort as this
2939 * password change method loses the NT password hash
2940 * and cannot change the UNIX password as no plaintext
2944 if(SVAL(*rparam,0) != NERR_Success) {
2945 struct samu *hnd = NULL;
2947 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2949 if (change_lanman_password(hnd,(uchar *)pass2)) {
2950 SSVAL(*rparam,0,NERR_Success);
2957 memset((char *)pass1,'\0',sizeof(fstring));
2958 memset((char *)pass2,'\0',sizeof(fstring));
2963 /****************************************************************************
2964 Set the user password (SamOEM version - gets plaintext).
2965 ****************************************************************************/
2967 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2968 char *param, int tpscnt,
2969 char *data, int tdscnt,
2970 int mdrcnt,int mprcnt,
2971 char **rdata,char **rparam,
2972 int *rdata_len,int *rparam_len)
2974 struct smbd_server_connection *sconn = smbd_server_conn;
2976 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2978 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2988 SSVAL(*rparam,0,NERR_badpass);
2991 * Check the parameter definition is correct.
2994 /* Do we have a string ? */
2995 if (skip_string(param,tpscnt,p) == 0) {
2998 if(!strequal(p, "zsT")) {
2999 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3002 p = skip_string(param, tpscnt, p);
3007 /* Do we have a string ? */
3008 if (skip_string(param,tpscnt,p) == 0) {
3011 if(!strequal(p, "B516B16")) {
3012 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3015 p = skip_string(param,tpscnt,p);
3019 /* Do we have a string ? */
3020 if (skip_string(param,tpscnt,p) == 0) {
3023 p += pull_ascii_fstring(user,p);
3025 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3028 * Pass the user through the NT -> unix user mapping
3032 (void)map_username(sconn, user);
3034 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
3035 SSVAL(*rparam,0,NERR_Success);
3041 /****************************************************************************
3044 ****************************************************************************/
3046 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3047 char *param, int tpscnt,
3048 char *data, int tdscnt,
3049 int mdrcnt,int mprcnt,
3050 char **rdata,char **rparam,
3051 int *rdata_len,int *rparam_len)
3053 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3054 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3055 char *str2 = skip_string(param,tpscnt,str1);
3056 char *p = skip_string(param,tpscnt,str2);
3060 WERROR werr = WERR_OK;
3062 TALLOC_CTX *mem_ctx = talloc_tos();
3064 struct rpc_pipe_client *cli = NULL;
3065 struct policy_handle handle;
3066 struct spoolss_DevmodeContainer devmode_ctr;
3067 enum spoolss_JobControl command;
3069 if (!str1 || !str2 || !p) {
3073 * We use 1 here not 2 as we're checking
3074 * the last byte we want to access is safe.
3076 if (!is_offset_safe(param,tpscnt,p,1)) {
3079 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3082 /* check it's a supported varient */
3083 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3087 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3093 ZERO_STRUCT(handle);
3095 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3096 rpc_spoolss_dispatch, conn->server_info,
3098 if (!NT_STATUS_IS_OK(status)) {
3099 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3100 nt_errstr(status)));
3101 errcode = W_ERROR_V(ntstatus_to_werror(status));
3105 ZERO_STRUCT(devmode_ctr);
3107 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3111 SEC_FLAG_MAXIMUM_ALLOWED,
3114 if (!NT_STATUS_IS_OK(status)) {
3115 errcode = W_ERROR_V(ntstatus_to_werror(status));
3118 if (!W_ERROR_IS_OK(werr)) {
3119 errcode = W_ERROR_V(werr);
3123 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3124 * and NERR_DestNotFound if share did not exist */
3126 errcode = NERR_Success;
3129 case 81: /* delete */
3130 command = SPOOLSS_JOB_CONTROL_DELETE;
3132 case 82: /* pause */
3133 command = SPOOLSS_JOB_CONTROL_PAUSE;
3135 case 83: /* resume */
3136 command = SPOOLSS_JOB_CONTROL_RESUME;
3139 errcode = NERR_notsupported;
3143 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3146 NULL, /* unique ptr ctr */
3149 if (!NT_STATUS_IS_OK(status)) {
3150 errcode = W_ERROR_V(ntstatus_to_werror(status));
3153 if (!W_ERROR_IS_OK(werr)) {
3154 errcode = W_ERROR_V(werr);
3159 if (is_valid_policy_hnd(&handle)) {
3160 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3163 SSVAL(*rparam,0,errcode);
3164 SSVAL(*rparam,2,0); /* converter word */
3169 /****************************************************************************
3170 Purge a print queue - or pause or resume it.
3171 ****************************************************************************/
3173 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3174 char *param, int tpscnt,
3175 char *data, int tdscnt,
3176 int mdrcnt,int mprcnt,
3177 char **rdata,char **rparam,
3178 int *rdata_len,int *rparam_len)
3180 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3181 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3182 char *str2 = skip_string(param,tpscnt,str1);
3183 char *QueueName = skip_string(param,tpscnt,str2);
3184 int errcode = NERR_notsupported;
3185 WERROR werr = WERR_OK;
3188 TALLOC_CTX *mem_ctx = talloc_tos();
3189 struct rpc_pipe_client *cli = NULL;
3190 struct policy_handle handle;
3191 struct spoolss_SetPrinterInfoCtr info_ctr;
3192 struct spoolss_DevmodeContainer devmode_ctr;
3193 struct sec_desc_buf secdesc_ctr;
3194 enum spoolss_PrinterControl command;
3196 if (!str1 || !str2 || !QueueName) {
3200 /* check it's a supported varient */
3201 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3205 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3211 if (skip_string(param,tpscnt,QueueName) == NULL) {
3215 ZERO_STRUCT(handle);
3217 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3218 rpc_spoolss_dispatch, conn->server_info,
3220 if (!NT_STATUS_IS_OK(status)) {
3221 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3222 nt_errstr(status)));
3223 errcode = W_ERROR_V(ntstatus_to_werror(status));
3227 ZERO_STRUCT(devmode_ctr);
3229 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3233 SEC_FLAG_MAXIMUM_ALLOWED,
3236 if (!NT_STATUS_IS_OK(status)) {
3237 errcode = W_ERROR_V(ntstatus_to_werror(status));
3240 if (!W_ERROR_IS_OK(werr)) {
3241 errcode = W_ERROR_V(werr);
3246 case 74: /* Pause queue */
3247 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3249 case 75: /* Resume queue */
3250 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3252 case 103: /* Purge */
3253 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3256 werr = WERR_NOT_SUPPORTED;
3260 if (!W_ERROR_IS_OK(werr)) {
3261 errcode = W_ERROR_V(werr);
3265 ZERO_STRUCT(info_ctr);
3266 ZERO_STRUCT(secdesc_ctr);
3268 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3275 if (!NT_STATUS_IS_OK(status)) {
3276 errcode = W_ERROR_V(ntstatus_to_werror(status));
3279 if (!W_ERROR_IS_OK(werr)) {
3280 errcode = W_ERROR_V(werr);
3284 errcode = W_ERROR_V(werr);
3288 if (is_valid_policy_hnd(&handle)) {
3289 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3292 SSVAL(*rparam,0,errcode);
3293 SSVAL(*rparam,2,0); /* converter word */
3298 /****************************************************************************
3299 set the property of a print job (undocumented?)
3300 ? function = 0xb -> set name of print job
3301 ? function = 0x6 -> move print job up/down
3302 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3303 or <WWsTP> <WB21BB16B10zWWzDDz>
3304 ****************************************************************************/
3306 static int check_printjob_info(struct pack_desc* desc,
3307 int uLevel, char* id)
3309 desc->subformat = NULL;
3311 case 0: desc->format = "W"; break;
3312 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3313 case 2: desc->format = "WWzWWDDzz"; break;
3314 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3315 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3317 DEBUG(0,("check_printjob_info: invalid level %d\n",
3321 if (id == NULL || strcmp(desc->format,id) != 0) {
3322 DEBUG(0,("check_printjob_info: invalid format %s\n",
3323 id ? id : "<NULL>" ));
3329 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3330 char *param, int tpscnt,
3331 char *data, int tdscnt,
3332 int mdrcnt,int mprcnt,
3333 char **rdata,char **rparam,
3334 int *rdata_len,int *rparam_len)
3336 struct pack_desc desc;
3337 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3338 char *str2 = skip_string(param,tpscnt,str1);
3339 char *p = skip_string(param,tpscnt,str2);
3342 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3343 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3346 if (!str1 || !str2 || !p) {
3350 * We use 1 here not 2 as we're checking
3351 * the last byte we want to access is safe.
3353 if (!is_offset_safe(param,tpscnt,p,1)) {
3356 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3359 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3364 if (!share_defined(sharename)) {
3365 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
3372 /* check it's a supported varient */
3373 if ((strcmp(str1,"WWsTP")) ||
3374 (!check_printjob_info(&desc,uLevel,str2)))
3377 if (!print_job_exists(sharename, jobid)) {
3378 errcode=NERR_JobNotFound;
3382 errcode = NERR_notsupported;
3386 /* change print job name, data gives the name */
3387 if (print_job_set_name(sharename, jobid, data)) {
3388 errcode=NERR_Success;
3397 SSVALS(*rparam,0,errcode);
3398 SSVAL(*rparam,2,0); /* converter word */
3404 /****************************************************************************
3405 Get info about the server.
3406 ****************************************************************************/
3408 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3409 char *param, int tpscnt,
3410 char *data, int tdscnt,
3411 int mdrcnt,int mprcnt,
3412 char **rdata,char **rparam,
3413 int *rdata_len,int *rparam_len)
3415 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3416 char *str2 = skip_string(param,tpscnt,str1);
3417 char *p = skip_string(param,tpscnt,str2);
3418 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3422 if (!str1 || !str2 || !p) {
3426 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3428 /* check it's a supported varient */
3429 if (!prefix_ok(str1,"WrLh")) {
3435 if (strcmp(str2,"B16") != 0) {
3441 if (strcmp(str2,"B16BBDz") != 0) {
3447 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3453 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3459 if (strcmp(str2,"DN") != 0) {
3465 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3474 *rdata_len = mdrcnt;
3475 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3481 p2 = p + struct_len;
3483 srvstr_push(NULL, 0, p,global_myname(),16,
3484 STR_ASCII|STR_UPPER|STR_TERMINATE);
3488 struct srv_info_struct *servers=NULL;
3490 char *comment = NULL;
3491 TALLOC_CTX *ctx = talloc_tos();
3492 uint32 servertype= lp_default_server_announce();
3494 comment = talloc_strdup(ctx,lp_serverstring());
3499 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3500 for (i=0;i<count;i++) {
3501 if (strequal(servers[i].name,global_myname())) {
3502 servertype = servers[i].type;
3503 TALLOC_FREE(comment);
3504 comment = talloc_strdup(ctx,
3505 servers[i].comment);
3515 SCVAL(p,0,lp_major_announce_version());
3516 SCVAL(p,1,lp_minor_announce_version());
3517 SIVAL(p,2,servertype);
3519 if (mdrcnt == struct_len) {
3522 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3523 comment = talloc_sub_advanced(
3525 lp_servicename(SNUM(conn)),
3526 conn->server_info->unix_name,
3528 conn->server_info->utok.gid,
3529 conn->server_info->sanitized_username,
3530 pdb_get_domain(conn->server_info->sam_account),
3535 if (mdrcnt - struct_len <= 0) {
3540 MIN(mdrcnt - struct_len,
3541 MAX_SERVER_STRING_LENGTH),
3543 p2 = skip_string(*rdata,*rdata_len,p2);
3551 return False; /* not yet implemented */
3554 *rdata_len = PTR_DIFF(p2,*rdata);
3557 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3561 SSVAL(*rparam,0,NERR_Success);
3562 SSVAL(*rparam,2,0); /* converter word */
3563 SSVAL(*rparam,4,*rdata_len);
3568 /****************************************************************************
3569 Get info about the server.
3570 ****************************************************************************/
3572 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3573 char *param, int tpscnt,
3574 char *data, int tdscnt,
3575 int mdrcnt,int mprcnt,
3576 char **rdata,char **rparam,
3577 int *rdata_len,int *rparam_len)
3579 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3580 char *str2 = skip_string(param,tpscnt,str1);
3581 char *p = skip_string(param,tpscnt,str2);
3584 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3586 if (!str1 || !str2 || !p) {
3590 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3593 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3598 /* check it's a supported varient */
3599 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3603 *rdata_len = mdrcnt + 1024;
3604 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3609 SSVAL(*rparam,0,NERR_Success);
3610 SSVAL(*rparam,2,0); /* converter word */
3613 endp = *rdata + *rdata_len;
3615 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3620 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3621 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3623 p2 = skip_string(*rdata,*rdata_len,p2);
3629 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3630 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3631 p2 = skip_string(*rdata,*rdata_len,p2);
3637 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3638 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3640 p2 = skip_string(*rdata,*rdata_len,p2);
3646 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3647 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3650 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3651 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3652 p2 = skip_string(*rdata,*rdata_len,p2);
3658 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3659 strlcpy(p2,"",PTR_DIFF(endp,p2));
3660 p2 = skip_string(*rdata,*rdata_len,p2);
3666 *rdata_len = PTR_DIFF(p2,*rdata);
3668 SSVAL(*rparam,4,*rdata_len);
3673 /****************************************************************************
3674 get info about a user
3676 struct user_info_11 {
3677 char usri11_name[21]; 0-20
3679 char *usri11_comment; 22-25
3680 char *usri11_usr_comment; 26-29
3681 unsigned short usri11_priv; 30-31
3682 unsigned long usri11_auth_flags; 32-35
3683 long usri11_password_age; 36-39
3684 char *usri11_homedir; 40-43
3685 char *usri11_parms; 44-47
3686 long usri11_last_logon; 48-51
3687 long usri11_last_logoff; 52-55
3688 unsigned short usri11_bad_pw_count; 56-57
3689 unsigned short usri11_num_logons; 58-59
3690 char *usri11_logon_server; 60-63
3691 unsigned short usri11_country_code; 64-65
3692 char *usri11_workstations; 66-69
3693 unsigned long usri11_max_storage; 70-73
3694 unsigned short usri11_units_per_week; 74-75
3695 unsigned char *usri11_logon_hours; 76-79
3696 unsigned short usri11_code_page; 80-81
3701 usri11_name specifies the user name for which information is retrieved
3703 usri11_pad aligns the next data structure element to a word boundary
3705 usri11_comment is a null terminated ASCII comment
3707 usri11_user_comment is a null terminated ASCII comment about the user
3709 usri11_priv specifies the level of the privilege assigned to the user.
3710 The possible values are:
3712 Name Value Description
3713 USER_PRIV_GUEST 0 Guest privilege
3714 USER_PRIV_USER 1 User privilege
3715 USER_PRV_ADMIN 2 Administrator privilege
3717 usri11_auth_flags specifies the account operator privileges. The
3718 possible values are:
3720 Name Value Description
3721 AF_OP_PRINT 0 Print operator
3724 Leach, Naik [Page 28]
3728 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3731 AF_OP_COMM 1 Communications operator
3732 AF_OP_SERVER 2 Server operator
3733 AF_OP_ACCOUNTS 3 Accounts operator
3736 usri11_password_age specifies how many seconds have elapsed since the
3737 password was last changed.
3739 usri11_home_dir points to a null terminated ASCII string that contains
3740 the path name of the user's home directory.
3742 usri11_parms points to a null terminated ASCII string that is set
3743 aside for use by applications.
3745 usri11_last_logon specifies the time when the user last logged on.
3746 This value is stored as the number of seconds elapsed since
3747 00:00:00, January 1, 1970.
3749 usri11_last_logoff specifies the time when the user last logged off.
3750 This value is stored as the number of seconds elapsed since
3751 00:00:00, January 1, 1970. A value of 0 means the last logoff
3754 usri11_bad_pw_count specifies the number of incorrect passwords
3755 entered since the last successful logon.
3757 usri11_log1_num_logons specifies the number of times this user has
3758 logged on. A value of -1 means the number of logons is unknown.
3760 usri11_logon_server points to a null terminated ASCII string that
3761 contains the name of the server to which logon requests are sent.
3762 A null string indicates logon requests should be sent to the
3765 usri11_country_code specifies the country code for the user's language
3768 usri11_workstations points to a null terminated ASCII string that
3769 contains the names of workstations the user may log on from.
3770 There may be up to 8 workstations, with the names separated by
3771 commas. A null strings indicates there are no restrictions.
3773 usri11_max_storage specifies the maximum amount of disk space the user
3774 can occupy. A value of 0xffffffff indicates there are no
3777 usri11_units_per_week specifies the equal number of time units into
3778 which a week is divided. This value must be equal to 168.
3780 usri11_logon_hours points to a 21 byte (168 bits) string that
3781 specifies the time during which the user can log on. Each bit
3782 represents one unique hour in a week. The first bit (bit 0, word
3783 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3787 Leach, Naik [Page 29]
3791 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3794 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3795 are no restrictions.
3797 usri11_code_page specifies the code page for the user's language of
3800 All of the pointers in this data structure need to be treated
3801 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3802 to be ignored. The converter word returned in the parameters section
3803 needs to be subtracted from the lower 16 bits to calculate an offset
3804 into the return buffer where this ASCII string resides.
3806 There is no auxiliary data in the response.
3808 ****************************************************************************/
3810 #define usri11_name 0
3811 #define usri11_pad 21
3812 #define usri11_comment 22
3813 #define usri11_usr_comment 26
3814 #define usri11_full_name 30
3815 #define usri11_priv 34
3816 #define usri11_auth_flags 36
3817 #define usri11_password_age 40
3818 #define usri11_homedir 44
3819 #define usri11_parms 48
3820 #define usri11_last_logon 52
3821 #define usri11_last_logoff 56
3822 #define usri11_bad_pw_count 60
3823 #define usri11_num_logons 62
3824 #define usri11_logon_server 64
3825 #define usri11_country_code 68
3826 #define usri11_workstations 70
3827 #define usri11_max_storage 74
3828 #define usri11_units_per_week 78
3829 #define usri11_logon_hours 80
3830 #define usri11_code_page 84
3831 #define usri11_end 86
3833 #define USER_PRIV_GUEST 0
3834 #define USER_PRIV_USER 1
3835 #define USER_PRIV_ADMIN 2
3837 #define AF_OP_PRINT 0
3838 #define AF_OP_COMM 1
3839 #define AF_OP_SERVER 2
3840 #define AF_OP_ACCOUNTS 3
3843 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3844 char *param, int tpscnt,
3845 char *data, int tdscnt,
3846 int mdrcnt,int mprcnt,
3847 char **rdata,char **rparam,
3848 int *rdata_len,int *rparam_len)
3850 struct smbd_server_connection *sconn = smbd_server_conn;
3851 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3852 char *str2 = skip_string(param,tpscnt,str1);
3853 char *UserName = skip_string(param,tpscnt,str2);
3854 char *p = skip_string(param,tpscnt,UserName);
3855 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3858 const char *level_string;
3860 /* get NIS home of a previously validated user - simeon */
3861 /* With share level security vuid will always be zero.
3862 Don't depend on vuser being non-null !!. JRA */
3863 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3865 DEBUG(3,(" Username of UID %d is %s\n",
3866 (int)vuser->server_info->utok.uid,
3867 vuser->server_info->unix_name));
3870 if (!str1 || !str2 || !UserName || !p) {
3875 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3880 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3882 /* check it's a supported variant */
3883 if (strcmp(str1,"zWrLh") != 0) {
3887 case 0: level_string = "B21"; break;
3888 case 1: level_string = "B21BB16DWzzWz"; break;
3889 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3890 case 10: level_string = "B21Bzzz"; break;
3891 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3892 default: return False;
3895 if (strcmp(level_string,str2) != 0) {
3899 *rdata_len = mdrcnt + 1024;
3900 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3905 SSVAL(*rparam,0,NERR_Success);
3906 SSVAL(*rparam,2,0); /* converter word */
3909 endp = *rdata + *rdata_len;
3910 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3916 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3919 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3924 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3925 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3926 p2 = skip_string(*rdata,*rdata_len,p2);
3931 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3932 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3933 p2 = skip_string(*rdata,*rdata_len,p2);
3938 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3939 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3940 strlcpy(p2,((vuser != NULL)
3941 ? pdb_get_fullname(vuser->server_info->sam_account)
3942 : UserName),PTR_DIFF(endp,p2));
3943 p2 = skip_string(*rdata,*rdata_len,p2);
3950 const char *homedir = "";
3951 if (vuser != NULL) {
3952 homedir = pdb_get_homedir(
3953 vuser->server_info->sam_account);
3955 /* modelled after NTAS 3.51 reply */
3956 SSVAL(p,usri11_priv,
3957 (get_current_uid(conn) == sec_initial_uid())?
3958 USER_PRIV_ADMIN:USER_PRIV_USER);
3959 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3960 SIVALS(p,usri11_password_age,-1); /* password age */
3961 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3962 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3963 p2 = skip_string(*rdata,*rdata_len,p2);
3967 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3968 strlcpy(p2,"",PTR_DIFF(endp,p2));
3969 p2 = skip_string(*rdata,*rdata_len,p2);
3973 SIVAL(p,usri11_last_logon,0); /* last logon */
3974 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3975 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3976 SSVALS(p,usri11_num_logons,-1); /* num logons */
3977 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3978 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3979 p2 = skip_string(*rdata,*rdata_len,p2);
3983 SSVAL(p,usri11_country_code,0); /* country code */
3985 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3986 strlcpy(p2,"",PTR_DIFF(endp,p2));
3987 p2 = skip_string(*rdata,*rdata_len,p2);
3992 SIVALS(p,usri11_max_storage,-1); /* max storage */
3993 SSVAL(p,usri11_units_per_week,168); /* units per week */
3994 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3996 /* a simple way to get logon hours at all times. */
3998 SCVAL(p2,21,0); /* fix zero termination */
3999 p2 = skip_string(*rdata,*rdata_len,p2);
4004 SSVAL(p,usri11_code_page,0); /* code page */
4007 if (uLevel == 1 || uLevel == 2) {
4008 memset(p+22,' ',16); /* password */
4009 SIVALS(p,38,-1); /* password age */
4011 (get_current_uid(conn) == sec_initial_uid())?
4012 USER_PRIV_ADMIN:USER_PRIV_USER);
4013 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4014 strlcpy(p2, vuser ? pdb_get_homedir(
4015 vuser->server_info->sam_account) : "",
4017 p2 = skip_string(*rdata,*rdata_len,p2);
4021 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4023 SSVAL(p,52,0); /* flags */
4024 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4025 strlcpy(p2, vuser ? pdb_get_logon_script(
4026 vuser->server_info->sam_account) : "",
4028 p2 = skip_string(*rdata,*rdata_len,p2);
4033 SIVAL(p,60,0); /* auth_flags */
4034 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4035 strlcpy(p2,((vuser != NULL)
4036 ? pdb_get_fullname(vuser->server_info->sam_account)
4037 : UserName),PTR_DIFF(endp,p2));
4038 p2 = skip_string(*rdata,*rdata_len,p2);
4042 SIVAL(p,68,0); /* urs_comment */
4043 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4044 strlcpy(p2,"",PTR_DIFF(endp,p2));
4045 p2 = skip_string(*rdata,*rdata_len,p2);
4049 SIVAL(p,76,0); /* workstations */
4050 SIVAL(p,80,0); /* last_logon */
4051 SIVAL(p,84,0); /* last_logoff */
4052 SIVALS(p,88,-1); /* acct_expires */
4053 SIVALS(p,92,-1); /* max_storage */
4054 SSVAL(p,96,168); /* units_per_week */
4055 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4058 SSVALS(p,102,-1); /* bad_pw_count */
4059 SSVALS(p,104,-1); /* num_logons */
4060 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4062 TALLOC_CTX *ctx = talloc_tos();
4063 int space_rem = *rdata_len - (p2 - *rdata);
4066 if (space_rem <= 0) {
4069 tmp = talloc_strdup(ctx, "\\\\%L");
4073 tmp = talloc_sub_basic(ctx,
4086 p2 = skip_string(*rdata,*rdata_len,p2);
4090 SSVAL(p,110,49); /* country_code */
4091 SSVAL(p,112,860); /* code page */
4095 *rdata_len = PTR_DIFF(p2,*rdata);
4097 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4102 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4103 char *param, int tpscnt,
4104 char *data, int tdscnt,
4105 int mdrcnt,int mprcnt,
4106 char **rdata,char **rparam,
4107 int *rdata_len,int *rparam_len)
4109 struct smbd_server_connection *sconn = smbd_server_conn;
4110 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4111 char *str2 = skip_string(param,tpscnt,str1);
4112 char *p = skip_string(param,tpscnt,str2);
4114 struct pack_desc desc;
4116 /* With share level security vuid will always be zero.
4117 Don't depend on vuser being non-null !!. JRA */
4118 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4120 if (!str1 || !str2 || !p) {
4125 DEBUG(3,(" Username of UID %d is %s\n",
4126 (int)vuser->server_info->utok.uid,
4127 vuser->server_info->unix_name));
4130 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4131 name = get_safe_str_ptr(param,tpscnt,p,2);
4136 memset((char *)&desc,'\0',sizeof(desc));
4138 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4140 /* check it's a supported varient */
4141 if (strcmp(str1,"OOWb54WrLh") != 0) {
4144 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4148 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4155 desc.buflen = mdrcnt;
4156 desc.subformat = NULL;
4159 if (init_package(&desc,1,0)) {
4160 PACKI(&desc,"W",0); /* code */
4161 PACKS(&desc,"B21",name); /* eff. name */
4162 PACKS(&desc,"B",""); /* pad */
4164 (get_current_uid(conn) == sec_initial_uid())?
4165 USER_PRIV_ADMIN:USER_PRIV_USER);
4166 PACKI(&desc,"D",0); /* auth flags XXX */
4167 PACKI(&desc,"W",0); /* num logons */
4168 PACKI(&desc,"W",0); /* bad pw count */
4169 PACKI(&desc,"D",0); /* last logon */
4170 PACKI(&desc,"D",-1); /* last logoff */
4171 PACKI(&desc,"D",-1); /* logoff time */
4172 PACKI(&desc,"D",-1); /* kickoff time */
4173 PACKI(&desc,"D",0); /* password age */
4174 PACKI(&desc,"D",0); /* password can change */
4175 PACKI(&desc,"D",-1); /* password must change */
4179 fstrcpy(mypath,"\\\\");
4180 fstrcat(mypath,get_local_machine_name());
4182 PACKS(&desc,"z",mypath); /* computer */
4185 PACKS(&desc,"z",lp_workgroup());/* domain */
4186 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4187 vuser->server_info->sam_account) : ""); /* script path */
4188 PACKI(&desc,"D",0x00000000); /* reserved */
4191 *rdata_len = desc.usedlen;
4193 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4197 SSVALS(*rparam,0,desc.errcode);
4199 SSVAL(*rparam,4,desc.neededlen);
4201 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4206 /****************************************************************************
4207 api_WAccessGetUserPerms
4208 ****************************************************************************/
4210 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4211 char *param, int tpscnt,
4212 char *data, int tdscnt,
4213 int mdrcnt,int mprcnt,
4214 char **rdata,char **rparam,
4215 int *rdata_len,int *rparam_len)
4217 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4218 char *str2 = skip_string(param,tpscnt,str1);
4219 char *user = skip_string(param,tpscnt,str2);
4220 char *resource = skip_string(param,tpscnt,user);
4222 if (!str1 || !str2 || !user || !resource) {
4226 if (skip_string(param,tpscnt,resource) == NULL) {
4229 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4231 /* check it's a supported varient */
4232 if (strcmp(str1,"zzh") != 0) {
4235 if (strcmp(str2,"") != 0) {
4240 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4244 SSVALS(*rparam,0,0); /* errorcode */
4245 SSVAL(*rparam,2,0); /* converter word */
4246 SSVAL(*rparam,4,0x7f); /* permission flags */
4251 /****************************************************************************
4252 api_WPrintJobEnumerate
4253 ****************************************************************************/
4255 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4256 char *param, int tpscnt,
4257 char *data, int tdscnt,
4258 int mdrcnt,int mprcnt,
4259 char **rdata,char **rparam,
4260 int *rdata_len,int *rparam_len)
4262 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4263 char *str2 = skip_string(param,tpscnt,str1);
4264 char *p = skip_string(param,tpscnt,str2);
4268 struct pack_desc desc;
4271 TALLOC_CTX *mem_ctx = talloc_tos();
4274 struct rpc_pipe_client *cli = NULL;
4275 struct policy_handle handle;
4276 struct spoolss_DevmodeContainer devmode_ctr;
4277 union spoolss_JobInfo info;
4279 if (!str1 || !str2 || !p) {
4283 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4285 memset((char *)&desc,'\0',sizeof(desc));
4286 memset((char *)&status,'\0',sizeof(status));
4288 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4290 /* check it's a supported varient */
4291 if (strcmp(str1,"WWrLh") != 0) {
4294 if (!check_printjob_info(&desc,uLevel,str2)) {
4298 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4302 ZERO_STRUCT(handle);
4304 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4305 rpc_spoolss_dispatch, conn->server_info,
4307 if (!NT_STATUS_IS_OK(status)) {
4308 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4309 nt_errstr(status)));
4310 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4314 ZERO_STRUCT(devmode_ctr);
4316 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4320 SEC_FLAG_MAXIMUM_ALLOWED,
4323 if (!NT_STATUS_IS_OK(status)) {
4324 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4327 if (!W_ERROR_IS_OK(werr)) {
4328 desc.errcode = W_ERROR_V(werr);
4332 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4338 if (!W_ERROR_IS_OK(werr)) {
4339 desc.errcode = W_ERROR_V(werr);
4344 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4349 desc.buflen = mdrcnt;
4352 * Don't return data but need to get correct length
4353 * init_package will return wrong size if buflen=0
4355 desc.buflen = getlen(desc.format);
4356 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4359 if (init_package(&desc,1,0)) {
4360 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4361 *rdata_len = desc.usedlen;
4363 desc.errcode = NERR_JobNotFound;
4367 if (is_valid_policy_hnd(&handle)) {
4368 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4372 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4376 SSVALS(*rparam,0,desc.errcode);
4378 SSVAL(*rparam,4,desc.neededlen);
4382 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4387 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4388 char *param, int tpscnt,
4389 char *data, int tdscnt,
4390 int mdrcnt,int mprcnt,
4391 char **rdata,char **rparam,
4392 int *rdata_len,int *rparam_len)
4394 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4395 char *str2 = skip_string(param,tpscnt,str1);
4396 char *p = skip_string(param,tpscnt,str2);
4400 struct pack_desc desc;
4402 TALLOC_CTX *mem_ctx = talloc_tos();
4405 struct rpc_pipe_client *cli = NULL;
4406 struct policy_handle handle;
4407 struct spoolss_DevmodeContainer devmode_ctr;
4409 union spoolss_JobInfo *info;
4411 if (!str1 || !str2 || !p) {
4415 memset((char *)&desc,'\0',sizeof(desc));
4416 memset((char *)&status,'\0',sizeof(status));
4418 p = skip_string(param,tpscnt,p);
4422 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4424 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4426 /* check it's a supported variant */
4427 if (strcmp(str1,"zWrLeh") != 0) {
4432 return False; /* defined only for uLevel 0,1,2 */
4435 if (!check_printjob_info(&desc,uLevel,str2)) {
4439 ZERO_STRUCT(handle);
4441 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4442 rpc_spoolss_dispatch, conn->server_info,
4444 if (!NT_STATUS_IS_OK(status)) {
4445 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
4446 nt_errstr(status)));
4447 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4451 ZERO_STRUCT(devmode_ctr);
4453 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4457 SEC_FLAG_MAXIMUM_ALLOWED,
4460 if (!NT_STATUS_IS_OK(status)) {
4461 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4464 if (!W_ERROR_IS_OK(werr)) {
4465 desc.errcode = W_ERROR_V(werr);
4469 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4477 if (!W_ERROR_IS_OK(werr)) {
4478 desc.errcode = W_ERROR_V(werr);
4483 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4489 desc.buflen = mdrcnt;
4491 if (init_package(&desc,count,0)) {
4493 for (i = 0; i < count; i++) {
4494 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4495 if (desc.errcode == NERR_Success) {
4501 if (is_valid_policy_hnd(&handle)) {
4502 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4505 *rdata_len = desc.usedlen;
4508 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4512 SSVALS(*rparam,0,desc.errcode);
4514 SSVAL(*rparam,4,succnt);
4515 SSVAL(*rparam,6,count);
4517 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4522 static int check_printdest_info(struct pack_desc* desc,
4523 int uLevel, char* id)
4525 desc->subformat = NULL;
4528 desc->format = "B9";
4531 desc->format = "B9B21WWzW";
4537 desc->format = "zzzWWzzzWW";
4540 DEBUG(0,("check_printdest_info: invalid level %d\n",
4544 if (id == NULL || strcmp(desc->format,id) != 0) {
4545 DEBUG(0,("check_printdest_info: invalid string %s\n",
4546 id ? id : "<NULL>" ));
4552 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4553 struct pack_desc* desc)
4557 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4558 buf[sizeof(buf)-1] = 0;
4562 PACKS(desc,"B9",buf); /* szName */
4564 PACKS(desc,"B21",""); /* szUserName */
4565 PACKI(desc,"W",0); /* uJobId */
4566 PACKI(desc,"W",0); /* fsStatus */
4567 PACKS(desc,"z",""); /* pszStatus */
4568 PACKI(desc,"W",0); /* time */
4572 if (uLevel == 2 || uLevel == 3) {
4573 PACKS(desc,"z",buf); /* pszPrinterName */
4575 PACKS(desc,"z",""); /* pszUserName */
4576 PACKS(desc,"z",""); /* pszLogAddr */
4577 PACKI(desc,"W",0); /* uJobId */
4578 PACKI(desc,"W",0); /* fsStatus */
4579 PACKS(desc,"z",""); /* pszStatus */
4580 PACKS(desc,"z",""); /* pszComment */
4581 PACKS(desc,"z","NULL"); /* pszDrivers */
4582 PACKI(desc,"W",0); /* time */
4583 PACKI(desc,"W",0); /* pad1 */
4588 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4589 char *param, int tpscnt,
4590 char *data, int tdscnt,
4591 int mdrcnt,int mprcnt,
4592 char **rdata,char **rparam,
4593 int *rdata_len,int *rparam_len)
4595 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4596 char *str2 = skip_string(param,tpscnt,str1);
4597 char *p = skip_string(param,tpscnt,str2);
4598 char* PrinterName = p;
4600 struct pack_desc desc;
4604 if (!str1 || !str2 || !p) {
4608 memset((char *)&desc,'\0',sizeof(desc));
4610 p = skip_string(param,tpscnt,p);
4614 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4616 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4618 /* check it's a supported varient */
4619 if (strcmp(str1,"zWrLh") != 0) {
4622 if (!check_printdest_info(&desc,uLevel,str2)) {
4626 snum = find_service(PrinterName);
4627 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4629 desc.errcode = NERR_DestNotFound;
4633 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4638 desc.buflen = mdrcnt;
4641 * Don't return data but need to get correct length
4642 * init_package will return wrong size if buflen=0
4644 desc.buflen = getlen(desc.format);
4645 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4647 if (init_package(&desc,1,0)) {
4648 fill_printdest_info(conn,snum,uLevel,&desc);
4650 *rdata_len = desc.usedlen;
4654 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4658 SSVALS(*rparam,0,desc.errcode);
4660 SSVAL(*rparam,4,desc.neededlen);
4662 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4668 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4669 char *param, int tpscnt,
4670 char *data, int tdscnt,
4671 int mdrcnt,int mprcnt,
4672 char **rdata,char **rparam,
4673 int *rdata_len,int *rparam_len)
4675 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4676 char *str2 = skip_string(param,tpscnt,str1);
4677 char *p = skip_string(param,tpscnt,str2);
4681 struct pack_desc desc;
4682 int services = lp_numservices();
4684 if (!str1 || !str2 || !p) {
4688 memset((char *)&desc,'\0',sizeof(desc));
4690 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4692 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4694 /* check it's a supported varient */
4695 if (strcmp(str1,"WrLeh") != 0) {
4698 if (!check_printdest_info(&desc,uLevel,str2)) {
4703 for (i = 0; i < services; i++) {
4704 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4710 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4717 desc.buflen = mdrcnt;
4718 if (init_package(&desc,queuecnt,0)) {
4721 for (i = 0; i < services; i++) {
4722 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4723 fill_printdest_info(conn,i,uLevel,&desc);
4725 if (desc.errcode == NERR_Success) {
4732 *rdata_len = desc.usedlen;
4735 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4739 SSVALS(*rparam,0,desc.errcode);
4741 SSVAL(*rparam,4,succnt);
4742 SSVAL(*rparam,6,queuecnt);
4744 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4749 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4750 char *param, int tpscnt,
4751 char *data, int tdscnt,
4752 int mdrcnt,int mprcnt,
4753 char **rdata,char **rparam,
4754 int *rdata_len,int *rparam_len)
4756 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4757 char *str2 = skip_string(param,tpscnt,str1);
4758 char *p = skip_string(param,tpscnt,str2);
4761 struct pack_desc desc;
4763 if (!str1 || !str2 || !p) {
4767 memset((char *)&desc,'\0',sizeof(desc));
4769 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4771 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4773 /* check it's a supported varient */
4774 if (strcmp(str1,"WrLeh") != 0) {
4777 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4782 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4788 desc.buflen = mdrcnt;
4789 if (init_package(&desc,1,0)) {
4790 PACKS(&desc,"B41","NULL");
4793 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4795 *rdata_len = desc.usedlen;
4798 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4802 SSVALS(*rparam,0,desc.errcode);
4804 SSVAL(*rparam,4,succnt);
4807 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4812 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4813 char *param, int tpscnt,
4814 char *data, int tdscnt,
4815 int mdrcnt,int mprcnt,
4816 char **rdata,char **rparam,
4817 int *rdata_len,int *rparam_len)
4819 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4820 char *str2 = skip_string(param,tpscnt,str1);
4821 char *p = skip_string(param,tpscnt,str2);
4824 struct pack_desc desc;
4826 if (!str1 || !str2 || !p) {
4829 memset((char *)&desc,'\0',sizeof(desc));
4831 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4833 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4835 /* check it's a supported varient */
4836 if (strcmp(str1,"WrLeh") != 0) {
4839 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4844 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4850 desc.buflen = mdrcnt;
4852 if (init_package(&desc,1,0)) {
4853 PACKS(&desc,"B13","lpd");
4856 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4858 *rdata_len = desc.usedlen;
4861 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4865 SSVALS(*rparam,0,desc.errcode);
4867 SSVAL(*rparam,4,succnt);
4870 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4875 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4876 char *param, int tpscnt,
4877 char *data, int tdscnt,
4878 int mdrcnt,int mprcnt,
4879 char **rdata,char **rparam,
4880 int *rdata_len,int *rparam_len)
4882 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4883 char *str2 = skip_string(param,tpscnt,str1);
4884 char *p = skip_string(param,tpscnt,str2);
4887 struct pack_desc desc;
4889 if (!str1 || !str2 || !p) {
4893 memset((char *)&desc,'\0',sizeof(desc));
4895 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4897 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4899 /* check it's a supported varient */
4900 if (strcmp(str1,"WrLeh") != 0) {
4903 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4908 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4913 memset((char *)&desc,'\0',sizeof(desc));
4915 desc.buflen = mdrcnt;
4917 if (init_package(&desc,1,0)) {
4918 PACKS(&desc,"B13","lp0");
4921 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4923 *rdata_len = desc.usedlen;
4926 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4930 SSVALS(*rparam,0,desc.errcode);
4932 SSVAL(*rparam,4,succnt);
4935 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4940 /****************************************************************************
4942 ****************************************************************************/
4944 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4945 char *param, int tpscnt,
4946 char *data, int tdscnt,
4947 int mdrcnt,int mprcnt,
4948 char **rdata,char **rparam,
4949 int *rdata_len,int *rparam_len)
4952 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4953 char *str2 = skip_string(param,tpscnt,str1);
4954 char *p = skip_string(param,tpscnt,str2);
4956 struct pack_desc desc;
4957 struct sessionid *session_list;
4958 int i, num_sessions;
4960 if (!str1 || !str2 || !p) {
4964 memset((char *)&desc,'\0',sizeof(desc));
4966 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4968 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4969 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4970 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4972 /* check it's a supported varient */
4973 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4976 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4980 num_sessions = list_sessions(talloc_tos(), &session_list);
4983 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4988 memset((char *)&desc,'\0',sizeof(desc));
4990 desc.buflen = mdrcnt;
4992 if (!init_package(&desc,num_sessions,0)) {
4996 for(i=0; i<num_sessions; i++) {
4997 PACKS(&desc, "z", session_list[i].remote_machine);
4998 PACKS(&desc, "z", session_list[i].username);
4999 PACKI(&desc, "W", 1); /* num conns */
5000 PACKI(&desc, "W", 0); /* num opens */
5001 PACKI(&desc, "W", 1); /* num users */
5002 PACKI(&desc, "D", 0); /* session time */
5003 PACKI(&desc, "D", 0); /* idle time */
5004 PACKI(&desc, "D", 0); /* flags */
5005 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5008 *rdata_len = desc.usedlen;
5011 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5015 SSVALS(*rparam,0,desc.errcode);
5016 SSVAL(*rparam,2,0); /* converter */
5017 SSVAL(*rparam,4,num_sessions); /* count */
5019 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5025 /****************************************************************************
5026 The buffer was too small.
5027 ****************************************************************************/
5029 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5030 int mdrcnt, int mprcnt,
5031 char **rdata, char **rparam,
5032 int *rdata_len, int *rparam_len)
5034 *rparam_len = MIN(*rparam_len,mprcnt);
5035 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5042 SSVAL(*rparam,0,NERR_BufTooSmall);
5044 DEBUG(3,("Supplied buffer too small in API command\n"));
5049 /****************************************************************************
5050 The request is not supported.
5051 ****************************************************************************/
5053 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5054 char *param, int tpscnt,
5055 char *data, int tdscnt,
5056 int mdrcnt, int mprcnt,
5057 char **rdata, char **rparam,
5058 int *rdata_len, int *rparam_len)
5061 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5068 SSVAL(*rparam,0,NERR_notsupported);
5069 SSVAL(*rparam,2,0); /* converter word */
5071 DEBUG(3,("Unsupported API command\n"));
5076 static const struct {
5079 bool (*fn)(connection_struct *, uint16,
5082 int,int,char **,char **,int *,int *);
5083 bool auth_user; /* Deny anonymous access? */
5084 } api_commands[] = {
5085 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5086 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5087 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5088 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5089 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5090 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5091 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5092 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5093 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5094 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5095 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5096 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5097 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5098 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5099 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5100 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5101 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5102 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5103 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5104 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5105 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5106 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5107 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5108 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5109 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5110 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5111 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5112 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5113 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5114 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5115 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5116 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5117 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5118 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5119 {NULL, -1, api_Unsupported}
5120 /* The following RAP calls are not implemented by Samba:
5122 RAP_WFileEnum2 - anon not OK
5127 /****************************************************************************
5128 Handle remote api calls.
5129 ****************************************************************************/
5131 void api_reply(connection_struct *conn, uint16 vuid,
5132 struct smb_request *req,
5133 char *data, char *params,
5134 int tdscnt, int tpscnt,
5135 int mdrcnt, int mprcnt)
5137 struct smbd_server_connection *sconn = smbd_server_conn;
5140 char *rparam = NULL;
5141 const char *name1 = NULL;
5142 const char *name2 = NULL;
5149 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5150 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5155 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5158 api_command = SVAL(params,0);
5159 /* Is there a string at position params+2 ? */
5160 if (skip_string(params,tpscnt,params+2)) {
5165 name2 = skip_string(params,tpscnt,params+2);
5170 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5174 tdscnt,tpscnt,mdrcnt,mprcnt));
5176 for (i=0;api_commands[i].name;i++) {
5177 if (api_commands[i].id == api_command && api_commands[i].fn) {
5178 DEBUG(3,("Doing %s\n",api_commands[i].name));
5183 /* Check whether this api call can be done anonymously */
5185 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5186 user_struct *user = get_valid_user_struct(sconn, vuid);
5188 if (!user || user->server_info->guest) {
5189 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5194 rdata = (char *)SMB_MALLOC(1024);
5196 memset(rdata,'\0',1024);
5199 rparam = (char *)SMB_MALLOC(1024);
5201 memset(rparam,'\0',1024);
5204 if(!rdata || !rparam) {
5205 DEBUG(0,("api_reply: malloc fail !\n"));
5208 reply_nterror(req, NT_STATUS_NO_MEMORY);
5212 reply = api_commands[i].fn(conn,
5214 params,tpscnt, /* params + length */
5215 data,tdscnt, /* data + length */
5217 &rdata,&rparam,&rdata_len,&rparam_len);
5220 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5221 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5222 &rdata,&rparam,&rdata_len,&rparam_len);
5225 /* if we get False back then it's actually unsupported */
5227 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5228 &rdata,&rparam,&rdata_len,&rparam_len);
5231 /* If api_Unsupported returns false we can't return anything. */
5233 send_trans_reply(conn, req, rparam, rparam_len,
5234 rdata, rdata_len, False);