RHEL 9.0.0 Alpha bootstrap

The content of this branch was automatically imported from Fedora ELN
with the following as its source:
https://src.fedoraproject.org/rpms/krb5#501e2980728bcbd0c757fd9bb2b6274342420d2a
This commit is contained in:
Petr Šabata 2020-10-15 15:05:18 +02:00
parent c5329a1c4a
commit 908aeb56b2
56 changed files with 19268 additions and 0 deletions

189
.gitignore vendored
View File

@ -0,0 +1,189 @@
krb5-1.3.4.tar.gz
krb5-1.3.5.tar.gz
krb5-1.3.5.tar.gz.asc
krb5-1.3.6.tar.gz
krb5-1.3.6.tar.gz.asc
krb5-1.4.tar.gz
krb5-1.4.tar.gz.asc
krb5-1.4.1.tar.gz
krb5-1.4.1.tar.gz.asc
krb5-1.4.2.tar.gz
krb5-1.4.2.tar.gz.asc
krb5-1.4.3.tar.gz
krb5-1.4.3.tar.gz.asc
krb5-1.5.tar.gz
krb5-1.5.tar.gz.asc
krb5-1.6.tar.gz
krb5-1.6.tar.gz.asc
krb5-1.6-pdf.tar.gz
krb5-1.6.1.tar.gz
krb5-1.6.1.tar.gz.asc
krb5-1.6.1-pdf.tar.gz
krb5-1.6.2.tar.gz
krb5-1.6.2.tar.gz.asc
krb5-1.6.2-pdf.tar.gz
krb5-1.6.3.tar.gz
krb5-1.6.3.tar.gz.asc
krb5-1.6.3-pdf.tar.gz
krb5-1.7.tar.gz
krb5-1.7.tar.gz.asc
krb5-1.7-pdf.tar.gz
krb5-1.7.1.tar.gz
krb5-1.7.1.tar.gz.asc
krb5-1.7.1-pdf.tar.gz
krb5-1.8.tar.gz
krb5-1.8.tar.gz.asc
krb5-appl-1.0.tar.gz
krb5-appl-1.0.tar.gz.asc
krb5-1.8-pdf.tar.gz
krb5-1.8.1.tar.gz
krb5-1.8.1.tar.gz.asc
krb5-1.8.1-pdf.tar.gz
krb5-1.8.2.tar.gz.asc
krb5-1.8.2-pdf.tar.gz
krb5-1.8.3.tar.gz
krb5-1.8.3.tar.gz.asc
krb5-1.8.3-pdf.tar.gz
/krb5-1.9-beta2.tar.gz
/krb5-1.9-beta2.tar.gz.asc
/krb5-1.9-beta2-pdf.tar.bz2
/krb5-1.9-beta3.tar.gz
/krb5-1.9-beta3.tar.gz.asc
/krb5-1.9-beta3-pdf.tar.bz2
/krb5-1.9.tar.gz
/krb5-1.9.tar.gz.asc
/krb5-1.9-pdf.tar.bz2
/krb5-1.9.1.tar.gz
/krb5-1.9.1.tar.gz.asc
/krb5-1.9.1-pdf.tar.bz2
/krb5-1.10-alpha1.tar.gz
/krb5-1.10-alpha1.tar.gz.asc
/krb5-1.10-pdf.tar.bz2
/krb5-1.10-alpha2.tar.gz
/krb5-1.10-alpha2.tar.gz.asc
/krb5-1.10-beta1.tar.gz
/krb5-1.10-beta1.tar.gz.asc
/krb5-1.10.tar.gz
/krb5-1.10.tar.gz.asc
/krb5-1.10-pdf.tar.xz
/krb5-1.10.1.tar.gz
/krb5-1.10.1.tar.gz.asc
/krb5-1.10.1-pdf.tar.xz
/krb5-1.10.2.tar.gz
/krb5-1.10.2.tar.gz.asc
/krb5-1.10.2-pdf.tar.xz
/krb5-1.10.3.tar.gz
/krb5-1.10.3.tar.gz.asc
/krb5-1.10.3-pdf.tar.xz
/krb5-1.11-alpha1.tar.gz
/krb5-1.11-alpha1.tar.gz.asc
/krb5-1.11-beta1.tar.gz
/krb5-1.11-beta1.tar.gz.asc
/krb5-1.11-beta2.tar.gz
/krb5-1.11-beta2.tar.gz.asc
/krb5-1.11.tar.gz
/krb5-1.11.tar.gz.asc
/krb5-1.11.1-pdf.tar.xz
/krb5-1.11.2.tar.gz
/krb5-1.11.2.tar.gz.asc
/krb5-1.11.2-pdf.tar.xz
/krb5-1.11.3.tar.gz
/krb5-1.11.3.tar.gz.asc
/krb5-1.11.3-pdf.tar.xz
/nss_wrapper.tar.bz2
/nss_wrapper-0.0-20130719153839Z.git6cb59864.bz2
/krb5-1.11.4.tar.gz
/krb5-1.11.4.tar.gz.asc
/krb5-1.11.4-pdf.tar.xz
/krb5-1.12-beta1.tar.gz
/krb5-1.12-beta1.tar.gz.asc
/krb5-1.12-beta1-pdf.tar.xz
/krb5-1.12-beta2.tar.gz
/krb5-1.12-beta2.tar.gz.asc
/krb5-1.12-beta2-pdf.tar.xz
/krb5-1.12.tar.gz
/krb5-1.12.tar.gz.asc
/krb5-1.12-pdf.tar.xz
/krb5-1.12.1.tar.gz
/krb5-1.12.1.tar.gz.asc
/krb5-1.12.1-pdf.tar.xz
/krb5-1.12.2.tar.gz
/krb5-1.12.2.tar.gz.asc
/krb5-1.12.2-pdf.tar.xz
/krb5-1.13-alpha1.tar.gz
/krb5-1.13-alpha1.tar.gz.asc
/krb5-1.13-alpha1-pdf.tar.xz
/krb5-1.13.tar.gz
/krb5-1.13.tar.gz.asc
/krb5-1.13-pdf.tar.xz
/krb5-1.13.1-pdf.pax.xz
/krb5-1.13.2.tar.gz
/krb5-1.13.2.tar.gz.asc
/krb5-1.13.2-pdf.pax.xz
/krb5-1.13.2-pdfs.tar
/krb5-1.14-beta1.tar.gz
/krb5-1.14-beta1.tar.gz.asc
/krb5-1.14-beta1-pdfs.tar
/krb5-1.14-beta2.tar.gz.asc
/krb5-1.14-beta2.tar.gz
/krb5-1.14-beta2-pdfs.tar
/krb5-1.14-pdfs.tar
/krb5-1.14.tar.gz
/krb5-1.14.tar.gz.asc
/krb5-1.14.1-pdfs.tar
/krb5-1.14.1.tar.gz
/krb5-1.14.1.tar.gz.asc
/krb5-1.14.3.tar.gz
/krb5-1.14.3.tar.gz.asc
/krb5-1.14.3-pdfs.tar
/krb5-1.14.4.tar.gz
/krb5-1.14.4.tar.gz.asc
/krb5-1.14.4-pdfs.tar
/krb5-1.15-beta1.tar.gz
/krb5-1.15-beta1.tar.gz.asc
/krb5-1.15-beta1-pdfs.tar
/krb5-1.15-beta2-pdfs.tar
/krb5-1.15-beta2.tar.gz
/krb5-1.15-beta2.tar.gz.asc
/krb5-1.15-pdfs.tar
/krb5-1.15.tar.gz
/krb5-1.15.tar.gz.asc
/krb5-1.15.1-pdfs.tar
/krb5-1.15.1.tar.gz
/krb5-1.15.1.tar.gz.asc
/krb5-1.15.2-pdfs.tar
/krb5-1.15.2.tar.gz
/krb5-1.15.2.tar.gz.asc
/krb5-1.16-beta1-pdfs.tar
/krb5-1.16-beta1.tar.gz
/krb5-1.16-beta1.tar.gz.asc
/krb5-1.16-beta2.tar.gz
/krb5-1.16-beta2.tar.gz.asc
/krb5-1.16-beta2-pdfs.tar
/krb5-1.16-pdfs.tar
/krb5-1.16.tar.gz
/krb5-1.16.tar.gz.asc
/krb5-1.16.1-pdfs.tar
/krb5-1.16.1.tar.gz
/krb5-1.16.1.tar.gz.asc
/krb5-1.17-beta1.tar.gz
/krb5-1.17-beta1.tar.gz.asc
/krb5-1.17-beta1-pdfs.tar
/krb5-1.17-beta2.tar.gz
/krb5-1.17-beta2.tar.gz.asc
/krb5-1.17-beta2-pdfs.tar
/krb5-1.17-pdfs.tar
/krb5-1.17.tar.gz
/krb5-1.17.tar.gz.asc
/krb5-1.17.1.tar.gz
/krb5-1.17.1.tar.gz.asc
/krb5-1.18-beta1.tar.gz
/krb5-1.18-beta1.tar.gz.asc
/krb5-1.18-beta2.tar.gz
/krb5-1.18-beta2.tar.gz.asc
/krb5-1.18.tar.gz
/krb5-1.18.tar.gz.asc
/krb5-1.18.1.tar.gz
/krb5-1.18.1.tar.gz.asc
/krb5-1.18.2.tar.gz
/krb5-1.18.2.tar.gz.asc

View File

