diff options
| author | Russ Allbery <rra@stanford.edu> | 2007-08-28 06:22:35 +0000 | 
|---|---|---|
| committer | Russ Allbery <rra@stanford.edu> | 2007-08-28 06:22:35 +0000 | 
| commit | 3c3d5c870b45ba64b105742788384d8f83456a91 (patch) | |
| tree | 2f71de3dd80aeb38e6c12726bd03bb195095314a | |
| parent | 3c24b3a018dac170048d40419e1b00a78adaf5bb (diff) | |
Add the keytab object implementation.  Add the skeleton of a config
module which currently doesn't do anything useful except define some
variables so that I can do syntax checking.
| -rw-r--r-- | perl/Wallet/Config.pm | 41 | ||||
| -rw-r--r-- | perl/Wallet/Object/Keytab.pm | 184 | 
2 files changed, 225 insertions, 0 deletions
| diff --git a/perl/Wallet/Config.pm b/perl/Wallet/Config.pm new file mode 100644 index 0000000..6dd2313 --- /dev/null +++ b/perl/Wallet/Config.pm @@ -0,0 +1,41 @@ +# Wallet::Config -- Configuration handling for the wallet server. +# $Id$ +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2007 Board of Trustees, Leland Stanford Jr. University +# +# See README for licensing terms. + +############################################################################## +# Modules and declarations +############################################################################## + +package Wallet::Config; +require 5.006; + +use strict; +use vars qw($PATH $VERSION); + +# This version should be increased on any code change to this module.  Always +# use two digits for the minor version with a leading zero if necessary so +# that it will sort properly. +$VERSION = '0.01'; + +# Path to the config file to load. +$PATH = '/etc/wallet.conf'; + +############################################################################## +# Variables +############################################################################## + +# Configuration for the keytab object type. +our $KEYTAB_FILE; +our $KEYTAB_FLAGS     = '-clearpolicy'; +our $KEYTAB_HOST; +our $KEYTAB_KADMIN    = 'kadmin'; +our $KEYTAB_PRINCIPAL; +our $KEYTAB_REALM; +our $KEYTAB_TMP; + +1; +__END__ diff --git a/perl/Wallet/Object/Keytab.pm b/perl/Wallet/Object/Keytab.pm new file mode 100644 index 0000000..f03a29c --- /dev/null +++ b/perl/Wallet/Object/Keytab.pm @@ -0,0 +1,184 @@ +# Wallet::Object::Keytab -- Keytab object implementation for the wallet. +# $Id$ +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2007 Board of Trustees, Leland Stanford Jr. University +# +# See README for licensing terms. + +############################################################################## +# Modules and declarations +############################################################################## + +package Wallet::Object::Keytab; +require 5.006; + +use strict; +use vars qw(@ISA $VERSION); + +use Wallet::Config (); + +@ISA = qw(Wallet::Object); + +# This version should be increased on any code change to this module.  Always +# use two digits for the minor version with a leading zero if necessary so +# that it will sort properly. +$VERSION = '0.01'; + +############################################################################## +# kadmin Interaction +############################################################################## + +# Make sure that principals are well-formed and don't contain characters that +# will cause us problems when talking to kadmin.  Takes a principal and +# returns true if it's okay, false otherwise. +sub _valid_principal { +    my ($self, $principal) = @_; +    if ($principal !~ m,^[\w-]+(/[\w_-]+)?\@[\w._-]+,) { +        return undef; +    } +    return 1; +} + +# Run a kadmin command and capture the output.  Returns the output, either as +# a list of lines or, in scalar context, as one string.  The exit status of +# kadmin is often worthless. +sub _kadmin { +    my ($self, $command) = @_; +    my @args = ('-p', $Wallet::Config::KEYTAB_PRINCIPAL, '-k', '-t', +                $Wallet::Config::KEYTAB_FILE, '-q', $command); +    push (@args, '-s', $Wallet::Config::KEYTAB_HOST) +        if $Wallet::Config::KEYTAB_HOST; +    my $pid = open (KADMIN, '-|'); +    if (not defined $pid) { +        die "error: cannot fork: $!\n"; +    } elsif ($pid == 0) { +        open (STDERR, '>&STDOUT') or die "error: cannot dup stdout: $!\n"; +        exec ($Wallet::Config::KEYTAB_KADMIN, @args) +            or die "error: cannot run $Wallet::Config::KEYTAB_KADMIN\n"; +    } +    local $_; +    my @output; +    while (<KADMIN>) { +        push (@output, $_) unless /Authenticating as principal/; +    } +    close KADMIN; +    return wantarray ? @output : join ('', @output); +} + +# Check whether a given principal already exists in Kerberos.  Returns true if +# so, false otherwise. +sub _kadmin_exists { +    my ($self, $principal) = @_; +    return undef unless $self->_valid_principal ($principal); +    my $output = $self->_kadmin ("getprinc $principal"); +    if ($output =~ /does not exist/) { +        return undef; +    } else { +        return 1; +    } +} + +# Create a principal in Kerberos.  Return true if successful, false otherwise. +sub _kadmin_addprinc { +    my ($self, $principal) = @_; +    unless ($self->_valid_principal ($principal)) { +        $self->{error} = "invalid principal name: $principal"; +        return undef; +    } +    my $flags = $Wallet::Config::KEYTAB_FLAGS; +    my $output = $self->_kadmin ("addprinc -randkey $flags $principal"); +    if ($output =~ /^add_principal: (.*)/m) { +        return undef; +    } +    return 1; +} + +# Create a keytab from a principal.  Return true if successful, false +# otherwise.  If the keytab creation fails, sets the error. +sub _kadmin_ktadd { +    my ($self, $principal, $file) = @_; +    unless ($self->_valid_principal ($principal)) { +        $self->{error} = "invalid principal name: $principal"; +        return undef; +    } +    my $output = $self->_kadmin ("ktadd -q -k $file $principal"); +    if ($output =~ /^ktadd: (.*)/m) { +        $self->{error} = "error creating keytab for $principal: $1"; +        return undef; +    } +    return 1; +} + +# Delete a principal from Kerberos.  Return true if successful, false +# otherwise.  If the deletion fails, sets the error.  If the principal doesn't +# exist, return success; we're bringing reality in line with our expectations. +sub _kadmin_delprinc { +    my ($self, $principal) = @_; +    unless ($self->_valid_principal ($principal)) { +        $self->{error} = "invalid principal name: $principal"; +        return undef; +    } +    if (not $self->_kadmin_exists ($principal)) { +        return 1; +    } +    my $output = $self->_kadmin ("delprinc $principal"); +    if ($output =~ /^delete_principal: (.*)/m) { +        $self->{error} = "error deleting $principal: $1"; +        return undef; +    } +    return 1; +} + +############################################################################## +# Implementation +############################################################################## + +# Override create to start by creating the principal in Kerberos and only +# create the entry in the database if that succeeds.  Error handling isn't +# great here since we don't have a way to communicate the error back to the +# caller. +sub create { +    my ($class, $name, $type, $dbh, $creator, $host, $time) = @_; +    if ($name !~ /\@/ && $Wallet::Config::KEYTAB_REALM) { +        $name .= '@' . $Wallet::Config::KEYTAB_REALM; +    } +    return undef if not $class->_kadmin_addprinc ($name); +    return $class->SUPER::create ($name, $type, $dbh, $creator, $host, $time); +} + +# Override destroy to delete the principal out of Kerberos as well. +sub destroy { +    my ($self, $user, $host, $time) = @_; +    return undef if not $self->_kadmin_delprinc ($self->{name}); +    return $self->SUPER::destroy ($user, $host, $time); +} + +# Our get implementation.  Generate a keytab into a temporary file and then +# return that as the return value. +sub get { +    my ($self, $user, $host, $time) = @_; +    $time ||= time; +    my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$"; +    return undef if not $self->_kadmin_ktadd ($self->{name}); +    local *KEYTAB; +    unless (open (KEYTAB, '<', $file)) { +        my $princ = $self->{name}; +        $self->{error} = "error creating keytab for principal $princ: $!"; +        return undef; +    } +    local $/; +    undef $!; +    my $data = <KEYTAB>; +    if ($!) { +        my $princ = $self->{name}; +        $self->{error} = "error creating keytab for principal $princ: $!"; +        return undef; +    } +    close KEYTAB; +    $self->log_action ('get', $user, $host, $time); +    return $data; +} + +1; +__END__; | 
