Line data Source code
1 : /*
2 : * Copyright (c) 2003 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
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 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "gsskrb5_locl.h"
35 :
36 0 : OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred_from (
37 : OM_uint32 *minor_status,
38 : gss_cred_id_t input_cred_handle,
39 : gss_const_name_t desired_name,
40 : const gss_OID desired_mech,
41 : gss_cred_usage_t cred_usage,
42 : OM_uint32 initiator_time_req,
43 : OM_uint32 acceptor_time_req,
44 : gss_const_key_value_set_t cred_store,
45 : gss_cred_id_t *output_cred_handle,
46 : gss_OID_set *actual_mechs,
47 : OM_uint32 *initiator_time_rec,
48 : OM_uint32 *acceptor_time_rec)
49 : {
50 0 : krb5_context context;
51 0 : OM_uint32 major, lifetime;
52 0 : gsskrb5_cred cred, handle;
53 0 : krb5_const_principal dname;
54 :
55 0 : handle = NULL;
56 0 : cred = (gsskrb5_cred)input_cred_handle;
57 0 : dname = (krb5_const_principal)desired_name;
58 :
59 0 : if (cred == NULL && output_cred_handle == NULL) {
60 0 : *minor_status = EINVAL;
61 0 : return GSS_S_CALL_INACCESSIBLE_WRITE;
62 : }
63 :
64 0 : GSSAPI_KRB5_INIT (&context);
65 :
66 0 : if (desired_mech != GSS_C_NO_OID &&
67 0 : gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) {
68 0 : *minor_status = 0;
69 0 : return GSS_S_BAD_MECH;
70 : }
71 :
72 0 : if (cred == NULL) {
73 : /*
74 : * Acquire a credential; output_cred_handle can't be NULL, see above.
75 : */
76 0 : heim_assert(output_cred_handle != NULL,
77 : "internal error in _gsskrb5_add_cred()");
78 :
79 0 : major = _gsskrb5_acquire_cred_from(minor_status, desired_name,
80 : min(initiator_time_req,
81 : acceptor_time_req),
82 : GSS_C_NO_OID_SET,
83 : cred_usage,
84 : cred_store,
85 : output_cred_handle,
86 : actual_mechs, &lifetime);
87 0 : if (major != GSS_S_COMPLETE)
88 0 : goto failure;
89 :
90 : } else {
91 : /*
92 : * Check that we're done or copy input to output if
93 : * output_cred_handle != NULL.
94 : */
95 :
96 0 : HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
97 :
98 : /* Check if requested output usage is compatible with output usage */
99 0 : if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) {
100 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
101 0 : *minor_status = GSS_KRB5_S_G_BAD_USAGE;
102 0 : return(GSS_S_FAILURE);
103 : }
104 :
105 : /* Check that we have the same name */
106 0 : if (dname != NULL &&
107 0 : krb5_principal_compare(context, dname,
108 0 : cred->principal) != FALSE) {
109 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
110 0 : *minor_status = 0;
111 0 : return GSS_S_BAD_NAME;
112 : }
113 :
114 0 : if (output_cred_handle == NULL) {
115 : /*
116 : * This case is basically useless as we implement a single
117 : * mechanism here, so we can't add elements to the
118 : * input_cred_handle.
119 : */
120 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
121 0 : *minor_status = 0;
122 0 : return GSS_S_COMPLETE;
123 : }
124 :
125 : /*
126 : * Copy input to output -- this works as if we were a
127 : * GSS_Duplicate_cred() for one mechanism element.
128 : */
129 :
130 0 : handle = calloc(1, sizeof(*handle));
131 0 : if (handle == NULL) {
132 0 : if (cred != NULL)
133 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
134 0 : *minor_status = ENOMEM;
135 0 : return (GSS_S_FAILURE);
136 : }
137 :
138 0 : handle->usage = cred_usage;
139 0 : handle->endtime = cred->endtime;
140 0 : handle->principal = NULL;
141 0 : handle->destination_realm = NULL;
142 0 : handle->keytab = NULL;
143 0 : handle->ccache = NULL;
144 0 : handle->mechanisms = NULL;
145 0 : HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
146 :
147 0 : major = GSS_S_FAILURE;
148 :
149 0 : *minor_status = krb5_copy_principal(context, cred->principal,
150 : &handle->principal);
151 0 : if (*minor_status) {
152 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
153 0 : free(handle);
154 0 : return GSS_S_FAILURE;
155 : }
156 :
157 0 : if (cred->keytab) {
158 0 : char *name = NULL;
159 :
160 0 : *minor_status = krb5_kt_get_full_name(context, cred->keytab,
161 : &name);
162 0 : if (*minor_status)
163 0 : goto failure;
164 :
165 0 : *minor_status = krb5_kt_resolve(context, name, &handle->keytab);
166 0 : krb5_xfree(name);
167 0 : if (*minor_status)
168 0 : goto failure;
169 : }
170 :
171 0 : if (cred->ccache) {
172 0 : const char *type, *name;
173 0 : char *type_name = NULL;
174 :
175 0 : type = krb5_cc_get_type(context, cred->ccache);
176 0 : if (type == NULL){
177 0 : *minor_status = ENOMEM;
178 0 : goto failure;
179 : }
180 :
181 0 : if (strcmp(type, "MEMORY") == 0) {
182 0 : *minor_status = krb5_cc_new_unique(context, type,
183 0 : NULL, &handle->ccache);
184 0 : if (*minor_status)
185 0 : goto failure;
186 :
187 0 : *minor_status = krb5_cc_copy_cache(context, cred->ccache,
188 : handle->ccache);
189 0 : if (*minor_status)
190 0 : goto failure;
191 :
192 : } else {
193 0 : name = krb5_cc_get_name(context, cred->ccache);
194 0 : if (name == NULL) {
195 0 : *minor_status = ENOMEM;
196 0 : goto failure;
197 : }
198 :
199 0 : if (asprintf(&type_name, "%s:%s", type, name) == -1 ||
200 0 : type_name == NULL) {
201 0 : *minor_status = ENOMEM;
202 0 : goto failure;
203 : }
204 :
205 0 : *minor_status = krb5_cc_resolve(context, type_name,
206 0 : &handle->ccache);
207 0 : free(type_name);
208 0 : if (*minor_status)
209 0 : goto failure;
210 : }
211 : }
212 0 : major = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
213 0 : if (major != GSS_S_COMPLETE)
214 0 : goto failure;
215 :
216 0 : major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
217 : &handle->mechanisms);
218 0 : if (major != GSS_S_COMPLETE)
219 0 : goto failure;
220 :
221 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
222 :
223 0 : major = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred,
224 : NULL, &lifetime, NULL, actual_mechs);
225 0 : if (major != GSS_S_COMPLETE)
226 0 : goto failure;
227 :
228 0 : *output_cred_handle = (gss_cred_id_t)handle;
229 : }
230 :
231 0 : if (initiator_time_rec)
232 0 : *initiator_time_rec = lifetime;
233 0 : if (acceptor_time_rec)
234 0 : *acceptor_time_rec = lifetime;
235 :
236 0 : *minor_status = 0;
237 0 : return major;
238 :
239 0 : failure:
240 0 : if (handle) {
241 0 : if (handle->principal)
242 0 : krb5_free_principal(context, handle->principal);
243 0 : if (handle->keytab)
244 0 : krb5_kt_close(context, handle->keytab);
245 0 : if (handle->ccache)
246 0 : krb5_cc_destroy(context, handle->ccache);
247 0 : if (handle->mechanisms)
248 0 : gss_release_oid_set(NULL, &handle->mechanisms);
249 0 : free(handle);
250 : }
251 0 : if (cred && output_cred_handle)
252 0 : HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
253 0 : return major;
254 : }
|