1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/krb5/store_cred.c */
3 /*
4 * Copyright 2009 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-int.h"
28 #include "gssapiP_krb5.h"
29
30 static int
has_unexpired_creds(krb5_gss_cred_id_t kcred,const gss_OID desired_mech,int default_cred,gss_const_key_value_set_t cred_store)31 has_unexpired_creds(krb5_gss_cred_id_t kcred,
32 const gss_OID desired_mech,
33 int default_cred,
34 gss_const_key_value_set_t cred_store)
35 {
36 OM_uint32 major_status, minor;
37 gss_name_t cred_name;
38 gss_OID_set_desc desired_mechs;
39 gss_cred_id_t tmp_cred = GSS_C_NO_CREDENTIAL;
40 OM_uint32 time_rec;
41
42 desired_mechs.count = 1;
43 desired_mechs.elements = (gss_OID)desired_mech;
44
45 if (default_cred)
46 cred_name = GSS_C_NO_NAME;
47 else
48 cred_name = (gss_name_t)kcred->name;
49
50 major_status = krb5_gss_acquire_cred_from(&minor, cred_name, 0,
51 &desired_mechs, GSS_C_INITIATE,
52 cred_store, &tmp_cred, NULL,
53 &time_rec);
54
55 krb5_gss_release_cred(&minor, &tmp_cred);
56
57 return (GSS_ERROR(major_status) || time_rec);
58 }
59
60 static OM_uint32
copy_initiator_creds(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store)61 copy_initiator_creds(OM_uint32 *minor_status,
62 gss_cred_id_t input_cred_handle,
63 const gss_OID desired_mech,
64 OM_uint32 overwrite_cred,
65 OM_uint32 default_cred,
66 gss_const_key_value_set_t cred_store)
67 {
68 OM_uint32 major_status;
69 krb5_error_code code;
70 krb5_gss_cred_id_t kcred = NULL;
71 krb5_context context = NULL;
72 krb5_ccache ccache = NULL;
73 const char *ccache_name;
74
75 *minor_status = 0;
76
77 if (!default_cred && cred_store == GSS_C_NO_CRED_STORE) {
78 *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
79 major_status = GSS_S_FAILURE;
80 goto cleanup;
81 }
82
83 code = krb5_gss_init_context(&context);
84 if (code != 0) {
85 *minor_status = code;
86 major_status = GSS_S_FAILURE;
87 goto cleanup;
88 }
89
90 major_status = krb5_gss_validate_cred_1(minor_status,
91 input_cred_handle,
92 context);
93 if (GSS_ERROR(major_status))
94 goto cleanup;
95
96 kcred = (krb5_gss_cred_id_t)input_cred_handle;
97
98 if (kcred->ccache == NULL) {
99 *minor_status = KG_CCACHE_NOMATCH;
100 major_status = GSS_S_DEFECTIVE_CREDENTIAL;
101 goto cleanup;
102 }
103
104 if (!overwrite_cred &&
105 has_unexpired_creds(kcred, desired_mech, default_cred, cred_store)) {
106 major_status = GSS_S_DUPLICATE_ELEMENT;
107 goto cleanup;
108 }
109
110 major_status = kg_value_from_cred_store(cred_store,
111 KRB5_CS_CCACHE_URN, &ccache_name);
112 if (GSS_ERROR(major_status))
113 goto cleanup;
114
115 if (ccache_name != NULL) {
116 code = krb5_cc_resolve(context, ccache_name, &ccache);
117 if (code != 0) {
118 *minor_status = code;
119 major_status = GSS_S_FAILURE;
120 goto cleanup;
121 }
122 code = krb5_cc_initialize(context, ccache,
123 kcred->name->princ);
124 if (code != 0) {
125 *minor_status = code;
126 major_status = GSS_S_FAILURE;
127 goto cleanup;
128 }
129 }
130
131 if (ccache == NULL) {
132 if (!default_cred) {
133 *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
134 major_status = GSS_S_FAILURE;
135 goto cleanup;
136 }
137 code = krb5int_cc_default(context, &ccache);
138 if (code != 0) {
139 *minor_status = code;
140 major_status = GSS_S_FAILURE;
141 goto cleanup;
142 }
143 }
144
145 code = krb5_cc_copy_creds(context, kcred->ccache, ccache);
146 if (code != 0) {
147 *minor_status = code;
148 major_status = GSS_S_FAILURE;
149 goto cleanup;
150 }
151
152 *minor_status = 0;
153 major_status = GSS_S_COMPLETE;
154
155 cleanup:
156 if (kcred != NULL)
157 k5_mutex_unlock(&kcred->lock);
158 if (ccache != NULL)
159 krb5_cc_close(context, ccache);
160 krb5_free_context(context);
161
162 return major_status;
163 }
164
165 OM_uint32 KRB5_CALLCONV
krb5_gss_store_cred(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)166 krb5_gss_store_cred(OM_uint32 *minor_status,
167 gss_cred_id_t input_cred_handle,
168 gss_cred_usage_t cred_usage,
169 const gss_OID desired_mech,
170 OM_uint32 overwrite_cred,
171 OM_uint32 default_cred,
172 gss_OID_set *elements_stored,
173 gss_cred_usage_t *cred_usage_stored)
174 {
175 return krb5_gss_store_cred_into(minor_status, input_cred_handle,
176 cred_usage, desired_mech,
177 overwrite_cred, default_cred,
178 GSS_C_NO_CRED_STORE,
179 elements_stored, cred_usage_stored);
180 }
181
182 OM_uint32 KRB5_CALLCONV
krb5_gss_store_cred_into(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)183 krb5_gss_store_cred_into(OM_uint32 *minor_status,
184 gss_cred_id_t input_cred_handle,
185 gss_cred_usage_t cred_usage,
186 const gss_OID desired_mech,
187 OM_uint32 overwrite_cred,
188 OM_uint32 default_cred,
189 gss_const_key_value_set_t cred_store,
190 gss_OID_set *elements_stored,
191 gss_cred_usage_t *cred_usage_stored)
192 {
193 OM_uint32 major_status;
194 gss_cred_usage_t actual_usage;
195 OM_uint32 lifetime;
196
197 if (input_cred_handle == GSS_C_NO_CREDENTIAL)
198 return GSS_S_NO_CRED;
199
200 major_status = GSS_S_FAILURE;
201
202 if (cred_usage == GSS_C_ACCEPT) {
203 *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
204 return GSS_S_FAILURE;
205 } else if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
206 *minor_status = G_BAD_USAGE;
207 return GSS_S_FAILURE;
208 }
209
210 major_status = krb5_gss_inquire_cred(minor_status, input_cred_handle,
211 NULL, &lifetime,
212 &actual_usage, elements_stored);
213 if (GSS_ERROR(major_status))
214 return major_status;
215
216 if (lifetime == 0)
217 return GSS_S_CREDENTIALS_EXPIRED;
218
219 if (actual_usage != GSS_C_INITIATE && actual_usage != GSS_C_BOTH) {
220 *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
221 return GSS_S_FAILURE;
222 }
223
224 major_status = copy_initiator_creds(minor_status, input_cred_handle,
225 desired_mech, overwrite_cred,
226 default_cred, cred_store);
227 if (GSS_ERROR(major_status))
228 return major_status;
229
230 if (cred_usage_stored != NULL)
231 *cred_usage_stored = GSS_C_INITIATE;
232
233 return GSS_S_COMPLETE;
234 }
235