Commit 16a63146 authored by Kirk Webb's avatar Kirk Webb

Add taint checking and enforcement to the tmcc "accounts" command.

Taints applied to a node are now extracted from the database and can be
used wherever taint checking needs to happen in tmcd.  I've applied them
to the "accounts" command.  tmcd will never set the "root" flag for
non-admin users on OSes tainted with "useronly".  It won't return any
regular user accounts on nodes with the "blackbox" taint (but will
pass along admin accounts).
parent d24df9d2
...@@ -164,6 +164,14 @@ CHECKMASK(char *arg) ...@@ -164,6 +164,14 @@ CHECKMASK(char *arg)
/* Our answer to "geni-get --version" */ /* Our answer to "geni-get --version" */
#define GENI_VERSION "1" #define GENI_VERSION "1"
/* Taint support */
#define TB_TAINTSTATE_BLACKBOX 1
#define TB_TAINTSTATE_USERONLY 2
#define TB_TAINTSTATE_DANGEROUS 4
#define HAS_ANY_TAINTS(tset, tcheck) (tset & tcheck)
#define HAS_ALL_TAINTS(tset, tcheck) ((tset & tcheck) == tcheck)
#define HAS_TAINT(tset, tcheck) HAS_ALL_TAINTS(tset, tcheck)
int debug = 0; int debug = 0;
static int verbose = 0; static int verbose = 0;
static int insecure = 0; static int insecure = 0;
...@@ -241,6 +249,7 @@ typedef struct { ...@@ -241,6 +249,7 @@ typedef struct {
int genisliver_idx; int genisliver_idx;
int geniflags; int geniflags;
int nonfsmounts; int nonfsmounts;
unsigned int taintstates;
char nodeid[TBDB_FLEN_NODEID]; char nodeid[TBDB_FLEN_NODEID];
char vnodeid[TBDB_FLEN_NODEID]; char vnodeid[TBDB_FLEN_NODEID];
char pnodeid[TBDB_FLEN_NODEID]; /* XXX */ char pnodeid[TBDB_FLEN_NODEID]; /* XXX */
...@@ -2747,47 +2756,14 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -2747,47 +2756,14 @@ COMMAND_PROTOTYPE(doaccounts)
"order by u.uid", "order by u.uid",
18, reqp->nodeid); 18, reqp->nodeid);
} }
else if (reqp->isvnode ||
(reqp->islocal && !reqp->sharing_mode[0])) {
/*
* This crazy join is going to give us multiple lines for
* each user that is allowed on the node, where each line
* (for each user) differs by the project PID and it unix
* GID. The intent is to build up a list of GIDs for each
* user to return. Well, a primary group and a list of aux
* groups for that user.
*/
char adminclause[MYBUFSIZE];
strcpy(adminclause, "");
#ifdef ISOLATEADMINS
sprintf(adminclause, "and u.admin=%d", reqp->swapper_isadmin);
#endif
res = mydb_query("select distinct "
" u.uid,u.usr_pswd,u.unix_uid,u.usr_name, "
" p.trust,g.pid,g.gid,g.unix_gid,u.admin, "
" u.emulab_pubkey,u.home_pubkey, "
" UNIX_TIMESTAMP(u.usr_modified), "
" u.usr_email,u.usr_shell, "
" u.widearearoot,u.wideareajailroot, "
" u.usr_w_pswd,u.uid_idx "
"from group_membership as p "
"join users as u on p.uid_idx=u.uid_idx "
"join groups as g on "
" p.pid=g.pid and p.gid=g.gid "
"where ((p.pid='%s')) and p.trust!='none' "
" and u.status='active' "
" and u.webonly=0 "
" %s "
" and g.unix_gid is not NULL "
"order by u.uid",
18, reqp->pid, adminclause);
}
else if ((reqp->jailflag && !reqp->islocal) || else if ((reqp->jailflag && !reqp->islocal) ||
(reqp->islocal && reqp->sharing_mode[0])) { (reqp->islocal && reqp->sharing_mode[0]) ||
HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX)) {
/* /*
* A remote node, doing jails or a local node being * A remote node doing jails, a local node being
* shared. We still want to return accounts for the * shared, or a node with 'blackbox' taintstate:
* admin people outside the jails. Note that remote jail * We still want to return accounts for the
* admin people. Note that remote jail
* case is effectively deprecated at this point. * case is effectively deprecated at this point.
*/ */
res = mydb_query("select distinct " res = mydb_query("select distinct "
...@@ -2808,14 +2784,8 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -2808,14 +2784,8 @@ COMMAND_PROTOTYPE(doaccounts)
" order by u.uid", " order by u.uid",
18, RELOADPID, PROTOUSER); 18, RELOADPID, PROTOUSER);
} }
else if (!reqp->islocal && reqp->isdedicatedwa) { else if (reqp->isvnode || reqp->islocal ||
/* (!reqp->islocal && reqp->isdedicatedwa)) {
* Wonder why this code is a copy of the islocal || vnode
* case above? It's because I don't want to prevent us from
* from the above case where !islocal && jailflag
* for dedicated widearea nodes.
*/
/* /*
* This crazy join is going to give us multiple lines for * This crazy join is going to give us multiple lines for
* each user that is allowed on the node, where each line * each user that is allowed on the node, where each line
...@@ -2825,12 +2795,14 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -2825,12 +2795,14 @@ COMMAND_PROTOTYPE(doaccounts)
* groups for that user. * groups for that user.
*/ */
char adminclause[MYBUFSIZE]; char adminclause[MYBUFSIZE];
char *passwdfield = (!reqp->islocal && reqp->isdedicatedwa) ?
"'*'" : "u.usr_pswd";
strcpy(adminclause, ""); strcpy(adminclause, "");
#ifdef ISOLATEADMINS #ifdef ISOLATEADMINS
sprintf(adminclause, "and u.admin=%d", reqp->swapper_isadmin); sprintf(adminclause, "and u.admin=%d", reqp->swapper_isadmin);
#endif #endif
res = mydb_query("select distinct " res = mydb_query("select distinct "
" u.uid,'*',u.unix_uid,u.usr_name, " " u.uid,%s,u.unix_uid,u.usr_name, "
" p.trust,g.pid,g.gid,g.unix_gid,u.admin, " " p.trust,g.pid,g.gid,g.unix_gid,u.admin, "
" u.emulab_pubkey,u.home_pubkey, " " u.emulab_pubkey,u.home_pubkey, "
" UNIX_TIMESTAMP(u.usr_modified), " " UNIX_TIMESTAMP(u.usr_modified), "
...@@ -2847,7 +2819,7 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -2847,7 +2819,7 @@ COMMAND_PROTOTYPE(doaccounts)
" %s " " %s "
" and g.unix_gid is not NULL " " and g.unix_gid is not NULL "
"order by u.uid", "order by u.uid",
18, reqp->pid, adminclause); 18, passwdfield, reqp->pid, adminclause);
} }
else if (! reqp->islocal) { else if (! reqp->islocal) {
/* /*
...@@ -3014,6 +2986,16 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -3014,6 +2986,16 @@ COMMAND_PROTOTYPE(doaccounts)
root = 1; root = 1;
} }
/*
* Nuke the root flag if the node is tainted with
* 'usermode', except for admins. The 'blackbox' taintstate
* has already restricted the set of users to admins,
* so no need to check for that.
*/
if (HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_USERONLY) &&
!tbadmin)
root = 0;
/* There is an optional Windows password column. */ /* There is an optional Windows password column. */
pswd = row[1]; pswd = row[1];
wpswd = row[16]; wpswd = row[16];
...@@ -3238,7 +3220,9 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -3238,7 +3220,9 @@ COMMAND_PROTOTYPE(doaccounts)
} }
mysql_free_result(res); mysql_free_result(res);
if (!(reqp->islocal || reqp->isvnode) && !didwidearea) { /* No more accounts will be added if the node has 'blackbox' taint. */
if (!(reqp->islocal || reqp->isvnode) && !didwidearea &&
!HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX)) {
didwidearea = 1; didwidearea = 1;
/* /*
...@@ -3273,10 +3257,12 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -3273,10 +3257,12 @@ COMMAND_PROTOTYPE(doaccounts)
* When sharing mode is on, do not return these accounts to pnodes. * When sharing mode is on, do not return these accounts to pnodes.
* Note that sharing_mode and genisliver_idx should not both be set * Note that sharing_mode and genisliver_idx should not both be set
* on a pnode, but lets be careful. * on a pnode, but lets be careful.
* but *
* No more accounts will be added if the node has 'blackbox' taint.
*/ */
if (reqp->genisliver_idx && !didnonlocal && if (reqp->genisliver_idx && !didnonlocal &&
(reqp->isvnode || !reqp->sharing_mode[0])) { (reqp->isvnode || !reqp->sharing_mode[0]) &&
!HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX)) {
didnonlocal = 1; didnonlocal = 1;
/* /*
...@@ -6929,7 +6915,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -6929,7 +6915,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, " " r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,n.uuid, " " r.sharing_mode,e.geniflags,n.uuid, "
" n.nonfsmounts,e.nonfsmounts AS enonfs, " " n.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole " " r.erole, n.taint_states "
"FROM nodes AS n " "FROM nodes AS n "
"LEFT JOIN reserved AS r ON " "LEFT JOIN reserved AS r ON "
" r.node_id=n.node_id " " r.node_id=n.node_id "
...@@ -6958,7 +6944,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -6958,7 +6944,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" (SELECT node_id FROM widearea_nodeinfo " " (SELECT node_id FROM widearea_nodeinfo "
" WHERE privkey='%s') " " WHERE privkey='%s') "
" AND notmcdinfo_types.attrvalue IS NULL", " AND notmcdinfo_types.attrvalue IS NULL",
38, nodekey); 39, nodekey);
} }
else if (reqp->isvnode) { else if (reqp->isvnode) {
char clause[BUFSIZ]; char clause[BUFSIZ];
...@@ -6995,7 +6981,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -6995,7 +6981,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, " " r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,nv.uuid, " " r.sharing_mode,e.geniflags,nv.uuid, "
" nv.nonfsmounts,e.nonfsmounts AS enonfs, " " nv.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole " " r.erole, n.taint_states "
"from nodes as nv " "from nodes as nv "
"left join nodes as np on " "left join nodes as np on "
" np.node_id=nv.phys_nodeid " " np.node_id=nv.phys_nodeid "
...@@ -7016,7 +7002,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7016,7 +7002,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
"left join users as u on " "left join users as u on "
" u.uid_idx=e.swapper_idx " " u.uid_idx=e.swapper_idx "
"where nv.node_id='%s' and (%s)", "where nv.node_id='%s' and (%s)",
38, reqp->vnodeid, clause); 39, reqp->vnodeid, clause);
} }
else { else {
char clause[BUFSIZ]; char clause[BUFSIZ];
...@@ -7046,7 +7032,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7046,7 +7032,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, " " r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,n.uuid, " " r.sharing_mode,e.geniflags,n.uuid, "
" n.nonfsmounts,e.nonfsmounts AS enonfs, " " n.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole " " r.erole, n.taint_states "
"from interfaces as i " "from interfaces as i "
"left join nodes as n on n.node_id=i.node_id " "left join nodes as n on n.node_id=i.node_id "
"left join reserved as r on " "left join reserved as r on "
...@@ -7074,7 +7060,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7074,7 +7060,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" on n.type=dedicated_wa_types.type " " on n.type=dedicated_wa_types.type "
"where (%s) " "where (%s) "
" and notmcdinfo_types.attrvalue is NULL", " and notmcdinfo_types.attrvalue is NULL",
38, clause); 39, clause);
} }
if (!res) { if (!res) {
...@@ -7206,6 +7192,26 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7206,6 +7192,26 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
reqp->nonfsmounts = atoi(row[35]); reqp->nonfsmounts = atoi(row[35]);
else else
reqp->nonfsmounts = 0; reqp->nonfsmounts = 0;
/* taintstates - find the strings and set the bits. */
reqp->taintstates = 0;
if (row[38]) {
char tbuf[BUFSIZ];
char *tptr, *tok;
strcpy(tbuf, row[38]);
tptr = tbuf;
while ((tok = strsep(&tptr, ",")) != NULL) {
if (strcmp(tok,"blackbox") == 0) {
reqp->taintstates |= TB_TAINTSTATE_BLACKBOX;
} else if (strcmp(tok,"useronly") == 0) {
reqp->taintstates |= TB_TAINTSTATE_USERONLY;
} else if (strcmp(tok,"dangerous") == 0) {
reqp->taintstates |= TB_TAINTSTATE_DANGEROUS;
} else {
error("iptonodeid: %s: Unknown taintstate: '%s'\n", reqp->nodeid, tok);
}
}
}
/* If a vnode, copy into the nodeid. Eventually split this properly */ /* If a vnode, copy into the nodeid. Eventually split this properly */
strcpy(reqp->pnodeid, reqp->nodeid); strcpy(reqp->pnodeid, reqp->nodeid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment