Commit c6150425 authored by Mike Hibler's avatar Mike Hibler

Support for per-experiment root keypairs (Round 1). See issue #302.

Provide automated setup of an ssh keypair enabling root to login without
a password between nodes. The biggest challenge here is to get the private
key onto nodes in such a way that a non-root user on those nodes cannot
obtain it. Otherwise that user would be able to ssh as root to any node.
This precludes simple distribution of the private key using tmcd/tmcc as
any user can do a tmcc (tmcd authentication is based on the node, not the
user).

This version does a post-imaging "push" of the private key from boss using
ssh. The key is pushed from tbswap after nodes are imaged but before the
event system, and thus any user startup scripts, are started. We actually
use "pssh" (really "pscp") to scale a bit better, so YOU MUST HAVE THE
PSSH PACKAGE INSTALLED. So be sure to do a:

    pkg install -r Emulab pssh

on your boss node. See the new utils/pushrootkeys.in script for more.

The public key is distributed via the "tmcc localization" command which
was already designed to handle adding multiple public keys to root's
authorized_keys file on a node.

This approach should be backward compatible with old images. I BUMPED THE
VERSION NUMBER OF TMCD so that newer clients can also get back (via
rc.localize) a list of keys and the names of the files they should be stashed
in. This is used to allow us to pass along the SSL and SSH versions of the
public key so that they can be placed in /root/.ssl/<node>.pub and
/root/.ssh/id_rsa.pub respectively. Note that this step is not necessary for
inter-node ssh to work.

Also passed along is an indication of whether the returned key is encrypted.
This might be used in Round 2 if we securely implant a shared secret on every
node at imaging time and then use that to encrypt the ssh private key such
that we can return it via rc.localize. But the client side script currently
does not implement any decryption, so the client side would need to be changed
again in this future.

The per experiment root keypair mechanism has been exposed to the user via
old school NS experiments right now by adding a node "rootkey" method. To
export the private key to "nodeA" and the public key to "nodeB" do:

    $nodeA rootkey private 1
    $nodeB rootkey public 1

This enables an asymmetric relationship such that "nodeA" can ssh into
"nodeB" as root but not vice-versa. For a symmetric relationship you would do:

    $nodeA rootkey private 1
    $nodeB rootkey private 1
    $nodeA rootkey public 1
    $nodeB rootkey public 1

These user specifications will be overridden by hardwired Emulab restrictions.
The current restrictions are that we do *not* distribute a root pubkey to
tainted nodes (as it opens a path to root on a node where no one should be
root) or any keys to firewall nodes, virtnode hosts, delay nodes, subbosses,
storagehosts, etc. which are not really part of the user topology.

For more on how we got here and what might happen in Round 2, see:

    emulab/emulab-devel#302
