diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/dyndns-command.sh | 89 | ||||
-rwxr-xr-x | src/samizdat-ssh-command | 69 | ||||
-rwxr-xr-x | src/samizdat-ssh-uid | 39 |
3 files changed, 131 insertions, 66 deletions
diff --git a/src/dyndns-command.sh b/src/dyndns-command.sh index 1061b31..8530058 100755 --- a/src/dyndns-command.sh +++ b/src/dyndns-command.sh | |||
@@ -1,24 +1,24 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | subdomain=${SSH_REMOTE_FINGERPRINT//:/} | ||
3 | ip_address=${SSH_CLIENT%% *} | ||
4 | lan_address="$SSH_ORIGINAL_COMMAND" | ||
5 | 2 | ||
6 | domain=ssh.cryptonomic.net | 3 | die() { printf '%s\n' "$*" >&2; exit 1; } |
7 | 4 | ||
8 | sqlescape() | 5 | sql_string() |
9 | { | 6 | { |
10 | printf '%s' "'${1/\'/\'\'}'" | 7 | printf '%s' "'${1//\'/\'\'}'" |
11 | } | 8 | } |
12 | 9 | ||
13 | add() | 10 | powerdns_sqlite_add_replace_record() |
14 | { | 11 | { |
15 | local newdomain="$(sqlescape "$1.$domain")" ip_address="$(sqlescape "$2")" domain="$(sqlescape "$domain")" | 12 | local sql_new_domain="$(sql_string "$1.$3")" |
13 | local sql_ip_address="$(sql_string "$2")" | ||
14 | local sql_domain="$(sql_string "$3")" | ||
15 | local record_type="$(sql_string "$4")" | ||
16 | 16 | ||
17 | sqlite3 /etc/powerdns/powerdns.sqlite3 <<END | 17 | sqlite3 /etc/powerdns/powerdns.sqlite3 <<END |
18 | BEGIN; | 18 | BEGIN; |
19 | delete from records where type='A' and name=$newdomain; | 19 | DELETE FROM records WHERE type=$record_type AND name=$sql_new_domain; |
20 | 20 | ||
21 | insert into records | 21 | INSERT INTO records |
22 | 22 | ||
23 | (domain_id, | 23 | (domain_id, |
24 | name, | 24 | name, |
@@ -27,33 +27,58 @@ BEGIN; | |||
27 | ttl, | 27 | ttl, |
28 | prio) | 28 | prio) |
29 | 29 | ||
30 | select | 30 | SELECT |
31 | id, | 31 | id, |
32 | $newdomain, | 32 | $sql_new_domain, |
33 | 'A', | 33 | $record_type, |
34 | $ip_address, | 34 | $sql_ip_address, |
35 | 3600, | 35 | 3600, |
36 | 0 | 36 | 0 |
37 | from domains | 37 | FROM domains |
38 | where name=$domain; | 38 | WHERE name=$sql_domain; |
39 | COMMIT; | 39 | COMMIT; |
40 | END | 40 | END |
41 | if [ $? = 0 ]; then | ||
42 | printf '%s\n' "$1 $2" | ||
43 | fi | ||
44 | } | 41 | } |
45 | 42 | ||
46 | add "$subdomain" "$ip_address" | 43 | add() |
47 | 44 | { | |
48 | set -- $lan_address | 45 | local record_type |
49 | while [ $# -ge 2 ]; do | 46 | case "$2" in |
50 | d=$1 | 47 | *.*.*.*) record_type=A ;; |
51 | ip=$2 | 48 | *:*) record_type=AAAA ;; |
52 | shift 2 | 49 | *) exit 1 ;; |
53 | |||
54 | case "$d" in | ||
55 | *.*) continue;; | ||
56 | esac | 50 | esac |
57 | 51 | ||
58 | add "$d.$subdomain" "$ip" | 52 | powerdns_sqlite_add_replace_record "$1" "$2" "$domain" "$record_type" \ |
59 | done | 53 | && printf '%s %s\n' "$1.$domain $2" |
54 | } | ||
55 | |||
56 | main() | ||
57 | { | ||
58 | add "$subdomain" "$ip_address" | ||
59 | |||
60 | set -- $SSH_ORIGINAL_COMMAND | ||
61 | while [ $# -ge 2 ]; do | ||
62 | d=$1 | ||
63 | ip=$2 | ||
64 | shift 2 | ||
65 | |||
66 | case "$d" in | ||
67 | *.*) continue;; | ||
68 | esac | ||
69 | |||
70 | add "$d.$subdomain" "$ip" | ||
71 | done | ||
72 | } | ||
73 | |||
74 | PEM_DEST=$HOME/public_rsync | ||
75 | |||
76 | PATH=$HOME/bin:$PATH | ||
77 | |||
78 | eval "$(samizdat-ssh-uid --copy-pem "$PEM_DEST")" | ||
79 | |||
80 | domain=${SSH_CLIENT_DOMAIN} | ||
81 | subdomain=${SSH_CLIENT_FINGERPRINT} | ||
82 | ip_address=${SSH_CLIENT%% *} | ||
83 | |||
84 | main "$@" | ||
diff --git a/src/samizdat-ssh-command b/src/samizdat-ssh-command index 94679f2..79053fd 100755 --- a/src/samizdat-ssh-command +++ b/src/samizdat-ssh-command | |||
@@ -1,12 +1,21 @@ | |||
1 | #!/bin/dash | 1 | #!/bin/dash |
2 | default_command="$HOME/samizdat-default-command" | ||
3 | if ! [ "$default_command" ] || ! [ -e "$default_command" ] | ||
4 | then | ||
5 | default_command=password_authentication | ||
6 | fi | ||
7 | |||
2 | authorize() | 8 | authorize() |
3 | { | 9 | { |
4 | local pkey line authorized_keys_line cmd | 10 | local authtype authdata forced_command comment authorized_keys_line |
5 | [ "$SSH_USER_AUTH" -a -f "$SSH_USER_AUTH" ] || return | 11 | [ "$SSH_USER_AUTH" -a -f "$SSH_USER_AUTH" ] || return |
6 | read pkey line < "$SSH_USER_AUTH" || return | 12 | read authtype authdata < "$SSH_USER_AUTH" || return |
7 | [ "$pkey" = publickey ] || return | 13 | [ "$authtype" = publickey ] || return |
14 | |||
15 | forced_command="command=\"${0} authorize-full-access\",no-port-forwarding" | ||
16 | comment="samizdat: password-authenticated from ${SSH_CONNECTION%% *}" | ||
8 | 17 | ||
9 | authorized_keys_line="$line samizdat: password-authenticated from ${SSH_CONNECTION%% *}" | 18 | authorized_keys_line="$forced_command $authdata $comment" |
10 | sentinel='Samizdat - YES WE CAN' | 19 | sentinel='Samizdat - YES WE CAN' |
11 | 20 | ||
12 | su - "$USER" -c 'mkdir -p "$HOME"/.ssh; touch "$HOME"/.ssh/authorized_keys' && | 21 | su - "$USER" -c 'mkdir -p "$HOME"/.ssh; touch "$HOME"/.ssh/authorized_keys' && |
@@ -14,6 +23,7 @@ authorize() | |||
14 | "$authorized_keys_line" \ | 23 | "$authorized_keys_line" \ |
15 | "$HOME"/.ssh/authorized_keys | 24 | "$HOME"/.ssh/authorized_keys |
16 | } | 25 | } |
26 | |||
17 | add_before_sentinel() | 27 | add_before_sentinel() |
18 | { | 28 | { |
19 | local sentinel="$1" add_me="$2" target="$3" | 29 | local sentinel="$1" add_me="$2" target="$3" |
@@ -25,7 +35,7 @@ add_before_sentinel() | |||
25 | password_authentication() | 35 | password_authentication() |
26 | { | 36 | { |
27 | [ "$USER" ] || { echo 'Error: no $USER' >&2; exit 1; } | 37 | [ "$USER" ] || { echo 'Error: no $USER' >&2; exit 1; } |
28 | [ "$SSH_REMOTE_KEY" ] || { echo 'Error: no $SSH_REMOTE_KEY' >&2; exit 1; } | 38 | [ "$SSH_CLIENT_FINGERPRINT" ] || { echo 'Error: no $SSH_CLIENT_FINGERPRINT' >&2; exit 1; } |
29 | 39 | ||
30 | tty=$(tty) && [ "$tty" != 'not a tty' ] || tty= | 40 | tty=$(tty) && [ "$tty" != 'not a tty' ] || tty= |
31 | 41 | ||
@@ -143,7 +153,7 @@ valid_new_public_repo() | |||
143 | 153 | ||
144 | check_if_ssh_user_owns_repository() | 154 | check_if_ssh_user_owns_repository() |
145 | { | 155 | { |
146 | git --git-dir "$git_dir" config --get-all samizdat.anonymous-ssh-owner | grep -xqF "$SSH_REMOTE_FINGERPRINT_TRIMMED" | 156 | git --git-dir "$git_dir" config --get-all samizdat.anonymous-ssh-owner | grep -xqF "$SSH_CLIENT_FINGERPRINT" |
147 | } | 157 | } |
148 | ssh_user_owns_repository() | 158 | ssh_user_owns_repository() |
149 | { | 159 | { |
@@ -165,11 +175,11 @@ is_public_repository() | |||
165 | 175 | ||
166 | authorized() | 176 | authorized() |
167 | { | 177 | { |
168 | # TODO: check SSH_REMOTE_FINGERPRINT against a blacklist | 178 | # TODO: check SSH_CLIENT_FINGERPRINT against a blacklist |
169 | ssh_user_owns_repository && return | 179 | ssh_user_owns_repository && return |
170 | is_public_repository && return | 180 | is_public_repository && return |
171 | test "$(git --git-dir "$1" config --bool --get samizdat.allow-anonymous-access)" = true 2>/dev/null && return 0 | 181 | test "$(git --git-dir "$1" config --bool --get samizdat.allow-anonymous-access)" = true 2>/dev/null && return 0 |
172 | # TODO: check SSH_REMOTE_FINGERPRINT against a whitelist | 182 | # TODO: check SSH_CLIENT_FINGERPRINT against a whitelist |
173 | } | 183 | } |
174 | 184 | ||
175 | maybe_initialize_heads() | 185 | maybe_initialize_heads() |
@@ -197,31 +207,20 @@ if [ "$1" = "authorize-full-access" ]; then | |||
197 | "") | 207 | "") |
198 | shell=$(getent passwd $USER|cut -d: -f7) | 208 | shell=$(getent passwd $USER|cut -d: -f7) |
199 | argv0=-${shell##*/} | 209 | argv0=-${shell##*/} |
200 | exec chpst -b "$argv0" "$shell" | 210 | if which chpst >/dev/null 2>&1; then |
211 | exec chpst -b "$argv0" "$shell" | ||
212 | else | ||
213 | exec "$shell" | ||
214 | fi | ||
201 | ;; | 215 | ;; |
202 | *) | 216 | *) |
203 | exec /bin/sh -c "$SSH_ORIGINAL_COMMAND" | 217 | exec /bin/sh -c "$SSH_ORIGINAL_COMMAND" |
204 | ;; | 218 | ;; |
205 | esac | 219 | esac |
220 | exit | ||
206 | fi | 221 | fi |
207 | 222 | ||
208 | 223 | eval "$(samizdat-ssh-uid)" || die eval | |
209 | (exec >&2 | ||
210 | #env | grep '^SSH_' | ||
211 | #cat "${SSH_USER_AUTH}" | ||
212 | #ssh-keygen -l -f "${SSH_USER_AUTH}" | ||
213 | #sed -i -e 's/^publickey //' "${SSH_USER_AUTH}" | ||
214 | #set -x | ||
215 | #ssh-keygen -r . -f "${SSH_USER_AUTH}" | sed -ne 's/^. IN SSHFP [0-9]* 1 /SHA1:/p' | ||
216 | ) | ||
217 | |||
218 | USE_MD5_SIG= | ||
219 | if [ "$USE_MD5_SIG" ]; then | ||
220 | SSH_REMOTE_FINGERPRINT_TRIMMED=$(echo $SSH_REMOTE_FINGERPRINT|tr -d :) | ||
221 | else | ||
222 | sed -i -e 's/^publickey //' "${SSH_USER_AUTH}" || die "error rewriting SSH_USER_AUTH file" | ||
223 | SSH_REMOTE_FINGERPRINT_TRIMMED=$(ssh-keygen -r . -f "${SSH_USER_AUTH}" | sed -ne 's/^. IN SSHFP [0-9]* 1 //p') | ||
224 | fi | ||
225 | 224 | ||
226 | # TODO: call password_authentication on all authorization failures | 225 | # TODO: call password_authentication on all authorization failures |
227 | 226 | ||
@@ -262,14 +261,15 @@ case "$SSH_ORIGINAL_COMMAND" in | |||
262 | exit 1 | 261 | exit 1 |
263 | ;; | 262 | ;; |
264 | rsync\ --server\ *) | 263 | rsync\ --server\ *) |
265 | [ -d "$HOME"/incoming_rsync -a "${SSH_REMOTE_FINGERPRINT_TRIMMED}" ] || { password_authentication; exit 1; } | 264 | [ -d "$HOME"/incoming_rsync -a "${SSH_CLIENT_FINGERPRINT}" ] || { password_authentication; exit 1; } |
266 | destdir=$HOME/incoming_rsync/$SSH_REMOTE_FINGERPRINT_TRIMMED/ | 265 | destdir=$HOME/incoming_rsync/$SSH_CLIENT_FINGERPRINT/ |
267 | mkdir -p "$destdir" && exec rrsync "$destdir" | 266 | mkdir -p "$destdir" && exec rrsync "$destdir" |
268 | exit 1 | 267 | exit 1 |
269 | ;; | 268 | ;; |
270 | *) | 269 | *) |
271 | password_authentication | 270 | #password_authentication |
272 | exit 1 # unreached | 271 | $default_command |
272 | exit | ||
273 | ;; | 273 | ;; |
274 | esac | 274 | esac |
275 | 275 | ||
@@ -293,7 +293,7 @@ elif [ "$git_cmd" = 'git-receive-pack' ]; then | |||
293 | 293 | ||
294 | if [ ! -d "$git_dir" ]; then | 294 | if [ ! -d "$git_dir" ]; then |
295 | if valid_new_public_repo "$git_dir"; then | 295 | if valid_new_public_repo "$git_dir"; then |
296 | initialize_git "$git_dir" "$SSH_REMOTE_FINGERPRINT_TRIMMED" | 296 | initialize_git "$git_dir" "$SSH_CLIENT_FINGERPRINT" |
297 | else | 297 | else |
298 | deny | 298 | deny |
299 | fi | 299 | fi |
@@ -305,13 +305,14 @@ if authorized "$git_dir"; then | |||
305 | if [ "$git_cmd" = 'git-receive-pack' ]; then | 305 | if [ "$git_cmd" = 'git-receive-pack' ]; then |
306 | if ! ssh_user_owns_repository | 306 | if ! ssh_user_owns_repository |
307 | then | 307 | then |
308 | export GIT_NAMESPACE="$SSH_REMOTE_FINGERPRINT_TRIMMED" | 308 | export GIT_NAMESPACE="$SSH_CLIENT_FINGERPRINT" |
309 | maybe_initialize_heads | 309 | maybe_initialize_heads |
310 | printf '%s:%s\n' 'd@cryptonomic.net' "git_namespace/$GIT_NAMESPACE/${git_dir#${HOME}/}" >&2 | 310 | printf '%s:%s\n' 'd@cryptonomic.net' "git_namespace/$GIT_NAMESPACE/${git_dir#${HOME}/}" >&2 |
311 | fi | 311 | fi |
312 | fi | 312 | fi |
313 | exec "$git_cmd" "$git_dir" | 313 | exec "$git_cmd" "$git_dir" |
314 | else | 314 | else |
315 | password_authentication | 315 | $default_command |
316 | echo 'Error: git access is unauthorized' >&2; exit 1 # unreached | 316 | exit |
317 | # echo 'Error: git access is unauthorized' >&2; exit 1 # unreached | ||
317 | fi | 318 | fi |
diff --git a/src/samizdat-ssh-uid b/src/samizdat-ssh-uid new file mode 100755 index 0000000..c87232b --- /dev/null +++ b/src/samizdat-ssh-uid | |||
@@ -0,0 +1,39 @@ | |||
1 | #!/bin/dash | ||
2 | |||
3 | die() { echo "$0: Error: $*" >&2; exit 1; } | ||
4 | |||
5 | [ "$SSH_USER_AUTH" ] || die "not defined: \$SSH_USER_AUTH" | ||
6 | [ -f "$SSH_USER_AUTH" ] || die "file does not exist: \$SSH_USER_AUTH=${SSH_USER_AUTH}" | ||
7 | |||
8 | PEMFILE="${SSH_USER_AUTH}.tmp" | ||
9 | |||
10 | sed -ne 's/^publickey //p' < "${SSH_USER_AUTH}" > "${PEMFILE}" || die "could not rewrite SSH_USER_AUTH file" | ||
11 | |||
12 | SSH_CLIENT_FINGERPRINT=$(ssh-keygen -r . -f "${PEMFILE}" | sed -ne 's/^. IN SSHFP [0-9]* 1 //p') && | ||
13 | [ "$SSH_CLIENT_FINGERPRINT" ] || die "could not determine ssh client fingerprint" | ||
14 | |||
15 | read keytype keydata < "${PEMFILE}" || die "reading from PEMFILE=$PEMFILE" | ||
16 | case "$keytype" in | ||
17 | ssh-rsa|ssh-dss|ecdsa-sha2-nistp256|ssh-ed25519) | ||
18 | domain=$keytype.cryptonomic.net ;; | ||
19 | *) | ||
20 | die "Unsupported key type: $keytype" ;; | ||
21 | esac | ||
22 | |||
23 | if [ "$1" = '--copy-pem' -a "$2" ] | ||
24 | then | ||
25 | if [ -d "$2" ] || mkdir "$2" | ||
26 | then | ||
27 | mv "${PEMFILE}" "$2"/${SSH_CLIENT_FINGERPRINT}.${keytype}.pem | ||
28 | fi | ||
29 | else | ||
30 | rm -f "${PEMFILE}" | ||
31 | fi | ||
32 | |||
33 | env -i \ | ||
34 | SSH_CLIENT_FINGERPRINT="$SSH_CLIENT_FINGERPRINT" \ | ||
35 | SSH_CLIENT_KEYTYPE="$keytype" \ | ||
36 | SSH_CLIENT_DOMAIN="$domain" \ | ||
37 | SSH_CLIENT_PEMFILE="$PEMFILE" \ | ||
38 | SSH_CLIENT_KEYDATA="$keydata" | ||
39 | |||