gss_impl.c revision 184588
1/*-
2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/kgssapi/gss_impl.c 184588 2008-11-03 10:38:00Z dfr $");
30
31#include <sys/param.h>
32#include <sys/kernel.h>
33#include <sys/kobj.h>
34#include <sys/malloc.h>
35#include <sys/module.h>
36#include <sys/priv.h>
37#include <sys/syscall.h>
38#include <sys/sysent.h>
39#include <sys/sysproto.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
46#include "gssd.h"
47#include "kgss_if.h"
48
49MALLOC_DEFINE(M_GSSAPI, "GSS-API", "GSS-API");
50
51/*
52 * Syscall hooks
53 */
54static int gssd_syscall_offset = SYS_gssd_syscall;
55static struct sysent gssd_syscall_prev_sysent;
56MAKE_SYSENT(gssd_syscall);
57static bool_t gssd_syscall_registered = FALSE;
58
59struct kgss_mech_list kgss_mechs;
60CLIENT *kgss_gssd_handle;
61
62static void
63kgss_init(void *dummy)
64{
65	int error;
66
67	LIST_INIT(&kgss_mechs);
68	error = syscall_register(&gssd_syscall_offset, &gssd_syscall_sysent,
69	    &gssd_syscall_prev_sysent);
70	if (error)
71		printf("Can't register GSSD syscall\n");
72	else
73		gssd_syscall_registered = TRUE;
74}
75SYSINIT(kgss_init, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_init, NULL);
76
77static void
78kgss_uninit(void *dummy)
79{
80
81	if (gssd_syscall_registered)
82		syscall_deregister(&gssd_syscall_offset,
83		    &gssd_syscall_prev_sysent);
84}
85SYSUNINIT(kgss_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_uninit, NULL);
86
87int
88gssd_syscall(struct thread *td, struct gssd_syscall_args *uap)
89{
90        struct sockaddr_un sun;
91        struct netconfig *nconf;
92	char path[MAXPATHLEN];
93	int error;
94
95	error = priv_check(td, PRIV_NFS_DAEMON);
96	if (error)
97		return (error);
98
99	if (kgss_gssd_handle)
100		CLNT_DESTROY(kgss_gssd_handle);
101
102	error = copyinstr(uap->path, path, sizeof(path), NULL);
103	if (error)
104		return (error);
105
106        sun.sun_family = AF_LOCAL;
107        strcpy(sun.sun_path, path);
108        sun.sun_len = SUN_LEN(&sun);
109
110        nconf = getnetconfigent("local");
111        kgss_gssd_handle = clnt_reconnect_create(nconf,
112	    (struct sockaddr *) &sun, GSSD, GSSDVERS,
113	    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
114
115	return (0);
116}
117
118int
119kgss_oid_equal(const gss_OID oid1, const gss_OID oid2)
120{
121
122	if (oid1 == oid2)
123		return (1);
124	if (!oid1 || !oid2)
125		return (0);
126	if (oid1->length != oid2->length)
127		return (0);
128	if (memcmp(oid1->elements, oid2->elements, oid1->length))
129		return (0);
130	return (1);
131}
132
133void
134kgss_install_mech(gss_OID mech_type, const char *name, struct kobj_class *cls)
135{
136	struct kgss_mech *km;
137
138	km = malloc(sizeof(struct kgss_mech), M_GSSAPI, M_WAITOK);
139	km->km_mech_type = mech_type;
140	km->km_mech_name = name;
141	km->km_class = cls;
142	LIST_INSERT_HEAD(&kgss_mechs, km, km_link);
143}
144
145void
146kgss_uninstall_mech(gss_OID mech_type)
147{
148	struct kgss_mech *km;
149
150	LIST_FOREACH(km, &kgss_mechs, km_link) {
151		if (kgss_oid_equal(km->km_mech_type, mech_type)) {
152			LIST_REMOVE(km, km_link);
153			free(km, M_GSSAPI);
154			return;
155		}
156	}
157}
158
159gss_OID
160kgss_find_mech_by_name(const char *name)
161{
162	struct kgss_mech *km;
163
164	LIST_FOREACH(km, &kgss_mechs, km_link) {
165		if (!strcmp(km->km_mech_name, name)) {
166			return (km->km_mech_type);
167		}
168	}
169	return (GSS_C_NO_OID);
170}
171
172const char *
173kgss_find_mech_by_oid(const gss_OID oid)
174{
175	struct kgss_mech *km;
176
177	LIST_FOREACH(km, &kgss_mechs, km_link) {
178		if (kgss_oid_equal(km->km_mech_type, oid)) {
179			return (km->km_mech_name);
180		}
181	}
182	return (NULL);
183}
184
185gss_ctx_id_t
186kgss_create_context(gss_OID mech_type)
187{
188	struct kgss_mech *km;
189	gss_ctx_id_t ctx;
190
191	LIST_FOREACH(km, &kgss_mechs, km_link) {
192		if (kgss_oid_equal(km->km_mech_type, mech_type))
193			break;
194	}
195	if (!km)
196		return (NULL);
197
198	ctx = (gss_ctx_id_t) kobj_create(km->km_class, M_GSSAPI, M_WAITOK);
199	KGSS_INIT(ctx);
200
201	return (ctx);
202}
203
204void
205kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
206{
207
208	KGSS_DELETE(ctx, output_token);
209	kobj_delete((kobj_t) ctx, M_GSSAPI);
210}
211
212OM_uint32
213kgss_transfer_context(gss_ctx_id_t ctx)
214{
215	struct export_sec_context_res res;
216	struct export_sec_context_args args;
217	enum clnt_stat stat;
218	OM_uint32 maj_stat;
219
220	if (!kgss_gssd_handle)
221		return (GSS_S_FAILURE);
222
223	args.ctx = ctx->handle;
224	bzero(&res, sizeof(res));
225	stat = gssd_export_sec_context_1(&args, &res, kgss_gssd_handle);
226	if (stat != RPC_SUCCESS) {
227		return (GSS_S_FAILURE);
228	}
229
230	maj_stat = KGSS_IMPORT(ctx, res.format, &res.interprocess_token);
231	ctx->handle = 0;
232
233	xdr_free((xdrproc_t) xdr_export_sec_context_res, &res);
234
235	return (maj_stat);
236}
237
238void
239kgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to)
240{
241	to->length = from->length;
242	if (from->length) {
243		to->value = malloc(from->length, M_GSSAPI, M_WAITOK);
244		bcopy(from->value, to->value, from->length);
245	} else {
246		to->value = NULL;
247	}
248}
249
250/*
251 * Kernel module glue
252 */
253static int
254kgssapi_modevent(module_t mod, int type, void *data)
255{
256
257	return (0);
258}
259static moduledata_t kgssapi_mod = {
260	"kgssapi",
261	kgssapi_modevent,
262	NULL,
263};
264DECLARE_MODULE(kgssapi, kgssapi_mod, SI_SUB_VFS, SI_ORDER_ANY);
265MODULE_DEPEND(kgssapi, krpc, 1, 1, 1);
266MODULE_VERSION(kgssapi, 1);
267