Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kdc/policy.c
34878 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kdc/policy.c - Policy decision routines for KDC */
3
/*
4
* Copyright (C) 2017 by Red Hat, Inc.
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
#include "k5-int.h"
34
#include "kdc_util.h"
35
#include "extern.h"
36
#include "policy.h"
37
#include "adm_proto.h"
38
#include <krb5/kdcpolicy_plugin.h>
39
#include <syslog.h>
40
41
typedef struct kdcpolicy_handle_st {
42
struct krb5_kdcpolicy_vtable_st vt;
43
krb5_kdcpolicy_moddata moddata;
44
} *kdcpolicy_handle;
45
46
static kdcpolicy_handle *handles;
47
48
static void
49
free_indicators(char **ais)
50
{
51
size_t i;
52
53
if (ais == NULL)
54
return;
55
for (i = 0; ais[i] != NULL; i++)
56
free(ais[i]);
57
free(ais);
58
}
59
60
/* Convert inds to a null-terminated list of C strings. */
61
static krb5_error_code
62
authind_strings(krb5_data *const *inds, char ***strs_out)
63
{
64
krb5_error_code ret;
65
char **list = NULL;
66
size_t i, count;
67
68
*strs_out = NULL;
69
70
for (count = 0; inds != NULL && inds[count] != NULL; count++);
71
list = k5calloc(count + 1, sizeof(*list), &ret);
72
if (list == NULL)
73
goto error;
74
75
for (i = 0; i < count; i++) {
76
list[i] = k5memdup0(inds[i]->data, inds[i]->length, &ret);
77
if (list[i] == NULL)
78
goto error;
79
}
80
81
*strs_out = list;
82
return 0;
83
84
error:
85
free_indicators(list);
86
return ret;
87
}
88
89
/* Constrain times->endtime to life and times->renew_till to rlife, relative to
90
* now. */
91
static void
92
update_ticket_times(krb5_ticket_times *times, krb5_timestamp now,
93
krb5_deltat life, krb5_deltat rlife)
94
{
95
if (life)
96
times->endtime = ts_min(ts_incr(now, life), times->endtime);
97
if (rlife)
98
times->renew_till = ts_min(ts_incr(now, rlife), times->renew_till);
99
}
100
101
/* Check an AS request against kdcpolicy modules, updating times with any
102
* module endtime constraints. Set an appropriate status string on error. */
103
krb5_error_code
104
check_kdcpolicy_as(krb5_context context, const krb5_kdc_req *request,
105
const krb5_db_entry *client, const krb5_db_entry *server,
106
krb5_data *const *auth_indicators, krb5_timestamp kdc_time,
107
krb5_ticket_times *times, const char **status)
108
{
109
krb5_deltat life = 0, rlife = 0;
110
krb5_error_code ret;
111
kdcpolicy_handle *hp, h;
112
char **ais = NULL;
113
114
*status = NULL;
115
116
ret = authind_strings(auth_indicators, &ais);
117
if (ret)
118
goto done;
119
120
for (hp = handles; *hp != NULL; hp++) {
121
h = *hp;
122
if (h->vt.check_as == NULL)
123
continue;
124
125
ret = h->vt.check_as(context, h->moddata, request, client, server,
126
(const char **)ais, status, &life, &rlife);
127
if (ret)
128
goto done;
129
130
update_ticket_times(times, kdc_time, life, rlife);
131
}
132
133
done:
134
free_indicators(ais);
135
return ret;
136
}
137
138
/*
139
* Check the TGS request against the local TGS policy. Accepts an
140
* authentication indicator for the module policy decisions. Returns 0 and a
141
* NULL status string on success.
142
*/
143
krb5_error_code
144
check_kdcpolicy_tgs(krb5_context context, const krb5_kdc_req *request,
145
const krb5_db_entry *server, const krb5_ticket *ticket,
146
krb5_data *const *auth_indicators, krb5_timestamp kdc_time,
147
krb5_ticket_times *times, const char **status)
148
{
149
krb5_deltat life = 0, rlife = 0;
150
krb5_error_code ret;
151
kdcpolicy_handle *hp, h;
152
char **ais = NULL;
153
154
*status = NULL;
155
156
ret = authind_strings(auth_indicators, &ais);
157
if (ret)
158
goto done;
159
160
for (hp = handles; *hp != NULL; hp++) {
161
h = *hp;
162
if (h->vt.check_tgs == NULL)
163
continue;
164
165
ret = h->vt.check_tgs(context, h->moddata, request, server, ticket,
166
(const char **)ais, status, &life, &rlife);
167
if (ret)
168
goto done;
169
170
update_ticket_times(times, kdc_time, life, rlife);
171
}
172
173
done:
174
free_indicators(ais);
175
return ret;
176
}
177
178
void
179
unload_kdcpolicy_plugins(krb5_context context)
180
{
181
kdcpolicy_handle *hp, h;
182
183
for (hp = handles; hp != NULL && *hp != NULL; hp++) {
184
h = *hp;
185
if (h->vt.fini != NULL)
186
h->vt.fini(context, h->moddata);
187
free(h);
188
}
189
free(handles);
190
handles = NULL;
191
}
192
193
krb5_error_code
194
load_kdcpolicy_plugins(krb5_context context)
195
{
196
krb5_error_code ret;
197
krb5_plugin_initvt_fn *modules = NULL, *mod;
198
kdcpolicy_handle h;
199
size_t count;
200
201
ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPOLICY, &modules);
202
if (ret)
203
goto cleanup;
204
205
for (count = 0; modules[count] != NULL; count++);
206
handles = k5calloc(count + 1, sizeof(*handles), &ret);
207
if (handles == NULL)
208
goto cleanup;
209
210
count = 0;
211
for (mod = modules; *mod != NULL; mod++) {
212
h = k5calloc(1, sizeof(*h), &ret);
213
if (h == NULL)
214
goto cleanup;
215
216
ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt);
217
if (ret) { /* Version mismatch. */
218
TRACE_KDCPOLICY_VTINIT_FAIL(context, ret);
219
free(h);
220
continue;
221
}
222
if (h->vt.init != NULL) {
223
ret = h->vt.init(context, &h->moddata);
224
if (ret == KRB5_PLUGIN_NO_HANDLE) {
225
TRACE_KDCPOLICY_INIT_SKIP(context, h->vt.name);
226
free(h);
227
continue;
228
}
229
if (ret) {
230
kdc_err(context, ret, _("while loading policy module %s"),
231
h->vt.name);
232
free(h);
233
goto cleanup;
234
}
235
}
236
handles[count++] = h;
237
}
238
239
ret = 0;
240
241
cleanup:
242
if (ret)
243
unload_kdcpolicy_plugins(context);
244
k5_plugin_free_modules(context, modules);
245
return ret;
246
}
247
248