ping for kdc utility?

Russ Allbery eagle at eyrie.org
Wed Apr 2 16:33:38 EDT 2014


Wang Shouhua <shouhuaw at gmail.com> writes:

> To see if the KDC is still 'alive and kicking'. Apparently some
> students-as-admins here spend the night trying to find a problem in our
> Kerberos setup the whole night and they are very exhausted. The problem
> turned out to be a switch/firewall problem which caused the KDC to stop
> processing requests after some time, something which could have been
> diagnosed much earlier using a dedicated utility.

I would just authenticate using a keytab and ensure that you can get
tickets.  Here's the script we use for that purpose.  Note that this is
something of a hack and does things like use predictable files in /tmp by
default, so use with caution.  It uses k5start, but you could easily
modify it to use kinit instead.

#!/usr/bin/perl
#
# kdc-check -- Check a Kerberos KDC for correct operation.
#
# Written by R.L. "Bob" Morgan
# Updated by Russ Allbery <rra at stanford.edu>
# Copyright 1994, 2003, 2011
#     The Board of Trustees of the Leland Stanford Junior University

##############################################################################
# Site configuration
##############################################################################

# The location of Kerberos v5 files and programs.  The keytab locaction should
# contain host/<hostname> and the k5start program must support -q, -f, and -u.
our $KRB5_CONF  = '/etc/krb5.conf';
our $KRB_KEYTAB = '/etc/krb5.keytab';
our $K5START    = '/usr/bin/k5start';

# Path to klist that supports the -5 option.
our $KLIST      = '/usr/bin/klist';

##############################################################################
# Modules and declarations
##############################################################################

require 5.003;

use strict;

use Getopt::Long qw(GetOptions);
use Fcntl qw(O_CREAT O_EXCL O_WRONLY);
use Net::Domain qw(hostfqdn);
use Sys::Hostname qw(hostname);

our $USAGE = <<'EOU';
Usage: kdc-check [-5dv] [-c <conf>] [-f <keytab>] [-p <user>] [-r <realm>]
                 [-s <server>]

Checks a Kerberos server by attempting to obtain a ticket.  By default, it
obtains a TGT for host/<hostname> for the local fully qualified system
name, using the keytab in /etc/krb5.keytab and the Kerberos KDCs defined
in the default krb5.conf.

