<?php require_once($INC . "/sql.inc.php"); require_once($INC . "/state.inc.php"); require_once($INC . "/prof.inc.php"); $rg_keys_error = ""; function rg_keys_set_error($str) { global $rg_keys_error; $rg_keys_error = $str; } function rg_keys_error() { global $rg_keys_error; return $rg_keys_error; } /* * Extracts info about a ssh key */ function rg_keys_info($key) { $t = explode(" ", $key, 3); $ret = array(); $ret['ok'] = 0; if (!isset($t[1])) { rg_keys_set_error("malformed ssh key (missing fields)"); return $ret; } $ret['type'] = $t[0]; $ret['key'] = isset($t[1]) ? $t[1] : ""; $ret['comment'] = isset($t[2]) ? $t[2] : ""; $d = base64_decode($ret['key']); if ($d === FALSE) { rg_keys_set_error("malformed input (base64 failed)"); return $ret; } $digest = md5($d); $a = array(); for ($i = 0; $i < 16; $i++) $a[] = substr($digest, $i * 2, 2); $ret['fingerprint'] = implode(":", $a); $ret['ok'] = 1; return $ret; } /* * Remove a key from database */ function rg_keys_remove($db, $rg_ui, $key_id) { rg_prof_start("keys_remove"); // TODO: move this to caller? $e_key_id = sprintf("%u", $key_id); $sql = "DELETE FROM keys" . " WHERE uid = " . $rg_ui['uid'] . " AND key_id = $e_key_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_keys_set_error("cannot delete key $key_id (" . rg_sql_error() . ")"); return FALSE; } rg_sql_free_result($res); // mark dirty if (rg_state_set($db, "authorized_keys", 1) === FALSE) { rg_keys_set_error("cannot make state dirty (" . rg_state_error() . ")!"); return FALSE; } rg_prof_end("keys_remove"); return TRUE; } /* * Count the number of keys per user */ function rg_keys_count($db, $uid) { rg_prof_start("keys_count"); $sql = "SELECT COUNT(*) AS count FROM keys WHERE uid = $uid"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_keys_set_error("cannot query (" . rg_sql_error() . ")"); return FALSE; } $row = rg_sql_fetch_array($res); rg_sql_free_result($res); rg_prof_end("keys_count"); return $row['count']; } /* * Add a key * Returns the key_id of the key. */ function rg_keys_add($db, $rg_ui, $key) { global $rg_max_ssh_keys; rg_prof_start("keys_add"); $itime = time(); $e_key = rg_sql_escape($db, $key); $ki = rg_keys_info($key); if ($ki['ok'] != 1) return FALSE; // check if we are over the maximum // the config after update may not have this defined. if ($rg_max_ssh_keys == 0) $rg_max_ssh_keys = 10; $no_of_keys = rg_keys_count($db, $rg_ui['uid']); if ($no_of_keys === FALSE) return FALSE; if ($no_of_keys >= $rg_max_ssh_keys) { rg_keys_set_error("too many keys; please delete some"); return FALSE; } $sql = "INSERT INTO keys (itime, uid, key)" . " VALUES ($itime, " . $rg_ui['uid'] . ", '$e_key')" . " RETURNING key_id"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_keys_set_error("cannot insert key (" . rg_sql_error() . ")"); return FALSE; } $row = rg_sql_fetch_array($res); $id = $row['key_id']; rg_sql_free_result($res); // set dirty if (rg_state_set($db, "authorized_keys", 1) === FALSE) { rg_keys_set_error("cannot make state dirty: " . rg_state_error()); return FALSE; } rg_prof_end("keys_add"); return $id; } /* * Regenerates authorized_keys files */ function rg_keys_regen($db) { global $rg_keys_file; global $rg_scripts; global $rg_ssh_paras; rg_prof_start("keys_regen"); $dirty = rg_state_get($db, "authorized_keys"); if ($dirty == 0) { // Skip generation because is not dirty return TRUE; } // create .ssh folder if does not exists $dir = dirname($rg_keys_file); if (!file_exists($dir)) { if (!@mkdir($dir, 0700, TRUE)) { rg_keys_set_error("cannot create dir $dir ($php_errormsg)"); return FALSE; } } $tmp = $rg_keys_file . ".tmp"; $f = @fopen($tmp, "w"); if ($f === FALSE) { rg_keys_set_error("cannot open file $tmp ($php_errormsg)"); return FALSE; } if (chmod($tmp, 0600) === FALSE) { rg_keys_set_error("cannot chmod tmp file ($php_errmsg)"); fclose($f); return FALSE; } // mark file as clean rg_state_set($db, "authorized_keys", 0); $sql = "SELECT uid, key FROM keys"; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_keys_set_error("cannot query (" . rg_sql_error() . ")"); return FALSE; } while (($row = rg_sql_fetch_array($res))) { rg_log("Writing key [" . $row['key'] . "] for uid " . $row['uid']); $buf = "command=\"/usr/bin/php " . $rg_scripts . "/scripts/remote.php" . " " . $row['uid'] . "\"" . "," . $rg_ssh_paras . " " . $row['key'] . "\n"; if (@fwrite($f, $buf) === FALSE) { rg_keys_set_error("cannot write. Disk space problems? ($php_errormsg)"); fclose($f); unlink($tmp); rg_sql_free_result($res); return FALSE; } } rg_sql_free_result($res); fclose($f); if (@rename($tmp, $rg_keys_file) === FALSE) { rg_keys_set_error("cannot rename $tmp to $rg_keys_file ($php_errormsg)"); unlink($tmp); return FALSE; } rg_prof_end("keys_regen"); return TRUE; } /* * List keys */ function rg_keys_list($db, $rg_ui, $url) { rg_prof_start("keys_list"); rg_log("keys_list: rg_uid=" . $rg_ui['uid'] . ", url=$url..."); $sql = "SELECT * FROM keys WHERE uid = " . $rg_ui['uid']; $res = rg_sql_query($db, $sql); if ($res === FALSE) { rg_keys_set_error("Cannot query (" . rg_sql_error() . ")"); return FALSE; } $data = array(); while (($row = rg_sql_fetch_array($res))) { $ki = rg_keys_info($row['key']); if ($ki['ok'] != 1) { rg_internal_error("Invalid key in db!"); continue; } $t = $ki; $t['itime'] = gmdate("Y-m-d H:i", $row['itime']); $t['HTML:operations'] = "[<a href=\"$url" . "&key_id=" . $row['key_id'] . "&delete=1\">Delete</a>]"; $data[] = $t; } rg_sql_free_result($res); $ret = rg_template_table("user/keys/list", $data, array()); rg_prof_end("keys_list"); return $ret; } ?>