キアラの備忘録

雑多なメモを書いていきます

【SSH】SSHログイン時のチェック内容について

背景

  • 職場で .ssh関連ファイルの権限を変えてしまい、ログインできなくなる事象が発生
  • 対応過程で ssh 関連の権限をどうすればいいかがすぐ出て来なかったので、復習を兼ねて仕組みを調べてみました

前提

  • OpenSSH バージョン: V_7_6_P1
  • ログインユーザー名: Chiara
  • ssh_config にて 厳格モードが有効である

詳細

authorized_key の所有者・権限チェック

  • 所有者(以下、いずれかを満たす)
    • rootユーザー(ないし、root相当ユーザー)である
    • 所有者が、ログインするユーザーになっている
  • 権限
    • グループ, その他ユーザーに書き込み権限がない

https://github.com/openssh/openssh-portable/blob/V_7_6_P1/auth.c#L467

static FILE *
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
    int log_missing, char *file_type)
{
    /// 一部省略 ///
    if (strict_modes &&
        safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
        fclose(f);
        logit("Authentication refused: %s", line);
        auth_debug_add("Ignored %s: %s", file_type, line);
        return NULL;
    }
    /// 一部省略 ///
}

https://github.com/openssh/openssh-portable/blob/V_7_6_P1/misc.c#L1673

int
safe_path_fd(int fd, const char *file, struct passwd *pw,
    char *err, size_t errlen)
{
    struct stat st;

    /* check the open file to avoid races */
    if (fstat(fd, &st) < 0) {
        snprintf(err, errlen, "cannot stat file %s: %s",
            file, strerror(errno));
        return -1;
    }
    return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
}

https://github.com/openssh/openssh-portable/blob/V_7_6_P1/misc.c#L1608

int
safe_path(const char *name, struct stat *stp, const char *pw_dir,
    uid_t uid, char *err, size_t errlen)
{
    /// 一部省略 ///
    if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
        (stp->st_mode & 022) != 0) {
        snprintf(err, errlen, "bad ownership or modes for file %s",
            buf);
        return -1;
    }
    /// 一部省略 ///
}

.ssh、ホームディレクトリの所有者・権限チェック

  • 所有者(以下、いずれかを満たす)
    • rootユーザー(ないし、root相当ユーザー)である
    • 所有者が、ログインするユーザーになっている
  • 権限
    • グループ, その他ユーザーに書き込み権限がない
  • チェック範囲
    • /home/Chiara/.ssh
    • /home/Chiara

 ※ .sshから再帰的に、ホームディレクトリまでチェック

https://github.com/openssh/openssh-portable/blob/V_7_6_P1/auth.c#L467

static FILE *
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
    int log_missing, char *file_type)
{
    /// 一部省略 ///
    if (strict_modes &&
        safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
        fclose(f);
        logit("Authentication refused: %s", line);
        auth_debug_add("Ignored %s: %s", file_type, line);
        return NULL;
    }
    /// 一部省略 ///
}

https://github.com/openssh/openssh-portable/blob/V_7_6_P1/misc.c#L1673

int
safe_path_fd(int fd, const char *file, struct passwd *pw,
    char *err, size_t errlen)
{
    struct stat st;

    /* check the open file to avoid races */
    if (fstat(fd, &st) < 0) {
        snprintf(err, errlen, "cannot stat file %s: %s",
            file, strerror(errno));
        return -1;
    }
    return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
}

https://github.com/openssh/openssh-portable/blob/V_7_6_P1/misc.c#L1608

int
safe_path(const char *name, struct stat *stp, const char *pw_dir,
    uid_t uid, char *err, size_t errlen)
{
    /// 一部省略 ///
    /* for each component of the canonical path, walking upwards */
    for (;;) {
        if ((cp = dirname(buf)) == NULL) {
            snprintf(err, errlen, "dirname() failed");
            return -1;
        }
        strlcpy(buf, cp, sizeof(buf));

        if (stat(buf, &st) < 0 ||
            (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
            (st.st_mode & 022) != 0) {
            snprintf(err, errlen,
                "bad ownership or modes for directory %s", buf);
            return -1;
        }

        /* If are past the homedir then we can stop */
        if (comparehome && strcmp(homedir, buf) == 0)
            break;

        /*
         * dirname should always complete with a "/" path,
         * but we can be paranoid and check for "." too
         */
        if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
            break;
    }
    /// 一部省略 ///
}

今後について

  • authorized_key が rootユーザーでもいいような結果になったが、おそらく間違っていると思われます
    • 今後調査をして、正しいものに修正します