@ -0,0 +1,419 @@
From 6d36ea6fcfe281a8ce73fc5aa5c133f435d93fa4 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Fri, 20 Mar 2020 00:17:28 +0100
Subject: [PATCH] Add channel bindings tests
[ghudson@mit.edu: adjusted test program to output channel-bound state
instead of optionally enforcing it; adjusted tests to check program
output; split out tests into separate Python script; made cosmetic
changes]
ticket: 8900
(cherry picked from commit b0b21b6d25b06f3e2b365dfe9dd4c99b3d43bf57)
[rharwood@redhat.com: .gitignore]
---
src/plugins/gssapi/negoextest/main.c | 18 +++++
src/tests/gssapi/Makefile.in | 49 ++++++------
src/tests/gssapi/common.c | 25 ++++--
src/tests/gssapi/common.h | 9 +++
src/tests/gssapi/deps | 4 +
src/tests/gssapi/t_bindings.c | 111 +++++++++++++++++++++++++++
src/tests/gssapi/t_bindings.py | 43 +++++++++++
src/tests/gssapi/t_negoex.py | 7 ++
8 files changed, 237 insertions(+), 29 deletions(-)
create mode 100644 src/tests/gssapi/t_bindings.c
create mode 100644 src/tests/gssapi/t_bindings.py
diff --git a/src/plugins/gssapi/negoextest/main.c b/src/plugins/gssapi/negoextest/main.c
index 6c340f41b..72fc5273a 100644
--- a/src/plugins/gssapi/negoextest/main.c
+++ b/src/plugins/gssapi/negoextest/main.c
@@ -57,6 +57,15 @@ gss_init_sec_context(OM_uint32 *minor_status,
const char *envstr;
uint8_t hops, mech_last_octet;
+ envstr = getenv("GSS_INIT_BINDING");
+ if (envstr != NULL) {
+ assert(strlen(envstr) > 0);
+ assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
+ assert(strlen(envstr) == input_chan_bindings->application_data.length);
+ assert(strcmp((char *)input_chan_bindings->application_data.value,
+ envstr) == 0);
+ }
+
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
envstr = getenv("HOPS");
hops = (envstr != NULL) ? atoi(envstr) : 1;
@@ -112,6 +121,15 @@ gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
uint8_t hops, mech_last_octet;
const char *envstr;
+ envstr = getenv("GSS_ACCEPT_BINDING");
+ if (envstr != NULL) {
+ assert(strlen(envstr) > 0);
+ assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
+ assert(strlen(envstr) == input_chan_bindings->application_data.length);
+ assert(strcmp((char *)input_chan_bindings->application_data.value,
+ envstr) == 0);
+ }
+
/*
* The unwrapped token sits at the end and is just one byte giving the
* remaining number of hops. The final octet of the mech encoding should
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
index 5cc1e0f58..68c132b79 100644
--- a/src/tests/gssapi/Makefile.in
+++ b/src/tests/gssapi/Makefile.in
@@ -9,33 +9,33 @@ LOCALINCLUDES = -I$(srcdir)/../../lib/gssapi/mechglue \
-I../../lib/gssapi/generic
SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
- $(srcdir)/t_accname.c $(srcdir)/t_add_cred.c $(srcdir)/t_ccselect.c \
- $(srcdir)/t_ciflags.c $(srcdir)/t_context.c $(srcdir)/t_credstore.c \
- $(srcdir)/t_enctypes.c $(srcdir)/t_err.c $(srcdir)/t_export_cred.c \
- $(srcdir)/t_export_name.c $(srcdir)/t_gssexts.c \
- $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c $(srcdir)/t_invalid.c \
- $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
+ $(srcdir)/t_accname.c $(srcdir)/t_add_cred.c $(srcdir)/t_bindings.c \
+ $(srcdir)/t_ccselect.c $(srcdir)/t_ciflags.c $(srcdir)/t_context.c \
+ $(srcdir)/t_credstore.c $(srcdir)/t_enctypes.c $(srcdir)/t_err.c \
+ $(srcdir)/t_export_cred.c $(srcdir)/t_export_name.c \
+ $(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \
+ $(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
$(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
$(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \
$(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \
$(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
$(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
-OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_add_cred.o t_ccselect.o \
- t_ciflags.o t_context.o t_credstore.o t_enctypes.o t_err.o \
- t_export_cred.o t_export_name.o t_gssexts.o t_imp_cred.o t_imp_name.o \
- t_invalid.o t_inq_cred.o t_inq_ctx.o t_inq_mechs_name.o t_iov.o \
- t_lifetime.o t_namingexts.o t_oid.o t_pcontok.o t_prf.o t_s4u.o \
- t_s4u2proxy_krb5.o t_saslname.o t_spnego.o t_srcattrs.o
+OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_add_cred.o t_bindings.o \
+ t_ccselect.o t_ciflags.o t_context.o t_credstore.o t_enctypes.o \
+ t_err.o t_export_cred.o t_export_name.o t_gssexts.o t_imp_cred.o \
+ t_imp_name.o t_invalid.o t_inq_cred.o t_inq_ctx.o t_inq_mechs_name.o \
+ t_iov.o t_lifetime.o t_namingexts.o t_oid.o t_pcontok.o t_prf.o \
+ t_s4u.o t_s4u2proxy_krb5.o t_saslname.o t_spnego.o t_srcattrs.o
COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
-all: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags t_context \
- t_credstore t_enctypes t_err t_export_cred t_export_name t_gssexts \
- t_imp_cred t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name \
- t_iov t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u \
- t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
+all: ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect t_ciflags \
+ t_context t_credstore t_enctypes t_err t_export_cred t_export_name \
+ t_gssexts t_imp_cred t_imp_name t_invalid t_inq_cred t_inq_ctx \
+ t_inq_mechs_name t_iov t_lifetime t_namingexts t_oid t_pcontok t_prf \
+ t_s4u t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
check-unix: t_oid
$(RUN_TEST) ./t_invalid
@@ -43,11 +43,12 @@ check-unix: t_oid
$(RUN_TEST) ./t_prf
$(RUN_TEST) ./t_imp_name
-check-pytests: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags \
- t_context t_credstore t_enctypes t_err t_export_cred t_export_name \
- t_imp_cred t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \
- t_pcontok t_s4u t_s4u2proxy_krb5 t_spnego t_srcattrs
+check-pytests: ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect \
+ t_ciflags t_context t_credstore t_enctypes t_err t_export_cred \
+ t_export_name t_imp_cred t_inq_cred t_inq_ctx t_inq_mechs_name t_iov \
+ t_lifetime t_pcontok t_s4u t_s4u2proxy_krb5 t_spnego t_srcattrs
$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_bindings.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_enctypes.py $(PYTESTFLAGS)
@@ -64,6 +65,8 @@ t_accname: t_accname.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_accname.o $(COMMON_LIBS)
t_add_cred: t_add_cred.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_add_cred.o $(COMMON_LIBS)
+t_bindings: t_bindings.o $(COMMON_DEPS)
+ $(CC_LINK) -o $@ t_bindings.o $(COMMON_LIBS)
t_ccselect: t_ccselect.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_ccselect.o $(COMMON_LIBS)
t_ciflags: t_ciflags.o $(COMMON_DEPS)
@@ -118,8 +121,8 @@ t_srcattrs: t_srcattrs.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_srcattrs.o $(COMMON_LIBS)
clean:
- $(RM) ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags
- $(RM) t_context t_credstore t_enctypes t_err t_export_cred
+ $(RM) ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect
+ $(RM) t_ciflags t_context t_credstore t_enctypes t_err t_export_cred
$(RM) t_export_name t_gssexts t_imp_cred t_imp_name t_invalid
$(RM) t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime
$(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5
diff --git a/src/tests/gssapi/common.c b/src/tests/gssapi/common.c
index 83e9d9bb8..7ba72f7b2 100644
--- a/src/tests/gssapi/common.c
+++ b/src/tests/gssapi/common.c
@@ -115,6 +115,20 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
gss_ctx_id_t *actx, gss_name_t *src_name, gss_OID *amech,
gss_cred_id_t *deleg_cred)
+{
+ return establish_contexts_ex(imech, icred, acred, tname, flags, ictx, actx,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_CHANNEL_BINDINGS, NULL, src_name,
+ amech, deleg_cred);
+}
+
+void
+establish_contexts_ex(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
+ gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
+ gss_ctx_id_t *actx, gss_channel_bindings_t icb,
+ gss_channel_bindings_t acb, OM_uint32 *aret_flags,
+ gss_name_t *src_name, gss_OID *amech,
+ gss_cred_id_t *deleg_cred)
{
OM_uint32 minor, imaj, amaj;
gss_buffer_desc itok, atok;
@@ -126,17 +140,16 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
for (;;) {
(void)gss_release_buffer(&minor, &itok);
imaj = gss_init_sec_context(&minor, icred, ictx, tname, imech, flags,
- GSS_C_INDEFINITE,
- GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL,
- &itok, NULL, NULL);
+ GSS_C_INDEFINITE, icb, &atok, NULL, &itok,
+ NULL, NULL);
check_gsserr("gss_init_sec_context", imaj, minor);
if (amaj == GSS_S_COMPLETE)
break;
(void)gss_release_buffer(&minor, &atok);
- amaj = gss_accept_sec_context(&minor, actx, acred, &itok,
- GSS_C_NO_CHANNEL_BINDINGS, src_name,
- amech, &atok, NULL, NULL, deleg_cred);
+ amaj = gss_accept_sec_context(&minor, actx, acred, &itok, acb,
+ src_name, amech, &atok, aret_flags, NULL,
+ deleg_cred);
check_gsserr("gss_accept_sec_context", amaj, minor);
(void)gss_release_buffer(&minor, &itok);
if (imaj == GSS_S_COMPLETE)
diff --git a/src/tests/gssapi/common.h b/src/tests/gssapi/common.h
index ae11b51d4..a5c8f87e6 100644
--- a/src/tests/gssapi/common.h
+++ b/src/tests/gssapi/common.h
@@ -62,6 +62,15 @@ void establish_contexts(gss_OID imech, gss_cred_id_t icred,
gss_name_t *src_name, gss_OID *amech,
gss_cred_id_t *deleg_cred);
+/* Establish contexts with channel bindings. */
+void establish_contexts_ex(gss_OID imech, gss_cred_id_t icred,
+ gss_cred_id_t acred, gss_name_t tname,
+ OM_uint32 flags, gss_ctx_id_t *ictx,
+ gss_ctx_id_t *actx, gss_channel_bindings_t icb,
+ gss_channel_bindings_t acb, OM_uint32 *aret_flags,
+ gss_name_t *src_name, gss_OID *amech,
+ gss_cred_id_t *deleg_cred);
+
/* Export *cred to a token, then release *cred and replace it by re-importing
* the token. */
void export_import_cred(gss_cred_id_t *cred);
diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps
index acd0e96f8..73e4d9a74 100644
--- a/src/tests/gssapi/deps
+++ b/src/tests/gssapi/deps
@@ -33,6 +33,10 @@ $(OUTPRE)t_add_cred.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
common.h t_add_cred.c
+$(OUTPRE)t_bindings.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+ common.h t_bindings.c
$(OUTPRE)t_ccselect.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
diff --git a/src/tests/gssapi/t_bindings.c b/src/tests/gssapi/t_bindings.c
new file mode 100644
index 000000000..e8906715b
--- /dev/null
+++ b/src/tests/gssapi/t_bindings.c
@@ -0,0 +1,111 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2020 by Red Hat, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "common.h"
+
+/*
+ * Establish contexts (without and with GSS_C_DCE_STYLE) with the default
+ * initiator name, a specified principal name as target name, initiator
+ * bindings, and acceptor bindings. If any call is unsuccessful, display an
+ * error message. Output "yes" or "no" to indicate whether the contexts were
+ * reported as channel-bound on the acceptor. Exit with status 0 if all
+ * operations are successful, or 1 if not.
+ *
+ * Usage: ./t_bindings [-s] targetname icb acb
+ *
+ * An icb or abc value of "-" will not specify channel bindings.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ OM_uint32 minor, flags1, flags2;
+ gss_name_t target_name;
+ gss_ctx_id_t ictx, actx;
+ struct gss_channel_bindings_struct icb_data = {0}, acb_data = {0};
+ gss_channel_bindings_t icb = GSS_C_NO_CHANNEL_BINDINGS;
+ gss_channel_bindings_t acb = GSS_C_NO_CHANNEL_BINDINGS;
+ gss_OID_desc *mech;
+
+ argv++;
+ argc--;
+ if (*argv != NULL && strcmp(*argv, "-s") == 0) {
+ mech = &mech_spnego;
+ argv++;
+ argc--;
+ } else {
+ mech = &mech_krb5;
+ }
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: t_bindings [-s] targetname icb acb\n");
+ return 1;
+ }
+
+ target_name = import_name(argv[0]);
+
+ if (strcmp(argv[1], "-") != 0) {
+ icb_data.application_data.length = strlen(argv[1]);
+ icb_data.application_data.value = argv[1];
+ icb = &icb_data;
+ }
+
+ if (strcmp(argv[2], "-") != 0) {
+ acb_data.application_data.length = strlen(argv[2]);
+ acb_data.application_data.value = argv[2];
+ acb = &acb_data;
+ }
+
+ establish_contexts_ex(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
+ target_name, 0, &ictx, &actx, icb, acb, &flags1,
+ NULL, NULL, NULL);
+
+ /* Try again with GSS_C_DCE_STYLE */
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
+
+ establish_contexts_ex(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
+ target_name, GSS_C_DCE_STYLE, &ictx, &actx, icb, acb,
+ &flags2, NULL, NULL, NULL);
+ assert((flags1 & GSS_C_CHANNEL_BOUND_FLAG) ==
+ (flags2 & GSS_C_CHANNEL_BOUND_FLAG));
+ printf("%s\n", (flags1 & GSS_C_CHANNEL_BOUND_FLAG) ? "yes" : "no");
+
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
+ (void)gss_release_name(&minor, &target_name);
+
+ return 0;
+}
diff --git a/src/tests/gssapi/t_bindings.py b/src/tests/gssapi/t_bindings.py
new file mode 100644
index 000000000..f377977b6
--- /dev/null
+++ b/src/tests/gssapi/t_bindings.py
@@ -0,0 +1,43 @@
+from k5test import *
+
+realm = K5Realm()
+server = 'p:' + realm.host_princ
+
+mark('krb5 channel bindings')
+realm.run(['./t_bindings', server, '-', '-'], expected_msg='no')
+realm.run(['./t_bindings', server, 'a', '-'], expected_msg='no')
+realm.run(['./t_bindings', server, 'a', 'a'], expected_msg='yes')
+realm.run(['./t_bindings', server, '-', 'a'], expected_msg='no')
+realm.run(['./t_bindings', server, 'a', 'x'],
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+mark('SPNEGO channel bindings')
+realm.run(['./t_bindings', '-s', server, '-', '-'], expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', '-'], expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', 'a'], expected_msg='yes')
+realm.run(['./t_bindings', '-s', server, '-', 'a'], expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', 'x'],
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+client_aware_conf = {'libdefaults': {'client_aware_channel_bindings': 'true'}}
+e = realm.special_env('cb_aware', False, krb5_conf=client_aware_conf)
+
+mark('krb5 client_aware_channel_bindings')
+realm.run(['./t_bindings', server, '-', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', server, 'a', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', server, 'a', 'a'], env=e, expected_msg='yes')
+realm.run(['./t_bindings', server, '-', 'a'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+realm.run(['./t_bindings', server, 'a', 'x'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+mark('SPNEGO client_aware_channel_bindings')
+realm.run(['./t_bindings', '-s', server, '-', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', 'a'], env=e, expected_msg='yes')
+realm.run(['./t_bindings', '-s', server, '-', 'a'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+realm.run(['./t_bindings', '-s', server, 'a', 'x'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+success('channel bindings tests')
diff --git a/src/tests/gssapi/t_negoex.py b/src/tests/gssapi/t_negoex.py
index 88470d2fa..a218899c4 100644
--- a/src/tests/gssapi/t_negoex.py
+++ b/src/tests/gssapi/t_negoex.py
@@ -139,4 +139,11 @@ msgs = ('sending [3]AP_REQUEST', 'sending [7]CHALLENGE', 'sending [8]VERIFY',
'sending [11]CHALLENGE', 'sending [12]VERIFY', 'sending [13]VERIFY')
test({'HOPS': '4', 'KEY': 'accept-always'}, expected_trace=())
+mark('channel bindings')
+e = realm.env.copy()
+e.update({'HOPS': '1', 'GSS_INIT_BINDING': 'a', 'GSS_ACCEPT_BINDING': 'b'})
+# The test mech will verify that the bindings are communicated to the
+# mech, but does not set the channel-bound flag.
+realm.run(['./t_bindings', '-s', 'h:host', 'a', 'b'], env=e, expected_msg='no')
+
success('NegoEx tests')

View File

@ -0,0 +1,264 @@
From 46ec975eb8f33b6d42c440758fc0deb826f87313 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 10 Mar 2020 13:13:17 +0100
Subject: [PATCH] Add client_aware_channel_bindings option
Add client support for KERB_AP_OPTIONS_CBT in the form of a profile
option "client_aware_gss_bindings". Adjust the make_etype_list()
helper so that enctype negotiation and AP_OPTIONS can be included in
the same IF-RELEVANT wrapper.
[ghudson@mit.edu: refactored; edited documentation; wrote commit
message]
ticket: 8900
(cherry picked from commit 225e6ef7f021cd1a8ef2a054af0ca58b7288fd81)
---
doc/admin/conf_files/krb5_conf.rst | 6 +
src/include/k5-int.h | 1 +
src/lib/krb5/krb/mk_req_ext.c | 177 +++++++++++++++--------------
3 files changed, 98 insertions(+), 86 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 38f450367..da5ad00f2 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -388,6 +388,12 @@ The libdefaults section may contain any of the following relations:
credentials will fail if the client machine does not have a
keytab. The default value is false.
+**client_aware_channel_bindings**
+ If this flag is true, then all application protocol authentication
+ requests will be flagged to indicate that the application supports
+ channel bindings when operating over a secure channel. The
+ default value is false.
+
.. _realms:
[realms]
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 0d9af3d95..eb18a4cd6 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -299,6 +299,7 @@ typedef unsigned char u_char;
#define KRB5_CONF_V4_INSTANCE_CONVERT "v4_instance_convert"
#define KRB5_CONF_V4_REALM "v4_realm"
#define KRB5_CONF_VERIFY_AP_REQ_NOFAIL "verify_ap_req_nofail"
+#define KRB5_CONF_CLIENT_AWARE_GSS_BINDINGS "client_aware_channel_bindings"
/* Cache configuration variables */
#define KRB5_CC_CONF_FAST_AVAIL "fast_avail"
diff --git a/src/lib/krb5/krb/mk_req_ext.c b/src/lib/krb5/krb/mk_req_ext.c
index 9fc6a0e52..08504860c 100644
--- a/src/lib/krb5/krb/mk_req_ext.c
+++ b/src/lib/krb5/krb/mk_req_ext.c
@@ -68,10 +68,9 @@
*/
static krb5_error_code
-make_etype_list(krb5_context context,
- krb5_enctype *desired_etypes,
- krb5_enctype tkt_enctype,
- krb5_authdata ***authdata);
+make_ap_authdata(krb5_context context, krb5_enctype *desired_enctypes,
+ krb5_enctype tkt_enctype, krb5_boolean client_aware_cb,
+ krb5_authdata ***authdata_out);
static krb5_error_code
generate_authenticator(krb5_context,
@@ -263,7 +262,8 @@ generate_authenticator(krb5_context context, krb5_authenticator *authent,
krb5_enctype tkt_enctype)
{
krb5_error_code retval;
- krb5_authdata **ext_authdata = NULL;
+ krb5_authdata **ext_authdata = NULL, **ap_authdata, **combined;
+ int client_aware_cb;
authent->client = client;
authent->checksum = cksum;
@@ -297,99 +297,104 @@ generate_authenticator(krb5_context context, krb5_authenticator *authent,
krb5_free_authdata(context, ext_authdata);
}
- /* Only send EtypeList if we prefer another enctype to tkt_enctype */
- if (desired_etypes != NULL && desired_etypes[0] != tkt_enctype) {
- TRACE_MK_REQ_ETYPES(context, desired_etypes);
- retval = make_etype_list(context, desired_etypes, tkt_enctype,
- &authent->authorization_data);
+ retval = profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS,
+ KRB5_CONF_CLIENT_AWARE_GSS_BINDINGS, NULL,
+ FALSE, &client_aware_cb);
+ if (retval)
+ return retval;
+
+ /* Add etype negotiation or channel-binding awareness authdata to the
+ * front, if appropriate. */
+ retval = make_ap_authdata(context, desired_etypes, tkt_enctype,
+ client_aware_cb, &ap_authdata);
+ if (retval)
+ return retval;
+ if (ap_authdata != NULL) {
+ retval = krb5_merge_authdata(context, ap_authdata,
+ authent->authorization_data, &combined);
+ krb5_free_authdata(context, ap_authdata);
if (retval)
return retval;
+ krb5_free_authdata(context, authent->authorization_data);
+ authent->authorization_data = combined;
}
return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
}
-/* RFC 4537 */
+/* Set *out to a DER-encoded RFC 4537 etype list, or to NULL if no etype list
+ * should be sent. */
static krb5_error_code
-make_etype_list(krb5_context context,
- krb5_enctype *desired_etypes,
- krb5_enctype tkt_enctype,
- krb5_authdata ***authdata)
+make_etype_list(krb5_context context, krb5_enctype *desired_enctypes,
+ krb5_enctype tkt_enctype, krb5_data **out)
{
- krb5_error_code code;
- krb5_etype_list etypes;
- krb5_data *enc_etype_list;
- krb5_data *ad_if_relevant;
- krb5_authdata *etype_adata[2], etype_adatum, **adata;
- int i;
+ krb5_etype_list etlist;
+ int count;
- etypes.etypes = desired_etypes;
+ *out = NULL;
- for (etypes.length = 0;
- etypes.etypes[etypes.length] != ENCTYPE_NULL;
- etypes.length++)
- {
- /*
- * RFC 4537:
- *
- * If the enctype of the ticket session key is included in the enctype
- * list sent by the client, it SHOULD be the last on the list;
- */
- if (etypes.length && etypes.etypes[etypes.length - 1] == tkt_enctype)
+ /* Only send a list if we prefer another enctype to tkt_enctype. */
+ if (desired_enctypes == NULL || desired_enctypes[0] == tkt_enctype)
+ return 0;
+
+ /* Count elements of desired_etypes, stopping at tkt_enctypes if present.
+ * (Per RFC 4537, it must be the last option if it is included.) */
+ for (count = 0; desired_enctypes[count] != ENCTYPE_NULL; count++) {
+ if (count > 0 && desired_enctypes[count - 1] == tkt_enctype)
break;
}
- code = encode_krb5_etype_list(&etypes, &enc_etype_list);
- if (code) {
- return code;
- }
-
- etype_adatum.magic = KV5M_AUTHDATA;
- etype_adatum.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
- etype_adatum.length = enc_etype_list->length;
- etype_adatum.contents = (krb5_octet *)enc_etype_list->data;
-
- etype_adata[0] = &etype_adatum;
- etype_adata[1] = NULL;
-
- /* Wrap in AD-IF-RELEVANT container */
- code = encode_krb5_authdata(etype_adata, &ad_if_relevant);
- if (code) {
- krb5_free_data(context, enc_etype_list);
- return code;
- }
-
- krb5_free_data(context, enc_etype_list);
-
- adata = *authdata;
- if (adata == NULL) {
- adata = (krb5_authdata **)calloc(2, sizeof(krb5_authdata *));
- i = 0;
- } else {
- for (i = 0; adata[i] != NULL; i++)
- ;
-
- adata = (krb5_authdata **)realloc(*authdata,
- (i + 2) * sizeof(krb5_authdata *));
- }
- if (adata == NULL) {
- krb5_free_data(context, ad_if_relevant);
- return ENOMEM;
- }
- *authdata = adata;
-
- adata[i] = (krb5_authdata *)malloc(sizeof(krb5_authdata));
- if (adata[i] == NULL) {
- krb5_free_data(context, ad_if_relevant);
- return ENOMEM;
- }
- adata[i]->magic = KV5M_AUTHDATA;
- adata[i]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
- adata[i]->length = ad_if_relevant->length;
- adata[i]->contents = (krb5_octet *)ad_if_relevant->data;
- free(ad_if_relevant); /* contents owned by adata[i] */
-
- adata[i + 1] = NULL;
-
- return 0;
+ etlist.etypes = desired_enctypes;
+ etlist.length = count;
+ return encode_krb5_etype_list(&etlist, out);
+}
+
+/* Set *authdata_out to appropriate authenticator authdata for the request,
+ * encoded in a single AD_IF_RELEVANT element. */
+static krb5_error_code
+make_ap_authdata(krb5_context context, krb5_enctype *desired_enctypes,
+ krb5_enctype tkt_enctype, krb5_boolean client_aware_cb,
+ krb5_authdata ***authdata_out)
+{
+ krb5_error_code ret;
+ krb5_authdata etypes_ad, flags_ad, *list[3];
+ krb5_data *der_etypes = NULL;
+ size_t count = 0;
+ uint8_t flagbuf[4];
+ const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
+
+ *authdata_out = NULL;
+
+ /* Include an ETYPE_NEGOTIATION element if appropriate. */
+ ret = make_etype_list(context, desired_enctypes, tkt_enctype, &der_etypes);
+ if (ret)
+ goto cleanup;
+ if (der_etypes != NULL) {
+ etypes_ad.magic = KV5M_AUTHDATA;
+ etypes_ad.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
+ etypes_ad.length = der_etypes->length;
+ etypes_ad.contents = (uint8_t *)der_etypes->data;
+ list[count++] = &etypes_ad;
+ }
+
+ /* Include an AP_OPTIONS element if the CBT flag is configured. */
+ if (client_aware_cb != 0) {
+ store_32_le(KERB_AP_OPTIONS_CBT, flagbuf);
+ flags_ad.magic = KV5M_AUTHDATA;
+ flags_ad.ad_type = KRB5_AUTHDATA_AP_OPTIONS;
+ flags_ad.length = 4;
+ flags_ad.contents = flagbuf;
+ list[count++] = &flags_ad;
+ }
+
+ if (count > 0) {
+ list[count] = NULL;
+ ret = krb5_encode_authdata_container(context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ list, authdata_out);
+ }
+
+cleanup:
+ krb5_free_data(context, der_etypes);
+ return ret;
}

View File

@ -0,0 +1,53 @@
From 96a36ef54aecb48b71c1ae0cc85b83ef644c3bd0 Mon Sep 17 00:00:00 2001
From: Jiri Sasek <Jiri.Sasek@Oracle.COM>
Date: Fri, 13 Mar 2020 19:02:58 +0100
Subject: [PATCH] Add finalization safety check to com_err
If the linker erroneously runs the libkrb5 finalizer after the
libcom_err finalizer, the consequent remove_error_table() calls could
crash due to accessing a destroyed mutex or an invalid et_list
pointer. Add an unsynchronized check on finalized in
remove_error_table(), and set et_list to null in com_err_terminate()
after destroying the list.
[ghudson@mit.edu: minimized code hanges; rewrote comment and commit
message]
ticket: 8890 (new)
(cherry picked from commit 9d654aa05e26bbf22f140abde3436afeff2fdf8d)
---
src/util/et/error_message.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/util/et/error_message.c b/src/util/et/error_message.c
index d7069a9df..7dc02a34e 100644
--- a/src/util/et/error_message.c
+++ b/src/util/et/error_message.c
@@ -26,7 +26,7 @@
static struct et_list *et_list;
static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
-static int terminated = 0; /* for debugging shlib fini sequence errors */
+static int terminated = 0; /* for safety and finalization debugging */
MAKE_INIT_FUNCTION(com_err_initialize);
MAKE_FINI_FUNCTION(com_err_terminate);
@@ -69,6 +69,7 @@ void com_err_terminate(void)
enext = e->next;
free(e);
}
+ et_list = NULL;
k5_mutex_unlock(&et_list_lock);
k5_mutex_destroy(&et_list_lock);
terminated = 1;
@@ -280,6 +281,10 @@ remove_error_table(const struct error_table *et)
{
struct et_list **ep, *e;
+ /* Safety check in case libraries are finalized in the wrong order. */
+ if (terminated)
+ return ENOENT;
+
if (CALL_INIT_FUNCTION(com_err_initialize))
return 0;
k5_mutex_lock(&et_list_lock);

View File

@ -0,0 +1,241 @@
From 5b62f6f6a960e5a428a39a3e83e0a16dba5a914a Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 24 Feb 2020 15:58:59 -0500
Subject: [PATCH] Allow certauth modules to set hw-authent flag
In PKINIT, if a certauth module returns KRB5_CERTAUTH_HWAUTH from its
authorize method, set the hw-authent flag in the ticket.
ticket: 8879 (new)
(cherry picked from commit 50fb43b4a2d97ce2cd53e1ced30e8e8224fede70)
---
doc/plugindev/certauth.rst | 7 +++++--
src/include/krb5/certauth_plugin.h | 9 ++++++---
src/lib/krb5/error_tables/k5e1_err.et | 1 +
src/plugins/certauth/test/Makefile.in | 4 ++--
src/plugins/certauth/test/main.c | 11 +++++++++--
src/plugins/preauth/pkinit/pkinit_srv.c | 24 ++++++++++++++++--------
src/tests/t_certauth.py | 13 +++++++++++++
7 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/doc/plugindev/certauth.rst b/doc/plugindev/certauth.rst
index 8a7f7c5eb..3b715f738 100644
--- a/doc/plugindev/certauth.rst
+++ b/doc/plugindev/certauth.rst
@@ -15,8 +15,11 @@ principal. **authorize** receives the DER-encoded certificate, the
requested client principal, and a pointer to the client's
krb5_db_entry (for modules that link against libkdb5). It returns the
authorization status and optionally outputs a list of authentication
-indicator strings to be added to the ticket. A module must use its
-own internal or library-provided ASN.1 certificate decoder.
+indicator strings to be added to the ticket. Beginning in release
+1.19, the authorize method can request that the hardware
+authentication bit be set in the ticket by returning
+**KRB5_CERTAUTH_HWAUTH**. A module must use its own internal or
+library-provided ASN.1 certificate decoder.
A module can optionally create and destroy module data with the
**init** and **fini** methods. Module data objects last for the
diff --git a/src/include/krb5/certauth_plugin.h b/src/include/krb5/certauth_plugin.h
index 3074790f8..3466cf345 100644
--- a/src/include/krb5/certauth_plugin.h
+++ b/src/include/krb5/certauth_plugin.h
@@ -85,14 +85,17 @@ typedef void
(*krb5_certauth_fini_fn)(krb5_context context, krb5_certauth_moddata moddata);
/*
- * Mandatory:
- * Return 0 if the DER-encoded cert is authorized for PKINIT authentication by
- * princ; otherwise return one of the following error codes:
+ * Mandatory: return 0 or KRB5_CERTAUTH_HWAUTH if the DER-encoded cert is
+ * authorized for PKINIT authentication by princ; otherwise return one of the
+ * following error codes:
* - KRB5KDC_ERR_CLIENT_NAME_MISMATCH - incorrect SAN value
* - KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE - incorrect EKU
* - KRB5KDC_ERR_CERTIFICATE_MISMATCH - other extension error
* - KRB5_PLUGIN_NO_HANDLE - the module has no opinion about cert
*
+ * Returning KRB5_CERTAUTH_HWAUTH will cause the hw-authent flag to be set in
+ * the issued ticket (new in release 1.19).
+ *
* - opts is used by built-in modules to receive internal data, and must be
* ignored by other modules.
* - db_entry receives the client principal database entry, and can be ignored
diff --git a/src/lib/krb5/error_tables/k5e1_err.et b/src/lib/krb5/error_tables/k5e1_err.et
index ade5caecf..abd9f3bfe 100644
--- a/src/lib/krb5/error_tables/k5e1_err.et
+++ b/src/lib/krb5/error_tables/k5e1_err.et
@@ -42,4 +42,5 @@ error_code KRB5_KCM_MALFORMED_REPLY, "Malformed reply from KCM daemon"
error_code KRB5_KCM_RPC_ERROR, "Mach RPC error communicating with KCM daemon"
error_code KRB5_KCM_REPLY_TOO_BIG, "KCM daemon reply too big"
error_code KRB5_KCM_NO_SERVER, "No KCM server found"
+error_code KRB5_CERTAUTH_HWAUTH, "Authorize and set hw-authent ticket flag"
end
diff --git a/src/plugins/certauth/test/Makefile.in b/src/plugins/certauth/test/Makefile.in
index d3524084c..e94c13845 100644
--- a/src/plugins/certauth/test/Makefile.in
+++ b/src/plugins/certauth/test/Makefile.in
@@ -5,8 +5,8 @@ LIBBASE=certauth_test
LIBMAJOR=0
LIBMINOR=0
RELDIR=../plugins/certauth/test
-SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS)
-SHLIB_EXPLIBS=$(KRB5_BASE_LIBS)
+SHLIB_EXPDEPS=$(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+SHLIB_EXPLIBS=$(KDB5_LIBS) $(KRB5_BASE_LIBS)
STLIBOBJS=main.o
diff --git a/src/plugins/certauth/test/main.c b/src/plugins/certauth/test/main.c
index 77641230c..d4633b8cd 100644
--- a/src/plugins/certauth/test/main.c
+++ b/src/plugins/certauth/test/main.c
@@ -31,6 +31,7 @@
*/
#include <k5-int.h>
+#include <kdb.h>
#include "krb5/certauth_plugin.h"
struct krb5_certauth_moddata_st {
@@ -131,7 +132,8 @@ has_cn(krb5_context context, const uint8_t *cert, size_t cert_len,
/*
* Test module 2 returns OK if princ matches the CN part of the subject name,
- * and returns indicators of the module name and princ.
+ * and returns indicators of the module name and princ. If the "hwauth" string
+ * attribute is set on db_entry, it returns KRB5_CERTAUTH_HWAUTH.
*/
static krb5_error_code
test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
@@ -141,7 +143,7 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
char ***authinds_out)
{
krb5_error_code ret;
- char *name = NULL, **ais = NULL;
+ char *name = NULL, *strval = NULL, **ais = NULL;
*authinds_out = NULL;
@@ -167,6 +169,11 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
ais = NULL;
+ ret = krb5_dbe_get_string(context, (krb5_db_entry *)db_entry, "hwauth",
+ &strval);
+ ret = (strval != NULL) ? KRB5_CERTAUTH_HWAUTH : 0;
+ krb5_dbe_free_string(context, strval);
+
cleanup:
krb5_free_unparsed_name(context, name);
return ret;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index feca11806..3ae56c064 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -320,12 +320,12 @@ static krb5_error_code
authorize_cert(krb5_context context, certauth_handle *certauth_modules,
pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx,
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
- krb5_principal client)
+ krb5_principal client, krb5_boolean *hwauth_out)
{
krb5_error_code ret;
certauth_handle h;
struct certauth_req_opts opts;
- krb5_boolean accepted = FALSE;
+ krb5_boolean accepted = FALSE, hwauth = FALSE;
uint8_t *cert;
size_t i, cert_len;
void *db_ent = NULL;
@@ -347,9 +347,10 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
/*
* Check the certificate against each certauth module. For the certificate
- * to be authorized at least one module must return 0, and no module can an
- * error code other than KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from
- * modules that return 0 or pass.
+ * to be authorized at least one module must return 0 or
+ * KRB5_CERTAUTH_HWAUTH, and no module can return an error code other than
+ * KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from modules that return 0
+ * or pass.
*/
ret = KRB5_PLUGIN_NO_HANDLE;
for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) {
@@ -359,6 +360,8 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
&opts, db_ent, &ais);
if (ret == 0)
accepted = TRUE;
+ else if (ret == KRB5_CERTAUTH_HWAUTH)
+ accepted = hwauth = TRUE;
else if (ret != KRB5_PLUGIN_NO_HANDLE)
goto cleanup;
@@ -374,6 +377,7 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
}
}
+ *hwauth_out = hwauth;
ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
cleanup:
@@ -430,7 +434,7 @@ pkinit_server_verify_padata(krb5_context context,
int is_signed = 1;
krb5_pa_data **e_data = NULL;
krb5_kdcpreauth_modreq modreq = NULL;
- krb5_boolean valid_freshness_token = FALSE;
+ krb5_boolean valid_freshness_token = FALSE, hwauth = FALSE;
char **sp;
pkiDebug("pkinit_verify_padata: entered!\n");
@@ -494,7 +498,7 @@ pkinit_server_verify_padata(krb5_context context,
}
if (is_signed) {
retval = authorize_cert(context, moddata->certauth_modules, plgctx,
- reqctx, cb, rock, request->client);
+ reqctx, cb, rock, request->client, &hwauth);
if (retval)
goto cleanup;
@@ -613,6 +617,8 @@ pkinit_server_verify_padata(krb5_context context,
/* remember to set the PREAUTH flag in the reply */
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
+ if (hwauth)
+ enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
modreq = (krb5_kdcpreauth_modreq)reqctx;
reqctx = NULL;
@@ -1044,7 +1050,9 @@ pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
{
if (patype == KRB5_PADATA_PKINIT_KX)
return PA_INFO;
- return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA;
+ /* PKINIT does not normally set the hw-authent ticket flag, but a
+ * certauth module can cause it to do so. */
+ return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA | PA_HARDWARE;
}
static krb5_preauthtype supported_server_pa_types[] = {
diff --git a/src/tests/t_certauth.py b/src/tests/t_certauth.py
index 9c7094525..0fe0fdb4a 100644
--- a/src/tests/t_certauth.py
+++ b/src/tests/t_certauth.py
@@ -43,4 +43,17 @@ out = realm.kinit("user2@KRBTEST.COM",
expected_code=1,
expected_msg='kinit: Certificate mismatch')
+# Test the KRB5_CERTAUTH_HWAUTH return code.
+mark('hw-authent flag tests')
+# First test +requires_hwauth without causing the hw-authent ticket
+# flag to be set. This currently results in a preauth loop.
+realm.run([kadminl, 'modprinc', '+requires_hwauth', realm.user_princ])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % file_identity],
+ expected_code=1, expected_msg='Looping detected')
+# Cause the test2 module to return KRB5_CERTAUTH_HWAUTH and try again.
+realm.run([kadminl, 'setstr', realm.user_princ, 'hwauth', 'x'])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % file_identity])
+
success("certauth tests")

View File

@ -0,0 +1,49 @@
From 594c9d225f470e73a46dd2a85c5e50571e90598c Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 11 Jul 2020 21:57:30 -0400
Subject: [PATCH] Allow gss_unwrap_iov() of unpadded RC4 tokens
Windows Remote Management, when used with an RC4 session key, appears
to generate GSS wrap tokens with no padding instead of the expected
one byte (RFC 4757 section 7.3). These tokens cannot be decoded with
gss_unwrap() or a STREAM buffer (even with Microsoft SSPI), but SSPI
allows them to be decoded using explicit IOVs with either a
zero-length padding buffer or no padding buffer. Allow these cases to
work in kg_fixup_padding_iov(). (It is already possible to make this
work with HEADER | DATA | DATA, but only by
accident--kg_fixup_padding_iov() doesn't find a data buffer because
kg_locate_iov() only looks for singleton buffers, so it exits early.)
ticket: 8926 (new)
tags: pullup
target_version: 1.18-next
(cherry picked from commit 3f204ddd567715ef360b4bb0b32961b6a9877f9d)
---
src/lib/gssapi/krb5/util_crypt.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c
index f7d3e92c4..d6c71aeb8 100644
--- a/src/lib/gssapi/krb5/util_crypt.c
+++ b/src/lib/gssapi/krb5/util_crypt.c
@@ -638,16 +638,13 @@ kg_fixup_padding_iov(OM_uint32 *minor_status, gss_iov_buffer_desc *iov,
data = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_DATA);
padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
- if (data == NULL) {
+ /* Do nothing if padding is absent or empty, to allow unwrapping of WinRM
+ * unpadded RC4 tokens using an explicit IOV array. */
+ if (data == NULL || padding == NULL || padding->buffer.length == 0) {
*minor_status = 0;
return GSS_S_COMPLETE;
}
- if (padding == NULL || padding->buffer.length == 0) {
- *minor_status = EINVAL;
- return GSS_S_FAILURE;
- }
-
p = (unsigned char *)padding->buffer.value;
padlength = p[padding->buffer.length - 1];

View File

@ -0,0 +1,52 @@
From f56afbeb7848322f3208edd55f2c12a9e32127f0 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 30 Mar 2020 15:26:02 -0400
Subject: [PATCH] Correctly import "service@" GSS host-based name
The intended way to specify only a service in a GSS host-based name is
to omit the "@" separator. Some applications include the separator
but no hostname, and this happened to yield wildcard hostname behavior
prior to commit 996353767fe8afa7f67a3b5b465e4d70e18bad7c when
shortname qualification was added. To restore this behavior, check in
parse_hostbased() that at least one character is present after the "@"
separator before copying the hostname. Add a test case to t_gssapi.py.
ticket: 8892
tags: pullup
target_version: 1.18-next
(cherry picked from commit a2f047af0400ba8080dc26033fae2b17534501e2)
---
src/lib/gssapi/krb5/import_name.c | 4 ++--
src/tests/gssapi/t_gssapi.py | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index da2ab1423..21023dd76 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -102,8 +102,8 @@ parse_hostbased(const char *str, size_t len,
memcpy(service, str, servicelen);
service[servicelen] = '\0';
- /* If present, copy the hostname. */
- if (at != NULL) {
+ /* Copy the hostname if present (at least one character after '@'). */
+ if (len - servicelen > 1) {
hostlen = len - servicelen - 1;
host = malloc(hostlen + 1);
if (host == NULL) {
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
index 54d5cf549..ecf982604 100755
--- a/src/tests/gssapi/t_gssapi.py
+++ b/src/tests/gssapi/t_gssapi.py
@@ -47,6 +47,9 @@ realm.run(['./t_accname', 'p:service2/calvin', 'h:service2'],
expected_msg='service2/calvin')
realm.run(['./t_accname', 'p:service2/calvin', 'h:service1'], expected_code=1,
expected_msg=' found in keytab but does not match server principal')
+# Regression test for #8892 (trailing @ in name).
+realm.run(['./t_accname', 'p:service1/andrew', 'h:service1@'],
+ expected_msg='service1/abraham')
# Test with acceptor name containing service and host. Use the
# client's un-canonicalized hostname as acceptor input to mirror what

View File

@ -0,0 +1,371 @@
From c3d2c3bcafe0ac87d9cbbf37f1488ad642627fc3 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 27 May 2020 18:48:35 -0400
Subject: [PATCH] Default dns_canonicalize_hostname to "fallback"
This change should mitigate some of the pain caused by the rdns=true
default (generally associated with unwanted PTR records that cannot
easily be changed), with a minimum of fallout.
Update the documentation and tests accordingly. In test environments,
disable qualify_shortname and use the uncanonicalized system hostname
(lowercased) to match the initial sn2princ result.
ticket: 8911 (new)
---
doc/admin/appl_servers.rst | 14 +++---
doc/admin/conf_files/krb5_conf.rst | 9 ++--
doc/admin/princ_dns.rst | 44 +++++++++++--------
src/kadmin/testing/proto/krb5.conf.proto | 8 ++--
src/kadmin/testing/scripts/env-setup.shin | 4 +-
src/kadmin/testing/scripts/init_db | 3 +-
src/kadmin/testing/scripts/start_servers | 3 +-
.../testing/scripts/start_servers_local | 2 +-
.../kadm5/unit-test/api.current/init-v2.exp | 6 +--
src/lib/krb5/krb/init_ctx.c | 2 +-
src/tests/dejagnu/config/default.exp | 5 +--
src/tests/t_sn2princ.py | 5 ++-
src/util/k5test.py | 25 +++--------
13 files changed, 58 insertions(+), 72 deletions(-)
diff --git a/doc/admin/appl_servers.rst b/doc/admin/appl_servers.rst
index 5232db9af..afdf30297 100644
--- a/doc/admin/appl_servers.rst
+++ b/doc/admin/appl_servers.rst
@@ -115,14 +115,12 @@ Getting DNS information correct
-------------------------------
Several aspects of Kerberos rely on name service. When a hostname is
-used to name a service, the Kerberos library canonicalizes the
-hostname using forward and reverse name resolution. (The reverse name
-resolution step can be turned off using the **rdns** variable in
-:ref:`libdefaults`.) The result of this canonicalization must match
-the principal entry in the host's keytab, or authentication will fail.
-
-Each host's canonical name must be the fully-qualified host name
-(including the domain), and each host's IP address must
+used to name a service, clients may canonicalize the hostname using
+forward and possibly reverse name resolution. The result of this
+canonicalization must match the principal entry in the host's keytab,
+or authentication will fail. To work with all client canonicalization
+configurations, each host's canonical name must be the fully-qualified
+host name (including the domain), and each host's IP address must
reverse-resolve to the canonical name.
Configuration of hostnames varies by operating system. On the
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 3a8b9cf47..38f450367 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -188,11 +188,10 @@ The libdefaults section may contain any of the following relations:
hostnames for use in service principal names. Setting this flag
to false can improve security by reducing reliance on DNS, but
means that short hostnames will not be canonicalized to
- fully-qualified hostnames. The default value is true.
-
- If this option is set to ``fallback`` (new in release 1.18), DNS
- canonicalization will only be performed the server hostname is not
- found with the original name when requesting credentials.
+ fully-qualified hostnames. If this option is set to ``fallback`` (new
+ in release 1.18), DNS canonicalization will only be performed the
+ server hostname is not found with the original name when
+ requesting credentials. The default value is ``fallback``.
**dns_lookup_kdc**
Indicate whether DNS SRV records should be used to locate the KDCs
diff --git a/doc/admin/princ_dns.rst b/doc/admin/princ_dns.rst
index e1d823f27..32a269afc 100644
--- a/doc/admin/princ_dns.rst
+++ b/doc/admin/princ_dns.rst
@@ -31,27 +31,35 @@ based on rotating ``CNAME`` records in DNS.
Service principal canonicalization
----------------------------------
-MIT Kerberos clients currently always do forward resolution (looking
-up the IPv4 and possibly IPv6 addresses using ``getaddrinfo()``) of
-the hostname part of a host-based service principal to canonicalize
-the hostname. They obtain the "canonical" name of the host when doing
-so. By default, MIT Kerberos clients will also then do reverse DNS
-resolution (looking up the hostname associated with the IPv4 or IPv6
-address using ``getnameinfo()``) of the hostname. Using the
-:ref:`krb5.conf(5)` setting::
+In the MIT krb5 client library, canonicalization of host-based service
+principals is controlled by the **dns_canonicalize_hostname**,
+**rnds**, and **qualify_shortname** variables in :ref:`libdefaults`.
- [libdefaults]
- rdns = false
+If **dns_canonicalize_hostname** is set to ``true`` (the default value
+before release 1.19), the client performs forward resolution by
+looking up the IPv4 and/or IPv6 addresses of the hostname using
+``getaddrinfo()``. This process will typically add a domain suffix to
+the hostname if needed, and follow CNAME records in the DNS. If
+**rdns** is also set to ``true`` (the default), the client will then
+perform a reverse lookup of the first returned Internet address using
+``getnameinfo()``, finding the name associated with the PTR record.
-will disable reverse DNS lookup on clients. The default setting is
-"true".
+If **dns_canonicalize_hostname** is set to ``false``, the hostname is
+not canonicalized using DNS. If the hostname has only one component
+(i.e. it contains no "." characters), the host's primary DNS search
+domain will be appended, if there is one. The **qualify_shortname**
+variable can be used to override or disable this suffix.
+
+If **dns_canonicalize_hostname** is set to ``fallback`` (the default
+value in release 1.19 and later), the hostname is initially treated
+according to the rules for ``dns_canonicalize_hostname=false``. If a
+ticket request fails because the service principal is unknown, it the
+hostname will be canonicalized according to the rules for
+``dns_canonicalize_hostname=true`` and the request will be retried.
+
+In all cases, the hostname is converted to lowercase, and any trailing
+dot is removed.
-Operating system bugs may prevent a setting of ``rdns = false`` from
-disabling reverse DNS lookup. Some versions of GNU libc have a bug in
-``getaddrinfo()`` that cause them to look up ``PTR`` records even when
-not required. MIT Kerberos releases krb5-1.10.2 and newer have a
-workaround for this problem, as does the krb5-1.9.x series as of
-release krb5-1.9.4.
Reverse DNS mismatches
diff --git a/src/kadmin/testing/proto/krb5.conf.proto b/src/kadmin/testing/proto/krb5.conf.proto
index e710852d4..c0af716a5 100644
--- a/src/kadmin/testing/proto/krb5.conf.proto
+++ b/src/kadmin/testing/proto/krb5.conf.proto
@@ -2,19 +2,19 @@
default_realm = __REALM__
default_keytab_name = FILE:__K5ROOT__/keytab
dns_fallback = no
+ qualify_shortname = ""
plugin_base_dir = __PLUGIN_DIR__
allow_weak_crypto = true
[realms]
__REALM__ = {
- kdc = __KDCHOST__:1750
- admin_server = __KDCHOST__:1751
+ kdc = __HOSTNAME__:1750
+ admin_server = __HOSTNAME__:1751
database_module = foobar_db2_module_blah
}
[domain_realm]
- __LOCALHOST__ = __REALM__
- __KDCHOST__ = __REALM__
+ __HOSTNAME__ = __REALM__
[logging]
admin_server = FILE:__K5ROOT__/syslog
diff --git a/src/kadmin/testing/scripts/env-setup.shin b/src/kadmin/testing/scripts/env-setup.shin
index 969c5340c..88f8ad1aa 100755
--- a/src/kadmin/testing/scripts/env-setup.shin
+++ b/src/kadmin/testing/scripts/env-setup.shin
@@ -71,8 +71,8 @@ BSDDB_DUMP=$TESTDIR/util/bsddb_dump; export BSDDB_DUMP
CLNTTCL=$TESTDIR/util/kadm5_clnt_tcl; export CLNTTCL
SRVTCL=$TESTDIR/util/kadm5_srv_tcl; export SRVTCL
-QUALNAME=`$BUILDTOP/tests/resolve/resolve -q | tr '[A-Z]' '[a-z]'`
-export QUALNAME
+HOSTNAME=`hostname | tr '[A-Z]' '[a-z]'`
+export HOSTNAME
KRB5_CONFIG=$K5ROOT/krb5.conf; export KRB5_CONFIG
KRB5_KDC_PROFILE=$K5ROOT/kdc.conf; export KRB5_KDC_PROFILE
diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db
index e65826c96..216f62793 100755
--- a/src/kadmin/testing/scripts/init_db
+++ b/src/kadmin/testing/scripts/init_db
@@ -79,8 +79,7 @@ fi
# done
sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
- -e "s/__KDCHOST__/$QUALNAME/g" \
- -e "s/__LOCALHOST__/$QUALNAME/g" \
+ -e "s/__HOSTNAME__/$HOSTNAME/g" \
-e "s#__MODDIR__#$MODDIR#g" \
< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
diff --git a/src/kadmin/testing/scripts/start_servers b/src/kadmin/testing/scripts/start_servers
index f23df0682..05519e4ee 100755
--- a/src/kadmin/testing/scripts/start_servers
+++ b/src/kadmin/testing/scripts/start_servers
@@ -36,8 +36,7 @@ if [ $local = 0 ]; then
# Fix up the local krb5.conf to point to the remote
sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
- -e "s/__KDCHOST__/$hostname/g" \
- -e "s/__LOCALHOST__/$QUALNAME/g" \
+ -e "s/__HOSTNAME__/$HOSTNAME/g" \
-e "s#__MODDIR__#$TOP/../plugins/kdb#g"\
-e "s#__PLUGIN_DIR__#$TOP/../plugins#g"\
< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
diff --git a/src/kadmin/testing/scripts/start_servers_local b/src/kadmin/testing/scripts/start_servers_local
index 998ef9164..858e88031 100755
--- a/src/kadmin/testing/scripts/start_servers_local
+++ b/src/kadmin/testing/scripts/start_servers_local
@@ -79,7 +79,7 @@ cat - > /tmp/start_servers_local$$ <<\EOF
if { [catch {
source $env(STOP)/testing/tcl/util.t
set r $env(REALM)
- set q $env(QUALNAME)
+ set q $env(HOSTNAME)
puts stdout [kadm5_init $env(SRVTCL) mrroot null \
[config_params {KADM5_CONFIG_REALM} $r] \
$KADM5_STRUCT_VERSION $KADM5_API_VERSION_3 server_handle]
diff --git a/src/lib/kadm5/unit-test/api.current/init-v2.exp b/src/lib/kadm5/unit-test/api.current/init-v2.exp
index 7a353d4e9..47764c212 100644
--- a/src/lib/kadm5/unit-test/api.current/init-v2.exp
+++ b/src/lib/kadm5/unit-test/api.current/init-v2.exp
@@ -3,18 +3,14 @@ load_lib lib.t
api_exit
api_start
-if ![info exists RESOLVE] {
- set RESOLVE [findfile $objdir/../../../tests/resolve/resolve]
-}
proc get_hostname { } {
- global RESOLVE
global hostname
if {[info exists hostname]} {
return 1
}
- catch "exec $RESOLVE -q >myname" exec_output
+ catch "exec hostname >myname" exec_output
if ![string match "" $exec_output] {
send_log "$exec_output\n"
verbose $exec_output
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index 9a4741fa6..0b8ae6714 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -237,7 +237,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
ctx->enforce_ok_as_delegate = tmp;
retval = get_tristate(ctx, KRB5_CONF_DNS_CANONICALIZE_HOSTNAME, "fallback",
- CANONHOST_FALLBACK, 1, &tmp);
+ CANONHOST_FALLBACK, CANONHOST_FALLBACK, &tmp);
if (retval)
goto cleanup;
ctx->dns_canonicalize_hostname = tmp;
diff --git a/src/tests/dejagnu/config/default.exp b/src/tests/dejagnu/config/default.exp
index 4d8c917cd..1e7777f1e 100644
--- a/src/tests/dejagnu/config/default.exp
+++ b/src/tests/dejagnu/config/default.exp
@@ -268,7 +268,6 @@ foreach i {
{KTUTIL $objdir/../../kadmin/ktutil/ktutil}
{KLIST $objdir/../../clients/klist/klist}
{KDESTROY $objdir/../../clients/kdestroy/kdestroy}
- {RESOLVE $objdir/../resolve/resolve}
{T_INETD $objdir/t_inetd}
{KPROPLOG $objdir/../../kprop/kproplog}
{KPASSWD $objdir/../../clients/kpasswd/kpasswd}
@@ -462,7 +461,6 @@ proc setup_runtime_env { } {
# 0 on failure.
proc get_hostname { } {
- global RESOLVE
global hostname
global tmppwd
@@ -472,7 +470,7 @@ proc get_hostname { } {
envstack_push
setup_runtime_env
- catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output
+ catch "exec hostname >$tmppwd/hostname" exec_output
envstack_pop
if ![string match "" $exec_output] {
verbose -log $exec_output
@@ -710,6 +708,7 @@ proc setup_krb5_conf { {type client} } {
puts $conffile "\[libdefaults\]"
puts $conffile " default_realm = $REALMNAME"
puts $conffile " dns_lookup_kdc = false"
+ puts $conffile " qualify_shortname = \"\""
if [info exists allow_weak_crypto($type)] {
puts $conffile " allow_weak_crypto = $allow_weak_crypto($type)"
} else {
diff --git a/src/tests/t_sn2princ.py b/src/tests/t_sn2princ.py
index 26dcb91c2..f3e187286 100755
--- a/src/tests/t_sn2princ.py
+++ b/src/tests/t_sn2princ.py
@@ -2,7 +2,8 @@ from k5test import *
offline = (len(args) > 0 and args[0] != "no")
-conf = {'domain_realm': {'kerberos.org': 'R1',
+conf = {'libdefaults': {'dns_canonicalize_hostname': 'true'},
+ 'domain_realm': {'kerberos.org': 'R1',
'example.com': 'R2',
'mit.edu': 'R3'}}
no_rdns_conf = {'libdefaults': {'rdns': 'false'}}
@@ -28,7 +29,7 @@ def testbase(host, nametype, princhost, princrealm, env=None):
fail('Expected %s, got %s' % (expected, out))
def test(host, princhost, princrealm):
- # Test with the host-based name type in the default environment.
+ # Test with the host-based name type with canonicalization enabled.
testbase(host, 'srv-hst', princhost, princrealm)
def testnc(host, princhost, princrealm):
diff --git a/src/util/k5test.py b/src/util/k5test.py
index eea92275d..5196cfa43 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -193,7 +193,10 @@ Scripts may use the following functions and variables:
* plugins: The plugin directory in the build tree (absolute path).
-* hostname: This machine's fully-qualified domain name.
+* hostname: The local hostname as it will initially appear in
+ krb5_sname_to_principal() results. (Shortname qualification is
+ turned off in the test environment to make this value easy to
+ discover from Python.)
* null_input: A file opened to read /dev/null.
@@ -525,23 +528,6 @@ def _find_srctop():
return os.path.abspath(root)
-# Return the local hostname as it will be canonicalized by
-# krb5_sname_to_principal. We can't simply use socket.getfqdn()
-# because it explicitly prefers results containing periods and
-# krb5_sname_to_principal doesn't care.
-def _get_hostname():
- hostname = socket.gethostname()
- try:
- ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
- except socket.gaierror as e:
- fail('Local hostname "%s" does not resolve: %s.' % (hostname, e[1]))
- (family, socktype, proto, canonname, sockaddr) = ai[0]
- try:
- name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
- except socket.gaierror:
- return canonname.lower()
- return name[0].lower()
-
# Parse command line arguments, setting global option variables. Also
# sets the global variable args to the positional arguments, which may
# be used by the test script.
@@ -1263,6 +1249,7 @@ _default_krb5_conf = {
'libdefaults': {
'default_realm': '$realm',
'dns_lookup_kdc': 'false',
+ 'qualify_shortname': '',
'plugin_base_dir': '$plugins'},
'realms': {'$realm': {
'kdc': '$hostname:$port0',
@@ -1356,7 +1343,7 @@ buildtop = _find_buildtop()
srctop = _find_srctop()
plugins = os.path.join(buildtop, 'plugins')
runenv = _import_runenv()
-hostname = _get_hostname()
+hostname = socket.gethostname().lower()
null_input = open(os.devnull, 'r')
# A DB pass is a tuple of: name, kdc_conf.

View File

@ -0,0 +1,425 @@
From 51a9f8e7498591b22558a7a61d42a821030f9c4e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 28 Feb 2020 10:11:49 +0100
Subject: [PATCH] Do expiration warnings for all init_creds APIs
Move the password expiration warning code from gic_pwd.c to
get_in_tkt.c. Call it from init_creds_step_reply() on successful
completion.
[ghudson@mit.edu: added test case; simplified doc comment; moved call
site to init_creds_step_reply(); rewrote commit message]
ticket: 8893 (new)
(cherry picked from commit e1efb890f7ac31b32c68ab816ef118dbfb5a8c7e)
---
src/include/krb5/krb5.hin | 9 ++-
src/lib/krb5/krb/get_in_tkt.c | 112 ++++++++++++++++++++++++++++++
src/lib/krb5/krb/gic_pwd.c | 110 -----------------------------
src/lib/krb5/krb/t_expire_warn.c | 47 +++++++++----
src/lib/krb5/krb/t_expire_warn.py | 22 ++++--
5 files changed, 165 insertions(+), 135 deletions(-)
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 6355e6540..f8269fb17 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -7174,11 +7174,10 @@ typedef void
*
* Set a callback to receive password and account expiration times.
*
- * This option only applies to krb5_get_init_creds_password(). @a cb will be
- * invoked if and only if credentials are successfully acquired. The callback
- * will receive the @a context from the krb5_get_init_creds_password() call and
- * the @a data argument supplied with this API. The remaining arguments should
- * be interpreted as follows:
+ * @a cb will be invoked if and only if credentials are successfully acquired.
+ * The callback will receive the @a context from the calling function and the
+ * @a data argument supplied with this API. The remaining arguments should be
+ * interpreted as follows:
*
* If @a is_last_req is true, then the KDC reply contained last-req entries
* which unambiguously indicated the password expiration, account expiration,
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 870df62a1..cc0f70e83 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1482,6 +1482,116 @@ accept_method_data(krb5_context context, krb5_init_creds_context ctx)
ctx->method_padata);
}
+/* Return the password expiry time indicated by enc_part2. Set *is_last_req
+ * if the information came from a last_req value. */
+static void
+get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
+ krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
+{
+ krb5_last_req_entry **last_req;
+ krb5_int32 lr_type;
+
+ *pw_exp = 0;
+ *acct_exp = 0;
+ *is_last_req = FALSE;
+
+ /* Look for last-req entries for password or account expiration. */
+ if (enc_part2->last_req) {
+ for (last_req = enc_part2->last_req; *last_req; last_req++) {
+ lr_type = (*last_req)->lr_type;
+ if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
+ lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
+ *is_last_req = TRUE;
+ *pw_exp = (*last_req)->value;
+ } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
+ lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
+ *is_last_req = TRUE;
+ *acct_exp = (*last_req)->value;
+ }
+ }
+ }
+
+ /* If we didn't find any, use the ambiguous key_exp field. */
+ if (*is_last_req == FALSE)
+ *pw_exp = enc_part2->key_exp;
+}
+
+/*
+ * Send an appropriate warning prompter if as_reply indicates that the password
+ * is going to expire soon. If an expire callback was provided, use that
+ * instead.
+ */
+static void
+warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
+ krb5_prompter_fct prompter, void *data,
+ const char *in_tkt_service, krb5_kdc_rep *as_reply)
+{
+ krb5_error_code ret;
+ krb5_expire_callback_func expire_cb;
+ void *expire_data;
+ krb5_timestamp pw_exp, acct_exp, now;
+ krb5_boolean is_last_req;
+ krb5_deltat delta;
+ char ts[256], banner[1024];
+
+ if (as_reply == NULL || as_reply->enc_part2 == NULL)
+ return;
+
+ get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
+
+ k5_gic_opt_get_expire_cb(options, &expire_cb, &expire_data);
+ if (expire_cb != NULL) {
+ /* Invoke the expire callback and don't send prompter warnings. */
+ (*expire_cb)(context, expire_data, pw_exp, acct_exp, is_last_req);
+ return;
+ }
+
+ /* Don't warn if no password expiry value was sent. */
+ if (pw_exp == 0)
+ return;
+
+ /* Don't warn if the password is being changed. */
+ if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
+ return;
+
+ /*
+ * If the expiry time came from a last_req field, assume the KDC wants us
+ * to warn. Otherwise, warn only if the expiry time is less than a week
+ * from now.
+ */
+ ret = krb5_timeofday(context, &now);
+ if (ret != 0)
+ return;
+ if (!is_last_req &&
+ (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
+ return;
+
+ if (!prompter)
+ return;
+
+ ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
+ if (ret != 0)
+ return;
+
+ delta = ts_delta(pw_exp, now);
+ if (delta < 3600) {
+ snprintf(banner, sizeof(banner),
+ _("Warning: Your password will expire in less than one hour "
+ "on %s"), ts);
+ } else if (delta < 86400 * 2) {
+ snprintf(banner, sizeof(banner),
+ _("Warning: Your password will expire in %d hour%s on %s"),
+ delta / 3600, delta < 7200 ? "" : "s", ts);
+ } else {
+ snprintf(banner, sizeof(banner),
+ _("Warning: Your password will expire in %d days on %s"),
+ delta / 86400, ts);
+ }
+
+ /* PROMPTER_INVOCATION */
+ (*prompter)(context, data, 0, banner, 0, 0);
+}
+
static krb5_error_code
init_creds_step_reply(krb5_context context,
krb5_init_creds_context ctx,
@@ -1693,6 +1803,8 @@ init_creds_step_reply(krb5_context context,
/* success */
ctx->complete = TRUE;
+ warn_pw_expiry(context, ctx->opt, ctx->prompter, ctx->prompter_data,
+ ctx->in_tkt_service, ctx->reply);
cleanup:
krb5_free_pa_data(context, kdc_padata);
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index 14ce23ba4..54e0a8ebe 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -133,113 +133,6 @@ krb5_init_creds_set_password(krb5_context context,
return 0;
}
-/* Return the password expiry time indicated by enc_part2. Set *is_last_req
- * if the information came from a last_req value. */
-static void
-get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
- krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
-{
- krb5_last_req_entry **last_req;
- krb5_int32 lr_type;
-
- *pw_exp = 0;
- *acct_exp = 0;
- *is_last_req = FALSE;
-
- /* Look for last-req entries for password or account expiration. */
- if (enc_part2->last_req) {
- for (last_req = enc_part2->last_req; *last_req; last_req++) {
- lr_type = (*last_req)->lr_type;
- if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
- lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
- *is_last_req = TRUE;
- *pw_exp = (*last_req)->value;
- } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
- lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
- *is_last_req = TRUE;
- *acct_exp = (*last_req)->value;
- }
- }
- }
-
- /* If we didn't find any, use the ambiguous key_exp field. */
- if (*is_last_req == FALSE)
- *pw_exp = enc_part2->key_exp;
-}
-
-/*
- * Send an appropriate warning prompter if as_reply indicates that the password
- * is going to expire soon. If an expire callback was provided, use that
- * instead.
- */
-static void
-warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
- krb5_prompter_fct prompter, void *data,
- const char *in_tkt_service, krb5_kdc_rep *as_reply)
-{
- krb5_error_code ret;
- krb5_expire_callback_func expire_cb;
- void *expire_data;
- krb5_timestamp pw_exp, acct_exp, now;
- krb5_boolean is_last_req;
- krb5_deltat delta;
- char ts[256], banner[1024];
-
- get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
-
- k5_gic_opt_get_expire_cb(options, &expire_cb, &expire_data);
- if (expire_cb != NULL) {
- /* Invoke the expire callback and don't send prompter warnings. */
- (*expire_cb)(context, expire_data, pw_exp, acct_exp, is_last_req);
- return;
- }
-
- /* Don't warn if no password expiry value was sent. */
- if (pw_exp == 0)
- return;
-
- /* Don't warn if the password is being changed. */
- if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
- return;
-
- /*
- * If the expiry time came from a last_req field, assume the KDC wants us
- * to warn. Otherwise, warn only if the expiry time is less than a week
- * from now.
- */
- ret = krb5_timeofday(context, &now);
- if (ret != 0)
- return;
- if (!is_last_req &&
- (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
- return;
-
- if (!prompter)
- return;
-
- ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
- if (ret != 0)
- return;
-
- delta = ts_delta(pw_exp, now);
- if (delta < 3600) {
- snprintf(banner, sizeof(banner),
- _("Warning: Your password will expire in less than one hour "
- "on %s"), ts);
- } else if (delta < 86400*2) {
- snprintf(banner, sizeof(banner),
- _("Warning: Your password will expire in %d hour%s on %s"),
- delta / 3600, delta < 7200 ? "" : "s", ts);
- } else {
- snprintf(banner, sizeof(banner),
- _("Warning: Your password will expire in %d days on %s"),
- delta / 86400, ts);
- }
-
- /* PROMPTER_INVOCATION */
- (*prompter)(context, data, 0, banner, 0, 0);
-}
-
/*
* Create a temporary options structure for getting a kadmin/changepw ticket,
* based on the appplication-specified options. Propagate all application
@@ -496,9 +389,6 @@ krb5_get_init_creds_password(krb5_context context,
goto cleanup;
cleanup:
- if (ret == 0)
- warn_pw_expiry(context, options, prompter, data, in_tkt_service,
- as_reply);
free(chpw_opts);
zapfree(gakpw.storage.data, gakpw.storage.length);
memset(pw0array, 0, sizeof(pw0array));
diff --git a/src/lib/krb5/krb/t_expire_warn.c b/src/lib/krb5/krb/t_expire_warn.c
index 1e59acba1..dc8dc8fb3 100644
--- a/src/lib/krb5/krb/t_expire_warn.c
+++ b/src/lib/krb5/krb/t_expire_warn.c
@@ -28,6 +28,13 @@
static int exp_dummy, prompt_dummy;
+static void
+check(krb5_error_code code)
+{
+ if (code != 0)
+ abort();
+}
+
static krb5_error_code
prompter_cb(krb5_context ctx, void *data, const char *name,
const char *banner, int num_prompts, krb5_prompt prompts[])
@@ -52,36 +59,48 @@ int
main(int argc, char **argv)
{
krb5_context ctx;
+ krb5_init_creds_context icctx;
krb5_get_init_creds_opt *opt;
char *user, *password, *service = NULL;
- krb5_boolean use_cb;
+ krb5_boolean use_cb, stepwise;
krb5_principal client;
krb5_creds creds;
- if (argc < 4) {
- fprintf(stderr, "Usage: %s username password {1|0} [service]\n",
+ if (argc < 5) {
+ fprintf(stderr, "Usage: %s username password {1|0} {1|0} [service]\n",
argv[0]);
return 1;
}
user = argv[1];
password = argv[2];
use_cb = atoi(argv[3]);
- if (argc >= 5)
- service = argv[4];
+ stepwise = atoi(argv[4]);
+ if (argc >= 6)
+ service = argv[5];
- assert(krb5_init_context(&ctx) == 0);
- assert(krb5_get_init_creds_opt_alloc(ctx, &opt) == 0);
+ check(krb5_init_context(&ctx));
+ check(krb5_get_init_creds_opt_alloc(ctx, &opt));
if (use_cb) {
- assert(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
- &exp_dummy) == 0);
+ check(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
+ &exp_dummy));
+ }
+ check(krb5_parse_name(ctx, user, &client));
+ if (stepwise) {
+ check(krb5_init_creds_init(ctx, client, prompter_cb, &prompt_dummy, 0,
+ opt, &icctx));
+ krb5_init_creds_set_password(ctx, icctx, password);
+ if (service != NULL)
+ check(krb5_init_creds_set_service(ctx, icctx, service));
+ check(krb5_init_creds_get(ctx, icctx));
+ krb5_init_creds_free(ctx, icctx);
+ } else {
+ check(krb5_get_init_creds_password(ctx, &creds, client, password,
+ prompter_cb, &prompt_dummy, 0,
+ service, opt));
+ krb5_free_cred_contents(ctx, &creds);
}
- assert(krb5_parse_name(ctx, user, &client) == 0);
- assert(krb5_get_init_creds_password(ctx, &creds, client, password,
- prompter_cb, &prompt_dummy, 0, service,
- opt) == 0);
krb5_get_init_creds_opt_free(ctx, opt);
krb5_free_principal(ctx, client);
- krb5_free_cred_contents(ctx, &creds);
krb5_free_context(ctx);
return 0;
}
diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py
index 781f2728a..e163cc7e4 100755
--- a/src/lib/krb5/krb/t_expire_warn.py
+++ b/src/lib/krb5/krb/t_expire_warn.py
@@ -34,23 +34,33 @@ realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '12 hours',
realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days'])
# Check for expected prompter warnings when no expire callback is used.
-output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0'])
+output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0', '0'])
if output:
fail('Unexpected output for noexpire')
-realm.run(['./t_expire_warn', 'minutes', 'pass', '0'],
+realm.run(['./t_expire_warn', 'minutes', 'pass', '0', '0'],
expected_msg=' less than one hour on ')
-realm.run(['./t_expire_warn', 'hours', 'pass', '0'], expected_msg=' hours on ')
-realm.run(['./t_expire_warn', 'days', 'pass', '0'], expected_msg=' days on ')
+realm.run(['./t_expire_warn', 'hours', 'pass', '0', '0'],
+ expected_msg=' hours on ')
+realm.run(['./t_expire_warn', 'days', 'pass', '0', '0'],
+ expected_msg=' days on ')
+# Try one case with the stepwise interface.
+realm.run(['./t_expire_warn', 'days', 'pass', '0', '1'],
+ expected_msg=' days on ')
# Check for expected expire callback behavior. These tests are
# carefully agnostic about whether the KDC supports last_req fields,
# and could be made more specific if last_req support is added.
-output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '1'])
+output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '1', '0'])
if 'password_expiration = 0\n' not in output or \
'account_expiration = 0\n' not in output or \
'is_last_req = ' not in output:
fail('Expected callback output not seen for noexpire')
-output = realm.run(['./t_expire_warn', 'days', 'pass', '1'])
+output = realm.run(['./t_expire_warn', 'days', 'pass', '1', '0'])
+if 'password_expiration = ' not in output or \
+ 'password_expiration = 0\n' in output:
+ fail('Expected non-zero password expiration not seen for days')
+# Try one case with the stepwise interface.
+output = realm.run(['./t_expire_warn', 'days', 'pass', '1', '1'])
if 'password_expiration = ' not in output or \
'password_expiration = 0\n' in output:
fail('Expected non-zero password expiration not seen for days')

View File

@ -0,0 +1,93 @@
From b27a2f1f330afed53b034a66031f9a801b4568b7 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 23 Mar 2020 19:10:03 -0400
Subject: [PATCH] Eliminate redundant PKINIT responder invocation
In pkinit_client_prep_questions(), only act if the input padata type
is KRB5_PADATA_PK_AS_REQ. Otherwise we will ask questions again when
the KDC issues a ticket.
Commit 7621d2f9a87214327ca3b2594e34dc7cea84596b (ticket 8242)
unintentionally changed the behavior of pkinit_load_fs_cert_and_key(),
causing pkinit_client_prep_questions() to do nothing on its first
call. Restore the original behavior of returning 0 when prompting is
deferred.
Modify the existing "FILE identity, password on key (responder)"
PKINIT test to check that the responder is only invoked once.
ticket: 8885
(cherry picked from commit f1286842ce7b9e507a4ce0a47f44ab361a98be63)
---
src/plugins/preauth/pkinit/pkinit_clnt.c | 5 +++++
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 13 +++++++------
src/tests/t_pkinit.py | 11 +++++++----
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index 2f0431991..9b991ffe0 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -897,6 +897,11 @@ pkinit_client_prep_questions(krb5_context context,
k5_json_object jval = NULL;
k5_json_number jflag = NULL;
+ /* Don't ask questions for the informational padata items or when the
+ * ticket is issued. */
+ if (pa_data->pa_type != KRB5_PADATA_PK_AS_REQ)
+ return 0;
+
if (!reqctx->identity_initialized) {
pkinit_client_profile(context, plgctx, reqctx, cb, rock,
&request->server->realm);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index dd718c2be..dbb054378 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -4362,17 +4362,18 @@ pkinit_load_fs_cert_and_key(krb5_context context,
/* Load the certificate. */
retval = get_cert(certname, &x);
- if (retval != 0 || x == NULL) {
- retval = oerr(context, 0, _("Cannot read certificate file '%s'"),
+ if (retval) {
+ retval = oerr(context, retval, _("Cannot read certificate file '%s'"),
certname);
- goto cleanup;
}
+ if (retval || x == NULL)
+ goto cleanup;
/* Load the key. */
retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
- if (retval != 0 || y == NULL) {
- retval = oerr(context, 0, _("Cannot read key file '%s'"), fsname);
+ if (retval)
+ retval = oerr(context, retval, _("Cannot read key file '%s'"), fsname);
+ if (retval || y == NULL)
goto cleanup;
- }
id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
if (id_cryptoctx->creds[cindex] == NULL) {
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index 69daf4987..ecd450e8a 100755
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -248,10 +248,13 @@ realm.run(['./adata', realm.host_princ],
# supplied by the responder.
# Supply the response in raw form.
mark('FILE identity, password on key (responder)')
-realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
- '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
- '-X', 'X509_user_identity=%s' % file_enc_identity,
- realm.user_princ])
+out = realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
+ '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
+ '-X', 'X509_user_identity=%s' % file_enc_identity,
+ realm.user_princ])
+# Regression test for #8885 (password question asked twice).
+if out.count('OK: ') != 1:
+ fail('Wrong number of responder calls')
# Supply the response through the convenience API.
realm.run(['./responder', '-X', 'X509_user_identity=%s' % file_enc_identity,
'-p', '%s=%s' % (file_enc_identity, 'encrypted'), realm.user_princ])

View File

@ -0,0 +1,58 @@
From 5b42970afea248889fd3350448a40045d467ff3f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 28 Jul 2020 12:58:26 -0400
Subject: [PATCH] Fix input length checking in SPNEGO DER decoding
In get_mech_set(), check the length before reading the first byte, and
decrease the length by the tag byte when reading and verifying the
sequence length.
In get_req_flags(), check the length before reading the first byte,
and check the context tag length after decoding it.
ticket: 8933 (new)
tags: pullup
target_version: 1.18-next
target_version: 1.17-next
(cherry picked from commit 64f4b75a22212681ca293f8f09ddd24b0244d5b4)
---
src/lib/gssapi/spnego/spnego_mech.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 4cf011143..13c351620 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -3462,14 +3462,14 @@ get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in,
unsigned char *start;
int i;
- if (**buff_in != SEQUENCE_OF)
+ if (buff_length < 1 || **buff_in != SEQUENCE_OF)
return (NULL);
start = *buff_in;
(*buff_in)++;
- length = gssint_get_der_length(buff_in, buff_length, &bytes);
- if (length < 0 || buff_length - bytes < (unsigned int)length)
+ length = gssint_get_der_length(buff_in, buff_length - 1, &bytes);
+ if (length < 0 || buff_length - 1 - bytes < (unsigned int)length)
return NULL;
major_status = gss_create_empty_oid_set(minor_status,
@@ -3549,11 +3549,11 @@ get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
{
unsigned int len;
- if (**buff_in != (CONTEXT | 0x01))
+ if (bodysize < 1 || **buff_in != (CONTEXT | 0x01))
return (0);
if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
- bodysize, &len) < 0)
+ bodysize, &len) < 0 || len != 4)
return GSS_S_DEFECTIVE_TOKEN;
if (*(*buff_in)++ != BIT_STRING)

View File

@ -0,0 +1,59 @@
From ff47523d7d812fba24106f416aafa5d1f2c433a2 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 24 Jul 2020 16:05:24 -0400
Subject: [PATCH] Fix leak in KERB_AP_OPTIONS_CBT server support
In check_cbt(), use a local variable to hold the retrieved authdata
list, and free it before returning.
ticket: 8900
(cherry picked from commit bf2ddff13c178e0c291f8fb382b040080d159e4f)
---
src/lib/gssapi/krb5/accept_sec_context.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 175a24c4e..3d5b84b15 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -433,27 +433,30 @@ static const uint8_t null_cb[CB_MD5_LEN];
/* Look for AP_OPTIONS in authdata. If present and the options include
* KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
static krb5_error_code
-check_cbt(krb5_context context, krb5_authdata **authdata,
+check_cbt(krb5_context context, krb5_authdata *const *authdata,
krb5_boolean *cbt_out)
{
krb5_error_code code;
+ krb5_authdata **ad;
uint32_t ad_ap_options;
const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
*cbt_out = FALSE;
code = krb5_find_authdata(context, NULL, authdata,
- KRB5_AUTHDATA_AP_OPTIONS, &authdata);
- if (code || authdata == NULL)
+ KRB5_AUTHDATA_AP_OPTIONS, &ad);
+ if (code || ad == NULL)
return code;
- if (authdata[1] != NULL || authdata[0]->length != 4)
- return KRB5KRB_AP_ERR_MSG_TYPE;
+ if (ad[1] != NULL || ad[0]->length != 4) {
+ code = KRB5KRB_AP_ERR_MSG_TYPE;
+ } else {
+ ad_ap_options = load_32_le(ad[0]->contents);
+ if (ad_ap_options & KERB_AP_OPTIONS_CBT)
+ *cbt_out = TRUE;
+ }
- ad_ap_options = load_32_le(authdata[0]->contents);
- if (ad_ap_options & KERB_AP_OPTIONS_CBT)
- *cbt_out = TRUE;
-
- return 0;
+ krb5_free_authdata(context, ad);
+ return code;
}
/*

View File

@ -0,0 +1,37 @@
From bf8567ed95991628f198e88403e30f78e2d74e15 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 14 May 2020 15:01:18 -0400
Subject: [PATCH] Fix typo ("in in") in the ksu man page
(cherry picked from commit 1011841acdc1020f308ef4f569c6622f279d8c3f)
---
doc/user/user_commands/ksu.rst | 2 +-
src/man/ksu.man | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/user/user_commands/ksu.rst b/doc/user/user_commands/ksu.rst
index 8d6c7ef79..933738229 100644
--- a/doc/user/user_commands/ksu.rst
+++ b/doc/user/user_commands/ksu.rst
@@ -155,7 +155,7 @@ wrong password is typed in, ksu fails.
.. note::
During authentication, only the tickets that could be
- obtained without providing a password are cached in in the
+ obtained without providing a password are cached in the
source cache.
diff --git a/src/man/ksu.man b/src/man/ksu.man
index 81e34815d..8d4c6a359 100644
--- a/src/man/ksu.man
+++ b/src/man/ksu.man
@@ -176,7 +176,7 @@ wrong password is typed in, ksu fails.
.INDENT 0.0
.INDENT 3.5
During authentication, only the tickets that could be
-obtained without providing a password are cached in in the
+obtained without providing a password are cached in the
source cache.
.UNINDENT
.UNINDENT

View File

@ -0,0 +1,37 @@
From e74f9424e47ab914c46e549fc5a2cbdf2615ef93 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 15 Jul 2020 15:42:20 -0400
Subject: [PATCH] Ignore bad enctypes in krb5_string_to_keysalts()
Fixes a problem where the presence of legacy/unrecognized keysalts in
supported_enctypes would prevent the kadmin programs from starting.
[ghudson@mit.edu: ideally we would put a warning in the kadmind log,
but that is difficult to do when the parsing is done inside a library.
Even adding a trace log is difficult because the kadm5 str_conv
functions do not accept contexts.]
ticket: 8929 (new)
(cherry picked from commit be5396ada0e8dabd68bd0aceb733cfca39a609bc)
---
src/lib/kadm5/str_conv.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c
index 7cf51d316..798295606 100644
--- a/src/lib/kadm5/str_conv.c
+++ b/src/lib/kadm5/str_conv.c
@@ -340,9 +340,10 @@ krb5_string_to_keysalts(const char *string, const char *tupleseps,
while ((ksp = strtok_r(p, tseps, &tlasts)) != NULL) {
/* Pass a null pointer to subsequent calls to strtok_r(). */
p = NULL;
- ret = string_to_keysalt(ksp, ksaltseps, &etype, &stype);
- if (ret)
- goto cleanup;
+
+ /* Discard unrecognized keysalts. */
+ if (string_to_keysalt(ksp, ksaltseps, &etype, &stype) != 0)
+ continue;
/* Ignore duplicate keysalts if caller asks. */
if (!dups && krb5_keysalt_is_present(ksalts, nksalts, etype, stype))

View File

@ -0,0 +1,91 @@
From 651b9b8084ecff5553b7ef6ee723ce7c4438a9d8 Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Wed, 5 Jul 2017 11:38:30 -0400
Subject: [PATCH] Implement GSS_C_CHANNEL_BOUND_FLAG
Define a new channel-bound GSS return flag, and set it in the krb5
mech if the initiator sent channel bindings matching the acceptor's.
Do not error out if the acceptor specifies channel bindings and the
initiator does not send them.
[ghudson@mit.edu: simplified code changes; fleshed out commit message]
[iboukris: cherry-picked from another PR and reduced in scope]
ticket: 8899 (new)
(cherry picked from commit 429a31146083fac21958631c2af572b08ec91022)
---
src/lib/gssapi/generic/gssapi_ext.h | 2 ++
src/lib/gssapi/krb5/accept_sec_context.c | 18 +++++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
index 218456e44..c675e8ebb 100644
--- a/src/lib/gssapi/generic/gssapi_ext.h
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -595,6 +595,8 @@ gss_store_cred_into(
* attribute (along with any applicable RFC 5587 attributes).
*/
+#define GSS_C_CHANNEL_BOUND_FLAG 2048 /* 0x00000800 */
+
OM_uint32 KRB5_CALLCONV
gssspi_query_meta_data(
OM_uint32 *minor_status,
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 70dd7fc0c..9d3e2f4fe 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -427,6 +427,9 @@ kg_process_extension(krb5_context context,
GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
+/* A zero-value channel binding, for comparison */
+static const uint8_t null_cb[CB_MD5_LEN];
+
/*
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
* 4120 to store structured data instead of a checksum, indicated with checksum
@@ -435,9 +438,10 @@ kg_process_extension(krb5_context context,
*
* Interpret the checksum. Read delegated creds into *deleg_out if it is not
* NULL. Set *flags_out to the allowed subset of token flags, plus
- * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
- * extensions found using exts. On error, set *code_out to a krb5_error code
- * for use as a minor status value.
+ * GSS_C_DELEG_FLAG if a delegated credential was present and
+ * GSS_C_CHANNEL_BOUND_FLAG if matching channel bindings are present. Process
+ * any extensions found using exts. On error, set *code_out to a krb5_error
+ * code for use as a minor status value.
*/
static OM_uint32
process_checksum(OM_uint32 *minor_status, krb5_context context,
@@ -450,7 +454,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
krb5_error_code code = 0;
OM_uint32 status, option_id, token_flags;
size_t cb_len, option_len;
- krb5_boolean valid;
+ krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
krb5_key subkey;
krb5_data option, empty = empty_data();
krb5_checksum cb_cksum;
@@ -516,7 +520,9 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
goto fail;
}
assert(cb_cksum.length == cb_len);
- if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
+ token_cb_present = (k5_bcmp(token_cb, null_cb, cb_len) != 0);
+ cb_match = (k5_bcmp(token_cb, cb_cksum.contents, cb_len) == 0);
+ if (token_cb_present && !cb_match) {
status = GSS_S_BAD_BINDINGS;
goto fail;
}
@@ -525,6 +531,8 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
/* Read the token flags and accept some of them as context flags. */
token_flags = k5_input_get_uint32_le(&in);
*flags_out = token_flags & INITIATOR_FLAGS;
+ if (cb_match)
+ *flags_out |= GSS_C_CHANNEL_BOUND_FLAG;
/* Read the delegated credential if present. */
if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {

View File

@ -0,0 +1,102 @@
From bc89c6c720c4170d43010fead23550b80499c32a Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Mon, 9 Mar 2020 16:04:21 +0100
Subject: [PATCH] Implement KERB_AP_OPTIONS_CBT (server side)
Add server support for Microsoft's KERB_AP_OPTIONS_CBT as described in
MS-KILE. If the client includes the AP option in the authenticator
authdata and the server passed channel bindings, require the bindings
to match.
[ghudson@mit.edu: refactored to put more logic in the helper function;
added a comment; clarified commit message]
ticket: 8900 (new)
(cherry picked from commit 4f7c77b64a048ca5e3199b26b31493698c777a9c)
---
src/include/krb5/krb5.hin | 1 +
src/lib/gssapi/krb5/accept_sec_context.c | 45 +++++++++++++++++++++++-
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index f8269fb17..9264bede1 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -1915,6 +1915,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
#define KRB5_AUTHDATA_SIGNTICKET 512 /**< formerly 142 in krb5 1.8 */
#define KRB5_AUTHDATA_FX_ARMOR 71
#define KRB5_AUTHDATA_AUTH_INDICATOR 97
+#define KRB5_AUTHDATA_AP_OPTIONS 143
/** @} */ /* end of KRB5_AUTHDATA group */
/* password change constants */
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 9d3e2f4fe..175a24c4e 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -430,6 +430,32 @@ kg_process_extension(krb5_context context,
/* A zero-value channel binding, for comparison */
static const uint8_t null_cb[CB_MD5_LEN];
+/* Look for AP_OPTIONS in authdata. If present and the options include
+ * KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
+static krb5_error_code
+check_cbt(krb5_context context, krb5_authdata **authdata,
+ krb5_boolean *cbt_out)
+{
+ krb5_error_code code;
+ uint32_t ad_ap_options;
+ const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
+
+ *cbt_out = FALSE;
+
+ code = krb5_find_authdata(context, NULL, authdata,
+ KRB5_AUTHDATA_AP_OPTIONS, &authdata);
+ if (code || authdata == NULL)
+ return code;
+ if (authdata[1] != NULL || authdata[0]->length != 4)
+ return KRB5KRB_AP_ERR_MSG_TYPE;
+
+ ad_ap_options = load_32_le(authdata[0]->contents);
+ if (ad_ap_options & KERB_AP_OPTIONS_CBT)
+ *cbt_out = TRUE;
+
+ return 0;
+}
+
/*
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
* 4120 to store structured data instead of a checksum, indicated with checksum
@@ -454,7 +480,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
krb5_error_code code = 0;
OM_uint32 status, option_id, token_flags;
size_t cb_len, option_len;
- krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
+ krb5_boolean valid, client_cbt, token_cb_present = FALSE, cb_match = FALSE;
krb5_key subkey;
krb5_data option, empty = empty_data();
krb5_checksum cb_cksum;
@@ -582,6 +608,23 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
}
}
+ /*
+ * If the client asserts the KERB_AP_OPTIONS_CBT flag (from MS-KILE) in the
+ * authenticator authdata, and the acceptor passed channel bindings,
+ * require matching channel bindings from the client. The intent is to
+ * prevent an authenticator generated for use outside of a TLS channel from
+ * being used inside of one.
+ */
+ code = check_cbt(context, authenticator->authorization_data, &client_cbt);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if (client_cbt && acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS && !cb_match) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
status = GSS_S_COMPLETE;
fail:

View File

@ -0,0 +1,30 @@
From 4c96c8fef146337b7d3c0ebb4118a18818dd1f4e Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 9 Jun 2020 16:23:37 -0400
Subject: [PATCH] Improve negoex_parse_token() code hygiene
If the while loop in negoex_parse_token() runs for zero iterations,
major will be used initialized. Currently this cannot happen, but
only because both of the call sites check for zero-length tokens.
Initialize major for safety.
[ghudson@mit.edu: rewrote commit message]
(cherry picked from commit 4f91b6f8fa6fe1de662b3fdac0d59b7758ec642a)
---
src/lib/gssapi/spnego/negoex_util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/gssapi/spnego/negoex_util.c b/src/lib/gssapi/spnego/negoex_util.c
index 700368456..99580fd79 100644
--- a/src/lib/gssapi/spnego/negoex_util.c
+++ b/src/lib/gssapi/spnego/negoex_util.c
@@ -454,7 +454,7 @@ negoex_parse_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
gss_const_buffer_t token,
struct negoex_message **messages_out, size_t *count_out)
{
- OM_uint32 major;
+ OM_uint32 major = GSS_S_COMPLETE;
size_t count = 0;
struct k5input in;
struct negoex_message *messages = NULL, *newptr;

View File

@ -0,0 +1,48 @@
From f0ac5c1efef5401f669dc176e62c09b0b01fa2d0 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 6 May 2020 16:03:13 -0400
Subject: [PATCH] Omit KDC indicator check for S4U2Self requests
As there was no initial ticket exchange from the client for an
S4U2Self request, the auth indicator check is inapplicable (and would
always fail if any auth indicators are required).
ticket: 8902 (new)
(cherry picked from commit 183631fbf72351c2d5fc7d60b2d9fc4d09fe7465)
---
src/kdc/do_tgs_req.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 241f34e2a..463a9c0dd 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -392,8 +392,8 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
}
authtime = subject_tkt->times.authtime;
- /* Extract auth indicators from the subject ticket, except for S4U2Self
- * requests (where the client didn't authenticate). */
+ /* Extract and check auth indicators from the subject ticket, except for
+ * S4U2Self requests (where the client didn't authenticate). */
if (s4u_x509_user == NULL) {
errcode = get_auth_indicators(kdc_context, subject_tkt, local_tgt,
&local_tgt_key, &auth_indicators);
@@ -401,12 +401,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
status = "GET_AUTH_INDICATORS";
goto cleanup;
}
- }
- errcode = check_indicators(kdc_context, server, auth_indicators);
- if (errcode) {
- status = "HIGHER_AUTHENTICATION_REQUIRED";
- goto cleanup;
+ errcode = check_indicators(kdc_context, server, auth_indicators);
+ if (errcode) {
+ status = "HIGHER_AUTHENTICATION_REQUIRED";
+ goto cleanup;
+ }
}
if (is_referral)

View File

@ -0,0 +1,34 @@
From 5251097c927f476fe83ffe544b73fd2d785aaf2a Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Sat, 6 Jun 2020 11:03:37 +0200
Subject: [PATCH] Omit PA_FOR_USER if we can't compute its checksum
OpenSSL in FIPS mode will refuse to perform hmac-md5. Omit the legacy
PA_FOR_USER element in this case rather than failing out.
[ghudson@mit.edu: minor code and comment edits; wrote commit message]
ticket: 8912 (new)
(cherry picked from commit 03f122bdb22cfa53c7d855ed929c9541e56365e0)
---
src/lib/krb5/krb/s4u_creds.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
index fc5c886d6..d8f486dc6 100644
--- a/src/lib/krb5/krb/s4u_creds.c
+++ b/src/lib/krb5/krb/s4u_creds.c
@@ -534,6 +534,13 @@ krb5_get_self_cred_from_kdc(krb5_context context,
if (s4u_user.user_id.user != NULL && s4u_user.user_id.user->length) {
code = build_pa_for_user(context, tgtptr, &s4u_user.user_id,
&in_padata[1]);
+ /*
+ * If we couldn't compute the hmac-md5 checksum, send only the
+ * KRB5_PADATA_S4U_X509_USER; this will still work against modern
+ * Windows and MIT KDCs.
+ */
+ if (code == KRB5_CRYPTO_INTERNAL)
+ code = 0;
if (code != 0) {
krb5_free_pa_data(context, in_padata);
goto cleanup;

View File

@ -0,0 +1,256 @@
From 17d9b74328f247de5f9d820ae008726632d11d2a Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 28 Apr 2020 18:15:55 +0200
Subject: [PATCH] Pass channel bindings through SPNEGO
ticket: 8907 (new)
(cherry picked from commit d16325a24c34ec9a5f6fb4910987f162e0d4d9cd)
---
src/lib/gssapi/spnego/gssapiP_negoex.h | 8 ++---
src/lib/gssapi/spnego/negoex_ctx.c | 34 +++++++++++----------
src/lib/gssapi/spnego/spnego_mech.c | 41 +++++++++++++-------------
3 files changed, 43 insertions(+), 40 deletions(-)
diff --git a/src/lib/gssapi/spnego/gssapiP_negoex.h b/src/lib/gssapi/spnego/gssapiP_negoex.h
index 44b08f523..489ab7c42 100644
--- a/src/lib/gssapi/spnego/gssapiP_negoex.h
+++ b/src/lib/gssapi/spnego/gssapiP_negoex.h
@@ -201,10 +201,10 @@ negoex_restrict_auth_schemes(spnego_gss_ctx_id_t ctx,
OM_uint32
negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
gss_name_t target_name, OM_uint32 req_flags, OM_uint32 time_req,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec);
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec);
OM_uint32
negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec);
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec);
diff --git a/src/lib/gssapi/spnego/negoex_ctx.c b/src/lib/gssapi/spnego/negoex_ctx.c
index 18d9d4147..8848ee4db 100644
--- a/src/lib/gssapi/spnego/negoex_ctx.c
+++ b/src/lib/gssapi/spnego/negoex_ctx.c
@@ -276,7 +276,8 @@ static OM_uint32
mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
gss_name_t target, OM_uint32 req_flags, OM_uint32 time_req,
struct negoex_message *messages, size_t nmessages,
- gss_buffer_t output_token, OM_uint32 *time_rec)
+ gss_channel_bindings_t bindings, gss_buffer_t output_token,
+ OM_uint32 *time_rec)
{
OM_uint32 major, first_major = 0, first_minor = 0;
struct negoex_auth_mech *mech = NULL;
@@ -316,10 +317,9 @@ mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
mech = K5_TAILQ_FIRST(&ctx->negoex_mechs);
major = gss_init_sec_context(minor, cred, &mech->mech_context, target,
- mech->oid, req_flags, time_req,
- GSS_C_NO_CHANNEL_BINDINGS, input_token,
- &ctx->actual_mech, output_token,
- &ctx->ctx_flags, time_rec);
+ mech->oid, req_flags, time_req, bindings,
+ input_token, &ctx->actual_mech,
+ output_token, &ctx->ctx_flags, time_rec);
if (major == GSS_S_COMPLETE)
mech->complete = 1;
@@ -351,7 +351,8 @@ mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
static OM_uint32
mech_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
gss_cred_id_t cred, struct negoex_message *messages,
- size_t nmessages, gss_buffer_t output_token, OM_uint32 *time_rec)
+ size_t nmessages, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec)
{
OM_uint32 major, tmpmin;
struct negoex_auth_mech *mech;
@@ -395,10 +396,10 @@ mech_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
gss_release_cred(&tmpmin, &ctx->deleg_cred);
major = gss_accept_sec_context(minor, &mech->mech_context, cred,
- &msg->token, GSS_C_NO_CHANNEL_BINDINGS,
- &ctx->internal_name, &ctx->actual_mech,
- output_token, &ctx->ctx_flags,
- time_rec, &ctx->deleg_cred);
+ &msg->token, bindings, &ctx->internal_name,
+ &ctx->actual_mech, output_token,
+ &ctx->ctx_flags, time_rec,
+ &ctx->deleg_cred);
if (major == GSS_S_COMPLETE)
mech->complete = 1;
@@ -609,8 +610,8 @@ make_output_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
OM_uint32
negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
gss_name_t target_name, OM_uint32 req_flags, OM_uint32 time_req,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec)
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec)
{
OM_uint32 major, tmpmin;
gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER;
@@ -663,7 +664,8 @@ negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
/* Process the input token and/or produce an output token. This may prune
* the mech list, but on success there will be at least one mech entry. */
major = mech_init(minor, ctx, cred, target_name, req_flags, time_req,
- messages, nmessages, &mech_output_token, time_rec);
+ messages, nmessages, bindings, &mech_output_token,
+ time_rec);
if (major != GSS_S_COMPLETE)
goto cleanup;
assert(!K5_TAILQ_EMPTY(&ctx->negoex_mechs));
@@ -701,8 +703,8 @@ cleanup:
OM_uint32
negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec)
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec)
{
OM_uint32 major, tmpmin;
gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER;
@@ -754,7 +756,7 @@ negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
* prune the list to a single mech. Continue on error if an output token
* is generated, so that we send the token to the initiator.
*/
- major = mech_accept(minor, ctx, cred, messages, nmessages,
+ major = mech_accept(minor, ctx, cred, messages, nmessages, bindings,
&mech_output_token, time_rec);
if (major != GSS_S_COMPLETE && mech_output_token.length == 0)
goto cleanup;
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 594fc5894..4cf011143 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -130,6 +130,7 @@ init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
static OM_uint32
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
OM_uint32, gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+ gss_channel_bindings_t,
gss_buffer_t, OM_uint32 *, send_token_flag *);
static OM_uint32
@@ -144,8 +145,8 @@ acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
OM_uint32 *, send_token_flag *);
static OM_uint32
acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
- gss_buffer_t, gss_buffer_t, OM_uint32 *, OM_uint32 *,
- send_token_flag *);
+ gss_buffer_t, gss_channel_bindings_t, gss_buffer_t,
+ OM_uint32 *, OM_uint32 *, send_token_flag *);
static gss_OID
negotiate_mech(spnego_gss_ctx_id_t, gss_OID_set, OM_uint32 *);
@@ -905,6 +906,7 @@ init_ctx_call_init(OM_uint32 *minor_status,
OM_uint32 req_flags,
OM_uint32 time_req,
gss_buffer_t mechtok_in,
+ gss_channel_bindings_t bindings,
gss_buffer_t mechtok_out,
OM_uint32 *time_rec,
send_token_flag *send_token)
@@ -921,15 +923,14 @@ init_ctx_call_init(OM_uint32 *minor_status,
if (gss_oid_equal(sc->internal_mech, &negoex_mech)) {
ret = negoex_init(minor_status, sc, mcred, target_name,
mech_req_flags, time_req, mechtok_in,
- mechtok_out, time_rec);
+ bindings, mechtok_out, time_rec);
} else {
ret = gss_init_sec_context(minor_status, mcred,
&sc->ctx_handle, target_name,
sc->internal_mech, mech_req_flags,
- time_req, GSS_C_NO_CHANNEL_BINDINGS,
- mechtok_in, &sc->actual_mech,
- mechtok_out, &sc->ctx_flags,
- time_rec);
+ time_req, bindings, mechtok_in,
+ &sc->actual_mech, mechtok_out,
+ &sc->ctx_flags, time_rec);
}
/* Bail out if the acceptor gave us an error token but the mech didn't
@@ -981,8 +982,8 @@ init_ctx_call_init(OM_uint32 *minor_status,
gss_delete_sec_context(&tmpmin, &sc->ctx_handle, GSS_C_NO_BUFFER);
tmpret = init_ctx_call_init(&tmpmin, sc, spcred, acc_negState,
target_name, req_flags, time_req,
- mechtok_in, mechtok_out, time_rec,
- send_token);
+ mechtok_in, bindings, mechtok_out,
+ time_rec, send_token);
if (HARD_ERROR(tmpret))
goto fail;
*minor_status = tmpmin;
@@ -1004,7 +1005,7 @@ spnego_gss_init_sec_context(
gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
- gss_channel_bindings_t input_chan_bindings,
+ gss_channel_bindings_t bindings,
gss_buffer_t input_token,
gss_OID *actual_mech,
gss_buffer_t output_token,
@@ -1084,8 +1085,8 @@ spnego_gss_init_sec_context(
if (!spnego_ctx->mech_complete) {
ret = init_ctx_call_init(minor_status, spnego_ctx, spcred,
acc_negState, target_name, req_flags,
- time_req, mechtok_in, &mechtok_out,
- time_rec, &send_token);
+ time_req, mechtok_in, bindings,
+ &mechtok_out, time_rec, &send_token);
if (ret != GSS_S_COMPLETE)
goto cleanup;
@@ -1542,8 +1543,9 @@ cleanup:
static OM_uint32
acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
spnego_gss_cred_id_t spcred, gss_buffer_t mechtok_in,
- gss_buffer_t mechtok_out, OM_uint32 *time_rec,
- OM_uint32 *negState, send_token_flag *tokflag)
+ gss_channel_bindings_t bindings, gss_buffer_t mechtok_out,
+ OM_uint32 *time_rec, OM_uint32 *negState,
+ send_token_flag *tokflag)
{
OM_uint32 ret, tmpmin;
gss_OID_desc mechoid;
@@ -1568,13 +1570,12 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
if (negoex) {
ret = negoex_accept(minor_status, sc, mcred, mechtok_in,
- mechtok_out, time_rec);
+ bindings, mechtok_out, time_rec);
} else {
(void) gss_release_name(&tmpmin, &sc->internal_name);
(void) gss_release_cred(&tmpmin, &sc->deleg_cred);
ret = gss_accept_sec_context(minor_status, &sc->ctx_handle,
- mcred, mechtok_in,
- GSS_C_NO_CHANNEL_BINDINGS,
+ mcred, mechtok_in, bindings,
&sc->internal_name,
&sc->actual_mech, mechtok_out,
&sc->ctx_flags, time_rec,
@@ -1620,7 +1621,7 @@ spnego_gss_accept_sec_context(
gss_ctx_id_t *context_handle,
gss_cred_id_t verifier_cred_handle,
gss_buffer_t input_token,
- gss_channel_bindings_t input_chan_bindings,
+ gss_channel_bindings_t bindings,
gss_name_t *src_name,
gss_OID *mech_type,
gss_buffer_t output_token,
@@ -1734,8 +1735,8 @@ spnego_gss_accept_sec_context(
*/
if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
ret = acc_ctx_call_acc(minor_status, sc, spcred, mechtok_in,
- &mechtok_out, time_rec, &negState,
- &return_token);
+ bindings, &mechtok_out, time_rec,
+ &negState, &return_token);
}
/* Step 3: process or generate the MIC, if the negotiated mech is

View File

@ -0,0 +1,58 @@
From cec820485e8b854fe3ee42d0a67a77e7ad20595e Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sun, 26 Apr 2020 19:55:54 -0400
Subject: [PATCH] Pass gss_localname() through SPNEGO
ticket: 8897 (new)
(cherry picked from commit f7b8a6432bd289bdc528017be122305f95b8e285)
---
src/lib/gssapi/spnego/gssapiP_spnego.h | 8 ++++++++
src/lib/gssapi/spnego/spnego_mech.c | 9 ++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
index a93763314..066ec736f 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -357,6 +357,14 @@ OM_uint32 KRB5_CALLCONV spnego_gss_wrap_size_limit
OM_uint32 *max_input_size
);
+OM_uint32 KRB5_CALLCONV spnego_gss_localname
+(
+ OM_uint32 *minor_status,
+ const gss_name_t pname,
+ const gss_const_OID mech_type,
+ gss_buffer_t localname
+);
+
OM_uint32 KRB5_CALLCONV spnego_gss_get_mic
(
OM_uint32 *minor_status,
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index ec0bae6a4..594fc5894 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -237,7 +237,7 @@ static struct gss_config spnego_mechanism =
spnego_gss_inquire_context, /* gss_inquire_context */
NULL, /* gss_internal_release_oid */
spnego_gss_wrap_size_limit, /* gss_wrap_size_limit */
- NULL, /* gssd_pname_to_uid */
+ spnego_gss_localname,
NULL, /* gss_userok */
NULL, /* gss_export_name */
spnego_gss_duplicate_name, /* gss_duplicate_name */
@@ -2371,6 +2371,13 @@ spnego_gss_wrap_size_limit(
return (ret);
}
+OM_uint32 KRB5_CALLCONV
+spnego_gss_localname(OM_uint32 *minor_status, const gss_name_t pname,
+ const gss_const_OID mech_type, gss_buffer_t localname)
+{
+ return gss_localname(minor_status, pname, GSS_C_NO_OID, localname);
+}
+
OM_uint32 KRB5_CALLCONV
spnego_gss_get_mic(
OM_uint32 *minor_status,

View File

@ -0,0 +1,479 @@
From c90cef2ebfbefc595798dd5dbb805575e1be0fbf Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Fri, 30 Jun 2017 16:03:01 -0400
Subject: [PATCH] Refactor krb5 GSS checksum handling
Separate out checksum handling from kg_accept_krb5() into a new helper
process_checksum().
[ghudson@mit.edu: simplified checksum processing and made it use
k5-input.h instead of TREAD_ macros; moved more flag handling into
helper]
[iboukris: adjusted helper function arguments, allowing access to the
full authenticator for subsequent changes]
(cherry picked from commit 64d56233f9816a2a93f6e8d3030c8ed6ce397735)
[rharwood@redhat.com: problem with typo fix commit, I think]
---
src/lib/gssapi/krb5/accept_sec_context.c | 383 +++++++++++------------
1 file changed, 179 insertions(+), 204 deletions(-)
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index c5bddb1e8..70dd7fc0c 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -98,6 +98,7 @@
*/
#include "k5-int.h"
+#include "k5-input.h"
#include "gssapiP_krb5.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
@@ -413,6 +414,174 @@ kg_process_extension(krb5_context context,
return code;
}
+/* The length of the MD5 channel bindings in an 0x8003 checksum */
+#define CB_MD5_LEN 16
+
+/* The minimum length of an 0x8003 checksum value (4-byte channel bindings
+ * length, 16-byte channel bindings, 4-byte flags) */
+#define MIN_8003_LEN (4 + CB_MD5_LEN + 4)
+
+/* The flags we accept from the initiator's authenticator checksum. */
+#define INITIATOR_FLAGS (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | \
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
+ GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
+ GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
+
+/*
+ * The krb5 GSS mech appropriates the authenticator checksum field from RFC
+ * 4120 to store structured data instead of a checksum, indicated with checksum
+ * type 0x8003 (see RFC 4121 section 4.1.1). Some implementations instead send
+ * no checksum, or a regular checksum over empty data.
+ *
+ * Interpret the checksum. Read delegated creds into *deleg_out if it is not
+ * NULL. Set *flags_out to the allowed subset of token flags, plus
+ * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
+ * extensions found using exts. On error, set *code_out to a krb5_error code
+ * for use as a minor status value.
+ */
+static OM_uint32
+process_checksum(OM_uint32 *minor_status, krb5_context context,
+ gss_channel_bindings_t acceptor_cb,
+ krb5_auth_context auth_context, krb5_flags ap_req_options,
+ krb5_authenticator *authenticator, krb5_gss_ctx_ext_t exts,
+ krb5_gss_cred_id_t *deleg_out, krb5_ui_4 *flags_out,
+ krb5_error_code *code_out)
+{
+ krb5_error_code code = 0;
+ OM_uint32 status, option_id, token_flags;
+ size_t cb_len, option_len;
+ krb5_boolean valid;
+ krb5_key subkey;
+ krb5_data option, empty = empty_data();
+ krb5_checksum cb_cksum;
+ const uint8_t *token_cb, *option_bytes;
+ struct k5input in;
+ const krb5_checksum *cksum = authenticator->checksum;
+
+ cb_cksum.contents = NULL;
+
+ if (cksum == NULL) {
+ /*
+ * Some SMB client implementations use handcrafted GSSAPI code that
+ * does not provide a checksum. MS-KILE documents that the Microsoft
+ * implementation considers a missing checksum acceptable; the server
+ * assumes all flags are unset in this case, and does not check channel
+ * bindings.
+ */
+ *flags_out = 0;
+ } else if (cksum->checksum_type != CKSUMTYPE_KG_CB) {
+ /* Samba sends a regular checksum. */
+ code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* Verifying the checksum ensures that this authenticator wasn't
+ * replayed from one with a checksum over actual data. */
+ code = krb5_k_verify_checksum(context, subkey,
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, &empty,
+ cksum, &valid);
+ krb5_k_free_key(context, subkey);
+ if (code || !valid) {
+ status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
+ /* Use ap_options from the request to guess the mutual flag. */
+ *flags_out = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
+ if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
+ *flags_out |= GSS_C_MUTUAL_FLAG;
+ } else {
+ /* The checksum must contain at least a fixed 24-byte part. */
+ if (cksum->length < MIN_8003_LEN) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ k5_input_init(&in, cksum->contents, cksum->length);
+ cb_len = k5_input_get_uint32_le(&in);
+ if (cb_len != CB_MD5_LEN) {
+ code = KG_BAD_LENGTH;
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ token_cb = k5_input_get_bytes(&in, cb_len);
+ if (acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS) {
+ code = kg_checksum_channel_bindings(context, acceptor_cb,
+ &cb_cksum);
+ if (code) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+ assert(cb_cksum.length == cb_len);
+ if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+ }
+
+ /* Read the token flags and accept some of them as context flags. */
+ token_flags = k5_input_get_uint32_le(&in);
+ *flags_out = token_flags & INITIATOR_FLAGS;
+
+ /* Read the delegated credential if present. */
+ if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {
+ option_id = k5_input_get_uint16_le(&in);
+ option_len = k5_input_get_uint16_le(&in);
+ option_bytes = k5_input_get_bytes(&in, option_len);
+ option = make_data((uint8_t *)option_bytes, option_len);
+ if (in.status) {
+ code = KG_BAD_LENGTH;
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* Store the delegated credential. */
+ code = rd_and_store_for_creds(context, auth_context, &option,
+ deleg_out);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ *flags_out |= GSS_C_DELEG_FLAG;
+ }
+
+ /* Process any extensions at the end of the checksum. Extensions use
+ * 4-byte big-endian tag and length instead of 2-byte little-endian. */
+ while (in.len > 0) {
+ option_id = k5_input_get_uint32_be(&in);
+ option_len = k5_input_get_uint32_be(&in);
+ option_bytes = k5_input_get_bytes(&in, option_len);
+ option = make_data((uint8_t *)option_bytes, option_len);
+ if (in.status) {
+ code = KG_BAD_LENGTH;
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ code = kg_process_extension(context, auth_context, option_id,
+ &option, exts);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ status = GSS_S_COMPLETE;
+
+fail:
+ free(cb_cksum.contents);
+ *code_out = code;
+ return status;
+}
+
static OM_uint32
kg_accept_krb5(minor_status, context_handle,
verifier_cred_handle, input_token,
@@ -433,17 +602,13 @@ kg_accept_krb5(minor_status, context_handle,
krb5_gss_ctx_ext_t exts;
{
krb5_context context;
- unsigned char *ptr, *ptr2;
+ unsigned char *ptr;
char *sptr;
- OM_uint32 tmp;
- size_t md5len;
krb5_gss_cred_id_t cred = 0;
krb5_data ap_rep, ap_req;
- unsigned int i;
krb5_error_code code;
krb5_address addr, *paddr;
krb5_authenticator *authdat = 0;
- krb5_checksum reqcksum;
krb5_gss_name_t name = NULL;
krb5_ui_4 gss_flags = 0;
krb5_gss_ctx_id_rec *ctx = NULL;
@@ -451,8 +616,6 @@ kg_accept_krb5(minor_status, context_handle,
gss_buffer_desc token;
krb5_auth_context auth_context = NULL;
krb5_ticket * ticket = NULL;
- int option_id;
- krb5_data option;
const gss_OID_desc *mech_used = NULL;
OM_uint32 major_status = GSS_S_FAILURE;
OM_uint32 tmp_minor_status;
@@ -463,7 +626,6 @@ kg_accept_krb5(minor_status, context_handle,
krb5int_access kaccess;
int cred_rcache = 0;
int no_encap = 0;
- int token_deleg_flag = 0;
krb5_flags ap_req_options = 0;
krb5_enctype negotiated_etype;
krb5_authdata_context ad_context = NULL;
@@ -489,7 +651,6 @@ kg_accept_krb5(minor_status, context_handle,
output_token->length = 0;
output_token->value = NULL;
token.value = 0;
- reqcksum.contents = 0;
ap_req.data = 0;
ap_rep.data = 0;
@@ -654,195 +815,16 @@ kg_accept_krb5(minor_status, context_handle,
krb5_auth_con_getauthenticator(context, auth_context, &authdat);
- if (authdat->checksum == NULL) {
- /*
- * Some SMB client implementations use handcrafted GSSAPI code that
- * does not provide a checksum. MS-KILE documents that the Microsoft
- * implementation considers a missing checksum acceptable; the server
- * assumes all flags are unset in this case, and does not check channel
- * bindings.
- */
- gss_flags = 0;
- } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
- /* Samba does not send 0x8003 GSS-API checksums */
- krb5_boolean valid;
- krb5_key subkey;
- krb5_data zero;
+ major_status = process_checksum(minor_status, context, input_chan_bindings,
+ auth_context, ap_req_options,
+ authdat, exts,
+ delegated_cred_handle ? &deleg_cred : NULL,
+ &gss_flags, &code);
- code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
- if (code) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
+ if (major_status != GSS_S_COMPLETE)
+ goto fail;
- zero.length = 0;
- zero.data = "";
-
- code = krb5_k_verify_checksum(context,
- subkey,
- KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
- &zero,
- authdat->checksum,
- &valid);
- krb5_k_free_key(context, subkey);
- if (code || !valid) {
- major_status = GSS_S_BAD_SIG;
- goto fail;
- }
-
- /* Use ap_options from the request to guess the mutual flag. */
- gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
- if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
- gss_flags |= GSS_C_MUTUAL_FLAG;
- } else {
- /* gss krb5 v1 */
-
- /* stash this now, for later. */
- code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
- if (code) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /* verify that the checksum is correct */
-
- /*
- The checksum may be either exactly 24 bytes, in which case
- no options are specified, or greater than 24 bytes, in which case
- one or more options are specified. Currently, the only valid
- option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
- */
-
- if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
- (authdat->checksum->length < 24)) {
- code = 0;
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
-
- ptr = (unsigned char *) authdat->checksum->contents;
-
- TREAD_INT(ptr, tmp, 0);
-
- if (tmp != md5len) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /*
- The following section of code attempts to implement the
- optional channel binding facility as described in RFC2743.
-
- Since this facility is optional channel binding may or may
- not have been provided by either the client or the server.
-
- If the server has specified input_chan_bindings equal to
- GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
- the server does provide channel bindings then we compute
- a checksum and compare against those provided by the
- client. */
-
- if ((code = kg_checksum_channel_bindings(context,
- input_chan_bindings,
- &reqcksum))) {
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
-
- /* Always read the clients bindings - eventhough we might ignore them */
- TREAD_STR(ptr, ptr2, reqcksum.length);
-
- if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
- if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
- xfree(reqcksum.contents);
- reqcksum.contents = 0;
- code = 0;
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
-
- }
-
- xfree(reqcksum.contents);
- reqcksum.contents = 0;
-
- /* Read the token flags. Remember if GSS_C_DELEG_FLAG was set, but
- * mask it out until we actually read a delegated credential. */
- TREAD_INT(ptr, gss_flags, 0);
- token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
- gss_flags &= ~GSS_C_DELEG_FLAG;
-
- /* if the checksum length > 24, there are options to process */
-
- i = authdat->checksum->length - 24;
- if (i && token_deleg_flag) {
- if (i >= 4) {
- TREAD_INT16(ptr, option_id, 0);
- TREAD_INT16(ptr, option.length, 0);
- i -= 4;
-
- if (i < option.length) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /* have to use ptr2, since option.data is wrong type and
- macro uses ptr as both lvalue and rvalue */
-
- TREAD_STR(ptr, ptr2, option.length);
- option.data = (char *) ptr2;
-
- i -= option.length;
-
- if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /* store the delegated credential */
-
- code = rd_and_store_for_creds(context, auth_context, &option,
- (delegated_cred_handle) ?
- &deleg_cred : NULL);
- if (code) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- gss_flags |= GSS_C_DELEG_FLAG;
- } /* if i >= 4 */
- /* ignore any additional trailing data, for now */
- }
- while (i > 0) {
- /* Process Type-Length-Data options */
- if (i < 8) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- TREAD_INT(ptr, option_id, 1);
- TREAD_INT(ptr, option.length, 1);
- i -= 8;
- if (i < option.length) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- TREAD_STR(ptr, ptr2, option.length);
- option.data = (char *)ptr2;
-
- i -= option.length;
-
- code = kg_process_extension(context, auth_context,
- option_id, &option, exts);
- if (code != 0) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- }
- }
+ major_status = GSS_S_FAILURE;
if (exts->iakerb.conv && !exts->iakerb.verified) {
major_status = GSS_S_BAD_SIG;
@@ -869,12 +851,7 @@ kg_accept_krb5(minor_status, context_handle,
ctx->mech_used = (gss_OID) mech_used;
ctx->auth_context = auth_context;
ctx->initiate = 0;
- ctx->gss_flags = (GSS_C_TRANS_FLAG |
- ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
- GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
- GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
- GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
- GSS_C_EXTENDED_ERROR_FLAG)));
+ ctx->gss_flags = gss_flags | GSS_C_TRANS_FLAG;
ctx->seed_init = 0;
ctx->cred_rcache = cred_rcache;
@@ -1161,8 +1138,6 @@ fail:
krb5_auth_con_free(context, auth_context);
}
- if (reqcksum.contents)
- xfree(reqcksum.contents);
if (ap_rep.data)
krb5_free_data_contents(context, &ap_rep);
if (major_status == GSS_S_COMPLETE ||

View File

@ -0,0 +1,78 @@
From 7316aaa0e9249a88e919f2596d881f78970548bc Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 26 Feb 2020 18:27:17 -0500
Subject: [PATCH] Refresh manually acquired creds from client keytab
If a client keytab is present but credentials are acquired manually,
the credentials would not be refreshed because no refresh_time config
var is set in the cache. Change kg_cred_time_to_refresh() to attempt
a refresh from the client keytab on any credentials which will expire
in the next 30 seconds.
[ghudson@mit.edu: adjused code and added test case]
ticket: 7976
(cherry picked from commit 729896467e3c77904666019d6cbbda583ae49b95)
---
src/lib/gssapi/krb5/acquire_cred.c | 14 +++++++++++---
src/tests/gssapi/t_client_keytab.py | 18 ++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index acc1868f8..4062f4741 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -557,15 +557,23 @@ set_refresh_time(krb5_context context, krb5_ccache ccache,
krb5_boolean
kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
{
- krb5_timestamp now;
+ krb5_timestamp now, soon;
if (krb5_timeofday(context, &now))
return FALSE;
+ soon = ts_incr(now, 30);
if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) {
- set_refresh_time(context, cred->ccache,
- ts_incr(cred->refresh_time, 30));
+ set_refresh_time(context, cred->ccache, soon);
return TRUE;
}
+
+ /* If the creds will expire soon, try to refresh even if they weren't
+ * acquired with a client keytab. */
+ if (ts_after(soon, cred->expire)) {
+ set_refresh_time(context, cred->ccache, soon);
+ return TRUE;
+ }
+
return FALSE;
}
diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
index e474a27c7..7847b3ecd 100755
--- a/src/tests/gssapi/t_client_keytab.py
+++ b/src/tests/gssapi/t_client_keytab.py
@@ -124,4 +124,22 @@ realm.kinit(realm.user_princ, password('user'))
realm.run(['./t_ccselect', phost], env=bad_cktname,
expected_msg=realm.user_princ)
+mark('refresh of manually acquired creds')
+
+# Test 17: no name/ccache specified, manually acquired creds which
+# will expire soon. Verify that creds are refreshed using the current
+# client name, with refresh_time set in the refreshed ccache.
+realm.kinit('bob', password('bob'), ['-l', '15s'])
+realm.run(['./t_ccselect', phost], expected_msg='bob')
+realm.run([klist, '-C'], expected_msg='refresh_time = ')
+
+# Test 18: no name/ccache specified, manually acquired creds with a
+# client principal not present in the client keytab. A refresh is
+# attempted but fails, and an expired ticket error results.
+realm.kinit(realm.admin_princ, password('admin'), ['-l', '-1s'])
+msgs = ('Getting initial credentials for user/admin@KRBTEST.COM',
+ '/Matching credential not found')
+realm.run(['./t_ccselect', phost], expected_code=1,
+ expected_msg='Ticket expired', expected_trace=msgs)
+
success('Client keytab tests')

View File

@ -0,0 +1,547 @@
From 3e75969e0c0a52ec3ca8195200fcdadaa63b324f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 28 May 2020 18:41:02 -0400
Subject: [PATCH] Remove resolver test utility
tests/resolve is no longer used after the previous commit.
[rharwood@redhat.com: .gitignore]
---
src/configure.ac | 5 +-
src/tests/Makefile.in | 4 +-
src/tests/resolve/Makefile.in | 28 ---
src/tests/resolve/addrinfo-test.c | 306 -------------------------
src/tests/resolve/deps | 14 --
src/tests/resolve/fake-addrinfo-test.c | 3 -
src/tests/resolve/resolve.c | 115 ----------
7 files changed, 4 insertions(+), 471 deletions(-)
delete mode 100644 src/tests/resolve/Makefile.in
delete mode 100644 src/tests/resolve/addrinfo-test.c
delete mode 100644 src/tests/resolve/deps
delete mode 100644 src/tests/resolve/fake-addrinfo-test.c
delete mode 100644 src/tests/resolve/resolve.c
diff --git a/src/configure.ac b/src/configure.ac
index aafc462f9..00b5ea4c5 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1540,7 +1540,6 @@ V5_AC_OUTPUT_MAKEFILE(.
appl/simple appl/simple/client appl/simple/server
appl/gss-sample appl/user_user
- tests tests/resolve tests/asn.1 tests/create tests/hammer
- tests/verify tests/gssapi tests/dejagnu tests/threads tests/shlib
- tests/gss-threads tests/misc
+ tests tests/asn.1 tests/create tests/hammer tests/verify tests/gssapi
+ tests/dejagnu tests/threads tests/shlib tests/gss-threads tests/misc
)
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 3f88f1713..6b7749129 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -1,7 +1,7 @@
mydir=tests
BUILDTOP=$(REL)..
-SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
- gss-threads misc threads softpkcs11
+SUBDIRS = asn.1 create hammer verify gssapi dejagnu shlib gss-threads misc \
+ threads softpkcs11
RUN_DB_TEST = $(RUN_SETUP) KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf \
GSS_MECH_CONFIG=mech.conf LC_ALL=C $(VALGRIND)
diff --git a/src/tests/resolve/Makefile.in b/src/tests/resolve/Makefile.in
deleted file mode 100644
index 1f5954089..000000000
--- a/src/tests/resolve/Makefile.in
+++ /dev/null
@@ -1,28 +0,0 @@
-mydir=tests$(S)resolve
-BUILDTOP=$(REL)..$(S)..
-
-OBJS=resolve.o addrinfo-test.o fake-addrinfo-test.o
-SRCS=$(srcdir)/resolve.c $(srcdir)/addrinfo-test.c \
- $(srcdir)/fake-addrinfo-test.c
-
-all: resolve addrinfo-test fake-addrinfo-test
-
-resolve: resolve.o
- $(CC_LINK) -o $@ resolve.o $(SUPPORT_LIB) $(LIBS)
-
-addrinfo-test: addrinfo-test.o
- $(CC_LINK) -o $@ addrinfo-test.o $(SUPPORT_LIB) $(LIBS)
-
-fake-addrinfo-test: fake-addrinfo-test.o
- $(CC_LINK) -o $@ fake-addrinfo-test.o $(SUPPORT_LIB) $(LIBS)
-
-check: resolve addrinfo-test fake-addrinfo-test
- $(RUN_TEST) ./resolve
- $(RUN_TEST) ./addrinfo-test -p telnet
- $(RUN_TEST) ./fake-addrinfo-test -p telnet
-
-install:
-
-clean:
- $(RM) resolve addrinfo-test fake-addrinfo-test
-
diff --git a/src/tests/resolve/addrinfo-test.c b/src/tests/resolve/addrinfo-test.c
deleted file mode 100644
index e77640b62..000000000
--- a/src/tests/resolve/addrinfo-test.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* tests/resolve/addrinfo-test.c */
-/*
- * Copyright 2004 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * A simple program to test the functionality of the getaddrinfo function.
- *
- * Usage:
- * addrinfo-test [-t|-u|-R|-I] [-d|-s|-r] [-p port] [-P] [hostname]
- *
- * When invoked with no arguments, NULL is used for the node name,
- * which (at least with a non-null "port") means a socket address
- * is desired that can be used with connect() or bind() (depending
- * on whether "-P" is given).
- */
-
-#include <k5-platform.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h> /* needed for IPPROTO_* on NetBSD */
-#ifdef USE_FAKE_ADDRINFO
-#include "fake-addrinfo.h"
-#endif
-
-static const char *protoname (int p) {
- static char buf[30];
-
-#define X(N) if (p == IPPROTO_ ## N) return #N
-
- X(TCP);
- X(UDP);
- X(ICMP);
-#ifdef IPPROTO_IPV6
- X(IPV6);
-#endif
-#ifdef IPPROTO_GRE
- X(GRE);
-#endif
-#ifdef IPPROTO_NONE
- X(NONE);
-#endif
- X(RAW);
-#ifdef IPPROTO_COMP
- X(COMP);
-#endif
-
- snprintf(buf, sizeof(buf), " %-2d", p);
- return buf;
-}
-
-static const char *socktypename (int t) {
- static char buf[30];
- switch (t) {
- case SOCK_DGRAM: return "DGRAM";
- case SOCK_STREAM: return "STREAM";
- case SOCK_RAW: return "RAW";
- case SOCK_RDM: return "RDM";
- case SOCK_SEQPACKET: return "SEQPACKET";
- }
- snprintf(buf, sizeof(buf), " %-2d", t);
- return buf;
-}
-
-static char *whoami;
-
-static void usage () {
- fprintf(stderr,
- "usage:\n"
- "\t%s [ options ] [host]\n"
- "options:\n"
- "\t-t\tspecify protocol IPPROTO_TCP\n"
- "\t-u\tspecify protocol IPPROTO_UDP\n"
- "\t-R\tspecify protocol IPPROTO_RAW\n"
- "\t-I\tspecify protocol IPPROTO_ICMP\n"
- "\n"
- "\t-d\tspecify socket type SOCK_DGRAM\n"
- "\t-s\tspecify socket type SOCK_STREAM\n"
- "\t-r\tspecify socket type SOCK_RAW\n"
- "\n"
- "\t-4\tspecify address family AF_INET\n"
-#ifdef AF_INET6
- "\t-6\tspecify address family AF_INET6\n"
-#endif
- "\n"
- "\t-p P\tspecify port P (service name or port number)\n"
- "\t-N\thostname is numeric, skip DNS query\n"
- "\t-n\tservice/port is numeric (sets AI_NUMERICSERV)\n"
- "\t-P\tset AI_PASSIVE\n"
- "\n"
- "default: protocol 0, socket type 0, address family 0, null port\n"
- ,
- whoami);
- /* [ -t | -u | -R | -I ] [ -d | -s | -r ] [ -p port ] */
- exit (1);
-}
-
-static const char *familyname (int f) {
- static char buf[30];
- switch (f) {
- default:
- snprintf(buf, sizeof(buf), "AF %d", f);
- return buf;
- case AF_INET: return "AF_INET";
-#ifdef AF_INET6
- case AF_INET6: return "AF_INET6";
-#endif
- }
-}
-
-#define eaistr(X) (X == EAI_SYSTEM ? strerror(errno) : gai_strerror(X))
-
-int main (int argc, char *argv[])
-{
- struct addrinfo *ap, *ap2;
- int err, numerichost = 0, numericserv = 0;
- char *hname, *port = 0, *sep;
- struct addrinfo hints;
-
- whoami = strrchr(argv[0], '/');
- if (whoami == 0)
- whoami = argv[0];
- else
- whoami = whoami+1;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = 0;
- hints.ai_socktype = 0;
-
- hname = 0;
- hints.ai_family = 0;
-
- if (argc == 1)
- usage ();
-
- while (++argv, --argc > 0) {
- char *arg;
- arg = *argv;
-
- if (*arg != '-')
- hname = arg;
- else if (arg[1] == 0 || arg[2] != 0)
- usage ();
- else
- switch (arg[1]) {
- case 'u':
- hints.ai_protocol = IPPROTO_UDP;
- break;
- case 't':
- hints.ai_protocol = IPPROTO_TCP;
- break;
- case 'R':
- hints.ai_protocol = IPPROTO_RAW;
- break;
- case 'I':
- hints.ai_protocol = IPPROTO_ICMP;
- break;
- case 'd':
- hints.ai_socktype = SOCK_DGRAM;
- break;
- case 's':
- hints.ai_socktype = SOCK_STREAM;
- break;
- case 'r':
- hints.ai_socktype = SOCK_RAW;
- break;
- case 'p':
- if (argv[1] == 0 || argv[1][0] == 0 || argv[1][0] == '-')
- usage ();
- port = argv[1];
- argc--, argv++;
- break;
- case '4':
- hints.ai_family = AF_INET;
- break;
-#ifdef AF_INET6
- case '6':
- hints.ai_family = AF_INET6;
- break;
-#endif
- case 'N':
- numerichost = 1;
- break;
- case 'n':
- numericserv = 1;
- break;
- case 'P':
- hints.ai_flags |= AI_PASSIVE;
- break;
- default:
- usage ();
- }
- }
-
- if (hname && !numerichost)
- hints.ai_flags |= AI_CANONNAME;
- if (numerichost) {
-#ifdef AI_NUMERICHOST
- hints.ai_flags |= AI_NUMERICHOST;
-#else
- fprintf(stderr, "AI_NUMERICHOST not defined on this platform\n");
- exit(1);
-#endif
- }
- if (numericserv) {
-#ifdef AI_NUMERICSERV
- hints.ai_flags |= AI_NUMERICSERV;
-#else
- fprintf(stderr, "AI_NUMERICSERV not defined on this platform\n");
- exit(1);
-#endif
- }
-
- printf("getaddrinfo(hostname %s, service %s,\n"
- " hints { ",
- hname ? hname : "(null)", port ? port : "(null)");
- sep = "";
-#define Z(FLAG) if (hints.ai_flags & AI_##FLAG) printf("%s%s", sep, #FLAG), sep = "|"
- Z(CANONNAME);
- Z(PASSIVE);
-#ifdef AI_NUMERICHOST
- Z(NUMERICHOST);
-#endif
-#ifdef AI_NUMERICSERV
- Z(NUMERICSERV);
-#endif
- if (sep[0] == 0)
- printf ("no-flags");
- if (hints.ai_family)
- printf(" %s", familyname(hints.ai_family));
- if (hints.ai_socktype)
- printf(" SOCK_%s", socktypename(hints.ai_socktype));
- if (hints.ai_protocol)
- printf(" IPPROTO_%s", protoname(hints.ai_protocol));
- printf(" }):\n");
-
- err = getaddrinfo(hname, port, &hints, &ap);
- if (err) {
- printf("\terror => %s\n", eaistr(err));
- return 1;
- }
-
- for (ap2 = ap; ap2; ap2 = ap2->ai_next) {
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
- /* If we don't do this, even AIX's own getnameinfo will reject
- the sockaddr structures. The sa_len field doesn't get set
- either, on AIX, but getnameinfo won't complain. */
- if (ap2->ai_addr->sa_family == 0) {
- printf("BAD: sa_family zero! fixing...\n");
- ap2->ai_addr->sa_family = ap2->ai_family;
- } else if (ap2->ai_addr->sa_family != ap2->ai_family) {
- printf("BAD: sa_family != ai_family! fixing...\n");
- ap2->ai_addr->sa_family = ap2->ai_family;
- }
- if (getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof(hbuf),
- pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
- strlcpy(hbuf, "...", sizeof(hbuf));
- strlcpy(pbuf, "...", sizeof(pbuf));
- }
- printf("%p:\n"
- "\tfamily = %s\tproto = %-4s\tsocktype = %s\n",
- (void *) ap2, familyname(ap2->ai_family),
- protoname (ap2->ai_protocol),
- socktypename (ap2->ai_socktype));
- if (ap2->ai_canonname) {
- if (ap2->ai_canonname[0])
- printf("\tcanonname = %s\n", ap2->ai_canonname);
- else
- printf("BAD: ai_canonname is set but empty!\n");
- } else if (ap2 == ap && (hints.ai_flags & AI_CANONNAME)) {
- printf("BAD: first ai_canonname is null!\n");
- }
- printf("\taddr = %-28s\tport = %s\n", hbuf, pbuf);
-
- err = getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof (hbuf),
- pbuf, sizeof(pbuf), NI_NAMEREQD);
- if (err)
- printf("\tgetnameinfo(NI_NAMEREQD): %s\n", eaistr(err));
- else
- printf("\tgetnameinfo => %s, %s\n", hbuf, pbuf);
- }
- freeaddrinfo(ap);
- return 0;
-}
diff --git a/src/tests/resolve/deps b/src/tests/resolve/deps
deleted file mode 100644
index 762d9adab..000000000
--- a/src/tests/resolve/deps
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Generated makefile dependencies follow.
-#
-$(OUTPRE)resolve.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
- $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
- resolve.c
-$(OUTPRE)addrinfo-test.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
- $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
- addrinfo-test.c
-$(OUTPRE)fake-addrinfo-test.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
- $(top_srcdir)/include/fake-addrinfo.h $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/port-sockets.h \
- $(top_srcdir)/include/socket-utils.h addrinfo-test.c \
- fake-addrinfo-test.c
diff --git a/src/tests/resolve/fake-addrinfo-test.c b/src/tests/resolve/fake-addrinfo-test.c
deleted file mode 100644
index 86365a5ba..000000000
--- a/src/tests/resolve/fake-addrinfo-test.c
+++ /dev/null
@@ -1,3 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-#define USE_FAKE_ADDRINFO
-#include "addrinfo-test.c"
diff --git a/src/tests/resolve/resolve.c b/src/tests/resolve/resolve.c
deleted file mode 100644
index ea0239113..000000000
--- a/src/tests/resolve/resolve.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* tests/resolve/resolve.c */
-/*
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * A simple program to test the functionality of the resolver library.
- * It simply will try to get the IP address of the host, and then look
- * up the name from the address. If the resulting name does not contain the
- * domain name, then the resolve library is broken.
- *
- * Warning: It is possible to fool this program into thinking everything is
- * alright by a clever use of /etc/hosts - but this is better than nothing.
- *
- * Usage:
- * resolve [hostname]
- *
- * When invoked with no arguments, gethostname is used for the local host.
- *
- */
-
-/* This program tests the resolve library and sees if it is broken... */
-
-#include "k5-platform.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-int
-main(int argc, char **argv)
-{
- struct addrinfo *ai = NULL, hint;
- char myname[MAXHOSTNAMELEN + 1], namebuf[NI_MAXHOST], abuf[256];
- const char *addrstr;
- int err, quiet = 0;
-
- argc--; argv++;
- while (argc) {
- if ((strcmp(*argv, "--quiet") == 0) ||
- (strcmp(*argv, "-q") == 0)) {
- quiet++;
- } else
- break;
- argc--; argv++;
- }
-
- if (argc >= 1) {
- strlcpy(myname, *argv, sizeof(myname));
- } else {
- if(gethostname(myname, MAXHOSTNAMELEN)) {
- perror("gethostname failure");
- exit(1);
- }
- }
-
- myname[MAXHOSTNAMELEN] = '\0'; /* for safety */
-
- /* Look up the address... */
- if (!quiet)
- printf("Hostname: %s\n", myname);
-
- memset(&hint, 0, sizeof(hint));
- hint.ai_flags = AI_CANONNAME;
- err = getaddrinfo(myname, 0, &hint, &ai);
- if (err) {
- fprintf(stderr,
- "Could not look up address for hostname '%s' - fatal\n",
- myname);
- exit(2);
- }
-
- if (!quiet) {
- addrstr = inet_ntop(ai->ai_family, ai->ai_addr, abuf, sizeof(abuf));
- if (addrstr != NULL)
- printf("Host address: %s\n", addrstr);
- }
-
- err = getnameinfo(ai->ai_addr, ai->ai_addrlen, namebuf, sizeof(namebuf),
- NULL, 0, NI_NAMEREQD);
- if (err && !quiet)
- fprintf(stderr, "Error looking up IP address\n");
-
- printf("%s%s\n", quiet ? "" : "FQDN: ", err ? ai->ai_canonname : namebuf);
-
- if (!quiet)
- printf("Resolve library appears to have passed the test\n");
-
- freeaddrinfo(ai);
- return 0;
-}

View File

@ -0,0 +1,861 @@
From 404cc1152880a567fc27bb7c691a1a732692bbf9 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 15 Feb 2020 20:34:23 -0500
Subject: [PATCH] Replace gssrpc tests with a Python script
Replace the dejagnu RPC test framework with a short Python script to
do the same tests as fullrun.exp and gsserr.exp. Modify the server
test program to facilitate use by k5test.py.
expire.exp, together with a comment in the client test program, was
designed to test a libdb2 btree bug via the gssrpc server-side
authentication code. That code was subsequently changed not to use
libdb2, before it was merged into the main krb5 tree (in revision 1.23
of svc_auth_gssapi.c, according to the changelog removed in commit
2a43d772be1e45faa8e488d436b6e867371563fb). Remove the comment and do
not replace that test sequence.
[rharwood@redhat.com: .gitignore]
---
src/configure.ac | 2 -
src/lib/rpc/unit-test/Makefile.in | 36 +--
src/lib/rpc/unit-test/client.c | 26 ---
src/lib/rpc/unit-test/config/unix.exp | 176 --------------
src/lib/rpc/unit-test/lib/helpers.exp | 234 -------------------
src/lib/rpc/unit-test/rpc_test.0/expire.exp | 49 ----
src/lib/rpc/unit-test/rpc_test.0/fullrun.exp | 91 --------
src/lib/rpc/unit-test/rpc_test.0/gsserr.exp | 30 ---
src/lib/rpc/unit-test/server.c | 13 +-
src/lib/rpc/unit-test/t_rpc.py | 29 +++
10 files changed, 41 insertions(+), 645 deletions(-)
delete mode 100644 src/lib/rpc/unit-test/config/unix.exp
delete mode 100644 src/lib/rpc/unit-test/lib/helpers.exp
delete mode 100644 src/lib/rpc/unit-test/rpc_test.0/expire.exp
delete mode 100644 src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
delete mode 100644 src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
create mode 100644 src/lib/rpc/unit-test/t_rpc.py
diff --git a/src/configure.ac b/src/configure.ac
index 29be532cb..aafc462f9 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1102,8 +1102,6 @@ extern void endrpcent();],
AC_MSG_RESULT($k5_cv_type_endrpcent)
AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent])
K5_GEN_FILE(include/gssrpc/types.h:include/gssrpc/types.hin)
-PASS=tcp
-AC_SUBST(PASS)
# for pkinit
AC_ARG_ENABLE([pkinit],
diff --git a/src/lib/rpc/unit-test/Makefile.in b/src/lib/rpc/unit-test/Makefile.in
index 0b6e5203d..309ae2b21 100644
--- a/src/lib/rpc/unit-test/Makefile.in
+++ b/src/lib/rpc/unit-test/Makefile.in
@@ -16,10 +16,6 @@ server: server.o rpc_test_svc.o $(GSSRPC_DEPLIBS) $(KRB5_BASE_DEPLIBS)
client.o server.o: rpc_test.h
-runenv.exp: Makefile
- $(RUN_SETUP); for i in $(RUN_VARS); do \
- eval echo "set env\($$i\) \$$$$i"; done > runenv.exp
-
# If rpc_test.h and rpc_test_*.c do not work on your system, you can
# try using rpcgen by uncommenting these lines (be sure to uncomment
# then in the generated not Makefile.in).
@@ -34,37 +30,9 @@ runenv.exp: Makefile
# rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c
#
-check unit-test: unit-test-@DO_TEST@
-
-unit-test-:
- @echo "+++"
- @echo "+++ WARNING: lib/rpc unit tests not run."
- @echo "+++ Either tcl, runtest, or Perl is unavailable."
- @echo "+++"
- @echo 'Skipped rpc tests: runtest or Perl not found' >> $(SKIPTESTS)
-
-unit-test-ok: unit-test-body
-
-PASS=@PASS@
-unit-test-body: runenv.sh runenv.exp
- $(RM) krb5cc_rpc_test_*
- $(ENV_SETUP) $(VALGRIND) $(START_SERVERS)
- RPC_TEST_KEYTAB=/tmp/rpc_test_keytab.$$$$ ; export RPC_TEST_KEYTAB ; \
- trap "echo Failed, cleaning up... ; rm -f $$RPC_TEST_KEYTAB ; $(ENV_SETUP) $(STOP_SERVERS) ; trap '' 0 ; exit 1" 0 1 2 3 14 15 ; \
- if $(ENV_SETUP) \
- $(RUNTEST) SERVER=./server CLIENT=./client \
- KINIT=$(BUILDTOP)/clients/kinit/kinit \
- KDESTROY=$(BUILDTOP)/clients/kdestroy/kdestroy \
- PRIOCNTL_HACK=@PRIOCNTL_HACK@ VALGRIND="$(VALGRIND)" \
- PASS="$(PASS)" --tool rpc_test $(RUNTESTFLAGS) ; \
- then \
- echo Cleaning up... ; \
- rm -f $$RPC_TEST_KEYTAB krb5cc_rpc_test_* ; \
- $(ENV_SETUP) $(STOP_SERVERS) ; \
- trap 0 ; exit 0 ; \
- else exit 1 ; fi
+check-pytests:
+ $(RUNPYTEST) $(srcdir)/t_rpc.py $(PYTESTFLAGS)
clean:
$(RM) server client
- $(RM) dbg.log rpc_test.log rpc_test.sum runenv.exp
diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c
index 5edde49df..c9a812bc5 100644
--- a/src/lib/rpc/unit-test/client.c
+++ b/src/lib/rpc/unit-test/client.c
@@ -231,32 +231,6 @@ main(argc, argv)
else
gssrpc_xdr_free(xdr_wrapstring, echo_resp);
- /*
- * Test fix for secure-rpc/586, part 1: btree keys must be
- * unique. Create another context from the same credentials; it
- * should have the same expiration time and will cause the server
- * to abort if the clients are not differentiated.
- *
- * Test fix for secure-rpc/586, part 2: btree keys cannot be
- * mutated in place. To test this: a second client, *with a
- * later expiration time*, must be run. The second client should
- * destroy itself *after* the first one; if the key-mutating bug
- * is not fixed, the second client_data will be in the btree
- * before the first, but its key will be larger; thus, when the
- * first client calls AUTH_DESTROY, the server won't find it in
- * the btree and call abort.
- *
- * For unknown reasons, running just a second client didn't
- * tickle the bug; the btree code seemed to guess which node to
- * look at first. Running a total of three clients does ticket
- * the bug. Thus, the full test sequence looks like this:
- *
- * kinit -l 20m user && client server test@ddn 200
- * sleep 1
- * kini -l 30m user && client server test@ddn 300
- * sleep 1
- * kinit -l 40m user && client server test@ddn 400
- */
if (! auth_once) {
tmp_auth = clnt->cl_auth;
clnt->cl_auth = auth_gssapi_create_default(clnt, target);
diff --git a/src/lib/rpc/unit-test/config/unix.exp b/src/lib/rpc/unit-test/config/unix.exp
deleted file mode 100644
index 18da62be4..000000000
--- a/src/lib/rpc/unit-test/config/unix.exp
+++ /dev/null
@@ -1,176 +0,0 @@
-#
-# $Id$
-#
-
-source runenv.exp
-
-set kill /bin/kill
-set sleep /bin/sleep
-set kinit $KINIT
-set kdestroy $KDESTROY
-
-set hostname [exec hostname]
-
-# Hack around Solaris 9 kernel race condition that causes last output
-# from a pty to get dropped.
-if { $PRIOCNTL_HACK } {
- catch {exec priocntl -s -c FX -m 30 -p 30 -i pid [getpid]}
- rename spawn oldspawn
- proc spawn { args } {
- upvar 1 spawn_id spawn_id
- set newargs {}
- set inflags 1
- set eatnext 0
- foreach arg $args {
- if { $arg == "-ignore" \
- || $arg == "-open" \
- || $arg == "-leaveopen" } {
- lappend newargs $arg
- set eatnext 1
- continue
- }
- if [string match "-*" $arg] {
- lappend newargs $arg
- continue
- }
- if { $eatnext } {
- set eatnext 0
- lappend newargs $arg
- continue
- }
- if { $inflags } {
- set inflags 0
- set newargs [concat $newargs {priocntl -e -c FX -p 0}]
- }
- lappend newargs $arg
- }
- set pid [eval oldspawn $newargs]
- return $pid
- }
-}
-
-if { [string length $VALGRIND] } {
- rename spawn valgrind_aux_spawn
- proc spawn { args } {
- global VALGRIND
- upvar 1 spawn_id spawn_id
- set newargs {}
- set inflags 1
- set eatnext 0
- foreach arg $args {
- if { $arg == "-ignore" \
- || $arg == "-open" \
- || $arg == "-leaveopen" } {
- lappend newargs $arg
- set eatnext 1
- continue
- }
- if [string match "-*" $arg] {
- lappend newargs $arg
- continue
- }
- if { $eatnext } {
- set eatnext 0
- lappend newargs $arg
- continue
- }
- if { $inflags } {
- set inflags 0
- # Only run valgrind for local programs, not
- # system ones.
-#&&![string match "/bin/sh" $arg] sh is used to start kadmind!
- if [string match "/" [string index $arg 0]]&&![string match "/bin/ls" $arg]&&![regexp {/kshd$} $arg] {
- set newargs [concat $newargs $VALGRIND]
- } elseif [string match "." [string index $arg 0]] {
- set newargs [concat $newargs $VALGRIND]
- }
- }
- lappend newargs $arg
- }
- set pid [eval valgrind_aux_spawn $newargs]
- return $pid
- }
-}
-
-# this will initialize the database and keytab
-load_lib "helpers.exp"
-
-proc rpc_test_version {} {
- global CLIENT
- global SERVER
-
- clone_output "$CLIENT version <unknown>"
- clone_output "$SERVER version <unknown>"
-}
-
-proc rpc_test_load {} {
- #
-}
-
-# rpc_test_exit -- clean up and exit
-proc rpc_test_exit {} {
- global server_id
- global server_pid
- global server_started
- global kill
-
- if {[catch {
- expect {
- -i $server_id
- eof {
- fail "server exited!"
- verbose $expect_out(buffer) 1
- }
- timeout { pass "server survived" }
- }
- } tmp]} {
- fail "server exited! (expect failed)"
- }
-}
-
-#
-# rpc_test_start -- start the rpc_test server running
-#
-proc rpc_test_start { } {
- global SERVER PROT
- global server_id
- global server_pid
- global server_started
- global server_port
- global env
-
- if [info exists server_pid] { rpc_test_exit }
-
- set env(KRB5_KTNAME) FILE:$env(RPC_TEST_KEYTAB)
-
- verbose "% $SERVER" 1
- set server_pid [spawn $SERVER $PROT]
- set server_id $spawn_id
- set server_started 1
- set server_port -1
-
- unset env(KRB5_KTNAME)
-
- set timeout 30
-
- expect {
- -re "port: (\[0-9\]*)\r\n" {
- set server_port $expect_out(1,string)
- }
- "running" { }
- eof {
- send_error "server exited!"
- verbose $expect_out(buffer) 1
- }
- timeout {
- send_error "server didn't start in $timeout seconds"
- verbose $expect_out(buffer) 1
- }
- }
-
-}
-
-set MULTIPASS {
- {tcp PROT=-t dummy=[rpc_test_start]}
- {udp PROT=-u dummy=[rpc_test_start]}
-}
diff --git a/src/lib/rpc/unit-test/lib/helpers.exp b/src/lib/rpc/unit-test/lib/helpers.exp
deleted file mode 100644
index eb2797c53..000000000
--- a/src/lib/rpc/unit-test/lib/helpers.exp
+++ /dev/null
@@ -1,234 +0,0 @@
-if {[info commands exp_version] != {}} {
- set exp_version_4 [regexp {^4} [exp_version]]
-} else {
- set exp_version_4 [regexp {^4} [expect_version]]
-}
-
-# Backward compatibility until we're using expect 5 everywhere
-if {$exp_version_4} {
- global wait_error_index wait_errno_index wait_status_index
- set wait_error_index 0
- set wait_errno_index 1
- set wait_status_index 1
-} else {
- set wait_error_index 2
- set wait_errno_index 3
- set wait_status_index 3
-}
-
-proc set_from_env {varname default_value} {
- global env
- upvar $varname v
-
- if [info exists env($varname)] {
- set v $env($varname)
- } else {
- set v $default_value
- }
-}
-proc expect_tcl_prompt {} {
- global kadmin_tcl_spawn_id
- expect {
- -i $kadmin_tcl_spawn_id
- -re "^% $" { }
- -re . { perror "unexpected output {$expect_out(buffer)} from subprocess, expecting tcl prompt" }
- timeout { perror "timeout waiting for tcl prompt" }
- eof { perror "eof from subprocess when expecting tcl prompt" }
- }
-}
-proc send_tcl_cmd_await_echo {cmd} {
- global kadmin_tcl_spawn_id
- send -i $kadmin_tcl_spawn_id "$cmd\n"
- expect {
- -i $kadmin_tcl_spawn_id
- -ex "$cmd\r\n" { }
- timeout { perror "timeout waiting for tcl subprocess to echo input" }
- eof { perror "eof waiting for tcl subprocess to echo input" }
- }
-}
-proc expect_kadm_ok {} {
- global kadmin_tcl_spawn_id
- expect {
- -i $kadmin_tcl_spawn_id
- -re "^OK KADM5_OK \[^\n\]*\n" {}
- -re "^ERROR \[^\n\]*\n" { perror "kadmin tcl subprocess reported unexpected error" }
- -re "^marshall_new_creds: \[^\n\]*\n" { exp_continue }
- -re "^gssapi_\[^\n\]*\n" { exp_continue }
- -re "^\r?\n" { exp_continue }
- eof { perror "kadmin tcl subprocess died" }
- default { perror "didn't get ok back" }
- }
-}
-proc setup_database {} {
- global env spawn_id kadmin_tcl_spawn_id TESTDIR CANON_HOST
-
- # XXXXX
- set_from_env TOP {/x/x/x/x/x}
- send_user "TOP=$TOP\n"
-
- set_from_env TESTDIR $env(TOP)/testing
- set_from_env CLNTTCL $TESTDIR/util/kadm5_clnt_tcl
- set_from_env TCLUTIL $TESTDIR/tcl/util.t
- set env(TCLUTIL) $TCLUTIL
- set env(PATH) "$TOP/install/admin:$env(PATH)"
-
- # $VERBOSE ?
-
- if [info exists spawn_id] { set x $spawn_id }
- spawn $CLNTTCL
- set kadmin_tcl_spawn_id $spawn_id
- if [info exists x] { set spawn_id $x }
-
- expect_tcl_prompt
- # tcl 8.4 for some reason screws up autodetection of output EOL
- # translation. Work around it for now.
- send_tcl_cmd_await_echo "if { \[info commands fconfigure\] != \"\" } { fconfigure stdout -translation lf }"
- expect_tcl_prompt
- send_tcl_cmd_await_echo "source {$TCLUTIL}"
- expect_tcl_prompt
- send_tcl_cmd_await_echo "set h {$CANON_HOST}"
- expect {
- -ex "$CANON_HOST\r\n" { }
- timeout { perror "timeout waiting for subprocess" }
- eof { perror "eof from subprocess" }
- }
- expect_tcl_prompt
-
- send_tcl_cmd_await_echo {kadm5_init admin admin $KADM5_ADMIN_SERVICE null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_create_principal $server_handle [simple_principal server/$h] {KADM5_PRINCIPAL} admin}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_randkey_principal $server_handle server/$h key null}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_create_principal $server_handle [simple_principal notserver/$h] {KADM5_PRINCIPAL} admin}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_randkey_principal $server_handle notserver/$h key null}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_destroy $server_handle}
- expect_kadm_ok
- expect "^% "
- wait -nowait -i $spawn_id
- close -i $spawn_id
-}
-
-if ![info exists CANON_HOST] {
- set CANON_HOST $env(QUALNAME)
- setup_database
- file delete $env(RPC_TEST_KEYTAB)
- exec $env(TOP)/cli/kadmin -p admin -w admin ktadd -k $env(RPC_TEST_KEYTAB) server/$CANON_HOST
-}
-
-
-proc kinit {princ pass lifetime} {
- global kinit
- global wait_error_index wait_errno_index wait_status_index
-
- spawn -noecho $kinit -5 -l $lifetime $princ
- expect {
- -re "Password for $princ.*: " { send "$pass\n"; expect eof }
- timeout { perror "Timeout waiting for kinit"; close }
- eof
- }
-
- set ret [wait]
- if {[lindex $ret $wait_error_index] == -1} {
- perror \
- "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]"
- } else {
- if {[lindex $ret $wait_status_index] != 0} {
- perror \
- "kinit $princ failed with [lindex $ret $wait_status_index]"
- }
- }
-}
-
-proc flush_server {} {
- global server_id
- global expect_out
-
- verbose "flushing server output" 1
-
- while {1} {
- set timeout 5
-
- expect {
- -i $server_id
- -re "^.+$" {
- verbose "server output: $expect_out(buffer)"
- }
- timeout { break }
- }
- }
-}
-
-proc start_client {testname ccname user password lifetime count
- {target ""}} {
- global env CLIENT PROT hostname server_port spawn_id verbose
-
- if {$target == ""} {
- set target "server@$hostname"
- }
-
- set env(KRB5CCNAME) FILE:[pwd]/krb5cc_rpc_test_$ccname
- kinit $user $password $lifetime
-
- if {$verbose > 0} {
- spawn $CLIENT -a 1 -s 1 -m 1 $PROT $hostname $server_port $target $count
- } else {
- spawn $CLIENT $PROT $hostname $server_port $target $count
- }
-
- verbose "$testname: client $ccname started"
-
- unset env(KRB5CCNAME)
-}
-
-proc eof_client {testname ccname id status} {
- verbose "$testname: eof'ing for client $ccname" 1
-
- expect {
- -i $id
- -re "^marshall_new_creds\[^\n\]*\n" { exp_continue }
- -re "^gssapi_\[^\n\]*\n" { exp_continue }
- -re "^\r?\n" { exp_continue }
- eof { verbose $expect_out(buffer) 1 }
- timeout {
- fail "$testname: timeout waiting for client $ccname to exit"
- }
- }
- wait_client $testname $ccname $id $status
-}
-
-
-proc wait_client {testname ccname id status} {
- global env
- global kill
- global kdestroy
- global wait_error_index wait_errno_index wait_status_index
-
- verbose "$testname: waiting for client $ccname" 1
-
- set ret [wait -i $id]
- if {[lindex $ret $wait_error_index] == -1} {
- fail \
- "$testname: wait $ccname returned error [lindex $ret $wait_errno_index]"
- } else {
- if {[lindex $ret $wait_status_index] == $status} {
- pass "$testname: client $ccname"
- } else {
- fail "$testname: client $ccname: unexpected return status [lindex $ret $wait_status_index], should be $status."
- }
- }
-
- set env(KRB5CCNAME) FILE:[pwd]/krb5cc_rpc_test_$ccname
- if {[catch "exec $kdestroy -5"] != 0} {
- perror "$testname: cannot destroy client $ccname ccache"
- }
-
- unset env(KRB5CCNAME)
-}
diff --git a/src/lib/rpc/unit-test/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/rpc_test.0/expire.exp
deleted file mode 100644
index e19cca0ef..000000000
--- a/src/lib/rpc/unit-test/rpc_test.0/expire.exp
+++ /dev/null
@@ -1,49 +0,0 @@
-set timeout 40
-
-load_lib "helpers.exp"
-
-global server_started
-
-proc expired {} {
- global spawn_id server_id
-
- start_client expired expired testuser notathena -1m 100
- eof_client expired expired $spawn_id 2
-
- expect {
- -i $server_id
- -re "rpc_test server: Authen.*failed:.*credential.*expired" { pass "expired" }
- timeout { fail "expired: timeout waiting for expired creds error" }
- }
-
- flush_server
-}
-
-# This test doesn't work after #6948, because the client won't try to
-# authenticate using an expired TGT.
-#if { $server_started } {expired }
-
-proc overlap {} {
- global spawn_id
-
- start_client expire 1 testuser notathena 20m 100
- set client1_id $spawn_id
- flush_server
-
- start_client expire 2 testuser notathena 40m 300
- set client2_id $spawn_id
- flush_server
-
- start_client expire 3 testuser notathena 60m 500
- set client3_id $spawn_id
- flush_server
-
- eof_client expire 1 $client1_id 0
- eof_client expire 2 $client2_id 0
- eof_client expire 3 $client3_id 0
-
- flush_server
-}
-if { $server_started } {overlap}
-
-
diff --git a/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp b/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
deleted file mode 100644
index 73083de1f..000000000
--- a/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
+++ /dev/null
@@ -1,91 +0,0 @@
-set timeout 120
-
-load_lib "helpers.exp"
-
-global spawn_id
-global server_id
-global server_started
-
-if { !$server_started } {return}
-
-# Start the client and do a full run
-start_client "full run" fullrun testuser notathena 8h 1026
-set client_id $spawn_id
-
-#
-# test: did we get 11 dots?
-#
-verbose "Starting RPC echo test. This will take about 50 seconds.\n"
-
-set ver_line "rpc_test server: bad verifier\[^\r\n\]*\[\r\n]+"
-
-set dots 0
-set server_lines 0
-while {1} {
- expect {
- -i $server_id
- -re $ver_line {
- verbose "Got line from server."
- incr server_lines
- }
- default {
- exp_continue
- }
-
- -i $client_id
- . {
- incr dots
- verbose "$expect_out(buffer)" 1
- if ($dots==11) { break }
- }
- eof {
- #
- # test: was the exit status right?
- #
- wait_client "full run" fullrun $client_id 0
- break
- }
-
- timeout {
- verbose "Timeout waiting for dot\n" 1
- fail "full run: timeout waiting for dot"
- break
- }
- }
-}
-if {$dots==11} {
- pass "fullrun: echo test"
-} else {
- fail "fullrun: echo test: expected 11 dots, got $dots"
-}
-
-#
-# test: server logged four bad verifiers?
-#
-verbose "full run: checking server output"
-
-# Small timeout, since the server should have already printed everything
-set timeout 5
-
-while {$server_lines < 4} {
- expect {
- -i $server_id
- -re $ver_line {
- incr server_lines
- }
- -re ".+\r\n" {
- verbose "Unexpected server output: $expect_out(buffer)"
- }
- default {
- break
- }
- }
-}
-
-if {$server_lines == 4} {
- pass "fullrun: bad verifiers"
-} else {
- fail "fullrun: expected four bad verifiers, got $server_lines"
-}
-
-flush_server
diff --git a/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp b/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
deleted file mode 100644
index 005971989..000000000
--- a/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
+++ /dev/null
@@ -1,30 +0,0 @@
-set timeout 30
-
-load_lib "helpers.exp"
-
-global spawn_id
-global server_id
-global server_started
-global hostname
-
-if { !$server_started } {return}
-
-start_client "gss err" gsserr testuser notathena 8h 1026 notserver@$hostname
-
-eof_client "gss err" gsserr $spawn_id 2
-
-#
-# test: server logged an authentication attempted failed?
-#
-verbose "gss err: checking server output"
-
-expect {
- -i $server_id
- -re "rpc_test server: Authent.*failed: .* not found in keytab" {
- pass "gss err: server logged auth error"
- }
- eof { fail "gss err: server exited" }
- timeout { fail "gss err: timeout waiting for server output" }
-}
-
-flush_server
diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c
index 13e99bb06..c3bbcbf8c 100644
--- a/src/lib/rpc/unit-test/server.c
+++ b/src/lib/rpc/unit-test/server.c
@@ -37,7 +37,7 @@ static void rpc_test_badverf(gss_name_t client, gss_name_t server,
caddr_t data);
#ifndef SERVICE_NAME
-#define SERVICE_NAME "server"
+#define SERVICE_NAME "host"
#endif
static void usage()
@@ -120,7 +120,6 @@ main(int argc, char **argv)
prot == IPPROTO_TCP ? "tcp" : "udp");
exit(1);
}
- printf("port: %d\n", (int)transp->xp_port);
if (svcauth_gssapi_set_names(names, 0) == FALSE) {
fprintf(stderr, "unable to set gssapi names\n");
@@ -144,6 +143,8 @@ main(int argc, char **argv)
signal(SIGTERM, handlesig);
#endif
printf("running\n");
+ printf("port: %d\n", (int)transp->xp_port);
+ fflush(stdout);
svc_run();
fprintf(stderr, "svc_run returned");
@@ -177,6 +178,7 @@ static void rpc_test_badverf(gss_name_t client, gss_name_t server,
inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr),
ntohs(rqst->rq_xprt->xp_raddr.sin_port),
(int) server_name.length, (char *) server_name.value);
+ fflush(stdout);
(void) gss_release_buffer(&minor_stat, &client_name);
(void) gss_release_buffer(&minor_stat, &server_name);
@@ -211,6 +213,7 @@ void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
printf("rpc_test server: Authentication attempt failed: %s", a);
log_badauth_display_status(major, minor);
printf("\n");
+ fflush(stdout);
}
void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
@@ -220,6 +223,7 @@ void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
printf("Miscellaneous RPC error: %s, %s\n", a, error);
+ fflush(stdout);
}
void log_badauth_display_status(OM_uint32 major, OM_uint32 minor)
@@ -243,10 +247,12 @@ void log_badauth_display_status_1(OM_uint32 code, int type, int rec)
log_badauth_display_status_1(gssstat,GSS_C_GSS_CODE,1);
log_badauth_display_status_1(minor_stat,
GSS_C_MECH_CODE, 1);
- } else
+ } else {
printf("GSS-API authentication error %.*s: "
"recursive failure!\n", (int) msg.length,
(char *)msg.value);
+ }
+ fflush(stdout);
return;
}
@@ -256,4 +262,5 @@ void log_badauth_display_status_1(OM_uint32 code, int type, int rec)
if (!msg_ctx)
break;
}
+ fflush(stdout);
}
diff --git a/src/lib/rpc/unit-test/t_rpc.py b/src/lib/rpc/unit-test/t_rpc.py
new file mode 100644
index 000000000..4e565d25c
--- /dev/null
+++ b/src/lib/rpc/unit-test/t_rpc.py
@@ -0,0 +1,29 @@
+import re
+
+from k5test import *
+
+realm = K5Realm()
+
+server = realm.start_server(['./server', '-t'], 'running')
+line = server.stdout.readline()
+portstr = re.match(r'^port: (\d+)$', line).group(1)
+
+realm.run(['./client', '-t', hostname, portstr, 'host@' + hostname, '1026'],
+ expected_msg='...........')
+
+for i in range(4):
+ line = server.stdout.readline()
+ if 'rpc_test server: bad verifier from user@KRBTEST.COM at ' not in line:
+ fail('unexpected server message: ' + line)
+ output(line)
+
+realm.addprinc('nokey/' + hostname)
+
+realm.run(['./client', '-t', hostname, portstr, 'nokey@' + hostname, '1026'],
+ expected_code=2)
+
+line = server.stdout.readline()
+if 'rpc_test server: Authentication attempt failed: ' not in line:
+ fail('unexpected server message: ' + line)
+
+success('gssrpc auth_gssapi tests')

View File

@ -0,0 +1,41 @@
From 3e0d464f55320b393e32285f31710c24758a9101 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 4 Mar 2020 17:18:51 -0500
Subject: [PATCH] Use two queues for concurrent t_otp.py daemons
t_otp.py occasionally fails during the #8708 regression test, reading
a true answer instead of the expected false answer during the first
verify() call. Most likely the daemons are writing their answers to
the shared queue out of order. Use a separate queue for the second
daemon to ensure correct correlation of results.
(cherry picked from commit c03f67eefec05db19e84e889fab7c25904929633)
---
src/tests/t_otp.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index cba871a0f..c3b820a41 100755
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -256,16 +256,17 @@ verify(daemon, queue, True, realm.user_princ, 'accept')
## tokens configured, with the first rejecting and the second
## accepting. With the bug, the KDC incorrectly rejects the request
## and then performs invalid memory accesses, most likely crashing.
+queue2 = Queue()
daemon1 = UDPRadiusDaemon(args=(server_addr, secret_file, 'accept1', queue))
-daemon2 = UnixRadiusDaemon(args=(socket_file, None, 'accept2', queue))
+daemon2 = UnixRadiusDaemon(args=(socket_file, None, 'accept2', queue2))
daemon1.start()
queue.get()
daemon2.start()
-queue.get()
+queue2.get()
oconf = '[' + otpconfig_1('udp') + ', ' + otpconfig_1('unix') + ']'
realm.run([kadminl, 'setstr', realm.user_princ, 'otp', oconf])
realm.kinit(realm.user_princ, 'accept2', flags=flags)
verify(daemon1, queue, False, realm.user_princ.split('@')[0], 'accept2')
-verify(daemon2, queue, True, realm.user_princ, 'accept2')
+verify(daemon2, queue2, True, realm.user_princ, 'accept2')
success('OTP tests')

View File

@ -0,0 +1,72 @@
From 30ece66508c8e10f704cd2860dfd421ebee15897 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:45:26 -0400
Subject: [PATCH] [downstream] Adjust build configuration
Build binaries in this package as RELRO PIEs, libraries as partial RELRO,
and install shared libraries with the execute bit set on them. Prune out
the -L/usr/lib* and PIE flags where they might leak out and affect
apps which just want to link with the libraries. FIXME: needs to check and
not just assume that the compiler supports using these flags.
Last-updated: krb5-1.15-beta1
---
src/build-tools/krb5-config.in | 7 +++++++
src/config/pre.in | 2 +-
src/config/shlib.conf | 5 +++--
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
index c17cb5eb5..1891dea99 100755
--- a/src/build-tools/krb5-config.in
+++ b/src/build-tools/krb5-config.in
@@ -226,6 +226,13 @@ if test -n "$do_libs"; then
-e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \
-e 's#\$(CFLAGS)##'`
+ if test `dirname $libdir` = /usr ; then
+ lib_flags=`echo $lib_flags | sed -e "s#-L$libdir##" -e "s#$RPATH_FLAG$libdir##"`
+ fi
+ lib_flags=`echo $lib_flags | sed -e "s#-fPIE##g" -e "s#-pie##g"`
+ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,relro##g"`
+ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,now##g"`
+
if test $library = 'kdb'; then
lib_flags="$lib_flags -lkdb5 $KDB5_DB_LIB"
library=krb5
diff --git a/src/config/pre.in b/src/config/pre.in
index 917357df9..a8540ae2a 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -185,7 +185,7 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_STRIP)
INSTALL_SCRIPT=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@
INSTALL_SHLIB=@INSTALL_SHLIB@
-INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root
+INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755
## This is needed because autoconf will sometimes define @exec_prefix@ to be
## ${prefix}.
prefix=@prefix@
diff --git a/src/config/shlib.conf b/src/config/shlib.conf
index 3e4af6c02..2b20c3fda 100644
--- a/src/config/shlib.conf
+++ b/src/config/shlib.conf
@@ -423,7 +423,7 @@ mips-*-netbsd*)
# Linux ld doesn't default to stuffing the SONAME field...
# Use objdump -x to examine the fields of the library
# UNDEF_CHECK is suppressed by --enable-asan
- LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK)'
+ LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK) -Wl,-z,relro -Wl,--warn-shared-textrel'
UNDEF_CHECK='-Wl,--no-undefined'
# $(EXPORT_CHECK) runs export-check.pl when in maintainer mode.
LDCOMBINE_TAIL='-Wl,--version-script binutils.versions $(EXPORT_CHECK)'
@@ -435,7 +435,8 @@ mips-*-netbsd*)
SHLIB_EXPFLAGS='$(SHLIB_RPATH_FLAGS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
PROFFLAGS=-pg
PROG_RPATH_FLAGS='$(RPATH_FLAG)$(PROG_RPATH)'
- CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) $(LDFLAGS)'
+ CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) -pie -Wl,-z,relro -Wl,-z,now $(LDFLAGS)'
+ INSTALL_SHLIB='${INSTALL} -m755'
CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
CXX_LINK_SHARED='$(CXX) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CXXFLAGS) $(LDFLAGS)'
CXX_LINK_STATIC='$(CXX) $(PROG_LIBPATH) $(CXXFLAGS) $(LDFLAGS)'

View File

@ -0,0 +1,602 @@
From bf8521bfaa4a4d54f6eb94f785c68942f4afa055 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 9 Nov 2018 15:12:21 -0500
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4
NB: Use openssl's PRNG in FIPS mode and taint within krad.
A lot of the FIPS error conditions from OpenSSL are incredibly
mysterious (at best, things return NULL unexpectedly; at worst,
internal assertions are tripped; most of the time, you just get
ENOMEM). In order to cope with this, we need to have some level of
awareness of what we can and can't safely call.
This will slow down some calls slightly (FIPS_mode() takes multiple
locks), but not for any ciphers we care about - which is to say that
AES is fine. Shame about SPAKE though.
post6 restores MD4 (and therefore keygen-only RC4).
post7 restores MD5 and adds radius_md5_fips_override.
Last-updated: krb5-1.17
---
doc/admin/conf_files/krb5_conf.rst | 6 +++
src/lib/crypto/krb/prng.c | 11 ++++-
.../crypto/openssl/enc_provider/camellia.c | 6 +++
src/lib/crypto/openssl/enc_provider/rc4.c | 13 +++++-
.../crypto/openssl/hash_provider/hash_evp.c | 12 +++++
src/lib/crypto/openssl/hmac.c | 6 ++-
src/lib/krad/attr.c | 46 ++++++++++++++-----
src/lib/krad/attrset.c | 5 +-
src/lib/krad/internal.h | 28 ++++++++++-
src/lib/krad/packet.c | 22 +++++----
src/lib/krad/remote.c | 10 +++-
src/lib/krad/t_attr.c | 3 +-
src/lib/krad/t_attrset.c | 4 +-
src/plugins/preauth/spake/spake_client.c | 6 +++
src/plugins/preauth/spake/spake_kdc.c | 6 +++
15 files changed, 151 insertions(+), 33 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 1d2aa7f68..3a8b9cf47 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -331,6 +331,12 @@ The libdefaults section may contain any of the following relations:
qualification of shortnames, set this relation to the empty string
with ``qualify_shortname = ""``. (New in release 1.18.)
+**radius_md5_fips_override**
+ Downstream-only option to enable use of MD5 in RADIUS
+ communication (libkrad). This allows for local (or protected
+ tunnel) communication with a RADIUS server that doesn't use krad
+ (e.g., freeradius) while in FIPS mode.
+
**rdns**
If this flag is true, reverse name lookup will be used in addition
to forward name lookup to canonicalizing hostnames for use in
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
index cb9ca9b98..f0e9984ca 100644
--- a/src/lib/crypto/krb/prng.c
+++ b/src/lib/crypto/krb/prng.c
@@ -26,6 +26,8 @@
#include "crypto_int.h"
+#include <openssl/rand.h>
+
krb5_error_code KRB5_CALLCONV
krb5_c_random_seed(krb5_context context, krb5_data *data)
{
@@ -99,9 +101,16 @@ krb5_boolean
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
{
const char *device;
-#if defined(__linux__) && defined(SYS_getrandom)
int r;
+ /* A wild FIPS mode appeared! */
+ if (FIPS_mode()) {
+ /* The return codes on this API are not good */
+ r = RAND_bytes(buf, len);
+ return r == 1;
+ }
+
+#if defined(__linux__) && defined(SYS_getrandom)
while (len > 0) {
/*
* Pull from the /dev/urandom pool, but require it to have been seeded.
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
index 2da691329..f79679a0b 100644
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
struct iov_cursor cursor;
+ if (FIPS_mode())
+ return KRB5_CRYPTO_INTERNAL;
+
if (output->length < CAMELLIA_BLOCK_SIZE)
return KRB5_BAD_MSIZE;
@@ -331,6 +334,9 @@ static krb5_error_code
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
krb5_data *state)
{
+ if (FIPS_mode())
+ return KRB5_CRYPTO_INTERNAL;
+
state->length = 16;
state->data = (void *) malloc(16);
if (state->data == NULL)
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
index a65d57b7a..6ccaca94a 100644
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
EVP_CIPHER_CTX *ctx = NULL;
struct arcfour_state *arcstate;
+ if (FIPS_mode())
+ return KRB5_CRYPTO_INTERNAL;
+
arcstate = (state != NULL) ? (void *)state->data : NULL;
if (arcstate != NULL) {
ctx = arcstate->ctx;
@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
static void
k5_arcfour_free_state(krb5_data *state)
{
- struct arcfour_state *arcstate = (void *)state->data;
+ struct arcfour_state *arcstate;
+
+ if (FIPS_mode())
+ return;
+
+ arcstate = (void *) state->data;
EVP_CIPHER_CTX_free(arcstate->ctx);
free(arcstate);
@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
{
struct arcfour_state *arcstate;
+ if (FIPS_mode())
+ return KRB5_CRYPTO_INTERNAL;
+
/*
* The cipher state here is a saved pointer to a struct arcfour_state
* object, rather than a flat byte array as in most enc providers. The
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
index 1e0fb8fc3..2eb5139c0 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -49,6 +49,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
if (ctx == NULL)
return ENOMEM;
+ if (type == EVP_md4() || type == EVP_md5()) {
+ /* See comments below in hash_md4() and hash_md5(). */
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ }
+
ok = EVP_DigestInit_ex(ctx, type, NULL);
for (i = 0; i < num_data; i++) {
if (!SIGN_IOV(&data[i]))
@@ -64,12 +69,19 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
static krb5_error_code
hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
{
+ /*
+ * MD4 is needed in FIPS mode to perform key generation for RC4 keys used
+ * by IPA. These keys are only used along a (separately) secured channel
+ * for legacy reasons when performing trusts to Active Directory.
+ */
return hash_evp(EVP_md4(), data, num_data, output);
}
static krb5_error_code
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
{
+ /* MD5 is needed in FIPS mode for communication with RADIUS servers. This
+ * is gated in libkrad by libdefaults->radius_md5_fips_override. */
return hash_evp(EVP_md5(), data, num_data, output);
}
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index 7dc59dcc0..769a50c00 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
return EVP_sha256();
else if (!strncmp(hash->hash_name, "SHA-384",7))
return EVP_sha384();
- else if (!strncmp(hash->hash_name, "MD5", 3))
+
+ if (FIPS_mode())
+ return NULL;
+
+ if (!strncmp(hash->hash_name, "MD5", 3))
return EVP_md5();
else if (!strncmp(hash->hash_name, "MD4", 3))
return EVP_md4();
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
index 9c13d9d75..42d354a3b 100644
--- a/src/lib/krad/attr.c
+++ b/src/lib/krad/attr.c
@@ -38,7 +38,8 @@
typedef krb5_error_code
(*attribute_transform_fn)(krb5_context ctx, const char *secret,
const unsigned char *auth, const krb5_data *in,
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+ krb5_boolean *is_fips);
typedef struct {
const char *name;
@@ -51,12 +52,14 @@ typedef struct {
static krb5_error_code
user_password_encode(krb5_context ctx, const char *secret,
const unsigned char *auth, const krb5_data *in,
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+ krb5_boolean *is_fips);
static krb5_error_code
user_password_decode(krb5_context ctx, const char *secret,
const unsigned char *auth, const krb5_data *in,
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+ krb5_boolean *ignored);
static const attribute_record attributes[UCHAR_MAX] = {
{"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
@@ -128,7 +131,8 @@ static const attribute_record attributes[UCHAR_MAX] = {
static krb5_error_code
user_password_encode(krb5_context ctx, const char *secret,
const unsigned char *auth, const krb5_data *in,
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+ krb5_boolean *is_fips)
{
const unsigned char *indx;
krb5_error_code retval;
@@ -154,8 +158,15 @@ user_password_encode(krb5_context ctx, const char *secret,
for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
- &sum);
+ if (kr_use_fips(ctx)) {
+ /* Skip encryption here. Taint so that we won't pass it out of
+ * the machine by accident. */
+ *is_fips = TRUE;
+ sum.contents = calloc(1, BLOCKSIZE);
+ } else {
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
+ &sum);
+ }
if (retval != 0) {
zap(tmp.data, tmp.length);
zap(outbuf, len);
@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret,
static krb5_error_code
user_password_decode(krb5_context ctx, const char *secret,
const unsigned char *auth, const krb5_data *in,
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+ krb5_boolean *is_fips)
{
const unsigned char *indx;
krb5_error_code retval;
@@ -204,8 +216,15 @@ user_password_decode(krb5_context ctx, const char *secret,
for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
- &tmp, &sum);
+ if (kr_use_fips(ctx)) {
+ /* Skip encryption here. Taint so that we won't pass it out of
+ * the machine by accident. */
+ *is_fips = TRUE;
+ sum.contents = calloc(1, BLOCKSIZE);
+ } else {
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
+ &tmp, &sum);
+ }
if (retval != 0) {
zap(tmp.data, tmp.length);
zap(outbuf, in->length);
@@ -248,7 +267,7 @@ krb5_error_code
kr_attr_encode(krb5_context ctx, const char *secret,
const unsigned char *auth, krad_attr type,
const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
- size_t *outlen)
+ size_t *outlen, krb5_boolean *is_fips)
{
krb5_error_code retval;
@@ -265,7 +284,8 @@ kr_attr_encode(krb5_context ctx, const char *secret,
return 0;
}
- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
+ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen,
+ is_fips);
}
krb5_error_code
@@ -274,6 +294,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
{
krb5_error_code retval;
+ krb5_boolean ignored;
retval = kr_attr_valid(type, in);
if (retval != 0)
@@ -288,7 +309,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
return 0;
}
- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
+ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen,
+ &ignored);
}
krad_attr
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
index 03c613716..d89982a13 100644
--- a/src/lib/krad/attrset.c
+++ b/src/lib/krad/attrset.c
@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
krb5_error_code
kr_attrset_encode(const krad_attrset *set, const char *secret,
const unsigned char *auth,
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
+ krb5_boolean *is_fips)
{
unsigned char buffer[MAX_ATTRSIZE];
krb5_error_code retval;
@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
K5_TAILQ_FOREACH(a, &set->list, list) {
retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
- buffer, &attrlen);
+ buffer, &attrlen, is_fips);
if (retval != 0)
return retval;
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index 996a89372..312dc8258 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -39,6 +39,8 @@
#include <sys/socket.h>
#include <netdb.h>
+#include <openssl/crypto.h>
+
#ifndef UCHAR_MAX
#define UCHAR_MAX 255
#endif
@@ -49,6 +51,13 @@
typedef struct krad_remote_st krad_remote;
+struct krad_packet_st {
+ char buffer[KRAD_PACKET_SIZE_MAX];
+ krad_attrset *attrset;
+ krb5_data pkt;
+ krb5_boolean is_fips;
+};
+
/* Validate constraints of an attribute. */
krb5_error_code
kr_attr_valid(krad_attr type, const krb5_data *data);
@@ -57,7 +66,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data);
krb5_error_code
kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth,
krad_attr type, const krb5_data *in,
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+ krb5_boolean *is_fips);
/* Decode an attribute. */
krb5_error_code
@@ -69,7 +79,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
krb5_error_code
kr_attrset_encode(const krad_attrset *set, const char *secret,
const unsigned char *auth,
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
+ krb5_boolean *is_fips);
/* Decode attributes from a buffer. */
krb5_error_code
@@ -152,4 +163,17 @@ gai_error_code(int err)
}
}
+static inline krb5_boolean
+kr_use_fips(krb5_context ctx)
+{
+ int val = 0;
+
+ if (!FIPS_mode())
+ return 0;
+
+ profile_get_boolean(ctx->profile, "libdefaults",
+ "radius_md5_fips_override", NULL, 0, &val);
+ return !val;
+}
+
#endif /* INTERNAL_H_ */
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index c597174b6..fc2d24800 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
-struct krad_packet_st {
- char buffer[KRAD_PACKET_SIZE_MAX];
- krad_attrset *attrset;
- krb5_data pkt;
-};
-
typedef struct {
uchar x[(UCHAR_MAX + 1) / 8];
} idmap;
@@ -187,8 +181,14 @@ auth_generate_response(krb5_context ctx, const char *secret,
memcpy(data.data + response->pkt.length, secret, strlen(secret));
/* Hash it. */
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
- &hash);
+ if (kr_use_fips(ctx)) {
+ /* This checksum does very little security-wise anyway, so don't
+ * taint. */
+ hash.contents = calloc(1, AUTH_FIELD_SIZE);
+ } else {
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
+ &hash);
+ }
free(data.data);
if (retval != 0)
return retval;
@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
/* Encode the attributes. */
retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
- &attrset_len);
+ &attrset_len, &pkt->is_fips);
if (retval != 0)
goto error;
@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
/* Encode the attributes. */
retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
- &attrset_len);
+ &attrset_len, &pkt->is_fips);
if (retval != 0)
goto error;
@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
const krb5_data *
krad_packet_encode(const krad_packet *pkt)
{
+ if (pkt->is_fips)
+ return NULL;
return &pkt->pkt;
}
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 437f7e91a..0f90443ce 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
request *r;
K5_TAILQ_FOREACH(r, &rr->list, list) {
- tmp = krad_packet_encode(r->request);
+ tmp = &r->request->pkt;
/* If the packet has already been sent, do nothing. */
if (r->sent == tmp->length)
@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr)
if (req != NULL) {
K5_TAILQ_FOREACH(r, &rr->list, list) {
if (r->request == req &&
- r->sent == krad_packet_encode(req)->length) {
+ r->sent == req->pkt.length) {
request_finish(r, 0, rsp);
break;
}
@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
(krad_packet_iter_cb)iterator, &r, &tmp);
if (retval != 0)
goto error;
+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
+ rr->info->ai_family != AF_UNIX) {
+ /* This would expose cleartext passwords, so abort. */
+ retval = ESOCKTNOSUPPORT;
+ goto error;
+ }
K5_TAILQ_FOREACH(r, &rr->list, list) {
if (r->request == tmp) {
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
index eb2a780c8..4d285ad9d 100644
--- a/src/lib/krad/t_attr.c
+++ b/src/lib/krad/t_attr.c
@@ -50,6 +50,7 @@ main()
const char *tmp;
krb5_data in;
size_t len;
+ krb5_boolean is_fips = FALSE;
noerror(krb5_init_context(&ctx));
@@ -73,7 +74,7 @@ main()
in = string2data((char *)decoded);
retval = kr_attr_encode(ctx, secret, auth,
krad_attr_name2num("User-Password"),
- &in, outbuf, &len);
+ &in, outbuf, &len, &is_fips);
insist(retval == 0);
insist(len == sizeof(encoded));
insist(memcmp(outbuf, encoded, len) == 0);
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
index 7928335ca..0f9576253 100644
--- a/src/lib/krad/t_attrset.c
+++ b/src/lib/krad/t_attrset.c
@@ -49,6 +49,7 @@ main()
krb5_context ctx;
size_t len = 0, encode_len;
krb5_data tmp;
+ krb5_boolean is_fips = FALSE;
noerror(krb5_init_context(&ctx));
noerror(krad_attrset_new(ctx, &set));
@@ -62,7 +63,8 @@ main()
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
/* Encode attrset. */
- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
+ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
+ &is_fips));
krad_attrset_free(set);
/* Manually encode User-Name. */
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
index 00734a13b..a3ce22b70 100644
--- a/src/plugins/preauth/spake/spake_client.c
+++ b/src/plugins/preauth/spake/spake_client.c
@@ -38,6 +38,8 @@
#include "groups.h"
#include <krb5/clpreauth_plugin.h>
+#include <openssl/crypto.h>
+
typedef struct reqstate_st {
krb5_pa_spake *msg; /* set in prep_questions, used in process */
krb5_keyblock *initial_key;
@@ -375,6 +377,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
if (maj_ver != 1)
return KRB5_PLUGIN_VER_NOTSUPP;
+
+ if (FIPS_mode())
+ return KRB5_CRYPTO_INTERNAL;
+
vt = (krb5_clpreauth_vtable)vtable;
vt->name = "spake";
vt->pa_type_list = pa_types;
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
index 88c964ce1..c7df0392f 100644
--- a/src/plugins/preauth/spake/spake_kdc.c
+++ b/src/plugins/preauth/spake/spake_kdc.c
@@ -41,6 +41,8 @@
#include <krb5/kdcpreauth_plugin.h>
+#include <openssl/crypto.h>
+
/*
* The SPAKE kdcpreauth module uses a secure cookie containing the following
* concatenated fields (all integer fields are big-endian):
@@ -571,6 +573,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
if (maj_ver != 1)
return KRB5_PLUGIN_VER_NOTSUPP;
+
+ if (FIPS_mode())
+ return KRB5_CRYPTO_INTERNAL;
+
vt = (krb5_kdcpreauth_vtable)vtable;
vt->name = "spake";
vt->pa_type_list = pa_types;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,752 @@
From 040dd62418b918adc993b9cc3e1e80fc232286c4 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 15 Nov 2019 20:05:16 +0000
Subject: [PATCH] [downstream] Use backported version of OpenSSL-3 KDF
interface
Last-updated: krb5-1.17
---
src/configure.ac | 4 +
src/lib/crypto/krb/derive.c | 356 +++++++++++++-----
.../preauth/pkinit/pkinit_crypto_openssl.c | 257 ++++++++-----
3 files changed, 428 insertions(+), 189 deletions(-)
diff --git a/src/configure.ac b/src/configure.ac
index d4e4da525..29be532cb 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -282,6 +282,10 @@ AC_SUBST(CRYPTO_IMPL)
AC_SUBST(CRYPTO_IMPL_CFLAGS)
AC_SUBST(CRYPTO_IMPL_LIBS)
+AC_CHECK_FUNCS(EVP_KDF_CTX_new_id EVP_KDF_ctrl EVP_KDF_derive,
+ AC_DEFINE(OSSL_KDFS, 1, [Define if using OpenSSL KDFs]),
+ AC_MSG_ERROR([backported OpenSSL KDFs not found]))
+
AC_ARG_WITH([prng-alg],
AC_HELP_STRING([--with-prng-alg=ALG], [use specified PRNG algorithm. @<:@fortuna@:>@]),
[PRNG_ALG=$withval
diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c
index 6707a7308..915a173dd 100644
--- a/src/lib/crypto/krb/derive.c
+++ b/src/lib/crypto/krb/derive.c
@@ -27,6 +27,13 @@
#include "crypto_int.h"
+#ifdef OSSL_KDFS
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#else
+#error "Refusing to build without OpenSSL KDFs!"
+#endif
+
static krb5_key
find_cached_dkey(struct derived_key *list, const krb5_data *constant)
{
@@ -77,55 +84,193 @@ cleanup:
return ENOMEM;
}
+#ifdef OSSL_KDFS
static krb5_error_code
-derive_random_rfc3961(const struct krb5_enc_provider *enc,
- krb5_key inkey, krb5_data *outrnd,
- const krb5_data *in_constant)
+openssl_kbdkf_counter_hmac(const struct krb5_hash_provider *hash,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *label, const krb5_data *context)
{
- size_t blocksize, keybytes, n;
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_MD *digest;
+
+ if (!strcmp(hash->hash_name, "SHA1"))
+ digest = EVP_sha1();
+ else if (!strcmp(hash->hash_name, "SHA-256"))
+ digest = EVP_sha256();
+ else if (!strcmp(hash->hash_name, "SHA-384"))
+ digest = EVP_sha384();
+ else
+ goto done;
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+ if (!ctx)
+ goto done;
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
+ EVP_KDF_KB_MAC_TYPE_HMAC) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
+ inkey->keyblock.length) != 1 ||
+ (context->length > 0 &&
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_INFO, context->data,
+ context->length) != 1) ||
+ (label->length > 0 &&
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, label->data,
+ label->length) != 1) ||
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
+ outrnd->length) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ if (ret)
+ zap(outrnd->data, outrnd->length);
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+
+static krb5_error_code
+openssl_kbkdf_feedback_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_CIPHER *cipher;
+ static unsigned char zeroes[16];
+
+ memset(zeroes, 0, sizeof(zeroes));
+
+ if (enc->keylength == 16)
+ cipher = EVP_camellia_128_cbc();
+ else if (enc->keylength == 32)
+ cipher = EVP_camellia_256_cbc();
+ else
+ goto done;
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+ if (!ctx)
+ goto done;
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MODE,
+ EVP_KDF_KB_MODE_FEEDBACK) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
+ EVP_KDF_KB_MAC_TYPE_CMAC) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
+ inkey->keyblock.length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, in_constant->data,
+ in_constant->length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_SEED, zeroes,
+ sizeof(zeroes)) != 1 ||
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
+ outrnd->length) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ if (ret)
+ zap(outrnd->data, outrnd->length);
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+
+static krb5_error_code
+openssl_krb5kdf(const struct krb5_enc_provider *enc, krb5_key inkey,
+ krb5_data *outrnd, const krb5_data *in_constant)
+{
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_CIPHER *cipher;
+
+ if (inkey->keyblock.length != enc->keylength ||
+ outrnd->length != enc->keybytes) {
+ return KRB5_CRYPTO_INTERNAL;
+ }
+
+ if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 16)
+ cipher = EVP_aes_128_cbc();
+ else if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 32)
+ cipher = EVP_aes_256_cbc();
+ else if (enc->keylength == 24)
+ cipher = EVP_des_ede3_cbc();
+ else
+ goto done;
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF);
+ if (ctx == NULL)
+ goto done;
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
+ inkey->keyblock.length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT,
+ in_constant->data, in_constant->length) != 1 ||
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
+ outrnd->length) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ if (ret)
+ zap(outrnd->data, outrnd->length);
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+
+#else /* OSSL_KDFS */
+
+/*
+ * NIST SP800-108 KDF in counter mode (section 5.1).
+ * Parameters:
+ * - HMAC (with hash as the hash provider) is the PRF.
+ * - A block counter of four bytes is used.
+ * - Four bytes are used to encode the output length in the PRF input.
+ *
+ * There are no uses requiring more than a single PRF invocation.
+ */
+static krb5_error_code
+builtin_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *label,
+ const krb5_data *context)
+{
+ krb5_crypto_iov iov[5];
krb5_error_code ret;
- krb5_data block = empty_data();
+ krb5_data prf;
+ unsigned char ibuf[4], lbuf[4];
- blocksize = enc->block_size;
- keybytes = enc->keybytes;
-
- if (blocksize == 1)
- return KRB5_BAD_ENCTYPE;
- if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
+ if (hash == NULL || outrnd->length > hash->hashsize)
return KRB5_CRYPTO_INTERNAL;
/* Allocate encryption data buffer. */
- ret = alloc_data(&block, blocksize);
+ ret = alloc_data(&prf, hash->hashsize);
if (ret)
return ret;
- /* Initialize the input block. */
- if (in_constant->length == blocksize) {
- memcpy(block.data, in_constant->data, blocksize);
- } else {
- krb5int_nfold(in_constant->length * 8,
- (unsigned char *) in_constant->data,
- blocksize * 8, (unsigned char *) block.data);
- }
+ /* [i]2: four-byte big-endian binary string giving the block counter (1) */
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[0].data = make_data(ibuf, sizeof(ibuf));
+ store_32_be(1, ibuf);
+ /* Label */
+ iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[1].data = *label;
+ /* 0x00: separator byte */
+ iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[2].data = make_data("", 1);
+ /* Context */
+ iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[3].data = *context;
+ /* [L]2: four-byte big-endian binary string giving the output length */
+ iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[4].data = make_data(lbuf, sizeof(lbuf));
+ store_32_be(outrnd->length * 8, lbuf);
- /* Loop encrypting the blocks until enough key bytes are generated. */
- n = 0;
- while (n < keybytes) {
- ret = encrypt_block(enc, inkey, &block);
- if (ret)
- goto cleanup;
-
- if ((keybytes - n) <= blocksize) {
- memcpy(outrnd->data + n, block.data, (keybytes - n));
- break;
- }
-
- memcpy(outrnd->data + n, block.data, blocksize);
- n += blocksize;
- }
-
-cleanup:
- zapfree(block.data, blocksize);
+ ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
+ if (!ret)
+ memcpy(outrnd->data, prf.data, outrnd->length);
+ zapfree(prf.data, prf.length);
return ret;
}
@@ -139,9 +284,9 @@ cleanup:
* - Four bytes are used to encode the output length in the PRF input.
*/
static krb5_error_code
-derive_random_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
- krb5_key inkey, krb5_data *outrnd,
- const krb5_data *in_constant)
+builtin_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
{
size_t blocksize, keybytes, n;
krb5_crypto_iov iov[6];
@@ -204,56 +349,94 @@ cleanup:
return ret;
}
-/*
- * NIST SP800-108 KDF in counter mode (section 5.1).
- * Parameters:
- * - HMAC (with hash as the hash provider) is the PRF.
- * - A block counter of four bytes is used.
- * - Four bytes are used to encode the output length in the PRF input.
- *
- * There are no uses requiring more than a single PRF invocation.
- */
+static krb5_error_code
+builtin_derive_random_rfc3961(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+ size_t blocksize, keybytes, n;
+ krb5_error_code ret;
+ krb5_data block = empty_data();
+
+ blocksize = enc->block_size;
+ keybytes = enc->keybytes;
+
+ if (blocksize == 1)
+ return KRB5_BAD_ENCTYPE;
+ if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
+ return KRB5_CRYPTO_INTERNAL;
+
+ /* Allocate encryption data buffer. */
+ ret = alloc_data(&block, blocksize);
+ if (ret)
+ return ret;
+
+ /* Initialize the input block. */
+ if (in_constant->length == blocksize) {
+ memcpy(block.data, in_constant->data, blocksize);
+ } else {
+ krb5int_nfold(in_constant->length * 8,
+ (unsigned char *) in_constant->data,
+ blocksize * 8, (unsigned char *) block.data);
+ }
+
+ /* Loop encrypting the blocks until enough key bytes are generated. */
+ n = 0;
+ while (n < keybytes) {
+ ret = encrypt_block(enc, inkey, &block);
+ if (ret)
+ goto cleanup;
+
+ if ((keybytes - n) <= blocksize) {
+ memcpy(outrnd->data + n, block.data, (keybytes - n));
+ break;
+ }
+
+ memcpy(outrnd->data + n, block.data, blocksize);
+ n += blocksize;
+ }
+
+cleanup:
+ zapfree(block.data, blocksize);
+ return ret;
+}
+#endif /* OSSL_KDFS */
+
krb5_error_code
k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
krb5_key inkey, krb5_data *outrnd,
const krb5_data *label, const krb5_data *context)
{
- krb5_crypto_iov iov[5];
- krb5_error_code ret;
- krb5_data prf;
- unsigned char ibuf[4], lbuf[4];
+#ifdef OSSL_KDFS
+ return openssl_kbdkf_counter_hmac(hash, inkey, outrnd, label, context);
+#else
+ return builtin_sp800_108_counter_hmac(hash, inkey, outrnd, label,
+ context);
+#endif
+}
- if (hash == NULL || outrnd->length > hash->hashsize)
- return KRB5_CRYPTO_INTERNAL;
+static krb5_error_code
+k5_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+#ifdef OSSL_KDFS
+ return openssl_kbkdf_feedback_cmac(enc, inkey, outrnd, in_constant);
+#else
+ return builtin_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
+#endif
+}
- /* Allocate encryption data buffer. */
- ret = alloc_data(&prf, hash->hashsize);
- if (ret)
- return ret;
-
- /* [i]2: four-byte big-endian binary string giving the block counter (1) */
- iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[0].data = make_data(ibuf, sizeof(ibuf));
- store_32_be(1, ibuf);
- /* Label */
- iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[1].data = *label;
- /* 0x00: separator byte */
- iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[2].data = make_data("", 1);
- /* Context */
- iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[3].data = *context;
- /* [L]2: four-byte big-endian binary string giving the output length */
- iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[4].data = make_data(lbuf, sizeof(lbuf));
- store_32_be(outrnd->length * 8, lbuf);
-
- ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
- if (!ret)
- memcpy(outrnd->data, prf.data, outrnd->length);
- zapfree(prf.data, prf.length);
- return ret;
+static krb5_error_code
+k5_derive_random_rfc3961(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+#ifdef OSSL_KDFS
+ return openssl_krb5kdf(enc, inkey, outrnd, in_constant);
+#else
+ return builtin_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
+#endif
}
krb5_error_code
@@ -266,10 +449,9 @@ krb5int_derive_random(const struct krb5_enc_provider *enc,
switch (alg) {
case DERIVE_RFC3961:
- return derive_random_rfc3961(enc, inkey, outrnd, in_constant);
+ return k5_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
case DERIVE_SP800_108_CMAC:
- return derive_random_sp800_108_feedback_cmac(enc, inkey, outrnd,
- in_constant);
+ return k5_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
case DERIVE_SP800_108_HMAC:
return k5_sp800_108_counter_hmac(hash, inkey, outrnd, in_constant,
&empty);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 52976895b..dd718c2be 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -38,6 +38,13 @@
#include <dirent.h>
#include <arpa/inet.h>
+#ifdef OSSL_KDFS
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#else
+#error "Refusing to build without OpenSSL KDFs!"
+#endif
+
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
@@ -2331,11 +2338,51 @@ pkinit_alg_values(krb5_context context,
}
} /* pkinit_alg_values() */
+#ifdef OSSL_KDFS
+static krb5_error_code
+openssl_sskdf(krb5_context context, size_t hash_bytes, krb5_data *key,
+ krb5_data *info, char *out, size_t out_len)
+{
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_MD *digest;
-/* pkinit_alg_agility_kdf() --
- * This function generates a key using the KDF described in
- * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is
- * described as follows:
+ /* RFC 8636 defines a SHA384 variant, but we don't use it. */
+ if (hash_bytes == 20) {
+ digest = EVP_sha1();
+ } else if (hash_bytes == 32) {
+ digest = EVP_sha256();
+ } else if (hash_bytes == 64) {
+ digest = EVP_sha512();
+ } else {
+ krb5_set_error_message(context, ret, "Bad hash type for SSKDF");
+ goto done;
+ }
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SS);
+ if (!ctx) {
+ oerr(context, ret, _("Failed to instantiate SSKDF"));
+ goto done;
+ }
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key->data,
+ key->length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSKDF_INFO, info->data,
+ info->length) != 1 ||
+ EVP_KDF_derive(ctx, (unsigned char *)out, out_len) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+#else
+/*
+ * Generate a key using the KDF described in RFC 8636, also known as SSKDF
+ * (single-step kdf). Our caller precomputes `reps`, but otherwise the
+ * algorithm is as follows:
*
* 1. reps = keydatalen (K) / hash length (H)
*
@@ -2349,95 +2396,16 @@ pkinit_alg_values(krb5_context context,
*
* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes.
*/
-krb5_error_code
-pkinit_alg_agility_kdf(krb5_context context,
- krb5_data *secret,
- krb5_data *alg_oid,
- krb5_const_principal party_u_info,
- krb5_const_principal party_v_info,
- krb5_enctype enctype,
- krb5_data *as_req,
- krb5_data *pk_as_rep,
- krb5_keyblock *key_block)
+static krb5_error_code
+builtin_sskdf(krb5_context context, unsigned int reps, size_t hash_len,
+ const EVP_MD *(*EVP_func)(void), krb5_data *secret,
+ krb5_data *other_info, char *out, size_t out_len)
{
krb5_error_code retval = 0;
- unsigned int reps = 0;
- uint32_t counter = 1; /* Does this type work on Windows? */
+ uint32_t counter = 1;
size_t offset = 0;
- size_t hash_len = 0;
- size_t rand_len = 0;
- size_t key_len = 0;
- krb5_data random_data;
- krb5_sp80056a_other_info other_info_fields;
- krb5_pkinit_supp_pub_info supp_pub_info_fields;
- krb5_data *other_info = NULL;
- krb5_data *supp_pub_info = NULL;
- krb5_algorithm_identifier alg_id;
EVP_MD_CTX *ctx = NULL;
- const EVP_MD *(*EVP_func)(void);
-
- /* initialize random_data here to make clean-up safe */
- random_data.length = 0;
- random_data.data = NULL;
-
- /* allocate and initialize the key block */
- key_block->magic = 0;
- key_block->enctype = enctype;
- if (0 != (retval = krb5_c_keylengths(context, enctype, &rand_len,
- &key_len)))
- goto cleanup;
-
- random_data.length = rand_len;
- key_block->length = key_len;
-
- if (NULL == (key_block->contents = malloc(key_block->length))) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- memset (key_block->contents, 0, key_block->length);
-
- /* If this is anonymous pkinit, use the anonymous principle for party_u_info */
- if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info,
- krb5_anonymous_principal()))
- party_u_info = (krb5_principal)krb5_anonymous_principal();
-
- if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func)))
- goto cleanup;
-
- /* 1. reps = keydatalen (K) / hash length (H) */
- reps = key_block->length/hash_len;
-
- /* ... and round up, if necessary */
- if (key_block->length > (reps * hash_len))
- reps++;
-
- /* Allocate enough space in the random data buffer to hash directly into
- * it, even if the last hash will make it bigger than the key length. */
- if (NULL == (random_data.data = malloc(reps * hash_len))) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- /* Encode the ASN.1 octet string for "SuppPubInfo" */
- supp_pub_info_fields.enctype = enctype;
- supp_pub_info_fields.as_req = *as_req;
- supp_pub_info_fields.pk_as_rep = *pk_as_rep;
- if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
- &supp_pub_info))))
- goto cleanup;
-
- /* Now encode the ASN.1 octet string for "OtherInfo" */
- memset(&alg_id, 0, sizeof alg_id);
- alg_id.algorithm = *alg_oid; /*alias*/
-
- other_info_fields.algorithm_identifier = alg_id;
- other_info_fields.party_u_info = (krb5_principal) party_u_info;
- other_info_fields.party_v_info = (krb5_principal) party_v_info;
- other_info_fields.supp_pub_info = *supp_pub_info;
- if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info)))
- goto cleanup;
/* 2. Initialize a 32-bit, big-endian bit string counter as 1.
* 3. For i = 1 to reps by 1, do the following:
@@ -2471,8 +2439,9 @@ pkinit_alg_agility_kdf(krb5_context context,
goto cleanup;
}
- /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */
- if (!EVP_DigestFinal(ctx, (uint8_t *)random_data.data + offset, &s)) {
+ /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K
+ * bytes. */
+ if (!EVP_DigestFinal(ctx, (unsigned char *)out + offset, &s)) {
krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
"Call to OpenSSL EVP_DigestUpdate() returned an error.");
retval = KRB5_CRYPTO_INTERNAL;
@@ -2484,26 +2453,110 @@ pkinit_alg_agility_kdf(krb5_context context,
EVP_MD_CTX_free(ctx);
ctx = NULL;
}
-
- retval = krb5_c_random_to_key(context, enctype, &random_data,
- key_block);
-
cleanup:
EVP_MD_CTX_free(ctx);
+ return retval;
+} /* builtin_sskdf() */
+#endif /* OSSL_KDFS */
- /* If this has been an error, free the allocated key_block, if any */
- if (retval) {
- krb5_free_keyblock_contents(context, key_block);
+/* id-pkinit-kdf family, as specified by RFC 8636. */
+krb5_error_code
+pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
+ krb5_data *alg_oid, krb5_const_principal party_u_info,
+ krb5_const_principal party_v_info,
+ krb5_enctype enctype, krb5_data *as_req,
+ krb5_data *pk_as_rep, krb5_keyblock *key_block)
+{
+ krb5_error_code retval;
+ size_t hash_len = 0, rand_len = 0, key_len = 0;
+ const EVP_MD *(*EVP_func)(void);
+ krb5_sp80056a_other_info other_info_fields;
+ krb5_pkinit_supp_pub_info supp_pub_info_fields;
+ krb5_data *other_info = NULL, *supp_pub_info = NULL;
+ krb5_data random_data = empty_data();
+ krb5_algorithm_identifier alg_id;
+ unsigned int reps;
+
+ /* Allocate and initialize the key block. */
+ key_block->magic = 0;
+ key_block->enctype = enctype;
+
+ /* Use separate variables to avoid alignment restriction problems. */
+ retval = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
+ if (retval)
+ goto cleanup;
+ random_data.length = rand_len;
+ key_block->length = key_len;
+
+ key_block->contents = k5calloc(key_block->length, 1, &retval);
+ if (key_block->contents == NULL)
+ goto cleanup;
+
+ /* If this is anonymous pkinit, use the anonymous principle for
+ * party_u_info. */
+ if (party_u_info &&
+ krb5_principal_compare_any_realm(context, party_u_info,
+ krb5_anonymous_principal())) {
+ party_u_info = (krb5_principal)krb5_anonymous_principal();
}
- /* free other allocated resources, either way */
- if (random_data.data)
- free(random_data.data);
+ retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func);
+ if (retval)
+ goto cleanup;
+
+ /* 1. reps = keydatalen (K) / hash length (H) */
+ reps = key_block->length / hash_len;
+
+ /* ... and round up, if necessary. */
+ if (key_block->length > (reps * hash_len))
+ reps++;
+
+ /* Allocate enough space in the random data buffer to hash directly into
+ * it, even if the last hash will make it bigger than the key length. */
+ random_data.data = k5alloc(reps * hash_len, &retval);
+ if (random_data.data == NULL)
+ goto cleanup;
+
+ /* Encode the ASN.1 octet string for "SuppPubInfo". */
+ supp_pub_info_fields.enctype = enctype;
+ supp_pub_info_fields.as_req = *as_req;
+ supp_pub_info_fields.pk_as_rep = *pk_as_rep;
+ retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
+ &supp_pub_info);
+ if (retval)
+ goto cleanup;
+
+ /* Now encode the ASN.1 octet string for "OtherInfo". */
+ memset(&alg_id, 0, sizeof(alg_id));
+ alg_id.algorithm = *alg_oid;
+ other_info_fields.algorithm_identifier = alg_id;
+ other_info_fields.party_u_info = (krb5_principal)party_u_info;
+ other_info_fields.party_v_info = (krb5_principal)party_v_info;
+ other_info_fields.supp_pub_info = *supp_pub_info;
+ retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info);
+ if (retval)
+ goto cleanup;
+
+#ifdef OSSL_KDFS
+ retval = openssl_sskdf(context, hash_len, secret, other_info,
+ random_data.data, key_block->length);
+#else
+ retval = builtin_sskdf(context, reps, hash_len, EVP_func, secret,
+ other_info, random_data.data, key_block->length);
+#endif
+ if (retval)
+ goto cleanup;
+
+ retval = krb5_c_random_to_key(context, enctype, &random_data, key_block);
+cleanup:
+ if (retval)
+ krb5_free_keyblock_contents(context, key_block);
+
+ zapfree(random_data.data, random_data.length);
krb5_free_data(context, other_info);
krb5_free_data(context, supp_pub_info);
-
return retval;
-} /*pkinit_alg_agility_kdf() */
+}
/* Call DH_compute_key() and ensure that we left-pad short results instead of
* leaving junk bytes at the end of the buffer. */

