aboutsummaryrefslogtreecommitdiffstats
path: root/tests/drop-privileges
blob: fd432d99d248af3e761073c26e2d47911bd58cce (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# Check privilige drop: UID/GID changes, chdir, environment, and file
# descriptors

# ensure failure to drop privileges doesn't retain root privileges
sed -ri 's/^#(user|group)\s*=\s*$/\1 = nonexistent-\1/' /etc/lacme/lacme.conf
! lacme account 2>"$STDERR" || fail
grepstderr -Fxq "getgrnam(nonexistent-group)"
grepstderr -Fxq "Error: Invalid client version"

sed -ri 's/^group\s*=\s*nonexistent.*/#&/' /etc/lacme/lacme.conf
! lacme account 2>"$STDERR" || fail
grepstderr -Fxq "getpwnam(nonexistent-user)"
grepstderr -Fxq "Error: Invalid client version"

# create wrapper to inspect processes
STATUSDIR="/dev/shm/lacme-wrap"
install -oroot -groot -m0755 /dev/stdin /run/lacme-wrap <<-EOF
	#!/bin/sh
	set -ue
	PATH="/usr/bin:/bin"
	export PATH

	prefix="$STATUSDIR/\${1##*[/-]}"
	cat </proc/\$\$/status >"\$prefix/status"
	pwd >"\$prefix/cwd"
	stat -c "%U:%G %#a" . >"\$prefix/cwd-mod"
	sort -z </proc/\$\$/environ | tr "\\0" "\\n" >"\$prefix/environ"
	( find -P /proc/\$\$/fd -mindepth 1 \! -lname "\$0" -printf "%P %#m %U:%G %l\\n" >"\$prefix/fd" )

	exec "\$@"
EOF

# also check privilege drop for the spawned accountd
adduser --system --group \
       --home /nonexistent --no-create-home \
       --gecos "lacme account user" \
       --quiet lacme-account
sed -ri 's/^#?(user|group)\s*=\s*nonexistent.*/\1 = lacme-account/' /etc/lacme/lacme.conf
chown lacme-account: /etc/lacme/account.key

install -oroot -groot -dm0755 -- "$STATUSDIR"
install -olacme-account -groot -dm0700 -- "$STATUSDIR/accountd"
install -o_lacme-client -groot -dm0700 -- "$STATUSDIR/client"
install -o_lacme-www    -groot -dm0700 -- "$STATUSDIR/webserver"

# test with a group that's not the primary group (nogroup) of _lacme-www etc
addgroup --system nogroup2
sed -ri 's|^#?group\s*=\s*nogroup$|group = nogroup2|' /etc/lacme/lacme.conf
sed -ri 's|^#?command\s*=.*/lacme-accountd$|command = /run/lacme-wrap /usr/bin/lacme-accountd|' /etc/lacme/lacme.conf
sed -ri 's|^#?command\s*=.*/lacme/client$|command = /run/lacme-wrap /usr/libexec/lacme/client|' /etc/lacme/lacme.conf
sed -ri 's|^#?command\s*=.*/lacme/webserver$|command = /run/lacme-wrap /usr/libexec/lacme/webserver|' /etc/lacme/lacme.conf
sed -ri 's|^#?config\s*=\s*$|config = /etc/lacme/lacme-accountd.conf|' /etc/lacme/lacme.conf

check_status() {
    local path="$STATUSDIR/$1/status" user="$2" group="$3"
    UID="$(getent passwd "$user"  | cut -sd: -f3)"
    GID="$(getent group  "$group" | cut -sd: -f3)"
    [ -n "$UID" -a -n "$GID" ] || return 1
    grep -Ex "Uid:\\s+$UID\\s+$UID\\s+$UID\\s+$UID" "$path" || return 1
    grep -Ex "Gid:\\s+$GID\\s+$GID\\s+$GID\\s+$GID" "$path" || return 1
    grep -Ex "Groups:\s+$GID\s*" "$path" || return 1
}
check_cwd() {
    local path="$STATUSDIR/$1/cwd" dir="$2" cwd
    cwd="$(cat <"$path")" || return 1
    [ "$cwd" = "$dir" ] || return 1
}

check_accountd() {
    local socket_ino stderr prefix="$STATUSDIR/accountd"
    check_status accountd lacme-account lacme-account || return 1
    check_cwd    accountd / || return 1

    diff --label="a/accountd/environ" --label="b/accountd/environ" \
            --color=auto --unified "$prefix/environ" - <<-EOF
		HOME=/nonexistent
		LOGNAME=lacme-account
		PATH=/usr/bin:/bin
		SHELL=/usr/sbin/nologin
		TERM=$TERM
		USER=lacme-account
	EOF

    stderr="$(readlink -e "/proc/$$/fd/2")"
    socket_ino="$(sed -rn '/^0 .* socket:\[([0-9]+)\]$/ {s//\1/p;q}' "$prefix/fd")"
    [ -n "$socket_ino" ] || return 1
    grep -Fxq "0 0700 $UID:$GID socket:[$socket_ino]" "$prefix/fd" || return 1
    grep -Fxq "1 0700 $UID:$GID socket:[$socket_ino]" "$prefix/fd" || return 1
    grep -Fxq "2 0700 $UID:$GID $stderr" "$prefix/fd" || return 1
    sed -ri '\#^[012] #d' "$prefix/fd"
    ! test -s "$prefix/fd" || return 1
}
check_client() {
    local command="$1" cwd="$2" UID GID stdout stderr prefix="$STATUSDIR/client"
    check_status client _lacme-client nogroup2
    check_cwd    client "$cwd"

    diff --label="a/client/environ" --label="b/client/environ" \
            --color=auto --unified "$prefix/environ" - <<-EOF
		DEBUG=0
		HOME=/nonexistent
		LOGNAME=_lacme-client
		PATH=/usr/bin:/bin
		SHELL=/usr/sbin/nologin
		TERM=$TERM
		USER=_lacme-client
	EOF

    stdout="$(readlink -e "/proc/$$/fd/1")"
    stderr="$(readlink -e "/proc/$$/fd/2")"
    if [ "$command" = "account" ]; then # no pipe
        grep -Fxq "0 0500 $UID:$GID /dev/null" "$prefix/fd" || return 1
        grep -Fxq "1 0700 $UID:$GID $stdout"   "$prefix/fd" || return 1
    elif [ "$command" = "order" ]; then
        grep -Exq "0 0500 $UID:$GID pipe:\[[0-9]+\]" "$prefix/fd" || return 1
        grep -Exq "1 0300 $UID:$GID pipe:\[[0-9]+\]" "$prefix/fd" || return 1
    else
        exit 1
    fi
    grep -Fxq "2 0700 $UID:$GID $stderr" "$prefix/fd" || return 1
    sed -ri '\#^[012] #d' "$prefix/fd"

    grep -Exq "[0-9]+ 0700 $UID:$GID socket:\[[0-9]+\]" "$prefix/fd" || return 1
    sed -ri '0,\#^[0-9]+ .* socket:\[[0-9]+\]$# {//d}' "$prefix/fd"

    grep -Exq "[0-9]+ 0500 $UID:$GID /etc/lacme/lacme\.conf" "$prefix/fd" || return 1
    sed -ri '0,\#^[0-9]+ .* /etc/lacme/lacme\.conf$# {//d}' "$prefix/fd"
    ! test -s "$prefix/fd" || return 1
}
check_webserver() {
    local cwd="$1" UID GID stdout stderr prefix="$STATUSDIR/webserver"
    check_status webserver _lacme-www nogroup2
    check_cwd    webserver "$cwd"

    diff --label="a/webserver/environ" --label="b/webserver/environ" \
            --color=auto --unified "$prefix/environ" - <<-EOF
		DEBUG=0
		HOME=/nonexistent
		LOGNAME=_lacme-www
		PATH=/usr/bin:/bin
		SHELL=/usr/sbin/nologin
		TERM=$TERM
		USER=_lacme-www
	EOF

    stdout="$(readlink -e "/proc/$$/fd/1")"
    stderr="$(readlink -e "/proc/$$/fd/2")"
    grep -Fxq "0 0500 $UID:$GID /dev/null"  "$prefix/fd" || return 1
    grep -Fxq "1 0700 $UID:$GID $stdout" "$prefix/fd" || return 1
    grep -Fxq "2 0700 $UID:$GID $stderr" "$prefix/fd" || return 1
    sed -ri '\#^[012] #d' "$prefix/fd"

    grep -Exq "[0-9]+ 0700 $UID:$GID socket:\[[0-9]+\]" "$prefix/fd" || return 1
    sed -ri '0,\#^[0-9]+ .* socket:\[[0-9]+\]$# {//d}' "$prefix/fd"
    ! test -s "$prefix/fd" || return 1
}

lacme account
check_accountd
check_client account /
! test -e "$STATUSDIR/webserver/status" # account 'command' doesn't start the webserver

lacme newOrder
check_accountd
challenge_dir="$(cat "$STATUSDIR/webserver/cwd")"
[ "${challenge_dir#"/tmp/acme-challenge."}" != "$challenge_dir" ] || exit 1
check_client order "$challenge_dir"
check_webserver    "$challenge_dir"

# the temporary challenge directory is created with permissive mode
diff --label="a/webserver/cwd" --label="b/webserver/cwd" \
        --color=auto --unified "$STATUSDIR/webserver/cwd-mod" - <<-EOF
	_lacme-client:root 0755
EOF

# vim: set filetype=sh :