From 94b9fcc03560b36932405727759a5621966cd212 Mon Sep 17 00:00:00 2001
From: Jonathan Lebon <jlebon@redhat.com>
Date: Fri, 13 Dec 2013 16:37:57 -0500
Subject: BZ1044429: fix client.exp and improve client/server
---
csclient.cxx | 342 ++++++++++++----------
csclient.h | 4 +-
nsscommon.cxx | 11 +-
testsuite/lib/systemtap.exp | 1 +
testsuite/systemtap.server/client.exp | 333 ++++++++++-----------
testsuite/systemtap.server/server_args.exp | 17 +-
testsuite/systemtap.server/server_concurrency.exp | 4 +-
7 files changed, 373 insertions(+), 339 deletions(-)
diff --git a/csclient.cxx b/csclient.cxx
index cce5428..568cc8f 100644
--- a/csclient.cxx
+++ b/csclient.cxx
@@ -1,6 +1,6 @@
/*
Compile server client functions
- Copyright (C) 2010-2013 Red Hat Inc.
+ Copyright (C) 2010-2014 Red Hat Inc.
This file is part of systemtap, and is free software. You can
redistribute it and/or modify it under the terms of the GNU General
@@ -88,66 +88,71 @@ nsscommon_error (const char *msg, int logit __attribute ((unused)))
// Information about compile servers.
struct compile_server_info
{
- compile_server_info ()
+ compile_server_info () : port(0), fully_specified(false)
{
memset (& address, 0, sizeof (address));
}
string host_name;
PRNetAddr address;
+ unsigned short port;
+ bool fully_specified;
string version;
string sysinfo;
string certinfo;
bool empty () const
{
- return this->host_name.empty () && ! this->hasAddress ();
+ return this->host_name.empty () && ! this->hasAddress () && certinfo.empty ();
}
bool hasAddress () const
{
return this->address.raw.family != 0;
}
- unsigned short port () const
- {
- if (this->address.raw.family == PR_AF_INET)
- return ntohs (this->address.inet.port);
- if (this->address.raw.family == PR_AF_INET6)
- return ntohs (this->address.ipv6.port);
- return 0;
- }
- unsigned short setPort (unsigned short port)
+ unsigned short setAddressPort (unsigned short port)
{
if (this->address.raw.family == PR_AF_INET)
return this->address.inet.port = htons (port);
if (this->address.raw.family == PR_AF_INET6)
return this->address.ipv6.port = htons (port);
+ assert (0);
return 0;
}
+ bool isComplete () const
+ {
+ return this->hasAddress () && port != 0;
+ }
bool operator== (const compile_server_info &that) const
{
- // If both ip addressed are not set, then the host names must match, otherwise
- // the addresses must match.
- if (! this->hasAddress() || ! that.hasAddress())
+ // If one item or the other has only a name, and possibly a port specified,
+ // then allow a match by name and port only. This is so that the user can specify
+ // names which are returned by avahi, but are not dns resolvable.
+ // Otherwise, we will ignore the host_name.
+ if ((! this->hasAddress() && this->version.empty () &&
+ this->sysinfo.empty () && this->certinfo.empty ()) ||
+ (! that.hasAddress() && that.version.empty () &&
+ that.sysinfo.empty () && that.certinfo.empty ()))
{
if (this->host_name != that.host_name)
return false;
}
- else if (this->address != that.address)
- return false;
// Compare the other fields only if they have both been set.
- if (this->port() != 0 && that.port() != 0 &&
- this->port() != that.port())
+ if (this->hasAddress() && that.hasAddress() &&
+ this->address != that.address)
+ return false;
+ if (this->port != 0 && that.port != 0 &&
+ this->port != that.port)
return false;
if (! this->version.empty () && ! that.version.empty () &&
- this->version != that.version)
+ this->version != that.version)
return false;
if (! this->sysinfo.empty () && ! that.sysinfo.empty () &&
- this->sysinfo != that.sysinfo)
+ this->sysinfo != that.sysinfo)
return false;
if (! this->certinfo.empty () && ! that.certinfo.empty () &&
- this->certinfo != that.certinfo)
+ this->certinfo != that.certinfo)
return false;
return true; // They are equal
@@ -179,6 +184,14 @@ preferred_order (vector<compile_server_info> &servers)
sort (servers.begin (), servers.end ());
}
+struct resolved_host
+{
+ string host_name;
+ PRNetAddr address;
+ resolved_host(string chost_name, PRNetAddr caddress):
+ host_name(chost_name), address(caddress) {}
+};
+
struct compile_server_cache
{
vector<compile_server_info> default_servers;
@@ -187,7 +200,7 @@ struct compile_server_cache
vector<compile_server_info> signing_servers;
vector<compile_server_info> online_servers;
vector<compile_server_info> all_servers;
- map<string,vector<compile_server_info> > resolved_servers;
+ map<string,vector<resolved_host> > resolved_hosts;
};
// For filtering queries.
@@ -234,7 +247,7 @@ static void resolve_host (systemtap_session& s, compile_server_info &server, vec
// -----------------------------------------------------
// NSS related code used by the compile server client
// -----------------------------------------------------
-static void add_server_trust (systemtap_session &s, const string &cert_db_path, const vector<compile_server_info> &server_list);
+static void add_server_trust (systemtap_session &s, const string &cert_db_path, vector<compile_server_info> &server_list);
static void revoke_server_trust (systemtap_session &s, const string &cert_db_path, const vector<compile_server_info> &server_list);
static void get_server_info_from_db (systemtap_session &s, vector<compile_server_info> &servers, const string &cert_db_path);
@@ -1132,10 +1145,10 @@ compile_server_client::find_and_connect_to_server ()
i != specified_servers.end ();
++i)
{
- // If we have an ip address and port number, then just use the one we've
- // been given. Otherwise, check for matching online servers and try their
+ // If we have an ip address and were given a port number, then just use the one we've
+ // been given. Otherwise, check for matching compatible online servers and try their
// ip addresses and ports.
- if (i->hasAddress() && i->port() != 0)
+ if (i->hasAddress() && i->fully_specified)
add_server_info (*i, server_list);
else
{
@@ -1145,8 +1158,8 @@ compile_server_client::find_and_connect_to_server ()
// If no specific server (port) has been specified,
// then we'll need the servers to be
- // compatible and possible trusted as signers as well.
- if (i->port() == 0)
+ // compatible and possibly trusted as signers as well.
+ if (! i->fully_specified)
{
get_or_keep_compatible_server_info (s, online_servers, true/*keep*/);
if (! pr_contains (s.privilege, pr_stapdev))
@@ -1227,7 +1240,7 @@ compile_server_client::find_and_connect_to_server ()
int
compile_server_client::compile_using_server (
- const vector<compile_server_info> &servers
+ vector<compile_server_info> &servers
)
{
// Make sure NSPR is initialized. Must be done before NSS is initialized
@@ -1275,14 +1288,16 @@ compile_server_client::compile_using_server (
server_zipfile = s.tmpdir + "/server.zip";
// Try each server in turn.
- for (vector<compile_server_info>::const_iterator j = servers.begin ();
+ for (vector<compile_server_info>::iterator j = servers.begin ();
j != servers.end ();
++j)
{
// At a minimum we need an ip_address along with a port
// number in order to contact the server.
- if (! j->hasAddress() || j->port() == 0)
+ if (! j->hasAddress() || j->port == 0)
continue;
+ // Set the port within the address.
+ j->setAddressPort (j->port);
if (s.verbose >= 2)
clog << _F("Attempting SSL connection with %s\n"
@@ -1673,7 +1688,7 @@ static void
add_server_trust (
systemtap_session &s,
const string &cert_db_path,
- const vector<compile_server_info> &server_list
+ vector<compile_server_info> &server_list
)
{
// Get a list of servers already trusted. This opens the database, so do it
@@ -1716,7 +1731,7 @@ add_server_trust (
// Iterate over the servers to become trusted. Contact each one and
// add it to the list of trusted servers if it is not already trusted.
// client_connect will issue any error messages.
- for (vector<compile_server_info>::const_iterator server = server_list.begin();
+ for (vector<compile_server_info>::iterator server = server_list.begin();
server != server_list.end ();
++server)
{
@@ -1735,10 +1750,14 @@ add_server_trust (
trust_already_in_place (*server, server_list, cert_db_path, false/*revoking*/);
continue;
}
+
// At a minimum we need an ip_address along with a port
// number in order to contact the server.
- if (! server->hasAddress() || server->port() == 0)
+ if (! server->hasAddress() || server->port == 0)
continue;
+ // Set the port within the address.
+ server->setAddressPort (server->port);
+
int rc = client_connect (*server, NULL, NULL, "permanent");
if (rc != SUCCESS)
{
@@ -2076,8 +2095,8 @@ ostream &operator<< (ostream &s, const compile_server_info &i)
else
s << "offline";
s << " port=";
- if (i.port() != 0)
- s << i.port();
+ if (i.port != 0)
+ s << i.port;
else
s << "unknown";
s << " sysinfo=\"";
@@ -2586,7 +2605,8 @@ isPort (const char *pstr, compile_server_info &server_info)
clog << _F("Invalid port number specified: %s", pstr) << endl;
return false;
}
- server_info.setPort (p);
+ server_info.port = p;
+ server_info.fully_specified = true;
return true;
}
@@ -2665,8 +2685,10 @@ isIPv6 (const string &server, compile_server_info &server_info)
if (! empty && components.size() != 8)
return false; // Not a valid IPv6 address
- // Calls to setPort and isPort need to know that this is an IPv6 address.
- server_info.address.raw.family = PR_AF_INET6;
+ // Try to convert the string to an address.
+ PRStatus prStatus = PR_StringToNetAddr (ip.c_str(), & server_info.address);
+ if (prStatus != PR_SUCCESS)
+ return false;
// Examine the optional port
if (portIx != string::npos)
@@ -2683,10 +2705,8 @@ isIPv6 (const string &server, compile_server_info &server_info)
}
}
else
- server_info.setPort (0);
+ server_info.port = 0;
- // Treat the ip address string like a host name.
- server_info.host_name = ip;
return true; // valid IPv6 address.
}
@@ -2703,20 +2723,20 @@ isIPv4 (const string &server, compile_server_info &server_info)
if (components.size() > 2)
return false; // Not a valid IPv4 address
- // Separate the host from the port (if any).
- string host;
+ // Separate the address from the port (if any).
+ string addr;
string port;
if (components.size() <= 1)
- host = server;
+ addr = server;
else {
- host = components[0];
+ addr = components[0];
port = components[1];
}
- // Separate the host components.
+ // Separate the address components.
// There must be exactly 4 components.
components.clear ();
- tokenize (server, components, ".");
+ tokenize (addr, components, ".");
if (components.size() != 4)
return false; // Not a valid IPv4 address
@@ -2732,8 +2752,10 @@ isIPv4 (const string &server, compile_server_info &server_info)
return false; // Not a valid IPv4 address
}
- // Calls to setPort and isPort need to know that this is an IPv4 address.
- server_info.address.raw.family = PR_AF_INET;
+ // Try to convert the string to an address.
+ PRStatus prStatus = PR_StringToNetAddr (addr.c_str(), & server_info.address);
+ if (prStatus != PR_SUCCESS)
+ return false;
// Examine the optional port
if (! port.empty ()) {
@@ -2741,10 +2763,8 @@ isIPv4 (const string &server, compile_server_info &server_info)
return false; // not a valid port
}
else
- server_info.setPort (0);
+ server_info.port = 0;
- // Treat the ip address string like a host name.
- server_info.host_name = host;
return true; // valid IPv4 address.
}
@@ -2754,8 +2774,6 @@ isCertSerialNumber (const string &server, compile_server_info &server_info)
// This function assumes that we have already ruled out the server spec being an IPv6 address.
// Certificate serial numbers are 5 fields separated by colons plus an optional 6th decimal
// field specifying a port.
- // Assume IPv4 (for now) when storing the port.
- server_info.address.raw.family = PR_AF_INET;
assert (! server.empty());
string host = server;
vector<string> components;
@@ -2782,8 +2800,6 @@ isDomain (const string &server, compile_server_info &server_info)
{
// Accept one or two components separated by a colon. The first will be the domain name and
// the second must a port number.
- // Assume IPv4 (for now) when storing the port.
- server_info.address.raw.family = PR_AF_INET;
assert (! server.empty());
string host = server;
vector<string> components;
@@ -2858,50 +2874,69 @@ get_specified_server_info (
// Check for IPv6 addresses first. It reduces the amount of checking necessary for
// certificate serial numbers.
compile_server_info server_info;
- vector<compile_server_info> known_servers;
+ vector<compile_server_info> resolved_servers;
if (isIPv6 (server, server_info) || isIPv4 (server, server_info) ||
- isDomain (server, server_info))
+ isCertSerialNumber (server, server_info))
{
- // Resolve this host and add any information that is discovered.
- // Try to augment the resolved servers with information about known servers.
- // There may be no intersection.
- get_all_server_info (s, known_servers);
-
- vector<compile_server_info> resolved_servers;
+ // An address or cert serial number has been specified.
+ // No resolution is needed.
+ resolved_servers.push_back (server_info);
+ }
+ else if (isDomain (server, server_info))
+ {
+ // Try to resolve the given name.
resolve_host (s, server_info, resolved_servers);
-
- vector<compile_server_info> common_servers = resolved_servers;
- keep_common_server_info (known_servers, common_servers);
- if (! common_servers.empty ())
- add_server_info (common_servers, resolved_servers);
-
- if (s.verbose >= 3)
- {
- clog << _F("Servers matching %s: ", server.c_str()) << endl;
- clog << resolved_servers;
- }
- add_server_info (resolved_servers, specified_servers);
- }
- else if (isCertSerialNumber (server, server_info))
- {
- // The host could not be resolved. Try resolving it as a certificate serial
- // number. Look for all known servers with this serial number and (optional)
- // port number.
- get_all_server_info (s, known_servers);
- keep_server_info_with_cert_and_port (s, server_info, known_servers);
- if (s.verbose >= 3)
- {
- clog << _F("Servers matching %s: ", server.c_str()) << endl;
- clog << known_servers;
- }
-
- add_server_info (known_servers, specified_servers);
}
else
{
clog << _F("Invalid server specification for --use-server: %s", server.c_str())
<< endl;
+ continue;
}
+
+ // Now examine the server(s) identified and add them to the list of specified
+ // servers.
+ vector<compile_server_info> known_servers;
+ vector<compile_server_info> new_servers;
+ for (vector<compile_server_info>::iterator i = resolved_servers.begin();
+ i != resolved_servers.end();
+ ++i)
+ {
+ // If this item was fully specified, then just add it.
+ if (i->fully_specified)
+ add_server_info (*i, new_servers);
+ else {
+ // It was not fully specified, so we need additional info. Try
+ // to get it by matching what we have against other known servers.
+ if (known_servers.empty ())
+ get_all_server_info (s, known_servers);
+
+ // See if this server spec matches that of a known server
+ vector<compile_server_info> matched_servers = known_servers;
+ keep_common_server_info (*i, matched_servers);
+
+ // If this server spec matches one or more known servers, then add the
+ // augmented info to the specified_servers. Otherwise, if this server
+ // spec is complete, then add it directly. Otherwise this server spec
+ // is incomplete.
+ if (! matched_servers.empty())
+ add_server_info (matched_servers, new_servers);
+ else if (i->isComplete ())
+ add_server_info (*i, new_servers);
+ else if (s.verbose >= 3)
+ clog << _("Incomplete server spec: ") << *i << endl;
+ }
+ }
+
+ if (s.verbose >= 3)
+ {
+ clog << _F("Servers matching %s: ", server.c_str()) << endl;
+ clog << new_servers;
+ }
+
+ // Add the newly identified servers to the list.
+ if (! new_servers.empty())
+ add_server_info (new_servers, specified_servers);
} // Loop over --use-server options
} // -- use-server specified
@@ -3087,13 +3122,16 @@ keep_server_info_with_cert_and_port (
continue;
}
if (servers[i].certinfo == server.certinfo &&
- (servers[i].port() == 0 || server.port() == 0 ||
- servers[i].port() == server.port()))
+ (servers[i].port == 0 || server.port == 0 ||
+ servers[i].port == server.port))
{
// If the server is not online, then use the specified
// port, if any.
- if (servers[i].port() == 0)
- servers[i].setPort (server.port());
+ if (servers[i].port == 0)
+ {
+ servers[i].port = server.port;
+ servers[i].fully_specified = server.fully_specified;
+ }
++i;
continue;
}
@@ -3110,8 +3148,8 @@ resolve_host (
vector<compile_server_info> &resolved_servers
)
{
- vector<compile_server_info>& cached_servers = cscache(s)->resolved_servers[server.host_name];
- if (cached_servers.empty ())
+ vector<resolved_host>& cached_hosts = cscache(s)->resolved_hosts[server.host_name];
+ if (cached_hosts.empty ())
{
// The server's host_name member is a string containing either a host name or an ip address.
// Either is acceptable for lookup.
@@ -3128,10 +3166,8 @@ resolve_host (
// Failure to resolve will result in an appropriate message later, if other methods fail.
if (rc != 0)
{
- // At a minimum, return the information we were given.
if (s.verbose >= 6)
clog << _F("%s not found: %s", lookup_name, gai_strerror (rc)) << endl;
- add_server_info (server, cached_servers);
}
else
{
@@ -3139,28 +3175,23 @@ resolve_host (
assert (addr_info);
for (const struct addrinfo *ai = addr_info; ai != NULL; ai = ai->ai_next)
{
- // Start with the info we were given.
- compile_server_info new_server = server;
+ PRNetAddr new_address;
// We support IPv4 and IPv6, Ignore other protocols,
if (ai->ai_family == AF_INET)
{
// IPv4 Address
struct sockaddr_in *ip = (struct sockaddr_in *)ai->ai_addr;
- new_server.address.inet.family = PR_AF_INET;
- if (ip->sin_port != 0)
- new_server.address.inet.port = ip->sin_port;
- new_server.address.inet.ip = ip->sin_addr.s_addr;
+ new_address.inet.family = PR_AF_INET;
+ new_address.inet.ip = ip->sin_addr.s_addr;
}
else if (ai->ai_family == AF_INET6)
{
// IPv6 Address
struct sockaddr_in6 *ip = (struct sockaddr_in6 *)ai->ai_addr;
- new_server.address.ipv6.family = PR_AF_INET6;
- if (ip->sin6_port != 0)
- new_server.address.ipv6.port = ip->sin6_port;
- new_server.address.ipv6.scope_id = ip->sin6_scope_id;
- copyAddress (new_server.address.ipv6.ip, ip->sin6_addr);
+ new_address.ipv6.family = PR_AF_INET6;
+ new_address.ipv6.scope_id = ip->sin6_scope_id;
+ copyAddress (new_address.ipv6.ip, ip->sin6_addr);
}
else
continue;
@@ -3169,25 +3200,54 @@ resolve_host (
char hbuf[NI_MAXHOST];
int status = getnameinfo (ai->ai_addr, ai->ai_addrlen, hbuf, sizeof (hbuf), NULL, 0,
NI_NAMEREQD | NI_IDN);
- if (status == 0)
- new_server.host_name = hbuf;
+ if (status != 0)
+ hbuf[0] = '\0';
- // Add the new resolved server to the list.
- add_server_info (new_server, cached_servers);
+ resolved_host *new_host = new resolved_host(hbuf, new_address);
+ cached_hosts.push_back(*new_host);
}
}
if (addr_info)
freeaddrinfo (addr_info); // free the linked list
-
- if (s.verbose >= 6)
- {
- clog << _F("%s resolves to:", lookup_name) << endl;
- clog << cached_servers;
- }
}
- // Add the information, but not duplicates.
- add_server_info (cached_servers, resolved_servers);
+ // If no addresses were resolved, then return the info we were given.
+ if (cached_hosts.empty())
+ add_server_info (server, resolved_servers);
+ else {
+ // We will add a new server for each address resolved
+ vector<compile_server_info> new_servers;
+ for (vector<resolved_host>::const_iterator it = cached_hosts.begin();
+ it != cached_hosts.end(); ++it)
+ {
+ // Start with the info we were given
+ compile_server_info new_server = server;
+
+ // NB: do not overwrite port info
+ if (it->address.raw.family == AF_INET)
+ {
+ new_server.address.inet.family = PR_AF_INET;
+ new_server.address.inet.ip = it->address.inet.ip;
+ }
+ else // AF_INET6
+ {
+ new_server.address.ipv6.family = PR_AF_INET6;
+ new_server.address.ipv6.scope_id = it->address.ipv6.scope_id;
+ new_server.address.ipv6.ip = it->address.ipv6.ip;
+ }
+ if (!it->host_name.empty())
+ new_server.host_name = it->host_name;
+ add_server_info (new_server, new_servers);
+ }
+
+ if (s.verbose >= 6)
+ {
+ clog << _F("%s resolves to:", server.host_name.c_str()) << endl;
+ clog << new_servers;
+ }
+
+ add_server_info (new_servers, resolved_servers);
+ }
}
#if HAVE_AVAHI
@@ -3268,12 +3328,12 @@ void resolve_callback(
// We support both IPv4 and IPv6. Ignore other protocols.
if (protocol == AVAHI_PROTO_INET6) {
info.address.ipv6.family = PR_AF_INET6;
- info.address.ipv6.port = htons (port);
info.address.ipv6.scope_id = interface;
+ info.port = port;
}
else if (protocol == AVAHI_PROTO_INET) {
info.address.inet.family = PR_AF_INET;
- info.address.inet.port = htons (port);
+ info.port = port;
}
else
break;
@@ -3388,7 +3448,6 @@ get_or_keep_online_server_info (
online_servers.push_back (compile_server_info ());
#if HAVE_AVAHI
// Must predeclare these due to jumping on error to fail:
- unsigned limit;
vector<compile_server_info> avahi_servers;
// Initialize.
@@ -3449,25 +3508,6 @@ get_or_keep_online_server_info (
clog << avahi_servers;
}
- // Resolve each server discovered, in case there are alternate ways to reach them
- // (e.g. localhost).
- limit = avahi_servers.size ();
- for (unsigned i = 0; i < limit; ++i)
- {
- compile_server_info &avahi_server = avahi_servers[i];
-
- // Delete the domain, if it is '.local'
- string &host_name = avahi_server.host_name;
- string::size_type dot_index = host_name.find ('.');
- assert (dot_index != 0);
- string domain = host_name.substr (dot_index + 1);
- if (domain == "local")
- host_name = host_name.substr (0, dot_index);
-
- // Add it to the list of servers, unless it is duplicate.
- resolve_host (s, avahi_server, online_servers);
- }
-
// Merge with the list of servers, as obtained by avahi.
add_server_info (avahi_servers, online_servers);
@@ -3619,15 +3659,19 @@ merge_server_info (
compile_server_info &target
)
{
- if (target.host_name.empty ())
+ // Copy the host name if the source has one.
+ if (! source.host_name.empty())
target.host_name = source.host_name;
// Copy the address unconditionally, if the source has an address, even if they are already
// equal. The source address may be an IPv6 address with a scope_id that the target is missing.
assert (! target.hasAddress () || ! source.hasAddress () || source.address == target.address);
if (source.hasAddress ())
copyNetAddr (target.address, source.address);
- if (target.port() == 0)
- target.setPort (source.port());
+ if (target.port == 0)
+ {
+ target.port = source.port;
+ target.fully_specified = source.fully_specified;
+ }
if (target.sysinfo.empty ())
target.sysinfo = source.sysinfo;
if (target.version.empty ())
diff --git a/csclient.h b/csclient.h
index b7eeda4..e4508ea 100644
--- a/csclient.h
+++ b/csclient.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-// Copyright (C) 2010-2011 Red Hat Inc.
+// Copyright (C) 2010-2014 Red Hat Inc.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
@@ -35,7 +35,7 @@ private:
);
int add_package_args ();
int add_package_arg (const std::string &arg);
- int compile_using_server (const std::vector<compile_server_info> &servers);
+ int compile_using_server (std::vector<compile_server_info> &servers);
int add_localization_variables();
int read_from_file (const std::string &fname, int &data);
diff --git a/nsscommon.cxx b/nsscommon.cxx
index 70aac54..78e38b0 100644
--- a/nsscommon.cxx
+++ b/nsscommon.cxx
@@ -1,7 +1,7 @@
/*
Common functions used by the NSS-aware code in systemtap.
- Copyright (C) 2009-2013 Red Hat Inc.
+ Copyright (C) 2009-2014 Red Hat Inc.
This file is part of systemtap, and is free software. You can
redistribute it and/or modify it under the terms of the GNU General Public
@@ -998,12 +998,19 @@ gen_cert_db (const string &db_path, const string &extraDnsNames, bool use_passwo
goto error;
}
- // Now, generate the cert. We need our host name and the supplied additional dns names (if any).
+ // For the cert, we need our host name.
struct utsname utsname;
uname (& utsname);
dnsNames = utsname.nodename;
+
+ // Because avahi identifies hosts using a ".local" domain, add one to the list of names.
+ dnsNames += string(",") + dnsNames + ".local";
+
+ // Add any extra names that were supplied.
if (! extraDnsNames.empty ())
dnsNames += "," + extraDnsNames;
+
+ // Now, generate the cert.
cert = create_cert (cr, dnsNames);
CERT_DestroyCertificateRequest (cr);
if (! cert)
diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp
index d4e4d85..64bbed1 100644
--- a/testsuite/lib/systemtap.exp
+++ b/testsuite/lib/systemtap.exp
@@ -244,6 +244,7 @@ proc setup_server { args } {
}
# Make sure that stap can find the server.
+ exec sleep 1
set use_server --use-server
set res [catch { exec stap --list-servers=online,trusted,compatible >& stap-list-servers.out } looksee]
verbose -log "stap --list-servers returned: res==$res"
diff --git a/testsuite/systemtap.server/client.exp b/testsuite/systemtap.server/client.exp
index f0d0728..41a06cc 100644
--- a/testsuite/systemtap.server/client.exp
+++ b/testsuite/systemtap.server/client.exp
@@ -1,3 +1,6 @@
+# In this test, we are using arrays as sets. The key itself does not matter,
+# only the value
+
# many of these tests use as_root
if {! [installtest_p]} { return }
if {! [nss_p]} { return }
@@ -5,37 +8,111 @@ if {! [nss_p]} { return }
# Let's start with a clean slate in terms of trust.
exec rm -fr $env(SYSTEMTAP_DIR)/ssl
-# Compare two arrays. If equal, return 1, otherwise 0.
-# (Borrowed from http://wiki.tcl.tk/1032.)
-proc array_compare {array1 array2} {
- upvar 1 $array1 foo $array2 bar
+# arr given as list (e.g. [array_has [array get myarr] elem])
+proc array_has {arr elem} {
- if {![array exists foo]} {
- return -code error "$array1 is not an array"
- }
- if {![array exists bar]} {
- return -code error "$array2 is not an array"
- }
- if {[array size foo] != [array size bar]} {
- return 0
- }
+ array set foo $arr
if {[array size foo] == 0} {
+ return 0
+ }
+
+ foreach {key val} [array get foo] {
+ if {[string equal $val $elem]} {
+ return 1
+ }
+ }
+
+ return 0
+}
+
+# Check if array1 is a subset of array2. Returns 1 if yes, otherwise 0.
+# (Modified from http://wiki.tcl.tk/1032.)
+proc array_in {array1 array2} {
+ upvar 1 $array1 sub $array2 super
+
+ if {![array exists sub]} {
+ return -code error "$array1 is not an array"
+ }
+ if {![array exists super]} {
+ return -code error "$array2 is not an array"
+ }
+ if {[array size sub] > [array size super]} {
+ return 0
+ }
+ if {[array size sub] == 0} {
return 1
}
- set keys [lsort -unique [concat [array names foo] [array names bar]]]
- if {[llength $keys] != [array size foo]} {
- return 0
- }
-
- foreach key $keys {
- if {$foo($key) ne $bar($key)} {
+ foreach key [array names sub] {
+ if {![array_has [array get super] $sub($key)]} {
return 0
}
}
return 1
}
+# Check if array1 and array2 have all the same elements
+proc array_equal {array1 array2} {
+ upvar 1 $array1 foo $array2 bar
+ return [array_in foo bar] \
+ && [array_in bar foo]
+}
+
+# Returns the union of the three arrays
+proc array_union {array1 array2 array3} {
+ upvar 1 $array1 foo $array2 bar $array3 baz
+ array unset ::union
+
+ if {![array exists foo]} {
+ return -code error "$array1 is not an array"
+ }
+ if {![array exists bar]} {
+ return -code error "$array2 is not an array"
+ }
+ if {![array exists baz]} {
+ return -code error "$array3 is not an array"
+ }
+
+ set n 0
+ foreach key [array names foo] {
+ set ::union($n) $foo($key)
+ incr n
+ }
+ foreach key [array names bar] {
+ if {![array_has [array get ::union] $bar($key)]} {
+ set ::union($n) $bar($key)
+ incr n
+ }
+ }
+ foreach key [array names baz] {
+ if {![array_has [array get ::union] $baz($key)]} {
+ set ::union($n) $baz($key)
+ incr n
+ }
+ }
+}
+
+# Returns all the elements in array_new not in array_old
+proc array_diff {array_new array_old} {
+ upvar 1 $array_new anew $array_old aold
+ array unset ::diff
+
+ if {![array exists anew]} {
+ return -code error "$array_new is not an array"
+ }
+ if {![array exists aold]} {
+ return -code error "$array_old is not an array"
+ }
+
+ set n 0
+ foreach key [array names anew] {
+ if {![array_has [array get aold] $anew($key)]} {
+ set ::diff($n) $anew($key)
+ incr n
+ }
+ }
+}
+
# Test the --list-servers option and return an array of the servers found.
proc list_servers { TEST_NAME SERVER_SPEC args } {
set failed 0
@@ -82,7 +159,6 @@ proc list_servers { TEST_NAME SERVER_SPEC args } {
# Sometimes, we'll see a server running from the last test, if it
# hasn't quite died yet. So, make sure we get the same result twice.
list_servers "List existing online servers" online
-array unset eos1
array set existing_online_servers [array get servers]
set i 0
while {1} {
@@ -94,9 +170,9 @@ while {1} {
fail "List existing online servers: never got stable"
return
}
-
+
verbose -log "verify existing online servers - attempt $i: [array size existing_online_servers] [array size eos2]"
- if {[array_compare existing_online_servers eos2]} {
+ if {[array_equal existing_online_servers eos2]} {
# Arrays are equal, we're done
break
}
@@ -120,37 +196,23 @@ list_servers "List all existing servers" all
array unset all_existing_servers
array set all_existing_servers [array get servers]
-set test "Verify existing online server list"
-if {[array_compare existing_online_servers all_existing_servers]} {
- pass "$test"
-} else {
- fail "$test"
-}
+# First we create a union
+array_union existing_online_servers \
+ existing_trusted_servers \
+ existing_signing_servers
+array set existing_unioned_servers [array get union]
-set test "Verify existing trusted server list"
-if {[array_compare existing_trusted_servers all_existing_servers]} {
- pass "$test"
-} else {
- fail "$test"
-}
-
-set test "Verify existing signing server list"
-if {[array_compare existing_signing_servers all_existing_servers]} {
- pass "$test"
-} else {
- fail "$test"
-}
-
-set test "Verify all existing server list"
-if {[array_compare existing_online_servers all_existing_servers]} {
+# Now we can compare
+set test "Verify existing server list"
+if {[array_equal existing_unioned_servers all_existing_servers]} {
pass "$test"
} else {
fail "$test"
}
list_servers "List existing online servers (before start)" online
-array unset existing_online_servers1
-array set existing_online_servers1 [array get servers]
+array unset existing_online_servers
+array set existing_online_servers [array get servers]
# Now start our own server and make sure we can work with it.
if {! [setup_server] || $avahi_ok_p != 1} {
@@ -159,31 +221,22 @@ if {! [setup_server] || $avahi_ok_p != 1} {
}
# Our server should now appear online, separate from the previously discovered
-# online servers. Note that our server could generate serveral listings
-# because it could appear at more than one ip address,
+# online servers. Note that our server could generate serveral listings because
+# it could appear at more than one ip address,
list_servers "List current online servers" online
array unset current_online_servers
array set current_online_servers [array get servers]
+# array_diff will give us all the servers in current not in existing
+array_diff current_online_servers existing_online_servers
+array unset new_online_servers
+array set new_online_servers [array get diff]
+
set test "New online servers"
-set n 0
-foreach idx1 [array names current_online_servers] {
- set found 0
- foreach idx2 [array names existing_online_servers] {
- if {"$existing_online_servers($idx2)" == "$current_online_servers($idx1)"} {
- set found 1
- break
- }
- }
- if {$found == 0} {
- set new_online_servers($n) "$current_online_servers($idx1)"
- incr n
- }
-}
-if {$n == 0} {
- fail "$test"
-} else {
+if {[array size new_online_servers] > 0} {
pass "$test"
+} else {
+ fail "$test"
}
# Our server should now be trusted, separate from the previously discovered
@@ -192,48 +245,27 @@ list_servers "List current trusted servers" online,trusted
array unset current_trusted_servers
array set current_trusted_servers [array get servers]
+# array_diff will give us all the servers in current not in existing
+array_diff current_trusted_servers existing_trusted_servers
+array unset new_trusted_servers
+array set new_trusted_servers [array get diff]
+
set test "New trusted servers"
-set n 0
-foreach idx1 [array names current_trusted_servers] {
- set found 0
- foreach idx2 [array names existing_trusted_servers] {
- if {"$existing_trusted_servers($idx2)" == "$current_trusted_servers($idx1)"} {
- set found 1
- break
- }
- }
- if {$found == 0} {
- set new_trusted_servers($n) "$current_trusted_servers($idx1)"
- incr n
- }
-}
-if {$n == 0} {
- fail "$test"
-} else {
+if {[array size new_trusted_servers] > 0} {
pass "$test"
+} else {
+ fail "$test"
}
# The new servers should automatically be trusted, so the new_trusted_servers
-# array should be a subset of the new_online_servers
-# array, but not necessarilty vice-versa, since new servers may have come
-# online independently of our testing.
+# array should be a subset of the new_online_servers array, but not necessarily
+# vice-versa, since new servers may have come online independently of our
+# testing.
set test "Verify new trusted server list"
-set failed 0
-foreach idx1 [array names new_trusted_servers] {
- set found 0
- foreach idx2 [array names new_online_servers] {
- if {"$new_trusted_servers($idx1)" == "$new_online_servers($idx2)"} {
- set found 1
- break
- }
- }
- if {$found == 0} {
- set failed 1
- fail "$test $idx1"
- }
-}
-if {$failed == 0} {
+if {[array_in new_trusted_servers new_online_servers]} {
pass "$test"
+} else {
+ fail "$test"
}
# The newly trusted servers represent the server we just started.
@@ -247,7 +279,7 @@ array unset current_signing_servers
array set current_signing_servers [array get servers]
set test "No new signing servers"
-if {[array_compare current_signing_servers existing_signing_servers]} {
+if {[array_equal current_signing_servers existing_signing_servers]} {
pass "$test"
} else {
fail "$test"
@@ -287,7 +319,7 @@ array unset current_trusted_servers
array set current_trusted_servers [array get servers]
set test "No longer trusted after revokation by host name"
-if {[array_compare current_trusted_servers existing_trusted_servers]} {
+if {[array_equal current_trusted_servers existing_trusted_servers]} {
pass "$test"
} else {
fail "$test"
@@ -320,54 +352,24 @@ list_servers "List current trusted servers after reinstatement by ip address" on
array unset current_trusted_servers
array set current_trusted_servers [array get servers]
+array_diff current_trusted_servers existing_trusted_servers
+array unset new_trusted_servers
+array set new_trusted_servers [array get diff]
+
set test "New trusted servers after reinstatement by ip address"
-array unset new_trusted_servers
-set n 0
-foreach idx1 [array names current_trusted_servers] {
- set found 0
- foreach idx2 [array names existing_trusted_servers] {
- if {"$existing_trusted_servers($idx2)" == "$current_trusted_servers($idx1)"} {
- set found 1
- break
- }
- }
- if {$found == 0} {
- set new_trusted_servers($n) "$current_trusted_servers($idx1)"
- incr n
- }
-}
-if {$n == 0} {
- fail "$test"
-} else {
+if {[array size new_trusted_servers] > 0} {
pass "$test"
+} else {
+ fail "$test"
}
# The new_trusted_servers array should now match the our_servers array, since
# the our_servers array is a copy of the original new_trusted_servers array.
-set test "Number of new trusted servers matches after reinstatement by ip address"
-if {[array size new_trusted_servers] == [array size our_servers]} {
- pass "$test"
-} else {
- fail "$test"
-}
set test "New trusted servers matches after reinstatement by ip address"
-set n 0
-foreach idx1 [array names new_trusted_servers] {
- set found 0
- foreach idx2 [array names our_servers] {
- if {"$our_servers($idx2)" == "$new_trusted_servers($idx1)"} {
- set found 1
- break
- }
- }
- if {$found == 1} {
- incr n
- }
-}
-if {$n != [array size new_trusted_servers]} {
- fail "$test"
-} else {
+if {[array_equal new_trusted_servers our_servers]} {
pass "$test"
+} else {
+ fail "$test"
}
# Trust our server as a module signer. This must be done as root. Specify
@@ -394,28 +396,18 @@ list_servers "List current online signing servers" online,signer
array unset current_signing_servers
array set current_signing_servers [array get servers]
+array_diff current_signing_servers existing_signing_servers
+array unset new_signing_servers
+array set new_signing_servers [array get diff]
+
set test "New signing servers"
-set n 0
-foreach idx1 [array names current_signing_servers] {
- set found 0
- foreach idx2 [array names existing_signing_servers] {
- if {"$existing_signing_servers($idx2)" == "$current_signing_servers($idx1)"} {
- set found 1
- break
- }
- }
- if {$found == 0} {
- set new_signing_servers($n) "$current_signing_servers($idx1)"
- incr n
- }
-}
if {$effective_pid == 0} {
setup_xfail *-*-*
}
-if {$n == 0} {
- fail "$test"
-} else {
+if {[array size new_signing_servers] > 0} {
pass "$test"
+} else {
+ fail "$test"
}
# The new_signing_servers array should now match the our_servers array, since
@@ -428,26 +420,13 @@ if {$effective_pid == 0} {
if {[array size new_signing_servers] == [array size our_servers]} {
pass "$test"
set test "New signing servers matches"
- set n 0
- foreach idx1 [array names new_signing_servers] {
- set found 0
- foreach idx2 [array names our_servers] {
- if {"$our_servers($idx2)" == "$new_signing_servers($idx1)"} {
- set found 1
- break
- }
- }
- if {$found == 1} {
- incr n
- }
- }
if {$effective_pid == 0} {
setup_xfail *-*-*
}
- if {$n != [array size new_signing_servers]} {
- fail "$test"
- } else {
+ if {[array_equal new_signing_servers our_servers]} {
pass "$test"
+ } else {
+ fail "$test"
}
} else {
fail "$test"
@@ -594,7 +573,7 @@ array unset current_signing_servers
array set current_signing_servers [array get servers]
set test "No longer trusted as a signer after revokation"
-if {[array_compare current_signing_servers existing_signing_servers]} {
+if {[array_in current_signing_servers existing_signing_servers]} {
pass "$test"
} else {
fail "$test"
diff --git a/testsuite/systemtap.server/server_args.exp b/testsuite/systemtap.server/server_args.exp
index 2f5deed..91536a5 100644
--- a/testsuite/systemtap.server/server_args.exp
+++ b/testsuite/systemtap.server/server_args.exp
@@ -66,20 +66,23 @@ proc stap_direct_and_with_client {stap options} {
verbose -log $res_stap_client
# Now check the output
- set skip 0
+ set skip_hostname_mode 0
set n 0
set expected [split $res_stap "\n"]
set received [split $res_stap_client "\n"]
foreach line $received {
- # Instructed to skip a line?
- if {$skip} {
- set skip [expr $skip - 1]
- verbose -log "skipping: $line"
- continue
+ # Instructed to skip hostnames?
+ if {$skip_hostname_mode} {
+ if {[regexp {^ \S+$} $line]} {
+ verbose -log "skipping: $line"
+ continue
+ } else {
+ set skip_hostname_mode 0
+ }
}
# Ignore warnings about the domain name on the certificate not matching
if {[regexp {^WARNING: The domain name, [^,]*, does not match the DNS name\(s\) on the server certificate:} $line]} {
- set skip 1
+ set skip_hostname_mode 1
verbose -log "skipping: $line"
continue
}
diff --git a/testsuite/systemtap.server/server_concurrency.exp b/testsuite/systemtap.server/server_concurrency.exp
index dbacb51..a31415b 100644
--- a/testsuite/systemtap.server/server_concurrency.exp
+++ b/testsuite/systemtap.server/server_concurrency.exp
@@ -26,7 +26,7 @@ if {! [setup_server --max-threads 6]} {
set server_port 0
set f [open $logfile]
set matched 0
-verbose -log "Server ouput: "
+verbose -log "Server output: "
while {1} {
set line [gets $f]
if {[eof $f]} {
@@ -34,7 +34,7 @@ while {1} {
break
}
verbose -log "$line"
- if { [regexp {^.*Using network port (\d*)$} $line matched server_port ] } {
+ if { [regexp {^.*Using network address .+:(\d+)$} $line matched server_port ] } {
close $f
break
}
--
1.8.3.1