View File

@ -0,0 +1,41 @@
From c6e103db0eb02c31a13b8cbcbae296c473074991 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:49:25 -0400
Subject: [PATCH] [downstream] fix debuginfo with y.tab.c
We want to keep these y.tab.c files around because the debuginfo points to
them. It would be more elegant at the end to use symbolic links, but that
could mess up people working in the tree on other things.
Last-updated: krb5-1.9
---
src/kadmin/cli/Makefile.in | 5 +++++
src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
index adfea6e2b..d1327e400 100644
--- a/src/kadmin/cli/Makefile.in
+++ b/src/kadmin/cli/Makefile.in
@@ -37,3 +37,8 @@ clean-unix::
# CC_LINK is not meant for compilation and this use may break in the future.
datetest: getdate.c
$(CC_LINK) $(ALL_CFLAGS) -DTEST -o datetest getdate.c
+
+%.c: %.y
+ $(RM) y.tab.c $@
+ $(YACC.y) $<
+ $(CP) y.tab.c $@
diff --git a/src/plugins/kdb/ldap/ldap_util/Makefile.in b/src/plugins/kdb/ldap/ldap_util/Makefile.in
index 8669c2436..a22f23c02 100644
--- a/src/plugins/kdb/ldap/ldap_util/Makefile.in
+++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in
@@ -20,7 +20,7 @@ $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIB) $(GETDATE)
getdate.c: $(GETDATE)
$(RM) getdate.c y.tab.c
$(YACC) $(GETDATE)
- $(MV) y.tab.c getdate.c
+ $(CP) y.tab.c getdate.c
install:
$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)

