CVE-2022-2031 s4:kdc: Reject tickets during the last two minutes of their life
[Samba.git] / lib / krb5_wrap / gss_samba.c
bloba5940561cdaf7cc1a209b21a0381904aa49a6850
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 */
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.
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 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)
62 uint32_t major_status = 0;
64 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
65 uint32_t minor = 0;
66 gss_key_value_element_desc ccache_element = {
67 .key = "ccache",
68 .value = NULL,
71 gss_key_value_element_desc keytab_element = {
72 .key = "keytab",
73 .value = NULL,
76 gss_key_value_element_desc elements[2];
78 gss_key_value_set_desc cred_store = {
79 .elements = &ccache_element,
80 .count = 1,
83 /* we are interested exclusively in krb5 credentials,
84 * indicate to GSSAPI that we are not interested in any other
85 * mechanism here */
86 gss_OID_set_desc mech_set = {
87 .count = 1,
88 .elements = discard_const_p(struct gss_OID_desc_struct,
89 gss_mech_krb5),
92 gss_cred_usage_t cred_usage = GSS_C_INITIATE;
93 gss_name_t name = NULL;
94 gss_buffer_desc pr_name = {
95 .value = NULL,
96 .length = 0,
99 if (id != NULL) {
100 major_status = krb5_cc_get_full_name(ctx,
102 discard_const(&ccache_element.value));
103 if (major_status != 0) {
104 return major_status;
108 if (keytab != NULL) {
109 keytab_element.value = malloc(4096);
110 if (!keytab_element.value) {
111 return ENOMEM;
113 major_status = krb5_kt_get_name(ctx,
114 keytab,
115 discard_const(keytab_element.value), 4096);
116 if (major_status != 0) {
117 free(discard_const(keytab_element.value));
118 return major_status;
120 cred_usage = GSS_C_ACCEPT;
121 cred_store.elements = &keytab_element;
123 if (keytab_principal != NULL) {
124 major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
125 if (major_status != 0) {
126 free(discard_const(keytab_element.value));
127 return major_status;
129 pr_name.length = strlen(pr_name.value);
131 major_status = gss_import_name(minor_status,
132 &pr_name,
133 discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
134 &name);
135 if (major_status != 0) {
136 krb5_free_unparsed_name(ctx, pr_name.value);
137 free(discard_const(keytab_element.value));
138 return major_status;
143 if (id != NULL && keytab != NULL) {
144 elements[0] = ccache_element;
145 elements[1] = keytab_element;
147 cred_store.elements = elements;
148 cred_store.count = 2;
149 cred_usage = GSS_C_BOTH;
152 major_status = gss_acquire_cred_from(minor_status,
153 name,
155 &mech_set,
156 cred_usage,
157 &cred_store,
158 cred,
159 NULL,
160 NULL);
162 if (pr_name.value != NULL) {
163 (void)gss_release_name(&minor, &name);
164 krb5_free_unparsed_name(ctx, pr_name.value);
166 if (keytab_element.value != NULL) {
167 free(discard_const(keytab_element.value));
169 krb5_free_string(ctx, discard_const(ccache_element.value));
170 #else
171 major_status = gss_krb5_import_cred(minor_status,
173 keytab_principal,
174 keytab, cred);
176 if (major_status == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
177 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 gss_OID_set_desc mech_set;
181 char *kt_name = NULL;
183 kt_name = malloc(4096);
184 if (!kt_name) {
185 return ENOMEM;
188 major_status = krb5_kt_get_name(ctx,
189 keytab,
190 kt_name, 4096);
191 if (major_status != 0) {
192 free(kt_name);
193 return major_status;
196 major_status = gsskrb5_register_acceptor_identity(kt_name);
197 if (major_status) {
198 free(kt_name);
199 return major_status;
202 /* We are dealing with krb5 GSSAPI mech in this fallback */
203 mech_set.count = 1;
204 mech_set.elements =
205 discard_const_p(struct gss_OID_desc_struct,
206 gss_mech_krb5);
207 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 free(kt_name);
217 #endif
218 return major_status;
222 #endif /* HAVE_GSSAPI */