parent a7a3bc78
......@@ -46,4 +46,4 @@
* it in clientside/tmcc/common/libsetup.pm!
*/
#define DEFAULT_VERSION 2
#define CURRENT_VERSION 41
#define CURRENT_VERSION 42
......@@ -111,6 +111,7 @@ sub doboot()
{
my @tmccresults;
my @pubkeys = ();
my %keyfiles = ();
print STDOUT "Checking Testbed localization configuration ... \n";
......@@ -124,22 +125,57 @@ sub doboot()
#
# Go through and see what we got. For now, we expect just ssh keys
#
my $curkey = "";
foreach my $str (@tmccresults) {
if ($str =~ /^ROOTPUBKEY='(.*)'$/) {
push(@pubkeys, $1);
}
else {
warning("Bad localization line: $str");
if (!$curkey) {
if ($str =~ /^ROOTPUBKEY='(.*)'$/) {
push(@pubkeys, $1);
next;
}
if ($str =~ /^ROOTKEY='(.*)' KEYFILE='(.*)' ENCRYPTED='(.*)'/) {
$keyfiles{$2}{'key'} = $1;
$keyfiles{$2}{'encrypted'} = ($3 eq "no") ? 0 : 1;
next;
}
# XXX keys can also have embedded newlines
if ($str =~ /^ROOTKEY='(.*)$/) {
$curkey = "$1\n";
next;
}
} else {
if ($str =~ /^' KEYFILE='(.*)' ENCRYPTED='(.*)'/) {
$keyfiles{$1}{'key'} = $curkey;
$keyfiles{$1}{'encrypted'} = ($2 eq "no") ? 0 : 1;
$curkey = "";
next;
}
if ($str !~ /^(ROOTPUBKEY|ROOTKEY)=/) {
$curkey .= "$str";
next;
}
}
warning("Bad localization line: $str");
$curkey = "";
}
my %secured = ();
my $keydir = (WINDOWS() ? "/sshkeys/root" : "/root/.ssh");
if (securekeydir($keydir)) {
warning("Could not secure key directory '$keydir', ".
"will not store decrypted keys");
$secured{$keydir} = 0;
} else {
$secured{$keydir} = 1;
}
#
# Ensure that the given keys are in root's authorized_keys file,
# Ensure that the given pubkeys are in root's authorized_keys file,
# put them there if not.
#
if (@pubkeys) {
my $authdir = (WINDOWS() ? "/sshkeys/root" : "/root/.ssh");
my $authkeys = $authdir . "/authorized_keys";
my $authkeys = $keydir . "/authorized_keys";
my $authkeysold = $authkeys . ".old";
my $authkeysnew = $authkeys . ".new";
my $oldumask = umask(022);
......@@ -151,13 +187,6 @@ sub doboot()
#
if (STORAGEHOST()) {
$authkeysnew = "/tmp/authorized_keys.new";
} else {
if (! -e $authdir) {
system("mkdir -p $authdir") == 0
or fatal("Could not create $authdir");
system("chmod 700 $authdir") == 0
or fatal("Failed to chmod $authdir");
}
}
#
......@@ -177,7 +206,7 @@ sub doboot()
if (open(OKEYS, "<$authkeys")) {
while (my $key = <OKEYS>) {
chomp $key;
if ($key && $key !~ /^\s*#/ && exists($keyhash{$key})) {
if ($key && $key !~ /^\s*\#/ && exists($keyhash{$key})) {
$keyhash{$key} = 1;
}
push @lines, $key;
......@@ -201,7 +230,7 @@ sub doboot()
#
if (!$added) {
umask($oldumask);
return 0;
goto sshdone;
}
#
......@@ -229,8 +258,97 @@ sub doboot()
if (system("mv -f $authkeysnew $authkeys")) {
warning("Could not mv $authkeysnew to $authkeys");
}
}
sshdone:
# XXX don't know what this means for windows
if (WINDOWS()) {
return 0;
}
#
# Create standalone key files
#
foreach my $k (keys %keyfiles) {
my $file = "/root/$k";
($keydir = $file) =~ s#^(.*)/[^/]+$#$1#;
if (!exists($secured{$keydir})) {
if (securekeydir($keydir)) {
warning("Could not secure key directory '$keydir', ".
"will not store decrypted keys");
$secured{$keydir} = 0;
} else {
$secured{$keydir} = 1;
}
}
if ($keyfiles{$k}{'encrypted'}) {
if (!$secured{$keydir}) {
warning("will not decrypt key for '$file', skipped");
next;
}
# XXX decrypt key
warning("cannot decrypt keys yet, key for '$file' skipped");
next;
}
if (-e "$file" && unlink("$file") != 1) {
warning("could not unlink old $file, key skipped");
next;
}
if (!open(FD, ">$file") ||
!chown(0, 0, $file) || !chmod(0600, $file)) {
close(FD);
unlink($file);
warning("could not open $file, key skipped");
next;
}
print FD $keyfiles{$k}{'key'};
close(FD);
}
return 0;
}
sub securekeydir($)
{
my ($keydir) = @_;
my $oldumask = umask(022);
# XXX root FS is RO, nothing we can do; but nothing they can do either!
if (STORAGEHOST()) {
return 0;
}
if (! -e $keydir || -l $keydir || ! -d $keydir) {
unlink($keydir);
if (system("mkdir -p $keydir")) {
warning("could not create $keydir");
return -1;
}
}
#
# Be super paranoid. Even though keys won't work if the permissions
# and ownership are wrong, we could still wind up exposing keys.
#
my (undef,undef,$mode,undef,$uid,$gid) = stat($keydir);
if (($mode & 0777) != 0700) {
if (chmod(0700, $keydir) != 1) {
warning("could not chmod $keydir to 0700, ".
"private key not downloaded");
return -1;
}
}
if ($uid != 0 || $gid != 0) {
if (chown(0, 0, $keydir) != 1) {
warning("could not chown $keydir to 0:0, ".
"private key not downloaded");
return -1;
}
}
return 0;
}
#
......
......@@ -84,7 +84,7 @@ use librc;
# IMPORTANT NOTE: if you change the version here, you must also change it
# in clientside/lib/tmcd/tmcd.h!
#
sub TMCD_VERSION() { 41; };
sub TMCD_VERSION() { 42; };
libtmcc::configtmcc("version", TMCD_VERSION());
# Control tmcc timeout.
......
......@@ -50,6 +50,7 @@ my $LOADERCONF = "/boot/loader.conf";
my $PUBSUBCONF = "/usr/local/etc/pubsubd.conf";
my $PUBSUBEXPR = "/usr/local/etc/pubsubd.expr";
my $ROOTSSHDIR = "/root/.ssh";
my $ROOTSSLDIR = "/root/.ssl";
#
#
......@@ -247,15 +248,20 @@ if (-f $HISTORY) {
}
#
# Remove /root/.ssh and then regenerate an empty directory.
# Remove /root/.ssh and .ssl and then regenerate empty directories.
# We don't want any Utah specific keys tainting the images.
#
print "Cleaning root's .ssh directory ...\n";
print "Cleaning root's .ssh/ssl directories ...\n";
if (system("rm -rf $ROOTSSHDIR") ||
system("mkdir -p -m 700 $ROOTSSHDIR") ||
system("chown root:wheel $ROOTSSHDIR")) {
die("Could not clean root .ssh directory");
}
if (system("rm -rf $ROOTSSLDIR") ||
system("mkdir -p -m 700 $ROOTSSLDIR") ||
system("chown root:wheel $ROOTSSLDIR")) {
die("Could not clean root .ssl directory");
}
#
# XXX unlike the root .ssh directory above, the proper host keys will
......
......@@ -54,6 +54,7 @@ my $GRUBDEF = "/etc/default/grub";
my $PUBSUBCONF = "/usr/local/etc/pubsubd.conf";
my $PUBSUBEXPR = "/usr/local/etc/pubsubd.expr";
my $ROOTSSHDIR = "/root/.ssh";
my $ROOTSSLDIR = "/root/.ssl";
#
# Dead wood in $BINDIR
......@@ -353,15 +354,20 @@ if (-f "/root/$HISTORY") {
}
#
# Remove /root/.ssh and then regenerate an empty directory.
# Remove /root/.ssh and .ssl and then regenerate empty directories.
# We don't want any Utah specific keys tainting the images.
#
print "Cleaning root's .ssh directory ...\n";
print "Cleaning root's .ssh/ssl directories ...\n";
if (system("rm -rf $ROOTSSHDIR") ||
system("mkdir -p -m 700 $ROOTSSHDIR") ||
system("chown root:root $ROOTSSHDIR")) {
die("Could not clean root .ssh directory");
}
if (system("rm -rf $ROOTSSLDIR") ||
system("mkdir -p -m 700 $ROOTSSLDIR") ||
system("chown root:root $ROOTSSLDIR")) {
die("Could not clean root .ssl directory");
}
#
# XXX unlike the root .ssh directory above, the proper host keys will
......
......@@ -6688,5 +6688,45 @@ sub GenerateKeys($)
return 0;
}
#
# Return the per-experiment private key.
#
sub GetPrivkey($)
{
my ($self) = @_;
my $key = "";
# Must be a real reference.
return -1
if (! ref($self));
my $idx = $self->idx();
my $result = DBQueryWarn("select rsa_privkey from experiment_keys ".
"where exptidx='$idx'");
if ($result && $result->numrows) {
($key) = $result->fetchrow_array();
}
return $key;
}
#
# For all nodes in the experiment, determine which should receive
# per-experiment root private/public keys based on what the user wants
# and modified by Emulab policy (as encoded in Node::InitKeyDist).
#
sub InitKeyDist($)
{
my ($self) = @_;
my @nodelist = $self->NodeList();
foreach my $node (@nodelist) {
$node->InitKeyDist($self);
}
return 0;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -1346,6 +1346,121 @@ sub OnSharedNode($) {
return 0;
}
#
# This function takes the user-provided values for root key distribution
# from virt_nodes and adjusts them according to system restrictions, putting
# the result into the reserved table. The Get/Set accessor functions below
# use the values from reserved.
#
# The current restrictions are that we do *not* distribute a root pubkey
# to tainted nodes (as it opens a path to root on a node where no one should
# be root) or any keys to firewall nodes, virtnode hosts, delay nodes,
# subbosses, storagehosts, etc. which are not really part of the user
# topology.
#
sub InitKeyDist($;$)
{
my ($self,$experiment) = @_;
my ($priv,$pub);
return -1
if (!ref($self) || !$self->IsReserved());
if (!$experiment) {
$experiment = $self->Reservation();
return -1
if (!$experiment);
}
# XXX only PC class nodes for now, since we have to ssh to it
if ($self->class ne "pc") {
$priv = $pub = 0;
goto done;
}
my $node_id = $self->node_id();
# Get user-supplied values from virt_nodes
my $result =
DBQueryWarn("select v.rootkey_private,v.rootkey_public ".
" from virt_nodes as v, reserved as r ".
" where v.exptidx=r.exptidx and v.vname=r.vname ".
" and r.node_id='$node_id'");
if ($result && $result->numrows > 0) {
($priv, $pub) = $result->fetchrow_array();
my $fwnode;
# tainted node: no pub key
if ($self->IsTainted()) {
$pub = 0;
}
# special hosts: no keys at all
elsif ($self->erole() ne TBDB_RSRVROLE_NODE()) {
$priv = $pub = 0;
}
# firewall node for an experiment: no keys at all
elsif ($experiment->IsFirewalled(\$fwnode) && $fwnode eq $node_id) {
$priv = $pub = 0;
}
}
done:
return $self->SetKeyDist($priv, $pub);
}
sub GetKeyDist($$$)
{
my ($self,$privref,$pubref) = @_;
return -1
if (!ref($self));
return -1
if (! $self->IsReserved());
if ($privref) {
$$privref = ($self->{"RSRV"}->{'rootkey_private'} ? 1 : 0);
}
if ($pubref) {
$$pubref = ($self->{"RSRV"}->{'rootkey_public'} ? 1 : 0);
}
return 0;
}
sub SetKeyDist($$$)
{
my ($self,$privval,$pubval) = @_;
return -1
if (!ref($self));
return -1
if (! $self->IsReserved());
my $clause = "";
if (defined($privval)) {
$privval = 1
if ($privval != 0);
$clause = "rootkey_private=$privval";
}
if (defined($pubval)) {
$pubval = 1
if ($pubval != 0);
$clause .= ","
if ($clause);
$clause .= "rootkey_public=$pubval";
}
if ($clause) {
my $node_id = $self->node_id();
DBQueryWarn("update reserved set $clause where node_id='$node_id'")
or return -1;
$self->FlushReserved();
}
return 0;
}
#
# Load all attributes from the node_attributes table,
#
......@@ -4092,13 +4207,21 @@ sub SetTaintStates($@) {
my ($self, @taint_states) = @_;
require libTaintStates;
return libTaintStates::SetTaintStates($self, @taint_states);
my $rv = libTaintStates::SetTaintStates($self, @taint_states);
if (!$rv && libTaintStates::IsTainted($self)) {
$self->SetKeyDist(undef, 0);
}
return $rv;
}
sub AddTaintState($$) {
my ($self, $taint) = @_;
require libTaintStates;
return libTaintStates::AddTaintState($self, $taint);
my $rv = libTaintStates::AddTaintState($self, $taint);
if (!$rv && libTaintStates::IsTainted($self)) {
$self->SetKeyDist(undef, 0);
}
return $rv;
}
sub RemoveTaintState($;$) {
my ($self, $taint) = @_;
......@@ -4110,7 +4233,11 @@ sub InheritTaintStates($$) {
my ($self, $osimage) = @_;
require libTaintStates;
return libTaintStates::InheritTaintStates($self, $osimage);
my $rv = libTaintStates::InheritTaintStates($self, $osimage);
if (!$rv && libTaintStates::IsTainted($self)) {
$self->SetKeyDist(undef, 0);
}
return $rv;
}
......
......@@ -94,6 +94,7 @@ RUN_DEPENDS+= \
libtool:${PORTSDIR}/devel/libtool \
neato:${PORTSDIR}/graphics/graphviz \
otclsh:${PORTSDIR}/misc/otcl \
pssh:${PORTSDIR}/security/pssh \
rpm:${PORTSDIR}/archivers/rpm4 \
rrdtool:${PORTSDIR}/databases/rrdtool \
rsync:${PORTSDIR}/net/rsync \
......
......@@ -4543,6 +4543,8 @@ CREATE TABLE `reserved` (
`external_resource_key` tinytext,
`tmcd_redirect` tinytext,
`sharing_mode` varchar(32) default NULL,
`rootkey_private` tinyint(1) NOT NULL default '0',
`rootkey_public` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`node_id`),
UNIQUE KEY `vname` (`pid`,`eid`,`vname`),
UNIQUE KEY `vname2` (`exptidx`,`vname`),
......@@ -5754,6 +5756,8 @@ CREATE TABLE `virt_nodes` (
`firewall_style` tinytext,
`firewall_log` tinytext,
`nfsmounts` enum('emulabdefault','genidefault','all','none') default NULL,
`rootkey_private` tinyint(1) NOT NULL default '0',
`rootkey_public` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`exptidx`,`vname`),
UNIQUE KEY `pideid` (`pid`,`eid`,`vname`),
KEY `pid` (`pid`,`eid`,`vname`)
......
......@@ -942,6 +942,8 @@ REPLACE INTO table_regex VALUES ('virt_nodes','sharing_mode','text','regex','^[-
REPLACE INTO table_regex VALUES ('virt_nodes','osname','text','regex','^((([-\\w]+\\/{0,1})[-\\w\\.+]+(:\\d+){0,1})|((http|https|ftp)\\:\\/\\/[-\\w\\.\\/\\@\\:\\~\\?\\=\\&]*))$',2,128,NULL);
REPLACE INTO table_regex VALUES ('virt_nodes','parent_osname','text','redirect','virt_nodes:osname',2,128,NULL);
REPLACE INTO table_regex VALUES ('virt_nodes','nfsmounts','text','redirect','experiments:nfsmounts',0,0,NULL);
REPLACE INTO table_regex VALUES ('virt_nodes','rootkey_private','int','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('virt_nodes','rootkey_public','int','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('virt_programs','pid','text','redirect','projects:pid',0,0,NULL);
REPLACE INTO table_regex VALUES ('virt_programs','eid','text','redirect','experiments:eid',0,0,NULL);
REPLACE INTO table_regex VALUES ('virt_programs','vnode','text','redirect','virt_nodes:vname',0,0,NULL);
......
#
# Add experiment_keys slot to reserved table.
#
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (!DBSlotExists("virt_nodes", "rootkey_private")) {
DBQueryFatal("alter table virt_nodes add `rootkey_private` ".
" tinyint(1) NOT NULL default '0'");
DBQueryFatal("alter table virt_nodes add `rootkey_public` ".
" tinyint(1) NOT NULL default '0'");
}
if (!DBSlotExists("reserved", "rootkey_private")) {
DBQueryFatal("alter table reserved add `rootkey_private` ".
" tinyint(1) NOT NULL default '0'");
DBQueryFatal("alter table reserved add `rootkey_public` ".
" tinyint(1) NOT NULL default '0'");
}
DBQueryFatal("REPLACE INTO table_regex VALUES ".
"('virt_nodes','rootkey_private','int','redirect',".
"'default:boolean',0,0,NULL)");
DBQueryFatal("REPLACE INTO table_regex VALUES ".
"('virt_nodes','rootkey_public','int','redirect',".
"'default:boolean',0,0,NULL)");
return 0;
}
1;
# -*- tcl -*-
#
# Copyright (c) 2000-2014, 2016 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -159,6 +159,10 @@ Node instproc init {s} {
$self set next_rule 100
$self instvar fw_rules
array set fw_rules {}
# Distribution of per-experiment root keypair
$self set rootkey_private 0
$self set rootkey_public 0
}
Bridge instproc init {s} {
......@@ -244,6 +248,8 @@ Node instproc updatedb {DB} {
$self instvar topo
$self instvar fw_style
$self instvar fw_rules
$self instvar rootkey_private
$self instvar rootkey_public
$self instvar X_
$self instvar Y_
$self instvar orientation_
......@@ -433,6 +439,11 @@ Node instproc updatedb {DB} {
lappend values $fw_style
}
lappend fields "rootkey_private"
lappend values $rootkey_private
lappend fields "rootkey_public"
lappend values $rootkey_public
$sim spitxml_data "virt_nodes" $fields $values
if {$topo != "" && ($type == "robot" || $hwtype_class($type) == "robot")} {
......@@ -954,6 +965,25 @@ Node instproc add-rule {rule} {
incr next_rule
}
Node instproc rootkey {key onoff} {
$self instvar rootkey_public
$self instvar rootkey_private
if {$key != "public" && $key != "private"} {
perror "\[rootkey] key must be public or private"
return
}
if {$onoff != 0 && $onoff != 1} {
perror "\[rootkey] value must be 0/1"
return
}
if {$key == "public"} {
set rootkey_public $onoff
} elseif {$key == "private"} {
set rootkey_private $onoff
}
}
#
# Add a link to this bridge.
#
......
......@@ -63,6 +63,7 @@ my $wrapper = "$TBROOT/libexec/assign_wrapper";
my $SNMPIT = "$TBROOT/bin/snmpit";
my $RFLINKS = "$TBROOT/bin/rflinks";
my $IMAGESETUP = "$TBROOT/sbin/image_setup";
my $PUSHROOTKEY = "$TBROOT/sbin/pushrootkey";
my $portstats = "$TBROOT/bin/portstats";
my $TCPP = "$TBROOT/sbin/tcpp";
my $NFSTRACESUPPORT= @NFSTRACESUPPORT@;
......@@ -1385,6 +1386,13 @@ sub doSwapin($) {
}
TBDebugTimeStamp("named finished");
#
# Determine the distribution of per-experiment root private/public keys
# to the experiment nodes.
#
print "Determining root keypair distribution.\n";
$experiment->InitKeyDist();
if ($NFSTRACESUPPORT) {
print "Cleaning NFS traces.\n";
TBDebugTimeStamp("nfstrace gc started");
......@@ -1661,6 +1669,18 @@ sub doSwapin($) {
TBDebugTimeStamp("snmpit finished");
}
#
# Before we fire off any async activity, push out any experiment
# specific root private key.
#
my $privkey = $experiment->GetPrivkey();
if (-x $PUSHROOTKEY && $privkey) {
print "Pushing per-experiment root private key.\n";
if (system("$PUSHROOTKEY -e $pid/$eid")) {
tbwarn "Could not push private key, this may cause problems!";
}
}
#
# Okay, start the event system now that we know all the nodes have
# rebooted (os_setup is done). This only takes a moment (puts itself
......
......@@ -174,6 +174,12 @@ CHECKMASK(char *arg)
#define HAS_ALL_TAINTS(tset, tcheck) ((tset & tcheck) == tcheck)
#define HAS_TAINT(tset, tcheck) HAS_ALL_TAINTS(tset, tcheck)
/* Per-experiment root keypair support */
#define TB_ROOTKEYS_NONE 0
#define TB_ROOTKEYS_PRIVATE 1
#define TB_ROOTKEYS_PUBLIC 2
#define TB_ROOTKEYS_BOTH 3
typedef struct {
char pid[TBDB_FLEN_PID];
char gid[TBDB_FLEN_GID];
......@@ -259,8 +265,9 @@ typedef struct {
int genisliver_idx;
int geniflags;
int isnonlocal_pid;
unsigned short taintstates;
unsigned short experiment_keys;
char nfsmounts[TBDB_FLEN_TINYTEXT];
unsigned int taintstates;
char nodeid[TBDB_FLEN_NODEID];
char vnodeid[TBDB_FLEN_NODEID];
char pnodeid[TBDB_FLEN_NODEID]; /* XXX */
......@@ -7611,7 +7618,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" n.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole, n.taint_states, "
" n.nfsmounts,e.nfsmounts AS enfsmounts, "
" p.nonlocal_id,NULL "
" p.nonlocal_id,NULL, "
" r.rootkey_private,r.rootkey_public "
"FROM nodes AS n "
"LEFT JOIN reserved AS r ON "
" r.node_id=n.node_id "
......@@ -7642,7 +7650,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" (SELECT node_id FROM widearea_nodeinfo "
" WHERE privkey='%s') "
" AND notmcdinfo_types.attrvalue IS NULL",
43, nodekey);
45, nodekey);
}
else if (reqp->isvnode) {
char clause[BUFSIZ];
......@@ -7681,7 +7689,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" nv.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole, nv.taint_states, "
" nv.nfsmounts,e.nfsmounts AS enfsmounts, "
" p.nonlocal_id,va.attrvalue "
" p.nonlocal_id,va.attrvalue, "
" r.rootkey_private,r.rootkey_public "
"from nodes as nv "
"left join nodes as np on "
" np.node_id=nv.phys_nodeid "
......@@ -7708,7 +7717,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" va.vname=r.vname and "
" va.attrkey='routable_control_ip' "
"where nv.node_id='%s' and (%s)",
43, reqp->vnodeid, clause);
45, reqp->vnodeid, clause);
}
else {
char clause[BUFSIZ];
......@@ -7740,7 +7749,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" n.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole, n.taint_states, "
" n.nfsmounts,e.nfsmounts AS enfsmounts, "
" p.nonlocal_id,NULL "
" p.nonlocal_id,NULL, "
" r.rootkey_private,r.rootkey_public "
"from interfaces as i "
"left join nodes as n on n.node_id=i.node_id "
"left join reserved as r on "
......@@ -7770,7 +7780,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" on n.type=dedicated_wa_types.type "
"where (%s) "
" and notmcdinfo_types.attrvalue is NULL",
43, clause);
45, clause);
}
if (!res) {
......@@ -7943,6 +7953,13 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
else
reqp->isroutable_vnode = 0;
/* Which per-experiment root keys should be propogated if any */
reqp->experiment_keys = TB_ROOTKEYS_NONE;