1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	cred.c
24  *
25  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  *
28  */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <unistd.h>
33 #include <sys/note.h>
34 #include "dh_gssapi.h"
35 
36 /*
37  * This module supports the GSS credential family of routines for
38  * Diffie-Hellman mechanism.
39  */
40 
41 /*
42  * __dh_gss_acquire_cred: Get the credential associated with principal
43  * with the requested expire time and usage. Return the credential with
44  * the optional set of supported mechs and actual time left on the credential.
45  *
46  * Note in Diffie-Hellman the supplied principal name must be that of
47  * the caller. There is no way to delegate credentials.
48  *
49  * Libgss alwas sets desired_mechs to GSS_C_NO_OID_SET and set the return
50  * set of mechs to NULL.
51  */
52 
53 OM_uint32
__dh_gss_acquire_cred(void * ctx,OM_uint32 * minor,gss_name_t principal,OM_uint32 expire_req,gss_OID_set desired_mechs,gss_cred_usage_t usage,gss_cred_id_t * cred,gss_OID_set * mechs,OM_uint32 * expire_rec)54 __dh_gss_acquire_cred(void *ctx, /* Per mechanism context */
55 		    OM_uint32 *minor, /* Mechanism status */
56 		    gss_name_t principal, /* Requested principal */
57 		    OM_uint32  expire_req, /* Requested Expire time */
58 		    gss_OID_set desired_mechs, /* Set of desired mechs */
59 		    gss_cred_usage_t usage, /* Usage: init, accept, both */
60 		    gss_cred_id_t *cred, /* The return credential */
61 		    gss_OID_set *mechs, /* The return set of mechs */
62 		    OM_uint32 *expire_rec /* The expire time received*/)
63 {
64 	/* Diffie-Hellman mechanism context is ctx */
65 	dh_context_t cntx = (dh_context_t)ctx;
66 	dh_principal netname;
67 	dh_cred_id_t dh_cred;
68 
69 	/* Need to write to these */
70 	if (minor == 0 || cred == 0)
71 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
72 
73 	/* Set sane outputs */
74 	*minor = 0;
75 	if (mechs)
76 		*mechs = GSS_C_NO_OID_SET;
77 	if (expire_rec)
78 		*expire_rec = 0;
79 	*cred = GSS_C_NO_CREDENTIAL;
80 
81 	/*
82 	 * If not GSS_C_NO_OID_SET then the set must contain the
83 	 * Diffie-Hellman mechanism
84 	 */
85 	if (desired_mechs != GSS_C_NO_OID_SET &&
86 	    !__OID_is_member(desired_mechs, cntx->mech))
87 		return (GSS_S_BAD_MECH);
88 
89 	/* See if the callers secretkey is available */
90 	if (!cntx->keyopts->key_secretkey_is_set())
91 		return (GSS_S_NO_CRED);
92 
93 	/* Get the principal name of the caller */
94 	if ((netname = cntx->keyopts->get_principal()) == NULL)
95 		return (GSS_S_NO_CRED);
96 
97 	/*
98 	 * Diffie-Hellman requires the principal to be the principal
99 	 * of the caller
100 	 */
101 
102 	if (principal &&
103 	    strncmp(netname, (char *)principal, MAXNETNAMELEN) != 0) {
104 		Free(netname);
105 		return (GSS_S_NO_CRED);
106 	}
107 
108 	/* Allocate the credential */
109 	dh_cred = New(dh_cred_id_desc, 1);
110 	if (dh_cred == NULL) {
111 		Free(netname);
112 		*minor = DH_NOMEM_FAILURE;
113 		return (GSS_S_FAILURE);
114 	}
115 
116 	/* Set credential state */
117 	dh_cred->uid = geteuid();
118 	dh_cred->usage = usage;
119 	dh_cred->principal = netname;
120 	dh_cred->expire = expire_req ? time(0) + expire_req : GSS_C_INDEFINITE;
121 
122 	/*
123 	 * If mechs set it to the set that contains the appropriate
124 	 * Diffie-Hellman mechanism
125 	 */
126 	if (mechs && (*minor = __OID_to_OID_set(mechs, cntx->mech))) {
127 		Free(dh_cred);
128 		Free(netname);
129 		return (GSS_S_FAILURE);
130 	}
131 
132 	/* Register the credential */
133 	if ((*minor = __dh_install_cred(dh_cred)) != DH_SUCCESS) {
134 		Free(dh_cred);
135 		Free(netname);
136 		return (GSS_S_FAILURE);
137 	}
138 
139 	if (expire_rec)
140 		*expire_rec = expire_req ? expire_req : GSS_C_INDEFINITE;
141 
142 	/* Return the Diffie-Hellman credential through cred */
143 	*cred  = (gss_cred_id_t)dh_cred;
144 
145 	return (GSS_S_COMPLETE);
146 }
147 
148 
149 /*
150  * __dh_gss_add_cred is currently a no-op. All the work is done at the
151  * libgss layer. That layer will invoke the mechanism specific gss_acquire_cred
152  * routine. This entry point should never be called. The entry point for
153  * this routine is set to NULL in dhmech.c.
154  */
155 
156 /*
157  * OM_uint32
158  * __dh_gss_add_cred(void * ctx, OM_uint32 *minor, gss_cred_id_t cred_in,
159  *    gss_name_t name, gss_OID mech, gss_cred_usage_t usage,
160  *   OM_uint32 init_time_req, OM_uint32 accep_time_req,
161  *   gss_cred_id_t *cred_out, gss_OID_set *mechs,
162  *   OM_uint32 *init_time_rec, OM_uint32 *accep_time_rec)
163  * {
164  *	return (GSS_S_UNAVAILABLE);
165  * }
166  */
167 
168 /*
169  * __dh_gss_inquire_cred: Return tracked state of the supplied credential.
170  */
171 OM_uint32
__dh_gss_inquire_cred(void * ctx,OM_uint32 * minor,gss_cred_id_t cred,gss_name_t * name,OM_uint32 * lifetime,gss_cred_usage_t * usage,gss_OID_set * mechs)172 __dh_gss_inquire_cred(void *ctx, /* Per mechanism context */
173 		    OM_uint32 *minor, /* Mechanism status */
174 		    gss_cred_id_t cred, /* cred of interest */
175 		    gss_name_t *name, /* name of principal */
176 		    OM_uint32 *lifetime, /* return the time remainning */
177 		    gss_cred_usage_t *usage, /* usage: init, accept, both */
178 		    gss_OID_set *mechs /* Set containing mech_dh */)
179 {
180 	/* cred is a Diffie-Hellman credential */
181 	dh_cred_id_t crid = (dh_cred_id_t)cred;
182 	/* ctx is a Diffie-Hellman context */
183 	dh_context_t cntx = (dh_context_t)ctx;
184 	OM_uint32 t = GSS_C_INDEFINITE;
185 
186 	if (minor == 0)
187 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
188 	if (cntx == 0)
189 		return (GSS_S_CALL_INACCESSIBLE_READ);
190 
191 	*minor = DH_SUCCESS;
192 
193 	/* Default case */
194 	if (cred == GSS_C_NO_CREDENTIAL) {
195 		if (!(*cntx->keyopts->key_secretkey_is_set)())
196 			return (GSS_S_NO_CRED);
197 		if (name)
198 			*name = (gss_name_t)(*cntx->keyopts->get_principal)();
199 		if (lifetime)
200 			*lifetime = GSS_C_INDEFINITE;
201 		if (usage)
202 			*usage = GSS_C_BOTH;
203 	} else {
204 		/* Validate creditial */
205 		if ((*minor = __dh_validate_cred(crid)) != DH_SUCCESS)
206 			return (GSS_S_DEFECTIVE_CREDENTIAL);
207 		if (name)
208 			*name = (gss_name_t)strdup(crid->principal);
209 		if (lifetime) {
210 			if (crid->expire == GSS_C_INDEFINITE)
211 				*lifetime = GSS_C_INDEFINITE;
212 			else {
213 				time_t now = time(0);
214 				t = crid->expire > now ? crid->expire-now : 0;
215 				*lifetime = t;
216 			}
217 		}
218 		if (usage)
219 			*usage = crid->usage;
220 	}
221 
222 	if (name && *name == 0)
223 		return (GSS_S_FAILURE);
224 
225 
226 	if (mechs &&
227 	    (*minor = __OID_to_OID_set(mechs, cntx->mech)) != DH_SUCCESS) {
228 		free(name);
229 		return (GSS_S_FAILURE);
230 	}
231 
232 	/* Check if the credential is still valid */
233 	return (t ? GSS_S_COMPLETE : GSS_S_CREDENTIALS_EXPIRED);
234 }
235 
236 
237 /*
238  * __dh_gss_inquire_cred_by_mech: Return the information associated with
239  * cred and mech. Since we're a backend, mech must be our mech.
240  *
241  * We verify that passed in mech is correct and use the above routine
242  * to do the work.
243  */
244 OM_uint32
__dh_gss_inquire_cred_by_mech(void * ctx,OM_uint32 * minor,gss_cred_id_t cred,gss_OID mech,gss_name_t * name,OM_uint32 * init_time,OM_uint32 * accept_time,gss_cred_usage_t * usage)245 __dh_gss_inquire_cred_by_mech(void *ctx, /* Per mechananism context */
246 			    OM_uint32 *minor, /* Mechanism status */
247 			    gss_cred_id_t cred, /* Cred to iquire about */
248 			    gss_OID mech, /* Along with the mechanism */
249 			    gss_name_t *name, /* where to return principal */
250 			    OM_uint32 *init_time, /* Init time left */
251 			    OM_uint32 *accept_time, /* Accept time left */
252 			    gss_cred_usage_t *usage /* cred usage */)
253 {
254 	/* ctx is them Diffie-Hellman mechanism context */
255 	dh_context_t context = (dh_context_t)ctx;
256 	OM_uint32 lifetime;
257 	OM_uint32 major;
258 	gss_cred_usage_t use;
259 
260 	/* This should never happen. It would indicate a libgss failure */
261 	if (!__OID_equal(mech, context->mech)) {
262 		*minor = DH_BAD_CONTEXT;
263 		return (GSS_S_FAILURE);
264 	}
265 
266 	/* Fetch cred info */
267 	major = __dh_gss_inquire_cred(ctx, minor, cred, name,
268 				    &lifetime, &use, NULL);
269 
270 	/* Return option values */
271 	if (major == GSS_S_COMPLETE) {
272 		/* set init_time if we can */
273 		if (init_time)
274 			*init_time = (use == GSS_C_BOTH ||
275 				    use == GSS_C_INITIATE) ? lifetime : 0;
276 		/* Ditto for accept time */
277 		if (accept_time)
278 			*accept_time = (use == GSS_C_BOTH ||
279 					use == GSS_C_ACCEPT) ? lifetime : 0;
280 		if (usage)
281 			*usage = use;
282 	}
283 
284 	return (major);
285 }
286 
287 /*
288  * __dh_gss_release_cred: Release the resources associated with cred.
289  */
290 OM_uint32
__dh_gss_release_cred(void * ctx,OM_uint32 * minor,gss_cred_id_t * cred)291 __dh_gss_release_cred(void *ctx, /* Per mechananism context (not used) */
292 		    OM_uint32 *minor, /* Mechanism status */
293 		    gss_cred_id_t *cred /* The cred to free */)
294 {
295 _NOTE(ARGUNUSED(ctx))
296 	dh_cred_id_t dh_cred = (dh_cred_id_t)*cred;
297 
298 	/* Check that we can read and write required parameters */
299 	if (minor == 0 || cred == 0)
300 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
301 
302 	/* Nothing to do */
303 	if (*cred == GSS_C_NO_CREDENTIAL)
304 		return (GSS_S_COMPLETE);
305 
306 	/* Check if the credential is valid */
307 	if ((*minor = __dh_validate_cred(dh_cred)) != DH_SUCCESS)
308 		return (GSS_S_NO_CRED);
309 
310 	/* Unregister the credential */
311 	*minor = __dh_remove_cred(dh_cred);
312 
313 	/* Free the principal and the cred itself */
314 	Free(dh_cred->principal);
315 	Free(dh_cred);
316 
317 	/* Set cred to no credential */
318 	*cred = GSS_C_NO_CREDENTIAL;
319 
320 	return (GSS_S_COMPLETE);
321 }
322