Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Simple GSSAPI wrappers
5 : *
6 : * Copyright (c) 2012 Andreas Schneider <asn@samba.org>
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "gss_samba.h"
24 :
25 : #ifdef HAVE_GSSAPI
26 :
27 : #if !defined(HAVE_GSS_OID_EQUAL)
28 : int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid)
29 : {
30 : if (first_oid == GSS_C_NO_OID || second_oid == GSS_C_NO_OID) {
31 : return 0;
32 : }
33 :
34 : if (first_oid == second_oid) {
35 : return 1;
36 : }
37 :
38 : if ((first_oid)->length != (second_oid)->length) {
39 : return 0;
40 : }
41 :
42 : if (memcmp((first_oid)->elements, (second_oid)->elements,
43 : (first_oid)->length) == 0) {
44 : return 1;
45 : }
46 :
47 : return 0;
48 : }
49 : #endif /* !HAVE_GSS_OID_EQUAL */
50 :
51 : /* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
52 : * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
53 : * interposed by GSSPROXY while gss_krb5_import_cred() is not.
54 : *
55 : * This wrapper requires a proper krb5_context to resolve ccache name.
56 : * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
57 64632 : uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status,
58 : krb5_context ctx,
59 : krb5_ccache id,
60 : krb5_principal keytab_principal,
61 : krb5_keytab keytab,
62 : gss_cred_id_t *cred)
63 : {
64 64632 : return smb_gss_mech_import_cred(minor_status,
65 : ctx,
66 : id,
67 : keytab_principal,
68 : keytab,
69 : gss_mech_krb5,
70 : cred);
71 : }
72 :
73 68185 : uint32_t smb_gss_mech_import_cred(OM_uint32 *minor_status,
74 : krb5_context ctx,
75 : krb5_ccache id,
76 : krb5_principal keytab_principal,
77 : krb5_keytab keytab,
78 : const struct gss_OID_desc_struct *mech,
79 : gss_cred_id_t *cred)
80 : {
81 68185 : uint32_t major_status = 0;
82 :
83 : #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
84 18664 : uint32_t minor = 0;
85 18664 : gss_key_value_element_desc ccache_element = {
86 : .key = "ccache",
87 : .value = NULL,
88 : };
89 :
90 18664 : gss_key_value_element_desc keytab_element = {
91 : .key = "keytab",
92 : .value = NULL,
93 : };
94 :
95 : gss_key_value_element_desc elements[2];
96 :
97 18664 : gss_key_value_set_desc cred_store = {
98 : .elements = &ccache_element,
99 : .count = 1,
100 : };
101 :
102 : /* we are interested exclusively in krb5 credentials,
103 : * indicate to GSSAPI that we are not interested in any other
104 : * mechanism here */
105 18664 : gss_OID_set_desc mech_set = {
106 : .count = 1,
107 : .elements = discard_const_p(struct gss_OID_desc_struct,
108 : mech),
109 : };
110 :
111 18664 : gss_cred_usage_t cred_usage = GSS_C_INITIATE;
112 18664 : gss_name_t name = NULL;
113 18664 : gss_buffer_desc pr_name = {
114 : .value = NULL,
115 : .length = 0,
116 : };
117 :
118 18664 : if (id != NULL) {
119 4484 : major_status = krb5_cc_get_full_name(ctx,
120 : id,
121 : discard_const(&ccache_element.value));
122 4484 : if (major_status != 0) {
123 0 : return major_status;
124 : }
125 : }
126 :
127 18664 : if (keytab != NULL) {
128 14180 : keytab_element.value = malloc(4096);
129 14180 : if (!keytab_element.value) {
130 0 : return ENOMEM;
131 : }
132 28360 : major_status = krb5_kt_get_name(ctx,
133 : keytab,
134 14180 : discard_const(keytab_element.value), 4096);
135 14180 : if (major_status != 0) {
136 0 : free(discard_const(keytab_element.value));
137 0 : return major_status;
138 : }
139 14180 : cred_usage = GSS_C_ACCEPT;
140 14180 : cred_store.elements = &keytab_element;
141 :
142 14180 : if (keytab_principal != NULL) {
143 12422 : major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
144 12422 : if (major_status != 0) {
145 0 : free(discard_const(keytab_element.value));
146 0 : return major_status;
147 : }
148 12422 : pr_name.length = strlen(pr_name.value);
149 :
150 12422 : major_status = gss_import_name(minor_status,
151 : &pr_name,
152 : discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
153 : &name);
154 12422 : if (major_status != 0) {
155 0 : krb5_free_unparsed_name(ctx, pr_name.value);
156 0 : free(discard_const(keytab_element.value));
157 0 : return major_status;
158 : }
159 : }
160 : }
161 :
162 18664 : if (id != NULL && keytab != NULL) {
163 0 : elements[0] = ccache_element;
164 0 : elements[1] = keytab_element;
165 :
166 0 : cred_store.elements = elements;
167 0 : cred_store.count = 2;
168 0 : cred_usage = GSS_C_BOTH;
169 : }
170 :
171 18664 : major_status = gss_acquire_cred_from(minor_status,
172 : name,
173 : 0,
174 : &mech_set,
175 : cred_usage,
176 : &cred_store,
177 : cred,
178 : NULL,
179 : NULL);
180 :
181 18664 : if (pr_name.value != NULL) {
182 12422 : (void)gss_release_name(&minor, &name);
183 12422 : krb5_free_unparsed_name(ctx, pr_name.value);
184 : }
185 18664 : if (keytab_element.value != NULL) {
186 14180 : free(discard_const(keytab_element.value));
187 : }
188 18664 : krb5_free_string(ctx, discard_const(ccache_element.value));
189 : #else
190 49521 : major_status = gss_krb5_import_cred(minor_status,
191 : id,
192 : keytab_principal,
193 : keytab, cred);
194 :
195 49521 : if (major_status == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
196 0 : if ((keytab_principal == NULL) && (keytab != NULL)) {
197 : /* No principal was specified and MIT krb5 1.9 version failed.
198 : * We have to fall back to set global acceptor identity */
199 0 : gss_OID_set_desc mech_set;
200 0 : char *kt_name = NULL;
201 :
202 0 : kt_name = malloc(4096);
203 0 : if (!kt_name) {
204 0 : return ENOMEM;
205 : }
206 :
207 0 : major_status = krb5_kt_get_name(ctx,
208 : keytab,
209 : kt_name, 4096);
210 0 : if (major_status != 0) {
211 0 : free(kt_name);
212 0 : return major_status;
213 : }
214 :
215 0 : major_status = gsskrb5_register_acceptor_identity(kt_name);
216 0 : if (major_status) {
217 0 : free(kt_name);
218 0 : return major_status;
219 : }
220 :
221 : /* We are dealing with krb5 GSSAPI mech in this fallback */
222 0 : mech_set.count = 1;
223 0 : mech_set.elements =
224 : discard_const_p(struct gss_OID_desc_struct,
225 : gss_mech_krb5);
226 0 : major_status = gss_acquire_cred(minor_status,
227 : GSS_C_NO_NAME,
228 : GSS_C_INDEFINITE,
229 : &mech_set,
230 : GSS_C_ACCEPT,
231 : cred,
232 : NULL, NULL);
233 0 : free(kt_name);
234 : }
235 : }
236 : #endif
237 65409 : return major_status;
238 : }
239 :
240 :
241 : #endif /* HAVE_GSSAPI */
|