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