From 40d072cf23a48bb9aaef5feb5338d0db8829bcc0 Mon Sep 17 00:00:00 2001 From: "Leigh B. Stoller" Date: Wed, 10 Apr 2002 17:27:35 +0000 Subject: [PATCH] A fair amount of cleanup, both of the ssl stuff and of tmcd in general. Deal with ssl/nossl clients; at Chad's suggestion add a small handshake tag to ssl enabled tmcc/tmcd which tells tmcd that it needs to enter full SSL mode. This allows old tmcc to connect to an ssl enabled tmcd, and still work okay. I've also ironed out the verification stuff. At the client, we make sure that the CommonName field of the peer cert maps to the same address that we connected to (bossnode). At the server, we check the OU field of the cert (we create the client certs with the OU field set to the node type; a convention I made up!). It must match the type of the node, as we get it from the nodes table. Also check the CommonName to make sure it matches our hostname. This is by no means bulletproof, but perfection is costly, and we don't have the money! Also cleaned up the REDIRECT testmode stuff. Instead of ifdef'ed under TESTMODE, leave it compiled in all the time, but only allow it from the local node (where tmcd is running). Mere users will not be able to access it, but testbed people can use it since they have accounts on the boss node. --- tmcd/GNUmakefile.in | 4 +- tmcd/decls.h | 5 +- tmcd/ssl.c | 189 ++++++++++++++++++++---- tmcd/ssl.h | 9 +- tmcd/tmcd.c | 341 ++++++++++++++++++-------------------------- 5 files changed, 313 insertions(+), 235 deletions(-) diff --git a/tmcd/GNUmakefile.in b/tmcd/GNUmakefile.in index d747f410a..3bb107da1 100644 --- a/tmcd/GNUmakefile.in +++ b/tmcd/GNUmakefile.in @@ -20,9 +20,9 @@ TMLIBS = ${OBJDIR}/lib/libtb/libtb.a # # For SSL enabled tmcd/tmcc # -#CFLAGS += -DWITHSSL -DETCDIR='"$(INSTALL_ETCDIR)"' +#CFLAGS += -DWITHSSL -DETCDIR='"$(INSTALL_ETCDIR)"' #TMLIBS += -lssl -lcrypto -#SSLOBJ = ssl.o +#SSLOBJ = ssl.o ifeq ($(EVENTSYS),1) TMCDCFLAGS = `elvin-config --cflags vin4c` \ diff --git a/tmcd/decls.h b/tmcd/decls.h index e4a89dc91..7f7b602d9 100644 --- a/tmcd/decls.h +++ b/tmcd/decls.h @@ -2,8 +2,8 @@ * Insert Copyright Here. */ -#define TBSERVER_PORT 7777 -#define MYBUFSIZE 2048 +#define TBSERVER_PORT 7777 +#define MYBUFSIZE 2048 /* * As the tmcd changes, incompatable changes with older version of @@ -18,6 +18,7 @@ * sure to change it there too! * * Note, this is assumed to be an integer. No need for 3.23.479 ... + * NB: See ron/libsetup.pm. That is version 4! I'll merge that in. */ #define DEFAULT_VERSION 2 #define CURRENT_VERSION 3 diff --git a/tmcd/ssl.c b/tmcd/ssl.c index ff6400856..76fac7f9a 100644 --- a/tmcd/ssl.c +++ b/tmcd/ssl.c @@ -12,10 +12,13 @@ */ #include #include +#include +#include #include #include #include #include +#include #include #include #include "decls.h" @@ -31,6 +34,11 @@ #define SERVER_CERTFILE "server.pem" #define CLIENT_CERTFILE "client.pem" +/* + * This is used by tmcd to determine if the connection is ssl or not. + */ +int isssl; + /* * On the client, we search a couple of dirs for the pem file. */ @@ -46,6 +54,8 @@ static char *clientcertdirs[] = { static SSL *ssl; static SSL_CTX *ctx; static int client = 0; +static char nosslbuf[MYBUFSIZE]; +static int nosslbuflen, nosslbufidx; static void tmcd_sslerror(); static void tmcd_sslprint(const char *fmt, ...); @@ -180,24 +190,49 @@ tmcd_client_sslinit(void) int tmcd_sslaccept(int sock, struct sockaddr *addr, socklen_t *addrlen) { - int newsock; + int newsock, cc; if ((newsock = accept(sock, addr, addrlen)) < 0) return -1; + /* + * Read the first bit. It indicates whether we need to SSL + * handshake or not. + */ + if ((cc = read(newsock, nosslbuf, sizeof(nosslbuf) - 1)) <= 0) { + error("sslaccept: reading request"); + if (cc == 0) + errno = EIO; + return -1; + } + if (strncmp(nosslbuf, SPEAKSSL, strlen(SPEAKSSL))) { + /* + * No ssl. Need to return this data on the next read. + * See below. + */ + isssl = 0; + nosslbuflen = cc; + nosslbufidx = 0; + return newsock; + } + isssl = 1; + nosslbuflen = 0; + if (! (ssl = SSL_new(ctx))) { tmcd_sslerror(); + errno = EIO; return -1; } if (! SSL_set_fd(ssl, newsock)) { tmcd_sslerror(); + errno = EIO; return -1; } if (SSL_accept(ssl) <= 0) { tmcd_sslerror(); + errno = EAUTH; return -1; } - tmcd_sslverify(newsock, 0); return newsock; } @@ -209,53 +244,136 @@ tmcd_sslaccept(int sock, struct sockaddr *addr, socklen_t *addrlen) int tmcd_sslconnect(int sock, const struct sockaddr *name, socklen_t namelen) { + char *cp = SPEAKSSL; + int cc; + X509 *peer; + char cname[256]; + struct hostent *he; + struct in_addr ipaddr; + if (connect(sock, name, namelen) < 0) return -1; + + /* + * Send our special tag which says we speak SSL. + */ + if ((cc = write(sock, cp, strlen(cp))) != strlen(cp)) { + if (cc >= 0) { + error("sslconnect: short write\n"); + errno = EIO; + } + return -1; + } if (! (ssl = SSL_new(ctx))) { tmcd_sslerror(); + errno = EIO; return -1; } if (! SSL_set_fd(ssl, sock)) { tmcd_sslerror(); + errno = EIO; return -1; } if (SSL_connect(ssl) <= 0) { tmcd_sslerror(); - return -1; + goto badauth; + } + + /* + * Do the verification dance. + */ + if (SSL_get_verify_result(ssl) != X509_V_OK) { + tmcd_sslprint("Certificate did not verify!\n"); + goto badauth; + } + + if (! (peer = SSL_get_peer_certificate(ssl))) { + tmcd_sslprint("No certificate was presented by the peer!\n"); + goto badauth; + } + + /* + * Grab the common name from the cert. + */ + X509_NAME_get_text_by_NID(X509_get_subject_name(peer), + NID_commonName, cname, sizeof(cname)); + + /* + * On the client, the common name must map to the same + * host we just connected to. This should be enough of + * a check? + */ + ipaddr = ((struct sockaddr_in *)name)->sin_addr; + + if (!(he = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET))) { + error("Could not reverse map %s: %s\n", + inet_ntoa(ipaddr), hstrerror(h_errno)); + goto badauth; + } + if (strcmp(he->h_name, cname)) { + error("Certificate commonname mismatch: %s!=%s\n", + he->h_name, cname); + goto badauth; } - tmcd_sslverify(sock, 0); return 0; + + badauth: + errno = EAUTH; + return -1; } /* - * Verify the certificate of the peer. + * Verify the certificate of the client. */ int -tmcd_sslverify(int sock, char *host) +tmcd_sslverify_client(char *nodeid, char *class, char *type, int islocal) { - X509 *peer; - char *cp, buf[256]; + X509 *peer; + char cname[256], unitname[256]; if (SSL_get_verify_result(ssl) != X509_V_OK) { - tmcd_sslprint("Certificate did not verify!\n"); - return 1; + error("sslverify: Certificate did not verify!\n"); + return -1; } if (! (peer = SSL_get_peer_certificate(ssl))) { - tmcd_sslprint("No certificate was presented by the peer!\n"); - return 1; + error("sslverify: No certificate presented!\n"); + return -1; } - if ((cp = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0))) { - printf("Peer subject: %s\n", cp); - free(cp); + /* + * Grab stuff from the cert. + */ + X509_NAME_get_text_by_NID(X509_get_subject_name(peer), + NID_organizationalUnitName, + unitname, sizeof(unitname)); + + X509_NAME_get_text_by_NID(X509_get_subject_name(peer), + NID_commonName, + cname, sizeof(cname)); + + /* + * On the server, things are a bit more difficult since + * we share a common cert locally and a per group cert remotely. + * + * Make sure common name matches. + */ + if (strcmp(cname, BOSSNODE)) { + error("sslverify: commonname mismatch: %s!=%s\n", + cname, BOSSNODE); + return -1; } - if ((cp = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0))) { - printf("Peer issuer: %s\n", cp); - free(cp); + /* + * If the node is remote, then the unitname must match the type. + * Simply a convention. + */ + if (!islocal && strcmp(unitname, type)) { + error("sslverify: unitname mismatch: %s!=%s\n", + unitname, type); + return -1; } return 0; @@ -272,8 +390,13 @@ tmcd_sslwrite(int sock, const void *buf, size_t nbytes) int cc; errno = 0; - if ((cc = SSL_write(ssl, buf, nbytes)) <= 0) { - if (cc < 0) { + if (isssl || client) + cc = SSL_write(ssl, buf, nbytes); + else + cc = write(sock, buf, nbytes); + + if (cc <= 0) { + if (cc < 0 && isssl) { tmcd_sslerror(); } return cc; @@ -287,11 +410,27 @@ tmcd_sslwrite(int sock, const void *buf, size_t nbytes) int tmcd_sslread(int sock, void *buf, size_t nbytes) { - int cc; + int cc = 0; + + if (nosslbuflen) { + char *bp = (char *) buf, *cp = &nosslbuf[nosslbufidx]; + + while (cc < nbytes && nosslbuflen) { + *bp = *cp; + bp++; cp++; cc++; + nosslbuflen--; nosslbufidx++; + } + return cc; + } errno = 0; - if ((cc = SSL_read(ssl, buf, nbytes)) <= 0) { - if (cc < 0) { + if (isssl || client) + cc = SSL_read(ssl, buf, nbytes); + else + cc = read(sock, buf, nbytes); + + if (cc <= 0) { + if (cc < 0 && isssl) { tmcd_sslerror(); } return cc; @@ -310,6 +449,7 @@ tmcd_sslclose(int sock) SSL_free(ssl); ssl = NULL; } + nosslbuflen = 0; close(sock); return 0; } @@ -345,8 +485,7 @@ tmcd_sslprint(const char *fmt, ...) if (client) { fputs(buf, stderr); - fputs("\n", stderr); } else - error("%s\n", buf); + error("%s", buf); } diff --git a/tmcd/ssl.h b/tmcd/ssl.h index 0284bb792..80c150337 100644 --- a/tmcd/ssl.h +++ b/tmcd/ssl.h @@ -9,7 +9,14 @@ int tmcd_sslconnect(int sock, const struct sockaddr *, socklen_t); int tmcd_sslwrite(int sock, const void *buf, size_t nbytes); int tmcd_sslread(int sock, void *buf, size_t nbytes); int tmcd_sslclose(int sock); -int tmcd_sslverify(int sock, char *host); +int tmcd_sslverify_client(char *, char *, char *, int); +int isssl; + +/* + * The client sends this tag to indicate that it is SSL capable. + * Only local nodes can skip SSL. Remote nodes must use SSL! + */ +#define SPEAKSSL "ISPEAKSSL_TMCDV10" /* * When compiled to use SSL, redefine the routines appropriately diff --git a/tmcd/tmcd.c b/tmcd/tmcd.c index 65bf304b1..a68a2c664 100644 --- a/tmcd/tmcd.c +++ b/tmcd/tmcd.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include "config.h" #include "ssl.h" #include "log.h" +#include "tbdefs.h" #ifdef EVENTSYS #include "event.h" @@ -42,14 +44,15 @@ #define DBNAME_SIZE 64 #define DEFAULT_DBNAME TBDBNAME -static int debug = 0; +int debug = 0; static int portnum = TBSERVER_PORT; static char dbname[DBNAME_SIZE]; +static struct in_addr myipaddr; static int nodeidtoexp(char *nodeid, char *pid, char *eid, char *gid); -static int iptonodeid(struct in_addr ipaddr, char *bufp); +static int iptonodeid(struct in_addr, char *, char *, char *, int *); static int nodeidtonickname(char *nodeid, char *nickname); static int nodeidtocontrolnet(char *nodeid, int *net); -static int checkdbredirect(struct in_addr ipaddr); +static int checkdbredirect(char *nodeid); static void tcpserver(int sock); static void udpserver(int sock); static int handle_request(int, struct sockaddr_in *, char *, int); @@ -76,7 +79,7 @@ static event_handle_t event_handle = NULL; */ #define COMMAND_PROTOTYPE(x) \ static int \ - x(int sock, struct in_addr ipaddr, char *rdata, int tcp, int vers) + x(int sock, char *nodeid, char *rdata, int tcp, int vers) COMMAND_PROTOTYPE(doreboot); COMMAND_PROTOTYPE(dostatus); @@ -104,7 +107,7 @@ COMMAND_PROTOTYPE(docreator); struct command { char *cmdname; - int (*func)(int, struct in_addr, char *, int, int); + int (*func)(int, char *, char *, int, int); } command_array[] = { { "reboot", doreboot }, { "status", dostatus }, @@ -161,8 +164,8 @@ static void cleanup() { signal(SIGHUP, SIG_IGN); - killpg(0, SIGHUP); killme = 1; + killpg(0, SIGHUP); } int @@ -173,6 +176,7 @@ main(int argc, char **argv) struct sockaddr_in name; FILE *fp; char buf[BUFSIZ]; + struct hostent *he; extern char build_info[]; while ((ch = getopt(argc, argv, "dp:c:")) != -1) @@ -215,6 +219,21 @@ main(int argc, char **argv) info("daemon starting (version %d)\n", CURRENT_VERSION); info("%s\n", build_info); + /* + * Grab our IP for security check below. + */ +#ifdef LBS + strcpy(buf, BOSSNODE); +#else + if (gethostname(buf, sizeof(buf)) < 0) + pfatal("getting hostname"); +#endif + if ((he = gethostbyname(buf)) == NULL) { + error("Could not get IP (%s) - %s\n", buf, hstrerror(h_errno)); + exit(1); + } + memcpy((char *)&myipaddr, he->h_addr, he->h_length); + /* * Setup TCP socket for incoming connections. */ @@ -343,7 +362,7 @@ main(int argc, char **argv) } /* - * Listen for UDP requests. This not a secure channel, and so this should + * Listen for UDP requests. This is not a secure channel, and so this should * eventually be killed off. */ static void @@ -375,8 +394,7 @@ udpserver(int sock) } /* - * Listen for TCP requests. This not a secure channel, and so this should - * eventually be killed off. + * Listen for TCP requests. */ static void tcpserver(int sock) @@ -421,7 +439,10 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) struct sockaddr_in redirect_client; int redirect = 0; char buf[BUFSIZ], *bp; - int i, cc, err = 0; + char nodeid[TBDB_FLEN_NODEID]; + char class[TBDB_FLEN_NODECLASS]; + char type[TBDB_FLEN_NODETYPE]; + int i, cc, islocal, err = 0; int version = DEFAULT_VERSION; cc = strlen(rdata); @@ -459,14 +480,24 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) bp++; } -#ifndef TESTMODE + /* Start with default DB */ + strcpy(dbname, DEFAULT_DBNAME); + /* - * IN TESTMODE, we allow redirect. - * Otherwise not since that would be a (minor) privacy - * risk, by allowing testbed nodes to get info for other - * nodes. + * Map the ip to a nodeid. */ - if (redirect) { + if (iptonodeid(client->sin_addr, nodeid, class, type, &islocal)) { + error("No such node: %s\n", inet_ntoa(client->sin_addr)); + goto skipit; + } + + /* + * Redirect is allowed from the local host only! + * I use this for testing. See below where I test redirect + * if the verification fails. + */ + if (redirect && + redirect_client.sin_addr.s_addr != myipaddr.s_addr) { char buf1[32], buf2[32]; strcpy(buf1, inet_ntoa(redirect_client.sin_addr)); @@ -475,21 +506,49 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) info("%s INVALID REDIRECT: %s\n", buf1, buf2); goto skipit; } + +#ifdef WITHSSL + /* + * If the connection is not SSL, then it must be a local node. + */ + if (isssl) { + if (tmcd_sslverify_client(nodeid, class, type, islocal)) { + error("%s: SSL verification failure\n", nodeid); + if (! redirect) + goto skipit; + } + } + else if (!islocal) { + error("%s: Remote node connected without SSL!\n", nodeid); + /* + * Allow for now, until ron nodes updated. + * if (! redirect) + * goto skipit; + */ + } +#else + /* + * When not compiled for ssl, do not allow remote connections. + */ + if (!islocal) { + error("%s: Remote node without SSL!\n", nodeid); + /* + * Allow for now, until ron nodes updated. + * if (! redirect) + * goto skipit; + */ + } #endif /* * Check for a redirect using the default DB. This allows * for a simple redirect to a secondary DB for testing. - * Not very general. Might change to full blown tmcd - * redirection at some point, but this is a very quick and - * easy hack. Upon return, the dbname has been changed if - * redirection is in force. + * Upon return, the dbname has been changed if redirected. */ - strcpy(dbname, DEFAULT_DBNAME); - if (checkdbredirect(client->sin_addr)) { + if (checkdbredirect(nodeid)) { /* Something went wrong */ goto skipit; } - + /* * Figure out what command was given. */ @@ -498,36 +557,31 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) strlen(command_array[i].cmdname)) == 0) break; - /* - * And execute it. - */ if (i == numcommands) { - info("%s INVALID REQUEST: %.8s\n", - inet_ntoa(client->sin_addr), bp); + info("%s: INVALID REQUEST: %.8s\n", nodeid, bp); goto skipit; } - else { - bp += strlen(command_array[i].cmdname); - /* - * XXX hack, don't log "log" contents, - * both for privacy and to keep our syslog smaller. - */ - if (command_array[i].func == dolog) - info("%s log %d chars\n", - inet_ntoa(client->sin_addr), strlen(bp)); - else - info("%s vers:%d %s\n", - inet_ntoa(client->sin_addr), - version, command_array[i].cmdname); + /* + * Execute it. + */ + bp += strlen(command_array[i].cmdname); - err = command_array[i].func(sock, client->sin_addr, - bp, istcp, version); + /* + * XXX hack, don't log "log" contents, + * both for privacy and to keep our syslog smaller. + */ + if (command_array[i].func == dolog) + info("%s: log %d chars\n", nodeid, strlen(bp)); + else + info("%s: vers:%d %s\n", nodeid, + version, command_array[i].cmdname); - info("%s %s: returned %d\n", - inet_ntoa(client->sin_addr), - command_array[i].cmdname, err); - } + err = command_array[i].func(sock, nodeid, bp, istcp, version); + + if (err) + info("%s: %s: returned %d\n", + nodeid, command_array[i].cmdname, err); skipit: if (!istcp) @@ -542,18 +596,10 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp) COMMAND_PROTOTYPE(doreboot) { MYSQL_RES *res; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; - if (iptonodeid(ipaddr, nodeid)) { - error("REBOOT: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - - info("REBOOT: %s is reporting a reboot\n", nodeid); - /* * Clear the current_reloads for this node, in case it just finished * reloading. This needs to happen regardless of whether or not the @@ -596,7 +642,8 @@ COMMAND_PROTOTYPE(doreboot) * See if the node was in the reload state. If so we need to clear it * and its reserved status. */ - res = mydb_query("select node_id from scheduled_reloads where node_id='%s'", + res = mydb_query("select node_id from scheduled_reloads " + "where node_id='%s'", 1, nodeid); if (!res) { error("REBOOT: %s: DB Error getting reload!\n", nodeid); @@ -608,7 +655,8 @@ COMMAND_PROTOTYPE(doreboot) } mysql_free_result(res); - if (mydb_update("delete from scheduled_reloads where node_id='%s'", nodeid)) { + if (mydb_update("delete from scheduled_reloads where node_id='%s'", + nodeid)) { error("REBOOT: %s: DB Error clearing reload!\n", nodeid); return 1; } @@ -628,18 +676,12 @@ COMMAND_PROTOTYPE(doreboot) */ COMMAND_PROTOTYPE(dostatus) { - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char nickname[128]; char buf[MYBUFSIZE]; - if (iptonodeid(ipaddr, nodeid)) { - error("STATUS: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -670,18 +712,12 @@ COMMAND_PROTOTYPE(doifconfig) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; int control_net, nrows; - if (iptonodeid(ipaddr, nodeid)) { - error("IFCONFIG: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -788,7 +824,6 @@ COMMAND_PROTOTYPE(doaccounts) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; @@ -796,8 +831,9 @@ COMMAND_PROTOTYPE(doaccounts) int nrows, gidint; int shared = 0, tbadmin; - if (iptonodeid(ipaddr, nodeid)) { - error("ACCOUNTS: %s: No such node\n", inet_ntoa(ipaddr)); + if (! tcp) { + error("ACCOUNTS: %s: Cannot give account info out over UDP!\n", + nodeid); return 1; } @@ -1061,18 +1097,12 @@ COMMAND_PROTOTYPE(dodelay) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[2*MYBUFSIZE]; int nrows; - if (iptonodeid(ipaddr, nodeid)) { - error("DELAY: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -1167,7 +1197,7 @@ COMMAND_PROTOTYPE(dohostsV2) /* * This will go away. Ignore version and assume latest. */ - return(dohosts(sock, ipaddr, rdata, tcp, CURRENT_VERSION)); + return(dohosts(sock, nodeid, rdata, tcp, CURRENT_VERSION)); } COMMAND_PROTOTYPE(dohosts) @@ -1176,7 +1206,6 @@ COMMAND_PROTOTYPE(dohosts) MYSQL_ROW row; char buf[MYBUFSIZE]; char pid[64], eid[64], gid[64]; - char nodeid[32]; int nrows; int rv = 0; @@ -1193,11 +1222,6 @@ COMMAND_PROTOTYPE(dohosts) struct hostentry *next; } *hosts = 0, *host; - if (iptonodeid(ipaddr, nodeid)) { - error("HOSTNAMES: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -1404,17 +1428,11 @@ COMMAND_PROTOTYPE(dorpms) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE], *bp, *sp; - if (iptonodeid(ipaddr, nodeid)) { - error("TARBALLS: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -1468,17 +1486,11 @@ COMMAND_PROTOTYPE(dotarballs) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE], *bp, *sp, *tp; - if (iptonodeid(ipaddr, nodeid)) { - error("TARBALLS: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -1535,17 +1547,11 @@ COMMAND_PROTOTYPE(dodeltas) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE], *bp, *sp; - if (iptonodeid(ipaddr, nodeid)) { - error("DELTAS: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -1600,17 +1606,11 @@ COMMAND_PROTOTYPE(dostartcmd) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; - if (iptonodeid(ipaddr, nodeid)) { - error("STARTUPCMD: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -1678,23 +1678,16 @@ COMMAND_PROTOTYPE(dostartcmd) */ COMMAND_PROTOTYPE(dostartstat) { - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; int exitstatus; - if (iptonodeid(ipaddr, nodeid)) { - error("STARTSTAT: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Dig out the exit status */ if (! sscanf(rdata, "%d", &exitstatus)) { - error("STARTSTAT: %s: Invalid exit status: %s\n", - inet_ntoa(ipaddr), rdata); + error("STARTSTAT: %s: Invalid status: %s\n", nodeid, rdata); return 1; } @@ -1729,16 +1722,10 @@ COMMAND_PROTOTYPE(dostartstat) */ COMMAND_PROTOTYPE(doready) { - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; - if (iptonodeid(ipaddr, nodeid)) { - error("READY: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Make sure currently allocated to an experiment! */ @@ -1771,18 +1758,12 @@ COMMAND_PROTOTYPE(doreadycount) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; int total, ready, i; - if (iptonodeid(ipaddr, nodeid)) { - error("READYCOUNT: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Make sure currently allocated to an experiment! */ @@ -1835,7 +1816,6 @@ static char logfmt[] = "/proj/%s/logs/%s.log"; */ COMMAND_PROTOTYPE(dolog) { - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; @@ -1847,10 +1827,6 @@ COMMAND_PROTOTYPE(dolog) /* * Find the pid/eid of the requesting node */ - if (iptonodeid(ipaddr, nodeid)) { - error("LOG: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } if (nodeidtoexp(nodeid, pid, eid, gid)) { info("LOG: %s: Node is free\n", nodeid); return 1; @@ -1859,8 +1835,7 @@ COMMAND_PROTOTYPE(dolog) snprintf(logfile, sizeof(logfile)-1, logfmt, pid, eid); fd = fopen(logfile, "a"); if (fd == NULL) { - error("LOG: %s: Could not open %s\n", - inet_ntoa(ipaddr), logfile); + error("LOG: %s: Could not open %s\n", nodeid, logfile); return 1; } @@ -1872,7 +1847,7 @@ COMMAND_PROTOTYPE(dolog) while (isspace(*rdata)) rdata++; - fprintf(fd, "%s: %s\n\n%s\n=======\n", tstr, inet_ntoa(ipaddr), rdata); + fprintf(fd, "%s: %s\n\n%s\n=======\n", tstr, nodeid, rdata); fclose(fd); return 0; @@ -1885,18 +1860,12 @@ COMMAND_PROTOTYPE(domounts) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; int nrows; - if (iptonodeid(ipaddr, nodeid)) { - error("MOUNTS: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -2000,17 +1969,11 @@ COMMAND_PROTOTYPE(dorouting) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; - if (iptonodeid(ipaddr, nodeid)) { - error("ROUTES: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -2062,14 +2025,8 @@ COMMAND_PROTOTYPE(doloadinfo) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char buf[MYBUFSIZE]; - if (iptonodeid(ipaddr, nodeid)) { - error("doloadinfo: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Get the address the node should contact to load its image */ @@ -2114,12 +2071,6 @@ COMMAND_PROTOTYPE(doloadinfo) COMMAND_PROTOTYPE(doreset) { MYSQL_RES *res; - char nodeid[32]; - - if (iptonodeid(ipaddr, nodeid)) { - error("doreset: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } /* * Check to see if next_pxe_boot_path is set @@ -2196,18 +2147,12 @@ COMMAND_PROTOTYPE(dotrafgens) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; int nrows; - if (iptonodeid(ipaddr, nodeid)) { - error("TRAFGENS: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -2259,20 +2204,13 @@ COMMAND_PROTOTYPE(donseconfigs) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; int nrows; if (!tcp) { - error("NSECONFIGS: %s: Cannot do UDP mode!\n", - inet_ntoa(ipaddr)); - return 1; - } - - if (iptonodeid(ipaddr, nodeid)) { - error("NSECONFIGS: %s: No such node\n", inet_ntoa(ipaddr)); + error("NSECONFIGS: %s: Cannot do UDP mode!\n", nodeid); return 1; } @@ -2316,17 +2254,11 @@ COMMAND_PROTOTYPE(donseconfigs) */ COMMAND_PROTOTYPE(dostate) { - char nodeid[32]; char *newstate; #ifdef EVENTSYS address_tuple_t tuple; #endif - if (iptonodeid(ipaddr, nodeid)) { - error("STATE: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Dig out state that the node is reporting */ @@ -2380,17 +2312,11 @@ COMMAND_PROTOTYPE(docreator) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; char buf[MYBUFSIZE]; - if (iptonodeid(ipaddr, nodeid)) { - error("CREATOR: %s: No such node\n", inet_ntoa(ipaddr)); - return 1; - } - /* * Now check reserved table */ @@ -2532,16 +2458,22 @@ mydb_update(char *query, ...) } /* - * Map IP to node ID. + * Map IP to node ID (plus other info). */ static int -iptonodeid(struct in_addr ipaddr, char *bufp) +iptonodeid(struct in_addr ipaddr, + char *nodeid, char *class, char *type, int *islocal) { MYSQL_RES *res; MYSQL_ROW row; - res = mydb_query("select node_id from interfaces where IP='%s'", 1, - inet_ntoa(ipaddr)); + res = mydb_query("select t.class,t.type,n.node_id " + " from node_types as t " + "left join nodes as n on t.type=n.type " + "left join interfaces as i on n.node_id=i.node_id " + "where i.IP='%s'", + 3, inet_ntoa(ipaddr)); + if (!res) { error("iptonodeid: %s: DB Error getting interfaces!\n", inet_ntoa(ipaddr)); @@ -2549,13 +2481,21 @@ iptonodeid(struct in_addr ipaddr, char *bufp) } if (! (int)mysql_num_rows(res)) { - error("Cannot map IP %s to nodeid\n", inet_ntoa(ipaddr)); mysql_free_result(res); return 1; } row = mysql_fetch_row(res); mysql_free_result(res); - strcpy(bufp, row[0]); + + if (!row[0] || !row[1] || !row[2]) { + error("iptonodeid: %s: Malformed DB response!\n", + inet_ntoa(ipaddr)); + return 1; + } + strcpy(nodeid, row[2]); + strcpy(class, row[0]); + strcpy(type, row[1]); + *islocal = (! strcasecmp(class, "pcremote") ? 0 : 1); return 0; } @@ -2670,23 +2610,14 @@ nodeidtocontrolnet(char *nodeid, int *net) * Check for DBname redirection. */ static int -checkdbredirect(struct in_addr ipaddr) +checkdbredirect(char *nodeid) { MYSQL_RES *res; MYSQL_ROW row; - char nodeid[32]; char pid[64]; char eid[64]; char gid[64]; - /* - * Find the nodeid. - */ - if (iptonodeid(ipaddr, nodeid)) { - error("CHECKDBREDIRECT: %s: No such node\n", - inet_ntoa(ipaddr)); - return 1; - } if (nodeidtoexp(nodeid, pid, eid, gid)) { info("CHECKDBREDIRECT: %s: Node is free\n", nodeid); return 0; @@ -2724,9 +2655,9 @@ checkdbredirect(struct in_addr ipaddr) * Okay, lets test to make sure that DB exists. If not, fall back * on the main DB. */ - if (iptonodeid(ipaddr, nodeid)) { + if (nodeidtoexp(nodeid, pid, eid, gid)) { error("CHECKDBREDIRECT: %s: %s DB does not exist\n", - inet_ntoa(ipaddr), dbname); + nodeid, dbname); strcpy(dbname, DEFAULT_DBNAME); } mysql_free_result(res); -- GitLab