From 113ebd8533f7bea21fd50281cfbcc7d975b039e8 Mon Sep 17 00:00:00 2001 From: Mike Hibler <mike@flux.utah.edu> Date: Wed, 14 Aug 2002 06:51:43 +0000 Subject: [PATCH] First crack at authenticated ipod (APOD) --- ipod/GNUmakefile.in | 8 ++-- ipod/apod.in | 109 ++++++++++++++++++++++++++++++++++++++++++++ ipod/ipod.c | 54 ++++++++++++++++++---- 3 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 ipod/apod.in diff --git a/ipod/GNUmakefile.in b/ipod/GNUmakefile.in index 43ccfbf0b2..479666946b 100644 --- a/ipod/GNUmakefile.in +++ b/ipod/GNUmakefile.in @@ -10,7 +10,7 @@ SUBDIR = ipod include $(OBJDIR)/Makeconf -all: ipod +all: ipod apod include $(TESTBED_SRCDIR)/GNUmakerules @@ -19,12 +19,14 @@ CFLAGS= -g -O2 ipod: ipod.c $(CC) $(CFLAGS) -o ipod $< -install: all $(INSTALL_SBINDIR)/ipod +install: all $(INSTALL_SBINDIR)/ipod $(INSTALL_SBINDIR)/apod echo "Don't forget to do a post-install as root" post-install: chown root $(INSTALL_SBINDIR)/ipod chmod u+s $(INSTALL_SBINDIR)/ipod + chown root $(INSTALL_SBINDIR)/apod + chmod u+s $(INSTALL_SBINDIR)/apod # # Control node installation (okay, plastic) @@ -33,4 +35,4 @@ control-install: @echo "No wrapper for IPOD yet" clean: - rm -f ipod + rm -f ipod apod diff --git a/ipod/apod.in b/ipod/apod.in new file mode 100644 index 0000000000..5b17701f9d --- /dev/null +++ b/ipod/apod.in @@ -0,0 +1,109 @@ +#!/usr/bin/perl -wT + +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2002 University of Utah and the Flux Group. +# All rights reserved. +# + +use English; +use Getopt::Std; + +# +# Authenticated ICMP Ping of Death (APoD) +# A wrapper for the basic ipod program. Queries the DB for the 32 byte, +# one-time "hash" used to identify ourselves. +# +# usage: apod node [node ...] +# Exit value is the sum of the ipod exit codes. +# +sub usage() +{ + print STDOUT "Usage: apod node [node ...]\n"; + exit(-1); +} + +# +# Configure variables +# +my $TB = "@prefix@"; + +# +# Testbed Support libraries +# +use lib "@prefix@/lib"; +use libdb; +use libtestbed; + +#my $ipod = "$TB/sbin/ipod"; +my $ipod = "./ipod"; + +# un-taint path +$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin'; +delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; + +# Turn off line buffering on output +$| = 1; + +# +# We don't want to run this script unless its the real version. +# +if ($EUID != 0) { + die("Must be root! Maybe its a development version?"); +} + +if (@ARGV == 0) { + usage(); +} + +# Untaint the nodes. +foreach my $node ( @ARGV ) { + if ($node =~ /^([-\@\w]+)$/) { + $node = $1; + } + else { + die("Bad node name: $node."); + } + + push(@nodes, $node); +} + +# +# Verify permission to PoD these nodes. +# +if ($UID && !TBAdmin($UID) && + ! TBNodeAccessCheck($UID, TB_NODEACCESS_REBOOT, @nodes)) { + die("You do not have permission to APOD one (or more) ". + "of the nodes!\n"); +} + +# +# Smack em! +# +foreach my $node (@nodes) { + my $query_result = DBQueryFatal("select ipodhash from nodes ". + "where node_id='$node'"); + + if ($query_result->numrows != 1) { + print STDOUT "No ipodhash entry for node $node!?\n"; + exit(-1); + } + + my ($hash) = $query_result->fetchrow_array(); + my $didit = 0; + if (defined($hash)) { + if (system("echo $hash | $ipod -i - $node") != 0) { + print STDOUT "Authenticated IPOD failed on node $node"; + } else { + $didit = 1; + } + } else { + print STDOUT "No hash for node $node"; + } + if (!$didit) { + print STDOUT ", attempting naked IPOD...\n"; + if (system("$ipod $node") != 0) { + print STDOUT "IPOD failed on node $node\n"; + } + } +} diff --git a/ipod/ipod.c b/ipod/ipod.c index 220caae097..541015cbe1 100644 --- a/ipod/ipod.c +++ b/ipod/ipod.c @@ -27,8 +27,15 @@ #include <signal.h> #include <arpa/inet.h> +#define IPOD_ICMPTYPE 6 +#define IPOD_ICMPCODE 6 +#define IPOD_IPLEN 666 +#define IPOD_IDLEN 32 + int exit_on_first = 0; /* Find fastest, then quit */ int icmpid = 0; +static char myid[IPOD_IDLEN]; +static int myidlen = 0; u_short in_cksum(u_short *addr, int len); void icmpmap_init(); /* For getting information */ @@ -134,9 +141,7 @@ int makehosts(char **hostlist) void usage(char *prog) { - fprintf(stderr, - "%s target1 target2 ... targetn\n", - prog); + fprintf(stderr, "%s [ -i identityfile ] target [ target ... ]\n", prog); } /* @@ -163,10 +168,12 @@ void initpacket(char *buf, int querytype, struct in_addr fromaddr) icmp->icmp_seq = 1; icmp->icmp_cksum = 0; /* We'll compute it later. */ icmp->icmp_type = querytype; - icmp->icmp_code = 6; + icmp->icmp_code = IPOD_ICMPCODE; + if (myidlen) + memcpy(icmp->icmp_data, myid, myidlen); - icmplen = 666 - sizeof(struct ip); - ip->ip_len = sizeof(struct ip) + icmplen; + ip->ip_len = IPOD_IPLEN; + icmplen = IPOD_IPLEN - sizeof(struct ip); icmp->icmp_cksum = in_cksum((u_short *)icmp, icmplen); } @@ -258,15 +265,42 @@ main(int argc, char **argv) struct in_addr fromaddr; int timeout = 5; /* Default to 5 seconds */ int broadcast = 0; /* Should we wait for all responses? */ + int identityfile; fromaddr.s_addr = 0; progname = argv[0]; - querytype = 6; /* the magical death packet number */ - - argv++; - argc--; + querytype = IPOD_ICMPTYPE; /* the magical death packet number */ + + while ((ch = getopt(argc, argv, "i:")) != -1) + switch(ch) + { + case 'i': + if (optarg[0] == '-') + identityfile = 0; + else if ((identityfile = open(optarg, 0)) < 0) + { + perror(optarg); + exit(1); + } + myidlen = read(identityfile, myid, IPOD_IDLEN); + if (optarg[0] != '-') + close(identityfile); + if (myidlen != IPOD_IDLEN) + { + fprintf(stderr, "%s: cannot read %d-byte identity\n", + optarg[0] != '-' ? optarg : "<stdin>", IPOD_IDLEN); + exit(2); + } + break; + default: + usage(progname); + exit(-1); + } + + argc -= optind; + argv += optind; if (!argv[0] || !strlen(argv[0])) { usage(progname); -- GitLab