gss_impl.c revision 184588
1184588Sdfr/*-
2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org>
4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5184588Sdfr *
6184588Sdfr * Redistribution and use in source and binary forms, with or without
7184588Sdfr * modification, are permitted provided that the following conditions
8184588Sdfr * are met:
9184588Sdfr * 1. Redistributions of source code must retain the above copyright
10184588Sdfr *    notice, this list of conditions and the following disclaimer.
11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright
12184588Sdfr *    notice, this list of conditions and the following disclaimer in the
13184588Sdfr *    documentation and/or other materials provided with the distribution.
14184588Sdfr *
15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18184588Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25184588Sdfr * SUCH DAMAGE.
26184588Sdfr */
27184588Sdfr
28184588Sdfr#include <sys/cdefs.h>
29184588Sdfr__FBSDID("$FreeBSD: head/sys/kgssapi/gss_impl.c 184588 2008-11-03 10:38:00Z dfr $");
30184588Sdfr
31184588Sdfr#include <sys/param.h>
32184588Sdfr#include <sys/kernel.h>
33184588Sdfr#include <sys/kobj.h>
34184588Sdfr#include <sys/malloc.h>
35184588Sdfr#include <sys/module.h>
36184588Sdfr#include <sys/priv.h>
37184588Sdfr#include <sys/syscall.h>
38184588Sdfr#include <sys/sysent.h>
39184588Sdfr#include <sys/sysproto.h>
40184588Sdfr
41184588Sdfr#include <kgssapi/gssapi.h>
42184588Sdfr#include <kgssapi/gssapi_impl.h>
43184588Sdfr#include <rpc/rpc.h>
44184588Sdfr#include <rpc/rpc_com.h>
45184588Sdfr
46184588Sdfr#include "gssd.h"
47184588Sdfr#include "kgss_if.h"
48184588Sdfr
49184588SdfrMALLOC_DEFINE(M_GSSAPI, "GSS-API", "GSS-API");
50184588Sdfr
51184588Sdfr/*
52184588Sdfr * Syscall hooks
53184588Sdfr */
54184588Sdfrstatic int gssd_syscall_offset = SYS_gssd_syscall;
55184588Sdfrstatic struct sysent gssd_syscall_prev_sysent;
56184588SdfrMAKE_SYSENT(gssd_syscall);
57184588Sdfrstatic bool_t gssd_syscall_registered = FALSE;
58184588Sdfr
59184588Sdfrstruct kgss_mech_list kgss_mechs;
60184588SdfrCLIENT *kgss_gssd_handle;
61184588Sdfr
62184588Sdfrstatic void
63184588Sdfrkgss_init(void *dummy)
64184588Sdfr{
65184588Sdfr	int error;
66184588Sdfr
67184588Sdfr	LIST_INIT(&kgss_mechs);
68184588Sdfr	error = syscall_register(&gssd_syscall_offset, &gssd_syscall_sysent,
69184588Sdfr	    &gssd_syscall_prev_sysent);
70184588Sdfr	if (error)
71184588Sdfr		printf("Can't register GSSD syscall\n");
72184588Sdfr	else
73184588Sdfr		gssd_syscall_registered = TRUE;
74184588Sdfr}
75184588SdfrSYSINIT(kgss_init, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_init, NULL);
76184588Sdfr
77184588Sdfrstatic void
78184588Sdfrkgss_uninit(void *dummy)
79184588Sdfr{
80184588Sdfr
81184588Sdfr	if (gssd_syscall_registered)
82184588Sdfr		syscall_deregister(&gssd_syscall_offset,
83184588Sdfr		    &gssd_syscall_prev_sysent);
84184588Sdfr}
85184588SdfrSYSUNINIT(kgss_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_uninit, NULL);
86184588Sdfr
87184588Sdfrint
88184588Sdfrgssd_syscall(struct thread *td, struct gssd_syscall_args *uap)
89184588Sdfr{
90184588Sdfr        struct sockaddr_un sun;
91184588Sdfr        struct netconfig *nconf;
92184588Sdfr	char path[MAXPATHLEN];
93184588Sdfr	int error;
94184588Sdfr
95184588Sdfr	error = priv_check(td, PRIV_NFS_DAEMON);
96184588Sdfr	if (error)
97184588Sdfr		return (error);
98184588Sdfr
99184588Sdfr	if (kgss_gssd_handle)
100184588Sdfr		CLNT_DESTROY(kgss_gssd_handle);
101184588Sdfr
102184588Sdfr	error = copyinstr(uap->path, path, sizeof(path), NULL);
103184588Sdfr	if (error)
104184588Sdfr		return (error);
105184588Sdfr
106184588Sdfr        sun.sun_family = AF_LOCAL;
107184588Sdfr        strcpy(sun.sun_path, path);
108184588Sdfr        sun.sun_len = SUN_LEN(&sun);
109184588Sdfr
110184588Sdfr        nconf = getnetconfigent("local");
111184588Sdfr        kgss_gssd_handle = clnt_reconnect_create(nconf,
112184588Sdfr	    (struct sockaddr *) &sun, GSSD, GSSDVERS,
113184588Sdfr	    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
114184588Sdfr
115184588Sdfr	return (0);
116184588Sdfr}
117184588Sdfr
118184588Sdfrint
119184588Sdfrkgss_oid_equal(const gss_OID oid1, const gss_OID oid2)
120184588Sdfr{
121184588Sdfr
122184588Sdfr	if (oid1 == oid2)
123184588Sdfr		return (1);
124184588Sdfr	if (!oid1 || !oid2)
125184588Sdfr		return (0);
126184588Sdfr	if (oid1->length != oid2->length)
127184588Sdfr		return (0);
128184588Sdfr	if (memcmp(oid1->elements, oid2->elements, oid1->length))
129184588Sdfr		return (0);
130184588Sdfr	return (1);
131184588Sdfr}
132184588Sdfr
133184588Sdfrvoid
134184588Sdfrkgss_install_mech(gss_OID mech_type, const char *name, struct kobj_class *cls)
135184588Sdfr{
136184588Sdfr	struct kgss_mech *km;
137184588Sdfr
138184588Sdfr	km = malloc(sizeof(struct kgss_mech), M_GSSAPI, M_WAITOK);
139184588Sdfr	km->km_mech_type = mech_type;
140184588Sdfr	km->km_mech_name = name;
141184588Sdfr	km->km_class = cls;
142184588Sdfr	LIST_INSERT_HEAD(&kgss_mechs, km, km_link);
143184588Sdfr}
144184588Sdfr
145184588Sdfrvoid
146184588Sdfrkgss_uninstall_mech(gss_OID mech_type)
147184588Sdfr{
148184588Sdfr	struct kgss_mech *km;
149184588Sdfr
150184588Sdfr	LIST_FOREACH(km, &kgss_mechs, km_link) {
151184588Sdfr		if (kgss_oid_equal(km->km_mech_type, mech_type)) {
152184588Sdfr			LIST_REMOVE(km, km_link);
153184588Sdfr			free(km, M_GSSAPI);
154184588Sdfr			return;
155184588Sdfr		}
156184588Sdfr	}
157184588Sdfr}
158184588Sdfr
159184588Sdfrgss_OID
160184588Sdfrkgss_find_mech_by_name(const char *name)
161184588Sdfr{
162184588Sdfr	struct kgss_mech *km;
163184588Sdfr
164184588Sdfr	LIST_FOREACH(km, &kgss_mechs, km_link) {
165184588Sdfr		if (!strcmp(km->km_mech_name, name)) {
166184588Sdfr			return (km->km_mech_type);
167184588Sdfr		}
168184588Sdfr	}
169184588Sdfr	return (GSS_C_NO_OID);
170184588Sdfr}
171184588Sdfr
172184588Sdfrconst char *
173184588Sdfrkgss_find_mech_by_oid(const gss_OID oid)
174184588Sdfr{
175184588Sdfr	struct kgss_mech *km;
176184588Sdfr
177184588Sdfr	LIST_FOREACH(km, &kgss_mechs, km_link) {
178184588Sdfr		if (kgss_oid_equal(km->km_mech_type, oid)) {
179184588Sdfr			return (km->km_mech_name);
180184588Sdfr		}
181184588Sdfr	}
182184588Sdfr	return (NULL);
183184588Sdfr}
184184588Sdfr
185184588Sdfrgss_ctx_id_t
186184588Sdfrkgss_create_context(gss_OID mech_type)
187184588Sdfr{
188184588Sdfr	struct kgss_mech *km;
189184588Sdfr	gss_ctx_id_t ctx;
190184588Sdfr
191184588Sdfr	LIST_FOREACH(km, &kgss_mechs, km_link) {
192184588Sdfr		if (kgss_oid_equal(km->km_mech_type, mech_type))
193184588Sdfr			break;
194184588Sdfr	}
195184588Sdfr	if (!km)
196184588Sdfr		return (NULL);
197184588Sdfr
198184588Sdfr	ctx = (gss_ctx_id_t) kobj_create(km->km_class, M_GSSAPI, M_WAITOK);
199184588Sdfr	KGSS_INIT(ctx);
200184588Sdfr
201184588Sdfr	return (ctx);
202184588Sdfr}
203184588Sdfr
204184588Sdfrvoid
205184588Sdfrkgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
206184588Sdfr{
207184588Sdfr
208184588Sdfr	KGSS_DELETE(ctx, output_token);
209184588Sdfr	kobj_delete((kobj_t) ctx, M_GSSAPI);
210184588Sdfr}
211184588Sdfr
212184588SdfrOM_uint32
213184588Sdfrkgss_transfer_context(gss_ctx_id_t ctx)
214184588Sdfr{
215184588Sdfr	struct export_sec_context_res res;
216184588Sdfr	struct export_sec_context_args args;
217184588Sdfr	enum clnt_stat stat;
218184588Sdfr	OM_uint32 maj_stat;
219184588Sdfr
220184588Sdfr	if (!kgss_gssd_handle)
221184588Sdfr		return (GSS_S_FAILURE);
222184588Sdfr
223184588Sdfr	args.ctx = ctx->handle;
224184588Sdfr	bzero(&res, sizeof(res));
225184588Sdfr	stat = gssd_export_sec_context_1(&args, &res, kgss_gssd_handle);
226184588Sdfr	if (stat != RPC_SUCCESS) {
227184588Sdfr		return (GSS_S_FAILURE);
228184588Sdfr	}
229184588Sdfr
230184588Sdfr	maj_stat = KGSS_IMPORT(ctx, res.format, &res.interprocess_token);
231184588Sdfr	ctx->handle = 0;
232184588Sdfr
233184588Sdfr	xdr_free((xdrproc_t) xdr_export_sec_context_res, &res);
234184588Sdfr
235184588Sdfr	return (maj_stat);
236184588Sdfr}
237184588Sdfr
238184588Sdfrvoid
239184588Sdfrkgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to)
240184588Sdfr{
241184588Sdfr	to->length = from->length;
242184588Sdfr	if (from->length) {
243184588Sdfr		to->value = malloc(from->length, M_GSSAPI, M_WAITOK);
244184588Sdfr		bcopy(from->value, to->value, from->length);
245184588Sdfr	} else {
246184588Sdfr		to->value = NULL;
247184588Sdfr	}
248184588Sdfr}
249184588Sdfr
250184588Sdfr/*
251184588Sdfr * Kernel module glue
252184588Sdfr */
253184588Sdfrstatic int
254184588Sdfrkgssapi_modevent(module_t mod, int type, void *data)
255184588Sdfr{
256184588Sdfr
257184588Sdfr	return (0);
258184588Sdfr}
259184588Sdfrstatic moduledata_t kgssapi_mod = {
260184588Sdfr	"kgssapi",
261184588Sdfr	kgssapi_modevent,
262184588Sdfr	NULL,
263184588Sdfr};
264184588SdfrDECLARE_MODULE(kgssapi, kgssapi_mod, SI_SUB_VFS, SI_ORDER_ANY);
265184588SdfrMODULE_DEPEND(kgssapi, krpc, 1, 1, 1);
266184588SdfrMODULE_VERSION(kgssapi, 1);
267