View File

@ -0,0 +1,774 @@
From 9feb7298b90d3e6a34821fce7315757c0bf81c9e Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:29:58 -0400
Subject: [PATCH] [downstream] ksu pam integration
Modify ksu so that it performs account and session management on behalf of
the target user account, mimicking the action of regular su. The default
service name is "ksu", because on Fedora at least the configuration used
is determined by whether or not a login shell is being opened, and so
this may need to vary, too. At run-time, ksu's behavior can be reset to
the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu]
section of /etc/krb5.conf.
When enabled, ksu gains a dependency on libpam.
Originally RT#5939, though it's changed since then to perform the account
and session management before dropping privileges, and to apply on top of
changes we're proposing for how it handles cache collections.
Last-updated: krb5-1.18-beta1
---
src/aclocal.m4 | 69 +++++++
src/clients/ksu/Makefile.in | 8 +-
src/clients/ksu/main.c | 88 +++++++-
src/clients/ksu/pam.c | 389 ++++++++++++++++++++++++++++++++++++
src/clients/ksu/pam.h | 57 ++++++
src/configure.ac | 2 +
6 files changed, 610 insertions(+), 3 deletions(-)
create mode 100644 src/clients/ksu/pam.c
create mode 100644 src/clients/ksu/pam.h
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 2394f7e33..830203683 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -1675,3 +1675,72 @@ if test "$with_ldap" = yes; then
OPENLDAP_PLUGIN=yes
fi
])dnl
+dnl
+dnl
+dnl Use PAM instead of local crypt() compare for checking local passwords,
+dnl and perform PAM account, session management, and password-changing where
+dnl appropriate.
+dnl
+AC_DEFUN(KRB5_WITH_PAM,[
+AC_ARG_WITH(pam,[AC_HELP_STRING(--with-pam,[compile with PAM support])],
+ withpam="$withval",withpam=auto)
+AC_ARG_WITH(pam-ksu-service,[AC_HELP_STRING(--with-ksu-service,[PAM service name for ksu ["ksu"]])],
+ withksupamservice="$withval",withksupamservice=ksu)
+old_LIBS="$LIBS"
+if test "$withpam" != no ; then
+ AC_MSG_RESULT([checking for PAM...])
+ PAM_LIBS=
+
+ AC_CHECK_HEADERS(security/pam_appl.h)
+ if test "x$ac_cv_header_security_pam_appl_h" != xyes ; then
+ if test "$withpam" = auto ; then
+ AC_MSG_RESULT([Unable to locate security/pam_appl.h.])
+ withpam=no
+ else
+ AC_MSG_ERROR([Unable to locate security/pam_appl.h.])
+ fi
+ fi
+
+ LIBS=
+ unset ac_cv_func_pam_start
+ AC_CHECK_FUNCS(putenv pam_start)
+ if test "x$ac_cv_func_pam_start" = xno ; then
+ unset ac_cv_func_pam_start
+ AC_CHECK_LIB(dl,dlopen)
+ AC_CHECK_FUNCS(pam_start)
+ if test "x$ac_cv_func_pam_start" = xno ; then
+ AC_CHECK_LIB(pam,pam_start)
+ unset ac_cv_func_pam_start
+ unset ac_cv_func_pam_getenvlist
+ AC_CHECK_FUNCS(pam_start pam_getenvlist)
+ if test "x$ac_cv_func_pam_start" = xyes ; then
+ PAM_LIBS="$LIBS"
+ else
+ if test "$withpam" = auto ; then
+ AC_MSG_RESULT([Unable to locate libpam.])
+ withpam=no
+ else
+ AC_MSG_ERROR([Unable to locate libpam.])
+ fi
+ fi
+ fi
+ fi
+ if test "$withpam" != no ; then
+ AC_MSG_NOTICE([building with PAM support])
+ AC_DEFINE(USE_PAM,1,[Define if Kerberos-aware tools should support PAM])
+ AC_DEFINE_UNQUOTED(KSU_PAM_SERVICE,"$withksupamservice",
+ [Define to the name of the PAM service name to be used by ksu.])
+ PAM_LIBS="$LIBS"
+ NON_PAM_MAN=".\\\" "
+ PAM_MAN=
+ else
+ PAM_MAN=".\\\" "
+ NON_PAM_MAN=
+ fi
+fi
+LIBS="$old_LIBS"
+AC_SUBST(PAM_LIBS)
+AC_SUBST(PAM_MAN)
+AC_SUBST(NON_PAM_MAN)
+])dnl
+
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
index 8b4edce4d..9d58f29b5 100644
--- a/src/clients/ksu/Makefile.in
+++ b/src/clients/ksu/Makefile.in
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin /usr/bin"'
KSU_LIBS=@KSU_LIBS@
+PAM_LIBS=@PAM_LIBS@
SRCS = \
$(srcdir)/krb_auth_su.c \
$(srcdir)/ccache.c \
$(srcdir)/authorization.c \
$(srcdir)/main.c \
+ $(srcdir)/pam.c \
$(srcdir)/heuristic.c \
$(srcdir)/xmalloc.c \
$(srcdir)/setenv.c
@@ -17,13 +19,17 @@ OBJS = \
ccache.o \
authorization.o \
main.o \
+ pam.o \
heuristic.o \
xmalloc.o @SETENVOBJ@
all: ksu
ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
- $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
+ $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS)
+
+pam.o: pam.c
+ $(CC) $(ALL_CFLAGS) -c $<
clean:
$(RM) ksu
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
index 57c349200..508242e0e 100644
--- a/src/clients/ksu/main.c
+++ b/src/clients/ksu/main.c
@@ -26,6 +26,7 @@
* KSU was writen by: Ari Medvinsky, ari@isi.edu
*/
+#include "autoconf.h"
#include "ksu.h"
#include "adm_proto.h"
#include <sys/types.h>
@@ -33,6 +34,10 @@
#include <signal.h>
#include <grp.h>
+#ifdef USE_PAM
+#include "pam.h"
+#endif
+
/* globals */
char * prog_name;
int auth_debug =0;
@@ -40,6 +45,7 @@ char k5login_path[MAXPATHLEN];
char k5users_path[MAXPATHLEN];
char * gb_err = NULL;
int quiet = 0;
+int force_fork = 0;
/***********/
#define KS_TEMPORARY_CACHE "MEMORY:_ksu"
@@ -536,6 +542,23 @@ main (argc, argv)
prog_name,target_user,client_name,
source_user,ontty());
+#ifdef USE_PAM
+ if (appl_pam_enabled(ksu_context, "ksu")) {
+ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
+ NULL, source_user,
+ ttyname(STDERR_FILENO)) != 0) {
+ fprintf(stderr, "Access denied for %s.\n", target_user);
+ exit(1);
+ }
+ if (appl_pam_requires_chauthtok()) {
+ fprintf(stderr, "Password change required for %s.\n",
+ target_user);
+ exit(1);
+ }
+ force_fork++;
+ }
+#endif
+
/* Run authorization as target.*/
if (krb5_seteuid(target_uid)) {
com_err(prog_name, errno, _("while switching to target for "
@@ -596,6 +619,24 @@ main (argc, argv)
exit(1);
}
+#ifdef USE_PAM
+ } else {
+ /* we always do PAM account management, even for root */
+ if (appl_pam_enabled(ksu_context, "ksu")) {
+ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
+ NULL, source_user,
+ ttyname(STDERR_FILENO)) != 0) {
+ fprintf(stderr, "Access denied for %s.\n", target_user);
+ exit(1);
+ }
+ if (appl_pam_requires_chauthtok()) {
+ fprintf(stderr, "Password change required for %s.\n",
+ target_user);
+ exit(1);
+ }
+ force_fork++;
+ }
+#endif
}
if( some_rest_copy){
@@ -653,6 +694,30 @@ main (argc, argv)
exit(1);
}
+#ifdef USE_PAM
+ if (appl_pam_enabled(ksu_context, "ksu")) {
+ if (appl_pam_session_open() != 0) {
+ fprintf(stderr, "Error opening session for %s.\n", target_user);
+ exit(1);
+ }
+#ifdef DEBUG
+ if (auth_debug){
+ printf(" Opened PAM session.\n");
+ }
+#endif
+ if (appl_pam_cred_init()) {
+ fprintf(stderr, "Error initializing credentials for %s.\n",
+ target_user);
+ exit(1);
+ }
+#ifdef DEBUG
+ if (auth_debug){
+ printf(" Initialized PAM credentials.\n");
+ }
+#endif
+ }
+#endif
+
/* set permissions */
if (setgid(target_pwd->pw_gid) < 0) {
perror("ksu: setgid");
@@ -750,7 +815,7 @@ main (argc, argv)
fprintf(stderr, "program to be execed %s\n",params[0]);
}
- if( keep_target_cache ) {
+ if( keep_target_cache && !force_fork ) {
execv(params[0], params);
com_err(prog_name, errno, _("while trying to execv %s"), params[0]);
sweep_up(ksu_context, cc_target);
@@ -780,16 +845,35 @@ main (argc, argv)
if (ret_pid == -1) {
com_err(prog_name, errno, _("while calling waitpid"));
}
- sweep_up(ksu_context, cc_target);
+ if( !keep_target_cache ) {
+ sweep_up(ksu_context, cc_target);
+ }
exit (statusp);
case -1:
com_err(prog_name, errno, _("while trying to fork."));
sweep_up(ksu_context, cc_target);
exit (1);
case 0:
+#ifdef USE_PAM
+ if (appl_pam_enabled(ksu_context, "ksu")) {
+ if (appl_pam_setenv() != 0) {
+ fprintf(stderr, "Error setting up environment for %s.\n",
+ target_user);
+ exit (1);
+ }
+#ifdef DEBUG
+ if (auth_debug){
+ printf(" Set up PAM environment.\n");
+ }
+#endif
+ }
+#endif
execv(params[0], params);
com_err(prog_name, errno, _("while trying to execv %s"),
params[0]);
+ if( keep_target_cache ) {
+ sweep_up(ksu_context, cc_target);
+ }
exit (1);
}
}
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
new file mode 100644
index 000000000..cbfe48704
--- /dev/null
+++ b/src/clients/ksu/pam.c
@@ -0,0 +1,389 @@
+/*
+ * src/clients/ksu/pam.c
+ *
+ * Copyright 2007,2009,2010 Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Red Hat, Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Convenience wrappers for using PAM.
+ */
+
+#include "autoconf.h"
+#ifdef USE_PAM
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "k5-int.h"
+#include "pam.h"
+
+#ifndef MAXPWSIZE
+#define MAXPWSIZE 128
+#endif
+
+static int appl_pam_started;
+static pid_t appl_pam_starter = -1;
+static int appl_pam_session_opened;
+static int appl_pam_creds_initialized;
+static int appl_pam_pwchange_required;
+static pam_handle_t *appl_pamh;
+static struct pam_conv appl_pam_conv;
+static char *appl_pam_user;
+struct appl_pam_non_interactive_args {
+ const char *user;
+ const char *password;
+};
+
+int
+appl_pam_enabled(krb5_context context, const char *section)
+{
+ int enabled = 1;
+ if ((context != NULL) && (context->profile != NULL)) {
+ if (profile_get_boolean(context->profile,
+ section,
+ USE_PAM_CONFIGURATION_KEYWORD,
+ NULL,
+ enabled, &enabled) != 0) {
+ enabled = 1;
+ }
+ }
+ return enabled;
+}
+
+void
+appl_pam_cleanup(void)
+{
+ if (getpid() != appl_pam_starter) {
+ return;
+ }
+#ifdef DEBUG
+ printf("Called to clean up PAM.\n");
+#endif
+ if (appl_pam_creds_initialized) {
+#ifdef DEBUG
+ printf("Deleting PAM credentials.\n");
+#endif
+ pam_setcred(appl_pamh, PAM_DELETE_CRED);
+ appl_pam_creds_initialized = 0;
+ }
+ if (appl_pam_session_opened) {
+#ifdef DEBUG
+ printf("Closing PAM session.\n");
+#endif
+ pam_close_session(appl_pamh, 0);
+ appl_pam_session_opened = 0;
+ }
+ appl_pam_pwchange_required = 0;
+ if (appl_pam_started) {
+#ifdef DEBUG
+ printf("Shutting down PAM.\n");
+#endif
+ pam_end(appl_pamh, 0);
+ appl_pam_started = 0;
+ appl_pam_starter = -1;
+ free(appl_pam_user);
+ appl_pam_user = NULL;
+ }
+}
+static int
+appl_pam_interactive_converse(int num_msg, const struct pam_message **msg,
+ struct pam_response **presp, void *appdata_ptr)
+{
+ const struct pam_message *message;
+ struct pam_response *resp;
+ int i, code;
+ char *pwstring, pwbuf[MAXPWSIZE];
+ unsigned int pwsize;
+ resp = malloc(sizeof(struct pam_response) * num_msg);
+ if (resp == NULL) {
+ return PAM_BUF_ERR;
+ }
+ memset(resp, 0, sizeof(struct pam_response) * num_msg);
+ code = PAM_SUCCESS;
+ for (i = 0; i < num_msg; i++) {
+ message = &(msg[0][i]); /* XXX */
+ message = msg[i]; /* XXX */
+ pwstring = NULL;
+ switch (message->msg_style) {
+ case PAM_TEXT_INFO:
+ case PAM_ERROR_MSG:
+ printf("[%s]\n", message->msg ? message->msg : "");
+ fflush(stdout);
+ resp[i].resp = NULL;
+ resp[i].resp_retcode = PAM_SUCCESS;
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ case PAM_PROMPT_ECHO_OFF:
+ if (message->msg_style == PAM_PROMPT_ECHO_ON) {
+ if (fgets(pwbuf, sizeof(pwbuf),
+ stdin) != NULL) {
+ pwbuf[strcspn(pwbuf, "\r\n")] = '\0';
+ pwstring = pwbuf;
+ }
+ } else {
+ pwstring = getpass(message->msg ?
+ message->msg :
+ "");
+ }
+ if ((pwstring != NULL) && (pwstring[0] != '\0')) {
+ pwsize = strlen(pwstring);
+ resp[i].resp = malloc(pwsize + 1);
+ if (resp[i].resp == NULL) {
+ resp[i].resp_retcode = PAM_BUF_ERR;
+ } else {
+ memcpy(resp[i].resp, pwstring, pwsize);
+ resp[i].resp[pwsize] = '\0';
+ resp[i].resp_retcode = PAM_SUCCESS;
+ }
+ } else {
+ resp[i].resp_retcode = PAM_CONV_ERR;
+ code = PAM_CONV_ERR;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ *presp = resp;
+ return code;
+}
+static int
+appl_pam_non_interactive_converse(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **presp,
+ void *appdata_ptr)
+{
+ const struct pam_message *message;
+ struct pam_response *resp;
+ int i, code;
+ unsigned int pwsize;
+ struct appl_pam_non_interactive_args *args;
+ const char *pwstring;
+ resp = malloc(sizeof(struct pam_response) * num_msg);
+ if (resp == NULL) {
+ return PAM_BUF_ERR;
+ }
+ args = appdata_ptr;
+ memset(resp, 0, sizeof(struct pam_response) * num_msg);
+ code = PAM_SUCCESS;
+ for (i = 0; i < num_msg; i++) {
+ message = &((*msg)[i]);
+ message = msg[i];
+ pwstring = NULL;
+ switch (message->msg_style) {
+ case PAM_TEXT_INFO:
+ case PAM_ERROR_MSG:
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ case PAM_PROMPT_ECHO_OFF:
+ if (message->msg_style == PAM_PROMPT_ECHO_ON) {
+ /* assume "user" */
+ pwstring = args->user;
+ } else {
+ /* assume "password" */
+ pwstring = args->password;
+ }
+ if ((pwstring != NULL) && (pwstring[0] != '\0')) {
+ pwsize = strlen(pwstring);
+ resp[i].resp = malloc(pwsize + 1);
+ if (resp[i].resp == NULL) {
+ resp[i].resp_retcode = PAM_BUF_ERR;
+ } else {
+ memcpy(resp[i].resp, pwstring, pwsize);
+ resp[i].resp[pwsize] = '\0';
+ resp[i].resp_retcode = PAM_SUCCESS;
+ }
+ } else {
+ resp[i].resp_retcode = PAM_CONV_ERR;
+ code = PAM_CONV_ERR;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ *presp = resp;
+ return code;
+}
+static int
+appl_pam_start(const char *service, int interactive,
+ const char *login_username,
+ const char *non_interactive_password,
+ const char *hostname,
+ const char *ruser,
+ const char *tty)
+{
+ static int exit_handler_registered;
+ static struct appl_pam_non_interactive_args args;
+ int ret = 0;
+ if (appl_pam_started &&
+ (strcmp(login_username, appl_pam_user) != 0)) {
+ appl_pam_cleanup();
+ appl_pam_user = NULL;
+ }
+ if (!appl_pam_started) {
+#ifdef DEBUG
+ printf("Starting PAM up (service=\"%s\",user=\"%s\").\n",
+ service, login_username);
+#endif
+ memset(&appl_pam_conv, 0, sizeof(appl_pam_conv));
+ appl_pam_conv.conv = interactive ?
+ &appl_pam_interactive_converse :
+ &appl_pam_non_interactive_converse;
+ memset(&args, 0, sizeof(args));
+ args.user = strdup(login_username);
+ args.password = non_interactive_password ?
+ strdup(non_interactive_password) :
+ NULL;
+ appl_pam_conv.appdata_ptr = &args;
+ ret = pam_start(service, login_username,
+ &appl_pam_conv, &appl_pamh);
+ if (ret == 0) {
+ if (hostname != NULL) {
+#ifdef DEBUG
+ printf("Setting PAM_RHOST to \"%s\".\n", hostname);
+#endif
+ pam_set_item(appl_pamh, PAM_RHOST, hostname);
+ }
+ if (ruser != NULL) {
+#ifdef DEBUG
+ printf("Setting PAM_RUSER to \"%s\".\n", ruser);
+#endif
+ pam_set_item(appl_pamh, PAM_RUSER, ruser);
+ }
+ if (tty != NULL) {
+#ifdef DEBUG
+ printf("Setting PAM_TTY to \"%s\".\n", tty);
+#endif
+ pam_set_item(appl_pamh, PAM_TTY, tty);
+ }
+ if (!exit_handler_registered &&
+ (atexit(appl_pam_cleanup) != 0)) {
+ pam_end(appl_pamh, 0);
+ appl_pamh = NULL;
+ ret = -1;
+ } else {
+ appl_pam_started = 1;
+ appl_pam_starter = getpid();
+ appl_pam_user = strdup(login_username);
+ exit_handler_registered = 1;
+ }
+ }
+ }
+ return ret;
+}
+int
+appl_pam_acct_mgmt(const char *service, int interactive,
+ const char *login_username,
+ const char *non_interactive_password,
+ const char *hostname,
+ const char *ruser,
+ const char *tty)
+{
+ int ret;
+ appl_pam_pwchange_required = 0;
+ ret = appl_pam_start(service, interactive, login_username,
+ non_interactive_password, hostname, ruser, tty);
+ if (ret == 0) {
+#ifdef DEBUG
+ printf("Calling pam_acct_mgmt().\n");
+#endif
+ ret = pam_acct_mgmt(appl_pamh, 0);
+ switch (ret) {
+ case PAM_IGNORE:
+ ret = 0;
+ break;
+ case PAM_NEW_AUTHTOK_REQD:
+ appl_pam_pwchange_required = 1;
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+int
+appl_pam_requires_chauthtok(void)
+{
+ return appl_pam_pwchange_required;
+}
+int
+appl_pam_session_open(void)
+{
+ int ret = 0;
+ if (appl_pam_started) {
+#ifdef DEBUG
+ printf("Opening PAM session.\n");
+#endif
+ ret = pam_open_session(appl_pamh, 0);
+ if (ret == 0) {
+ appl_pam_session_opened = 1;
+ }
+ }
+ return ret;
+}
+int
+appl_pam_setenv(void)
+{
+ int ret = 0;
+#ifdef HAVE_PAM_GETENVLIST
+#ifdef HAVE_PUTENV
+ int i;
+ char **list;
+ if (appl_pam_started) {
+ list = pam_getenvlist(appl_pamh);
+ for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) {
+#ifdef DEBUG
+ printf("Setting \"%s\" in environment.\n", list[i]);
+#endif
+ putenv(list[i]);
+ }
+ }
+#endif
+#endif
+ return ret;
+}
+int
+appl_pam_cred_init(void)
+{
+ int ret = 0;
+ if (appl_pam_started) {
+#ifdef DEBUG
+ printf("Initializing PAM credentials.\n");
+#endif
+ ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED);
+ if (ret == 0) {
+ appl_pam_creds_initialized = 1;
+ }
+ }
+ return ret;
+}
+#endif
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
new file mode 100644
index 000000000..0ab76569c
--- /dev/null
+++ b/src/clients/ksu/pam.h
@@ -0,0 +1,57 @@
+/*
+ * src/clients/ksu/pam.h
+ *
+ * Copyright 2007,2009,2010 Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Red Hat, Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Convenience wrappers for using PAM.
+ */
+
+#include <krb5.h>
+#ifdef HAVE_SECURITY_PAM_APPL_H
+#include <security/pam_appl.h>
+#endif
+
+#define USE_PAM_CONFIGURATION_KEYWORD "use_pam"
+
+#ifdef USE_PAM
+int appl_pam_enabled(krb5_context context, const char *section);
+int appl_pam_acct_mgmt(const char *service, int interactive,
+ const char *local_username,
+ const char *non_interactive_password,
+ const char *hostname,
+ const char *ruser,
+ const char *tty);
+int appl_pam_requires_chauthtok(void);
+int appl_pam_session_open(void);
+int appl_pam_setenv(void);
+int appl_pam_cred_init(void);
+void appl_pam_cleanup(void);
+#endif
diff --git a/src/configure.ac b/src/configure.ac
index 234f4281c..d1f576124 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1390,6 +1390,8 @@ AC_SUBST([VERTO_VERSION])
AC_PATH_PROG(GROFF, groff)
+KRB5_WITH_PAM
+
# Make localedir work in autoconf 2.5x.
if test "${localedir+set}" != set; then
localedir='$(datadir)/locale'

View File

@ -0,0 +1,24 @@
From 4254bee1b97edeb0848efce635bcf1b56306f968 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:46:21 -0400
Subject: [PATCH] [downstream] netlib and dns
We want to be able to use --with-netlib and --enable-dns at the same time.
Last-updated: krb5-1.3.1
---
src/aclocal.m4 | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 6796fec53..c4358988a 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -724,6 +724,7 @@ AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
LIBS="$LIBS $withval"
AC_MSG_RESULT("netlib will use \'$withval\'")
fi
+ KRB5_AC_ENABLE_DNS
],dnl
[AC_LIBRARY_NET]
)])dnl

1
kadm5.acl Normal file
View File

@ -0,0 +1 @@
*/admin@EXAMPLE.COM *

15
kadmin.service Normal file
View File

@ -0,0 +1,15 @@
[Unit]
Description=Kerberos 5 Password-changing and Administration
Wants=network-online.target
After=syslog.target network.target network-online.target
AssertPathExists=!/var/kerberos/krb5kdc/kpropd.acl
[Service]
Type=forking
PIDFile=/var/run/kadmind.pid
EnvironmentFile=-/etc/sysconfig/kadmin
ExecStart=/usr/sbin/kadmind -P /var/run/kadmind.pid $KADMIND_ARGS
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

1
kadmin.sysconfig Normal file
View File

@ -0,0 +1 @@
KADMIND_ARGS=

9
kadmind.logrotate Normal file
View File

@ -0,0 +1,9 @@
/var/log/kadmind.log {
missingok
notifempty
monthly
rotate 12
postrotate
systemctl reload kadmin.service || true
endscript
}

14
kdc.conf Normal file
View File

@ -0,0 +1,14 @@
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
spake_preauth_kdc_challenge = edwards25519
[realms]
EXAMPLE.COM = {
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
default_principal_flags = +preauth
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal
}

13
kprop.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=Kerberos 5 Propagation
Wants=network-online.target
After=syslog.target network.target network-online.target
AssertPathExists=/var/kerberos/krb5kdc/kpropd.acl
[Service]
Type=forking
EnvironmentFile=-/etc/sysconfig/kprop
ExecStart=/usr/sbin/kpropd $KPROPD_ARGS
[Install]
WantedBy=multi-user.target

1
kprop.sysconfig Normal file
View File

@ -0,0 +1 @@
KPROPD_ARGS=

1
krb5-krb5kdc.conf Normal file
View File

@ -0,0 +1 @@
d /var/run/krb5kdc 0755 root root

30
krb5.conf Normal file
View File

@ -0,0 +1,30 @@
# To opt out of the system crypto-policies configuration of krb5, remove the
# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
dns_lookup_realm = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
rdns = false
pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
spake_preauth_groups = edwards25519
dns_canonicalize_hostname = fallback
qualify_shortname = ""
# default_realm = EXAMPLE.COM
[realms]
# EXAMPLE.COM = {
# kdc = kerberos.example.com
# admin_server = kerberos.example.com
# }
[domain_realm]
# .example.com = EXAMPLE.COM
# example.com = EXAMPLE.COM

14
krb5.rpmlintrc Normal file
View File

@ -0,0 +1,14 @@
addFilter(r'spelling-error .* en_US (unencrypted)')
addFilter(r'hidden-file-or-dir /usr/share/man/man5/.k5identity.5.gz')
addFilter(r'non-standard-dir-in-var kerberos')
addFilter(r'explicit-lib-dependency libverto-module-base')
addFilter(r'shared-lib-calls-exit')
addFilter(r'dir-or-file-in-var-run /var/run/krb5kdc')
addFilter(r'devel-file-in-non-devel-package /usr/lib64/libkadm5(clnt|srv)_mit.so')
addFilter(r'non-readable /var/kerberos/krb5kdc')
addFilter(r'devel-file-in-non-devel-package /usr/lib64/libkdb_ldap.so')
addFilter(r'/usr/bin/ksu')
addFilter(r'no-documentation')
addFilter(r'invalid-directory-reference .*pkgconfig')
addFilter(r'incoherent-logrotate-file /etc/logrotate.d/k')
addFilter(r'library-not-linked-against-libc')

3958
krb5.spec Normal file

File diff suppressed because it is too large Load Diff

9
krb5kdc.logrotate Normal file
View File

@ -0,0 +1,9 @@
/var/log/krb5kdc.log {
missingok
notifempty
monthly
rotate 12
postrotate
systemctl reload krb5kdc.service || true
endscript
}

14
krb5kdc.service Normal file
View File

@ -0,0 +1,14 @@
[Unit]
Description=Kerberos 5 KDC
Wants=network-online.target
After=syslog.target network.target network-online.target
[Service]
Type=forking
PIDFile=/var/run/krb5kdc.pid
EnvironmentFile=-/etc/sysconfig/krb5kdc
ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

1
krb5kdc.sysconfig Normal file
View File

@ -0,0 +1 @@
KRB5KDC_ARGS=

4
ksu.pamd Normal file
View File

@ -0,0 +1,4 @@
#%PAM-1.0
auth include su
account include su
session include su

2
sources Normal file
View File

@ -0,0 +1,2 @@
SHA512 (krb5-1.18.2.tar.gz) = 7cbb1b28e677fea3e0794e93951f3caaa2c49bb1175dd187951e72a466cc69d96c3b833d838000fe911c1a437d96a558e550f27c53a8b332fb9dfc7cbb7ec44c
SHA512 (krb5-1.18.2.tar.gz.asc) = 70775a06104b4d792d278da2efa92e94ddacb4ea319bfe2b253f5afcfec27f3bc5ddd12560294a265e3cf3d4fc74bcbfc3f5eeff8634d66c00d67e18dc93a74a

View File

@ -0,0 +1,64 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Makefile of /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test
# Description: Verifies basic scenarios which should work after inplace upgrade.
# Author: Patrik Kis <pkis@redhat.com>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2014 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing
# to use, modify, copy, or redistribute it subject to the terms
# and conditions of the GNU General Public License version 2.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export TEST=/CoreOS/krb5/Sanity/inplace-upgrade-sanity-test
export TESTVERSION=1.0
BUILT_FILES=
FILES=$(METADATA) runtest.sh Makefile PURPOSE
.PHONY: all install download clean
run: $(FILES) build
./runtest.sh
build: $(BUILT_FILES)
test -x runtest.sh || chmod a+x runtest.sh
clean:
rm -f *~ $(BUILT_FILES)
include /usr/share/rhts/lib/rhts-make.include
$(METADATA): Makefile
@echo "Owner: Patrik Kis <pkis@redhat.com>" > $(METADATA)
@echo "Name: $(TEST)" >> $(METADATA)
@echo "TestVersion: $(TESTVERSION)" >> $(METADATA)
@echo "Path: $(TEST_DIR)" >> $(METADATA)
@echo "Description: Verifies basic scenarios which should work after inplace upgrade." >> $(METADATA)
@echo "Type: Sanity" >> $(METADATA)
@echo "TestTime: 20m" >> $(METADATA)
@echo "RunFor: krb5" >> $(METADATA)
@echo "Requires: expect krb5-server krb5-workstation openssh-clients openssh-server rng-tools" >> $(METADATA)
@echo "Priority: Normal" >> $(METADATA)
@echo "License: GPLv2" >> $(METADATA)
@echo "Confidential: no" >> $(METADATA)
@echo "Destructive: no" >> $(METADATA)
@echo "Releases: -RHEL4 -RHELClient5 -RHELServer5" >> $(METADATA)
rhts-lint $(METADATA)

View File

@ -0,0 +1,3 @@
PURPOSE of /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test
Description: Verifies basic scenarios which should work after inplace upgrade.
Author: Patrik Kis <pkis@redhat.com>

View File

@ -0,0 +1,19 @@
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
[realms]
${krb5REALM1} = {
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
}
${krb5REALM2} = {
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
}

View File

@ -0,0 +1,36 @@
# To opt out of the system crypto-policies configuration of krb5, remove the
# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = ${krb5REALM1}
dns_lookup_realm = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
rdns = false
default_ccache_name = KEYRING:persistent:%{uid}
[realms]
${krb5REALM1} = {
kdc = localhost.localdomain
admin_server = localhost.localdomain
}
${krb5REALM2} = {
kdc = localhost.localdomain
admin_server = localhost.localdomain
}
[domain_realm]
${krb5HostName} = ${krb5REALM1}
${krb5HostName} = ${krb5REALM2}
[capaths]
${krb5REALM1} = {
${krb5REALM2} = .
}

View File

@ -0,0 +1,308 @@
#!/bin/bash
# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# runtest.sh of /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test
# Description: Verifies basic scenarios which should work after inplace upgrade.
# Author: Patrik Kis <pkis@redhat.com>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2014 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing
# to use, modify, copy, or redistribute it subject to the terms
# and conditions of the GNU General Public License version 2.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Include Beaker environment
. /usr/bin/rhts-environment.sh
. /usr/share/beakerlib/beakerlib.sh || exit 1
PACKAGE="krb5"
PACKAGES="krb5-libs krb5-server krb5-workstation openssh"
TEST_ENTROPY_SOURCE=${TEST_ENTROPY_SOURCE:-no}
echo TEST_ENTROPY_SOURCE=$TEST_ENTROPY_SOURCE
hostnamectl set-hostname test.fedora.com
host_ip=`hostname -I | awk '{print$1}'`
echo "$host_ip test.fedora.com" >> /etc/hosts
krb5REALM1='ZMRAZ.COM'
krb5REALM2='PKIS.NET'
krb5HostName=`hostname`
krb5DomainName='fedora.com'
krb5User='alice'
krb5UserPass='alice'
krb5UserKrbPass='aaa'
krb5User2='bob'
krb5User3='carl'
krb5KDCPass='qwe'
krb5RootPass='rrr'
krb5conf="/etc/krb5.conf"
krb5confdir="/etc/krb5.conf.d"
krb5kdcconf="/var/kerberos/krb5kdc/kdc.conf"
krb5kadmacl="/var/kerberos/krb5kdc/kadm5.acl"
rlJournalStart
rlPhaseStartSetup
for pkg in $PACKAGES; do
rlAssertRpm $pkg
done
rlRun "TmpDir=\$(mktemp -d)"
rlRun "pushd $TmpDir"
rlPhaseEnd
# Run this part on OLD and in "normal" mode
if [[ -z $IN_PLACE_UPGRADE || $IN_PLACE_UPGRADE == old ]]; then
rlPhaseStartSetup "KDC and kadmind setup"
# Stop and backup
rlRun "rlServiceStop kadmin krb5kdc"
rlRun "rm -f /var/kerberos/krb5kdc/principal* /var/kerberos/krb5kdc/.k5*"
rlFileBackup $krb5conf /var/kerberos/krb5kdc /etc/sysconfig/{kadmin,krb5kdc}
[ -e /etc/krb5.keytab ] && rlFileBackup /etc/krb5.keytab
[ -e $krb5confdir ] && rlFileBackup $krb5confdir
# Basic setup of KDC and krb5.conf
if rlIsRHEL 6; then
rlRun "sed -i \"s/EXAMPLE.COM/$krb5REALM1/\" $krb5conf"
rlRun "sed -i \"s/kerberos.example.com/$krb5HostName/\" $krb5conf"
rlRun "sed -i \"s/example.com/$krb5DomainName/\" $krb5conf"
else
rlRun "sed -i \"s/\[libdefaults\]/[libdefaults]\n default_realm = $krb5REALM1/\" $krb5conf"
rlRun "sed -i \"s/\[realms\]/[realms]\n $krb5REALM1 = {\n kdc = $krb5HostName\n admin_server = $krb5HostName\n }/\" $krb5conf"
rlRun "sed -i \"s/\[domain_realm\]/[domain_realm]\n .$krb5DomainName = $krb5REALM1\n $krb5DomainName = $krb5REALM1/\" $krb5conf"
fi
rlRun "sed -i s/EXAMPLE.COM/$krb5REALM1/ $krb5kdcconf"
# Configure the kadmin ACL
rlRun "echo \"*/master@$krb5REALM1 *\" > $krb5kadmacl"
# Configure the 2nd realmd
cat >>$krb5kdcconf <<_EOF
$krb5REALM2 = {
#master_key_type = aes256-cts
database_name = /var/kerberos/krb5kdc/principal.$krb5REALM1
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
}
_EOF
rlIsRHEL 6 || rlRun "sed -i \"s/supported_enctypes.*/supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal/\" /var/kerberos/krb5kdc/kdc.conf"
rlRun "sed -i \"s/\[realms\]/[realms]\n $krb5REALM2 = {\n kdc = $krb5HostName\n admin_server = $krb5HostName\n }/\" $krb5conf"
cat >> $krb5conf << _EOF
[capaths]
$krb5REALM1 = {
$krb5REALM2 = .
}
_EOF
# Test the entropy source (not relevant for RHEL6)
if ! rlIsRHEL 6 && [[ $TEST_ENTROPY_SOURCE == 'yes' ]]; then
rlLog "The source of entropy will be tested as well"
START_DATE=`date +%H:%M:%S`
echo START_DATE=$START_DATE
sleep 1
rlRun "auditctl -w /dev/random -p rwxa -k RAND"
auditctl -l
sleep 1
rlRun "ausearch -i -k RAND -ts $START_DATE"
fi
# Create the realm databases
rlRun "rngd -r /dev/urandom"
rlRun "kdb5_util create -s -r $krb5REALM1 -P $krb5KDCPass"
rlRun "kdb5_util create -s -r $krb5REALM2 -P $krb5KDCPass"
# Configure KDC to handle 2 realms
if rlIsRHEL 6; then
rlRun "echo \"KRB5REALM=$krb5REALM1\" > /etc/sysconfig/krb5kdc"
rlRun "echo KRB5KDC_ARGS=\\\"-r $krb5REALM2\\\" >> /etc/sysconfig/krb5kdc"
else
rlRun "echo KRB5KDC_ARGS=\\\"-r $krb5REALM1 -r $krb5REALM2 \\\" >/etc/sysconfig/krb5kdc"
fi
rlRun "rlServiceStart kadmin krb5kdc"
# Add krb5 principals for the 2nd realm
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -pw $krb5RootPass root/master\""
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -pw $krb5UserKrbPass $krb5User\""
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -randkey host/$krb5HostName\""
rlRun "kadmin.local -r $krb5REALM1 -q \"ktadd host/$krb5HostName\""
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -pw $krb5KDCPass krbtgt/$krb5REALM1@$krb5REALM2\""
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -pw $krb5KDCPass krbtgt/$krb5REALM2@$krb5REALM1\""
# Add krb5 principals for the 2nd realm
rlRun "kadmin.local -r $krb5REALM2 -q \"addprinc -pw $krb5UserKrbPass $krb5User2\""
rlRun "kadmin.local -r $krb5REALM2 -q \"addprinc -randkey host/$krb5HostName\""
rlRun "kadmin.local -r $krb5REALM2 -q \"addprinc -pw $krb5KDCPass krbtgt/$krb5REALM1@$krb5REALM2\""
rlRun "kadmin.local -r $krb5REALM2 -q \"addprinc -pw $krb5KDCPass krbtgt/$krb5REALM2@$krb5REALM1\""
# Create test system user
[ $krb5User != "root" ] && rlRun "useradd $krb5User"
rlRun "echo $krb5UserPass | passwd --stdin $krb5User"
rlPhaseEnd
fi
rlPhaseStartTest "Daemon start and log file test"
# Make sure there is enough entropy and start recording of the logs
rlRun "rngd -r /dev/urandom"
if grep -q krb5kdc /var/log/krb5kdc.log; then
tail -n0 -f /var/log/krb5kdc.log &> krb5kdc.log.record &
KRB5KDC_LOG_PID=$!
echo "log_record_start: PID = $KRB5KDC_LOG_PID"
sleep 1
elif journalctl |grep -q krb5kdc; then
journalctl -f &> krb5kdc.log.record &
KRB5KDC_LOG_PID=$!
echo "log_record_start: PID = $KRB5KDC_LOG_PID"
sleep 1
else
rlFail "Could not find krb5kdc logs"
echo "journalctl:"
journalctl -n 100
ls -la /var/log/krb5kdc*
echo "/var/log/krb5kdc.log:"
tail -n 100 /var/log/krb5kdc.log
fi
if grep -q kadmind /var/log/kadmind.log; then
tail -n0 -f /var/log/kadmind.log &> kadmind.log.record &
KADMIND_LOG_PID=$!
echo "log_record_start: PID = $KADMIND_LOG_PID"
sleep 1
elif journalctl |grep -q kadmind; then
journalctl -f &> kadmind.log.record &
KADMIND_LOG_PID=$!
echo "log_record_start: PID = $KADMIND_LOG_PID"
sleep 1
else
rlFail "Could not find kadmind logs"
echo "journalctl:"
journalctl -n 100
ls -la /var/log/kadmind*
echo "/var/log/kadmind.log:"
tail -n 100 /var/log/kadmind.log
fi
# Restart daemon auto start
if rlIsRHEL 6; then
rlRun "service krb5kdc restart"
rlRun "service kadmin restart"
rlRun "service krb5kdc status"
rlRun "service kadmin status"
else
rlRun "systemctl restart krb5kdc.service"
rlRun "systemctl restart kadmin.service"
rlRun "systemctl --no-pager status krb5kdc.service"
rlRun "systemctl --no-pager status kadmin.service"
fi
rlRun "echo $krb5UserKrbPass |kinit $krb5User && klist"
rlRun "kdestroy"
rlRun "kadmin -p root/master -w rrr -q ''"
rlAssertGrep "AS_REQ.*$krb5User@$krb5REALM1.*krbtgt/$krb5REALM1@$krb5REALM1" krb5kdc.log.record
cat krb5kdc.log.record
rlAssertGrep "Request: kadm5_init.*root/master@$krb5REALM1.*service=kadmin/`hostname`@$krb5REALM1" kadmind.log.record
cat kadmind.log.record
# Stop log recording
kill $KADMIND_LOG_PID
kill $KRB5KDC_LOG_PID
rlPhaseEnd
rlPhaseStartTest "SSH test"
cat > sshtest.exp <<'_EOF'
#!/usr/bin/expect -f
set USER [lindex $argv 0]
set HOST [lindex $argv 1]
set timeout 15
spawn ssh $USER@$HOST pwd
expect {
-re ".*(yes/no).*" { send -- "yes\r"; exp_continue }
-re ".*password:.*" { exit 1 }
"/home/$USER" { exit 0 }
timeout { exit 2 }
eof { exit 3 }
}
exit 4
_EOF
chmod 744 sshtest.exp
rlAssertExists sshtest.exp
rlRun "echo $krb5UserKrbPass |kinit $krb5User && klist"
rlRun "./sshtest.exp $krb5User $krb5HostName"; echo
rlRun "klist &>klist.log"
cat klist.log
rlAssertGrep "host/`hostname`@$krb5REALM1" klist.log
rlRun "kdestroy"
rlPhaseEnd
rlPhaseStartTest "Basic kadmin and kpasswd test"
rlRun "kadmin.local -q \"listprincs\" |grep -v Authenticating >lplocal"
rlRun "kadmin -p root/master -w $krb5RootPass -q \"listprincs\" |grep -v Authenticating >lpremote"
rlAssertNotDiffer lplocal lpremote || diff -u lplocal lpremote
diff lplocal lpremote
rlRun "kadmin -p root/master -w $krb5RootPass -q \"addprinc -pw $krb5User2 $krb5User2@$krb5REALM1\""
rlRun "kadmin -p root/master -w $krb5RootPass -q \"listprincs\" | grep \"$krb5User2@$krb5REALM1\""
rlRun "echo $krb5User2 | kinit $krb5User2"
rlRun "echo -e \"$krb5User2\nqwerty\nqwerty\" | kpasswd &>kpasswd.log"
cat kpasswd.log
rlAssertGrep "Password changed." kpasswd.log
rlRun "echo qwerty | kinit $krb5User2"
rlRun "kdestroy"
rlRun "kadmin -p root/master -w $krb5RootPass -q \"delprinc -force $krb5User2@$krb5REALM1\""
rlPhaseEnd
rlPhaseStartTest "Basic ksu test"
[[ -f /root/.k5login ]] && rlRun "mv /root/.k5login ."
rlRun "echo $krb5User@$krb5REALM1 > /root/.k5login"
rlRun "su - $krb5User -c \"echo $krb5UserKrbPass | kinit $krb5User\""
rlRun "su - $krb5User -c \"ksu -e /usr/bin/id\" &> ksu.log"
cat ksu.log
rlAssertGrep "^uid=0(root) gid=0(root)" ksu.log
rlRun "su - $krb5User -c kdestroy"
[[ -f .k5login ]] && rlRun "mv .k5login /root/.k5login"
rlPhaseEnd
rlPhaseStartTest "Cross realm test"
rlRun "echo $krb5UserKrbPass |kinit $krb5User && klist"
rlRun "kvno host/`hostname`@$krb5REALM2"
rlRun "klist &>klist.log"
cat klist.log
rlAssertGrep "krbtgt/$krb5REALM1@$krb5REALM1" klist.log
rlAssertGrep "krbtgt/$krb5REALM2@$krb5REALM1" klist.log
rlAssertGrep "host/`hostname`@$krb5REALM2" klist.log
rlRun "kdestroy"
rlPhaseEnd
# Test the entropy source (not relevant for RHEL6)
if ! rlIsRHEL 6 && [[ $TEST_ENTROPY_SOURCE == 'yes' ]]; then
rlPhaseStartTest "Enable faster getrandom-based entropy system"
echo START_DATE=$START_DATE
auditctl -l
rlRun "ausearch -i -k RAND -ts $START_DATE"
rlRun "ausearch -i -k RAND -ts $START_DATE |grep comm= |grep -v 'comm=rngd'" 1
rlRun "auditctl -D"
rlPhaseEnd
fi
# Run this part on "normal" mode; in inplace upgrade no cleanup is needed
if [[ -z $IN_PLACE_UPGRADE ]]; then
rlPhaseStartCleanup "KDC and kadmind cleanup"
rlRun "rm -rf /var/kerberos/krb5kdc/* /var/kerberos/krb5kdc/.k5* /etc/krb5* /etc/sysconfig/{kadmin,krb5kdc}"
rlFileRestore
rlRun "rlServiceRestore krb5kdc kadmin"
[ $krb5User != "root" ] && rlRun "userdel -r -f $krb5User"
rlPhaseEnd
fi
rlPhaseStartCleanup
rlRun "popd"
rlRun "rm -r $TmpDir"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd

16
tests/tests.yml Normal file
View File

@ -0,0 +1,16 @@
---
# This first play always runs on the local staging system
- hosts: localhost
roles:
- role: standard-test-beakerlib
tags:
- classic
tests:
- inplace-upgrade-sanity-test
required_packages:
- expect # Required for inplace-upgrade-sanity-test
- krb5-server # Required for inplace-upgrade-sanity-test
- krb5-workstation # Required for inplace-upgrade-sanity-test
- openssh-clients # Required for inplace-upgrade-sanity-test
- openssh-server # Required for inplace-upgrade-sanity-test
- rng-tools # Required for inplace-upgrade-sanity-test