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 :
52 : /* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
53 : * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
54 : * interposed by GSSPROXY while gss_krb5_import_cred() is not.
55 : *
56 : * This wrapper requires a proper krb5_context to resolve ccache name.
57 : * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
58 80962 : uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
59 : krb5_ccache id, krb5_principal keytab_principal,
60 : krb5_keytab keytab, gss_cred_id_t *cred)
61 : {
62 80962 : uint32_t major_status = 0;
63 :
64 : #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
65 19019 : uint32_t minor = 0;
66 19019 : gss_key_value_element_desc ccache_element = {
67 : .key = "ccache",
68 : .value = NULL,
69 : };
70 :
71 19019 : gss_key_value_element_desc keytab_element = {
72 : .key = "keytab",
73 : .value = NULL,
74 : };
75 :
76 : gss_key_value_element_desc elements[2];
77 :
78 19019 : gss_key_value_set_desc cred_store = {
79 : .elements = &ccache_element,
80 : .count = 1,
81 : };
82 :
83 : /* we are interested exclusively in krb5 credentials,
84 : * indicate to GSSAPI that we are not interested in any other
85 : * mechanism here */
86 19019 : gss_OID_set_desc mech_set = {
87 : .count = 1,
88 : .elements = discard_const_p(struct gss_OID_desc_struct,
89 : gss_mech_krb5),
90 : };
91 :
92 19019 : gss_cred_usage_t cred_usage = GSS_C_INITIATE;
93 19019 : gss_name_t name = NULL;
94 19019 : gss_buffer_desc pr_name = {
95 : .value = NULL,
96 : .length = 0,
97 : };
98 :
99 19019 : if (id != NULL) {
100 4595 : major_status = krb5_cc_get_full_name(ctx,
101 : id,
102 : discard_const(&ccache_element.value));
103 4595 : if (major_status != 0) {
104 0 : return major_status;
105 : }
106 : }
107 :
108 19019 : if (keytab != NULL) {
109 14424 : keytab_element.value = malloc(4096);
110 14424 : if (!keytab_element.value) {
111 0 : return ENOMEM;
112 : }
113 28848 : major_status = krb5_kt_get_name(ctx,
114 : keytab,
115 14424 : discard_const(keytab_element.value), 4096);
116 14424 : if (major_status != 0) {
117 0 : free(discard_const(keytab_element.value));
118 0 : return major_status;
119 : }
120 14424 : cred_usage = GSS_C_ACCEPT;
121 14424 : cred_store.elements = &keytab_element;
122 :
123 14424 : if (keytab_principal != NULL) {
124 12681 : major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
125 12681 : if (major_status != 0) {
126 0 : free(discard_const(keytab_element.value));
127 0 : return major_status;
128 : }
129 12681 : pr_name.length = strlen(pr_name.value);
130 :
131 12681 : major_status = gss_import_name(minor_status,
132 : &pr_name,
133 : discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
134 : &name);
135 12681 : if (major_status != 0) {
136 0 : krb5_free_unparsed_name(ctx, pr_name.value);
137 0 : free(discard_const(keytab_element.value));
138 0 : return major_status;
139 : }
140 : }
141 : }
142 :
143 19019 : if (id != NULL && keytab != NULL) {
144 0 : elements[0] = ccache_element;
145 0 : elements[1] = keytab_element;
146 :
147 0 : cred_store.elements = elements;
148 0 : cred_store.count = 2;
149 0 : cred_usage = GSS_C_BOTH;
150 : }
151 :
152 19019 : major_status = gss_acquire_cred_from(minor_status,
153 : name,
154 : 0,
155 : &mech_set,
156 : cred_usage,
157 : &cred_store,
158 : cred,
159 : NULL,
160 : NULL);
161 :
162 19019 : if (pr_name.value != NULL) {
163 12681 : (void)gss_release_name(&minor, &name);
164 12681 : krb5_free_unparsed_name(ctx, pr_name.value);
165 : }
166 19019 : if (keytab_element.value != NULL) {
167 14424 : free(discard_const(keytab_element.value));
168 : }
169 19019 : krb5_free_string(ctx, discard_const(ccache_element.value));
170 : #else
171 61943 : major_status = gss_krb5_import_cred(minor_status,
172 : id,
173 : keytab_principal,
174 : keytab, cred);
175 :
176 61943 : if (major_status == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
177 0 : if ((keytab_principal == NULL) && (keytab != NULL)) {
178 : /* No principal was specified and MIT krb5 1.9 version failed.
179 : * We have to fall back to set global acceptor identity */
180 0 : gss_OID_set_desc mech_set;
181 0 : char *kt_name = NULL;
182 :
183 0 : kt_name = malloc(4096);
184 0 : if (!kt_name) {
185 0 : return ENOMEM;
186 : }
187 :
188 0 : major_status = krb5_kt_get_name(ctx,
189 : keytab,
190 : kt_name, 4096);
191 0 : if (major_status != 0) {
192 0 : free(kt_name);
193 0 : return major_status;
194 : }
195 :
196 0 : major_status = gsskrb5_register_acceptor_identity(kt_name);
197 0 : if (major_status) {
198 0 : free(kt_name);
199 0 : return major_status;
200 : }
201 :
202 : /* We are dealing with krb5 GSSAPI mech in this fallback */
203 0 : mech_set.count = 1;
204 0 : mech_set.elements =
205 : discard_const_p(struct gss_OID_desc_struct,
206 : gss_mech_krb5);
207 0 : major_status = gss_acquire_cred(minor_status,
208 : GSS_C_NO_NAME,
209 : GSS_C_INDEFINITE,
210 : &mech_set,
211 : GSS_C_ACCEPT,
212 : cred,
213 : NULL, NULL);
214 0 : free(kt_name);
215 : }
216 : }
217 : #endif
218 78220 : return major_status;
219 : }
220 :
221 :
222 : #endif /* HAVE_GSSAPI */
|