Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/kgssapi/gss_impl.c
101184 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
#if 0
92
static void
93
kgss_unload(void)
94
{
95
96
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
97
clnt_destroy(KGSS_VNET(kgss_gssd_handle));
98
KGSS_CURVNET_RESTORE();
99
}
100
#endif
101
102
int
103
kgss_oid_equal(const gss_OID oid1, const gss_OID oid2)
104
{
105
106
if (oid1 == oid2)
107
return (1);
108
if (!oid1 || !oid2)
109
return (0);
110
if (oid1->length != oid2->length)
111
return (0);
112
if (memcmp(oid1->elements, oid2->elements, oid1->length))
113
return (0);
114
return (1);
115
}
116
117
void
118
kgss_install_mech(gss_OID mech_type, const char *name, struct kobj_class *cls)
119
{
120
struct kgss_mech *km;
121
122
km = malloc(sizeof(struct kgss_mech), M_GSSAPI, M_WAITOK);
123
km->km_mech_type = mech_type;
124
km->km_mech_name = name;
125
km->km_class = cls;
126
LIST_INSERT_HEAD(&kgss_mechs, km, km_link);
127
}
128
129
void
130
kgss_uninstall_mech(gss_OID mech_type)
131
{
132
struct kgss_mech *km;
133
134
LIST_FOREACH(km, &kgss_mechs, km_link) {
135
if (kgss_oid_equal(km->km_mech_type, mech_type)) {
136
LIST_REMOVE(km, km_link);
137
free(km, M_GSSAPI);
138
return;
139
}
140
}
141
}
142
143
gss_OID
144
kgss_find_mech_by_name(const char *name)
145
{
146
struct kgss_mech *km;
147
148
LIST_FOREACH(km, &kgss_mechs, km_link) {
149
if (!strcmp(km->km_mech_name, name)) {
150
return (km->km_mech_type);
151
}
152
}
153
return (GSS_C_NO_OID);
154
}
155
156
const char *
157
kgss_find_mech_by_oid(const gss_OID oid)
158
{
159
struct kgss_mech *km;
160
161
LIST_FOREACH(km, &kgss_mechs, km_link) {
162
if (kgss_oid_equal(km->km_mech_type, oid)) {
163
return (km->km_mech_name);
164
}
165
}
166
return (NULL);
167
}
168
169
gss_ctx_id_t
170
kgss_create_context(gss_OID mech_type)
171
{
172
struct kgss_mech *km;
173
gss_ctx_id_t ctx;
174
175
LIST_FOREACH(km, &kgss_mechs, km_link) {
176
if (kgss_oid_equal(km->km_mech_type, mech_type))
177
break;
178
}
179
if (!km)
180
return (NULL);
181
182
ctx = (gss_ctx_id_t) kobj_create(km->km_class, M_GSSAPI, M_WAITOK);
183
KGSS_INIT(ctx);
184
185
return (ctx);
186
}
187
188
void
189
kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
190
{
191
192
KGSS_DELETE(ctx, output_token);
193
kobj_delete((kobj_t) ctx, M_GSSAPI);
194
}
195
196
OM_uint32
197
kgss_transfer_context(gss_ctx_id_t ctx, void *lctx)
198
{
199
struct export_sec_context_res res;
200
struct export_sec_context_args args;
201
enum clnt_stat stat;
202
OM_uint32 maj_stat;
203
204
if (lctx != NULL) {
205
maj_stat = KGSS_IMPORT(ctx, MIT_V1, lctx);
206
ctx->handle = 0;
207
return (maj_stat);
208
}
209
210
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
211
if (!KGSS_VNET(kgss_gssd_handle)) {
212
KGSS_CURVNET_RESTORE();
213
return (GSS_S_FAILURE);
214
}
215
216
args.ctx = ctx->handle;
217
bzero(&res, sizeof(res));
218
stat = gssd_export_sec_context_1(&args, &res, KGSS_VNET(kgss_gssd_handle));
219
KGSS_CURVNET_RESTORE();
220
if (stat != RPC_SUCCESS) {
221
return (GSS_S_FAILURE);
222
}
223
224
maj_stat = KGSS_IMPORT(ctx, res.format, &res.interprocess_token);
225
ctx->handle = 0;
226
227
xdr_free((xdrproc_t) xdr_export_sec_context_res, &res);
228
229
return (maj_stat);
230
}
231
232
void
233
kgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to)
234
{
235
to->length = from->length;
236
if (from->length) {
237
to->value = malloc(from->length, M_GSSAPI, M_WAITOK);
238
bcopy(from->value, to->value, from->length);
239
} else {
240
to->value = NULL;
241
}
242
}
243
244
/*
245
* Acquire the kgss_gssd_handle and return it with a reference count,
246
* if it is available.
247
*/
248
CLIENT *
249
kgss_gssd_client(void)
250
{
251
CLIENT *cl;
252
253
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
254
mtx_lock(&kgss_gssd_lock);
255
cl = KGSS_VNET(kgss_gssd_handle);
256
if (cl != NULL)
257
CLNT_ACQUIRE(cl);
258
mtx_unlock(&kgss_gssd_lock);
259
KGSS_CURVNET_RESTORE();
260
return (cl);
261
}
262
263
/*
264
* Kernel module glue
265
*/
266
static int
267
kgssapi_modevent(module_t mod, int type, void *data)
268
{
269
int error = 0;
270
271
switch (type) {
272
case MOD_LOAD:
273
rpc_gss_entries.rpc_gss_refresh_auth = rpc_gss_refresh_auth;
274
rpc_gss_entries.rpc_gss_secfind = rpc_gss_secfind;
275
rpc_gss_entries.rpc_gss_secpurge = rpc_gss_secpurge;
276
rpc_gss_entries.rpc_gss_seccreate = rpc_gss_seccreate;
277
rpc_gss_entries.rpc_gss_set_defaults = rpc_gss_set_defaults;
278
rpc_gss_entries.rpc_gss_max_data_length =
279
rpc_gss_max_data_length;
280
rpc_gss_entries.rpc_gss_get_error = rpc_gss_get_error;
281
rpc_gss_entries.rpc_gss_mech_to_oid = rpc_gss_mech_to_oid;
282
rpc_gss_entries.rpc_gss_oid_to_mech = rpc_gss_oid_to_mech;
283
rpc_gss_entries.rpc_gss_qop_to_num = rpc_gss_qop_to_num;
284
rpc_gss_entries.rpc_gss_get_mechanisms = rpc_gss_get_mechanisms;
285
rpc_gss_entries.rpc_gss_get_versions = rpc_gss_get_versions;
286
rpc_gss_entries.rpc_gss_is_installed = rpc_gss_is_installed;
287
rpc_gss_entries.rpc_gss_set_svc_name = rpc_gss_set_svc_name;
288
rpc_gss_entries.rpc_gss_clear_svc_name = rpc_gss_clear_svc_name;
289
rpc_gss_entries.rpc_gss_getcred = rpc_gss_getcred;
290
rpc_gss_entries.rpc_gss_set_callback = rpc_gss_set_callback;
291
rpc_gss_entries.rpc_gss_clear_callback = rpc_gss_clear_callback;
292
rpc_gss_entries.rpc_gss_get_principal_name =
293
rpc_gss_get_principal_name;
294
rpc_gss_entries.rpc_gss_svc_max_data_length =
295
rpc_gss_svc_max_data_length;
296
rpc_gss_entries.rpc_gss_ip_to_srv_principal =
297
rpc_gss_ip_to_srv_principal;
298
mtx_init(&kgss_gssd_lock, "kgss_gssd_lock", NULL, MTX_DEF);
299
error = kgss_load();
300
break;
301
case MOD_UNLOAD:
302
#if 0
303
kgss_unload();
304
mtx_destroy(&kgss_gssd_lock);
305
#endif
306
/*
307
* Unloading of the kgssapi module is not currently supported.
308
* If somebody wants this, we would need to keep track of
309
* currently executing threads and make sure the count is 0.
310
*/
311
/* FALLTHROUGH */
312
default:
313
error = EOPNOTSUPP;
314
}
315
return (error);
316
}
317
static moduledata_t kgssapi_mod = {
318
"kgssapi",
319
kgssapi_modevent,
320
NULL,
321
};
322
DECLARE_MODULE(kgssapi, kgssapi_mod, SI_SUB_VFS, SI_ORDER_SECOND);
323
MODULE_DEPEND(kgssapi, xdr, 1, 1, 1);
324
MODULE_DEPEND(kgssapi, krpc, 1, 1, 1);
325
MODULE_VERSION(kgssapi, 1);
326
327