Skip to content

Commit 1508917

Browse files
simo5frozencemetery
authored andcommitted
Missing keytab should not be fatal
In 1e6b5a4 we've been a littl bit too zealous and made lack of a keytab a fatal condition when a keytab was specified explicitly in config files. However we distribute a config file that explictly mentions the default keytab. In general lack of a keytab is not really an impediment and gssproxy will work properly until restarted (at which point saved cfredentials will become unreadable as the encryption key is lost). But even if access to crdential is lost in most cases this is a recoverable situation. So relax the constraint and fallback to a random key in all cases. Signed-off-by: Simo Sorce <[email protected]> [[email protected] Style fixup] Reviewed-by: Robbie Harwood <[email protected]> Merged: https://pagure.io/gssproxy/pull-request/45
1 parent e45dcdd commit 1508917

File tree

2 files changed

+114
-85
lines changed

2 files changed

+114
-85
lines changed

proxy/src/gp_export.c

Lines changed: 98 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,108 @@ void gp_free_creds_handle(struct gp_creds_handle **in)
3939
return;
4040
}
4141

42+
uint32_t gp_init_creds_with_keytab(uint32_t *min, const char *svc_name,
43+
const char *keytab,
44+
struct gp_creds_handle *handle)
45+
{
46+
char ktname[MAX_KEYTAB_NAME_LEN + 1] = {0};
47+
krb5_keytab ktid = NULL;
48+
krb5_kt_cursor cursor;
49+
krb5_keytab_entry entry;
50+
krb5_enctype *permitted;
51+
uint32_t ret_maj = 0;
52+
uint32_t ret_min = 0;
53+
int ret;
54+
55+
if (keytab) {
56+
strncpy(ktname, keytab, MAX_KEYTAB_NAME_LEN);
57+
ret = krb5_kt_resolve(handle->context, keytab, &ktid);
58+
}
59+
/* if the keytab is not specified or fails to resolve try default */
60+
if (!keytab || ret != 0) {
61+
ret = krb5_kt_default_name(handle->context, ktname,
62+
MAX_KEYTAB_NAME_LEN);
63+
if (ret) {
64+
strncpy(ktname, "[default]", MAX_KEYTAB_NAME_LEN);
65+
}
66+
ret = krb5_kt_default(handle->context, &ktid);
67+
}
68+
if (ret == 0) {
69+
ret = krb5_kt_have_content(handle->context, ktid);
70+
}
71+
if (ret) {
72+
GPDEBUG("Keytab %s has no content (%d)\n", ktname, ret);
73+
ret_min = ret;
74+
ret_maj = GSS_S_CRED_UNAVAIL;
75+
goto done;
76+
}
77+
78+
ret = krb5_get_permitted_enctypes(handle->context, &permitted);
79+
if (ret) {
80+
GPDEBUG("Failed to source permitted enctypes (%d)\n", ret);
81+
ret_min = ret;
82+
ret_maj = GSS_S_FAILURE;
83+
goto done;
84+
}
85+
86+
ret = krb5_kt_start_seq_get(handle->context, ktid, &cursor);
87+
if (ret) {
88+
GPDEBUG("krb5_kt_start_seq_get() failed (%d)\n", ret);
89+
ret_min = ret;
90+
ret_maj = GSS_S_FAILURE;
91+
goto done;
92+
}
93+
do {
94+
ret = krb5_kt_next_entry(handle->context, ktid, &entry, &cursor);
95+
if (ret == 0) {
96+
for (unsigned i = 0; permitted[i] != 0; i++) {
97+
if (permitted[i] == entry.key.enctype) {
98+
/* should we derive a key instead ? */
99+
ret = krb5_copy_keyblock(handle->context, &entry.key,
100+
&handle->key);
101+
if (ret == 0) {
102+
GPDEBUG("Service: %s, Keytab: %s, Enctype: %d\n",
103+
svc_name, ktname, entry.key.enctype);
104+
ret = KRB5_KT_END;
105+
} else {
106+
GPDEBUG("krb5_copy_keyblock failed (%d)\n", ret);
107+
}
108+
break;
109+
}
110+
}
111+
(void)krb5_free_keytab_entry_contents(handle->context, &entry);
112+
}
113+
} while (ret == 0);
114+
(void)krb5_kt_end_seq_get(handle->context, ktid, &cursor);
115+
if ((ret == KRB5_KT_END) && (handle->key == NULL)) {
116+
ret = KRB5_WRONG_ETYPE;
117+
ret_maj = GSS_S_CRED_UNAVAIL;
118+
goto done;
119+
}
120+
if (ret != KRB5_KT_END) {
121+
ret_min = ret;
122+
ret_maj = GSS_S_CRED_UNAVAIL;
123+
goto done;
124+
}
125+
126+
ret_min = 0;
127+
ret_maj = GSS_S_COMPLETE;
128+
129+
done:
130+
if (ktid) {
131+
(void)krb5_kt_close(handle->context, ktid);
132+
}
133+
*min = ret_min;
134+
return ret_maj;
135+
}
136+
42137
uint32_t gp_init_creds_handle(uint32_t *min, const char *svc_name,
43138
const char *keytab,
44139
struct gp_creds_handle **out)
45140
{
46141
struct gp_creds_handle *handle;
47142
uint32_t ret_maj = 0;
48143
uint32_t ret_min = 0;
49-
krb5_keytab ktid = NULL;
50-
char ktname[MAX_KEYTAB_NAME_LEN + 1] = {0};
51144
int ret;
52145

53146
handle = calloc(1, sizeof(struct gp_creds_handle));
@@ -67,85 +160,9 @@ uint32_t gp_init_creds_handle(uint32_t *min, const char *svc_name,
67160

68161
/* Try to use a keytab, and fall back to a random runtime secret if all
69162
* else fails */
70-
if (keytab) {
71-
ret = krb5_kt_resolve(handle->context, keytab, &ktid);
72-
if (ret == 0) {
73-
ret = krb5_kt_have_content(handle->context, ktid);
74-
}
75-
/* if a keytab is specified then it must be usable */
76-
if (ret) {
77-
ret_min = ret;
78-
ret_maj = GSS_S_CRED_UNAVAIL;
79-
goto done;
80-
}
81-
strncpy(ktname, keytab, MAX_KEYTAB_NAME_LEN);
82-
} else {
83-
ret = krb5_kt_default(handle->context, &ktid);
84-
/* if the default keyab does not exist or is empty it is not fatal */
85-
if (ret) {
86-
ktid = NULL;
87-
} else {
88-
ret = krb5_kt_have_content(handle->context, ktid);
89-
if (ret) {
90-
(void)krb5_kt_close(handle->context, ktid);
91-
ktid = NULL;
92-
} else {
93-
ret = krb5_kt_default_name(handle->context, ktname,
94-
MAX_KEYTAB_NAME_LEN);
95-
if (ret) strncpy(ktname, "[default]", MAX_KEYTAB_NAME_LEN);
96-
}
97-
}
98-
}
99-
100-
if (ktid) {
101-
krb5_kt_cursor cursor;
102-
krb5_keytab_entry entry;
103-
krb5_enctype *permitted;
104-
105-
ret = krb5_get_permitted_enctypes(handle->context, &permitted);
106-
if (ret) {
107-
ret_min = ret;
108-
ret_maj = GSS_S_FAILURE;
109-
goto done;
110-
}
111-
112-
ret = krb5_kt_start_seq_get(handle->context, ktid, &cursor);
113-
if (ret) {
114-
ret_min = ret;
115-
ret_maj = GSS_S_FAILURE;
116-
goto done;
117-
}
118-
do {
119-
ret = krb5_kt_next_entry(handle->context, ktid, &entry, &cursor);
120-
if (ret == 0) {
121-
for (unsigned i = 0; permitted[i] != 0; i++) {
122-
if (permitted[i] == entry.key.enctype) {
123-
/* should we derive a key instead ? */
124-
ret = krb5_copy_keyblock(handle->context, &entry.key,
125-
&handle->key);
126-
if (ret == 0) {
127-
GPDEBUG("Service: %s, Enckey: %s, Enctype: %d\n",
128-
svc_name, ktname, entry.key.enctype);
129-
ret = KRB5_KT_END;
130-
}
131-
break;
132-
}
133-
}
134-
(void)krb5_free_keytab_entry_contents(handle->context, &entry);
135-
}
136-
} while (ret == 0);
137-
(void)krb5_kt_end_seq_get(handle->context, ktid, &cursor);
138-
if ((ret == KRB5_KT_END) && (handle->key == NULL)) {
139-
ret = KRB5_WRONG_ETYPE;
140-
ret_maj = GSS_S_CRED_UNAVAIL;
141-
goto done;
142-
}
143-
if (ret != KRB5_KT_END) {
144-
ret_min = ret;
145-
ret_maj = GSS_S_CRED_UNAVAIL;
146-
goto done;
147-
}
148-
} else {
163+
ret_maj = gp_init_creds_with_keytab(&ret_min, svc_name, keytab, handle);
164+
if (ret_maj != GSS_S_COMPLETE) {
165+
/* fallback */
149166
ret = krb5_init_keyblock(handle->context,
150167
GP_CREDS_HANDLE_KEY_ENCTYPE, 0,
151168
&handle->key);
@@ -167,9 +184,6 @@ uint32_t gp_init_creds_handle(uint32_t *min, const char *svc_name,
167184
ret_min = 0;
168185

169186
done:
170-
if (handle->context && ktid) {
171-
(void)krb5_kt_close(handle->context, ktid);
172-
}
173187
*min = ret_min;
174188
if (ret_maj) {
175189
gp_free_creds_handle(&handle);

proxy/tests/testlib.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,11 @@ def setup_gssapi_env(testdir, wrapenv):
538538
cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB}
539539
trusted = yes
540540
euid = ${UIDNUMBER}
541+
542+
[service/badkeytab]
543+
mechs = krb5
544+
cred_store = keytab:/intentionally/missing/keytab
545+
euid = 123
541546
'''
542547

543548
# Contains a garbage service entry
@@ -553,7 +558,17 @@ def setup_gssapi_env(testdir, wrapenv):
553558
euid = nobody
554559
'''
555560

556-
GSSPROXY_CONF_SOCKET_TEMPLATE = GSSPROXY_CONF_TEMPLATE + '''
561+
GSSPROXY_CONF_SOCKET_TEMPLATE = '''
562+
[gssproxy]
563+
debug_level = 3
564+
565+
[service/test]
566+
mechs = krb5
567+
cred_store = keytab:${GSSPROXY_KEYTAB}
568+
cred_store = ccache:FILE:${GSSPROXY_CLIENT_CCACHE}
569+
cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB}
570+
trusted = yes
571+
euid = ${UIDNUMBER}
557572
socket = ${SECOND_SOCKET}
558573
'''
559574

0 commit comments

Comments
 (0)