gss_impl.c revision 253049
1198090Srdivacky/*-
2198090Srdivacky * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3198090Srdivacky * Authors: Doug Rabson <dfr@rabson.org>
4198090Srdivacky * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5198090Srdivacky *
6198090Srdivacky * Redistribution and use in source and binary forms, with or without
7198090Srdivacky * modification, are permitted provided that the following conditions
8198090Srdivacky * are met:
9198090Srdivacky * 1. Redistributions of source code must retain the above copyright
10198090Srdivacky *    notice, this list of conditions and the following disclaimer.
11198090Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
12198090Srdivacky *    notice, this list of conditions and the following disclaimer in the
13198090Srdivacky *    documentation and/or other materials provided with the distribution.
14198090Srdivacky *
15198090Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16198090Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17198090Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18198090Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19198090Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20198090Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21198090Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22198090Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23198090Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24198090Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25198090Srdivacky * SUCH DAMAGE.
26198090Srdivacky */
27198090Srdivacky
28198090Srdivacky#include <sys/cdefs.h>
29198090Srdivacky__FBSDID("$FreeBSD: head/sys/kgssapi/gss_impl.c 253049 2013-07-09 01:05:28Z rmacklem $");
30198090Srdivacky
31198090Srdivacky#include <sys/param.h>
32198090Srdivacky#include <sys/kernel.h>
33198090Srdivacky#include <sys/kobj.h>
34198090Srdivacky#include <sys/lock.h>
35198090Srdivacky#include <sys/malloc.h>
36198090Srdivacky#include <sys/module.h>
37198090Srdivacky#include <sys/mutex.h>
38198090Srdivacky#include <sys/priv.h>
39198090Srdivacky#include <sys/syscall.h>
40198090Srdivacky#include <sys/sysent.h>
41198090Srdivacky#include <sys/sysproto.h>
42198090Srdivacky
43198090Srdivacky#include <kgssapi/gssapi.h>
44198090Srdivacky#include <kgssapi/gssapi_impl.h>
45198090Srdivacky#include <rpc/rpc.h>
46198090Srdivacky#include <rpc/rpc_com.h>
47198090Srdivacky#include <rpc/rpcsec_gss.h>
48198090Srdivacky
49198090Srdivacky#include "gssd.h"
50198090Srdivacky#include "kgss_if.h"
51198090Srdivacky
52198090SrdivackyMALLOC_DEFINE(M_GSSAPI, "GSS-API", "GSS-API");
53198090Srdivacky
54198090Srdivacky/*
55198090Srdivacky * Syscall hooks
56198090Srdivacky */
57198090Srdivackystatic int gssd_syscall_offset = SYS_gssd_syscall;
58198090Srdivackystatic struct sysent gssd_syscall_prev_sysent;
59198090SrdivackyMAKE_SYSENT(gssd_syscall);
60198090Srdivackystatic bool_t gssd_syscall_registered = FALSE;
61198090Srdivacky
62198090Srdivackystruct kgss_mech_list kgss_mechs;
63198090SrdivackyCLIENT *kgss_gssd_handle;
64198090Srdivackystruct mtx kgss_gssd_lock;
65198090Srdivacky
66198090Srdivackystatic void
67198090Srdivackykgss_init(void *dummy)
68198090Srdivacky{
69198090Srdivacky	int error;
70198090Srdivacky
71198090Srdivacky	LIST_INIT(&kgss_mechs);
72198090Srdivacky	error = syscall_register(&gssd_syscall_offset, &gssd_syscall_sysent,
73198090Srdivacky	    &gssd_syscall_prev_sysent);
74198090Srdivacky	if (error)
75198090Srdivacky		printf("Can't register GSSD syscall\n");
76198090Srdivacky	else
77198090Srdivacky		gssd_syscall_registered = TRUE;
78198090Srdivacky}
79198090SrdivackySYSINIT(kgss_init, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_init, NULL);
80198090Srdivacky
81198090Srdivackystatic void
82198090Srdivackykgss_uninit(void *dummy)
83198090Srdivacky{
84198090Srdivacky
85198090Srdivacky	if (gssd_syscall_registered)
86198090Srdivacky		syscall_deregister(&gssd_syscall_offset,
87198090Srdivacky		    &gssd_syscall_prev_sysent);
88198090Srdivacky}
89198090SrdivackySYSUNINIT(kgss_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_uninit, NULL);
90198090Srdivacky
91198090Srdivackyint
92198090Srdivackysys_gssd_syscall(struct thread *td, struct gssd_syscall_args *uap)
93198090Srdivacky{
94198090Srdivacky        struct sockaddr_un sun;
95198090Srdivacky        struct netconfig *nconf;
96198090Srdivacky	char path[MAXPATHLEN];
97198090Srdivacky	int error;
98198090Srdivacky	CLIENT *cl, *oldcl;
99198090Srdivacky
100198090Srdivacky	error = priv_check(td, PRIV_NFS_DAEMON);
101198090Srdivacky	if (error)
102198090Srdivacky		return (error);
103198090Srdivacky
104198090Srdivacky	error = copyinstr(uap->path, path, sizeof(path), NULL);
105198090Srdivacky	if (error)
106198090Srdivacky		return (error);
107198090Srdivacky
108198090Srdivacky        sun.sun_family = AF_LOCAL;
109198090Srdivacky        strcpy(sun.sun_path, path);
110198090Srdivacky        sun.sun_len = SUN_LEN(&sun);
111198090Srdivacky
112198090Srdivacky        nconf = getnetconfigent("local");
113198090Srdivacky        cl = clnt_reconnect_create(nconf,
114198090Srdivacky	    (struct sockaddr *) &sun, GSSD, GSSDVERS,
115198090Srdivacky	    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
116198090Srdivacky
117198090Srdivacky	mtx_lock(&kgss_gssd_lock);
118198090Srdivacky	oldcl = kgss_gssd_handle;
119198090Srdivacky	kgss_gssd_handle = cl;
120198090Srdivacky	mtx_unlock(&kgss_gssd_lock);
121198090Srdivacky
122198090Srdivacky	if (oldcl != NULL) {
123198090Srdivacky		CLNT_CLOSE(oldcl);
124198090Srdivacky		CLNT_RELEASE(oldcl);
125198090Srdivacky	}
126198090Srdivacky
127198090Srdivacky	return (0);
128198090Srdivacky}
129198090Srdivacky
130198090Srdivackyint
131198090Srdivackykgss_oid_equal(const gss_OID oid1, const gss_OID oid2)
132198090Srdivacky{
133198090Srdivacky
134198090Srdivacky	if (oid1 == oid2)
135198090Srdivacky		return (1);
136198090Srdivacky	if (!oid1 || !oid2)
137198090Srdivacky		return (0);
138198090Srdivacky	if (oid1->length != oid2->length)
139198090Srdivacky		return (0);
140198090Srdivacky	if (memcmp(oid1->elements, oid2->elements, oid1->length))
141198090Srdivacky		return (0);
142198090Srdivacky	return (1);
143198090Srdivacky}
144198396Srdivacky
145198090Srdivackyvoid
146198090Srdivackykgss_install_mech(gss_OID mech_type, const char *name, struct kobj_class *cls)
147198396Srdivacky{
148198090Srdivacky	struct kgss_mech *km;
149198090Srdivacky
150198090Srdivacky	km = malloc(sizeof(struct kgss_mech), M_GSSAPI, M_WAITOK);
151198090Srdivacky	km->km_mech_type = mech_type;
152198090Srdivacky	km->km_mech_name = name;
153198090Srdivacky	km->km_class = cls;
154198090Srdivacky	LIST_INSERT_HEAD(&kgss_mechs, km, km_link);
155198090Srdivacky}
156198090Srdivacky
157198090Srdivackyvoid
158198090Srdivackykgss_uninstall_mech(gss_OID mech_type)
159198090Srdivacky{
160198090Srdivacky	struct kgss_mech *km;
161198090Srdivacky
162198090Srdivacky	LIST_FOREACH(km, &kgss_mechs, km_link) {
163198090Srdivacky		if (kgss_oid_equal(km->km_mech_type, mech_type)) {
164198090Srdivacky			LIST_REMOVE(km, km_link);
165198090Srdivacky			free(km, M_GSSAPI);
166198090Srdivacky			return;
167198090Srdivacky		}
168198090Srdivacky	}
169198090Srdivacky}
170198090Srdivacky
171198090Srdivackygss_OID
172198090Srdivackykgss_find_mech_by_name(const char *name)
173198090Srdivacky{
174198090Srdivacky	struct kgss_mech *km;
175198090Srdivacky
176198396Srdivacky	LIST_FOREACH(km, &kgss_mechs, km_link) {
177198090Srdivacky		if (!strcmp(km->km_mech_name, name)) {
178198090Srdivacky			return (km->km_mech_type);
179198090Srdivacky		}
180198090Srdivacky	}
181198090Srdivacky	return (GSS_C_NO_OID);
182198090Srdivacky}
183198090Srdivacky
184198396Srdivackyconst char *
185198396Srdivackykgss_find_mech_by_oid(const gss_OID oid)
186198396Srdivacky{
187198396Srdivacky	struct kgss_mech *km;
188198396Srdivacky
189198396Srdivacky	LIST_FOREACH(km, &kgss_mechs, km_link) {
190198090Srdivacky		if (kgss_oid_equal(km->km_mech_type, oid)) {
191198090Srdivacky			return (km->km_mech_name);
192198090Srdivacky		}
193198090Srdivacky	}
194198090Srdivacky	return (NULL);
195198090Srdivacky}
196198090Srdivacky
197198396Srdivackygss_ctx_id_t
198198090Srdivackykgss_create_context(gss_OID mech_type)
199198090Srdivacky{
200198090Srdivacky	struct kgss_mech *km;
201198090Srdivacky	gss_ctx_id_t ctx;
202198090Srdivacky
203198090Srdivacky	LIST_FOREACH(km, &kgss_mechs, km_link) {
204198090Srdivacky		if (kgss_oid_equal(km->km_mech_type, mech_type))
205198090Srdivacky			break;
206198090Srdivacky	}
207198090Srdivacky	if (!km)
208198090Srdivacky		return (NULL);
209198090Srdivacky
210198090Srdivacky	ctx = (gss_ctx_id_t) kobj_create(km->km_class, M_GSSAPI, M_WAITOK);
211198090Srdivacky	KGSS_INIT(ctx);
212198090Srdivacky
213198090Srdivacky	return (ctx);
214198090Srdivacky}
215198090Srdivacky
216198090Srdivackyvoid
217198090Srdivackykgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
218198090Srdivacky{
219198090Srdivacky
220198090Srdivacky	KGSS_DELETE(ctx, output_token);
221198090Srdivacky	kobj_delete((kobj_t) ctx, M_GSSAPI);
222198090Srdivacky}
223198090Srdivacky
224198090SrdivackyOM_uint32
225198090Srdivackykgss_transfer_context(gss_ctx_id_t ctx)
226198090Srdivacky{
227198090Srdivacky	struct export_sec_context_res res;
228198090Srdivacky	struct export_sec_context_args args;
229198090Srdivacky	enum clnt_stat stat;
230198396Srdivacky	OM_uint32 maj_stat;
231198396Srdivacky
232198090Srdivacky	if (!kgss_gssd_handle)
233198090Srdivacky		return (GSS_S_FAILURE);
234198090Srdivacky
235198090Srdivacky	args.ctx = ctx->handle;
236198090Srdivacky	bzero(&res, sizeof(res));
237198090Srdivacky	stat = gssd_export_sec_context_1(&args, &res, kgss_gssd_handle);
238198090Srdivacky	if (stat != RPC_SUCCESS) {
239198090Srdivacky		return (GSS_S_FAILURE);
240198090Srdivacky	}
241198090Srdivacky
242198090Srdivacky	maj_stat = KGSS_IMPORT(ctx, res.format, &res.interprocess_token);
243198090Srdivacky	ctx->handle = 0;
244198090Srdivacky
245198090Srdivacky	xdr_free((xdrproc_t) xdr_export_sec_context_res, &res);
246198090Srdivacky
247198090Srdivacky	return (maj_stat);
248198090Srdivacky}
249198090Srdivacky
250198090Srdivackyvoid
251198090Srdivackykgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to)
252198090Srdivacky{
253198090Srdivacky	to->length = from->length;
254198090Srdivacky	if (from->length) {
255198090Srdivacky		to->value = malloc(from->length, M_GSSAPI, M_WAITOK);
256198090Srdivacky		bcopy(from->value, to->value, from->length);
257198090Srdivacky	} else {
258198090Srdivacky		to->value = NULL;
259198090Srdivacky	}
260198090Srdivacky}
261198090Srdivacky
262198090Srdivacky/*
263198090Srdivacky * Acquire the kgss_gssd_handle and return it with a reference count,
264198090Srdivacky * if it is available.
265198090Srdivacky */
266198090SrdivackyCLIENT *
267198090Srdivackykgss_gssd_client(void)
268198090Srdivacky{
269198090Srdivacky	CLIENT *cl;
270198090Srdivacky
271198090Srdivacky	mtx_lock(&kgss_gssd_lock);
272198090Srdivacky	cl = kgss_gssd_handle;
273198090Srdivacky	if (cl != NULL)
274198090Srdivacky		CLNT_ACQUIRE(cl);
275198090Srdivacky	mtx_unlock(&kgss_gssd_lock);
276198090Srdivacky	return (cl);
277198090Srdivacky}
278198090Srdivacky
279198090Srdivacky/*
280198090Srdivacky * Kernel module glue
281198090Srdivacky */
282198090Srdivackystatic int
283198090Srdivackykgssapi_modevent(module_t mod, int type, void *data)
284198090Srdivacky{
285198090Srdivacky	int error = 0;
286198090Srdivacky
287198090Srdivacky	switch (type) {
288198090Srdivacky	case MOD_LOAD:
289		rpc_gss_entries.rpc_gss_refresh_auth = rpc_gss_refresh_auth;
290		rpc_gss_entries.rpc_gss_secfind = rpc_gss_secfind;
291		rpc_gss_entries.rpc_gss_secpurge = rpc_gss_secpurge;
292		rpc_gss_entries.rpc_gss_seccreate = rpc_gss_seccreate;
293		rpc_gss_entries.rpc_gss_set_defaults = rpc_gss_set_defaults;
294		rpc_gss_entries.rpc_gss_max_data_length =
295		    rpc_gss_max_data_length;
296		rpc_gss_entries.rpc_gss_get_error = rpc_gss_get_error;
297		rpc_gss_entries.rpc_gss_mech_to_oid = rpc_gss_mech_to_oid;
298		rpc_gss_entries.rpc_gss_oid_to_mech = rpc_gss_oid_to_mech;
299		rpc_gss_entries.rpc_gss_qop_to_num = rpc_gss_qop_to_num;
300		rpc_gss_entries.rpc_gss_get_mechanisms = rpc_gss_get_mechanisms;
301		rpc_gss_entries.rpc_gss_get_versions = rpc_gss_get_versions;
302		rpc_gss_entries.rpc_gss_is_installed = rpc_gss_is_installed;
303		rpc_gss_entries.rpc_gss_set_svc_name = rpc_gss_set_svc_name;
304		rpc_gss_entries.rpc_gss_clear_svc_name = rpc_gss_clear_svc_name;
305		rpc_gss_entries.rpc_gss_getcred = rpc_gss_getcred;
306		rpc_gss_entries.rpc_gss_set_callback = rpc_gss_set_callback;
307		rpc_gss_entries.rpc_gss_clear_callback = rpc_gss_clear_callback;
308		rpc_gss_entries.rpc_gss_get_principal_name =
309		    rpc_gss_get_principal_name;
310		rpc_gss_entries.rpc_gss_svc_max_data_length =
311		    rpc_gss_svc_max_data_length;
312		mtx_init(&kgss_gssd_lock, "kgss_gssd_lock", NULL, MTX_DEF);
313		break;
314	case MOD_UNLOAD:
315		/*
316		 * Unloading of the kgssapi module is not currently supported.
317		 * If somebody wants this, we would need to keep track of
318		 * currently executing threads and make sure the count is 0.
319		 */
320		/* FALLTHROUGH */
321	default:
322		error = EOPNOTSUPP;
323	};
324	return (error);
325}
326static moduledata_t kgssapi_mod = {
327	"kgssapi",
328	kgssapi_modevent,
329	NULL,
330};
331DECLARE_MODULE(kgssapi, kgssapi_mod, SI_SUB_VFS, SI_ORDER_ANY);
332MODULE_DEPEND(kgssapi, krpc, 1, 1, 1);
333MODULE_VERSION(kgssapi, 1);
334