summaryrefslogtreecommitdiff
path: root/EndoForge
diff options
context:
space:
mode:
authorAndrew Cady <d@cryptonomic.net>2021-10-23 12:52:42 -0400
committerAndrew Cady <d@cryptonomic.net>2021-10-23 12:52:42 -0400
commit2e5909e761f40e42684fbaa71f3b5bcb49500567 (patch)
tree335259ca973c5e07807fcb97fb09a1f49fb2a1dc /EndoForge
parent4d14156fd5b306b366b4d74e1a5bbf82e0ae081a (diff)
move all files to EndoForge
Diffstat (limited to 'EndoForge')
-rw-r--r--EndoForge/Makefile40
-rw-r--r--EndoForge/README.md102
-rwxr-xr-xEndoForge/src/AnonymousAccessCommand126
-rwxr-xr-xEndoForge/src/AuthorizedKeysCommand15
-rw-r--r--EndoForge/src/anonymous-access.conf10
-rw-r--r--EndoForge/test/Makefile38
-rw-r--r--EndoForge/test/tests.sh66
7 files changed, 397 insertions, 0 deletions
diff --git a/EndoForge/Makefile b/EndoForge/Makefile
new file mode 100644
index 0000000..2501da9
--- /dev/null
+++ b/EndoForge/Makefile
@@ -0,0 +1,40 @@
1ifeq ($(shell id -u),0)
2SUDO =
3else
4SUDO = sudo
5endif
6
7ROOT_INSTALL = $(SUDO) install
8
9USER != echo "$${SUDO_USER:-$$(id -un)}"
10
11SSH_CONFIG_DIR = /etc/ssh
12SSHD_CONFIG_DIR = $(SSH_CONFIG_DIR)/sshd_config.d
13SSH_LIB_DIR = /usr/lib/ssh
14USER_SSH_CONFIG_DIR = ~$(USER)/.ssh
15
16BROWSER != 2>/dev/null which xdg-open || which w3m || which links || which elinks
17
18.PHONY: install shared doc test
19
20doc: README.html
21 $(BROWSER) $<
22
23shared: install
24 git config core.self-forge true
25
26SRC = src
27SOURCES = $(addprefix $(SRC), AnonymousAccessCommand anonymous-access.conf AuthorizedKeysCommand)
28
29install:
30 install -t $(USER_SSH_CONFIG_DIR) $(SRC)/AnonymousAccessCommand
31 $(ROOT_INSTALL) -d "$(SSH_CONFIG_DIR)" "$(SSHD_CONFIG_DIR)" "$(SSH_LIB_DIR)" || true
32 $(ROOT_INSTALL) -m0644 -t "$(SSHD_CONFIG_DIR)" $(SRC)/anonymous-access.conf || true
33 $(ROOT_INSTALL) -t "$(SSH_LIB_DIR)" $(SRC)/AuthorizedKeysCommand || true
34 [ -e "$(SSH_LIB_DIR)"/AuthorizedKeysCommand ] || $(SUDO) ln -s -t /etc/ssh "$(SSH_LIB_DIR)"/AuthorizedKeysCommand
35
36README.html: README.md
37 pandoc -t html $< > $@
38
39test:
40 make -C test
diff --git a/EndoForge/README.md b/EndoForge/README.md
new file mode 100644
index 0000000..9c22bf3
--- /dev/null
+++ b/EndoForge/README.md
@@ -0,0 +1,102 @@
1EndoForge
2---------
3Convert a Git repository into a Forge by merging this repository.
4
5
6
7
8
9
10WHAT IT DOES
11------------
12
13This repository contains the code to share itself (the repository)
14through Git-over-SSH.
15
16It also contains the code to listen for changes sent to itself through
17Git-over-SSH.
18
19
20
21
22
23
24HOW IT WORKS
25------------
26
27Git contains a program `git-receive-pack` which implements a git
28protocol server. The `git-receive-pack` expects to be launched as an SSH
29server "ForcedCommand" in a configuration that protects the server from
30untrustworthy users.
31
32Normally, the SSH server only permits users who have already uploaded
33their public keys to the server. It assumes that access should be closed
34to new users.
35
36Installing this code reverses that assumption, granting open access to
37unrecognized users. This is made safe by limiting write access to a
38GIT_NAMESPACE over which the user proves global mathematical ownership with
39their SSH client key. This means that the user cannot overwrite anyone else's
40data.
41
42The user's uploaded data is still saved and is ready to be be merged into the
43main repository manually, or even automatically.
44
45
46
47
48
49HOW TO INSTALL
50--------------
51
52Run:
53```
54 make install
55```
56
57This installs the `AnonymousAccessCommand` in the current user's home
58directory.
59
60Then, if sudo access is available, it enables anonymous access by
61editing the system `OpenSSH` configuration.
62
63
64
65
66
67
68NON-ROOT INSTALLATION
69---------------------
70
71If sudo access is not available, you can install to a different
72location:
73
74```
75 make SSH_CONFIG_DIR=.config/ssh \
76 SSHD_CONFIG_DIR=.config/ssh/config.d \
77 SSH_LIB_DIR=.local/lib/ssh \
78 install
79```
80
81Then you will need to run `OpenSSH` on a non-default port (the default
82port requires root access).
83
84
85
86
87
88
89ALTERNATIVE LOCATION OF `AnonymousAccessCommand`
90------------------------------------------------
91
92It is also possible to choose the location of the
93`AnonymousAccessCommand` itself:
94
95```
96 make USER_SSH_CONFIG_DIR=$HOME/.config/ssh \
97 install
98```
99
100First you would have to make the contents of the installed file
101`AuthorizedKeysCommand` vary according to that `Makefile` paremeter, by
102editing `Makefile`.
diff --git a/EndoForge/src/AnonymousAccessCommand b/EndoForge/src/AnonymousAccessCommand
new file mode 100755
index 0000000..443d25e
--- /dev/null
+++ b/EndoForge/src/AnonymousAccessCommand
@@ -0,0 +1,126 @@
1#!/bin/sh
2default_msg()
3{
4 sshfpline="$(get_sshfp_authline ${SSH_CLIENT%% *})"
5 cat <<EOF >&2
6
7 You are:
8
9 $authline
10 $sshfpline
11
12EOF
13}
14
15get_sshfp_authline()
16{
17 (
18 r=${1:-.}
19 key=$(mktemp) || exit
20 trap 'rm -rf "$key"' EXIT
21 echo "$authline" > "$key"
22 get_sshfp "$key" "$r"
23 )
24}
25
26get_sshfp()
27{
28 (
29 key="$1"
30 r="${2:-.}"
31 dns=$(mktemp) || exit
32 trap 'rm -rf "$dns"' EXIT
33
34 ssh-keygen -r "$r" -f "$key" > "$dns"
35 exec < "$dns"
36 while read line
37 do
38 set -- $line
39 if [ "$3 $5" = "SSHFP 2" ]
40 then
41 echo "$line"
42 break
43 fi
44 done
45 )
46}
47
48ssh_client_fingerprint_base16()
49{
50 set -- $(get_sshfp_authline)
51 [ "$6" ]
52 echo $6
53}
54
55check_if_self_forge()
56{
57 # TODO: don't use description, but something else.
58 local dir="$1"
59 [ -d "$dir" ] || exit
60 [ -r "$dir"/description ] || exit
61 read description < "$dir"/description
62 if [ "$description" != self-forge ] && [ "$(GIT_DIR=$dir git config core.self-forge)" != true ]
63 then
64 echo 'Error: access denied. The specified directory is not a self-forge.' >&2
65 exit
66 fi
67}
68
69read authtype authline < "$SSH_USER_AUTH" || exit
70[ "$authtype" = publickey ] || exit
71
72cmd=${SSH_ORIGINAL_COMMAND%% *}
73
74case "$cmd" in
75 git-send-pack | git-upload-pack)
76 GIT_NAMESPACE=
77 ;;
78 git-receive-pack)
79 export GIT_NAMESPACE="$(ssh_client_fingerprint_base16)"
80 [ "$GIT_NAMESPACE" ] || exit
81 ;;
82 *)
83 default_msg
84 exit
85 ;;
86esac
87
88arg=${SSH_ORIGINAL_COMMAND#* }
89arg=${arg%\'}
90arg=${arg#\'}
91case "$arg" in
92 *\'*) exit ;;
93 *.git) ;;
94 *) arg=$arg/.git ;;
95esac
96
97dir=$(readlink -e "$arg") || exit
98
99check_if_self_forge "$dir"
100
101with_allowCurrentBranch()
102{
103 local cmd="$1" dir="$2"
104 (
105 set -eC
106 lockfile=$GIT_DIR/index.lock
107 echo $$ > "$lockfile"
108 trap 'rm -f "$lockfile"' EXIT
109
110 # This doesn't seem very secure. Need to patch git probably.
111 for deny in CurrentBranch # DeleteCurrent
112 do git config receive.deny$deny false
113 done
114 "$@"
115 for deny in CurrentBranch # DeleteCurrent
116 do git config receive.deny$deny true
117 done
118 )
119}
120
121if [ "$GIT_NAMESPACE" ]
122then
123 GIT_DIR=$dir with_allowCurrentBranch "$cmd" "$dir"
124else
125 "$cmd" "$dir"
126fi
diff --git a/EndoForge/src/AuthorizedKeysCommand b/EndoForge/src/AuthorizedKeysCommand
new file mode 100755
index 0000000..6e13063
--- /dev/null
+++ b/EndoForge/src/AuthorizedKeysCommand
@@ -0,0 +1,15 @@
1#!/bin/sh
2username=$1
3userhome=$2
4fingerprint=$3
5authline="$4 $5"
6
7case "$userhome" in
8 *'"'*) exit ;;
9esac
10
11usercommand=$userhome/.ssh/AnonymousAccessCommand
12
13[ -x "$usercommand" ] || exit
14
15printf 'command="%s",no-port-forwarding %s\n' "$usercommand $fingerprint" "$authline"
diff --git a/EndoForge/src/anonymous-access.conf b/EndoForge/src/anonymous-access.conf
new file mode 100644
index 0000000..5cd6b6a
--- /dev/null
+++ b/EndoForge/src/anonymous-access.conf
@@ -0,0 +1,10 @@
1ExposeAuthInfo=yes
2AuthorizedKeysCommandUser=root
3AuthorizedKeysCommand=/etc/ssh/AuthorizedKeysCommand %u %h %f "%t %k"
4
5# %u The username.
6# %h The home directory of the user.
7# %f The fingerprint of the key or certificate.
8# %t The key or certificate type.
9# %k The base64-encoded key or certificate for authentication.
10
diff --git a/EndoForge/test/Makefile b/EndoForge/test/Makefile
new file mode 100644
index 0000000..3bc1a66
--- /dev/null
+++ b/EndoForge/test/Makefile
@@ -0,0 +1,38 @@
1.DEFAULT_GOAL = test
2
3include ../Makefile
4
5testuser = testuser
6
7SU = $(SUDO) su
8
9.PHONY: test useradd cleanuser
10
11useradd:
12 $(SUDO) useradd $(testuser) --shell /bin/bash --create-home
13 $(SU) - $(testuser) -c 'ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""'
14 $(SU) - $(testuser) -c 'git config --global user.name $(testuser)'
15 $(SU) - $(testuser) -c 'git config --global user.email $(testuser)'
16
17test: $(shell getent passwd $(testuser) >/dev/null || echo useradd)
18 $(ROOT_INSTALL) -t ~$(testuser) tests.sh
19 $(SU) - $(testuser) -c ./tests.sh
20
21ifeq ($(testuser),)
22$(error testuser not defined)
23endif
24cleanuser_command = $(SUDO) rm -I -r ~$(testuser)
25
26cleanuser:
27 : Preparing to run destructive command:
28 :
29 :
30 : $(cleanuser_command)
31 :
32 :
33 : Press ctrl-c to abort.
34 :
35 @for n in 5 4 3 2 1; do printf ' %d\r' "$$n"; sleep 1; done
36 $(cleanuser_command) || true
37 $(SUDO) userdel testuser || true
38
diff --git a/EndoForge/test/tests.sh b/EndoForge/test/tests.sh
new file mode 100644
index 0000000..37f819f
--- /dev/null
+++ b/EndoForge/test/tests.sh
@@ -0,0 +1,66 @@
1#!/bin/sh
2set -ex
3USER=u
4DIR=src/anonymous-ssh
5HOST=localhost
6SSH_ID=~/.ssh/id_ed25519
7
8get_sshfp()
9{
10 (
11 key="$1"
12 r="${2:-.}"
13 dns=$(mktemp) || exit
14 trap 'rm -rf "$dns"' EXIT
15
16 ssh-keygen -r "$r" -f "$key" > "$dns"
17 exec < "$dns"
18 while read line
19 do
20 set -- $line
21 if [ "$3 $5" = "SSHFP 2" ]
22 then
23 echo "$line"
24 break
25 fi
26 done
27 )
28}
29
30make_test_commit()
31{
32 newfile=newfile.$(date -Ins|tr -d :)
33 touch "$newfile"
34 git add "$newfile"
35 git commit -m "$newfile"
36}
37
38[ -e "$SSH_ID" ] || ssh-keygen -t ed25519 -f "$SSH_ID" -P ''
39
40git_namespace=$(set -- $(get_sshfp "$SSH_ID") && echo $6)
41
42ssh -o NoHostAuthenticationForLocalhost=yes $USER@$HOST -- test || true
43[ ! -e anonymous-ssh ] || rm -rf anonymous-ssh
44export GIT_SSH_COMMAND="ssh -o NoHostAuthenticationForLocalhost=yes -i $SSH_ID"
45git clone -v ${USER}@${HOST}:${DIR}
46cd anonymous-ssh
47
48make install
49
50git pull --ff-only
51make_test_commit
52git push -f
53make_test_commit
54git push
55git log -n4
56git pull --ff-only
57git log -n4
58git push
59
60# branch=$(git branch -q --show-current)
61# forkname=origin-myfork
62# ns_branch=refs/namespaces/$git_namespace/refs/heads/$branch
63# git remote add -m "$ns_branch" "$forkname" $(git remote get-url origin)
64# git push "$forkname"
65# git pull "$forkname" --ff-only "$branch"
66exit