2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
5 * Copyright 2000 by the Massachusetts Institute of Technology.
8 * Export of this software from the United States of America may
9 * require a specific license from the United States Government.
10 * It is the responsibility of any person or organization contemplating
11 * export to obtain such a license before exporting.
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission. Furthermore if you modify this software you must label
21 * your software as modified software and not distribute it in such a
22 * fashion that it might be confused with the original M.I.T. software.
23 * M.I.T. makes no representations about the suitability of
24 * this software for any purpose. It is provided "as is" without express
25 * or implied warranty.
29 * Copyright (C) 1998 by the FundsXpress, INC.
31 * All rights reserved.
33 * Export of this software from the United States of America may require
34 * a specific license from the United States Government. It is the
35 * responsibility of any person or organization contemplating export to
36 * obtain such a license before exporting.
38 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39 * distribute this software and its documentation for any purpose and
40 * without fee is hereby granted, provided that the above copyright
41 * notice appear in all copies and that both that copyright notice and
42 * this permission notice appear in supporting documentation, and that
43 * the name of FundsXpress. not be used in advertising or publicity pertaining
44 * to distribution of the software without specific, written prior
45 * permission. FundsXpress makes no representations about the suitability of
46 * this software for any purpose. It is provided "as is" without express
47 * or implied warranty.
49 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
50 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
51 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
54 #include "gssapiP_krb5.h"
60 #include <locale.h> /* Solaris Kerberos */
63 * $Id: add_cred.c 18396 2006-07-25 20:29:43Z lxs $
68 krb5_gss_add_cred(minor_status
, input_cred_handle
,
69 desired_name
, desired_mech
, cred_usage
,
70 initiator_time_req
, acceptor_time_req
,
71 output_cred_handle
, actual_mechs
,
72 initiator_time_rec
, acceptor_time_rec
)
73 OM_uint32
*minor_status
;
74 gss_cred_id_t input_cred_handle
;
75 gss_name_t desired_name
;
77 gss_cred_usage_t cred_usage
;
78 OM_uint32 initiator_time_req
;
79 OM_uint32 acceptor_time_req
;
80 gss_cred_id_t
*output_cred_handle
;
81 gss_OID_set
*actual_mechs
;
82 OM_uint32
*initiator_time_rec
;
83 OM_uint32
*acceptor_time_rec
;
86 OM_uint32 major_status
, lifetime
;
87 krb5_gss_cred_id_t cred
;
90 /* this is pretty simple, since there's not really any difference
91 between the underlying mechanisms. The main hair is in copying
92 a mechanism if requested. */
94 /* check if the desired_mech is bogus */
96 if (!g_OID_equal(desired_mech
, gss_mech_krb5
) &&
97 !g_OID_equal(desired_mech
, gss_mech_krb5_old
)) {
99 return(GSS_S_BAD_MECH
);
102 /* check if the desired_mech is bogus */
104 if ((cred_usage
!= GSS_C_INITIATE
) &&
105 (cred_usage
!= GSS_C_ACCEPT
) &&
106 (cred_usage
!= GSS_C_BOTH
)) {
107 *minor_status
= (OM_uint32
) G_BAD_USAGE
;
108 return(GSS_S_FAILURE
);
111 /* since the default credential includes all the mechanisms,
112 return an error for that case. */
115 if (input_cred_handle
== GSS_C_NO_CREDENTIAL
) {
117 return(GSS_S_DUPLICATE_ELEMENT
);
120 code
= krb5_gss_init_context(&context
);
122 *minor_status
= code
;
123 return GSS_S_FAILURE
;
126 major_status
= krb5_gss_validate_cred_1(minor_status
, input_cred_handle
,
128 if (GSS_ERROR(major_status
)) {
129 save_error_info(*minor_status
, context
);
130 krb5_free_context(context
);
134 cred
= (krb5_gss_cred_id_t
) input_cred_handle
;
135 k5_mutex_assert_locked(&cred
->lock
);
137 /* check if the cred_usage is equal or "less" than the passed-in cred
140 if (!((cred
->usage
== cred_usage
) ||
141 ((cred
->usage
== GSS_C_BOTH
) &&
142 (output_cred_handle
!= NULL
)))) {
143 *minor_status
= (OM_uint32
) G_BAD_USAGE
;
144 krb5_free_context(context
);
145 return(GSS_S_FAILURE
);
148 /* check that desired_mech isn't already in the credential */
150 if ((g_OID_equal(desired_mech
, gss_mech_krb5_old
) && cred
->prerfc_mech
) ||
151 (g_OID_equal(desired_mech
, gss_mech_krb5
) && cred
->rfc_mech
)) {
153 krb5_free_context(context
);
154 return(GSS_S_DUPLICATE_ELEMENT
);
157 if (GSS_ERROR(kg_sync_ccache_name(context
, minor_status
))) {
158 save_error_info(*minor_status
, context
);
159 krb5_free_context(context
);
160 return GSS_S_FAILURE
;
163 /* verify the desired_name */
166 if ((desired_name
!= (gss_name_t
) NULL
) &&
167 (! kg_validate_name(desired_name
))) {
168 *minor_status
= (OM_uint32
) G_VALIDATE_FAILED
;
169 krb5_free_context(context
);
170 return(GSS_S_CALL_BAD_STRUCTURE
|GSS_S_BAD_NAME
);
173 /* make sure the desired_name is the same as the existing one */
176 !krb5_principal_compare(context
, (krb5_principal
) desired_name
,
178 /* Solaris Kerberos: spruce-up the err msg */
179 krb5_principal dname
= (krb5_principal
) desired_name
;
180 char *s_name
= NULL
, *s_princ
= NULL
;
181 int kret
= krb5_unparse_name(context
, dname
, &s_name
);
182 int kret1
= krb5_unparse_name(context
, cred
->princ
, &s_princ
);
183 *minor_status
= (OM_uint32
) G_BAD_USAGE
;
184 if (kret
== 0 && kret1
== 0) {
185 krb5_set_error_message(context
, *minor_status
,
186 dgettext(TEXT_DOMAIN
,
187 "Desired name principal '%s' does not match '%s'"),
189 save_error_info(*minor_status
, context
);
192 krb5_free_unparsed_name(context
, s_name
);
194 krb5_free_unparsed_name(context
, s_princ
);
196 krb5_free_context(context
);
197 return(GSS_S_BAD_NAME
);
200 /* copy the cred if necessary */
202 if (output_cred_handle
) {
204 krb5_gss_cred_id_t new_cred
;
205 char *kttype
, ktboth
[1024];
206 const char *cctype
, *ccname
;
210 (krb5_gss_cred_id_t
) xmalloc(sizeof(krb5_gss_cred_id_rec
)))
212 *minor_status
= ENOMEM
;
213 krb5_free_context(context
);
214 return(GSS_S_FAILURE
);
216 memset(new_cred
, 0, sizeof(krb5_gss_cred_id_rec
));
218 new_cred
->usage
= cred_usage
;
219 new_cred
->prerfc_mech
= cred
->prerfc_mech
;
220 new_cred
->rfc_mech
= cred
->rfc_mech
;
221 new_cred
->tgt_expire
= cred
->tgt_expire
;
224 code
= krb5_copy_principal(context
, cred
->princ
, &new_cred
->princ
);
228 *minor_status
= code
;
229 save_error_info(*minor_status
, context
);
230 krb5_free_context(context
);
231 return(GSS_S_FAILURE
);
235 kttype
= krb5_kt_get_type(context
, cred
->keytab
);
236 if ((strlen(kttype
)+2) > sizeof(ktboth
)) {
238 krb5_free_principal(context
, new_cred
->princ
);
241 *minor_status
= ENOMEM
;
242 krb5_free_context(context
);
243 return(GSS_S_FAILURE
);
246 strncpy(ktboth
, kttype
, sizeof(ktboth
) - 1);
247 ktboth
[sizeof(ktboth
) - 1] = '\0';
248 strncat(ktboth
, ":", sizeof(ktboth
) - 1 - strlen(ktboth
));
250 code
= krb5_kt_get_name(context
, cred
->keytab
,
251 ktboth
+strlen(ktboth
),
252 sizeof(ktboth
)-strlen(ktboth
));
255 krb5_free_principal(context
, new_cred
->princ
);
258 *minor_status
= code
;
259 save_error_info(*minor_status
, context
);
260 krb5_free_context(context
);
261 return(GSS_S_FAILURE
);
264 code
= krb5_kt_resolve(context
, ktboth
, &new_cred
->keytab
);
267 krb5_free_principal(context
, new_cred
->princ
);
270 *minor_status
= code
;
271 save_error_info(*minor_status
, context
);
272 krb5_free_context(context
);
273 return(GSS_S_FAILURE
);
276 new_cred
->keytab
= NULL
;
280 /* Open the replay cache for this principal. */
281 if ((code
= krb5_get_server_rcache(context
,
282 krb5_princ_component(context
, cred
->princ
, 0),
283 &new_cred
->rcache
))) {
284 if (new_cred
->keytab
)
285 krb5_kt_close(context
, new_cred
->keytab
);
287 krb5_free_principal(context
, new_cred
->princ
);
290 *minor_status
= code
;
291 save_error_info(*minor_status
, context
);
292 krb5_free_context(context
);
293 return(GSS_S_FAILURE
);
296 new_cred
->rcache
= NULL
;
300 cctype
= krb5_cc_get_type(context
, cred
->ccache
);
301 ccname
= krb5_cc_get_name(context
, cred
->ccache
);
303 if ((strlen(cctype
)+strlen(ccname
)+2) > sizeof(ccboth
)) {
304 if (new_cred
->rcache
)
305 krb5_rc_close(context
, new_cred
->rcache
);
306 if (new_cred
->keytab
)
307 krb5_kt_close(context
, new_cred
->keytab
);
309 krb5_free_principal(context
, new_cred
->princ
);
312 krb5_free_context(context
);
313 *minor_status
= ENOMEM
;
314 return(GSS_S_FAILURE
);
317 strncpy(ccboth
, cctype
, sizeof(ccboth
) - 1);
318 ccboth
[sizeof(ccboth
) - 1] = '\0';
319 strncat(ccboth
, ":", sizeof(ccboth
) - 1 - strlen(ccboth
));
320 strncat(ccboth
, ccname
, sizeof(ccboth
) - 1 - strlen(ccboth
));
322 code
= krb5_cc_resolve(context
, ccboth
, &new_cred
->ccache
);
324 if (new_cred
->rcache
)
325 krb5_rc_close(context
, new_cred
->rcache
);
326 if (new_cred
->keytab
)
327 krb5_kt_close(context
, new_cred
->keytab
);
329 krb5_free_principal(context
, new_cred
->princ
);
331 *minor_status
= code
;
332 save_error_info(*minor_status
, context
);
333 krb5_free_context(context
);
334 return(GSS_S_FAILURE
);
337 new_cred
->ccache
= NULL
;
340 /* intern the credential handle */
342 if (! kg_save_cred_id((gss_cred_id_t
) new_cred
)) {
343 if (new_cred
->ccache
)
344 krb5_cc_close(context
, new_cred
->ccache
);
345 if (new_cred
->rcache
)
346 krb5_rc_close(context
, new_cred
->rcache
);
347 if (new_cred
->keytab
)
348 krb5_kt_close(context
, new_cred
->keytab
);
350 krb5_free_principal(context
, new_cred
->princ
);
352 krb5_free_context(context
);
354 *minor_status
= (OM_uint32
) G_VALIDATE_FAILED
;
355 return(GSS_S_FAILURE
);
358 /* modify new_cred */
363 /* set the flag for the new mechanism */
365 if (g_OID_equal(desired_mech
, gss_mech_krb5_old
))
366 cred
->prerfc_mech
= 1;
367 else if (g_OID_equal(desired_mech
, gss_mech_krb5
))
370 /* set the outputs */
372 if (GSS_ERROR(major_status
= krb5_gss_inquire_cred(minor_status
,
375 NULL
, actual_mechs
))) {
378 if (output_cred_handle
)
379 (void) krb5_gss_release_cred(&dummy
, (gss_cred_id_t
*) &cred
);
380 krb5_free_context(context
);
382 return(major_status
);
385 if (initiator_time_rec
)
386 *initiator_time_rec
= lifetime
;
387 if (acceptor_time_rec
)
388 *acceptor_time_rec
= lifetime
;
390 if (output_cred_handle
)
391 *output_cred_handle
= (gss_cred_id_t
)cred
;
393 krb5_free_context(context
);
395 return(GSS_S_COMPLETE
);