diff --git a/tmcd/decls.h b/tmcd/decls.h index a99d03862c003c20fbd9921bdb50fef7ec918c0a..e2c2e46999eb95a50e82e2c2e75e1e9acf974b2e 100644 --- a/tmcd/decls.h +++ b/tmcd/decls.h @@ -4,9 +4,10 @@ * All rights reserved. */ -#define TBSERVER_PORT 7777 -#define TBSERVER_PORT2 14443 -#define MYBUFSIZE 2048 +#define TBSERVER_PORT 7777 +#define TBSERVER_PORT2 14443 +#define MYBUFSIZE 2048 +#define BOSSNODE_FILENAME "bossnode" /* * As the tmcd changes, incompatable changes with older version of diff --git a/tmcd/tmcc.c b/tmcd/tmcc.c index e2571f1efaac1e4f14159f4bac690e5238155c1f..53324ab0a06adcb5477af1b4fea574c8bf4dea7f 100644 --- a/tmcd/tmcc.c +++ b/tmcd/tmcc.c @@ -28,18 +28,22 @@ #include "config.h" #endif -#ifndef STANDALONE -#undef BOSSNODE -#endif -#ifdef BOSSNODE -#define DEFAULT_BOSSNODE BOSSNODE -#else -#define DEFAULT_BOSSNODE NULL -#endif -#ifndef BOSSNODEFILE -#define BOSSNODEFILE "/usr/local/etc/testbed/bossnode" +#undef BOSSNODE +#ifndef KEYFILE +#define KEYFILE "/etc/emulab.pkey" #endif +/* + * We search a couple of dirs for the bossnode file. + */ +static char *bossnodedirs[] = { + "/etc/testbed", + "/etc/rc.d/testbed", + "/usr/local/etc/testbed", + "/usr/local/etc/emulab", + 0 +}; + /* * Need to try several ports cause of firewalling. */ @@ -61,6 +65,7 @@ char *usagestr = " -p portnum Specify a port number to connect to\n" " -v versnum Specify a version number for tmcd\n" " -n vnodeid Specify the vnodeid\n" + " -k keyfile Specify the private keyfile\n" " -u Use UDP instead of TCP\n" " -t timeout Timeout waiting for the controller.\n" "\n"; @@ -81,10 +86,13 @@ main(int argc, char **argv) struct hostent *he; struct in_addr serverip; char buf[MYBUFSIZE], *bp, *response = ""; - char *bossnode = DEFAULT_BOSSNODE; + char *bossnode = NULL; int version = CURRENT_VERSION; char *vnodeid = NULL; + char *keyfile = NULL; + char *privkey = NULL; int waitfor = 0; + FILE *fp; #ifdef UDP int useudp = 0; #endif @@ -101,6 +109,9 @@ main(int argc, char **argv) case 'n': vnodeid = optarg; break; + case 'k': + keyfile = optarg; + break; case 'v': version = atoi(optarg); break; @@ -126,20 +137,30 @@ main(int argc, char **argv) * How do we find our bossnode? * * 1. Command line. - * 2. Compiled in. - * 3. /usr/local/etc/bossnode - * 4. nameserver goo below. + * 2. From a file in the list above. + * 3. nameserver goo below. */ if (!bossnode) { - FILE *fp; - - if ((fp = fopen(BOSSNODEFILE, "r")) != NULL) { - if (fgets(buf, sizeof(buf), fp)) { - if ((bp = strchr(buf, '\n'))) - *bp = (char) NULL; - bossnode = strdup(buf); + /* + * Search for the file. + */ + char **cp = bossnodedirs; + while (*cp) { + sprintf(buf, "%s/%s", *cp, BOSSNODE_FILENAME); + + if (access(buf, R_OK) == 0) + break; + cp++; + } + if (*cp) { + if ((fp = fopen(buf, "r")) != NULL) { + if (fgets(buf, sizeof(buf), fp)) { + if ((bp = strchr(buf, '\n'))) + *bp = (char) NULL; + bossnode = strdup(buf); + } + fclose(fp); } - fclose(fp); } } if (!bossnode) @@ -152,6 +173,28 @@ main(int argc, char **argv) exit(1); } + /* + * Grab the key. Its not an error if we do not find it. + */ + if (keyfile) { + /* Well, if one was specifed it has to exist. */ + if (access(keyfile, R_OK) < 0) { + perror("keyfile"); + exit(1); + } + } + else + keyfile = KEYFILE; + + if ((fp = fopen(keyfile, "r")) != NULL) { + if (fgets(buf, sizeof(buf), fp)) { + if ((bp = strchr(buf, '\n'))) + *bp = (char) NULL; + privkey = strdup(buf); + } + fclose(fp); + } + if (waitfor) { alarm(waitfor); } @@ -226,6 +269,11 @@ main(int argc, char **argv) sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid); } + /* Tack on privkey */ + if (privkey) { + sprintf(&buf[strlen(buf)], "PRIVKEY=%s ", privkey); + } + /* * Since we've gone through a getopt() pass, argv[0] is now the * first argument diff --git a/tmcd/tmcd.c b/tmcd/tmcd.c index 7b12060c9614a4cefe4daf278a27b61aa2f74a3a..54d32b9786d543fcb2c48911273fc753d9b9e95c 100644 --- a/tmcd/tmcd.c +++ b/tmcd/tmcd.c @@ -66,6 +66,7 @@ static int iptonodeid(struct in_addr, char *,char *,char *,char *,int *); static int nodeidtonickname(char *nodeid, char *nickname); static int nodeidtocontrolnet(char *nodeid, int *net); static int checkdbredirect(char *nodeid); +static int checkprivkey(struct in_addr, char *); static void tcpserver(int sock); static void udpserver(int sock); static int handle_request(int, struct sockaddr_in *, char *, int); @@ -262,6 +263,9 @@ main(int argc, char **argv) fgets(fshostid, HOSTID_SIZE, fp); if (rindex(fshostid, '\n')) { *rindex(fshostid, '\n') = 0; + if (debug) { + info("fshostid: %s\n", fshostid); + } } else { error("fshostid from %s may be corrupt: %s", @@ -489,11 +493,12 @@ static int handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) { struct sockaddr_in redirect_client; - int redirect = 0, isvnode = 0; + int redirect = 0, isvnode = 0, havekey = 0; char buf[BUFSIZ], *bp, *cp; char nodeid[TBDB_FLEN_NODEID]; char vnodeid[TBDB_FLEN_NODEID]; char class[TBDB_FLEN_NODECLASS]; + char privkey[TBDB_FLEN_PRIVKEY]; char type[TBDB_FLEN_NODETYPE]; int i, islocal, err = 0; int version = DEFAULT_VERSION; @@ -503,6 +508,20 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) */ bp = rdata; while ((bp = strsep(&rdata, " ")) != NULL) { + /* + * Look for PRIVKEY. + */ + if (sscanf(bp, "PRIVKEY=%64s", buf)) { + havekey = 1; + strncpy(privkey, buf, sizeof(privkey)); + + if (debug) { + info("PRIVKEY %s\n", buf); + } + continue; + } + + /* * Look for VERSION. */ @@ -651,6 +670,26 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) goto skipit; } + /* + * Do private key check. widearea nodes must report a private key + * It comes over ssl of course. At present we skip this check for + * ron nodes. + */ + if (!islocal) { + if (!havekey) { + error("%s: No privkey sent!\n", nodeid); + /* + * Skip. Okay, the problem is that the nodes out + * there are not reporting the key! + goto skipit; + */ + } + else if (checkprivkey(client->sin_addr, privkey)) { + error("%s: privkey mismatch: %s!\n", nodeid, privkey); + goto skipit; + } + } + /* * Figure out what command was given. */ @@ -2297,9 +2336,10 @@ COMMAND_PROTOTYPE(dosfshostid) signal(SIGALRM, dosfshostiddead); alarm(1); - unlink(dspath); - if (symlink(sfspath, dspath) < 0) + if (unlink(dspath) < 0 || + symlink(sfspath, dspath) < 0) { sfshostiddeadfl = 1; + } } alarm(0); if (sfshostiddeadfl) { @@ -3217,6 +3257,37 @@ checkdbredirect(char *nodeid) return 0; } +/* + * Check private key. + */ +static int +checkprivkey(struct in_addr ipaddr, char *privkey) +{ + MYSQL_RES *res; + MYSQL_ROW row; + + res = mydb_query("select privkey from widearea_privkeys " + "where IP='%s'", + 1, inet_ntoa(ipaddr)); + + if (!res) { + error("checkprivkey: %s: DB Error getting privkey!\n", + inet_ntoa(ipaddr)); + return 1; + } + + if (! (int)mysql_num_rows(res)) { + mysql_free_result(res); + return 1; + } + row = mysql_fetch_row(res); + mysql_free_result(res); + if (! row[0] || !row[0][0]) + return 1; + + return strcmp(privkey, row[0]); +} + #ifdef EVENTSYS /* * Connect to the event system. It's not an error to call this function if