File: daemon-t

package info (click to toggle)
kstart 4.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 1,884 kB
  • sloc: ansic: 5,937; sh: 4,785; perl: 2,130; makefile: 142
file content (363 lines) | stat: -rwxr-xr-x 13,880 bytes parent folder | download
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#!/usr/bin/perl -w
#
# Tests for k5start daemon functionality.
#
# Written by Russ Allbery <eagle@eyrie.org>
# Copyright 2015, 2021 Russ Allbery <eagle@eyrie.org>
# Copyright 2008-2009, 2011-2012, 2014
#     The Board of Trustees of the Leland Stanford Junior University
#
# SPDX-License-Identifier: MIT

use Cwd;
use File::Copy qw(copy);

use Test::More;

# The full path to the newly-built k5start client.
our $K5START = "$ENV{C_TAP_BUILD}/../commands/k5start";

# The path to our data directory, which contains the keytab to use to test.
our $DATA = "$ENV{C_TAP_BUILD}/data";

# The path to our temporary directory used for test ticket caches and the
# like.
our $TMP = "$ENV{C_TAP_BUILD}/tmp";
unless (-d $TMP) {
    mkdir $TMP or BAIL_OUT ("cannot create $TMP: $!");
}

# Load our test utility programs.
require "$ENV{C_TAP_SOURCE}/libtest.pl";

# Decide whether we have the configuration to run the tests.
if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") {
    plan tests => 86;
} else {
    plan skip_all => "no keytab configuration";
    exit 0;
}

# Get the test principal.
my $principal = contents ("$DATA/test.principal");

# Don't overwrite the user's ticket cache.
$ENV{KRB5CCNAME} = "$TMP/krb5cc_test";

