=head1 INSTANCE METHODS
-All instance methods throw exceptions on any error.
+All instance methods throw Authen::Kerberos::Exception exceptions on any
+error.
=over 4
Change the Kerberos password for PRINCIPAL to PASSWORD.
+If password quality checking is enabled via the C<password_quality>
+parameter to the constructor, this method will fail and throw an exception
+on any password quality check failure.
+
=back
=cut
Russ Allbery <eagle@eyrie.org>
+=head1 SEE ALSO
+
+L<Authen::Kerberos::Exception>
+
=cut
#include <krb5.h>
#include <kadm5/admin.h>
+#include <kadm5/kadm5_err.h>
/*
* Define a struct that wraps the kadmin API handle so that we can include
- * some other data structures that we need to use.
+ * some other data structures and configuration parameters that we need to
+ * use.
*/
typedef struct {
void *handle;
krb5_context ctx;
+ bool quality;
} *Authen__Kerberos__Kadmin;
/* Used to check that an object argument to a function is not NULL. */
}
self->ctx = ctx;
self->handle = handle;
+ self->quality = quality;
RETVAL = self;
}
OUTPUT:
PREINIT:
krb5_error_code code;
krb5_principal princ = NULL;
+ krb5_data pwd_data;
+ const char *reason;
CODE:
{
code = krb5_parse_name(self->ctx, principal, &princ);
if (code != 0)
kadmin_croak(self->ctx, code, "krb5_parse_name", FALSE);
+
+ /*
+ * If configured to do quality checking, we need to do that manually,
+ * since the server-side kadmin libraries never check quality.
+ */
+ if (self->quality) {
+ pwd_data.data = (char *) password;
+ pwd_data.length = strlen(password);
+ reason = kadm5_check_password_quality(self->ctx, princ, &pwd_data);
+ if (reason != NULL) {
+ krb5_set_error_message(self->ctx, KADM5_PASS_Q_DICT, "%s", reason);
+ kadmin_croak(self->ctx, KADM5_PASS_Q_DICT,
+ "kadm5_check_password_quality", FALSE);
+ }
+ }
+
+ /* Do the actual password change. */
code = kadm5_chpass_principal(self->handle, princ, password);
krb5_free_principal(self->ctx, princ);
if (code != 0)
dbname = db:./heimdal
realm = TEST.EXAMPLE.COM
}
+
+[password_quality]
+ policies = external-check
+ external_program = ./t/data/kdb/password-quality
--- /dev/null
+#!/usr/bin/perl
+#
+# Trivial Heimdal quality check program used for testing that quality checking
+# happens. Accept any password other than "password".
+#
+# Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2014
+# The Board of Trustees of the Leland Stanford Junior University
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+use 5.010;
+use strict;
+use warnings;
+
+# Check whether the password is "password".
+while (defined(my $line = <STDIN>)) {
+ if ($line =~ m{ \A new-password: [ ] password \n \z }xms) {
+ warn "weak password\n"
+ or die "Cannot write to standard output: $!\n";
+ exit(0);
+ }
+}
+
+# Everything looks good.
+print {*STDOUT} "APPROVED\n"
+ or die "Cannot write to standard output: $!\n";
+exit(0);
use File::Copy qw(copy);
-use Test::More tests => 6;
+use Test::More tests => 10;
BEGIN {
use_ok('Authen::Kerberos::Kadmin');
db_name => 'db:./t/tmp/heimdal',
realm => 'TEST.EXAMPLE.COM',
server => 1,
+ password_quality => 1,
}
);
isa_ok($kadmin, 'Authen::Kerberos::Kadmin');
'Password change is successful');
is($@, q{}, '...with no exception');
+# Test password change to something that should be rejected by the password
+# quality check.
+ok(
+ !eval { $kadmin->chpass('test@TEST.EXAMPLE.COM', 'password') },
+ 'Password change to bad-quality password rejected'
+);
+my $error = $@;
+isa_ok($error, 'Authen::Kerberos::Exception', 'Thrown exception');
+my ($function, $message);
+if (ref($error) && $error->isa('Authen::Kerberos::Exception')) {
+ $function = $error->function;
+ $message = $error->message;
+}
+is($function, 'kadm5_check_password_quality', '...with correct function');
+is(
+ $message,
+ 'External password quality program failed: weak password',
+ '...and correct message'
+);
+
# The same should fail if we attempt it with an unknown database.
$kadmin = Authen::Kerberos::Kadmin->new(
{