Rearrange conflicting tincd globals
[tinc] / test / command-fsck.test
1 #!/bin/sh
2
3 # shellcheck disable=SC1090
4 . "$TESTLIB_PATH"
5
6 foo_dir=$(peer_directory foo)
7 foo_host=$foo_dir/hosts/foo
8 foo_conf=$foo_dir/tinc.conf
9 foo_rsa_priv=$foo_dir/rsa_key.priv
10 foo_ec_priv=$foo_dir/ed25519_key.priv
11 foo_tinc_up=$foo_dir/tinc-up
12 foo_host_up=$foo_dir/host-up
13
14 if is_windows; then
15   foo_tinc_up=$foo_tinc_up.cmd
16   foo_host_up=$foo_host_up.cmd
17 fi
18
19 # Sample RSA key pair (old format). Uses e = 0xFFFF.
20 rsa_n=BB82C3A9B906E98ABF2D99FF9B320B229F5C1E58EC784762DA1F4D3509FFF78ECA7FFF19BA170736CDE458EC8E732DDE2C02009632DF731B4A6BD6C504E50B7B875484506AC1E49FD0DF624F6612F564C562BD20F870592A49195023D744963229C35081C8AE48BE2EBB5CC9A0D64924022DC0EB782A3A8F3EABCA04AA42B24B2A6BD2353A6893A73AE01FA54891DD24BF36CA032F19F7E78C01273334BAA2ECF36B6998754CB012BC985C975503D945E4D925F6F719ACC8FBA7B18C810FF850C3CCACD60565D4FCFE02A98FE793E2D45D481A34D1F90584D096561FF3184C462C606535F3F9BB260541DF0D1FEB16938FFDEC2FF96ACCC6BD5BFBC19471F6AB
21 rsa_d=8CEC9A4316FE45E07900197D8FBB52D3AF01A51C4F8BD08A1E21A662E3CFCF7792AD7680673817B70AC1888A08B49E8C5835357016D9BF56A0EBDE8B5DF214EC422809BC8D88177F273419116EF2EC7951453F129768DE9BC31D963515CC7481559E4C0E65C549169F2B94AE68DB944171189DD654DC6970F2F5843FB7C8E9D057E2B5716752F1F5686811AC075ED3D3CBD06B5D35AE33D01260D9E0560AF545D0C9D89A31D5EAF96D5422F6567FE8A90E23906B840545805644DFD656E526A686D3B978DD271578CA3DA0F7D23FC1252A702A5D597CAE9D4A5BBF6398A75AF72582C7538A7937FB71A2610DCBC39625B77103FA3B7D0A55177FD98C39CD4A27
22
23 # Extracts the PEM key from a config file, leaving the file unchanged.
24 # usage: extract_pem_key_from_config path_to_file
25 extract_pem_key_from_config() {
26   sed -n '/-----BEGIN /,/-----END /p' "$1"
27 }
28
29 # Removes the PEM key from a config file.
30 # usage: rm_pem_key_from_config path_to_file
31 rm_pem_key_from_config() {
32   sed_cmd '/-----BEGIN /,/-----END /d' "$1"
33 }
34
35 reinit_configs() {
36   if [ -d "$foo_dir" ]; then
37     chmod -f 755 "$foo_dir"
38     rm -rf "$foo_dir"
39   fi
40
41   tinc foo <<EOF
42 init foo
43 set DeviceType dummy
44 EOF
45 }
46
47 fsck_test() {
48   echo >&2 "[STEP] $*"
49   reinit_configs
50 }
51
52 run_access_checks() {
53   ! is_root && ! is_windows
54 }
55
56 test_private_keys() {
57   keyfile=$1
58
59   fsck_test "Must fail on broken $keyfile"
60   printf '' >"$foo_dir/$keyfile"
61   if with_legacy; then
62     expect_msg 'no private key is known' tinc foo fsck
63   else
64     must_fail_with_msg 'no Ed25519 private key found' tinc foo fsck
65   fi
66
67   if run_access_checks; then
68     fsck_test "Must fail on inaccessible $keyfile"
69     chmod 000 "$foo_dir/$keyfile"
70     if with_legacy; then
71       expect_msg 'error reading' tinc foo fsck
72     else
73       must_fail_with_msg 'error reading' tinc foo fsck
74     fi
75   fi
76
77   if ! is_windows; then
78     fsck_test "Must warn about unsafe permissions on $keyfile"
79     chmod 666 "$foo_dir/$keyfile"
80     expect_msg 'unsafe file permissions' tinc foo fsck
81   fi
82
83   if with_legacy; then
84     fsck_test "Must pass on missing $keyfile when the other key is present"
85     rm -f "$foo_dir/$keyfile"
86     tinc foo fsck
87   fi
88 }
89
90 test_private_key_var() {
91   var=$1
92   keyfile=$2
93
94   fsck_test "Must find private key at $var"
95   mv "$foo_dir/$keyfile" "$foo_dir/renamed_private_key"
96   echo "$var = $(normalize_path "$foo_dir/renamed_private_key")" >>"$foo_conf"
97   fail_on_msg 'key was found but no private key' tinc foo fsck
98 }
99
100 test_ec_public_key_file_var() {
101   conf=$1
102   fsck_test "EC public key in Ed25519PublicKeyFile in $conf must work"
103   cat >"$foo_dir/ec_pubkey" <<EOF
104 -----BEGIN ED25519 PUBLIC KEY-----
105 $(awk '/^Ed25519PublicKey/ { printf $NF }' "$foo_host")
106 -----END ED25519 PUBLIC KEY-----
107 EOF
108   sed_cmd '/Ed25519PublicKey/d' "$foo_host"
109   echo "Ed25519PublicKeyFile = $(normalize_path "$foo_dir/ec_pubkey")" >>"$foo_dir/$conf"
110   fail_on_msg 'no (usable) public Ed25519' tinc foo fsck
111 }
112
113 test_rsa_public_key_file_var() {
114   conf=$1
115   fsck_test "RSA public key in PublicKeyFile in $conf must work"
116   extract_pem_key_from_config "$foo_host" >"$foo_dir/rsa_pubkey"
117   rm_pem_key_from_config "$foo_host"
118   echo "PublicKeyFile = $(normalize_path "$foo_dir/rsa_pubkey")" >>"$foo_dir/$conf"
119   fail_on_msg 'error reading RSA public key' tinc foo fsck
120 }
121
122 fsck_test 'Newly created configuration should pass'
123 tinc foo fsck
124
125 fsck_test 'Must fail on missing tinc.conf'
126 rm -f "$foo_conf"
127 must_fail_with_msg 'no tinc configuration found' tinc foo fsck
128
129 if run_access_checks; then
130   fsck_test 'Must fail on inaccessible tinc.conf'
131   chmod 000 "$foo_dir"
132   must_fail_with_msg 'not running tinc as root' tinc foo fsck
133 fi
134
135 if ! is_windows; then
136   fsck_test 'Non-executable tinc-up MUST be fixed by tinc --force'
137   chmod a-x "$foo_tinc_up"
138   expect_msg 'cannot read and execute' tinc foo --force fsck
139   test -x "$foo_tinc_up"
140
141   fsck_test 'Non-executable tinc-up MUST NOT be fixed by tinc without --force'
142   chmod a-x "$foo_tinc_up"
143   expect_msg 'cannot read and execute' tinc foo fsck
144   must_fail test -x "$foo_tinc_up"
145 fi
146
147 fsck_test 'Unknown -up script warning'
148 touch "$foo_dir/fake-up"
149 expect_msg 'unknown script' tinc foo fsck
150
151 fsck_test 'Unknown -down script warning'
152 touch "$foo_dir/fake-down"
153 expect_msg 'unknown script' tinc foo fsck
154
155 if ! is_windows; then
156   fsck_test 'Non-executable foo-up MUST be fixed by tinc --force'
157   touch "$foo_host_up"
158   chmod a-x "$foo_host_up"
159   expect_msg 'cannot read and execute' tinc foo --force fsck
160   test -x "$foo_tinc_up"
161
162   fsck_test 'Non-executable bar-up MUST NOT be fixed by tinc'
163   touch "$foo_dir/hosts/bar-up"
164   chmod a-x "$foo_dir/hosts/bar-up"
165   expect_msg 'cannot read and execute' tinc foo fsck
166   must_fail test -x "$foo_dir/bar-up"
167 fi
168
169 if run_access_checks; then
170   fsck_test 'Inaccessible hosts/foo must fail'
171   chmod 000 "$foo_host"
172   must_fail_with_msg 'cannot open config file' tinc foo fsck
173 fi
174
175 fsck_test 'Must fail when all private keys are missing'
176 rm -f "$foo_ec_priv" "$foo_rsa_priv"
177 if with_legacy; then
178   must_fail_with_msg 'neither RSA or Ed25519 private key' tinc foo fsck
179 else
180   must_fail_with_msg 'no Ed25519 private key' tinc foo fsck
181 fi
182
183 if with_legacy; then
184   test_private_keys rsa_key.priv
185
186   if ! is_windows; then
187     fsck_test 'Must warn about unsafe permissions on tinc.conf with PrivateKey'
188     rm -f "$foo_rsa_priv"
189     echo "PrivateKey = $rsa_d" >>"$foo_conf"
190     echo "PublicKey = $rsa_n" >>"$foo_host"
191     chmod 666 "$foo_conf"
192     expect_msg 'unsafe file permissions' tinc foo fsck
193   fi
194
195   fsck_test 'Must warn about missing RSA private key if public key is present'
196   rm -f "$foo_rsa_priv"
197   expect_msg 'public RSA key was found but no private key' tinc foo fsck
198
199   fsck_test 'Must warn about missing RSA public key'
200   rm_pem_key_from_config "$foo_host"
201   expect_msg 'no (usable) public RSA' tinc foo fsck
202   must_fail grep -q 'BEGIN RSA PUBLIC KEY' "$foo_host"
203
204   fsck_test 'Must fix missing RSA public key on --force'
205   rm_pem_key_from_config "$foo_host"
206   expect_msg 'wrote RSA public key' tinc foo --force fsck
207   grep -q 'BEGIN RSA PUBLIC KEY' "$foo_host"
208
209   test_private_key_var PrivateKeyFile rsa_key.priv
210
211   test_rsa_public_key_file_var tinc.conf
212   test_rsa_public_key_file_var hosts/foo
213
214   fsck_test 'RSA PublicKey + PrivateKey must work'
215   rm -f "$foo_rsa_priv"
216   rm_pem_key_from_config "$foo_host"
217   echo "PrivateKey = $rsa_d" >>"$foo_conf"
218   echo "PublicKey = $rsa_n" >>"$foo_host"
219   fail_on_msg 'no (usable) public RSA' tinc foo fsck
220
221   fsck_test 'RSA PrivateKey without PublicKey must warn'
222   rm -f "$foo_rsa_priv"
223   rm_pem_key_from_config "$foo_host"
224   echo "PrivateKey = $rsa_d" >>"$foo_conf"
225   expect_msg 'PrivateKey used but no PublicKey found' tinc foo fsck
226
227   fsck_test 'Must warn about missing EC private key if public key is present'
228   rm -f "$foo_ec_priv"
229   expect_msg 'public Ed25519 key was found but no private key' tinc foo fsck
230
231   fsck_test 'Must fix broken RSA public key with --force'
232   sed_cmd 2d "$foo_host"
233   expect_msg 'old key(s) found and disabled' tinc foo --force fsck
234   tinc foo fsck
235
236   fsck_test 'Must fix missing RSA public key with --force'
237   rm_pem_key_from_config "$foo_host"
238   expect_msg 'no (usable) public RSA key found' tinc foo --force fsck
239   tinc foo fsck
240 fi
241
242 fsck_test 'Must fix broken Ed25519 public key with --force'
243 sed_cmd 's/Ed25519PublicKey.*/Ed25519PublicKey = foobar/' "$foo_host"
244 expect_msg 'no (usable) public Ed25519 key' tinc foo --force fsck
245 tinc foo fsck
246
247 fsck_test 'Must fix missing Ed25519 public key with --force'
248 sed_cmd '/Ed25519PublicKey/d' "$foo_host"
249 expect_msg 'no (usable) public Ed25519 key' tinc foo --force fsck
250 tinc foo fsck
251
252 test_private_keys ed25519_key.priv
253 test_private_key_var Ed25519PrivateKeyFile ed25519_key.priv
254
255 test_ec_public_key_file_var tinc.conf
256 test_ec_public_key_file_var hosts/foo
257
258 fsck_test 'Must warn about missing EC public key and NOT fix without --force'
259 sed_cmd '/Ed25519PublicKey/d' "$foo_host"
260 expect_msg 'no (usable) public Ed25519' tinc foo fsck
261 must_fail grep -q 'ED25519 PUBLIC KEY' "$foo_host"
262
263 fsck_test 'Must fix missing EC public key on --force'
264 sed_cmd '/Ed25519PublicKey/d' "$foo_host"
265 expect_msg 'wrote Ed25519 public key' tinc foo --force fsck
266 grep -q 'ED25519 PUBLIC KEY' "$foo_host"
267
268 fsck_test 'Must warn about obsolete variables'
269 echo 'GraphDumpFile = /dev/null' >>"$foo_host"
270 expect_msg 'obsolete variable GraphDumpFile' tinc foo fsck
271
272 fsck_test 'Must warn about missing values'
273 echo 'Weight = ' >>"$foo_host"
274 must_fail_with_msg 'no value for variable `Weight' tinc foo fsck
275
276 fsck_test 'Must warn about duplicate variables'
277 echo 'Weight = 0' >>"$foo_host"
278 echo 'Weight = 1' >>"$foo_host"
279 expect_msg 'multiple instances of variable Weight' tinc foo fsck
280
281 fsck_test 'Must warn about server variables in host config'
282 echo 'Interface = fake0' >>"$foo_host"
283 expect_msg 'server variable Interface found' tinc foo fsck
284
285 fsck_test 'Must warn about host variables in server config'
286 echo 'Port = 1337' >>"$foo_conf"
287 expect_msg 'host variable Port found' tinc foo fsck
288
289 fsck_test 'Must warn about missing Name'
290 sed_cmd '/^Name =/d' "$foo_conf"
291 must_fail_with_msg 'without a valid Name' tinc foo fsck