Backport fix for change password requests when using FAST (RT#7868)

This commit is contained in:
Nathaniel McCallum 2014-03-04 11:22:42 -05:00
parent 2550f0f56b
commit 44d0e80df0
2 changed files with 183 additions and 1 deletions

176
krb5-1.12-pwdch-fast.patch Normal file
View File

@ -0,0 +1,176 @@
From 230858394d2dded001ef3d2029daa6c468aca097 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 28 Feb 2014 14:49:35 -0500
Subject: [PATCH] Use preauth options when changing password
If we try to change the password in rb5_get_init_creds_password, we
must use all application-specified gic options which affect
preauthentication when getting the kadmin/changepw ticket. Create a
helper function make_chpw_options which copies the application's
options, unsets the options we don't want, and sets options
appropriate for a temporary ticket.
ticket: 7868
npmccallum:
* include tests from 06817686bfdef99523f300464bcbb0c8b037a27d
---
src/lib/krb5/krb/gic_pwd.c | 63 +++++++++++++++++++++++++++++++++++++---------
src/tests/Makefile.in | 1 +
src/tests/t_changepw.py | 37 +++++++++++++++++++++++++++
3 files changed, 89 insertions(+), 12 deletions(-)
create mode 100644 src/tests/t_changepw.py
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index a97823f6b51b7393755e82f36612c30b64096754..6aec7c3a71f99d2194b09374b296327174e6d4b8 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -242,6 +242,54 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
(*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
+ * options which affect preauthentication, but not options which affect the
+ * resulting ticket or how it is stored. Set lifetime and flags appropriate
+ * for a ticket which we will use immediately and then discard.
+ *
+ * storage1 and storage2 will be used to hold the temporary options. The
+ * caller must not free the result, as it will contain aliases into the
+ * application options.
+ */
+static krb5_get_init_creds_opt *
+make_chpw_options(krb5_get_init_creds_opt *in, krb5_gic_opt_ext *storage1,
+ gic_opt_private *storage2)
+{
+ krb5_gic_opt_ext *in_ext;
+ krb5_get_init_creds_opt *opt;
+
+ /* Copy the application's options to storage. */
+ if (in == NULL) {
+ storage1->flags = 0;
+ } else if (gic_opt_is_extended(in)) {
+ in_ext = (krb5_gic_opt_ext *)in;
+ *storage1 = *in_ext;
+ *storage2 = *in_ext->opt_private;
+ storage1->opt_private = storage2;
+ } else {
+ *(krb5_get_init_creds_opt *)storage1 = *in;
+ }
+
+ /* Get a non-forwardable, non-proxiable, short-lifetime ticket. */
+ opt = (krb5_get_init_creds_opt *)storage1;
+ krb5_get_init_creds_opt_set_tkt_life(opt, 5 * 60);
+ krb5_get_init_creds_opt_set_renew_life(opt, 0);
+ krb5_get_init_creds_opt_set_forwardable(opt, 0);
+ krb5_get_init_creds_opt_set_proxiable(opt, 0);
+
+ /* Unset options which should only apply to the actual ticket. */
+ opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
+ opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
+
+ /* The output ccache should only be used for the actual ticket. */
+ if (gic_opt_is_extended(opt))
+ storage2->out_ccache = NULL;
+
+ return opt;
+}
+
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password(krb5_context context,
krb5_creds *creds,
@@ -259,6 +307,8 @@ krb5_get_init_creds_password(krb5_context context,
int tries;
krb5_creds chpw_creds;
krb5_get_init_creds_opt *chpw_opts = NULL;
+ krb5_gic_opt_ext storage1;
+ gic_opt_private storage2;
struct gak_password gakpw;
krb5_data pw0, pw1;
char banner[1024], pw0array[1024], pw1array[1024];
@@ -345,16 +395,7 @@ krb5_get_init_creds_password(krb5_context context,
/* ok, we have an expired password. Give the user a few chances
to change it */
- /* use a minimal set of options */
-
- ret = krb5_get_init_creds_opt_alloc(context, &chpw_opts);
- if (ret)
- goto cleanup;
- krb5_get_init_creds_opt_set_tkt_life(chpw_opts, 5*60);
- krb5_get_init_creds_opt_set_renew_life(chpw_opts, 0);
- krb5_get_init_creds_opt_set_forwardable(chpw_opts, 0);
- krb5_get_init_creds_opt_set_proxiable(chpw_opts, 0);
-
+ chpw_opts = make_chpw_options(options, &storage1, &storage2);
ret = k5_get_init_creds(context, &chpw_creds, client, prompter, data,
start_time, "kadmin/changepw", chpw_opts,
krb5_get_as_key_password, &gakpw, &use_master,
@@ -471,8 +512,6 @@ cleanup:
warn_pw_expiry(context, options, prompter, data, in_tkt_service,
as_reply);
- if (chpw_opts)
- krb5_get_init_creds_opt_free(context, chpw_opts);
zapfree(gakpw.storage.data, gakpw.storage.length);
memset(pw0array, 0, sizeof(pw0array));
memset(pw1array, 0, sizeof(pw1array));
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 62523895d53da24844141a6ada6cab23e77dd9e6..55f1d6419f8d924a6f9a2971d36f1eac6d293d32 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -94,6 +94,7 @@ check-pytests:: t_init_creds t_localauth
$(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_kprop.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_policy.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_changepw.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_pkinit.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_otp.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_localauth.py $(PYTESTFLAGS)
diff --git a/src/tests/t_changepw.py b/src/tests/t_changepw.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b9832668e618b3db8d88cf388ec918898bb4df3
--- /dev/null
+++ b/src/tests/t_changepw.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+from k5test import *
+
+# This file is intended to cover any password-changing mechanism. For
+# now it only contains a regression test for #7868.
+
+realm = K5Realm(create_host=False, get_creds=False, start_kadmind=True)
+
+# Mark a principal as expired and change its password through kinit.
+realm.run_kadminl('modprinc -pwexpire "1 day ago" user')
+pwinput = password('user') + '\nabcd\nabcd\n'
+realm.run([kinit, realm.user_princ], input=pwinput)
+
+# Do the same thing with FAST, with tracing turned on.
+realm.run_kadminl('modprinc -pwexpire "1 day ago" user')
+pwinput = 'abcd\nefgh\nefgh\n'
+tracefile = os.path.join(realm.testdir, 'trace')
+realm.run(['env', 'KRB5_TRACE=' + tracefile, kinit, '-T', realm.ccache,
+ realm.user_princ], input=pwinput)
+
+# Read the trace and check that FAST was used when getting the
+# kadmin/changepw ticket.
+f = open(tracefile, 'r')
+trace = f.read()
+f.close()
+getting_changepw = fast_used_for_changepw = False
+for line in trace.splitlines():
+ if 'Getting initial credentials for user@' in line:
+ getting_changepw_ticket = False
+ if 'Setting initial creds service to kadmin/changepw' in line:
+ getting_changepw_ticket = True
+ if getting_changepw_ticket and 'Using FAST' in line:
+ fast_used_for_changepw = True
+if not fast_used_for_changepw:
+ fail('FAST was not used to get kadmin/changepw ticket')
+
+success('Password change tests')
--
1.8.5.3

View File

@ -41,7 +41,7 @@
Summary: The Kerberos network authentication system Summary: The Kerberos network authentication system
Name: krb5 Name: krb5
Version: 1.12.1 Version: 1.12.1
Release: 5%{?dist} Release: 6%{?dist}
# Maybe we should explode from the now-available-to-everybody tarball instead? # Maybe we should explode from the now-available-to-everybody tarball instead?
# http://web.mit.edu/kerberos/dist/krb5/1.12/krb5-1.12.1-signed.tar # http://web.mit.edu/kerberos/dist/krb5/1.12/krb5-1.12.1-signed.tar
Source0: krb5-%{version}.tar.gz Source0: krb5-%{version}.tar.gz
@ -76,6 +76,7 @@ Source100: nss_wrapper-0.0-20140204195100.git3d58327.tar.xz
Source101: noport.c Source101: noport.c
Source102: socket_wrapper-0.0-20140204194748.gitf3b2ece.tar.xz Source102: socket_wrapper-0.0-20140204194748.gitf3b2ece.tar.xz
Patch1: krb5-1.12-pwdch-fast.patch
Patch6: krb5-1.12-ksu-path.patch Patch6: krb5-1.12-ksu-path.patch
Patch12: krb5-1.12-ktany.patch Patch12: krb5-1.12-ktany.patch
Patch16: krb5-1.12-buildconf.patch Patch16: krb5-1.12-buildconf.patch
@ -309,6 +310,8 @@ certificate.
%setup -q -a 3 -a 100 -a 102 %setup -q -a 3 -a 100 -a 102
ln -s NOTICE LICENSE ln -s NOTICE LICENSE
%patch1 -p1 -b .pwdch-fast
%patch201 -p1 -b .Don-t-try-to-stat-not-on-disk-ccache-residuals %patch201 -p1 -b .Don-t-try-to-stat-not-on-disk-ccache-residuals
%patch202 -p1 -b .Use-an-in-memory-cache-until-we-need-the-target-s %patch202 -p1 -b .Use-an-in-memory-cache-until-we-need-the-target-s
%patch203 -p1 -b .Learn-to-destroy-the-ccache-we-re-copying-from %patch203 -p1 -b .Learn-to-destroy-the-ccache-we-re-copying-from
@ -1018,6 +1021,9 @@ exit 0
%{_sbindir}/uuserver %{_sbindir}/uuserver
%changelog %changelog
* Tue Mar 04 2014 Nathaniel McCallum <npmccallum@redhat.com> - 1.12.1-6
- Backport fix for change password requests when using FAST (RT#7868)
* Mon Feb 17 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-5 * Mon Feb 17 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-5
- spnego: pull in patch from master to restore preserving the OID of the - spnego: pull in patch from master to restore preserving the OID of the
mechanism the initiator requested when we have multiple OIDs for the same mechanism the initiator requested when we have multiple OIDs for the same