Options:

  -5            Ignored for backward compatibility
  -c <conf>     Use <conf> instead of the default krb5.conf
  -d            Enable debugging (don't delete temporary files)
  -f <keytab>   Use <keytab> instead of /etc/krb5.keytab
  -p <user>     Obtain tickets for <user> instead of host/<hostname>
  -r <realm>    Use the realm <realm>, requires -s be given
  -s <server>   Use the KDC <server>, writing out a temporary krb5.conf
  -v            Be verbose

Exit status:

  0     if server is up and returns proper response
  1     otherwise

EOU
#'# for cperl-mode

##############################################################################
# Kerberos handling
##############################################################################

# Create a temporary file name and return it.  This is a really bad function
# for this and should be replaced with a standard tmp file creation call.
sub tmp_file_name {
    my $program = $0;
    $program =~ s%.*/%%;
    my $tmp = $ENV{TMPDIR} || '/tmp';
    return "$tmp/$program.$$";
}

# Create a krb5.conf file limited to the particular server.  Takes the realm
# name, the server, and optionally the file name into which to put the new
# krb5.conf file, and returns the file name used.  Ideally more of the
# libdefaults section should come from the current configuration file.
sub create_krb5_conf {
    my ($realm, $server, $file) = @_;
    $file = tmp_file_name unless $file;
    sysopen (CONF, $file, O_WRONLY | O_CREAT | O_EXCL)
        or die "$0: cannot create $file: $!\n";
    print CONF <<"EOC";
[libdefaults]
    default_realm   = $realm
    ticket_lifetime = 25hrs

[realms]
    $realm = {
        kdc         = $server:88
    }
EOC
    close CONF or die "$0: cannot flush $file: $!\n";
    return $file;
}

# Given the path to the krb5.conf file, determine the default realm name and
# return it.
sub get_realm {
    my ($conf) = @_;
    open (CONF, $conf) or die "$0: cannot open $conf: $!\n";
    my $realm;
    while (<CONF>) {
        if (/^\s*default_realm\s*=\s*(\S+)/) {
            $realm = $1;
            last;
        }
    }
    return $realm;
}

# Obtain a ticket using k5start.  Takes the ticket file into which it should
# be put, the path to the keytab file, the principal, and a flag saying
# whether to be verbose.  Returns true on success, false on failure.
sub get_ticket {
    my ($cache, $srvtab, $principal, $verbose) = @_;
    unlink $cache;
    $ENV{KRB5CCNAME} = $cache;
    die "$0: unsafe ticket cache name: $cache\n" if $cache =~ /[\'\\\s]/;
    my @args = ('-f', $srvtab, '-u', $principal);
    unshift (@args, '-q') unless $verbose;
    return (system ($K5START, @args) == 0);
}

# Check a Kerberos ticket cache to make sure that it contains the right
# principal.  Takes the cache to check and the principal we're looking for and
# runs klist on the file.
sub check_ticket {
    my ($cache, $principal) = @_;
    my $output = `$KLIST -5 '$cache'`;
    return ($output =~ /\nDefault principal: $principal(\@|\s)/);
}

##############################################################################
# Implementation
##############################################################################

# Trim $0 for error messages.
my $fullname = $0;
$0 =~ s%.*/%%;

# Parse the command line options.
my ($config, $debug, $dummy, $principal, $realm, $server, $keytab,
    $verbose, $help, $version);
Getopt::Long::Configure ('bundling');
GetOptions ('5|krb5'        => \$dummy,
            'c|config=s'    => \$config,
            'd|debug'       => \$debug,
            'f|keytab=s'    => \$keytab,
            'h|help'        => \$help,
            'p|principal=s' => \$principal,
            'r|realm=s'     => \$realm,
            's|server=s'    => \$server,
            'v|verbose'     => \$verbose) or exit 1;

# Act on some standard options.
if ($help) {
    print $USAGE;
    exit 0;
}

# Determine the principal and keytab.
my $hostname = hostfqdn;
$principal = 'host/' . $hostname unless $principal;
$keytab = $KRB_KEYTAB unless $keytab;

# Check the command-line options for consistency and set some defaults.
die "$0: -c cannot be given if -s is given\n" if $config && $server;
die "$0: -r <realm> requires -s <server>\n" if $realm && !$server;
$verbose = 1 if $debug;
if ($server && !$realm) {
    $realm = get_realm ($KRB5_CONF)
        or die "$0: cannot obtain Kerberos realm from $KRB5_CONF\n";
}
$config = create_krb5_conf ($realm, $server) if $server;
$ENV{KRB5_CONFIG} = $config if $config;
my $cache = ($ENV{TMPDIR} || '/tmp') . "/kdc-check.tk$$";

# Print out debugging information if desired.
if ($debug) {
    print "server       = $server\n";
    print "realm        = $realm\n";
    print "principal    = $principal\n";
    print "keytab       = $keytab\n";
    print "cache        = $cache\n";
    print "config       = $config\n";
    print "\nWill run the command:\n\n";
    print "    $K5START " . ($verbose ? '' : "-q ")
        . "-f $keytab -u $principal\n\n";
}

# Now, do the actual work.
my $status;
$status = get_ticket ($cache, $keytab, $principal, $verbose);
$status = check_ticket ($cache, $principal) if $status;
unless ($debug) {
    unlink $cache;
    unlink $config if $server;
}
exit ($status ? 0 : 1);

##############################################################################
# Documentation
##############################################################################

=head1 NAME

kdc-check - Check a Kerberos KDC for correct operation

=head1 SYNOPSIS

B<kdc-check> [B<-5dhv>] [B<--version>] [B<-c> I<config>] [B<-f> I<srvtab>]
    S<[B<-p> I<principal>]> [B<-r> I<realm>] [B<-s> I<server>]

=head1 DESCRIPTION

B<kdc-check> checks the operation of a Kerberos KDC by attempting to
obtain a ticket from it.  It depends on B<k5start> to actually obtain the
ticket. Use the "kstart" Debian package.

It obtains the default realm from F</etc/krb5.conf> and then attempts to
obtain a Kerberos TGT for host/<hostname> in that realm using
F</etc/krb5.keytab>, where <hostname> is the fully-qualified name of the
local system.  Various options can change that behavior.

B<kdc-check> exits with status 0 if the KDC hands back the appropriate
ticket, and with status 1 otherwise.

=head1 OPTIONS

=over 4

=item B<-5>, B<--krb5>

Ignored for backward compatibility.

=item B<-c> I<config>, B<--config>=I<config>

Use I<config> as the krb5.conf file rather than F</etc/krb5.conf>.  This
option cannot be used in combination with the B<-s> option.  It sets the
environment variable KRB5_CONFIG to point the Kerberos libraries at a
different configuration file.

=item B<-d>, B<--debug>

Do not delete the temporary files and print out the values of all internal
variables.  This flag implies B<-v>.

=item B<-f> I<keytab>, B<--keytab>=I<keytab>

Use I<keytab> as the keytab for authentication rather than the default of
F</etc/krb5.keytab>.

=item B<-h>, B<--help>

Print out usage information.

=item B<-p> I<principal>, B<--principal>=I<principal>

Authenticate as I<principal> rather than as the default of host/<host>
where <host> is the fully-qualified local hostname.

=item B<-r> I<realm>, B<--realm>=I<realm>

Obtain a ticket in I<realm> rather than the default Kerberos realm (as
determined by looking in F</etc/krb5.conf>).  This option can only be used
in combination with B<-s>.

=item B<-s> I<server>, B<--server>=I<server>

Obtain tickets specifically from I<server> rather than using the system
default krb5.conf.  This is done by writing out a one-time krb5.conf file
and then setting the environment variable KRB5_CONFIG to point to it.  The
realm can be specified with B<-r>, and if not specified is taken from the
system krb5.conf.  This option cannot be used with B<-c> (for obvious
reasons).

=item B<-v>, B<--verbose>

Do not pass the B<-q> flag to B<k5start>, allowing B<k5start> to be more
verbose about what it's doing.  This flag is implied by B<-d>.

=back

=head1 EXAMPLES

Check default operations by obtaining a TGT for host/<host> using
F</etc/krb5.keytab> from whatever servers are listed in the system default
krb5.conf file (F</etc/krb5.conf>):

    kdc-check

Specifically test that kerberos1.stanford.edu returns a TGT for the
stanford.edu realm, using the default principal and keytab:

    kdc-check -s kerberos1.stanford.edu -r stanford.edu

Test that kerberos1.stanford.edu returns a TGT for the default realm, as
determined from the system krb5.conf file (F</etc/krb5.conf>), for the
principal service/monitoring, using the keytab in
F</etc/keytabs/service.monitoring> for authentication.

    kdc-check -s kerberos1.stanford.edu -p service/monitoring \
        -f /etc/keytabs/service.monitoring

=head1 SEE ALSO

k5start(1)

=head1 AUTHORS

Original version written by R.L. "Bob" Morgan.  Updated and reorganized by
Russ Allbery <rra at stanford.edu>, who also added Kerberos v5 support.

=cut

-- 
Russ Allbery (eagle at eyrie.org)              <http://www.eyrie.org/~eagle/>


More information about the Kerberos mailing list