ctdb-daemon: Use ctdb_parse_node_address() in ctdbd
[samba4-gss.git] / lib / krb5_wrap / gss_samba.c
blob608cb60f155e2a7ce6941a270a96cf9922fe4a98
1 /*
2 * Unix SMB/CIFS implementation.
4 * Simple GSSAPI wrappers
6 * Copyright (c) 2012 Andreas Schneider <asn@samba.org>
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.
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.
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/>.
22 #include "includes.h"
23 #include "gss_samba.h"
25 #ifdef HAVE_GSSAPI
27 #if !defined(HAVE_GSS_OID_EQUAL)
28 int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid)
30 if (first_oid == GSS_C_NO_OID || second_oid == GSS_C_NO_OID) {
31 return 0;
34 if (first_oid == second_oid) {
35 return 1;
38 if ((first_oid)->length != (second_oid)->length) {
39 return 0;
42 if (memcmp((first_oid)->elements, (second_oid)->elements,
43 (first_oid)->length) == 0) {
44 return 1;
47 return 0;
49 #endif /* !HAVE_GSS_OID_EQUAL */
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.
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 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)
64 return smb_gss_mech_import_cred(minor_status,
65 ctx,
66 id,
67 keytab_principal,
68 keytab,
69 gss_mech_krb5,
70 cred);
73 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)
81 uint32_t major_status = 0;
83 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
84 uint32_t minor = 0;
85 gss_key_value_element_desc ccache_element = {
86 .key = "ccache",
87 .value = NULL,
90 gss_key_value_element_desc keytab_element = {
91 .key = "keytab",
92 .value = NULL,
95 gss_key_value_element_desc elements[2];
97 gss_key_value_set_desc cred_store = {
98 .elements = &ccache_element,
99 .count = 1,
102 /* we are interested exclusively in krb5 credentials,
103 * indicate to GSSAPI that we are not interested in any other
104 * mechanism here */
105 gss_OID_set_desc mech_set = {
106 .count = 1,
107 .elements = discard_const_p(struct gss_OID_desc_struct,
108 mech),
111 gss_cred_usage_t cred_usage = GSS_C_INITIATE;
112 gss_name_t name = NULL;
113 gss_buffer_desc pr_name = {
114 .value = NULL,
115 .length = 0,
118 if (id != NULL) {
119 major_status = krb5_cc_get_full_name(ctx,
121 discard_const(&ccache_element.value));
122 if (major_status != 0) {
123 return major_status;
127 if (keytab != NULL) {
128 keytab_element.value = malloc(4096);
129 if (!keytab_element.value) {
130 return ENOMEM;
132 major_status = krb5_kt_get_name(ctx,
133 keytab,
134 discard_const(keytab_element.value), 4096);
135 if (major_status != 0) {
136 free(discard_const(keytab_element.value));
137 return major_status;
139 cred_usage = GSS_C_ACCEPT;
140 cred_store.elements = &keytab_element;
142 if (keytab_principal != NULL) {
143 major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
144 if (major_status != 0) {
145 free(discard_const(keytab_element.value));
146 return major_status;
148 pr_name.length = strlen(pr_name.value);
150 major_status = gss_import_name(minor_status,
151 &pr_name,
152 discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
153 &name);
154 if (major_status != 0) {
155 krb5_free_unparsed_name(ctx, pr_name.value);
156 free(discard_const(keytab_element.value));
157 return major_status;
162 if (id != NULL && keytab != NULL) {
163 elements[0] = ccache_element;
164 elements[1] = keytab_element;
166 cred_store.elements = elements;
167 cred_store.count = 2;
168 cred_usage = GSS_C_BOTH;
171 major_status = gss_acquire_cred_from(minor_status,
172 name,
174 &mech_set,
175 cred_usage,
176 &cred_store,
177 cred,
178 NULL,
179 NULL);
181 if (pr_name.value != NULL) {
182 (void)gss_release_name(&minor, &name);
183 krb5_free_unparsed_name(ctx, pr_name.value);
185 if (keytab_element.value != NULL) {
186 free(discard_const(keytab_element.value));
188 krb5_free_string(ctx, discard_const(ccache_element.value));
189 #else
190 major_status = gss_krb5_import_cred(minor_status,
192 keytab_principal,
193 keytab, cred);
195 if (major_status == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
196 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 gss_OID_set_desc mech_set;
200 char *kt_name = NULL;
202 kt_name = malloc(4096);
203 if (!kt_name) {
204 return ENOMEM;
207 major_status = krb5_kt_get_name(ctx,
208 keytab,
209 kt_name, 4096);
210 if (major_status != 0) {
211 free(kt_name);
212 return major_status;
215 major_status = gsskrb5_register_acceptor_identity(kt_name);
216 if (major_status) {
217 free(kt_name);
218 return major_status;
221 /* We are dealing with krb5 GSSAPI mech in this fallback */
222 mech_set.count = 1;
223 mech_set.elements =
224 discard_const_p(struct gss_OID_desc_struct,
225 gss_mech_krb5);
226 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 free(kt_name);
236 #endif
237 return major_status;
241 #endif /* HAVE_GSSAPI */