Users can now add an SSH public key on the account edit page. This will
later be used to authenticate users via SSH.

Signed-off-by: Lukas Fleischer <[email protected]>
---
 schema/aur-schema.sql              |  1 +
 upgrading/4.0.0.txt                |  5 +++
 web/html/account.php               |  5 ++-
 web/lib/acctfuncs.inc.php          | 78 ++++++++++++++++++++++++++++++++++----
 web/template/account_edit_form.php |  5 +++
 5 files changed, 85 insertions(+), 9 deletions(-)
 create mode 100644 upgrading/4.0.0.txt

diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql
index 9c57683..dfd158f 100644
--- a/schema/aur-schema.sql
+++ b/schema/aur-schema.sql
@@ -33,6 +33,7 @@ CREATE TABLE Users (
        LangPreference VARCHAR(5) NOT NULL DEFAULT 'en',
        IRCNick VARCHAR(32) NOT NULL DEFAULT '',
        PGPKey VARCHAR(40) NULL DEFAULT NULL,
+       SSHPubKey VARCHAR(4096) NULL DEFAULT NULL,
        LastLogin BIGINT UNSIGNED NOT NULL DEFAULT 0,
        LastLoginIPAddress INTEGER UNSIGNED NOT NULL DEFAULT 0,
        InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0,
diff --git a/upgrading/4.0.0.txt b/upgrading/4.0.0.txt
new file mode 100644
index 0000000..543fbac
--- /dev/null
+++ b/upgrading/4.0.0.txt
@@ -0,0 +1,5 @@
+1. Add a field for the SSH public key to the Users table:
+
+----
+ALTER TABLE Users ADD COLUMN SSHPubKey VARCHAR(4096) NULL DEFAULT NULL;
+----
diff --git a/web/html/account.php b/web/html/account.php
index c1a1cd7..3dc8ef0 100644
--- a/web/html/account.php
+++ b/web/html/account.php
@@ -59,7 +59,7 @@ if (isset($_COOKIE["AURSID"])) {
                                display_account_form("UpdateAccount", 
$row["Username"],
                                        $row["AccountTypeID"], 
$row["Suspended"], $row["Email"],
                                        "", "", $row["RealName"], 
$row["LangPreference"],
-                                       $row["IRCNick"], $row["PGPKey"],
+                                       $row["IRCNick"], $row["PGPKey"], 
$row["SSHPubKey"],
                                        $row["InactivityTS"] ? 1 : 0, 
$row["ID"]);
                        } else {
                                print __("You do not have permission to edit 
this account.");
@@ -98,7 +98,8 @@ if (isset($_COOKIE["AURSID"])) {
                                        in_request("U"), in_request("T"), 
in_request("S"),
                                        in_request("E"), in_request("P"), 
in_request("C"),
                                        in_request("R"), in_request("L"), 
in_request("I"),
-                                       in_request("K"), in_request("J"), 
in_request("ID"));
+                                       in_request("K"), in_request("PK"), 
in_request("J"),
+                                       in_request("ID"));
                }
        } else {
                if (has_credential(CRED_ACCOUNT_SEARCH)) {
diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php
index 2d8dbaf..20ac081 100644
--- a/web/lib/acctfuncs.inc.php
+++ b/web/lib/acctfuncs.inc.php
@@ -53,13 +53,14 @@ function html_format_pgp_fingerprint($fingerprint) {
  * @param string $L The language preference of the displayed user
  * @param string $I The IRC nickname of the displayed user
  * @param string $K The PGP key fingerprint of the displayed user
+ * @param string $PK The SSH public key of the displayed user
  * @param string $J The inactivity status of the displayed user
  * @param string $UID The user ID of the displayed user
  *
  * @return void
  */
-function display_account_form($A,$U="",$T="",$S="",
-               $E="",$P="",$C="",$R="",$L="",$I="",$K="",$J="", $UID=0) {
+function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="",
+               $L="",$I="",$K="",$PK="",$J="", $UID=0) {
        global $SUPPORTED_LANGS;
 
        include("account_edit_form.php");
@@ -82,13 +83,14 @@ function display_account_form($A,$U="",$T="",$S="",
  * @param string $L The language preference of the user
  * @param string $I The IRC nickname of the user
  * @param string $K The PGP fingerprint of the user
+ * @param string $PK The SSH public key of the user
  * @param string $J The inactivity status of the user
  * @param string $UID The user ID of the modified account
  *
  * @return string|void Return void if successful, otherwise return error
  */
-function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",
-                       $P="",$C="",$R="",$L="",$I="",$K="",$J="",$UID=0) {
+function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="",
+               $R="",$L="",$I="",$K="",$PK="",$J="",$UID=0) {
        global $SUPPORTED_LANGS;
 
        $error = '';
@@ -146,6 +148,15 @@ function 
process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",
                $error = __("The PGP key fingerprint is invalid.");
        }
 
+       if (!$error && !empty($PK)) {
+               if (valid_ssh_pubkey($PK)) {
+                       $tokens = explode(" ", $PK);
+                       $PK = $tokens[0] . " " . $tokens[1];
+               } else {
+                       $error = __("The SSH public key is invalid.");
+               }
+       }
+
        if (isset($_COOKIE['AURSID'])) {
                $atype = account_from_sid($_COOKIE['AURSID']);
                if (($atype == "User" && $T > 1) || ($atype == "Trusted User" 
&& $T > 2)) {
@@ -192,11 +203,29 @@ function 
process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",
                                        "<strong>", 
htmlspecialchars($E,ENT_QUOTES), "</strong>");
                }
        }
+       if (!$error) {
+               /*
+                * Check whether the SSH public key is available.
+                * TODO: Fix race condition.
+                */
+               $q = "SELECT COUNT(*) FROM Users ";
+               $q.= "WHERE SSHPubKey = " . $dbh->quote($PK);
+               if ($TYPE == "edit") {
+                       $q.= " AND ID != " . intval($UID);
+               }
+               $result = $dbh->query($q);
+               $row = $result->fetch(PDO::FETCH_NUM);
+
+               if ($row[0]) {
+                       $error = __("The SSH public key, %s%s%s, is already in 
use.",
+                                       "<strong>", htmlspecialchars($PK, 
ENT_QUOTES), "</strong>");
+               }
+       }
 
        if ($error) {
                print "<ul class='errorlist'><li>".$error."</li></ul>\n";
                display_account_form($A, $U, $T, $S, $E, "", "",
-                               $R, $L, $I, $K, $J, $UID);
+                               $R, $L, $I, $K, $PK, $J, $UID);
                return;
        }
 
@@ -218,11 +247,13 @@ function 
process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",
                $L = $dbh->quote($L);
                $I = $dbh->quote($I);
                $K = $dbh->quote(str_replace(" ", "", $K));
+               $PK = $dbh->quote($PK);
                $q = "INSERT INTO Users (AccountTypeID, Suspended, ";
                $q.= "InactivityTS, Username, Email, Passwd, Salt, ";
-               $q.= "RealName, LangPreference, IRCNick, PGPKey) ";
+               $q.= "RealName, LangPreference, IRCNick, PGPKey, ";
+               $q.= "SSHPubKey) ";
                $q.= "VALUES (1, 0, 0, $U, $E, $P, $salt, $R, $L, ";
-               $q.= "$I, $K)";
+               $q.= "$I, $K, $PK)";
                $result = $dbh->exec($q);
                if (!$result) {
                        print __("Error trying to create account, %s%s%s.",
@@ -290,6 +321,7 @@ function 
process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",
                $q.= ", LangPreference = " . $dbh->quote($L);
                $q.= ", IRCNick = " . $dbh->quote($I);
                $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K));
+               $q.= ", SSHPubKey = " . $dbh->quote($PK);
                $q.= ", InactivityTS = " . $inactivity_ts;
                $q.= " WHERE ID = ".intval($UID);
                $result = $dbh->exec($q);
@@ -800,6 +832,38 @@ function valid_pgp_fingerprint($fingerprint) {
 }
 
 /**
+ * Determine if the SSH public key is valid
+ *
+ * @param string $pubkey SSH public key to check
+ *
+ * @return bool True if the SSH public key is valid, otherwise false
+ */
+function valid_ssh_pubkey($pubkey) {
+       $valid_prefixes = array(
+               "ssh-rsa", "ssh-dss", "ecdsa-sha2-nistp256",
+               "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "ssh-ed25519"
+       );
+
+       $has_valid_prefix = false;
+       foreach ($valid_prefixes as $prefix) {
+               if (strpos($pubkey, $prefix . " ") === 0) {
+                       $has_valid_prefix = true;
+                       break;
+               }
+       }
+       if (!$has_valid_prefix) {
+               return false;
+       }
+
+       $tokens = explode(" ", $pubkey);
+       if (empty($tokens[1])) {
+               return false;
+       }
+
+       return (base64_encode(base64_decode($tokens[1], true)) == $tokens[1]);
+}
+
+/**
  * Determine if the user account has been suspended
  *
  * @param string $id The ID of user to check if suspended
diff --git a/web/template/account_edit_form.php 
b/web/template/account_edit_form.php
index 17dd937..996c207 100644
--- a/web/template/account_edit_form.php
+++ b/web/template/account_edit_form.php
@@ -98,6 +98,11 @@
                </p>
 
                <p>
+                       <label for="id_ssh"><?= __("SSH Public Key") ?>:</label>
+                       <textarea name="PK" id="id_ssh" rows="5" cols="30"><?= 
htmlspecialchars($PK) ?></textarea>
+               </p>
+
+               <p>
                        <label for="id_language"><?= __("Language") ?>:</label>
                        <select name="L" id="id_language">
 <?php
-- 
2.2.1

Reply via email to