From fddcd467d5e278dc63f8135c77a76e978a6577cf Mon Sep 17 00:00:00 2001 From: Leigh B Stoller <stoller@flux.utah.edu> Date: Thu, 3 Apr 2014 12:07:23 -0600 Subject: [PATCH] Return the root password hash in the jailconfig call. This allows dom0 to set the password of the guest at creation time, so that if something goes wrong, we can get in on the console. This also fixes an error where on a shared node, we were returning the password hash for the physical host. Return a per-node hash instead. Also abstract out the various places we get read from /dev/urandom. --- tmcd/tmcd.c | 140 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 51 deletions(-) diff --git a/tmcd/tmcd.c b/tmcd/tmcd.c index 57dd191958..40074259a2 100644 --- a/tmcd/tmcd.c +++ b/tmcd/tmcd.c @@ -173,6 +173,7 @@ int mydb_update(char *query, ...); static int safesymlink(char *name1, char *name2); static int getImageInfo(char *path, char *nodeid, char *pid, char *imagename, unsigned int *mtime, unsigned int *chunks); +static int getrandomchars(char *buf, int len); /* socket timeouts */ static int readtimo = READTIMO; @@ -7354,38 +7355,17 @@ COMMAND_PROTOTYPE(doisalive) */ COMMAND_PROTOTYPE(doipodinfo) { - char buf[MYBUFSIZE], *bp; - unsigned char randdata[16], hashbuf[16*2+1]; - int fd, cc, i; + char buf[MYBUFSIZE], hashbuf[BUFSIZ]; if (!tcp) { error("IPODINFO: %s: Cannot do this in UDP mode!\n", reqp->nodeid); return 1; } - - if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { - errorc("opening /dev/urandom"); - return 1; - } - if ((cc = read(fd, randdata, sizeof(randdata))) < 0) { - errorc("reading /dev/urandom"); - close(fd); + if (getrandomchars(hashbuf, 32)) { + error("IPODINFO: no random chars for password\n"); return 1; } - if (cc != sizeof(randdata)) { - error("Short read from /dev/urandom: %d", cc); - close(fd); - return 1; - } - close(fd); - - bp = (char *)hashbuf; - for (i = 0; i < sizeof(randdata); i++) { - bp += sprintf(bp, "%02x", randdata[i]); - } - *bp = '\0'; - mydb_update("update nodes set ipodhash='%s' " "where node_id='%s'", hashbuf, reqp->nodeid); @@ -7679,6 +7659,38 @@ COMMAND_PROTOTYPE(dojailconfig) mysql_free_result(res); } + /* + * Per jail root password hash if one has been set. + */ + res = mydb_query("select attrvalue from node_attributes " + " where node_id='%s' and " + " attrkey='root_password'", + 1, reqp->nodeid); + + if (!res) { + error("JAILCONFIG: %s: DB Error getting root_password.\n", + reqp->nodeid); + return 1; + } + if ((nrows = (int)mysql_num_rows(res))) { + row = mysql_fetch_row(res); + if (row[0] && row[0][0]) { + char saltbuf[BUFSIZ], *bp; + + if (getrandomchars(saltbuf, 8) != 0) { + snprintf(saltbuf, sizeof(saltbuf), + "%ud", time(NULL)); + } + sprintf(buf, "$1$%s", saltbuf); + bp = crypt(row[0], buf); + + bufp = buf; + bufp += OUTPUT(bufp, ebufp - bufp, "ROOTHASH=%s\n", bp); + client_writeback(sock, buf, strlen(buf), tcp); + } + } + mysql_free_result(res); + /* * Now return the IP interface list that this jail has access to. * These are tunnels or ip aliases on the real interfaces, but @@ -9489,43 +9501,33 @@ COMMAND_PROTOTYPE(dorootpswd) { MYSQL_RES *res; MYSQL_ROW row; - char buf[MYBUFSIZE], hashbuf[MYBUFSIZE], *bp; + char buf[BUFSIZ], hashbuf[BUFSIZ], saltbuf[BUFSIZ], *bp; + char *nodeid = reqp->pnodeid; + + /* + * On a virtnode, we return the password for the physical + * host, but not on a shared node, it needs its own. + */ + if (reqp->isvnode && reqp->sharing_mode[0]) { + nodeid = reqp->nodeid; + } res = mydb_query("select attrvalue from node_attributes " " where node_id='%s' and " " attrkey='root_password'", - 1, reqp->pnodeid); + 1, nodeid); if (!res || (int)mysql_num_rows(res) == 0) { - unsigned char randdata[5]; - int fd, cc, i; - - if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { - errorc("opening /dev/urandom"); - return 1; - } - if ((cc = read(fd, randdata, sizeof(randdata))) < 0) { - errorc("reading /dev/urandom"); - close(fd); - return 1; - } - if (cc != sizeof(randdata)) { - error("Short read from /dev/urandom: %d", cc); - close(fd); + if (getrandomchars(hashbuf, 12)) { + error("DOROOTPSWD: no random chars for password\n"); + if (res) + mysql_free_result(res); return 1; } - close(fd); - - bp = hashbuf; - for (i = 0; i < sizeof(randdata); i++) { - bp += sprintf(bp, "%02x", randdata[i]); - } - *bp = '\0'; - mydb_update("replace into node_attributes set " " node_id='%s', " " attrkey='root_password',attrvalue='%s'", - reqp->nodeid, hashbuf); + nodeid, hashbuf); } else { row = mysql_fetch_row(res); @@ -9538,7 +9540,11 @@ COMMAND_PROTOTYPE(dorootpswd) * Need to crypt() this for the node since we obviously do not want * to return the plain text. */ - sprintf(buf, "$1$%s", hashbuf); + if (getrandomchars(saltbuf, 8)) { + error("DOROOTPSWD: no random chars for salt\n"); + return 1; + } + sprintf(buf, "$1$%s", saltbuf); bp = crypt(hashbuf, buf); OUTPUT(buf, sizeof(buf), "HASH=%s\n", bp); @@ -12488,3 +12494,35 @@ COMMAND_PROTOTYPE(dotiplineinfo) return 0; } +static int +getrandomchars(char *buf, int len) +{ + unsigned char randdata[MYBUFSIZE]; + int fd, cc, i; + char *bp; + + if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { + errorc("opening /dev/urandom"); + return 1; + } + if ((cc = read(fd, randdata, len)) < 0) { + errorc("reading /dev/urandom"); + close(fd); + return 1; + } + if (cc != len) { + error("Short read from /dev/urandom: %d", len); + close(fd); + return 1; + } + bp = buf; + for (i = 0; i < len;) { + cc = sprintf(bp, "%02x", randdata[i]); + i += cc; + bp += cc; + } + buf[len] = '\0'; + + close(fd); + return 0; +} -- GitLab