gss_impl.c revision 224084
1139804Simp/*-
246197Sphk * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
346197Sphk * Authors: Doug Rabson <dfr@rabson.org>
446197Sphk * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
546197Sphk *
646197Sphk * Redistribution and use in source and binary forms, with or without
746197Sphk * modification, are permitted provided that the following conditions
846197Sphk * are met:
946155Sphk * 1. Redistributions of source code must retain the above copyright
10116182Sobrien *    notice, this list of conditions and the following disclaimer.
11116182Sobrien * 2. Redistributions in binary form must reproduce the above copyright
12116182Sobrien *    notice, this list of conditions and the following disclaimer in the
13131177Spjd *    documentation and/or other materials provided with the distribution.
14131177Spjd *
1546155Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1646155Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1746155Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1846155Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1946155Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2046155Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2146155Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22164032Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2346155Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24124882Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2546155Sphk * SUCH DAMAGE.
2687275Srwatson */
2787275Srwatson
28168401Spjd#include <sys/cdefs.h>
29113275Smike__FBSDID("$FreeBSD: head/sys/kgssapi/gss_impl.c 224084 2011-07-16 08:05:49Z zack $");
30147185Spjd
31113275Smike#include <sys/param.h>
3246155Sphk#include <sys/kernel.h>
33113275Smike#include <sys/kobj.h>
3457163Srwatson#include <sys/malloc.h>
35113275Smike#include <sys/module.h>
3646155Sphk#include <sys/priv.h>
3746155Sphk#include <sys/syscall.h>
3846155Sphk#include <sys/sysent.h>
39163606Srwatson#include <sys/sysproto.h>
40163606Srwatson
4146155Sphk#include <kgssapi/gssapi.h>
4246155Sphk#include <kgssapi/gssapi_impl.h>
4389414Sarr#include <rpc/rpc.h>
4457163Srwatson#include <rpc/rpc_com.h>
4557163Srwatson#include <rpc/rpcsec_gss.h>
4657163Srwatson
4789414Sarr#include "gssd.h"
4857163Srwatson#include "kgss_if.h"
4957163Srwatson
5057163SrwatsonMALLOC_DEFINE(M_GSSAPI, "GSS-API", "GSS-API");
5161235Srwatson
5289414Sarr/*
5361235Srwatson * Syscall hooks
5461235Srwatson */
5561235Srwatsonstatic int gssd_syscall_offset = SYS_gssd_syscall;
5668024Srwatsonstatic struct sysent gssd_syscall_prev_sysent;
5789414SarrMAKE_SYSENT(gssd_syscall);
5868024Srwatsonstatic bool_t gssd_syscall_registered = FALSE;
5968024Srwatson
6068024Srwatsonstruct kgss_mech_list kgss_mechs;
61147185SpjdCLIENT *kgss_gssd_handle;
62147185Spjd
63147185Spjdstatic void
64147185Spjdkgss_init(void *dummy)
65125804Srwatson{
66128664Sbmilekic	int error;
67128664Sbmilekic
68128664Sbmilekic	LIST_INIT(&kgss_mechs);
69128664Sbmilekic	error = syscall_register(&gssd_syscall_offset, &gssd_syscall_sysent,
70128664Sbmilekic	    &gssd_syscall_prev_sysent);
71141543Scperciva	if (error)
72141543Scperciva		printf("Can't register GSSD syscall\n");
73141543Scperciva	else
74141543Scperciva		gssd_syscall_registered = TRUE;
75141543Scperciva}
76168396SpjdSYSINIT(kgss_init, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_init, NULL);
77168396Spjd
78168396Spjdstatic void
79168396Spjdkgss_uninit(void *dummy)
80168396Spjd{
81168401Spjd
82113275Smike	if (gssd_syscall_registered)
83168401Spjd		syscall_deregister(&gssd_syscall_offset,
84113275Smike		    &gssd_syscall_prev_sysent);
85113275Smike}
86113275SmikeSYSUNINIT(kgss_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kgss_uninit, NULL);
87168401Spjd
88168401Spjdint
89168401Spjdgssd_syscall(struct thread *td, struct gssd_syscall_args *uap)
90168401Spjd{
91168401Spjd        struct sockaddr_un sun;
92168401Spjd        struct netconfig *nconf;
93168401Spjd	char path[MAXPATHLEN];
94168401Spjd	int error;
95168401Spjd
96168401Spjd	error = priv_check(td, PRIV_NFS_DAEMON);
97168401Spjd	if (error)
98168401Spjd		return (error);
99168401Spjd
100168401Spjd	if (kgss_gssd_handle)
101168401Spjd		CLNT_DESTROY(kgss_gssd_handle);
102168401Spjd
103113275Smike	error = copyinstr(uap->path, path, sizeof(path), NULL);
104124882Srwatson	if (error)
105113275Smike		return (error);
106113275Smike
107113275Smike        sun.sun_family = AF_LOCAL;
108113275Smike        strcpy(sun.sun_path, path);
109113275Smike        sun.sun_len = SUN_LEN(&sun);
110113275Smike
111168401Spjd        nconf = getnetconfigent("local");
112113275Smike        kgss_gssd_handle = clnt_reconnect_create(nconf,
113113275Smike	    (struct sockaddr *) &sun, GSSD, GSSDVERS,
114113275Smike	    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
115113275Smike
116113275Smike	return (0);
11782710Sdillon}
118114168Smike
119114168Smikeint
120114168Smikekgss_oid_equal(const gss_OID oid1, const gss_OID oid2)
12182710Sdillon{
12246155Sphk
123114168Smike	if (oid1 == oid2)
12446155Sphk		return (1);
125113275Smike	if (!oid1 || !oid2)
126113275Smike		return (0);
127168401Spjd	if (oid1->length != oid2->length)
12846155Sphk		return (0);
129113275Smike	if (memcmp(oid1->elements, oid2->elements, oid1->length))
130150652Scsjp		return (0);
13146155Sphk	return (1);
132114168Smike}
13346155Sphk
13484828Sjhbvoid
13584828Sjhbkgss_install_mech(gss_OID mech_type, const char *name, struct kobj_class *cls)
13684828Sjhb{
13784828Sjhb	struct kgss_mech *km;
138114168Smike
13993818Sjhb	km = malloc(sizeof(struct kgss_mech), M_GSSAPI, M_WAITOK);
140113275Smike	km->km_mech_type = mech_type;
141114168Smike	km->km_mech_name = name;
142113275Smike	km->km_class = cls;
143113275Smike	LIST_INSERT_HEAD(&kgss_mechs, km, km_link);
144150652Scsjp}
145150652Scsjp
146113275Smikevoid
147150652Scsjpkgss_uninstall_mech(gss_OID mech_type)
148113275Smike{
149150652Scsjp	struct kgss_mech *km;
150113275Smike
151113275Smike	LIST_FOREACH(km, &kgss_mechs, km_link) {
152113275Smike		if (kgss_oid_equal(km->km_mech_type, mech_type)) {
153150652Scsjp			LIST_REMOVE(km, km_link);
154114168Smike			free(km, M_GSSAPI);
15584828Sjhb			return;
156113275Smike		}
157113275Smike	}
158113275Smike}
159113275Smike
160168401Spjdgss_OID
161168401Spjdkgss_find_mech_by_name(const char *name)
162168401Spjd{
163168401Spjd	struct kgss_mech *km;
164168401Spjd
165168401Spjd	LIST_FOREACH(km, &kgss_mechs, km_link) {
166113275Smike		if (!strcmp(km->km_mech_name, name)) {
167113275Smike			return (km->km_mech_type);
168168401Spjd		}
169113275Smike	}
170113275Smike	return (GSS_C_NO_OID);
171113275Smike}
172113275Smike
173113275Smikeconst char *
174113275Smikekgss_find_mech_by_oid(const gss_OID oid)
175113275Smike{
176113275Smike	struct kgss_mech *km;
177168401Spjd
178113275Smike	LIST_FOREACH(km, &kgss_mechs, km_link) {
179113275Smike		if (kgss_oid_equal(km->km_mech_type, oid)) {
180113275Smike			return (km->km_mech_name);
181113275Smike		}
182113275Smike	}
183113275Smike	return (NULL);
184113275Smike}
185113275Smike
186113275Smikegss_ctx_id_t
187168401Spjdkgss_create_context(gss_OID mech_type)
188168401Spjd{
189168401Spjd	struct kgss_mech *km;
190168401Spjd	gss_ctx_id_t ctx;
191168401Spjd
192113275Smike	LIST_FOREACH(km, &kgss_mechs, km_link) {
193113275Smike		if (kgss_oid_equal(km->km_mech_type, mech_type))
194113275Smike			break;
195113275Smike	}
196113275Smike	if (!km)
197113275Smike		return (NULL);
198113275Smike
199113275Smike	ctx = (gss_ctx_id_t) kobj_create(km->km_class, M_GSSAPI, M_WAITOK);
200113275Smike	KGSS_INIT(ctx);
201113275Smike
202168401Spjd	return (ctx);
203113275Smike}
204113275Smike
205168401Spjdvoid
206168401Spjdkgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
207168401Spjd{
208168401Spjd
209168401Spjd	KGSS_DELETE(ctx, output_token);
210113275Smike	kobj_delete((kobj_t) ctx, M_GSSAPI);
211150652Scsjp}
212113275Smike
213150652ScsjpOM_uint32
214113275Smikekgss_transfer_context(gss_ctx_id_t ctx)
215113275Smike{
216113275Smike	struct export_sec_context_res res;
217113275Smike	struct export_sec_context_args args;
218113275Smike	enum clnt_stat stat;
219113275Smike	OM_uint32 maj_stat;
220113275Smike
221114168Smike	if (!kgss_gssd_handle)
222114168Smike		return (GSS_S_FAILURE);
223114168Smike
224113275Smike	args.ctx = ctx->handle;
225113275Smike	bzero(&res, sizeof(res));
226114168Smike	stat = gssd_export_sec_context_1(&args, &res, kgss_gssd_handle);
227113275Smike	if (stat != RPC_SUCCESS) {
228113275Smike		return (GSS_S_FAILURE);
229113275Smike	}
230113275Smike
231150652Scsjp	maj_stat = KGSS_IMPORT(ctx, res.format, &res.interprocess_token);
232167309Spjd	ctx->handle = 0;
233126023Snectar
234126023Snectar	xdr_free((xdrproc_t) xdr_export_sec_context_res, &res);
235126023Snectar
236126023Snectar	return (maj_stat);
237126023Snectar}
238126023Snectar
239126023Snectarvoid
240126023Snectarkgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to)
241164032Srwatson{
242126023Snectar	to->length = from->length;
243126023Snectar	if (from->length) {
244126023Snectar		to->value = malloc(from->length, M_GSSAPI, M_WAITOK);
245113275Smike		bcopy(from->value, to->value, from->length);
246168401Spjd	} else {
247113275Smike		to->value = NULL;
248113275Smike	}
249168401Spjd}
250113275Smike
251113275Smike/*
252113275Smike * Kernel module glue
253113275Smike */
254168401Spjdstatic int
255113275Smikekgssapi_modevent(module_t mod, int type, void *data)
256150652Scsjp{
257113275Smike	int error = 0;
258113275Smike
259113275Smike	switch (type) {
260113275Smike	case MOD_LOAD:
261172930Srwatson		rpc_gss_entries.rpc_gss_secfind = rpc_gss_secfind;
262113275Smike		rpc_gss_entries.rpc_gss_secpurge = rpc_gss_secpurge;
263113275Smike		rpc_gss_entries.rpc_gss_seccreate = rpc_gss_seccreate;
264113275Smike		rpc_gss_entries.rpc_gss_set_defaults = rpc_gss_set_defaults;
265113275Smike		rpc_gss_entries.rpc_gss_max_data_length =
266150652Scsjp		    rpc_gss_max_data_length;
267113275Smike		rpc_gss_entries.rpc_gss_get_error = rpc_gss_get_error;
26884828Sjhb		rpc_gss_entries.rpc_gss_mech_to_oid = rpc_gss_mech_to_oid;
26984828Sjhb		rpc_gss_entries.rpc_gss_oid_to_mech = rpc_gss_oid_to_mech;
27084828Sjhb		rpc_gss_entries.rpc_gss_qop_to_num = rpc_gss_qop_to_num;
271113275Smike		rpc_gss_entries.rpc_gss_get_mechanisms = rpc_gss_get_mechanisms;
27284828Sjhb		rpc_gss_entries.rpc_gss_get_versions = rpc_gss_get_versions;
273113630Sjhb		rpc_gss_entries.rpc_gss_is_installed = rpc_gss_is_installed;
27484828Sjhb		rpc_gss_entries.rpc_gss_set_svc_name = rpc_gss_set_svc_name;
27584828Sjhb		rpc_gss_entries.rpc_gss_clear_svc_name = rpc_gss_clear_svc_name;
27684828Sjhb		rpc_gss_entries.rpc_gss_getcred = rpc_gss_getcred;
27746155Sphk		rpc_gss_entries.rpc_gss_set_callback = rpc_gss_set_callback;
278113275Smike		rpc_gss_entries.rpc_gss_clear_callback = rpc_gss_clear_callback;
279113275Smike		rpc_gss_entries.rpc_gss_get_principal_name =
280150652Scsjp		    rpc_gss_get_principal_name;
281113275Smike		rpc_gss_entries.rpc_gss_svc_max_data_length =
282113275Smike		    rpc_gss_svc_max_data_length;
283113275Smike		break;
28446155Sphk	case MOD_UNLOAD:
28546155Sphk		/*
28646155Sphk		 * Unloading of the kgssapi module is not currently supported.
287113275Smike		 * If somebody wants this, we would need to keep track of
288113275Smike		 * currently executing threads and make sure the count is 0.
289113275Smike		 */
290168399Spjd		/* FALLTHROUGH */
291113275Smike	default:
292113275Smike		error = EOPNOTSUPP;
293113275Smike	};
294113275Smike	return (error);
295168401Spjd}
296113275Smikestatic moduledata_t kgssapi_mod = {
297113275Smike	"kgssapi",
298113275Smike	kgssapi_modevent,
299168489Spjd	NULL,
300168489Spjd};
301168489SpjdDECLARE_MODULE(kgssapi, kgssapi_mod, SI_SUB_VFS, SI_ORDER_ANY);
302168489SpjdMODULE_DEPEND(kgssapi, krpc, 1, 1, 1);
303113275SmikeMODULE_VERSION(kgssapi, 1);
304113275Smike