1
0
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:
cvs2svn Import User 2003-03-18 07:09:24 +00:00
commit 74d3be0218
16 changed files with 2239 additions and 0 deletions

View 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
View 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
View 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
View 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 */
}

View 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;
}

View 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;
}

View File

@ -0,0 +1,3 @@
*.po
*.po32

1
source3/stf/.cvsignore Normal file
View File

@ -0,0 +1 @@
*.pyc

3
source3/stf/README.stf Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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)

View 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;
}