Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/tests/conccache.c
34878 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* tests/conccache.c - ccache concurrent get_creds/refresh test program */
3
/*
4
* Copyright (C) 2021 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
17
* distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
* OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
/*
34
* Usage: conccache ccname clientprinc serverprinc
35
*
36
* This program spawns two subprocesses. One repeatedly runs
37
* krb5_get_credentials() on ccname, and the other repeatedly refreshes ccname
38
* from the default keytab. If either subprocess fails, the program exits with
39
* status 1. The goal is to expose time windows where cache refreshes cause
40
* get_cred operations to fail.
41
*/
42
43
#include "k5-platform.h"
44
#include <sys/types.h>
45
#include <sys/wait.h>
46
#include <pthread.h>
47
#include <krb5.h>
48
49
/* Run this many iterations of each operation. */
50
static const int iterations = 200;
51
52
/* Saved command-line arguments. */
53
static const char *ccname, *server_name, *client_name;
54
55
static void
56
check(krb5_error_code code)
57
{
58
if (code)
59
abort();
60
}
61
62
static krb5_boolean
63
get_cred(krb5_context context)
64
{
65
krb5_error_code ret;
66
krb5_ccache cc;
67
krb5_principal client, server;
68
krb5_creds mcred, *cred;
69
70
check(krb5_cc_resolve(context, ccname, &cc));
71
check(krb5_parse_name(context, client_name, &client));
72
check(krb5_parse_name(context, server_name, &server));
73
74
memset(&mcred, 0, sizeof(mcred));
75
mcred.client = client;
76
mcred.server = server;
77
ret = krb5_get_credentials(context, 0, cc, &mcred, &cred);
78
79
krb5_free_creds(context, cred);
80
krb5_free_principal(context, client);
81
krb5_free_principal(context, server);
82
krb5_cc_close(context, cc);
83
84
return ret == 0;
85
}
86
87
static krb5_boolean
88
refresh_cache(krb5_context context)
89
{
90
krb5_error_code ret;
91
krb5_ccache cc;
92
krb5_principal client;
93
krb5_get_init_creds_opt *opt;
94
krb5_creds cred;
95
96
check(krb5_cc_resolve(context, ccname, &cc));
97
check(krb5_parse_name(context, client_name, &client));
98
99
check(krb5_get_init_creds_opt_alloc(context, &opt));
100
check(krb5_get_init_creds_opt_set_out_ccache(context, opt, cc));
101
ret = krb5_get_init_creds_keytab(context, &cred, client, NULL, 0, NULL,
102
opt);
103
104
krb5_get_init_creds_opt_free(context, opt);
105
krb5_free_cred_contents(context, &cred);
106
krb5_free_principal(context, client);
107
krb5_cc_close(context, cc);
108
109
return ret == 0;
110
}
111
112
static pid_t
113
spawn_cred_subprocess(void)
114
{
115
krb5_context context;
116
pid_t pid;
117
int i;
118
119
pid = fork();
120
assert(pid >= 0);
121
if (pid > 0)
122
return pid;
123
124
check(krb5_init_context(&context));
125
for (i = 0; i < iterations; i++) {
126
if (!get_cred(context)) {
127
fprintf(stderr, "cred worker failed after %d successes\n", i);
128
exit(1);
129
}
130
}
131
krb5_free_context(context);
132
exit(0);
133
}
134
135
static pid_t
136
spawn_refresh_subprocess(void)
137
{
138
krb5_context context;
139
pid_t pid;
140
int i;
141
142
pid = fork();
143
assert(pid >= 0);
144
if (pid > 0)
145
return pid;
146
147
check(krb5_init_context(&context));
148
for (i = 0; i < iterations; i++) {
149
if (!refresh_cache(context)) {
150
fprintf(stderr, "refresh worker failed after %d successes\n", i);
151
exit(1);
152
}
153
}
154
krb5_free_context(context);
155
exit(0);
156
}
157
158
int
159
main(int argc, char *argv[])
160
{
161
krb5_context context;
162
pid_t cred_pid, refresh_pid, pid;
163
int cstatus, rstatus;
164
165
assert(argc == 4);
166
ccname = argv[1];
167
client_name = argv[2];
168
server_name = argv[3];
169
170
/* Begin with an initialized cache. */
171
check(krb5_init_context(&context));
172
refresh_cache(context);
173
krb5_free_context(context);
174
175
cred_pid = spawn_cred_subprocess();
176
refresh_pid = spawn_refresh_subprocess();
177
178
pid = waitpid(cred_pid, &cstatus, 0);
179
if (pid == -1)
180
abort();
181
pid = waitpid(refresh_pid, &rstatus, 0);
182
if (pid == -1)
183
abort();
184
185
if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus) != 0)
186
return 1;
187
if (!WIFEXITED(rstatus) || WEXITSTATUS(rstatus) != 0)
188
return 1;
189
return 0;
190
}
191
192