1
2/*
3 * Copyright (c) 2004, PADL Software Pty Ltd.
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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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
36static OM_uint32
37import_cred(OM_uint32 *minor_status,
38	    krb5_context context,
39            gss_cred_id_t *cred_handle,
40            const gss_buffer_t value)
41{
42    OM_uint32 major_stat;
43    krb5_error_code ret;
44    krb5_principal keytab_principal = NULL;
45    krb5_keytab keytab = NULL;
46    krb5_storage *sp = NULL;
47    krb5_ccache id = NULL;
48    char *str;
49
50    if (cred_handle == NULL || *cred_handle != GSS_C_NO_CREDENTIAL) {
51	*minor_status = 0;
52	return GSS_S_FAILURE;
53    }
54
55    sp = krb5_storage_from_mem(value->value, value->length);
56    if (sp == NULL) {
57	*minor_status = 0;
58	return GSS_S_FAILURE;
59    }
60
61    /* credential cache name */
62    ret = krb5_ret_string(sp, &str);
63    if (ret) {
64	*minor_status = ret;
65	major_stat =  GSS_S_FAILURE;
66	goto out;
67    }
68    if (str[0]) {
69	ret = krb5_cc_resolve(context, str, &id);
70	if (ret) {
71	    *minor_status = ret;
72	    major_stat =  GSS_S_FAILURE;
73	    goto out;
74	}
75    }
76    free(str);
77    str = NULL;
78
79    /* keytab principal name */
80    ret = krb5_ret_string(sp, &str);
81    if (ret == 0 && str[0])
82	ret = krb5_parse_name(context, str, &keytab_principal);
83    if (ret) {
84	*minor_status = ret;
85	major_stat = GSS_S_FAILURE;
86	goto out;
87    }
88    free(str);
89    str = NULL;
90
91    /* keytab principal */
92    ret = krb5_ret_string(sp, &str);
93    if (ret) {
94	*minor_status = ret;
95	major_stat =  GSS_S_FAILURE;
96	goto out;
97    }
98    if (str[0]) {
99	ret = krb5_kt_resolve(context, str, &keytab);
100	if (ret) {
101	    *minor_status = ret;
102	    major_stat =  GSS_S_FAILURE;
103	    goto out;
104	}
105    }
106    free(str);
107    str = NULL;
108
109    major_stat = _gsskrb5_krb5_import_cred(minor_status, id, keytab_principal,
110					   keytab, cred_handle);
111out:
112    if (id)
113	krb5_cc_close(context, id);
114    if (keytab_principal)
115	krb5_free_principal(context, keytab_principal);
116    if (keytab)
117	krb5_kt_close(context, keytab);
118    if (str)
119	free(str);
120    if (sp)
121	krb5_storage_free(sp);
122
123    return major_stat;
124}
125
126
127static OM_uint32
128allowed_enctypes(OM_uint32 *minor_status,
129		 krb5_context context,
130		 gss_cred_id_t *cred_handle,
131		 const gss_buffer_t value)
132{
133    OM_uint32 major_stat;
134    krb5_error_code ret;
135    size_t len, i, j;
136    krb5_enctype *enctypes = NULL;
137    krb5_storage *sp = NULL;
138    gsskrb5_cred cred;
139
140    if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) {
141	*minor_status = 0;
142	return GSS_S_FAILURE;
143    }
144
145    cred = (gsskrb5_cred)*cred_handle;
146
147    if ((value->length % 4) != 0) {
148	*minor_status = 0;
149	major_stat = GSS_S_FAILURE;
150	goto out;
151    }
152
153    len = value->length / 4;
154    enctypes = malloc((len + 1) * 4);
155    if (enctypes == NULL) {
156	*minor_status = ENOMEM;
157	major_stat = GSS_S_FAILURE;
158	goto out;
159    }
160
161    sp = krb5_storage_from_mem(value->value, value->length);
162    if (sp == NULL) {
163	*minor_status = ENOMEM;
164	major_stat = GSS_S_FAILURE;
165	goto out;
166    }
167
168    for (j = 0, i = 0; i < len; i++) {
169	uint32_t e;
170
171	ret = krb5_ret_uint32(sp, &e);
172	if (ret) {
173	    *minor_status = ret;
174	    major_stat =  GSS_S_FAILURE;
175	    goto out;
176	}
177	if (krb5_enctype_valid(context, e) == 0)
178	    enctypes[j++] = e;
179    }
180    enctypes[j++] = 0;
181
182    if (cred->enctypes)
183	free(cred->enctypes);
184    cred->enctypes = enctypes;
185
186    krb5_storage_free(sp);
187
188    return GSS_S_COMPLETE;
189
190out:
191    if (sp)
192	krb5_storage_free(sp);
193    if (enctypes)
194	free(enctypes);
195
196    return major_stat;
197}
198
199static OM_uint32
200no_ci_flags(OM_uint32 *minor_status,
201	    krb5_context context,
202	    gss_cred_id_t *cred_handle,
203	    const gss_buffer_t value)
204{
205    gsskrb5_cred cred;
206
207    if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) {
208	*minor_status = 0;
209	return GSS_S_FAILURE;
210    }
211
212    cred = (gsskrb5_cred)*cred_handle;
213    cred->cred_flags |= GSS_CF_NO_CI_FLAGS;
214
215    *minor_status = 0;
216    return GSS_S_COMPLETE;
217
218}
219
220OM_uint32 GSSAPI_CALLCONV
221_gsskrb5_set_cred_option
222           (OM_uint32 *minor_status,
223            gss_cred_id_t *cred_handle,
224            const gss_OID desired_object,
225            const gss_buffer_t value)
226{
227    krb5_context context;
228
229    GSSAPI_KRB5_INIT (&context);
230
231    if (value == GSS_C_NO_BUFFER) {
232	*minor_status = EINVAL;
233	return GSS_S_FAILURE;
234    }
235
236    if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_CRED_X))
237	return import_cred(minor_status, context, cred_handle, value);
238
239    if (gss_oid_equal(desired_object, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X))
240	return allowed_enctypes(minor_status, context, cred_handle, value);
241
242    if (gss_oid_equal(desired_object, GSS_KRB5_CRED_NO_CI_FLAGS_X))
243	return no_ci_flags(minor_status, context, cred_handle, value);
244
245    *minor_status = EINVAL;
246    return GSS_S_FAILURE;
247}
248