mirror of
https://github.com/samba-team/samba.git
synced 2025-02-28 01:58:17 +03:00
This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to be commit f0d009c3e91979b0dc3443e16f3f545bcc64cfda)
This commit is contained in:
commit
74d3be0218
181
docs/docbook/projdoc/securing-samba.sgml
Normal file
181
docs/docbook/projdoc/securing-samba.sgml
Normal file
@ -0,0 +1,181 @@
|
||||
<chapter id="securing-samba">
|
||||
|
||||
<chapterinfo>
|
||||
<author>
|
||||
<firstname>Andrew</firstname><surname>Tridgell</surname>
|
||||
<affiliation><orgname>Samba Team</orgname></affiliation>
|
||||
</author>
|
||||
<pubdate>17 March 2003</pubdate>
|
||||
</chapterinfo>
|
||||
|
||||
<title>Securing Samba</title>
|
||||
|
||||
<sect1>
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
This note was attached to the Samba 2.2.8 release notes as it contained an
|
||||
important security fix. The information contained here applies to Samba
|
||||
installations in general.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Using host based protection</title>
|
||||
|
||||
<para>
|
||||
In many installations of Samba the greatest threat comes for outside
|
||||
your immediate network. By default Samba will accept connections from
|
||||
any host, which means that if you run an insecure version of Samba on
|
||||
a host that is directly connected to the Internet you can be
|
||||
especially vulnerable.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
One of the simplest fixes in this case is to use the 'hosts allow' and
|
||||
'hosts deny' options in the Samba smb.conf configuration file to only
|
||||
allow access to your server from a specific range of hosts. An example
|
||||
might be:
|
||||
</para>
|
||||
|
||||
<para><programlisting>
|
||||
hosts allow = 127.0.0.1 192.168.2.0/24 192.168.3.0/24
|
||||
hosts deny = 0.0.0.0/0
|
||||
</programlisting></para>
|
||||
|
||||
<para>
|
||||
The above will only allow SMB connections from 'localhost' (your own
|
||||
computer) and from the two private networks 192.168.2 and
|
||||
192.168.3. All other connections will be refused connections as soon
|
||||
as the client sends its first packet. The refusal will be marked as a
|
||||
'not listening on called name' error.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
|
||||
<title>Using interface protection</title>
|
||||
|
||||
<para>
|
||||
By default Samba will accept connections on any network interface that
|
||||
it finds on your system. That means if you have a ISDN line or a PPP
|
||||
connection to the Internet then Samba will accept connections on those
|
||||
links. This may not be what you want.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You can change this behaviour using options like the following:
|
||||
</para>
|
||||
|
||||
<para><programlisting>
|
||||
interfaces = eth* lo
|
||||
bind interfaces only = yes
|
||||
</programlisting><para>
|
||||
|
||||
<para>
|
||||
This tells Samba to only listen for connections on interfaces with a
|
||||
name starting with 'eth' such as eth0, eth1, plus on the loopback
|
||||
interface called 'lo'. The name you will need to use depends on what
|
||||
OS you are using, in the above I used the common name for Ethernet
|
||||
adapters on Linux.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you use the above and someone tries to make a SMB connection to
|
||||
your host over a PPP interface called 'ppp0' then they will get a TCP
|
||||
connection refused reply. In that case no Samba code is run at all as
|
||||
the operating system has been told not to pass connections from that
|
||||
interface to any process.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Using a firewall</title>
|
||||
|
||||
<para>
|
||||
Many people use a firewall to deny access to services that they don't
|
||||
want exposed outside their network. This can be a very good idea,
|
||||
although I would recommend using it in conjunction with the above
|
||||
methods so that you are protected even if your firewall is not active
|
||||
for some reason.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you are setting up a firewall then you need to know what TCP and
|
||||
UDP ports to allow and block. Samba uses the following:
|
||||
</para>
|
||||
|
||||
<para><programlisting>
|
||||
UDP/137 - used by nmbd
|
||||
UDP/138 - used by nmbd
|
||||
TCP/139 - used by smbd
|
||||
TCP/445 - used by smbd
|
||||
</programlisting></para>
|
||||
|
||||
<para>
|
||||
The last one is important as many older firewall setups may not be
|
||||
aware of it, given that this port was only added to the protocol in
|
||||
recent years.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Using a IPC$ share deny</title>
|
||||
|
||||
<para>
|
||||
If the above methods are not suitable, then you could also place a
|
||||
more specific deny on the IPC$ share that is used in the recently
|
||||
discovered security hole. This allows you to offer access to other
|
||||
shares while denying access to IPC$ from potentially untrustworthy
|
||||
hosts.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To do that you could use:
|
||||
</para>
|
||||
|
||||
<para><programlisting>
|
||||
[ipc$]
|
||||
hosts allow = 192.168.115.0/24 127.0.0.1
|
||||
hosts deny = 0.0.0.0/0
|
||||
</programlisting></para>
|
||||
|
||||
<para>
|
||||
this would tell Samba that IPC$ connections are not allowed from
|
||||
anywhere but the two listed places (localhost and a local
|
||||
subnet). Connections to other shares would still be allowed. As the
|
||||
IPC$ share is the only share that is always accessible anonymously
|
||||
this provides some level of protection against attackers that do not
|
||||
know a username/password for your host.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you use this method then clients will be given a 'access denied'
|
||||
reply when they try to access the IPC$ share. That means that those
|
||||
clients will not be able to browse shares, and may also be unable to
|
||||
access some other resources.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is not recommended unless you cannot use one of the other
|
||||
methods listed above for some reason.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Upgrading Samba</title>
|
||||
|
||||
<para>
|
||||
Please check regularly on http://www.samba.org/ for updates and
|
||||
important announcements. Occasionally security releases are made and
|
||||
it is highly recommended to upgrade Samba when a security vulnerability
|
||||
is discovered.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
557
source3/client/mount.cifs.c
Executable file
557
source3/client/mount.cifs.c
Executable file
@ -0,0 +1,557 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <mntent.h>
|
||||
|
||||
#define MOUNT_CIFS_VERSION "1"
|
||||
|
||||
extern char *getusername(void);
|
||||
|
||||
char * thisprogram;
|
||||
int verboseflag = 0;
|
||||
static int got_password = 0;
|
||||
static int got_user = 0;
|
||||
static int got_domain = 0;
|
||||
static int got_ip = 0;
|
||||
static int got_unc = 0;
|
||||
static int got_uid = 0;
|
||||
static int got_gid = 0;
|
||||
static char * user_name = NULL;
|
||||
char * mountpassword = NULL;
|
||||
|
||||
|
||||
void mount_cifs_usage()
|
||||
{
|
||||
printf("\nUsage: %s remotetarget dir\n", thisprogram);
|
||||
printf("\nMount the remotetarget, specified as either a UNC name or ");
|
||||
printf(" CIFS URL, to the local directory, dir.\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* caller frees username if necessary */
|
||||
char * getusername() {
|
||||
char *username = NULL;
|
||||
struct passwd *password = getpwuid(getuid());
|
||||
|
||||
if (password) {
|
||||
username = password->pw_name;
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
char * parse_cifs_url(unc_name)
|
||||
{
|
||||
printf("\ncifs url %s\n",unc_name);
|
||||
}
|
||||
|
||||
int parse_options(char * options)
|
||||
{
|
||||
char * data;
|
||||
char * value = 0;
|
||||
|
||||
if (!options)
|
||||
return 1;
|
||||
|
||||
while ((data = strsep(&options, ",")) != NULL) {
|
||||
if (!*data)
|
||||
continue;
|
||||
if ((value = strchr(data, '=')) != NULL) {
|
||||
*value++ = '\0';
|
||||
}
|
||||
if (strncmp(data, "user", 4) == 0) {
|
||||
if (!value || !*value) {
|
||||
printf("invalid or missing username\n");
|
||||
return 1; /* needs_arg; */
|
||||
}
|
||||
if (strnlen(value, 260) < 260) {
|
||||
got_user=1;
|
||||
/* BB add check for format user%pass */
|
||||
/* if(strchr(username%passw) got_password = 1) */
|
||||
} else {
|
||||
printf("username too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (strncmp(data, "pass", 4) == 0) {
|
||||
if (!value || !*value) {
|
||||
if(got_password) {
|
||||
printf("password specified twice, ignoring second\n");
|
||||
} else
|
||||
got_password = 1;
|
||||
} else if (strnlen(value, 17) < 17) {
|
||||
got_password = 1;
|
||||
} else {
|
||||
printf("password too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (strncmp(data, "ip", 2) == 0) {
|
||||
if (!value || !*value) {
|
||||
printf("target ip address argument missing");
|
||||
} else if (strnlen(value, 35) < 35) {
|
||||
got_ip = 1;
|
||||
} else {
|
||||
printf("ip address too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if ((strncmp(data, "unc", 3) == 0)
|
||||
|| (strncmp(data, "target", 6) == 0)
|
||||
|| (strncmp(data, "path", 4) == 0)) {
|
||||
if (!value || !*value) {
|
||||
printf("invalid path to network resource\n");
|
||||
return 1; /* needs_arg; */
|
||||
} else if(strnlen(value,5) < 5) {
|
||||
printf("UNC name too short");
|
||||
}
|
||||
|
||||
if (strnlen(value, 300) < 300) {
|
||||
got_unc = 1;
|
||||
if (strncmp(value, "//", 2) == 0) {
|
||||
if(got_unc)
|
||||
printf("unc name specified twice, ignoring second\n");
|
||||
else
|
||||
got_unc = 1;
|
||||
} else if (strncmp(value, "\\\\", 2) != 0) {
|
||||
printf("UNC Path does not begin with // or \\\\ \n");
|
||||
return 1;
|
||||
} else {
|
||||
if(got_unc)
|
||||
printf("unc name specified twice, ignoring second\n");
|
||||
else
|
||||
got_unc = 1;
|
||||
}
|
||||
} else {
|
||||
printf("CIFS: UNC name too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if ((strncmp(data, "domain", 3) == 0)
|
||||
|| (strncmp(data, "workgroup", 5) == 0)) {
|
||||
if (!value || !*value) {
|
||||
printf("CIFS: invalid domain name\n");
|
||||
return 1; /* needs_arg; */
|
||||
}
|
||||
if (strnlen(value, 65) < 65) {
|
||||
got_domain = 1;
|
||||
} else {
|
||||
printf("domain name too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (strncmp(data, "uid", 3) == 0) {
|
||||
if (value && *value) {
|
||||
got_uid = 1;
|
||||
}
|
||||
} else if (strncmp(data, "gid", 3) == 0) {
|
||||
if (value && *value) {
|
||||
got_gid = 1;
|
||||
}
|
||||
} /* else if (strnicmp(data, "file_mode", 4) == 0) {
|
||||
if (value && *value) {
|
||||
vol->file_mode =
|
||||
simple_strtoul(value, &value, 0);
|
||||
}
|
||||
} else if (strnicmp(data, "dir_mode", 3) == 0) {
|
||||
if (value && *value) {
|
||||
vol->dir_mode =
|
||||
simple_strtoul(value, &value, 0);
|
||||
}
|
||||
} else if (strnicmp(data, "port", 4) == 0) {
|
||||
if (value && *value) {
|
||||
vol->port =
|
||||
simple_strtoul(value, &value, 0);
|
||||
}
|
||||
} else if (strnicmp(data, "rsize", 5) == 0) {
|
||||
if (value && *value) {
|
||||
vol->rsize =
|
||||
simple_strtoul(value, &value, 0);
|
||||
}
|
||||
} else if (strnicmp(data, "wsize", 5) == 0) {
|
||||
if (value && *value) {
|
||||
vol->wsize =
|
||||
simple_strtoul(value, &value, 0);
|
||||
}
|
||||
} else if (strnicmp(data, "version", 3) == 0) {
|
||||
|
||||
} else if (strnicmp(data, "rw", 2) == 0) {
|
||||
|
||||
} else
|
||||
printf("CIFS: Unknown mount option %s\n",data); */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note that caller frees the returned buffer if necessary */
|
||||
char * parse_server(char * unc_name)
|
||||
{
|
||||
int length = strnlen(unc_name,1024);
|
||||
char * share;
|
||||
char * ipaddress_string = NULL;
|
||||
struct hostent * host_entry;
|
||||
struct in_addr server_ipaddr;
|
||||
int rc,j;
|
||||
char temp[64];
|
||||
|
||||
if(length > 1023) {
|
||||
printf("mount error: UNC name too long");
|
||||
return 0;
|
||||
}
|
||||
if (strncasecmp("cifs://",unc_name,7) == 0)
|
||||
return parse_cifs_url(unc_name+7);
|
||||
if (strncasecmp("smb://",unc_name,6) == 0) {
|
||||
return parse_cifs_url(unc_name+6);
|
||||
}
|
||||
|
||||
if(length < 3) {
|
||||
/* BB add code to find DFS root here */
|
||||
printf("\nMounting the DFS root for domain not implemented yet");
|
||||
return 0;
|
||||
} else {
|
||||
/* BB add support for \\\\ not just // */
|
||||
if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
|
||||
printf("mount error: improperly formatted UNC name.");
|
||||
printf(" %s does not begin with \\\\ or //\n",unc_name);
|
||||
return 0;
|
||||
} else {
|
||||
unc_name[0] = '\\';
|
||||
unc_name[1] = '\\';
|
||||
unc_name += 2;
|
||||
if ((share = strchr(unc_name, '/')) ||
|
||||
(share = strchr(unc_name,'\\'))) {
|
||||
*share = 0; /* temporarily terminate the string */
|
||||
share += 1;
|
||||
host_entry = gethostbyname(unc_name);
|
||||
*(share - 1) = '\\'; /* put the slash back */
|
||||
/* rc = getipnodebyname(unc_name, AF_INET, AT_ADDRCONFIG ,&rc);*/
|
||||
if(host_entry == NULL) {
|
||||
printf("mount error: could not find target server. TCP name %s not found ", unc_name);
|
||||
printf(" rc = %d\n",rc);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* BB should we pass an alternate version of the share name as Unicode */
|
||||
/* BB what about ipv6? BB */
|
||||
/* BB add retries with alternate servers in list */
|
||||
|
||||
memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
|
||||
|
||||
ipaddress_string = inet_ntoa(server_ipaddr);
|
||||
if(ipaddress_string == NULL) {
|
||||
printf("mount error: could not get valid ip address for target server\n");
|
||||
return 0;
|
||||
}
|
||||
return ipaddress_string;
|
||||
}
|
||||
} else {
|
||||
/* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
|
||||
printf("Mounting the DFS root for a particular server not implemented yet\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct option longopts[] = {
|
||||
{ "all", 0, 0, 'a' },
|
||||
{ "help", 0, 0, 'h' },
|
||||
{ "read-only", 0, 0, 'r' },
|
||||
{ "ro", 0, 0, 'r' },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
{ "read-write", 0, 0, 'w' },
|
||||
{ "rw", 0, 0, 'w' },
|
||||
{ "options", 1, 0, 'o' },
|
||||
{ "types", 1, 0, 't' },
|
||||
{ "replace", 0, 0, 129 },
|
||||
{ "after", 0, 0, 130 },
|
||||
{ "before", 0, 0, 131 },
|
||||
{ "over", 0, 0, 132 },
|
||||
{ "move", 0, 0, 133 },
|
||||
{ "rsize",1, 0, 136 },
|
||||
{ "wsize",1, 0, 137 },
|
||||
{ "uid", 1, 0, 138},
|
||||
{ "gid", 1, 0, 139},
|
||||
{ "uuid",1,0,'U' },
|
||||
{ "user",1,0,140},
|
||||
{ "username",1,0,140},
|
||||
{ "dom",1,0,141},
|
||||
{ "domain",1,0,141},
|
||||
{ "password",1,0,142},
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
int c;
|
||||
int flags = MS_MANDLOCK | MS_MGC_VAL;
|
||||
char * orgoptions = NULL;
|
||||
char * share_name = NULL;
|
||||
char * domain_name = NULL;
|
||||
char * ipaddr = NULL;
|
||||
char * uuid = NULL;
|
||||
char * mountpoint;
|
||||
char * options;
|
||||
int rc,i;
|
||||
int rsize = 0;
|
||||
int wsize = 0;
|
||||
int nomtab = 0;
|
||||
int uid = 0;
|
||||
int gid = 0;
|
||||
int optlen = 0;
|
||||
struct stat statbuf;
|
||||
struct utsname sysinfo;
|
||||
struct mntent mountent;
|
||||
FILE * pmntfile;
|
||||
|
||||
/* setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE); */
|
||||
|
||||
if(argc && argv) {
|
||||
thisprogram = argv[0];
|
||||
}
|
||||
if(thisprogram == NULL)
|
||||
thisprogram = "mount.cifs";
|
||||
|
||||
uname(&sysinfo);
|
||||
/* BB add workstation name and domain and pass down */
|
||||
/*#ifdef _GNU_SOURCE
|
||||
printf(" node: %s machine: %s\n", sysinfo.nodename,sysinfo.machine);
|
||||
#endif*/
|
||||
if(argc < 3)
|
||||
mount_cifs_usage();
|
||||
share_name = argv[1];
|
||||
mountpoint = argv[2];
|
||||
/* add sharename in opts string as unc= parm */
|
||||
|
||||
while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:",
|
||||
longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
/* case 'a':
|
||||
++mount_all;
|
||||
break;
|
||||
case 'f':
|
||||
++fake;
|
||||
break;
|
||||
case 'F':
|
||||
++optfork;
|
||||
break; */
|
||||
case 'h': /* help */
|
||||
mount_cifs_usage ();
|
||||
break;
|
||||
/* case 'i':
|
||||
external_allowed = 0;
|
||||
break;
|
||||
case 'l':
|
||||
list_with_volumelabel = 1;
|
||||
break;
|
||||
case 'L':
|
||||
volumelabel = optarg;
|
||||
break; */
|
||||
case 'n':
|
||||
++nomtab;
|
||||
break;
|
||||
case 'o':
|
||||
if (orgoptions) {
|
||||
orgoptions = strcat(orgoptions, ",");
|
||||
orgoptions = strcat(orgoptions,optarg);
|
||||
} else
|
||||
orgoptions = strdup(optarg);
|
||||
break;
|
||||
|
||||
/* case 'O':
|
||||
if (test_opts)
|
||||
test_opts = xstrconcat3(test_opts, ",", optarg);
|
||||
else
|
||||
test_opts = xstrdup(optarg);
|
||||
break;*/
|
||||
case 'r': /* mount readonly */
|
||||
flags |= MS_RDONLY;;
|
||||
break;
|
||||
case 'U':
|
||||
uuid = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
++verboseflag;
|
||||
break;
|
||||
/* case 'V':
|
||||
printf ("mount: %s\n", version);
|
||||
exit (0);*/
|
||||
case 'w':
|
||||
flags &= ~MS_RDONLY;;
|
||||
break;
|
||||
/* case 0:
|
||||
break;
|
||||
|
||||
case 128:
|
||||
mounttype = MS_BIND;
|
||||
break;
|
||||
case 129:
|
||||
mounttype = MS_REPLACE;
|
||||
break;
|
||||
case 130:
|
||||
mounttype = MS_AFTER;
|
||||
break;
|
||||
case 131:
|
||||
mounttype = MS_BEFORE;
|
||||
break;
|
||||
case 132:
|
||||
mounttype = MS_OVER;
|
||||
break;
|
||||
case 133:
|
||||
mounttype = MS_MOVE;
|
||||
break;
|
||||
case 135:
|
||||
mounttype = (MS_BIND | MS_REC);
|
||||
break; */
|
||||
case 136:
|
||||
rsize = atoi(optarg) ;
|
||||
break;
|
||||
case 137:
|
||||
wsize = atoi(optarg);
|
||||
break;
|
||||
case 138:
|
||||
uid = atoi(optarg);
|
||||
break;
|
||||
case 139:
|
||||
gid = atoi(optarg);
|
||||
break;
|
||||
case 140:
|
||||
got_user = 1;
|
||||
user_name = optarg;
|
||||
break;
|
||||
case 141:
|
||||
domain_name = optarg;
|
||||
break;
|
||||
case 142:
|
||||
got_password = 1;
|
||||
mountpassword = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
mount_cifs_usage ();
|
||||
}
|
||||
}
|
||||
|
||||
/* canonicalize the path in argv[1]? */
|
||||
|
||||
if(stat (mountpoint, &statbuf)) {
|
||||
printf("mount error: mount point %s does not exist\n",mountpoint);
|
||||
return -1;
|
||||
}
|
||||
if (S_ISDIR(statbuf.st_mode) == 0) {
|
||||
printf("mount error: mount point %s is not a directory\n",mountpoint);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(geteuid()) {
|
||||
printf("mount error: permission denied, not superuser and cifs.mount not installed SUID\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipaddr = parse_server(share_name);
|
||||
/* if(share_name == NULL)
|
||||
return 1; */
|
||||
if (parse_options(strdup(orgoptions)))
|
||||
return 1;
|
||||
|
||||
if(got_user == 0)
|
||||
user_name = getusername();
|
||||
|
||||
/* check username for user%password format */
|
||||
|
||||
if(got_password == 0) {
|
||||
if (getenv("PASSWD")) {
|
||||
mountpassword = malloc(33);
|
||||
if(mountpassword) {
|
||||
strncpy(mountpassword,getenv("PASSWD"),32);
|
||||
got_password = 1;
|
||||
}
|
||||
/* } else if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
|
||||
get_password_file();
|
||||
got_password = 1;*/ /* BB add missing function */
|
||||
} else {
|
||||
mountpassword = getpass("Password: "); /* BB obsolete */
|
||||
got_password = 1;
|
||||
}
|
||||
}
|
||||
/* FIXME launch daemon (handles dfs name resolution and credential change)
|
||||
remember to clear parms and overwrite password field before launching */
|
||||
if(orgoptions) {
|
||||
optlen = strlen(orgoptions);
|
||||
} else
|
||||
optlen = 0;
|
||||
if(share_name)
|
||||
optlen += strlen(share_name) + 4;
|
||||
if(user_name)
|
||||
optlen += strlen(user_name) + 6;
|
||||
if(ipaddr)
|
||||
optlen += strlen(ipaddr) + 4;
|
||||
if(mountpassword)
|
||||
optlen += strlen(mountpassword) + 6;
|
||||
options = malloc(optlen + 10);
|
||||
|
||||
options[0] = 0;
|
||||
strncat(options,"unc=",4);
|
||||
strcat(options,share_name);
|
||||
if(ipaddr) {
|
||||
strncat(options,",ip=",4);
|
||||
strcat(options,ipaddr);
|
||||
}
|
||||
if(user_name) {
|
||||
strncat(options,",user=",6);
|
||||
strcat(options,user_name);
|
||||
}
|
||||
if(mountpassword) {
|
||||
strncat(options,",pass=",6);
|
||||
strcat(options,mountpassword);
|
||||
}
|
||||
strncat(options,",ver=",5);
|
||||
strcat(options,MOUNT_CIFS_VERSION);
|
||||
|
||||
if(orgoptions) {
|
||||
strcat(options,",");
|
||||
strcat(options,orgoptions);
|
||||
}
|
||||
/* printf("\noptions %s \n",options);*/
|
||||
if(mount(share_name, mountpoint, "cifs", flags, options)) {
|
||||
/* remember to kill daemon on error */
|
||||
switch (errno) {
|
||||
case 0:
|
||||
printf("mount failed but no error number set\n");
|
||||
return 0;
|
||||
case ENODEV:
|
||||
printf("mount error: cifs filesystem not supported by the system\n");
|
||||
break;
|
||||
default:
|
||||
printf("mount error %d = %s",errno,strerror(errno));
|
||||
}
|
||||
printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
|
||||
return -1;
|
||||
} else {
|
||||
pmntfile = setmntent(MOUNTED, "a+");
|
||||
if(pmntfile) {
|
||||
mountent.mnt_fsname = share_name;
|
||||
mountent.mnt_dir = mountpoint;
|
||||
mountent.mnt_type = "cifs";
|
||||
mountent.mnt_opts = "";
|
||||
mountent.mnt_freq = 0;
|
||||
mountent.mnt_passno = 0;
|
||||
rc = addmntent(pmntfile,&mountent);
|
||||
endmntent(pmntfile);
|
||||
} else {
|
||||
printf("could not update mount table\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
36
source3/include/srvstr.h
Normal file
36
source3/include/srvstr.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
server specific string routines
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define srvstr_push(base_ptr, dest, src, dest_len, flags) \
|
||||
push_string(base_ptr, dest, src, dest_len, flags)
|
||||
|
||||
#define srvstr_pull(base_ptr, dest, src, dest_len, src_len, flags) \
|
||||
pull_string(base_ptr, dest, src, dest_len, src_len, flags)
|
||||
|
||||
/* pull a string from the smb_buf part of a packet. In this case the
|
||||
string can either be null terminated or it can be terminated by the
|
||||
end of the smbbuf area
|
||||
*/
|
||||
|
||||
#define srvstr_pull_buf(inbuf, dest, src, dest_len, flags) \
|
||||
pull_string(inbuf, dest, src, dest_len, smb_bufrem(inbuf, src), flags)
|
||||
|
60
source3/lib/clobber.c
Normal file
60
source3/lib/clobber.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
Copyright (C) Martin Pool 2003
|
||||
Copyright (C) Andrew Bartlett 2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef DEVELOPER
|
||||
const char *global_clobber_region_function;
|
||||
unsigned int global_clobber_region_line;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* In developer builds, clobber a region of memory.
|
||||
*
|
||||
* If we think a string buffer is longer than it really is, this ought
|
||||
* to make the failure obvious, by segfaulting (if in the heap) or by
|
||||
* killing the return address (on the stack), or by trapping under a
|
||||
* memory debugger.
|
||||
*
|
||||
* This is meant to catch possible string overflows, even if the
|
||||
* actual string copied is not big enough to cause an overflow.
|
||||
*
|
||||
* In addition, under Valgrind the buffer is marked as uninitialized.
|
||||
**/
|
||||
void clobber_region(const char *fn, unsigned int line, char *dest, size_t len)
|
||||
{
|
||||
#ifdef DEVELOPER
|
||||
global_clobber_region_function = fn;
|
||||
global_clobber_region_line = line;
|
||||
|
||||
/* F1 is odd and 0xf1f1f1f1 shouldn't be a valid pointer */
|
||||
memset(dest, 0xF1, len);
|
||||
#ifdef VALGRIND
|
||||
/* Even though we just wrote to this, from the application's
|
||||
* point of view it is not initialized.
|
||||
*
|
||||
* (This is not redundant with the clobbering above. The
|
||||
* marking might not actually take effect if we're not running
|
||||
* under valgrind.) */
|
||||
VALGRIND_MAKE_WRITABLE(dest, len);
|
||||
#endif /* VALGRIND */
|
||||
#endif /* DEVELOPER */
|
||||
}
|
208
source3/libsmb/ntlmssp_sign.c
Normal file
208
source3/libsmb/ntlmssp_sign.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
* Version 3.0
|
||||
* NTLMSSP Signing routines
|
||||
* Copyright (C) Luke Kenneth Casson Leighton 1996-2001
|
||||
* Copyright (C) Andrew Bartlett 2003
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define CLI_SIGN "session key to client-to-server signing key magic constant"
|
||||
#define CLI_SEAL "session key to client-to-server sealing key magic constant"
|
||||
#define SRV_SIGN "session key to server-to-client signing key magic constant"
|
||||
#define SRV_SEAL "session key to server-to-client sealing key magic constant"
|
||||
|
||||
static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len)
|
||||
{
|
||||
unsigned char index_i = hash[256];
|
||||
unsigned char index_j = hash[257];
|
||||
int ind;
|
||||
|
||||
for (ind = 0; ind < len; ind++)
|
||||
{
|
||||
unsigned char tc;
|
||||
unsigned char t;
|
||||
|
||||
index_i++;
|
||||
index_j += hash[index_i];
|
||||
|
||||
tc = hash[index_i];
|
||||
hash[index_i] = hash[index_j];
|
||||
hash[index_j] = tc;
|
||||
|
||||
t = hash[index_i] + hash[index_j];
|
||||
data[ind] = data[ind] ^ hash[t];
|
||||
}
|
||||
|
||||
hash[256] = index_i;
|
||||
hash[257] = index_j;
|
||||
}
|
||||
|
||||
static void calc_hash(unsigned char *hash, const char *k2, int k2l)
|
||||
{
|
||||
unsigned char j = 0;
|
||||
int ind;
|
||||
|
||||
for (ind = 0; ind < 256; ind++)
|
||||
{
|
||||
hash[ind] = (unsigned char)ind;
|
||||
}
|
||||
|
||||
for (ind = 0; ind < 256; ind++)
|
||||
{
|
||||
unsigned char tc;
|
||||
|
||||
j += (hash[ind] + k2[ind%k2l]);
|
||||
|
||||
tc = hash[ind];
|
||||
hash[ind] = hash[j];
|
||||
hash[j] = tc;
|
||||
}
|
||||
|
||||
hash[256] = 0;
|
||||
hash[257] = 0;
|
||||
}
|
||||
|
||||
static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
|
||||
const char encrypted_response[16],
|
||||
const char *constant)
|
||||
{
|
||||
struct MD5Context ctx3;
|
||||
|
||||
MD5Init(&ctx3);
|
||||
MD5Update(&ctx3, encrypted_response, 5);
|
||||
MD5Update(&ctx3, constant, strlen(constant));
|
||||
MD5Final(digest, &ctx3);
|
||||
|
||||
calc_hash(hash, digest, 16);
|
||||
}
|
||||
|
||||
static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_state,
|
||||
const uchar *data, size_t length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
|
||||
HMACMD5Context ctx;
|
||||
char seq_num[4];
|
||||
uchar digest[16];
|
||||
SIVAL(seq_num, 0, &ntlmssp_state->ntlmssp_seq_num);
|
||||
|
||||
hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
|
||||
hmac_md5_update(seq_num, 4, &ctx);
|
||||
hmac_md5_update(data, length, &ctx);
|
||||
hmac_md5_final(digest, &ctx);
|
||||
|
||||
if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, sig->data, sig->length);
|
||||
} else {
|
||||
uint32 crc;
|
||||
crc = crc32_calc_buffer(data, length);
|
||||
if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
|
||||
const uchar *data, size_t length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
ntlmssp_state->ntlmssp_seq_num++;
|
||||
return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, sig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the signature of an incoming packet
|
||||
* @note caller *must* check that the signature is the size it expects
|
||||
*
|
||||
*/
|
||||
|
||||
NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
|
||||
const uchar *data, size_t length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
DATA_BLOB local_sig;
|
||||
NTSTATUS nt_status;
|
||||
|
||||
if (sig->length < 8) {
|
||||
DEBUG(0, ("NTLMSSP packet check failed due to short signiture (%u bytes)!\n",
|
||||
sig->length));
|
||||
}
|
||||
|
||||
nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data,
|
||||
length, &local_sig);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
|
||||
return NT_STATUS_OK;
|
||||
} else {
|
||||
DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialise the state for NTLMSSP signing.
|
||||
*/
|
||||
NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
|
||||
{
|
||||
unsigned char p24[24];
|
||||
unsigned char lm_hash[16];
|
||||
|
||||
if (!ntlmssp_state->lm_resp.data) {
|
||||
/* can't sign or check signitures yet */
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
E_deshash(ntlmssp_state->password, lm_hash);
|
||||
|
||||
NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
|
||||
|
||||
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
|
||||
{
|
||||
calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
|
||||
calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
|
||||
calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
|
||||
calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
char k2[8];
|
||||
memcpy(k2, p24, 5);
|
||||
k2[5] = 0xe5;
|
||||
k2[6] = 0x38;
|
||||
k2[7] = 0xb0;
|
||||
|
||||
calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
|
||||
}
|
||||
|
||||
ntlmssp_state->ntlmssp_seq_num = 0;
|
||||
|
||||
ZERO_STRUCT(lm_hash);
|
||||
return NT_STATUS_OK;
|
||||
}
|
461
source3/libsmb/smb_signing.c
Normal file
461
source3/libsmb/smb_signing.c
Normal file
@ -0,0 +1,461 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB Signing Code
|
||||
Copyright (C) Jeremy Allison 2002.
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct smb_basic_signing_context {
|
||||
DATA_BLOB mac_key;
|
||||
uint32 send_seq_num;
|
||||
uint32 reply_seq_num;
|
||||
};
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Common code before we set a new signing implementation
|
||||
************************************************************/
|
||||
|
||||
static BOOL set_smb_signing_common(struct cli_state *cli)
|
||||
{
|
||||
if (!cli->sign_info.negotiated_smb_signing
|
||||
&& !cli->sign_info.mandetory_signing) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (cli->sign_info.doing_signing) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (cli->sign_info.free_signing_context)
|
||||
cli->sign_info.free_signing_context(cli);
|
||||
|
||||
/* These calls are INCOMPATIBLE with SMB signing */
|
||||
cli->readbraw_supported = False;
|
||||
cli->writebraw_supported = False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Common code for 'real' implementations
|
||||
************************************************************/
|
||||
|
||||
static BOOL set_smb_signing_real_common(struct cli_state *cli)
|
||||
{
|
||||
if (cli->sign_info.mandetory_signing) {
|
||||
DEBUG(5, ("Mandatory SMB signing enabled!\n"));
|
||||
cli->sign_info.doing_signing = True;
|
||||
}
|
||||
|
||||
DEBUG(5, ("SMB signing enabled!\n"));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static void mark_packet_signed(struct cli_state *cli)
|
||||
{
|
||||
uint16 flags2;
|
||||
flags2 = SVAL(cli->outbuf,smb_flg2);
|
||||
flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
|
||||
SSVAL(cli->outbuf,smb_flg2, flags2);
|
||||
}
|
||||
|
||||
static BOOL signing_good(struct cli_state *cli, BOOL good)
|
||||
{
|
||||
DEBUG(10, ("got SMB signature of\n"));
|
||||
dump_data(10,&cli->outbuf[smb_ss_field] , 8);
|
||||
|
||||
if (good && !cli->sign_info.doing_signing) {
|
||||
cli->sign_info.doing_signing = True;
|
||||
}
|
||||
|
||||
if (!good) {
|
||||
if (cli->sign_info.doing_signing) {
|
||||
DEBUG(1, ("SMB signature check failed!\n"));
|
||||
return False;
|
||||
} else {
|
||||
DEBUG(3, ("Server did not sign reply correctly\n"));
|
||||
cli_free_signing_context(cli);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void cli_simple_sign_outgoing_message(struct cli_state *cli)
|
||||
{
|
||||
unsigned char calc_md5_mac[16];
|
||||
struct MD5Context md5_ctx;
|
||||
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
|
||||
|
||||
/*
|
||||
* Firstly put the sequence number into the first 4 bytes.
|
||||
* and zero out the next 4 bytes.
|
||||
*/
|
||||
SIVAL(cli->outbuf, smb_ss_field,
|
||||
data->send_seq_num);
|
||||
SIVAL(cli->outbuf, smb_ss_field + 4, 0);
|
||||
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(cli);
|
||||
|
||||
/* Calculate the 16 byte MAC and place first 8 bytes into the field. */
|
||||
MD5Init(&md5_ctx);
|
||||
MD5Update(&md5_ctx, data->mac_key.data,
|
||||
data->mac_key.length);
|
||||
MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
|
||||
MD5Final(calc_md5_mac, &md5_ctx);
|
||||
|
||||
DEBUG(10, ("sent SMB signature of\n"));
|
||||
dump_data(10, calc_md5_mac, 8);
|
||||
|
||||
memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
|
||||
|
||||
/* cli->outbuf[smb_ss_field+2]=0;
|
||||
Uncomment this to test if the remote server actually verifies signitures...*/
|
||||
data->send_seq_num++;
|
||||
data->reply_seq_num = data->send_seq_num;
|
||||
data->send_seq_num++;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
|
||||
{
|
||||
BOOL good;
|
||||
unsigned char calc_md5_mac[16];
|
||||
unsigned char server_sent_mac[8];
|
||||
struct MD5Context md5_ctx;
|
||||
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
|
||||
|
||||
/*
|
||||
* Firstly put the sequence number into the first 4 bytes.
|
||||
* and zero out the next 4 bytes.
|
||||
*/
|
||||
|
||||
memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
|
||||
|
||||
DEBUG(10, ("got SMB signature of\n"));
|
||||
dump_data(10, server_sent_mac, 8);
|
||||
|
||||
SIVAL(cli->inbuf, smb_ss_field, data->reply_seq_num);
|
||||
SIVAL(cli->inbuf, smb_ss_field + 4, 0);
|
||||
|
||||
/* Calculate the 16 byte MAC and place first 8 bytes into the field. */
|
||||
MD5Init(&md5_ctx);
|
||||
MD5Update(&md5_ctx, data->mac_key.data,
|
||||
data->mac_key.length);
|
||||
MD5Update(&md5_ctx, cli->inbuf + 4, smb_len(cli->inbuf));
|
||||
MD5Final(calc_md5_mac, &md5_ctx);
|
||||
|
||||
good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
|
||||
|
||||
return signing_good(cli, good);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_simple_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
|
||||
|
||||
data_blob_free(&data->mac_key);
|
||||
SAFE_FREE(cli->sign_info.signing_context);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
|
||||
BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
|
||||
{
|
||||
struct smb_basic_signing_context *data;
|
||||
|
||||
if (!set_smb_signing_common(cli)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!set_smb_signing_real_common(cli)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
data = smb_xmalloc(sizeof(*data));
|
||||
cli->sign_info.signing_context = data;
|
||||
|
||||
data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
|
||||
|
||||
memcpy(&data->mac_key.data[0], user_session_key, 16);
|
||||
memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
|
||||
|
||||
/* Initialize the sequence number */
|
||||
data->send_seq_num = 0;
|
||||
|
||||
cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
|
||||
cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
|
||||
cli->sign_info.free_signing_context = cli_simple_free_signing_context;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NTLMSSP implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
DATA_BLOB sig;
|
||||
NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
|
||||
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(cli);
|
||||
|
||||
nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4,
|
||||
smb_len(cli->outbuf), &sig);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(10, ("sent SMB signature of\n"));
|
||||
dump_data(10, sig.data, MIN(sig.length, 8));
|
||||
memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
|
||||
|
||||
data_blob_free(&sig);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NTLMSSP implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
|
||||
{
|
||||
BOOL good;
|
||||
NTSTATUS nt_status;
|
||||
DATA_BLOB sig = data_blob(&cli->outbuf[smb_ss_field], 8);
|
||||
|
||||
NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
|
||||
|
||||
nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4,
|
||||
smb_len(cli->outbuf), &sig);
|
||||
|
||||
data_blob_free(&sig);
|
||||
|
||||
good = NT_STATUS_IS_OK(nt_status);
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
|
||||
}
|
||||
|
||||
return signing_good(cli, good);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NTLMSSP implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NTLMSSP implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
|
||||
BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
|
||||
NTLMSSP_CLIENT_STATE *ntlmssp_state)
|
||||
{
|
||||
if (!set_smb_signing_common(cli)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!set_smb_signing_real_common(cli)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
cli->sign_info.signing_context = ntlmssp_state;
|
||||
ntlmssp_state->ref_count++;
|
||||
|
||||
cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
|
||||
cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
|
||||
cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void cli_null_sign_outgoing_message(struct cli_state *cli)
|
||||
{
|
||||
/* we can't zero out the sig, as we might be trying to send a
|
||||
session request - which is NBT-level, not SMB level and doesn't
|
||||
have the field */
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_null_check_incoming_message(struct cli_state *cli)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_null_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
SMB signing - NULL implementation - setup the MAC key.
|
||||
|
||||
@note Used as an initialisation only - it will not correctly
|
||||
shut down a real signing mechinism
|
||||
*/
|
||||
|
||||
BOOL cli_null_set_signing(struct cli_state *cli)
|
||||
{
|
||||
struct smb_basic_sign_data *data;
|
||||
|
||||
cli->sign_info.signing_context = NULL;
|
||||
|
||||
cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
|
||||
cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
|
||||
cli->sign_info.free_signing_context = cli_null_free_signing_context;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - TEMP implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void cli_temp_sign_outgoing_message(struct cli_state *cli)
|
||||
{
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(cli);
|
||||
|
||||
/* I wonder what BSRSPYL stands for - but this is what MS
|
||||
actually sends! */
|
||||
memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - TEMP implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - TEMP implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_temp_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
|
||||
BOOL cli_temp_set_signing(struct cli_state *cli)
|
||||
{
|
||||
if (!set_smb_signing_common(cli)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
cli->sign_info.signing_context = NULL;
|
||||
|
||||
cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
|
||||
cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
|
||||
cli->sign_info.free_signing_context = cli_temp_free_signing_context;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the signing context
|
||||
*/
|
||||
|
||||
void cli_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
if (cli->sign_info.free_signing_context)
|
||||
cli->sign_info.free_signing_context(cli);
|
||||
|
||||
cli_null_set_signing(cli);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a packet with the current mechanism
|
||||
*/
|
||||
|
||||
void cli_caclulate_sign_mac(struct cli_state *cli)
|
||||
{
|
||||
cli->sign_info.sign_outgoing_message(cli);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a packet with the current mechanism
|
||||
* @return False if we had an established signing connection
|
||||
* which had a back checksum, True otherwise
|
||||
*/
|
||||
|
||||
BOOL cli_check_sign_mac(struct cli_state *cli)
|
||||
{
|
||||
BOOL good;
|
||||
good = cli->sign_info.check_incoming_message(cli);
|
||||
|
||||
if (!good) {
|
||||
if (cli->sign_info.doing_signing) {
|
||||
return False;
|
||||
} else {
|
||||
cli_free_signing_context(cli);
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
3
source3/rpc_client/.cvsignore
Normal file
3
source3/rpc_client/.cvsignore
Normal file
@ -0,0 +1,3 @@
|
||||
*.po
|
||||
*.po32
|
||||
|
1
source3/stf/.cvsignore
Normal file
1
source3/stf/.cvsignore
Normal file
@ -0,0 +1 @@
|
||||
*.pyc
|
3
source3/stf/README.stf
Normal file
3
source3/stf/README.stf
Normal file
@ -0,0 +1,3 @@
|
||||
This directory contains the Samba Testing Framework, a Python-based
|
||||
system for exercising Samba in various ways. It is quite small at the
|
||||
moment.
|
54
source3/stf/info3cache.py
Executable file
54
source3/stf/info3cache.py
Executable file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Upon a winbindd authentication, test that an info3 record is cached in
|
||||
# netsamlogon_cache.tdb and cache records are removed from winbindd_cache.tdb
|
||||
#
|
||||
|
||||
import comfychair, stf
|
||||
from samba import tdb, winbind
|
||||
|
||||
#
|
||||
# We want to implement the following test on a win2k native mode domain.
|
||||
#
|
||||
# 1. trash netsamlogon_cache.tdb
|
||||
# 2. wbinfo -r DOMAIN\Administrator [FAIL]
|
||||
# 3. wbinfo --auth-crap DOMAIN\Administrator%password [PASS]
|
||||
# 4. wbinfo -r DOMAIN\Administrator [PASS]
|
||||
#
|
||||
# Also for step 3 we want to try 'wbinfo --auth-smbd' and
|
||||
# 'wbinfo --auth-plaintext'
|
||||
#
|
||||
|
||||
#
|
||||
# TODO: To implement this test we need to be able to
|
||||
#
|
||||
# - pass username%password combination for an invidivual winbindd request
|
||||
# (so we can get the administrator SID so we can clear the info3 cache)
|
||||
#
|
||||
# - start/restart winbindd (to trash the winbind cache)
|
||||
#
|
||||
# - from samba import dynconfig (to find location of info3 cache)
|
||||
#
|
||||
# - be able to modify the winbindd cache (to set/reset individual winbind
|
||||
# cache entries)
|
||||
#
|
||||
# - have --auth-crap present in HEAD
|
||||
#
|
||||
|
||||
class WinbindAuthCrap(comfychair.TestCase):
|
||||
def runtest(self):
|
||||
raise comfychair.NotRunError, "not implemented"
|
||||
|
||||
class WinbindAuthSmbd(comfychair.TestCase):
|
||||
def runtest(self):
|
||||
# Grr - winbindd in HEAD doesn't contain the auth_smbd function
|
||||
raise comfychair.NotRunError, "no auth_smbd in HEAD"
|
||||
|
||||
class WinbindAuthPlaintext(comfychair.TestCase):
|
||||
def runtest(self):
|
||||
raise comfychair.NotRunError, "not implemented"
|
||||
|
||||
tests = [WinbindAuthCrap, WinbindAuthSmbd, WinbindAuthPlaintext]
|
||||
|
||||
if __name__ == "__main__":
|
||||
comfychair.main(tests)
|
175
source3/stf/notes.txt
Normal file
175
source3/stf/notes.txt
Normal file
@ -0,0 +1,175 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
(set lotus no)
|
||||
|
||||
|
||||
|
||||
Notes on using comfychair with Samba (samba testing framework units):
|
||||
|
||||
The tests need to rely on some external resources, such as
|
||||
|
||||
If suitable resources are not available, need to skip particular
|
||||
tests. Must include a message indicating what resources would be
|
||||
needed to run that test. (e.g. must be root.)
|
||||
|
||||
We want to be able to select and run particular subsets of tests, such
|
||||
as "all winbind tests".
|
||||
|
||||
We want to keep the number of configurable parameters down as much as
|
||||
possible, to make it easy on people running the tests.
|
||||
|
||||
Wherever possible, the tests should set up their preconditions, but a
|
||||
few basic resources need to be provided by the people running the
|
||||
tests. So for example, rather than asking the user for the name of a
|
||||
non-root user, we should give the tests the administrator name and
|
||||
password, and it can create a new user to use.
|
||||
|
||||
This makes it simpler to get the tests running, and possible also
|
||||
makes them more reproducible.
|
||||
|
||||
In the future, rather than using NT machines provided by the test
|
||||
person, we might have a way to drive VMWare non-persistent sessions,
|
||||
to make tests even more tightly controlled.
|
||||
|
||||
|
||||
Another design question is how to communicate this information to the
|
||||
tests. If there's a lot of settings, then it might need to be stored
|
||||
in a configuration file.
|
||||
|
||||
However, if we succeed in cutting down the number of parameters, then
|
||||
it might be straightforward to pass the information on the command
|
||||
line or in an environment variable.
|
||||
|
||||
Environment variables are probably better because they can't be seen
|
||||
by other users, and they are more easily passed down through an
|
||||
invocation of "make check".
|
||||
|
||||
|
||||
|
||||
Notes on Samba Testing Framework for Unittests
|
||||
----------------------------------------------
|
||||
|
||||
This is to be read after reading the notes.txt from comfychair. I'm
|
||||
proposing a slightly more concrete description of what's described
|
||||
there.
|
||||
|
||||
The model of having tests require named resources looks useful for
|
||||
incorporation into a framework that can be run by many people in
|
||||
widely different environments.
|
||||
|
||||
Some possible environments for running the test framework in are:
|
||||
|
||||
- Casual downloader of Samba compiling from source and just wants
|
||||
to run 'make check'. May only have one Unix machine and a
|
||||
handful of clients.
|
||||
|
||||
- Samba team member with access to a small number of other
|
||||
machines or VMware sessions.
|
||||
|
||||
- PSA developer who may not have intimate knowledge of Samba
|
||||
internals and is only interested in testing against the PSA.
|
||||
|
||||
- Non-team hacker wanting to run test suite after making small
|
||||
hacks.
|
||||
|
||||
- Build farm environment (loaner machine with no physical access
|
||||
or root privilege).
|
||||
|
||||
- HP BAT.
|
||||
|
||||
Developers in most of these environments are also potential test case
|
||||
authors. It should be easy for people unfamiliar with the framework
|
||||
to write new tests and have them work. We should provide examples and
|
||||
the existing tests should well written and understandable.
|
||||
|
||||
Different types of tests:
|
||||
|
||||
- Tests that check Samba internals and link against
|
||||
libbigballofmud.so. For example:
|
||||
|
||||
- Upper/lowercase string functions
|
||||
- user_in_list() for large lists
|
||||
|
||||
- Tests that use the Samba Python extensions.
|
||||
|
||||
- Tests that execute Samba command line programs, for example
|
||||
smbpasswd.
|
||||
|
||||
- Tests that require other resources on the network such as domain
|
||||
controllers or PSAs.
|
||||
|
||||
- Tests that are performed on the documentation or the source code
|
||||
such as:
|
||||
|
||||
- grep for common spelling mistakes made by abartlet (-:
|
||||
- grep for company copyright (IBM, HP)
|
||||
|
||||
- Link to other existing testing frameworks (smbtorture,
|
||||
abartlet's bash based build farm tests)
|
||||
|
||||
I propose a TestResourceManager which would be instantiated by a test
|
||||
case. The test case would require("resourcename") as part of its
|
||||
constructor and raise a comfychair.NotRun exception if the resource
|
||||
was not present. A TestResource class could be defined which could
|
||||
read a configuration file or examine a environment variable and
|
||||
register a resource only if some condition was satisfied.
|
||||
|
||||
It would be nice to be able to completely separate the PSA testing
|
||||
from the test framework. This would entail being able to define test
|
||||
resources dynamically, possibly with a plugin type system.
|
||||
|
||||
class TestResourceManager:
|
||||
def __init__(self, name):
|
||||
self.resources = {}
|
||||
|
||||
def register(self, resource):
|
||||
name = resource.name()
|
||||
if self.resources.has_key(name):
|
||||
raise "Test manager already has resource %s" % name
|
||||
self.resources[name] = resource
|
||||
|
||||
def require(self, resource_name):
|
||||
if not self.resources.has_key(resource_name):
|
||||
raise "Test manager does not have resources %s" % resource_name
|
||||
|
||||
class TestResource:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def name(self):
|
||||
return self.name
|
||||
|
||||
import os
|
||||
|
||||
trm = TestResourceManager()
|
||||
|
||||
if os.getuid() == 0:
|
||||
trm.register(TestResource("root"))
|
||||
|
||||
A config-o-matic Python module can take a list of machines and
|
||||
administrator%password entries and classify them by operating system
|
||||
version and service pack. These resources would be registered with
|
||||
the TestResourceManager.
|
||||
|
||||
Some random thoughts about named resources for network servers:
|
||||
|
||||
require("nt4.sp3")
|
||||
require("nt4.domaincontroller")
|
||||
require("psa")
|
||||
|
||||
Some kind of format for location of passwords, libraries:
|
||||
|
||||
require("exec(smbpasswd)")
|
||||
require("lib(bigballofmud)")
|
||||
|
||||
maybe require("exec.smbpasswd") looks nicer...
|
||||
|
||||
The require() function could return a dictionary of configuration
|
||||
information or some handle to fetch dynamic information on. We may
|
||||
need to create and destroy extra users or print queues. How to manage
|
||||
cleanup of dynamic resources?
|
||||
|
||||
Requirements for running stf:
|
||||
|
||||
- Python, obviously
|
||||
- Samba python extensions
|
55
source3/stf/osver.py
Executable file
55
source3/stf/osver.py
Executable file
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Utilities for determining the Windows operating system version remotely.
|
||||
#
|
||||
|
||||
from samba import srvsvc
|
||||
|
||||
# Constants
|
||||
|
||||
PLATFORM_UNKNOWN = 0
|
||||
PLATFORM_WIN9X = 1
|
||||
PLATFORM_NT4 = 2
|
||||
PLATFORM_NT5 = 3 # Windows 2000
|
||||
|
||||
def platform_name(platform_type):
|
||||
|
||||
platform_names = { PLATFORM_UNKNOWN: "Unknown",
|
||||
PLATFORM_WIN9X: "Windows 9x",
|
||||
PLATFORM_NT4: "Windows NT",
|
||||
PLATFORM_NT5: "Windows 2000" }
|
||||
|
||||
if platform_names.has_key(platform_type):
|
||||
return platform_names[platform_type]
|
||||
|
||||
return "Unknown"
|
||||
|
||||
def platform_type(info101):
|
||||
"""Determine the operating system type from a SRV_INFO_101."""
|
||||
|
||||
if info101['major_version'] == 4 and info101['minor_version'] == 0:
|
||||
return PLATFORM_NT4
|
||||
|
||||
if info101['major_version'] == 5 and info101['minor_version'] == 0:
|
||||
return PLATFORM_NT5
|
||||
|
||||
return PLATFORM_UNKNOWN
|
||||
|
||||
def is_domain_controller(info101):
|
||||
"""Return true if the server_type field from a SRV_INFO_101
|
||||
indicates a domain controller."""
|
||||
return info101['server_type'] & srvsvc.SV_TYPE_DOMAIN_CTRL
|
||||
|
||||
def os_version(name):
|
||||
info = srvsvc.netservergetinfo("\\\\%s" % name, 101)
|
||||
return platform_type(info)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
print "Usage: osver.py server"
|
||||
sys.exit(0)
|
||||
info = srvsvc.netservergetinfo("\\\\%s" % sys.argv[1], 101)
|
||||
print "platform type = %d" % platform_type(info)
|
||||
if is_domain_controller(info):
|
||||
print "%s is a domain controller" % sys.argv[1]
|
288
source3/stf/spoolss.py
Executable file
288
source3/stf/spoolss.py
Executable file
@ -0,0 +1,288 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import re
|
||||
import comfychair, stf
|
||||
from samba import spoolss
|
||||
|
||||
class PrintServerTest(comfychair.TestCase):
|
||||
"""An abstract class requiring a print server."""
|
||||
def setUp(self):
|
||||
# TODO: create a test printer
|
||||
self.server = stf.get_server(platform = "nt")
|
||||
self.require(self.server != None, "print server required")
|
||||
# TODO: remove hardcoded printer name
|
||||
self.printername = "p"
|
||||
self.uncname = "\\\\%s\\%s" % \
|
||||
(self.server["hostname"], self.printername)
|
||||
|
||||
class W2kPrintServerTest(comfychair.TestCase):
|
||||
"""An abstract class requiring a print server."""
|
||||
def setUp(self):
|
||||
# TODO: create a test printer
|
||||
self.server = stf.get_server(platform = "nt5")
|
||||
self.require(self.server != None, "print server required")
|
||||
# TODO: remove hardcoded printer name
|
||||
self.printername = "p"
|
||||
self.uncname = "\\\\%s\\%s" % \
|
||||
(self.server["hostname"], self.printername)
|
||||
|
||||
class CredentialTest(PrintServerTest):
|
||||
"""An class that calls a function with various sets of credentials."""
|
||||
def runTest(self):
|
||||
|
||||
bad_user_creds = {"username": "spotty",
|
||||
"domain": "dog",
|
||||
"password": "bone"}
|
||||
|
||||
cases = ((self.server["administrator"], "Admin credentials", 1),
|
||||
(bad_user_creds, "Bad credentials", 0))
|
||||
|
||||
# TODO: add unpriv user case
|
||||
|
||||
for creds, testname, result in cases:
|
||||
try:
|
||||
self.runTestArg(creds)
|
||||
except:
|
||||
if result:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
self.fail("rpc with creds %s failed when it "
|
||||
"should have suceeded" % creds)
|
||||
return
|
||||
|
||||
if not result:
|
||||
self.fail("rpc with creds %s suceeded when it should "
|
||||
"have failed" % creds)
|
||||
|
||||
class ArgTestServer(PrintServerTest):
|
||||
"""Test a RPC that takes a UNC print server name."""
|
||||
def runTest(self):
|
||||
|
||||
# List of test cases, %s substituted for server name
|
||||
|
||||
cases = (("", "No server name", 0),
|
||||
("\\\\%s", "Valid server name", 1),
|
||||
("\\%s", "Invalid unc server name", 0),
|
||||
("\\\\%s__", "Invalid unc server name", 0))
|
||||
|
||||
for unc, testname, result in cases:
|
||||
unc = re.sub("%s", self.server["hostname"], unc)
|
||||
try:
|
||||
self.runTestArg(unc)
|
||||
except:
|
||||
if result:
|
||||
self.fail("rpc(\"%s\") failed when it should have "
|
||||
"suceeded" % unc)
|
||||
return
|
||||
|
||||
if not result:
|
||||
# Suceeded when we should have failed
|
||||
self.fail("rpc(\"%s\") suceeded when it should have "
|
||||
"failed" % unc)
|
||||
|
||||
class ArgTestServerAndPrinter(ArgTestServer):
|
||||
"""Test a RPC that takes a UNC print server or UNC printer name."""
|
||||
def runTest(self):
|
||||
|
||||
ArgTestServer.runTest(self)
|
||||
|
||||
# List of test cases, %s substituted for server name, %p substituted
|
||||
# for printer name.
|
||||
|
||||
cases = (("\\\\%s\\%p", "Valid server and printer name", 1),
|
||||
("\\\\%s\\%p__", "Valid server, invalid printer name", 0),
|
||||
("\\\\%s__\\%p", "Invalid server, valid printer name", 0))
|
||||
|
||||
for unc, testname, result in cases:
|
||||
unc = re.sub("%s", self.server["hostname"], unc)
|
||||
unc = re.sub("%p", self.printername, unc)
|
||||
try:
|
||||
self.runTestArg(unc)
|
||||
except:
|
||||
if result:
|
||||
self.fail("openprinter(\"%s\") failed when it should have "
|
||||
"suceeded" % unc)
|
||||
return
|
||||
|
||||
if not result:
|
||||
# Suceeded when we should have failed
|
||||
self.fail("openprinter(\"%s\") suceeded when it should have "
|
||||
"failed" % unc)
|
||||
|
||||
class OpenPrinterArg(ArgTestServerAndPrinter):
|
||||
"""Test the OpenPrinter RPC with combinations of valid and invalid
|
||||
server and printer names."""
|
||||
def runTestArg(self, unc):
|
||||
spoolss.openprinter(unc)
|
||||
|
||||
class OpenPrinterCred(CredentialTest):
|
||||
"""Test opening printer with good and bad credentials."""
|
||||
def runTestArg(self, creds):
|
||||
spoolss.openprinter(self.uncname, creds = creds)
|
||||
|
||||
class ClosePrinter(PrintServerTest):
|
||||
"""Test the ClosePrinter RPC on a printer handle."""
|
||||
def runTest(self):
|
||||
hnd = spoolss.openprinter(self.uncname)
|
||||
spoolss.closeprinter(hnd)
|
||||
|
||||
class ClosePrinterServer(PrintServerTest):
|
||||
"""Test the ClosePrinter RPC on a print server handle."""
|
||||
def runTest(self):
|
||||
hnd = spoolss.openprinter("\\\\%s" % self.server["hostname"])
|
||||
spoolss.closeprinter(hnd)
|
||||
|
||||
class GetPrinterInfo(PrintServerTest):
|
||||
"""Retrieve printer info at various levels."""
|
||||
|
||||
# Sample printer data
|
||||
|
||||
sample_info = {
|
||||
0: {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '\\\\win2kdc1', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': 1114112, 'name': '\\\\win2kdc1\\p', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 2, 'status': 1, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0},
|
||||
1: {'comment': "I'm a teapot!", 'level': 1, 'flags': 8388608, 'name': '\\\\win2kdc1\\p', 'description': '\\\\win2kdc1\\p,HP LaserJet 4,Canberra office'},
|
||||
2: {'comment': "I'm a teapot!", 'status': 1, 'print_processor': 'WinPrint', 'until_time': 0, 'share_name': 'p', 'start_time': 0, 'device_mode': {'icm_method': 1, 'bits_per_pel': 0, 'log_pixels': 0, 'orientation': 1, 'panning_width': 0, 'color': 2, 'pels_width': 0, 'print_quality': 600, 'driver_version': 24, 'display_flags': 0, 'y_resolution': 600, 'media_type': 0, 'display_frequency': 0, 'icm_intent': 0, 'pels_height': 0, 'reserved1': 0, 'size': 220, 'scale': 100, 'dither_type': 0, 'panning_height': 0, 'default_source': 7, 'duplex': 1, 'fields': 16131, 'spec_version': 1025, 'copies': 1, 'device_name': '\\\\win2kdc1\\p', 'paper_size': 1, 'paper_length': 0, 'private': 'private', 'collate': 0, 'paper_width': 0, 'form_name': 'Letter', 'reserved2': 0, 'tt_option': 0}, 'port_name': 'LPT1:', 'sepfile': '', 'parameters': '', 'security_descriptor': {'group_sid': 'S-1-5-21-1606980848-1677128483-854245398-513', 'sacl': None, 'dacl': {'ace_list': [{'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-544'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-544'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1121'}, {'flags': 10, 'type': 0, 'mask': 131072, 'trustee': 'S-1-3-0'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-3-0'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1124'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-1-0'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-550'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-550'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-549'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-549'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1106'}], 'revision': 2}, 'owner_sid': 'S-1-5-32-544', 'revision': 1}, 'name': '\\\\win2kdc1\\p', 'server_name': '\\\\win2kdc1', 'level': 2, 'datatype': 'RAW', 'cjobs': 0, 'average_ppm': 0, 'priority': 1, 'driver_name': 'HP LaserJet 4', 'location': 'Canberra office', 'attributes': 8776, 'default_priority': 0},
|
||||
3: {'flags': 4, 'security_descriptor': {'group_sid': 'S-1-5-21-1606980848-1677128483-854245398-513', 'sacl': None, 'dacl': {'ace_list': [{'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-544'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-544'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1121'}, {'flags': 10, 'type': 0, 'mask': 131072, 'trustee': 'S-1-3-0'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-3-0'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1124'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-1-0'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-550'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-550'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-549'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-549'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1106'}], 'revision': 2}, 'owner_sid': 'S-1-5-32-544', 'revision': 1}, 'level': 3}
|
||||
}
|
||||
|
||||
def runTest(self):
|
||||
self.hnd = spoolss.openprinter(self.uncname)
|
||||
|
||||
# Everyone should have getprinter levels 0-3
|
||||
|
||||
for i in (0, 1, 2, 3):
|
||||
info = self.hnd.getprinter(level = i)
|
||||
try:
|
||||
stf.dict_check(self.sample_info[i], info)
|
||||
except ValueError, msg:
|
||||
raise "info%d: %s" % (i, msg)
|
||||
|
||||
class EnumPrinters(PrintServerTest):
|
||||
"""Enumerate print info at various levels."""
|
||||
|
||||
sample_info = {
|
||||
|
||||
0: {'q': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': -1833435136, 'name': 'q', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 0, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 'p': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': -1831337984, 'name': 'p', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 1, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 'magpie': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': 1114112, 'name': 'magpie', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 0, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}},
|
||||
|
||||
1: {'q': {'comment': 'cheepy birds', 'level': 1, 'flags': 8388608, 'name': 'q', 'description': 'q,HP LaserJet 4,'}, 'p': {'comment': "I'm a teapot!", 'level': 1, 'flags': 8388608, 'name': 'p', 'description': 'p,HP LaserJet 4,Canberra office'}, 'magpie': {'comment': '', 'level': 1, 'flags': 8388608, 'name': 'magpie', 'description': 'magpie,Generic / Text Only,'}}
|
||||
}
|
||||
|
||||
def runTest(self):
|
||||
for i in (0, 1):
|
||||
info = spoolss.enumprinters(
|
||||
"\\\\%s" % self.server["hostname"], level = i)
|
||||
try:
|
||||
stf.dict_check(self.sample_info[i], info)
|
||||
except ValueError, msg:
|
||||
raise "info%d: %s" % (i, msg)
|
||||
|
||||
class EnumPrintersArg(ArgTestServer):
|
||||
def runTestArg(self, unc):
|
||||
spoolss.enumprinters(unc)
|
||||
|
||||
class EnumPrintersCred(CredentialTest):
|
||||
"""Test opening printer with good and bad credentials."""
|
||||
def runTestArg(self, creds):
|
||||
spoolss.enumprinters(
|
||||
"\\\\%s" % self.server["hostname"], creds = creds)
|
||||
|
||||
class EnumPrinterdrivers(PrintServerTest):
|
||||
|
||||
sample_info = {
|
||||
1: {'Okipage 10ex (PCL5E) : STANDARD': {'name': 'Okipage 10ex (PCL5E) : STANDARD', 'level': 1}, 'Generic / Text Only': {'name': 'Generic / Text Only', 'level': 1}, 'Brother HL-1030 series': {'name': 'Brother HL-1030 series', 'level': 1}, 'Brother HL-1240 series': {'name': 'Brother HL-1240 series', 'level': 1}, 'HP DeskJet 1220C Printer': {'name': 'HP DeskJet 1220C Printer', 'level': 1}, 'HP LaserJet 4100 PCL 6': {'name': 'HP LaserJet 4100 PCL 6', 'level': 1}, 'HP LaserJet 4': {'name': 'HP LaserJet 4', 'level': 1}},
|
||||
2: {'Okipage 10ex (PCL5E) : STANDARD': {'version': 2, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\RASDDUI.DLL', 'name': 'Okipage 10ex (PCL5E) : STANDARD', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\2\\RASDD.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\OKIPAGE.DLL', 'level': 2, 'architecture': 'Windows NT x86'}, 'Generic / Text Only': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\UNIDRVUI.DLL', 'name': 'Generic / Text Only', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\UNIDRV.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\TTY.GPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'Brother HL-1030 series': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BRUHL99A.DLL', 'name': 'Brother HL-1030 series', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL99A.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL103.PPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'Brother HL-1240 series': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BRUHL99A.DLL', 'name': 'Brother HL-1240 series', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL99A.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL124.PPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP DeskJet 1220C Printer': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'name': 'HP DeskJet 1220C Printer', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP LaserJet 4100 PCL 6': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042E.DLL', 'name': 'HP LaserJet 4100 PCL 6', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042G.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042I.PMD', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP LaserJet 4': {'version': 2, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff0.dll', 'name': 'HP LaserJet 4', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff2.dll', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff39.pmd', 'level': 2, 'architecture': 'Windows NT x86'}}
|
||||
}
|
||||
|
||||
def runTest(self):
|
||||
for i in (1, 2):
|
||||
info = spoolss.enumprinterdrivers(
|
||||
"\\\\%s" % self.server["hostname"], level = i)
|
||||
try:
|
||||
if not self.sample_info.has_key(i):
|
||||
self.log("%s" % info)
|
||||
self.fail()
|
||||
stf.dict_check(self.sample_info[i], info)
|
||||
except ValueError, msg:
|
||||
raise "info%d: %s" % (i, msg)
|
||||
|
||||
class EnumPrinterdriversArg(ArgTestServer):
|
||||
def runTestArg(self, unc):
|
||||
spoolss.enumprinterdrivers(unc)
|
||||
|
||||
class EnumPrinterdriversCred(CredentialTest):
|
||||
"""Test opening printer with good and bad credentials."""
|
||||
def runTestArg(self, creds):
|
||||
spoolss.enumprinterdrivers(
|
||||
"\\\\%s" % self.server["hostname"], creds = creds)
|
||||
|
||||
def usage():
|
||||
print "Usage: spoolss.py [options] [test1[,test2...]]"
|
||||
print "\t -v/--verbose Display debugging information"
|
||||
print "\t -l/--list-tests List available tests"
|
||||
print
|
||||
print "A list of comma separated test names or regular expressions"
|
||||
print "can be used to filter the tests performed."
|
||||
|
||||
def test_match(subtest_list, test_name):
|
||||
"""Return true if a test matches a comma separated list of regular
|
||||
expression of test names."""
|
||||
# re.match does an implicit ^ at the start of the pattern.
|
||||
# Explicitly anchor to end to avoid matching substrings.
|
||||
for s in string.split(subtest_list, ","):
|
||||
if re.match(s + "$", test_name):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os, sys, string
|
||||
import getopt
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "vl", \
|
||||
["verbose", "list-tests"])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(0)
|
||||
|
||||
verbose = 0
|
||||
list_tests = 0
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt in ("-v", "--verbose"):
|
||||
verbose = 1
|
||||
if opt in ("-l", "--list-tests"):
|
||||
list_tests = 1
|
||||
|
||||
if len(args) > 1:
|
||||
usage()
|
||||
sys.exit(0)
|
||||
|
||||
test_list = [
|
||||
OpenPrinterArg,
|
||||
OpenPrinterCred,
|
||||
ClosePrinter,
|
||||
ClosePrinterServer,
|
||||
GetPrinterInfo,
|
||||
EnumPrinters,
|
||||
EnumPrintersCred,
|
||||
EnumPrintersArg,
|
||||
EnumPrinterdrivers,
|
||||
EnumPrinterdriversCred,
|
||||
EnumPrinterdriversArg,
|
||||
]
|
||||
|
||||
if len(args):
|
||||
t = []
|
||||
for test in test_list:
|
||||
if test_match(args[0], test.__name__):
|
||||
t.append(test)
|
||||
test_list = t
|
||||
|
||||
if os.environ.has_key("SAMBA_DEBUG"):
|
||||
spoolss.setup_logging(interactive = 1)
|
||||
spoolss.set_debuglevel(10)
|
||||
|
||||
if list_tests:
|
||||
for test in test_list:
|
||||
print test.__name__
|
||||
else:
|
||||
comfychair.runtests(test_list, verbose = verbose)
|
101
source3/stf/stf.py
Executable file
101
source3/stf/stf.py
Executable file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Samba Testing Framework for Unit-testing
|
||||
#
|
||||
|
||||
import os, string, re
|
||||
import osver
|
||||
|
||||
def get_server_list_from_string(s):
|
||||
|
||||
server_list = []
|
||||
|
||||
# Format is a list of server:domain\username%password separated
|
||||
# by commas.
|
||||
|
||||
for entry in string.split(s, ","):
|
||||
|
||||
# Parse entry
|
||||
|
||||
m = re.match("(.*):(.*)(\\\\|/)(.*)%(.*)", entry)
|
||||
if not m:
|
||||
raise "badly formed server list entry '%s'" % entry
|
||||
|
||||
server = m.group(1)
|
||||
domain = m.group(2)
|
||||
username = m.group(4)
|
||||
password = m.group(5)
|
||||
|
||||
# Categorise servers
|
||||
|
||||
server_list.append({"platform": osver.os_version(server),
|
||||
"hostname": server,
|
||||
"administrator": {"username": username,
|
||||
"domain": domain,
|
||||
"password" : password}})
|
||||
|
||||
return server_list
|
||||
|
||||
def get_server_list():
|
||||
"""Iterate through all sources of server info and append them all
|
||||
in one big list."""
|
||||
|
||||
server_list = []
|
||||
|
||||
# The $STF_SERVERS environment variable
|
||||
|
||||
if os.environ.has_key("STF_SERVERS"):
|
||||
server_list = server_list + \
|
||||
get_server_list_from_string(os.environ["STF_SERVERS"])
|
||||
|
||||
return server_list
|
||||
|
||||
def get_server(platform = None):
|
||||
"""Return configuration information for a server. The platform
|
||||
argument can be a string either 'nt4' or 'nt5' for Windows NT or
|
||||
Windows 2000 servers, or just 'nt' for Windows NT and higher."""
|
||||
|
||||
server_list = get_server_list()
|
||||
|
||||
for server in server_list:
|
||||
if platform:
|
||||
p = server["platform"]
|
||||
if platform == "nt":
|
||||
if (p == osver.PLATFORM_NT4 or p == osver.PLATFORM_NT5):
|
||||
return server
|
||||
if platform == "nt4" and p == osver.PLATFORM_NT4:
|
||||
return server
|
||||
if platform == "nt5" and p == osver.PLATFORM_NT5:
|
||||
return server
|
||||
else:
|
||||
# No filter defined, return first in list
|
||||
return server
|
||||
|
||||
return None
|
||||
|
||||
def dict_check(sample_dict, real_dict):
|
||||
"""Check that real_dict contains all the keys present in sample_dict
|
||||
and no extras. Also check that common keys are of them same type."""
|
||||
tmp = real_dict.copy()
|
||||
for key in sample_dict.keys():
|
||||
# Check existing key and type
|
||||
if not real_dict.has_key(key):
|
||||
raise ValueError, "dict does not contain key '%s'" % key
|
||||
if type(sample_dict[key]) != type(real_dict[key]):
|
||||
raise ValueError, "dict has differing types (%s vs %s) for key " \
|
||||
"'%s'" % (type(sample_dict[key]), type(real_dict[key]), key)
|
||||
# Check dictionaries recursively
|
||||
if type(sample_dict[key]) == dict:
|
||||
dict_check(sample_dict[key], real_dict[key])
|
||||
# Delete visited keys from copy
|
||||
del(tmp[key])
|
||||
# Any keys leftover are present in the real dict but not the sample
|
||||
if len(tmp) == 0:
|
||||
return
|
||||
result = "dict has extra keys: "
|
||||
for key in tmp.keys():
|
||||
result = result + key + " "
|
||||
raise ValueError, result
|
||||
|
||||
if __name__ == "__main__":
|
||||
print get_server(platform = "nt")
|
33
source3/stf/test.py
Executable file
33
source3/stf/test.py
Executable file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# meta-test-case / example for comfychair. Should demonstrate
|
||||
# different kinds of failure.
|
||||
|
||||
import comfychair
|
||||
|
||||
class NormalTest(comfychair.TestCase):
|
||||
def runtest(self):
|
||||
pass
|
||||
|
||||
class RootTest(comfychair.TestCase):
|
||||
def setup(self):
|
||||
self.require_root()
|
||||
|
||||
def runTest(self):
|
||||
pass
|
||||
|
||||
class GoodExecTest(comfychair.TestCase):
|
||||
def runtest(self):
|
||||
stdout = self.runcmd("ls -l")
|
||||
|
||||
class BadExecTest(comfychair.TestCase):
|
||||
def setup(self):
|
||||
exit, stdout = self.runcmd_unchecked("spottyfoot --slobber",
|
||||
skip_on_noexec = 1)
|
||||
|
||||
|
||||
tests = [NormalTest, RootTest, GoodExecTest, BadExecTest]
|
||||
|
||||
if __name__ == '__main__':
|
||||
comfychair.main(tests)
|
||||
|
23
source3/torture/t_stringoverflow.c
Normal file
23
source3/torture/t_stringoverflow.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "includes.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fstring dest;
|
||||
char *ptr = dest;
|
||||
|
||||
printf("running on valgrind? %d\n", RUNNING_ON_VALGRIND);
|
||||
|
||||
/* Try copying a string into an fstring buffer. The string
|
||||
* will actually fit, but this is still wrong because you
|
||||
* can't pstrcpy into an fstring. This should trap in a
|
||||
* developer build. */
|
||||
|
||||
#if 0
|
||||
/* As of CVS 20030318, this will be trapped at compile time! */
|
||||
pstrcpy(dest, "hello");
|
||||
#endif /* 0 */
|
||||
|
||||
pstrcpy(ptr, "hello!");
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user