summaryrefslogtreecommitdiff
path: root/EndoForge/src/AnonymousAccessCommand
blob: e000811ade4983e781ac4624c4ea6eb2a234c17d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/bin/sh
default_msg()
{
    sshfpline="$(authline_to_sshfp "$authline" "${SSH_CLIENT%% *}")"
    cat <<EOF >&2

    You are:

        $authline
        $sshfpline

EOF
}

not_self_forge_message()
{
    cat <<EOF >&2
Error: access denied.  The specified directory is not a self-forge.

    To enable anonymous access, use the following commands:

        ssh $(id -un)@$(hostname)
        cd "$1"
        git config core.self-forge true

EOF
}

authline_to_sshfp()
{
    (
        authline=$1
        dnsname=${2:-.}

        authfile=$(mktemp) || exit
        trap 'rm -f "$authfile"' EXIT
        echo "$authline" > "$authfile"
        ssh-keygen -f "$authfile" -r "$dnsname" |
            while read line
            do
                set -- $line
                if [ "$3 $5" = "SSHFP 2" ]
                then
                    echo "$line"
                    break
                fi
            done
    )
}

ssh_client_fingerprint_base16()
{
    set -- $(authline_to_sshfp "$authline")
    [ "$6" ]
    echo $6
}

is_self_forge()
{
    local dir="$1" confval
    [ -d "$dir" ] || return
    confval=$(GIT_DIR=$dir git config core.self-forge) || return
    [ "$confval" = true ]
}

with_soul_bare()
{
    (
        set -eC
        lockfile=$GIT_DIR/index.lock
        echo $$ > "$lockfile"
        trap 'rm -f "$lockfile"' EXIT

        git config core.bare true
        "$@"
        git config core.bare false
    )
}

unsupported()
{
    echo "$0: Error: unsupported" >&2
}

read authtype authline < "$SSH_USER_AUTH" || exit
[ "$authtype" = publickey ] || exit

cmd=${SSH_ORIGINAL_COMMAND%% *}
case "$cmd" in
    git-send-pack | git-upload-pack | git-receive-pack ) ;;
    * )
        default_msg
        exit
        ;;
esac

arg=${SSH_ORIGINAL_COMMAND#* }
arg=${arg%\'}
arg=${arg#\'}
case "$arg" in
    *\'* )
        unsupported
        exit
        ;;
esac

if ! dir=$(readlink -e "$arg")
then exit
elif [ -d "$dir"/.git ]
then dir=$dir/.git
fi

if ! is_self_forge "$dir"
then
    not_self_forge_message "$arg"
    exit
fi

case "$cmd" in
    git-send-pack | git-upload-pack )
        GIT_NAMESPACE=
        "$cmd" "$dir"
        ;;
    git-receive-pack )
        export GIT_NAMESPACE="$(ssh_client_fingerprint_base16)"
        [ "$GIT_NAMESPACE" ]
        GIT_DIR=$dir with_soul_bare "$cmd" "$dir"
        ;;
esac