/MYMETA.yml
/_build/
/blib/
+/config.log
/cover_db
+/glue/
/lib/Authen/Kerberos.c
/lib/Authen/Kerberos/Kadmin.c
*.o
use strict;
use warnings;
+use Config::AutoConf;
+use File::Basename qw(basename);
+use File::Path qw(remove_tree);
+use File::Spec;
use IPC::System::Simple qw(capturex);
use Module::Build;
+# Check whether it's possible to link a program that uses a particular
+# function. This is written like a Config::AutoConf method and should ideally
+# be incorporated into that module. This macro caches its result in the
+# ac_cv_func_FUNCTION variable.
+#
+# $self - The Config::AutoConf state object
+# $function - The function to check for
+# $found_ref - Code reference to call if the function was found
+# $notfound_ref - Code reference to call if the function wasn't found
+#
+# Returns: True if the function was found, false otherwise
+sub check_func {
+ my ($self, $function, $found_ref, $notfound_ref) = @_;
+ $self = $self->_get_instance();
+
+ # Build the name of the cache variable.
+ my $cache_name = $self->_cache_name('func', $function);
+
+ # Wrap the actual check in a closure so that we can use check_cached.
+ my $check_sub = sub {
+ my $have_func = $self->link_if_else($self->lang_call(q{}, $function));
+ if ($have_func) {
+ if (defined($found_ref) && ref($found_ref) eq 'CODE') {
+ $found_ref->();
+ }
+ } else {
+ if (defined($notfound_ref) && ref($notfound_ref) eq 'CODE') {
+ $notfound_ref->();
+ }
+ }
+ return $have_func;
+ };
+
+ # Run the check and cache the results.
+ return $self->check_cached($cache_name, "for $function", $check_sub);
+}
+
+# The same as check_func, but takes a list of functions to look for and checks
+# for each in turn. Define HAVE_FUNCTION for each function that was found,
+# and also run the $found_ref code each time a function was found. Run the
+# $notfound_ref code each time a function wasn't found. Both code references
+# are passed the name of the function that was found.
+#
+# $self - The Config::AutoConf state object
+# $functions_ref - Reference to an array of functions to check for
+# $found_ref - Code reference to call if a function was found
+# $notfound_ref - Code reference to call if a function wasn't found
+#
+# Returns: True if all functions were found, false otherwise.
+sub check_funcs {
+ my ($self, $functions_ref, $user_found_ref, $user_notfound_ref) = @_;
+ $self = $self->_get_instance();
+
+ # Build the code reference to run when a function was found. This defines
+ # a HAVE_FUNCTION symbol, plus runs the current $found_ref if there is
+ # one.
+ my $func_found_ref = sub {
+ my ($function) = @_;
+
+ # Generate the name of the symbol we'll define.
+ my $have_func_name = 'HAVE_' . uc($function);
+ $have_func_name =~ tr/_A-Za-z0-9/_/c;
+
+ # Define the symbol.
+ $self->define_var($have_func_name, 1,
+ "Defined when $function is available");
+
+ # Run the user-provided hook, if there is one.
+ if (defined($user_found_ref) && ref($user_found_ref) eq 'CODE') {
+ $user_found_ref->($function);
+ }
+ };
+
+ # Go through the list of functions and call check_func for each one. We
+ # generate new closures for the found and not-found functions that pass in
+ # the relevant function name.
+ my $return = 1;
+ for my $function (@{$functions_ref}) {
+ my $found_ref = sub { $func_found_ref->($function) };
+ my $notfound_ref = sub { $user_notfound_ref->($function) };
+ $return &= check_func($self, $function, $found_ref, $notfound_ref);
+ }
+ return $return;
+}
+
+# Returns C code that includes the given headers. Used to construct prologues
+# for check functions.
+#
+# @headers - The headers to include
+#
+# Returns: C source as a string that includes those headers
+sub include {
+ my @headers = @_;
+ my $result = q{};
+ for my $header (@headers) {
+ $result .= "#include <$header>\n";
+ }
+ return $result;
+}
+
+# Probes the C compilation environment for the information required to build
+# the Kerberos compatibility layer. This should be a Perl equivalent of the
+# m4/krb5.m4 Autoconf macros from rra-c-util, plus the additional probes
+# needed for the compatibility layer for building the code. Writes the
+# results to glue/config.h and returns a list of extra C files to add to the
+# module build.
+#
+# $build - The module build object, used to add additional libraries
+#
+# Returns: List of extra directories to add to the module build
+# Throws: Text exception if the module cannot be built in this environment
+sub config_kerberos {
+ my ($build) = @_;
+ my $config = Config::AutoConf->new;
+
+ # Checks needed for the generic portability layer.
+ $config->check_default_headers;
+ if (!$config->check_header('stdbool.h')) {
+ $config->check_type('_Bool');
+ }
+ $config->check_type('ssize_t', undef, undef, include('sys/types.h'));
+
+ # If the user passed extra flags into Build.PL, use them for probes.
+ if ($build->extra_linker_flags) {
+ my $flags = $build->extra_linker_flags;
+ my @flags = ref($flags) ? @{$flags} : ($flags);
+ $config->push_link_flags(@flags);
+ }
+
+ # Determine which Kerberos header to use.
+ my $header = $config->check_headers('krb5.h', 'krb5/krb5.h');
+ if (!defined($header)) {
+ die "No Kerberos headers found (tried krb5.h and krb5/krb5.h)\n";
+ }
+
+ # Check for functions that are different between Heimdal and MIT.
+ check_funcs($config, ['krb5_xfree']);
+ my $includes = include($header) . $config->_default_includes;
+ if ($config->check_decl('krb5_kt_free_entry', undef, undef, $includes)) {
+ $config->define_var('HAVE_DECL_KRB5_KT_FREE_ENTRY',
+ 1, 'Defined when krb5_kt_free_entry is declared');
+ }
+
+ # Write out the configuration.
+ $config->write_config_h('glue/config.h');
+ return;
+}
+
# Get the compiler and linker flags for Heimdal. Currently, a new enough
# Heimdal to support pkg-config is required.
my $compiler_flags = capturex('pkg-config', '--cflags', 'heimdal-kadm-server');
dist_version => '0.02',
license => 'mit',
recursive_test_files => 1,
+ add_to_cleanup => [qw(config.log cover_db glue/*.o util/*.o)],
# XS configuration.
- c_source => 'util',
- extra_compiler_flags => [split(q{ }, $compiler_flags)],
+ #<<<
+ c_source => ['glue', 'util'],
+ extra_compiler_flags => ['-I.', split(q{ }, $compiler_flags)],
extra_linker_flags => [split(q{ }, $linker_flags)],
+ #>>>
# Other package relationships.
configure_requires => {
+ 'Config::AutoConf' => 0,
'IPC::System::Simple' => 0,
- 'Module::Build' => '0.28',
+ 'Module::Build' => '0.3604',
autodie => 0,
perl => '5.010',
},
},
);
+# Create the directory that will be used for config.h and stub files.
+remove_tree('glue');
+mkdir('glue');
+
+# Write out the config.h file and get the list of files to add to the build.
+my @c_files = config_kerberos($build);
+
+# We can't just add the C source files directly to the build for a couple of
+# reasons. First, Perl ships its own config.h, so we need to be sure we
+# include our own instead of Perl's before building any source, since all of
+# the files (copied from rra-c-util, so we don't want to change them) include
+# config.h as the first action. Second, Module::Build can only handle
+# directories of supplemental files, not individual file names.
+#
+# We deal with both of these issues by creating stub files in a subdirectory
+# named glue that include glue/config.h and then the actual C source file.
+for my $file (@c_files) {
+ my $glue_file = File::Spec->catfile('glue', basename($file));
+ open(my $wrapper, '>', $glue_file);
+ say {$wrapper} '#include <glue/config.h>'
+ or die "Cannot write to $glue_file: $!\n";
+ say {$wrapper} "#include <$file>"
+ or die "Cannot write to $glue_file: $!\n";
+ close($wrapper);
+}
+
# Generate the build script.
$build->create_build_script;
# Avoid generated build files.
\bblib/
+^config\.log$
+^glue/
+^lib/Authen/Kerberos\.c$
^lib/Authen/Kerberos/Kadmin\.c$
\.o$
use base qw(DynaLoader);
-use Authen::Kerberos::Exception;
use Exporter qw(import);
our $VERSION;
$VERSION = '0.02';
}
+# The C code also creates some other types of objects and throws
+# Authen::Kerberos::Exception objects, and callers expect to be able to call
+# methods on those objects. Load all of the Perl classes for the caller that
+# provide additional object methods so that the caller doesn't have to
+# remember to do so.
+use Authen::Kerberos::Exception;
+use Authen::Kerberos::Principal;
+
# Load the binary module.
bootstrap Authen::Kerberos $VERSION;
=head1 CLASS METHODS
-All class methods throw Authen::Kerberos::Exception objects on any error.
+All class methods throw Authen::Kerberos::Exception objects on any
+Kerberos error.
=over 4
=back
+=head1 INSTANCE METHODS
+
+All class methods throw Authen::Kerberos::Exception objects on any
+Kerberos error.
+
+=over 4
+
+=item keytab(KEYTAB)
+
+Open the given keytab and return a new Authen::Kerberos::Keytab object for
+it. KEYTAB should be in the form I<type>:I<residual> where I<type> is one
+of the keytab type identifiers recognized by the underlying Kerberos
+library. The most common type is C<FILE>, in which case I<residual> is a
+path.
+
+=item principal(NAME)
+
+Convert the given principal name to an Authen::Kerberos::Principal object.
+Normally there is no need to use this method since all Authen::Kerberos
+APIs that take principal names will accept the string form of the principal
+name and convert it internally.
+
+=back
+
=head1 AUTHOR
Russ Allbery <eagle@eyrie.org>
* DEALINGS IN THE SOFTWARE.
*/
+#include <glue/config.h>
+#include <portable/krb5.h>
+#include <portable/system.h>
+
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
-#include <krb5.h>
+#include <util/util.h>
/*
* This typedefs are needed for xsubpp to work its magic with type translation
- * to Perl objects. The krb5_context pointer is used as the Authen::Kerberos
- * object, wrapped in an SV and blessed.
+ * to Perl objects. This strategy can only be used for objects that don't
+ * need to stash a copy of the Kerberos context, such as the Kerberos context
+ * object itself or ones where all methods on the object do not need a
+ * context.
*/
typedef krb5_context Authen__Kerberos;
+/*
+ * Wrapper structs for additional data structures returned by the Kerberos
+ * libraries. We wrap the API data structure so that we can store a reference
+ * to the Authen::Kerberos object (the Kerberos context), ensuring that the
+ * Kerberos context is not freed before the secondary object and that the same
+ * Kerberos context is used for all operations on that object.
+ */
+typedef struct {
+ SV *ctx;
+ krb5_keytab keytab;
+} *Authen__Kerberos__Keytab;
+
+typedef struct {
+ SV *ctx;
+ krb5_keytab_entry entry;
+} *Authen__Kerberos__KeytabEntry;
+
+typedef struct {
+ SV *ctx;
+ krb5_principal principal;
+} *Authen__Kerberos__Principal;
+
/* XS code below this point. */
if (self != NULL)
krb5_free_context(self);
}
+
+
+Authen::Kerberos::Keytab
+keytab(self, name)
+ Authen::Kerberos self
+ const char *name
+ PREINIT:
+ Authen__Kerberos__Keytab kt;
+ krb5_error_code code;
+ krb5_keytab keytab;
+ CODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos", "keytab_open");
+ code = krb5_kt_resolve(self, name, &keytab);
+ if (code != 0)
+ krb5_croak(self, code, "krb5_kt_resolve", FALSE);
+ kt = malloc(sizeof(*kt));
+ if (kt == NULL)
+ croak("cannot allocate memory");
+ kt->keytab = keytab;
+ kt->ctx = SvRV(ST(0));
+ SvREFCNT_inc_simple_void_NN(kt->ctx);
+ RETVAL = kt;
+}
+ OUTPUT:
+ RETVAL
+
+
+Authen::Kerberos::Principal
+principal(self, name)
+ Authen::Kerberos self
+ const char *name
+ PREINIT:
+ krb5_error_code code;
+ krb5_principal principal;
+ Authen__Kerberos__Principal princ;
+ CODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos", "principal");
+ code = krb5_parse_name(self, name, &principal);
+ if (code != 0)
+ krb5_croak(self, code, "krb5_parse_name", FALSE);
+ princ = malloc(sizeof(*princ));
+ if (princ == NULL)
+ croak("cannot allocate memory");
+ princ->principal = principal;
+ princ->ctx = SvRV(ST(0));
+ SvREFCNT_inc_simple_void_NN(princ->ctx);
+ RETVAL = princ;
+}
+ OUTPUT:
+ RETVAL
+
+
+MODULE = Authen::Kerberos PACKAGE = Authen::Kerberos::Keytab
+
+void
+DESTROY(self)
+ Authen::Kerberos::Keytab self
+ PREINIT:
+ krb5_context ctx;
+ CODE:
+{
+ if (self == NULL)
+ return;
+ ctx = krb5_context_from_sv(self->ctx, "Authen::Kerberos::Keytab");
+ krb5_kt_close(ctx, self->keytab);
+ SvREFCNT_dec(self->ctx);
+ free(self);
+}
+
+
+void
+entries(self, callback)
+ Authen::Kerberos::Keytab self
+ SV *callback
+ PREINIT:
+ krb5_context ctx;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ Authen__Kerberos__KeytabEntry obj;
+ krb5_error_code code;
+ size_t count = 0;
+ PPCODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos::Keytab", "entries");
+ ctx = krb5_context_from_sv(self->ctx, "Authen::Kerberos::Keytab");
+
+ /* Start the cursor. */
+ code = krb5_kt_start_seq_get(ctx, self->keytab, &cursor);
+ if (code != 0)
+ krb5_croak(ctx, code, "krb5_kt_start_seq_get", FALSE);
+
+ /* For each entry, either count it or add it to the output stack. */
+ code = krb5_kt_next_entry(ctx, self->keytab, &entry, &cursor);
+ while (code != KRB5_KT_END) {
+ count++;
+ if (GIMME_V == G_ARRAY) {
+ SV *obj;
+ Authen__Kerberos__KeytabEntry wrapper;
+
+ wrapper = malloc(sizeof(*wrapper));
+ if (wrapper == NULL)
+ croak("cannot allocate memory");
+ wrapper->ctx = self->ctx;
+ SvREFCNT_inc_simple_void_NN(wrapper->ctx);
+ wrapper->entry = entry;
+ obj = sv_newmortal();
+ sv_setref_pv(obj, "Authen::Kerberos::KeytabEntry", wrapper);
+ XPUSHs(obj);
+ }
+ code = krb5_kt_next_entry(ctx, self->keytab, &entry, &cursor);
+ }
+
+ /* Make sure everything was successful and close the cursor. */
+ if (code != KRB5_KT_END)
+ krb5_croak(ctx, code, "krb5_kt_next_entry", FALSE);
+ krb5_kt_end_seq_get(ctx, self->keytab, &cursor);
+
+ /* If we're in a scalar context, push the count. */
+ if (GIMME_V != G_ARRAY) {
+ ST(0) = newSViv(count);
+ sv_2mortal(ST(0));
+ XSRETURN(1);
+ }
+}
+
+
+MODULE = Authen::Kerberos PACKAGE = Authen::Kerberos::KeytabEntry
+
+void
+DESTROY(self)
+ Authen::Kerberos::KeytabEntry self
+ PREINIT:
+ krb5_context ctx;
+ CODE:
+{
+ if (self == NULL)
+ return;
+ ctx = krb5_context_from_sv(self->ctx, "Authen::Kerberos::KeytabEntry");
+ krb5_kt_free_entry(ctx, &self->entry);
+ SvREFCNT_dec(self->ctx);
+ free(self);
+}
+
+
+krb5_kvno
+kvno(self)
+ Authen::Kerberos::KeytabEntry self
+ CODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos::KeytabEntry", "kvno");
+ RETVAL = self->entry.vno;
+}
+ OUTPUT:
+ RETVAL
+
+
+Authen::Kerberos::Principal
+principal(self)
+ Authen::Kerberos::KeytabEntry self
+ PREINIT:
+ krb5_context ctx;
+ krb5_principal princ;
+ krb5_error_code code;
+ Authen__Kerberos__Principal principal;
+ CODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos::KeytabEntry", "principal");
+ ctx = krb5_context_from_sv(self->ctx, "Authen::Kerberos::KeytabEntry");
+ if (principal == NULL)
+ croak("cannot allocate memory");
+ code = krb5_copy_principal(ctx, self->entry.principal, &princ);
+ if (code != 0)
+ krb5_croak(ctx, code, "krb5_copy_principal", FALSE);
+ principal = malloc(sizeof(*principal));
+ principal->ctx = self->ctx;
+ SvREFCNT_inc_simple_void_NN(principal->ctx);
+ principal->principal = princ;
+ RETVAL = principal;
+}
+ OUTPUT:
+ RETVAL
+
+
+krb5_timestamp
+timestamp(self)
+ Authen::Kerberos::KeytabEntry self
+ CODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos::KeytabEntry", "timestamp");
+ RETVAL = self->entry.timestamp;
+}
+ OUTPUT:
+ RETVAL
+
+
+MODULE = Authen::Kerberos PACKAGE = Authen::Kerberos::Principal
+
+void
+DESTROY(self)
+ Authen::Kerberos::Principal self
+ PREINIT:
+ krb5_context ctx;
+ CODE:
+{
+ if (self == NULL)
+ return;
+ ctx = krb5_context_from_sv(self->ctx, "Authen::Kerberos::Principal");
+ krb5_free_principal(ctx, self->principal);
+ SvREFCNT_dec(self->ctx);
+ free(self);
+}
+
+
+SV *
+to_string(self, other = NULL, swap = 0)
+ Authen::Kerberos::Principal self
+ SV *other
+ bool swap
+ OVERLOAD: \"\"
+ PREINIT:
+ krb5_context ctx;
+ krb5_error_code code;
+ char *principal;
+ CODE:
+{
+ CROAK_NULL_SELF(self, "Authen::Kerberos::Principal", "to_string");
+ ctx = krb5_context_from_sv(self->ctx, "Authen::Kerberos::Principal");
+ code = krb5_unparse_name(ctx, self->principal, &principal);
+ if (code != 0)
+ krb5_croak(ctx, code, "krb5_unparse_name", FALSE);
+ RETVAL = newSVpv(principal, 0);
+ krb5_free_unparsed_name(ctx, principal);
+}
+ OUTPUT:
+ RETVAL
#include <perl.h>
#include <XSUB.h>
-#include <krb5.h>
+#include <portable/krb5.h>
#include <kadm5/admin.h>
#include <kadm5/kadm5_err.h>
--- /dev/null
+# Wrapper class for Kerberos keytab objects.
+#
+# This class provides the Perl representation of a krb5_keytab structure as
+# used in the Kerberos API. Most of the implementation is in the XS code
+# underlying Authen::Kerberos. This file provides documentation and some
+# additional code that's easier to represent in Perl.
+#
+# 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.
+
+package Authen::Kerberos::Keytab;
+
+use 5.010;
+use strict;
+use warnings;
+
+use Authen::Kerberos;
+
+our $VERSION;
+
+# Set $VERSION in a BEGIN block for robustness.
+BEGIN {
+ $VERSION = '0.02';
+}
+
+1;
+
+__END__
+
+=for stopwords
+Allbery keytab
+
+=head1 NAME
+
+Authen::Kerberos::Keytab - Kerberos API representation of a keytab
+
+=head1 SYNOPSIS
+
+ use Authen::Kerberos;
+
+ my $krb5 = Authen::Kerberos->new;
+ my $keytab = $krb5->keytab('FILE:/etc/krb5.keytab');
+ my @entries = $keytab->entries;
+ print 'First principal: ', $entries[0]->principal, "\n";
+
+=head1 DESCRIPTION
+
+An Authen::Kerberos::Keytab object wraps the Kerberos API
+representation of an open keytab (key table). A keytab holds zero or
+more principal keys, usually in the form of a disk file.
+
+=head1 INSTANCE METHODS
+
+As with all Authen::Kerberos methods, an Authen::Kerberos::Exception
+object will be thrown on any Kerberos error.
+
+=over 4
+
+=item entries()
+
+In a scalar context, returns the number of entries in a keytab. In an
+array context, returns all of the entries of the keytab as
+Authen::Kerberos::KeytabEntry objects.
+
+=back
+
+=head1 AUTHOR
+
+Russ Allbery <eagle@eyrie.org>
+
+=head1 SEE ALSO
+
+L<Authen::Kerberos>, L<Authen::Kerberos::Exception>,
+L<Authen::Kerberos::KeytabEntry>
+
+=cut
--- /dev/null
+# Wrapper class for Kerberos keytab entry objects.
+#
+# This class provides the Perl representation of a krb5_keytab_entry structure
+# as used in the Kerberos API. Most of the implementation is in the XS code
+# underlying Authen::Kerberos. This file provides documentation and some
+# additional code that's easier to represent in Perl.
+#
+# 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.
+
+package Authen::Kerberos::KeytabEntry;
+
+use 5.010;
+use strict;
+use warnings;
+
+use Authen::Kerberos;
+
+our $VERSION;
+
+# Set $VERSION in a BEGIN block for robustness.
+BEGIN {
+ $VERSION = '0.02';
+}
+
+1;
+
+__END__
+
+=for stopwords
+Allbery KVNO keytab
+
+=head1 NAME
+
+Authen::Kerberos::KeytabEntry - Kerberos API representation of a keytab entry
+
+=head1 SYNOPSIS
+
+ use Authen::Kerberos;
+
+ my $krb5 = Authen::Kerberos->new;
+ my $keytab = $krb5->keytab('FILE:/etc/krb5.keytab');
+ my @entries = $keytab->entries;
+ print 'First principal: ', $entries[0]->principal, "\n";
+
+=head1 DESCRIPTION
+
+An Authen::Kerberos::KeytabEntry object wraps the Kerberos API
+representation of an entry in a keytab (key table). A keytab holds zero
+or more entries, usually in the form of a disk file. Each entry has a
+key for a particular principal.
+
+=head1 INSTANCE METHODS
+
+As with all Authen::Kerberos methods, an Authen::Kerberos::Exception
+object will be thrown on any Kerberos error.
+
+=over 4
+
+=item kvno()
+
+Returns the KVNO (key version number) of this keytab entry.
+
+=item principal()
+
+Returns the principal whose key is stored in this entry, in the form of an
+Authen::Kerberos::Principal object.
+
+=item timestamp()
+
+Returns the timestamp of this keytab entry as seconds since UNIX epoch.
+
+=back
+
+=head1 AUTHOR
+
+Russ Allbery <eagle@eyrie.org>
+
+=head1 SEE ALSO
+
+L<Authen::Kerberos>, L<Authen::Kerberos::Exception>,
+L<Authen::Kerberos::Keytab>
+
+=cut
--- /dev/null
+# Wrapper class for Kerberos principal objects.
+#
+# This class provides the Perl representation of a krb5_principal structure as
+# used in the Kerberos API. Most of the implementation is in the XS code
+# underlying Authen::Kerberos. This file provides documentation and some
+# additional code that's easier to represent in Perl.
+#
+# 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.
+
+package Authen::Kerberos::Principal;
+
+use 5.010;
+use strict;
+use warnings;
+
+use Authen::Kerberos;
+
+our $VERSION;
+
+# Set $VERSION in a BEGIN block for robustness.
+BEGIN {
+ $VERSION = '0.02';
+}
+
+1;
+
+__END__
+
+=for stopwords
+Allbery
+
+=head1 NAME
+
+Authen::Kerberos::Principal - Kerberos API representation of a principal name
+
+=head1 SYNOPSIS
+
+ use Authen::Kerberos;
+ use Authen::Kerberos::Principal;
+
+ my $krb5 = Authen::Kerberos->new;
+ my $principal = $krb5->principal('test@EXAMPLE.COM');
+ print "Principal: $principal\n";
+
+=head1 DESCRIPTION
+
+An Authen::Kerberos::Principal object wraps the Kerberos API
+representation of a parsed principal name.
+
+Normally, a user of the Authen::Kerberos module does not have to care
+about the existence of this object. APIs that take principals will take
+either strings or Authen::Kerberos::Principal objects, and an
+Authen::Kerberos::Principal object will be automatically converted to a
+string when necessary. Under the hood, this object holds a parsed form of
+the principal that unambiguously separates the principal components and
+realm without needing to use the escaping that the string display form
+uses.
+
+=head1 INSTANCE METHODS
+
+As with all Authen::Kerberos methods, an Authen::Kerberos::Exception
+object will be thrown on any Kerberos error.
+
+=over 4
+
+=item to_string()
+
+Returns the string form (the display form) of the principal. This method
+will be automatically called if an Authen::Kerberos::Principal object is
+interpolated into a string. It may also be called directly to retrieve
+the string form of the principal name. Special characters in any
+principal component, such as C<@> or C</>, will be escaped using the
+normal Kerberos principal string encoding.
+
+=back
+
+=head1 AUTHOR
+
+Russ Allbery <eagle@eyrie.org>
+
+=head1 SEE ALSO
+
+L<Authen::Kerberos>, L<Authen::Kerberos::Exception>
+
+=cut
--- /dev/null
+/*
+ * Portability wrapper around krb5.h.
+ *
+ * This header includes krb5.h and then adjusts for various portability
+ * issues, primarily between MIT Kerberos and Heimdal, so that code can be
+ * written to a consistent API.
+ *
+ * Unfortunately, due to the nature of the differences between MIT Kerberos
+ * and Heimdal, it's not possible to write code to either one of the APIs and
+ * adjust for the other one. In general, this header tries to make available
+ * the Heimdal API and fix it for MIT Kerberos, but there are places where MIT
+ * Kerberos requires a more specific call. For those cases, it provides the
+ * most specific interface.
+ *
+ * For example, MIT Kerberos has krb5_free_unparsed_name() whereas Heimdal
+ * prefers the generic krb5_xfree(). In this case, this header provides
+ * krb5_free_unparsed_name() for both APIs since it's the most specific call.
+ *
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ *
+ * The authors hereby relinquish any claim to any copyright that they may have
+ * in this work, whether granted under contract or by operation of law or
+ * international treaty, and hereby commit to the public, at large, that they
+ * shall not, at any time in the future, seek to enforce any copyright in this
+ * work against any person or entity, or prevent any person or entity from
+ * copying, publishing, distributing or creating derivative works of this
+ * work.
+ */
+
+#ifndef PORTABLE_KRB5_H
+#define PORTABLE_KRB5_H 1
+
+/*
+ * Allow inclusion of config.h to be skipped, since sometimes we have to use a
+ * stripped-down version of config.h with a different name.
+ */
+#ifndef CONFIG_H_INCLUDED
+# include <config.h>
+#endif
+#include <portable/macros.h>
+
+#ifdef HAVE_KRB5_H
+# include <krb5.h>
+#else
+# include <krb5/krb5.h>
+#endif
+
+BEGIN_DECLS
+
+/* Default to a hidden visibility for all portability functions. */
+#pragma GCC visibility push(hidden)
+
+/* Heimdal: krb5_xfree, MIT: krb5_free_unparsed_name. */
+#ifdef HAVE_KRB5_XFREE
+# define krb5_free_unparsed_name(c, p) krb5_xfree(p)
+#endif
+
+/*
+ * Heimdal: krb5_kt_free_entry, MIT: krb5_free_keytab_entry_contents. We
+ * check for the declaration rather than the function since the function is
+ * present in older MIT Kerberos libraries but not prototyped.
+ */
+#if !HAVE_DECL_KRB5_KT_FREE_ENTRY
+# define krb5_kt_free_entry(c, e) krb5_free_keytab_entry_contents((c), (e))
+#endif
+
+/* Undo default visibility change. */
+#pragma GCC visibility pop
+
+END_DECLS
+
+#endif /* !PORTABLE_KRB5_H */
--- /dev/null
+/*
+ * Portability wrapper around <stdbool.h>.
+ *
+ * Provides the bool and _Bool types and the true and false constants,
+ * following the C99 specification, on hosts that don't have stdbool.h. This
+ * logic is based heavily on the example in the Autoconf manual.
+ *
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ *
+ * The authors hereby relinquish any claim to any copyright that they may have
+ * in this work, whether granted under contract or by operation of law or
+ * international treaty, and hereby commit to the public, at large, that they
+ * shall not, at any time in the future, seek to enforce any copyright in this
+ * work against any person or entity, or prevent any person or entity from
+ * copying, publishing, distributing or creating derivative works of this
+ * work.
+ */
+
+#ifndef PORTABLE_STDBOOL_H
+#define PORTABLE_STDBOOL_H 1
+
+/*
+ * Allow inclusion of config.h to be skipped, since sometimes we have to use a
+ * stripped-down version of config.h with a different name.
+ */
+#ifndef CONFIG_H_INCLUDED
+# include <config.h>
+#endif
+
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# if HAVE__BOOL
+# define bool _Bool
+# else
+# ifdef __cplusplus
+typedef bool _Bool;
+# elif _WIN32
+# include <windef.h>
+# define bool BOOL
+# else
+typedef unsigned char _Bool;
+# define bool _Bool
+# endif
+# endif
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif
+
+/*
+ * If we define bool and don't tell Perl, it will try to define its own and
+ * fail. Only of interest for programs that also include Perl headers.
+ */
+#ifndef HAS_BOOL
+# define HAS_BOOL 1
+#endif
+
+#endif /* !PORTABLE_STDBOOL_H */
--- /dev/null
+/*
+ * Standard system includes and portability adjustments.
+ *
+ * Declarations of routines and variables in the C library. Including this
+ * file is the equivalent of including all of the following headers,
+ * portably:
+ *
+ * #include <sys/types.h>
+ * #include <stdarg.h>
+ * #include <stdbool.h>
+ * #include <stddef.h>
+ * #include <stdio.h>
+ * #include <stdlib.h>
+ * #include <stdint.h>
+ * #include <string.h>
+ * #include <strings.h>
+ * #include <unistd.h>
+ *
+ * Missing functions are provided via #define or prototyped if available from
+ * the portable helper library. Also provides some standard #defines.
+ *
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ *
+ * The authors hereby relinquish any claim to any copyright that they may have
+ * in this work, whether granted under contract or by operation of law or
+ * international treaty, and hereby commit to the public, at large, that they
+ * shall not, at any time in the future, seek to enforce any copyright in this
+ * work against any person or entity, or prevent any person or entity from
+ * copying, publishing, distributing or creating derivative works of this
+ * work.
+ */
+
+#ifndef PORTABLE_SYSTEM_H
+#define PORTABLE_SYSTEM_H 1
+
+/* Make sure we have our configuration information. */
+#include <config.h>
+
+/* BEGIN_DECL and __attribute__. */
+#include <portable/macros.h>
+
+/* A set of standard ANSI C headers. We don't care about pre-ANSI systems. */
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#include <stdarg.h>
+#include <stddef.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#include <sys/types.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* SCO OpenServer gets int32_t from here. */
+#if HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h>
+#endif
+
+/* Get the bool type. */
+#include <portable/stdbool.h>
+
+/* Windows provides snprintf under a different name. */
+#ifdef _WIN32
+# define snprintf _snprintf
+#endif
+
+/* Windows does not define ssize_t. */
+#ifndef HAVE_SSIZE_T
+typedef ptrdiff_t ssize_t;
+#endif
+
+/*
+ * POSIX requires that these be defined in <unistd.h>. If one of them has
+ * been defined, all the rest almost certainly have.
+ */
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+# define STDOUT_FILENO 1
+# define STDERR_FILENO 2
+#endif
+
+/*
+ * C99 requires va_copy. Older versions of GCC provide __va_copy. Per the
+ * Autoconf manual, memcpy is a generally portable fallback.
+ */
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy(d, s) __va_copy((d), (s))
+# else
+# define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list))
+# endif
+#endif
+
+#endif /* !PORTABLE_SYSTEM_H */
use strict;
use warnings;
-use Test::More tests => 2;
+use Test::More tests => 4;
BEGIN {
use_ok('Authen::Kerberos');
# Test creation of a Kerberos context (Authen::Kerberos object).
my $krb5 = Authen::Kerberos->new;
isa_ok($krb5, 'Authen::Kerberos');
+
+# Create a principal (Authen::Kerberos::Principal object).
+my $principal = $krb5->principal('test@EXAMPLE.COM');
+isa_ok($principal, 'Authen::Kerberos::Principal');
+is("$principal", 'test@EXAMPLE.COM', 'Principal is correct');
TYPEMAP
+krb5_kvno T_IV
+krb5_timestamp T_IV
+
Authen::Kerberos T_PTROBJ_NU
Authen::Kerberos::Kadmin T_PTROBJ_NU
+Authen::Kerberos::Keytab T_PTROBJ_NU
+Authen::Kerberos::KeytabEntry T_PTROBJ_NU
+Authen::Kerberos::Principal T_PTROBJ_NU
INPUT
--- /dev/null
+/*
+ * Utility functions for XS code to manipulate Kerberos contexts.
+ *
+ * Provides helper functions to manipulate Kerberos contexts in the
+ * representation used inside Authen::Kerberos objects.
+ *
+ * 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.
+ */
+
+#include <EXTERN.h>
+#include <perl.h>
+#include <XSUB.h>
+
+#include <portable/krb5.h>
+
+
+/*
+ * Given an SV containing a krb5_context, return the underlying context
+ * pointer for use with direct Kerberos calls. Takes the type of object from
+ * which the context is being retrieved for error reporting.
+ */
+krb5_context
+krb5_context_from_sv(SV *ctx_sv, const char *type)
+{
+ IV ctx_iv;
+ krb5_context ctx;
+
+ if (ctx_sv == NULL)
+ croak("no Kerberos context in %s object", type);
+ ctx_iv = SvIV(ctx_sv);
+ ctx = INT2PTR(krb5_context, ctx_iv);
+ return ctx;
+}
#include <perl.h>
#include <XSUB.h>
-#include <krb5.h>
+#include <portable/krb5.h>
/*
#include <portable/macros.h>
-#include <krb5.h> /* krb5_contxt, krb5_error_code */
+#include <portable/krb5.h> /* krb5_contxt, krb5_error_code */
#include <perl.h> /* bool */
/* Used to check that an object argument to a function is not NULL. */
/* Default to a hidden visibility for all util functions. */
#pragma GCC visibility push(hidden)
+/*
+ * Given an SV that represents a Kerberos context, returns the underlying
+ * context. Takes the type of the object making this call for error
+ * reporting. Croaks if the SV is not valid.
+ */
+krb5_context krb5_context_from_sv(SV *, const char *type);
+
/*
* Given a Kerberos context, an error code, and the Kerberos function that
* failed, construct an Authen::Kerberos::Exception object and throw it using