# Start a k5start daemon and be sure it gets tickets and stays running.
unlink "$TMP/krb5cc_test";
my $pid = fork;
if (!defined $pid) {
    BAIL_OUT ("can't fork: $!");
} elsif ($pid == 0) {
    exec ($K5START, '-K', 1, '-f', "$DATA/test.keytab", '-p', "$TMP/pid",
          $principal) or BAIL_OUT ("can't run $K5START: $!");
}
my $tries = 0;
while (not -s "$TMP/pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
my ($default, $service) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/,
      'Authentication succeeded for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
if (-f "$TMP/pid") {
    my $daemon = contents ("$TMP/pid");
    is ($pid, $daemon, ' and the right PID is written');
    $pid = $daemon if $daemon;
} else {
    ok (0, ' and the right PID is written');
}
ok (kill (0, $pid), ' and k5start is still running');
unlink "$TMP/krb5cc_test";
ok (! -f "$TMP/krb5cc_test", 'Ticket cache was deleted');
kill (14, $pid) or warn "Can't kill $pid: $!\n";
$tries = 0;
while (not -f "$TMP/krb5cc_test" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
ok (kill (0, $pid), ' and k5start is still running after ALRM');
($default, $service) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/,
      ' and recreates cache with the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
kill (15, $pid) or warn "Can't kill $pid: $!\n";
is (waitpid ($pid, 0), $pid, ' and k5start dies after SIGTERM');
ok (!-f "$TMP/pid", ' and the PID file was removed');
unlink "$TMP/pid";

# Try again with the -b flag.
unlink "$TMP/krb5cc_test";
my ($out, $err, $status)
    = command ($K5START, '-bK', 1, '-f', "$DATA/test.keytab", '-p',
               "$TMP/pid", $principal);
is ($status, 0, 'Backgrounding k5start works');
is ($err, '', ' with no error output');
is ($out, '', ' and -q was added implicitly');
$tries = 0;
while (not -s "$TMP/pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
($default, $service) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/,
      'Authentication succeeded for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), ' and the PID file is correct');
kill (15, $pid) or warn "Can't kill $pid: $!\n";
select (undef, undef, undef, 0.2);
ok (!-f "$TMP/pid", ' and the PID file was removed');
unlink "$TMP/pid";

# Try again with an initial authentication failure and ensure that k5start
# keeps running anyway.
unlink "$TMP/krb5cc_test";
($out, $err, $status)
    = command ($K5START, '-bK', 1, '-f', "$DATA/test.keytab-BAD", '-p',
               "$TMP/pid", $principal);
is ($status, 0, 'Backgrounding k5start with bad keytab works');
like ($err, qr/^k5start: error getting credentials: /, ' with error output');
is ($out, '', ' and -q was added implicitly');
while (not -s "$TMP/pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), ' and the PID file is correct');
kill (15, $pid) or warn "Can't kill $pid: $!\n";
select (undef, undef, undef, 2.0);
ok (!-f "$TMP/pid", ' and the PID file was removed');
unlink "$TMP/pid";

# Providing -x should override that behavior and cause the daemon to refuse
# to start.
unlink "$TMP/krb5cc_test";
($out, $err, $status)
    = command ($K5START, '-bxK', 1, '-f', "$DATA/test.keytab-BAD", '-p',
               "$TMP/pid", $principal);
is ($status, 1, 'Backgrounding k5start -x with bad keytab fails');
like ($err, qr/^k5start: error getting credentials: /, ' with error output');
is ($out, '', ' and -q was added implicitly');
if ($status == 0) {
    while (not -s "$TMP/pid" and $tries < 100) {
        select (undef, undef, undef, 0.1);
        $tries++;
    }
    $pid = contents ("$TMP/pid");
    kill (15, $pid) or warn "Can't kill $pid: $!\n";
}

# Check that k5start keeps running if the ticket cache directory is not
# writeable.
$pid = fork;
if (!defined $pid) {
    BAIL_OUT ("can't fork: $!");
} elsif ($pid == 0) {
    open (STDERR, '>', "$TMP/k5start-errors")
        or BAIL_OUT ("can't create $TMP/k5start-errors: $!");
    exec ($K5START, '-K', 1, '-Uf', "$DATA/test.keytab", '-p', "$TMP/pid")
        or BAIL_OUT ("can't run $K5START: $!");
}
$tries = 0;
while (not -s "$TMP/pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), 'k5start -K 1 started');
chmod 0555, $TMP or BAIL_OUT ("cannot chmod $TMP: $!");
kill (14, $pid) or warn "Can't kill $pid: $!\n";
$tries = 0;
while (not -s "$TMP/k5start-errors" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
ok (kill (0, $pid), ' and it keeps running on a non-writeable cache');
chmod 0755, $TMP or BAIL_OUT ("cannot chmod $TMP: $!");
if (open (ERRORS, '<', "$TMP/k5start-errors")) {
    like (scalar (<ERRORS>), qr/^k5start: error initializing ticket cache: /,
          ' and the correct error message');
} else {
    ok (0, ' and the correct error message');
}
unlink "$TMP/k5start-errors";
kill (15, $pid) or warn "Can't kill $pid: $!\n";
is (waitpid ($pid, 0), $pid, ' and k5start dies after SIGTERM');
ok (!-f "$TMP/pid", ' and the PID file was removed');

# If we do that again with -x, k5start should exit.
($out, $err, $status)
    = command ($K5START, '-xbK', 1, '-f', "$DATA/test.keytab", '-p',
               "$TMP/pid", $principal);
is ($status, 0, 'k5start -xb works');
is ($err, '', ' with no error output');
is ($out, '', ' and -q was added implicitly');
$tries = 0;
while (not -s "$TMP/pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), 'k5start -xb started');
chmod 0555, $TMP or BAIL_OUT ("cannot chmod $TMP: $!");
kill (14, $pid) or warn "Can't kill $pid: $!\n";
$tries = 0;
while (kill (0, $pid) and $tries < 100) {
    select (undef, undef, undef, 0.5);
    $tries++;
}
ok (!kill (0, $pid), ' and it exits on a non-writeable cache');
chmod 0755, $TMP or BAIL_OUT ("cannot chmod $TMP: $!");
unlink "$TMP/pid";

# Now, run a command in the background.
unlink "$TMP/krb5cc_test", "$TMP/krb5cc_child", "$TMP/child-out";
($out, $err, $status)
    = command ($K5START, '-bK', 1, '-k', "$TMP/krb5cc_child", '-f',
               "$DATA/test.keytab", '-p', "$TMP/pid", '-c', "$TMP/child-pid",
               $principal, '--', "$ENV{C_TAP_SOURCE}/data/command",
               "$TMP/child-out");
is ($status, 0, 'Backgrounding k5start works');
is ($err, '', ' with no error output');
is ($out, '', ' and output was redirected properly');
$tries = 0;
while (not -s "$TMP/child-pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
($default, $service) = klist ();
is ($default, undef, 'The normal ticket cache is untouched');
$ENV{KRB5CCNAME} = "$TMP/krb5cc_child";
($default, $service) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/,
      ' but the other cache has the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), 'k5start is running');
$child = contents ("$TMP/child-pid");
ok (kill (0, $child), 'The child process is running');
$tries = 0;
while (not -s "$TMP/child-out" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
kill (1, $child) or warn "Cannot send HUP to child $child: $!\n";
select (undef, undef, undef, 0.1);
kill (2, $child) or warn "Cannot send INT to child $child: $!\n";
select (undef, undef, undef, 0.1);
kill (15, $child) or warn "Cannot send TERM to child $child: $!\n";
select (undef, undef, undef, 0.2);
ok (!kill (0, $pid), 'k5start is no longer running');
ok (!kill (0, $child), 'The child process is no longer running');
open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open child-out: $!");
is (scalar (<OUT>), "$child\n", 'Child PID is correct');
is (scalar (<OUT>), "/\n", 'Child working directory is /');
is (scalar (<OUT>), "FILE:$TMP/krb5cc_child\n", 'Child cache is correct');
is (scalar (<OUT>), "got SIGHUP\n", 'SIGHUP was recorded');
is (scalar (<OUT>), "got SIGINT\n", 'SIGINT was recorded');
is (scalar (<OUT>), "got SIGTERM\n", 'SIGTERM was recorded');
ok (eof OUT, 'No more child output written');
close OUT;
ok (!-f "$TMP/pid", 'PID file cleaned up');
ok (!-f "$TMP/child-pid", 'Child PID file cleaned up');

# Now, do that again, but test signal propagation from the parent to the
# child.
unlink "$TMP/krb5cc_child", "$TMP/child-out";
($out, $err, $status)
    = command ($K5START, '-bK', 1, '-k', "$TMP/krb5cc_child", '-f',
               "$DATA/test.keytab", '-p', "$TMP/pid", '-c', "$TMP/child-pid",
               $principal, '--', "$ENV{C_TAP_SOURCE}/data/command",
               "$TMP/child-out");
is ($status, 0, 'Backgrounding k5start works');
is ($err, '', ' with no error output');
is ($out, '', ' and output was redirected properly');
$tries = 0;
while (not -s "$TMP/child-pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), 'k5start is running');
$child = contents ("$TMP/child-pid");
ok (kill (0, $child), 'The child process is running');
$tries = 0;
while (not -s "$TMP/child-out" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
kill (1, $pid) or warn "Cannot send HUP to parent $pid: $!\n";
select (undef, undef, undef, 0.1);
kill (2, $pid) or warn "Cannot send INT to parent $pid: $!\n";
select (undef, undef, undef, 0.1);
kill (15, $pid) or warn "Cannot send TERM to parent $pid: $!\n";
select (undef, undef, undef, 0.2);
ok (!kill (0, $pid), 'k5start is no longer running');
ok (!kill (0, $child), 'The child process is no longer running');
open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open child-out: $!");
is (scalar (<OUT>), "$child\n", 'Child PID is correct');
is (scalar (<OUT>), "/\n", 'Child working directory is /');
is (scalar (<OUT>), "FILE:$TMP/krb5cc_child\n", 'Child cache is correct');
is (scalar (<OUT>), "got SIGHUP\n", 'SIGHUP was propagated');
is (scalar (<OUT>), "got SIGINT\n", 'SIGINT was propagated');
is (scalar (<OUT>), "got SIGTERM\n", 'SIGTERM was propagated');
ok (eof OUT, 'No more child output written');
close OUT;
ok (!-f "$TMP/pid", 'PID file cleaned up');
ok (!-f "$TMP/child-pid", 'Child PID file cleaned up');

# Finally, start a child program with an invalid keytab path.  This should
# start and keep trying to authenticate but never start the actual child
# process until the ticket cache does exist.  We also test SIGQUIT handling.
unlink "$TMP/krb5cc_child", "$TMP/child-out";
($out, $err, $status)
    = command ($K5START, '-bK', 1, '-k', "$TMP/krb5cc_child", '-f',
               "$TMP/test.keytab", '-p', "$TMP/pid", '-c', "$TMP/child-pid",
               $principal, '--', "$ENV{C_TAP_SOURCE}/data/command",
               "$TMP/child-out");
is ($status, 0, 'Backgrounding k5start works');
like ($err, qr/^k5start: error getting credentials: /, ' with error output');
is ($out, '', ' and output was redirected properly');
while (not -s "$TMP/pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
$pid = contents ("$TMP/pid");
ok (kill (0, $pid), 'k5start is running');
select (undef, undef, undef, 1);
ok (!-f "$TMP/child-pid", ' child did not start');
ok (!-f "$TMP/child-out", ' and has no output');
copy ("$DATA/test.keytab", "$TMP/test.keytab");
$tries = 0;
while (not -s "$TMP/child-pid" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
$child = contents ("$TMP/child-pid");
ok (kill (0, $child), 'The child process is running');
$tries = 0;
while (not -s "$TMP/child-out" and $tries < 100) {
    select (undef, undef, undef, 0.1);
    $tries++;
}
kill (3, $pid) or warn "Cannot send QUIT to parent $pid: $!\n";
select (undef, undef, undef, 0.2);
ok (!kill (0, $pid), 'k5start is no longer running');
ok (!kill (0, $child), 'The child process is no longer running');
open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open child-out: $!");
is (scalar (<OUT>), "$child\n", 'Child PID is correct');
is (scalar (<OUT>), "/\n", 'Child working directory is /');
is (scalar (<OUT>), "FILE:$TMP/krb5cc_child\n", 'Child cache is correct');
is (scalar (<OUT>), "got SIGQUIT\n", 'SIGQUIT was propagated');
ok (eof OUT, 'No more child output written');
close OUT;
ok (!-f "$TMP/pid", 'PID file cleaned up');
ok (!-f "$TMP/child-pid", 'Child PID file cleaned up');

# Clean up.
unlink "$TMP/krb5cc_child", "$TMP/child-out", "$TMP/test.keytab";
unlink "$TMP/pid", "$TMP/child-pid";
rmdir $TMP;