From 312976c1da23aa75e2c74ca1529d5109d01dbed4 Mon Sep 17 00:00:00 2001 From: Andrew Cady Date: Fri, 29 May 2020 11:06:11 -0400 Subject: more automagic --- src/samizdat-ssh-command | 324 ----------------------------------------------- 1 file changed, 324 deletions(-) delete mode 100755 src/samizdat-ssh-command (limited to 'src/samizdat-ssh-command') diff --git a/src/samizdat-ssh-command b/src/samizdat-ssh-command deleted file mode 100755 index a03b554..0000000 --- a/src/samizdat-ssh-command +++ /dev/null @@ -1,324 +0,0 @@ -#!/bin/dash -default_command="$HOME/samizdat-default-command" -if ! [ "$default_command" ] || ! [ -e "$default_command" ] -then - default_command=password_authentication -fi - -authorize() -{ - local authtype authdata forced_command comment authorized_keys_line - [ "$SSH_USER_AUTH" -a -f "$SSH_USER_AUTH" ] || return - read authtype authdata < "$SSH_USER_AUTH" || return - [ "$authtype" = publickey ] || return - - forced_command="command=\"${0} authorize-full-access\",no-port-forwarding" - comment="samizdat: password-authenticated from ${SSH_CONNECTION%% *}" - - authorized_keys_line="$forced_command $authdata $comment" - sentinel='Samizdat - YES WE CAN' - - su - "$USER" -c 'mkdir -p "$HOME"/.ssh; touch "$HOME"/.ssh/authorized_keys' && - add_before_sentinel "$sentinel" \ - "$authorized_keys_line" \ - "$HOME"/.ssh/authorized_keys -} - -add_before_sentinel() -{ - local sentinel="$1" add_me="$2" target="$3" - sed -i.samizdat~ \ - -e "/$sentinel/i $add_me" \ - "$target" -} - -password_authentication() -{ - [ "$USER" ] || { echo 'Error: no $USER' >&2; exit 1; } - [ "$SSH_CLIENT_FINGERPRINT" ] || { echo 'Error: no $SSH_CLIENT_FINGERPRINT' >&2; exit 1; } - - tty=$(tty) && [ "$tty" != 'not a tty' ] || tty= - - if [ "$SSH_ORIGINAL_COMMAND" ]; then - msg='You are not authorized to execute the command: %s\n' - if ! [ "$tty" ]; then - msg="$msg"'To authorize your public key via password, reconnect without a command, or with a terminal attached.\n' - msg="$msg"'To attach a terminal, use the "-t" option to ssh.\n' - else - msg="$msg"'To authorize your public key and execute the command, enter your password.\n' - fi - printf "\n$msg\n" "$SSH_ORIGINAL_COMMAND" >&2 - if ! [ "$tty" ]; then - exit 1 - fi - else - msg='You are not authorized to log in.\n' - msg="$msg"'To authorize your public key and log in, enter your password.\n' - printf "\n$msg\n" >&2 - fi - authorize || exit $? - # TODO: blacklist after too many authentication failures - if [ "$SSH_ORIGINAL_COMMAND" ]; then - exec "$SSH_ORIGINAL_COMMAND" - else - exec $(getent passwd "$USER"|cut -d: -f7) -i - fi - exit $? # exec failed -} - -die() { echo "Error: $*" >&2; exit 1; } - -dequote() -{ - # Sorry about the slashes. The perl would be: s{ \\(.) | '([^']+)' }{ $1$2 }gx - git_dir=$(echo -n "$git_dir" | sed -e "s/\\\\\\(.\\)\\|'\\([^']\\+\\)'/\\1\\2/g") -} - -homedir_expand() -{ - git_dir=$(homedir_expand_arg "$git_dir") && - [ "$git_dir" ] || die "Could not expand home directory. HOME=$HOME, USER=$USER, id=$(id)" -} - -homedir_expand_arg() -{ - [ "$HOME" ] || die '$HOME is not set.' - case "$1" in - \~) echo "$HOME";; - \~/*) echo "${HOME}${1#\~}";; - \~*) - local u - u=${1#\~} - u=${u%%/*} - u=$(getent passwd "$u"|cut -f6 -d:) && [ "$u" ] || return 1 - echo "$u/${1#*/}";; - /*) echo "$1";; - *) echo "$HOME/$1";; - esac -} - -initialize_git() -{ - local git_dir="$1" anonymous="$2" - if ! [ -e "$git_dir" ]; then - mkdir -p "$(dirname "$git_dir")" - git init --bare "$git_dir" >&2 - if [ "$anonymous" ]; then - git --git-dir "$git_dir" config samizdat.allow-anonymous-access true - git --git-dir "$git_dir" config samizdat.anonymous-ssh-owner "$anonymous" - fi - fi -} - -is_gitdir() { git rev-parse --resolve-git-dir "$1" >/dev/null 2>&1; } - -deny() { echo 'Error: permission denied.' >&2; exit 1; } - -valid_new_public_repo() -{ - local git_dir="$1" - [ ! -e "$git_dir" ] || return - [ "$HOME" -a -d "$HOME"/public_git ] || return - local dirname="$(dirname "$git_dir")" - - case "$git_dir" in - *.git) ;; - *) - echo 'Error: public repos must be named *.git' >&2 - return 1 ;; - esac - - case "$dirname" in - $HOME/public_git) return 0 ;; - $HOME/public_git/*) - # Ensure that no parent directory is named *.git - # Also enforce a maximum depth of 4. - # Valid: public_git/a/b/c/d.git - # Invalid: public_git/a/b/c/d/e.git - local n relative="${git_dir#$HOME/public_git/}" - for n in 1 2 3 4; do - local topmost="${relative%%/*}" - case "$topmost" in - "$relative") return 0;; - *.git) return 1;; - esac - relative=${relative#$topmost/} - done - echo 'Error: directories nest too deep' >&2 - return 1 - ;; - *) return 1 ;; - esac -} - -check_if_ssh_user_owns_repository() -{ - git --git-dir "$git_dir" config --get-all samizdat.anonymous-ssh-owner | grep -xqF "$SSH_CLIENT_FINGERPRINT" -} -ssh_user_owns_repository() -{ - if [ -z "$SSH_USER_OWNS_REPOSITORY" ]; then - check_if_ssh_user_owns_repository - SSH_USER_OWNS_REPOSITORY=$? - fi - return $SSH_USER_OWNS_REPOSITORY -} - -is_public_repository() -{ - case "$git_dir" in - */../*) false;; - "$HOME"/public_git/*) true;; - *) false;; - esac -} - -authorized() -{ - # TODO: check SSH_CLIENT_FINGERPRINT against a blacklist - ssh_user_owns_repository && return - is_public_repository && return - test "$(git --git-dir "$1" config --bool --get samizdat.allow-anonymous-access)" = true 2>/dev/null && return 0 - # TODO: check SSH_CLIENT_FINGERPRINT against a whitelist -} - -maybe_initialize_heads() -{ - [ "$GIT_NAMESPACE" ] || die 'Programmer error' - heads=$git_dir/refs/namespaces/$GIT_NAMESPACE/refs/heads - mkdir -p "$heads" - found_file=$(find "$heads" -type f -print -quit) - [ "$found_file" ] && return - [ -e "$git_dir/refs/heads/master" ] && cp "$git_dir/refs/heads/master" "$heads" - # TODO: copy actual file 'HEAD' and whatever it references -} - - -if [ "$1" = "authorize-full-access" ]; then - case "$SSH_ORIGINAL_COMMAND" in - git-receive-pack\ *) - git_cmd=git-receive-pack - git_dir="${SSH_ORIGINAL_COMMAND#git-receive-pack }" - dequote - homedir_expand - initialize_git "$git_dir" - exec "$git_cmd" "$git_dir" - ;; - "") - shell=$(getent passwd $USER|cut -d: -f7) - argv0=-${shell##*/} - if which chpst >/dev/null 2>&1; then - exec chpst -b "$argv0" "$shell" - else - exec "$shell" - fi - ;; - *) - exec /bin/sh -c "$SSH_ORIGINAL_COMMAND" - ;; - esac - exit -fi - -eval "$(samizdat-ssh-uid)" || die eval - -if [ $# -gt 0 ] -then - exec "$@" - exit -fi - -# TODO: call password_authentication on all authorization failures - -#echo "SSH_ORIGINAL_COMMAND=$SSH_ORIGINAL_COMMAND" >&2 -case "$SSH_ORIGINAL_COMMAND" in - git-upload-pack\ *|git-receive-pack\ *) - # set three variables - # 1. git_cmd - # 2. git_dir - # 3. git_ns (optional) - - git_cmd=${SSH_ORIGINAL_COMMAND%%\ *} - git_dir=${SSH_ORIGINAL_COMMAND#*\ } - - dequote - homedir_expand - - case "$git_dir" in - $HOME/git_namespace/*/public_git/*) - git_ns_subdir=${git_dir#$HOME/git_namespace/} - git_ns=${git_ns_subdir%%/*} - git_dir=$HOME/${git_ns_subdir#*/} - ;; - esac - - ;; - rsync\ --server\ --sender\ -de.LsfxC\ .\ public_git/|rsync\ --server\ --sender\ -de.LsfxC\ .\ public_git/|rsync\ --server\ --sender\ -de.Lsf\ .\ public_git/) - #echo "$SSH_ORIGINAL_COMMAND" >&2 - [ -d "$HOME"/public_git ] || { password_authentication; exit 1; } - exec $SSH_ORIGINAL_COMMAND - #exec rrsync -ro "$HOME"/public_git - exit 1 - ;; - rsync\ --server\ --sender\ *) - #echo "$SSH_ORIGINAL_COMMAND" >&2 - [ -d "$HOME"/public_rsync ] || { password_authentication; exit 1; } - exec rrsync -ro "$HOME"/public_rsync - exit 1 - ;; - rsync\ --server\ *) - [ -d "$HOME"/incoming_rsync -a "${SSH_CLIENT_FINGERPRINT}" ] || { password_authentication; exit 1; } - destdir=$HOME/incoming_rsync/$SSH_CLIENT_FINGERPRINT/ - mkdir -p "$destdir" && exec rrsync "$destdir" - exit 1 - ;; - *) - #password_authentication - $default_command - exit - ;; -esac - -if [ "$git_cmd" = 'git-upload-pack' ]; then - case "$git_dir" in - $HOME/public_git/*|public_git/*) - is_gitdir "$git_dir" || git_dir="$git_dir/.git" - if ! is_gitdir "$git_dir"; then - # git rev-parse --resolve-git-dir "${git_dir%/.git}" # show git's error message - deny - fi - if [ "$git_ns" -a -e "$git_dir/refs/namespaces/$git_ns" ]; then - export GIT_NAMESPACE="$git_ns" - # maybe_initialize_heads - fi - exec "$git_cmd" "$git_dir" - ;; - esac - -elif [ "$git_cmd" = 'git-receive-pack' ]; then - - if [ ! -d "$git_dir" ]; then - if valid_new_public_repo "$git_dir"; then - initialize_git "$git_dir" "$SSH_CLIENT_FINGERPRINT" - else - deny - fi - fi - -fi - -if authorized "$git_dir"; then - if [ "$git_cmd" = 'git-receive-pack' ]; then - if ! ssh_user_owns_repository - then - export GIT_NAMESPACE="$SSH_CLIENT_FINGERPRINT" - maybe_initialize_heads - printf '%s:%s\n' 'd@cryptonomic.net' "git_namespace/$GIT_NAMESPACE/${git_dir#${HOME}/}" >&2 - fi - fi - exec "$git_cmd" "$git_dir" -else - $default_command - exit - # echo 'Error: git access is unauthorized' >&2; exit 1 # unreached -fi -- cgit v1.2.3