summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2020-05-05 19:09:56 -0400
committerAndrew Cady <d@jerkface.net>2020-05-05 19:18:59 -0400
commitdb4cdab4a87e5cbe118535039e7a4cae0c140211 (patch)
tree4795bcbd44b6ea704239744d77620797f64dcfdb
parentbe86419c6f2282fd1387621833d13b165a50aefe (diff)
avoid use of SHA-1
refactor producing samizdat-ssh-uid
-rwxr-xr-xsrc/dyndns-command.sh89
-rwxr-xr-xsrc/samizdat-ssh-command69
-rwxr-xr-xsrc/samizdat-ssh-uid39
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
2subdomain=${SSH_REMOTE_FINGERPRINT//:/}
3ip_address=${SSH_CLIENT%% *}
4lan_address="$SSH_ORIGINAL_COMMAND"
5 2
6domain=ssh.cryptonomic.net 3die() { printf '%s\n' "$*" >&2; exit 1; }
7 4
8sqlescape() 5sql_string()
9{ 6{
10 printf '%s' "'${1/\'/\'\'}'" 7 printf '%s' "'${1//\'/\'\'}'"
11} 8}
12 9
13add() 10powerdns_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
18BEGIN; 18BEGIN;
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;
39COMMIT; 39COMMIT;
40END 40END
41 if [ $? = 0 ]; then
42 printf '%s\n' "$1 $2"
43 fi
44} 41}
45 42
46add "$subdomain" "$ip_address" 43add()
47 44{
48set -- $lan_address 45 local record_type
49while [ $# -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" \
59done 53 && printf '%s %s\n' "$1.$domain $2"
54}
55
56main()
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
74PEM_DEST=$HOME/public_rsync
75
76PATH=$HOME/bin:$PATH
77
78eval "$(samizdat-ssh-uid --copy-pem "$PEM_DEST")"
79
80domain=${SSH_CLIENT_DOMAIN}
81subdomain=${SSH_CLIENT_FINGERPRINT}
82ip_address=${SSH_CLIENT%% *}
83
84main "$@"
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
2default_command="$HOME/samizdat-default-command"
3if ! [ "$default_command" ] || ! [ -e "$default_command" ]
4then
5 default_command=password_authentication
6fi
7
2authorize() 8authorize()
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
17add_before_sentinel() 27add_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()
25password_authentication() 35password_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
144check_if_ssh_user_owns_repository() 154check_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}
148ssh_user_owns_repository() 158ssh_user_owns_repository()
149{ 159{
@@ -165,11 +175,11 @@ is_public_repository()
165 175
166authorized() 176authorized()
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
175maybe_initialize_heads() 185maybe_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
206fi 221fi
207 222
208 223eval "$(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
218USE_MD5_SIG=
219if [ "$USE_MD5_SIG" ]; then
220 SSH_REMOTE_FINGERPRINT_TRIMMED=$(echo $SSH_REMOTE_FINGERPRINT|tr -d :)
221else
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')
224fi
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 ;;
274esac 274esac
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"
314else 314else
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
317fi 318fi
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
3die() { 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
8PEMFILE="${SSH_USER_AUTH}.tmp"
9
10sed -ne 's/^publickey //p' < "${SSH_USER_AUTH}" > "${PEMFILE}" || die "could not rewrite SSH_USER_AUTH file"
11
12SSH_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
15read keytype keydata < "${PEMFILE}" || die "reading from PEMFILE=$PEMFILE"
16case "$keytype" in
17 ssh-rsa|ssh-dss|ecdsa-sha2-nistp256|ssh-ed25519)
18 domain=$keytype.cryptonomic.net ;;
19 *)
20 die "Unsupported key type: $keytype" ;;
21esac
22
23if [ "$1" = '--copy-pem' -a "$2" ]
24then
25 if [ -d "$2" ] || mkdir "$2"
26 then
27 mv "${PEMFILE}" "$2"/${SSH_CLIENT_FINGERPRINT}.${keytype}.pem
28 fi
29else
30 rm -f "${PEMFILE}"
31fi
32
33env -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