Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/kgssapi/gss_impl.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5
* Authors: Doug Rabson <[email protected]>
6
* Developed with Red Inc: Alfred Perlstein <[email protected]>
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/param.h>
31
#include <sys/jail.h>
32
#include <sys/kernel.h>
33
#include <sys/kobj.h>
34
#include <sys/lock.h>
35
#include <sys/malloc.h>
36
#include <sys/module.h>
37
#include <sys/mutex.h>
38
#include <sys/priv.h>
39
#include <sys/proc.h>
40
41
#include <kgssapi/gssapi.h>
42
#include <kgssapi/gssapi_impl.h>
43
#include <rpc/rpc.h>
44
#include <rpc/rpc_com.h>
45
#include <rpc/rpcsec_gss.h>
46
47
#include "gssd.h"
48
#include "kgss_if.h"
49
50
MALLOC_DEFINE(M_GSSAPI, "GSS-API", "GSS-API");
51
52
struct kgss_mech_list kgss_mechs;
53
struct mtx kgss_gssd_lock;
54
55
KGSS_VNET_DEFINE(CLIENT *, kgss_gssd_handle) = NULL;
56
57
static int
58
kgss_load(void)
59
{
60
CLIENT *cl;
61
62
LIST_INIT(&kgss_mechs);
63
64
cl = client_nl_create("kgss", GSSD, GSSDVERS);
65
KASSERT(cl, ("%s: netlink client already exist", __func__));
66
67
/*
68
* The transport default is no retries at all, since there could
69
* be no userland listener to our messages. We will retry for 5
70
* minutes with 10 second interval. This will potentially cure hosts
71
* with misconfigured startup, where kernel starts sending GSS queries
72
* before userland had started up the gssd(8) daemon.
73
*/
74
clnt_control(cl, CLSET_RETRIES, &(int){30});
75
clnt_control(cl, CLSET_TIMEOUT, &(struct timeval){.tv_sec = 300});
76
77
/*
78
* We literally wait on gssd(8), let's see that in top(1).
79
*/
80
clnt_control(cl, CLSET_WAITCHAN, "gssd");
81
82
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
83
mtx_lock(&kgss_gssd_lock);
84
KGSS_VNET(kgss_gssd_handle) = cl;
85
mtx_unlock(&kgss_gssd_lock);
86
KGSS_CURVNET_RESTORE();
87
88
return (0);
89
}
90
91
static void
92
kgss_unload(void)
93
{
94
95
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
96
clnt_destroy(KGSS_VNET(kgss_gssd_handle));
97
KGSS_CURVNET_RESTORE();
98
}
99
100
int
101
kgss_oid_equal(const gss_OID oid1, const gss_OID oid2)
102
{
103
104
if (oid1 == oid2)
105
return (1);
106
if (!oid1 || !oid2)
107
return (0);
108
if (oid1->length != oid2->length)
109
return (0);
110
if (memcmp(oid1->elements, oid2->elements, oid1->length))
111
return (0);
112
return (1);
113
}
114
115
void
116
kgss_install_mech(gss_OID mech_type, const char *name, struct kobj_class *cls)
117
{
118
struct kgss_mech *km;
119
120
km = malloc(sizeof(struct kgss_mech), M_GSSAPI, M_WAITOK);
121
km->km_mech_type = mech_type;
122
km->km_mech_name = name;
123
km->km_class = cls;
124
LIST_INSERT_HEAD(&kgss_mechs, km, km_link);
125
}
126
127
void
128
kgss_uninstall_mech(gss_OID mech_type)
129
{
130
struct kgss_mech *km;
131
132
LIST_FOREACH(km, &kgss_mechs, km_link) {
133
if (kgss_oid_equal(km->km_mech_type, mech_type)) {
134
LIST_REMOVE(km, km_link);
135
free(km, M_GSSAPI);
136
return;
137
}
138
}
139
}
140
141
gss_OID
142
kgss_find_mech_by_name(const char *name)
143
{
144
struct kgss_mech *km;
145
146
LIST_FOREACH(km, &kgss_mechs, km_link) {
147
if (!strcmp(km->km_mech_name, name)) {
148
return (km->km_mech_type);
149
}
150
}
151
return (GSS_C_NO_OID);
152
}
153
154
const char *
155
kgss_find_mech_by_oid(const gss_OID oid)
156
{
157
struct kgss_mech *km;
158
159
LIST_FOREACH(km, &kgss_mechs, km_link) {
160
if (kgss_oid_equal(km->km_mech_type, oid)) {
161
return (km->km_mech_name);
162
}
163
}
164
return (NULL);
165
}
166
167
gss_ctx_id_t
168
kgss_create_context(gss_OID mech_type)
169
{
170
struct kgss_mech *km;
171
gss_ctx_id_t ctx;
172
173
LIST_FOREACH(km, &kgss_mechs, km_link) {
174
if (kgss_oid_equal(km->km_mech_type, mech_type))
175
break;
176
}
177
if (!km)
178
return (NULL);
179
180
ctx = (gss_ctx_id_t) kobj_create(km->km_class, M_GSSAPI, M_WAITOK);
181
KGSS_INIT(ctx);
182
183
return (ctx);
184
}
185
186
void
187
kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
188
{
189
190
KGSS_DELETE(ctx, output_token);
191
kobj_delete((kobj_t) ctx, M_GSSAPI);
192
}
193
194
OM_uint32
195
kgss_transfer_context(gss_ctx_id_t ctx, void *lctx)
196
{
197
struct export_sec_context_res res;
198
struct export_sec_context_args args;
199
enum clnt_stat stat;
200
OM_uint32 maj_stat;
201
202
if (lctx != NULL) {
203
maj_stat = KGSS_IMPORT(ctx, MIT_V1, lctx);
204
ctx->handle = 0;
205
return (maj_stat);
206
}
207
208
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
209
if (!KGSS_VNET(kgss_gssd_handle)) {
210
KGSS_CURVNET_RESTORE();
211
return (GSS_S_FAILURE);
212
}
213
214
args.ctx = ctx->handle;
215
bzero(&res, sizeof(res));
216
stat = gssd_export_sec_context_1(&args, &res, KGSS_VNET(kgss_gssd_handle));
217
KGSS_CURVNET_RESTORE();
218
if (stat != RPC_SUCCESS) {
219
return (GSS_S_FAILURE);
220
}
221
222
maj_stat = KGSS_IMPORT(ctx, res.format, &res.interprocess_token);
223
ctx->handle = 0;
224
225
xdr_free((xdrproc_t) xdr_export_sec_context_res, &res);
226
227
return (maj_stat);
228
}
229
230
void
231
kgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to)
232
{
233
to->length = from->length;
234
if (from->length) {
235
to->value = malloc(from->length, M_GSSAPI, M_WAITOK);
236
bcopy(from->value, to->value, from->length);
237
} else {
238
to->value = NULL;
239
}
240
}
241
242
/*
243
* Acquire the kgss_gssd_handle and return it with a reference count,
244
* if it is available.
245
*/
246
CLIENT *
247
kgss_gssd_client(void)
248
{
249
CLIENT *cl;
250
251
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
252
mtx_lock(&kgss_gssd_lock);
253
cl = KGSS_VNET(kgss_gssd_handle);
254
if (cl != NULL)
255
CLNT_ACQUIRE(cl);
256
mtx_unlock(&kgss_gssd_lock);
257
KGSS_CURVNET_RESTORE();
258
return (cl);
259
}
260
261
/*
262
* Kernel module glue
263
*/
264
static int
265
kgssapi_modevent(module_t mod, int type, void *data)
266
{
267
int error = 0;
268
269
switch (type) {
270
case MOD_LOAD:
271
rpc_gss_entries.rpc_gss_refresh_auth = rpc_gss_refresh_auth;
272
rpc_gss_entries.rpc_gss_secfind = rpc_gss_secfind;
273
rpc_gss_entries.rpc_gss_secpurge = rpc_gss_secpurge;
274
rpc_gss_entries.rpc_gss_seccreate = rpc_gss_seccreate;
275
rpc_gss_entries.rpc_gss_set_defaults = rpc_gss_set_defaults;
276
rpc_gss_entries.rpc_gss_max_data_length =
277
rpc_gss_max_data_length;
278
rpc_gss_entries.rpc_gss_get_error = rpc_gss_get_error;
279
rpc_gss_entries.rpc_gss_mech_to_oid = rpc_gss_mech_to_oid;
280
rpc_gss_entries.rpc_gss_oid_to_mech = rpc_gss_oid_to_mech;
281
rpc_gss_entries.rpc_gss_qop_to_num = rpc_gss_qop_to_num;
282
rpc_gss_entries.rpc_gss_get_mechanisms = rpc_gss_get_mechanisms;
283
rpc_gss_entries.rpc_gss_get_versions = rpc_gss_get_versions;
284
rpc_gss_entries.rpc_gss_is_installed = rpc_gss_is_installed;
285
rpc_gss_entries.rpc_gss_set_svc_name = rpc_gss_set_svc_name;
286
rpc_gss_entries.rpc_gss_clear_svc_name = rpc_gss_clear_svc_name;
287
rpc_gss_entries.rpc_gss_getcred = rpc_gss_getcred;
288
rpc_gss_entries.rpc_gss_set_callback = rpc_gss_set_callback;
289
rpc_gss_entries.rpc_gss_clear_callback = rpc_gss_clear_callback;
290
rpc_gss_entries.rpc_gss_get_principal_name =
291
rpc_gss_get_principal_name;
292
rpc_gss_entries.rpc_gss_svc_max_data_length =
293
rpc_gss_svc_max_data_length;
294
rpc_gss_entries.rpc_gss_ip_to_srv_principal =
295
rpc_gss_ip_to_srv_principal;
296
mtx_init(&kgss_gssd_lock, "kgss_gssd_lock", NULL, MTX_DEF);
297
error = kgss_load();
298
break;
299
case MOD_UNLOAD:
300
kgss_unload();
301
mtx_destroy(&kgss_gssd_lock);
302
/*
303
* Unloading of the kgssapi module is not currently supported.
304
* If somebody wants this, we would need to keep track of
305
* currently executing threads and make sure the count is 0.
306
*/
307
/* FALLTHROUGH */
308
default:
309
error = EOPNOTSUPP;
310
}
311
return (error);
312
}
313
static moduledata_t kgssapi_mod = {
314
"kgssapi",
315
kgssapi_modevent,
316
NULL,
317
};
318
DECLARE_MODULE(kgssapi, kgssapi_mod, SI_SUB_VFS, SI_ORDER_SECOND);
319
MODULE_DEPEND(kgssapi, xdr, 1, 1, 1);
320
MODULE_DEPEND(kgssapi, krpc, 1, 1, 1);
321
MODULE_VERSION(kgssapi, 1);
322
323