]> eyrie.org Git - kerberos/heimdal-kadm5.git/commitdiff
Initial revision
authorleifj <leifj@453aeaa5-fa1e-0410-b91d-a05dbf4e1782>
Wed, 23 Apr 2003 11:02:26 +0000 (11:02 +0000)
committerleifj <leifj@453aeaa5-fa1e-0410-b91d-a05dbf4e1782>
Wed, 23 Apr 2003 11:02:26 +0000 (11:02 +0000)
git-svn-id: svn://svn.it.su.se/Heimdal-Kadm5/trunk@2 453aeaa5-fa1e-0410-b91d-a05dbf4e1782

Changes [new file with mode: 0644]
Kadm5.pm [new file with mode: 0644]
Kadm5.xs [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
consts.h [new file with mode: 0644]
test.pl [new file with mode: 0644]
typemap [new file with mode: 0644]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..d2f2e25
--- /dev/null
+++ b/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension Heimdal::Kadm5.
+
+0.01  Sun Feb  9 22:01:22 2003
+       - original version; created by h2xs 1.21 with options
+               -n Heimdal::Kadm5
+
diff --git a/Kadm5.pm b/Kadm5.pm
new file mode 100644 (file)
index 0000000..f1eb3ab
--- /dev/null
+++ b/Kadm5.pm
@@ -0,0 +1,783 @@
+package Heimdal::Kadm5;
+
+use strict;
+use Carp;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
+
+require Exporter;
+require DynaLoader;
+require AutoLoader;
+
+@ISA = qw(Exporter DynaLoader);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT_OK = qw(
+               KADM5_ADMIN_SERVICE
+               KADM5_API_VERSION_1
+               KADM5_API_VERSION_2
+               KADM5_ATTRIBUTES
+               KADM5_AUX_ATTRIBUTES
+               KADM5_CHANGEPW_SERVICE
+               KADM5_CONFIG_ACL_FILE
+               KADM5_CONFIG_ADBNAME
+               KADM5_CONFIG_ADB_LOCKFILE
+               KADM5_CONFIG_ADMIN_KEYTAB
+               KADM5_CONFIG_ADMIN_SERVER
+               KADM5_CONFIG_DBNAME
+               KADM5_CONFIG_DICT_FILE
+               KADM5_CONFIG_ENCTYPE
+               KADM5_CONFIG_ENCTYPES
+               KADM5_CONFIG_EXPIRATION
+               KADM5_CONFIG_FLAGS
+               KADM5_CONFIG_KADMIND_PORT
+               KADM5_CONFIG_MAX_LIFE
+               KADM5_CONFIG_MAX_RLIFE
+               KADM5_CONFIG_MKEY_FROM_KEYBOARD
+               KADM5_CONFIG_MKEY_NAME
+               KADM5_CONFIG_PROFILE
+               KADM5_CONFIG_REALM
+               KADM5_CONFIG_STASH_FILE
+               KADM5_FAIL_AUTH_COUNT
+               KADM5_HIST_PRINCIPAL
+               KADM5_KEY_DATA
+               KADM5_KVNO
+               KADM5_LAST_FAILED
+               KADM5_LAST_PWD_CHANGE
+               KADM5_LAST_SUCCESS
+               KADM5_MAX_LIFE
+               KADM5_MAX_RLIFE
+               KADM5_MKVNO
+               KADM5_MOD_NAME
+               KADM5_MOD_TIME
+               KADM5_POLICY
+               KADM5_POLICY_CLR
+               KADM5_POLICY_NORMAL_MASK
+               KADM5_PRINCIPAL
+               KADM5_PRINCIPAL_NORMAL_MASK
+               KADM5_PRINC_EXPIRE_TIME
+               KADM5_PRIV_ADD
+               KADM5_PRIV_ALL
+               KADM5_PRIV_CPW
+               KADM5_PRIV_DELETE
+               KADM5_PRIV_GET
+               KADM5_PRIV_LIST
+               KADM5_PRIV_MODIFY
+               KADM5_PW_EXPIRATION
+               KADM5_PW_HISTORY_NUM
+               KADM5_PW_MAX_LIFE
+               KADM5_PW_MIN_CLASSES
+               KADM5_PW_MIN_LENGTH
+               KADM5_PW_MIN_LIFE
+               KADM5_REF_COUNT
+               KADM5_STRUCT_VERSION
+               KADM5_TL_DATA
+               KRB5_KDB_DISALLOW_ALL_TIX
+               KRB5_KDB_DISALLOW_DUP_SKEY
+               KRB5_KDB_DISALLOW_FORWARDABLE
+               KRB5_KDB_DISALLOW_POSTDATED
+               KRB5_KDB_DISALLOW_PROXIABLE
+               KRB5_KDB_DISALLOW_RENEWABLE
+               KRB5_KDB_DISALLOW_SVR
+               KRB5_KDB_DISALLOW_TGT_BASED
+               KRB5_KDB_NEW_PRINC
+               KRB5_KDB_PWCHANGE_SERVICE
+               KRB5_KDB_REQUIRES_HW_AUTH
+               KRB5_KDB_REQUIRES_PRE_AUTH
+               KRB5_KDB_REQUIRES_PWCHANGE
+               KRB5_KDB_SUPPORT_DESMD5
+               USE_KADM5_API_VERSION
+              );
+
+$VERSION = '0.01';
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.  If a constant is not found then control is passed
+    # to the AUTOLOAD in AutoLoader.
+
+    my $constname;
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    croak "& not defined" if $constname eq 'constant';
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+       if ($! =~ /Invalid/) {
+           $AutoLoader::AUTOLOAD = $AUTOLOAD;
+           goto &AutoLoader::AUTOLOAD;
+       }
+       else {
+               croak "Your vendor has not defined Heimdal::Kadm5 macro $constname";
+       }
+    }
+    eval "sub $AUTOLOAD { $val } }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Heimdal::Kadm5 $VERSION;
+
+package Heimdal::Kadm5;
+
+# Preloaded methods go here.
+
+package Heimdal::Kadm5::Client;
+@Heimdal::Kadm5::Client::ISA = qw(Heimdal::Kadm5);
+use vars qw($KADMIN_SERVICE);
+
+$KADMIN_SERVICE = 'kadmin/admin';
+
+sub new
+  {
+    my $self = shift;
+    my $class = ref $self || $self;
+    
+    my %opts = @_;
+    my $me = bless \%opts,$class;
+
+    my $client = $me->{'Principal'} or
+          die "[Heimdal::Kadm5] Heimdal::Kadm5::Client::new missing required \'Principal\' parameter"; 
+    my $keytab = $me->{'Keytab'};
+    my $password = $me->{'Password'};
+    warn %opts;
+    eval
+      {
+       $me->{'_handle'} = Heimdal::Kadm5::SHandle->new(\%opts);
+       if ($keytab)
+         {
+           $me->handle->c_init_with_skey($client,$keytab,$KADMIN_SERVICE,0,0);
+         }
+       else 
+         {
+           $me->handle->c_init_with_password($client,$password,$KADMIN_SERVICE,0,0);
+         }
+       $me->{'_privs'} = $me->handle->c_get_privs();
+      };
+
+    if ($@)
+      {
+       my $err = $@;
+       if ($me->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to initialize a Heimdal::Kadm5::Client instance\n";
+       return undef;
+      }
+    $me;
+  }
+
+sub privis { $_[0]->{'_privs'}; }
+
+my %pnames = (
+             KADM5_PRIV_ADD => 'add',
+             KADM5_PRIV_CPW => 'cpw',
+             KADM5_PRIV_DELETE => 'delete',
+             KADM5_PRIV_LIST => 'list',
+             KADM5_PRIV_GET => 'get',
+             KADM5_PRIV_MODIFY => 'modify'
+            );
+
+sub getPriviledges 
+  { 
+    my $mask = $_[0]->privs;
+    my @p;
+    
+    foreach my $bit (keys %pnames) 
+      {
+       push(@p,$pnames{$bit}) if ($mask & $bit);
+      }
+    return (wantarray ? @p : join(',',@p));
+  }
+
+sub handle { $_[0]->{'_handle'}; }
+
+sub makePrincipal
+  {
+    my $principal = Heimdal::Kadm5::Principal->new($_[0]);
+    $principal->setPrincipal($_[1]);
+    $principal;
+  }
+
+sub getPrincipals
+  {
+    my $self = shift;
+    $self->handle->c_get_principals(@_);
+  }
+
+sub getPrincipal
+  {
+    my $self = shift;
+    my $princ = shift;
+    my $mask = shift;
+
+    $mask = (KADM5_PRINCIPAL_NORMAL_MASK()|KADM5_KEY_DATA()) unless $mask;
+    $self->handle->c_get_principal($princ,$mask);
+  }
+
+sub disablePrincipal
+  {
+    my $self = shift;
+    my $name = shift;
+
+    die "[Heimdal::Kadm5] Disable whom" unless $name;
+    
+    eval
+      {
+       my $principal = $self->getPrincipal($name);
+       my $attrs = $principal->getAttributes;
+       $attrs |= Heimdal::Kadm5::KRB5_KDB_DISALLOW_ALL_TIX();
+       $principal->setAttributes($attrs);
+       
+       $self->modifyPrincipal($principal);
+      };
+    if ($@)
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to disable $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub enablePrincipal
+  {
+    my $self = shift;
+    my $name = shift;
+
+    die "[Heimdal::Kadm5] Enable whom" unless $name;
+
+    eval
+      {
+       my $principal = $self->getPrincipal($name);
+       my $attrs = $principal->getAttributes;
+       $attrs &= (~KRB5_KDB_DISALLOW_ALL_TIX());
+       $principal->setAttributes($attrs);
+       
+       $self->modifyPrincipal($principal);
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError})
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to enable $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub modifyPrincipal
+  {
+    my ($self,$principal,$mask) = @_;
+    
+    eval
+      {
+       $self->handle->c_modify_principal($principal,$mask);
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       my $name = $principal->getPrincipal;
+       warn $err;
+       warn "Unable to modify $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub changePassword
+  {
+    my ($self,$name,$password) = @_;
+
+    eval
+      {
+       $self->handle->c_chpass_principal($name,$password);
+       undef $password;
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to change password for $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub createPrincipal
+  {
+    my $self = shift;
+    my $principal = shift;
+    my $password = shift;
+    my $mask = shift;
+    
+    my $name = $principal->getPrincipal;
+    die "[Heimdal::Kadm5] Create whom?" unless $name;
+    
+    eval
+      {
+       $self->handle->c_create_principal($principal,$password,$mask);
+       undef $password;
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to create $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub renamePrincipal
+  {
+    my ($self,$source,$target) = @_;
+
+    eval
+      {
+       $self->handle->c_rename_principal($source,$target);
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to rename $source to $target\n";
+       return undef;
+      }
+    1;
+  }
+
+sub deletePrincipal
+  {
+    my ($self,$name) = @_;
+
+    eval
+      {
+       $self->handle->c_delete_principal($name);
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to delete $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub randKeyPricipal
+  {
+    my ($self,$name) = @_;
+
+    eval
+      {
+       $self->handle->c_randkey_principal($name);
+      };
+    if ($@) 
+      {
+       my $err = $@;
+       if ($self->{RaiseError}) 
+         {
+           die $@;
+         }
+       warn $err;
+       warn "Unable to generate random key for $name\n";
+       return undef;
+      }
+    1;
+  }
+
+sub extractKeytab
+   {
+     my $self = shift;
+     my $principal = shift;
+     my $keytab = shift;
+
+     my $nkeys;
+     eval
+       {
+        $self->handle->c_ext_keytab($principal,$keytab);
+       };
+     if ($@)
+       {
+         my $err = $@;
+        if ($self->{RaiseError}) 
+          {
+            die $err;
+          }
+        warn $err;
+        warn "Unable to extract keytab $keytab\n";
+        return undef
+       }
+     1;
+   }
+
+package Heimdal::Kadm5::Principal;
+@Heimdal::Kadm5::Principal::ISA = qw(Heimdal::Kadm5::SPrincipal);
+
+use POSIX qw(strftime);
+
+sub _sec2date { $_[0] ? strftime "%Y-%m-%d", localtime($_[0]): 'never'; }
+
+sub dump
+  {
+    my $sp = shift;
+    my $io = (shift or \*STDOUT);
+    
+    printf $io "%24s: %s\n", 'Principal',$sp->getPrincipal;
+    printf $io "%24s: %s\n", 'Principal Expires',_sec2date($sp->getPrincExpireTime);
+    printf $io "%24s: %s\n", 'Password Expires',_sec2date($sp->getPwExpiration);
+    printf $io "%24s: %s\n", 'Last Password Change',_sec2date($sp->getLastPwdChange);
+    printf $io "%24s: %d seconds\n", 'Max Ticket Life',$sp->getMaxLife;
+    printf $io "%24s: %d seconds\n", 'Max Renewable Life',$sp->getMaxRenewableLife;
+    my @keys;
+    foreach my $kt (@{$sp->getKeytypes}) 
+      {
+       push(@keys,"$kt->[0] ($kt->[1])");
+      }
+    printf $io "%24s: %s\n\n", 'Keytypes(salts)', join(',',@keys);
+  }
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+package Heimdal::Kadm5;
+
+1;
+__END__
+# Below is the stub of documentation for your module. You better edit it!
+
+=head1 NAME
+
+Heimdal::Kadm5 - Perl extension for adminstration of Heimdal Kerberos servers (kadmin)
+
+=head1 SYNOPSIS
+
+use Heimdal::Kadm5;
+
+$client = Heimdal::Kadm5::Client->new('Client'=>'you/admin@YOUR.REALM',
+                         'Password'=>'eatmyshorts');
+foreach my $name ($client->getPrincipals('*/admin'))
+  {
+     my $principal = $client->getPrincipal($name);
+     $principal->dump;
+  }
+
+=head1 DESCRIPTION
+
+Heimdal::Kadm5 is a basic XSUB perl glue to the Heimdal (http://www.pdc.kth.se/src/heimdal) kadm5clnt
+library. Heimdal is a free, slightly less export challenged implementation of Kerberos5 by Assar
+Westerlund and Johan Danielsson. Heimdal::Kadm5 allows you to perform more administration of your kdc
+than you can usually pull off with the included kadmin program. Heimdal::Kadm5 should be considered
+alpha-code and may consequently crash and burn but should not muck up your kdc any more than kadmin
+itself does.
+
+=head1 OBJECTS
+
+C<Heimdal::Kadm5::Client> represents a client connection (the truly perverse may conspire to write a kadmin
+servlet in perl and put that in C<Heimdal::Kadm5::Server>) to a kadmin server. The main object handled by
+a kadmin server is a C<kadm5_principal_ent_t> (F<kadm5/admin.h>). This type corresponds to the perl class
+C<Heimdal::Kadm5::Principal>. This object is returned by the C<getPrincipal> method of C<Heimdal::Kadm5::Client>
+and can be created (when adding principals to the kdc) using the C<makePrincipal> method of C<Heimdal::Kadm5::Client>.
+Note: B<Do not create Principals directly through C<Heimdal::Kadm5::Principal>>.
+Principals in the traditional sense of the word (i.e things of type C<krb5_principal>) are passed around
+as strings ('name/instance@REALM' or 'name@REALM');
+
+=head1 METHODS
+
+In what follows $principal denotes an instance of Heimdal::Kadm5::Principal, $name denotes a principal
+name, $bitmask denotes an (you guessed it!) integer representing a bitmask, $seconds an integer
+representing seconds since the epoch (time_t value), $client a Heimdal::Kadm5::Client instance. Other
+variables should be even more obvious or are explained in the text.
+
+
+=head2 Heimdal::Kadm5::Client
+
+Minimal use:
+
+my $client = 
+   Heimdal::Kadm5::Client->new(Client=>'you');
+
+This would connect using a password for 'you@DEFREALM'. The password is
+prompted on the active tty.
+
+A more complex example:
+
+my $client = 
+   Heimdal::Kadm5::Client->new(
+                    RaiseErrors => 1,
+                    Server => 'adm.somewhere.net',
+                    Port   => '8899',
+                    # Required: 
+                    Client => 'you/admin',
+                    Realm  => 'OTHER.REALM',
+                    # --- Either ---
+                    Password => 'very secret',
+                    # --- Or ---
+                    Keytab => '$HOME/mysecrec.keytab'
+                   );
+
+Be very careful when using the Password parameter: it implies storing the password in the
+script or reading it from commmand line arguments or through some other means. Only use
+this on secured hosts, never from NFS mounted filesystems, and B<never> using principals
+allowed to perform all operations on the kdc. In this case using a keytable (see 
+L<ktutil(8)> for information on how to create keytabs) is a better way to go.
+
+Normally both the Server, Port and Realm parameters are determined from the kerberos context
+(configuration files, DNS etc etc) but you may need to override them. If you leave out the password
+or set it to undef the client library will prompt you for a password. You must include the
+Client parameter which is usually your admin or root -instance depending on your local
+system of belief. If for some reason the client connection cannot be initialized undef is
+returned and errors are sent to warn unless the RaiseError parameter is set in which case
+all errors are propagated by die.
+
+my @names = $client->getPrincipals($pattern);
+
+The getPrincipals method returns a list of principals matching $pattern which is not a 
+regular expression but rather a glob-like animal. For instance '*/admin@REALM' is an
+ok pattern. The elements of the list are principal names which can be used to obtain
+Heimdal::Kadm5::Principal object using
+
+my $principal = $client->getPrincipal($name);
+
+which returns a Heimdal::Kadm5::Principal object (see the next section for details).
+
+my $principal = $client->makePrincipal($name);
+
+The makePrincipal method takes a principal name and creates an empty Heimdal::Kadm5::Principal 
+object. This is intended for adding principals to the kdc. After creating the principal
+using makePrincipal use the accessor methods in Heimdal::Kadm5::Principal to set values
+before adding the principal using
+
+$client->createPrincipal($principal,$password,$mask);
+
+If $mask is set this value is used to determine which elements of the principal to include 
+in the creation. Normally this value is automatically determined by tracking the uses of 
+the accessor methods in the Heimdal::Kadm5::Principal class.
+
+Modifications to an existing principal is done using this method:
+
+$client->createPrincipal($principal,$mask);
+
+The $mask value works in the same way as described above for createPrincipal. It is sometimes 
+useful to disable (lock) a principal, for instance when several operations must be performed. 
+The following methods can be used:
+
+$client->disablePrincipal($name);
+
+$client->enablePrincipal($name);
+
+Other methods which modify the kdc are and the use of which should be obvious:
+
+$client->changePassword($name, $password);
+
+$client->deletePrincipal($name);
+
+$client->renamePrincipal($name, $newname);
+
+$client->randKeyPrincipal($name);
+
+This method creates a random set of keys for the principal named $name. This is typically
+done for service principals. When creating a new service principal it is probably a good
+idea to create the principal with some initial password, disable the principal, apply the
+randKeyPrincipal method and then enable the principal.
+
+$client->flush();
+
+This method flushes all modifications to the datastore. It is called automatically
+when the client handle is DESTROYed if any modifications (password change, create,
+rename or delete has been performed);
+
+$client->extractKeytab($principal,$keytab);
+
+This method extracts the keys belonging to the principal object to the keytab
+(optionally) specified by the second argument. If the second argument is missing 
+it defaults to the standard default keytab, typically F</etc/krb5.keytab>.
+
+=head2 Heimdal::Kadm5::Principal 
+
+$principal->dump($io);
+
+Dumps a representation of $principal on the $io handle (which defaults to \*STDOUT). 
+This is mostly usable for debugging or simple scripts.
+
+my $name = $principal->getPrincipal();
+$principal->setPrincipal($name);
+
+Gets and sets the principal name.
+
+my $seconds = $principal->getPrincExpireTime();
+$principal->setPrincExpireTime($seconds);
+
+Gets and sets the time this principal expires.
+
+my $seconds = $principal->getLastPwdChange();
+
+Returns the last time this principals password was changed.
+
+my $seconds = $principal->getPwExpiration();
+$principal->setPwExpiration($seconds);
+
+Gets and sets the password expriation time. 
+
+my $seconds = $principal->getMaxLife();
+$principal->setMaxLife($seconds);
+
+Gets and sets the maximum lifetime of a ticket.
+
+my $seconds = $principal->getMaxRenewableLife();
+$principal->setMaxRenewableLife($seconds);
+
+Gets and sets the maximum renewable ticket lifetime.
+
+my $name = $principal->getModName();
+
+Returns the principal name of the last modifier of the entry. Not currently
+(as of heimdal 0.1g) supported by heimdal and contains undef.
+
+my $seconds = $principal->getModDate();
+
+Returns the date of last modification of the entry.
+
+my $policyname = $principal->getPolicy(); 
+
+getPolicy returns undef if no policy is set. Policies are not currently
+supported (as of heimdal 0.1g) and always returns undef.
+
+my $seconds = $principal->getLastSuccess();
+
+Last time a successful authentication was done against this principal.
+
+my $seconds= $principal->getLastFailed();
+
+Last time a failed authentication was done against this principal.
+
+my $nfailed = $principal->getFailAuthCounts();
+
+How many failed login attempts was done against this principal.
+
+my $bitmask = $principal->getAttributes();
+
+my $arrayref = $principal->getKeyTypes();
+
+getKeyTypes returns an array reference consisting of a list of array
+references with two elements each: [keytype,salt]. The keytype and
+salt are strings which describe a key associated with the principal.
+Note that this data may not be present depending on how the principal
+was obtained.
+
+
+=head1 Exported constants
+
+  KADM5_ADMIN_SERVICE
+  KADM5_API_VERSION_1
+  KADM5_API_VERSION_2
+  KADM5_ATTRIBUTES
+  KADM5_AUX_ATTRIBUTES
+  KADM5_CHANGEPW_SERVICE
+  KADM5_CONFIG_ACL_FILE
+  KADM5_CONFIG_ADBNAME
+  KADM5_CONFIG_ADB_LOCKFILE
+  KADM5_CONFIG_ADMIN_KEYTAB
+  KADM5_CONFIG_ADMIN_SERVER
+  KADM5_CONFIG_DBNAME
+  KADM5_CONFIG_DICT_FILE
+  KADM5_CONFIG_ENCTYPE
+  KADM5_CONFIG_ENCTYPES
+  KADM5_CONFIG_EXPIRATION
+  KADM5_CONFIG_FLAGS
+  KADM5_CONFIG_KADMIND_PORT
+  KADM5_CONFIG_MAX_LIFE
+  KADM5_CONFIG_MAX_RLIFE
+  KADM5_CONFIG_MKEY_FROM_KEYBOARD
+  KADM5_CONFIG_MKEY_NAME
+  KADM5_CONFIG_PROFILE
+  KADM5_CONFIG_REALM
+  KADM5_CONFIG_STASH_FILE
+  KADM5_FAIL_AUTH_COUNT
+  KADM5_HIST_PRINCIPAL
+  KADM5_KEY_DATA
+  KADM5_KVNO
+  KADM5_LAST_FAILED
+  KADM5_LAST_PWD_CHANGE
+  KADM5_LAST_SUCCESS
+  KADM5_MAX_LIFE
+  KADM5_MAX_RLIFE
+  KADM5_MKVNO
+  KADM5_MOD_NAME
+  KADM5_MOD_TIME
+  KADM5_POLICY
+  KADM5_POLICY_CLR
+  KADM5_POLICY_NORMAL_MASK
+  KADM5_PRINCIPAL
+  KADM5_PRINCIPAL_NORMAL_MASK
+  KADM5_PRINC_EXPIRE_TIME
+  KADM5_PRIV_ADD
+  KADM5_PRIV_ALL
+  KADM5_PRIV_CPW
+  KADM5_PRIV_DELETE
+  KADM5_PRIV_GET
+  KADM5_PRIV_LIST
+  KADM5_PRIV_MODIFY
+  KADM5_PW_EXPIRATION
+  KADM5_PW_HISTORY_NUM
+  KADM5_PW_MAX_LIFE
+  KADM5_PW_MIN_CLASSES
+  KADM5_PW_MIN_LENGTH
+  KADM5_PW_MIN_LIFE
+  KADM5_REF_COUNT
+  KADM5_STRUCT_VERSION
+  KADM5_TL_DATA
+  KRB5_KDB_DISALLOW_ALL_TIX
+  KRB5_KDB_DISALLOW_DUP_SKEY
+  KRB5_KDB_DISALLOW_FORWARDABLE
+  KRB5_KDB_DISALLOW_POSTDATED
+  KRB5_KDB_DISALLOW_PROXIABLE
+  KRB5_KDB_DISALLOW_RENEWABLE
+  KRB5_KDB_DISALLOW_SVR
+  KRB5_KDB_DISALLOW_TGT_BASED
+  KRB5_KDB_NEW_PRINC
+  KRB5_KDB_PWCHANGE_SERVICE
+  KRB5_KDB_REQUIRES_HW_AUTH
+  KRB5_KDB_REQUIRES_PRE_AUTH
+  KRB5_KDB_REQUIRES_PWCHANGE
+  KRB5_KDB_SUPPORT_DESMD5
+  USE_KADM5_API_VERSION
+
+
+=head1 AUTHOR
+
+Leif Johansson, leifj@matematik.su.se
+
+=head1 SEE ALSO
+
+perl(1).
+
+=cut
diff --git a/Kadm5.xs b/Kadm5.xs
new file mode 100644 (file)
index 0000000..d7982e6
--- /dev/null
+++ b/Kadm5.xs
@@ -0,0 +1,793 @@
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm5_err.h>
+
+#include "consts.h"
+
+typedef struct shandle_t {
+  int modcount;
+  void *ptr;
+  kadm5_config_params params;
+  krb5_context context;
+} shandle_t;
+
+typedef struct sprincipal_t {
+  shandle_t               *handle;
+  int                      mask;
+  kadm5_principal_ent_rec  principal;
+} sprincipal_t;
+
+static sprincipal_t *
+create_sprincipal(shandle_t *handle)
+{
+  sprincipal_t *p = (sprincipal_t *)safemalloc(sizeof(sprincipal_t));
+  
+  memset(p,0,sizeof(*p));
+  p->handle = handle;
+  return p;
+}
+
+static void
+destroy_sprincipal(sprincipal_t *spp)
+{
+  kadm5_free_principal_ent(spp->handle,&spp->principal);
+  safefree(spp);
+}
+
+static shandle_t *
+sv2server_handle(SV *sv)
+{
+  if (SvROK(sv) && sv_isa(sv,"Heimdal::Kadm5::SHandle"))
+    return (shandle_t *)SvIV(SvRV(sv));
+  else
+    croak("Argument to sv2server_handle not referenced in package \"Heimdal::Kadm5::SHandle\"");
+}
+
+static sprincipal_t *
+sv2sprincipal(SV *sv)
+{
+  if (SvROK(sv) && sv_isa(sv,"Heimdal::Kadm5::Principal"))
+    return (sprincipal_t *)SvIV(SvRV(sv));
+  else
+    croak("Argument to sv2kadm5_principal not referenced in package \"Heimdal::Kadm5::Principal\"");
+}
+
+static int
+set_param_strval(HV *hv, char **str, char *key)
+{
+  SV **val = hv_fetch(hv, key, strlen(key), 0);
+  //fprintf(stderr,"%s=\"%s\"\n",key,val != NULL ? SvPV_nolen(*val):"(null)");
+  if (val != NULL)
+    {
+       *str = SvPV_nolen(*val);
+       return 1;
+     }
+  return 0;
+}
+
+static int
+set_param_intval(HV *hv, int *ival, char *key)
+{
+  SV **val = hv_fetch(hv, key, 0, 0);
+  if (val)
+    {
+      *ival = (int)SvIV(*val);
+      return 1;
+    }
+  return 0;
+}
+
+static int
+not_here(s)
+char *s;
+{
+    croak("%s not implemented on this architecture", s);
+    return -1;
+}
+
+MODULE = Heimdal::Kadm5::SHandle               PACKAGE = Heimdal::Kadm5::SHandle               PREFIX=kadm5_
+PROTOTYPES: ENABLE
+
+shandle_t *
+new(self,sv)
+     SV *self
+     SV *sv
+     CODE:
+     {
+       if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)
+       {
+        HV *hv = (HV *)SvRV(sv);
+        shandle_t *handle = (shandle_t *)safemalloc(sizeof(shandle_t));
+        kadm5_ret_t ret;
+        
+        memset(handle,0,sizeof(*handle));
+        ret = krb5_init_context(&handle->context);
+        if (ret)
+        {
+          safefree(handle);
+          croak("[Heimdal::Kadm5] krb5_init_context failed: %s\n",krb5_get_err_text(handle->context, ret));
+          handle = NULL;
+          goto cleanup;
+        }
+       
+        if (set_param_strval(hv,&handle->params.realm,"Realm"))
+        {
+           fprintf(stderr,"Realm=\"%s\"\n",handle->params.realm);
+          krb5_set_default_realm(handle->context, handle->params.realm);
+          handle->params.mask |= KADM5_CONFIG_REALM;
+        }
+        /* set_param_strval(hv,&handle->params.profile,"Profile"); */
+        if (set_param_intval(hv,&handle->params.kadmind_port,"Port"))
+                   handle->params.mask |= KADM5_CONFIG_KADMIND_PORT;
+        if (set_param_strval(hv,&handle->params.admin_server,"Server"))
+           handle->params.mask |= KADM5_CONFIG_ADMIN_SERVER;
+        
+        cleanup:
+        RETVAL = handle;
+       }
+       else
+       {
+         croak("[Heimdal::Kadm5] Argument to \"Heimdal::Kadm5::SHandle::new\" must be a hash-reference");
+        RETVAL = NULL;
+       }
+     }
+     OUTPUT:
+          RETVAL
+
+void
+DESTROY(handle)
+     shandle_t *handle
+     CODE:
+     {
+       if (handle->modcount > 0)
+        {
+          kadm5_c_flush(handle->ptr);
+        }
+       if (handle->ptr)
+          kadm5_c_destroy(handle->ptr);
+       if (handle->context)
+          krb5_free_context(handle->context);
+       safefree(handle);
+     }
+
+void
+kadm5_c_init_with_password (handle, client_name, password, service_name, struct_version, api_version)
+     shandle_t *handle
+     char *client_name
+     char *password
+     char *service_name
+     unsigned long struct_version
+     unsigned long api_version
+     CODE:
+     {
+       kadm5_ret_t ret = kadm5_c_init_with_password_ctx(handle->context,
+                                                       client_name,
+                                                       password,
+                                                       KADM5_ADMIN_SERVICE, 
+                                                       &handle->params,
+                                                       struct_version, 
+                                                       api_version,
+                                                       &handle->ptr);
+       if(ret)
+           croak("[Heimdal::Kadm5] kadm5_c_init_with_password_ctx failed: %s\n",
+                 krb5_get_err_text(handle->context, ret));
+     }
+
+void
+kadm5_c_init_with_skey (handle, client_name, keytab, service_name, struct_version, api_version)
+     shandle_t *handle
+     char *client_name
+     char *keytab
+     char *service_name
+     unsigned long struct_version
+     unsigned long api_version
+     CODE:
+     {
+       kadm5_ret_t ret = kadm5_c_init_with_skey_ctx(handle->context,
+                                                   client_name,
+                                                   keytab,
+                                                   KADM5_ADMIN_SERVICE, 
+                                                   &handle->params,
+                                                   struct_version, 
+                                                   api_version,
+                                                   &handle->ptr);
+       if(ret)
+           croak("[Heimdal::Kadm5] kadm5_c_init_with_skey_ctx failed: %s\n",
+                 krb5_get_err_text(handle->context, ret));
+     }
+
+void
+kadm5_c_flush(handle)
+     shandle_t *handle
+     CODE:
+     {
+       kadm5_ret_t ret = kadm5_c_flush(handle->ptr);
+       if (ret)
+        croak("[Heimdal::Kadm5] kadm5_c_flush failed: %s\n",krb5_get_err_text(handle->context, ret));
+       handle->modcount = 0;
+     }
+
+void
+kadm5_c_modify_principal(handle,spp,mask)
+     shandle_t     *handle
+     sprincipal_t  *spp
+     int            mask
+     CODE:
+     {
+       kadm5_ret_t ret;
+
+       if (mask == 0)
+        mask = spp->mask;
+       ret = kadm5_c_modify_principal(handle->ptr, &spp->principal, mask);
+       if (ret)
+        {
+          if (ret)
+            croak("[Heimdal::Kadm5] kadm5_c_modify_principal failed: %s\n",
+                  krb5_get_err_text(handle->context, ret));
+        }
+       handle->modcount++;
+     }
+
+int
+kadm5_c_randkey_principal(handle,name)
+     shandle_t    *handle
+     char         *name
+     CODE:
+     {
+       krb5_keyblock *new_keys;
+       int n_keys, i;
+       krb5_principal principal;
+       krb5_error_code err;
+       kadm5_ret_t ret;
+
+       err = krb5_parse_name(handle->context, name, &principal);
+       if (err)
+        croak("[Heimdal::Kadm5] krb5_parse_name failed on \"%s\": %s\n",
+              name,krb5_get_err_text(handle->context, err));
+       
+       ret = kadm5_randkey_principal(handle->ptr, principal, &new_keys, &n_keys);
+       if(ret)
+        {
+          krb5_free_principal(handle->context, principal);
+          croak("[Heimdal::Kadm5] kadm5_c_randkey_principal failed: %s\n",
+                krb5_get_err_text(handle->context, ret));
+        }
+       for(i = 0; i < n_keys; i++)
+        krb5_free_keyblock_contents(handle->context, &new_keys[i]);
+       free(new_keys);
+       krb5_free_principal(handle->context, principal);
+       handle->modcount++;
+       RETVAL = n_keys;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+kadm5_c_chpass_principal(handle,name,password)
+     shandle_t   *handle
+     char        *name
+     char        *password
+     CODE:
+     {
+       kadm5_ret_t ret;
+       krb5_error_code ret2;
+       krb5_principal principal;
+       
+       ret2 = krb5_parse_name(handle->context, name, &principal);
+       if (ret2)
+        croak("[Heimdal::Kadm5] krb5_parse_name failed on \"%s\": %s\n",
+              name,krb5_get_err_text(handle->context, ret2));
+       
+       ret = kadm5_c_chpass_principal(handle->ptr,principal,password);
+       if (ret)
+        croak("[Heimdal::Kadm5] kadm5_c_chpass_principal failed on \"%s\": %s\n",
+              name,krb5_get_err_text(handle->context, ret));
+       handle->modcount++;
+     }
+
+void
+kadm5_c_create_principal(handle,spp,password,mask)
+     shandle_t    *handle
+     sprincipal_t *spp
+     char         *password
+     int           mask
+     CODE:
+     {
+       kadm5_ret_t ret;
+
+       if (mask == 0)
+        mask = spp->mask;
+       
+       ret = kadm5_c_create_principal(handle->ptr,&spp->principal,mask,password);
+       if (ret)
+        {
+          char *p;
+          krb5_error_code ret2;
+          
+          ret2 = krb5_unparse_name(handle->context,spp->principal.principal,&p);
+          if (ret2)
+            {
+              safefree(p);
+              croak("[Heimdal::Kadm5] krb5_unparse_name failed: %s\n",
+                    krb5_get_err_text(spp->handle->context, ret2));
+            }
+          croak("[Heimdal::Kadm5] krb5_c_create_principal failed on \"%s\": %s\n",
+                p,krb5_get_err_text(handle->context, ret));
+        }
+       handle->modcount++;
+     }
+
+void
+kadm5_c_rename_principal(handle, src, trg)
+     shandle_t   *handle
+     char        *src
+     char        *trg
+     CODE:
+     {
+       krb5_error_code ret;
+       krb5_principal source, target;
+       kadm5_ret_t err;
+
+       ret = krb5_parse_name(handle->context, src, &source);
+       if (ret)
+        {
+          croak("[Heimdal::Kadm5] krb5_parse_name failed on \"%s\": %s\n",
+                src,krb5_get_err_text(handle->context, ret));
+        }
+       
+       ret = krb5_parse_name(handle->context, trg, &target);
+       if (ret)
+        {
+          krb5_free_principal(handle->context, target);
+          croak("[Heimdal::Kadm5] krb5_parse_name failed on \"%s\": %s\n",
+                trg,krb5_get_err_text(handle->context, ret));
+        }
+       
+       err = kadm5_c_rename_principal(handle->ptr, source, target);
+       if (err)
+        {
+          krb5_free_principal(handle->context, source);
+          krb5_free_principal(handle->context, target);
+          croak("[Heimdal::Kadm5] kadm5_rename_principal \"%s\" to \"%s\" failed: %s\n",
+                src,trg,krb5_get_err_text(handle->context, err));
+        }
+       krb5_free_principal(handle->context, source);
+       krb5_free_principal(handle->context, target);
+       handle->modcount++;
+     }
+
+void
+kadm5_c_delete_principal(handle,name)
+     shandle_t   *handle
+     char        *name
+     CODE:
+     {
+       krb5_error_code ret;
+       krb5_principal principal;
+       kadm5_ret_t err;
+       
+       ret = krb5_parse_name(handle->context, name, &principal);
+       if (ret)
+        croak("[Heimdal::Kadm5] krb5_parse_name failed on \"%s\": %s\n",
+              name,krb5_get_err_text(handle->context, ret));
+       
+       err = kadm5_c_delete_principal(handle->ptr,principal);
+       if (err)
+        {
+          krb5_free_principal(handle->context, principal);
+          croak("[Heimdal::Kadm5] kadm5_c_delete_principal failed for \"%s\": %s\n",
+                name,krb5_get_err_text(handle->context, err));
+        }
+       handle->modcount++;
+       krb5_free_principal(handle->context, principal);
+     }
+
+
+sprincipal_t *
+kadm5_c_get_principal(handle, name, mask)
+     shandle_t *handle
+     char      *name
+     IV         mask
+     CODE:
+     {
+       krb5_principal principal;
+       krb5_error_code ret;
+       sprincipal_t *spp;
+       
+       ret = krb5_parse_name(handle->context, name, &principal);
+       if (ret)
+        croak("[Heimdal::Kadm5] krb5_parse_name failed on \"%s\": %s\n",
+              name,krb5_get_err_text(handle->context, ret));
+       
+       spp = create_sprincipal(handle);
+       ret = kadm5_c_get_principal(handle->ptr,
+                                  principal,
+                                  &spp->principal,
+                                  mask);
+       if (ret)
+        {
+           if (ret == KADM5_UNK_PRINC) {
+              destroy_sprincipal(spp); 
+              spp = NULL;
+           } else {
+             krb5_free_principal(handle->context, principal);
+              destroy_sprincipal(spp); 
+             croak("[Heimdal::Kadm5] kadm5_c_get_principal failed for \"%s\": %s\n",
+                   name,krb5_get_err_text(handle->context, ret));
+           }
+        }
+       krb5_free_principal(handle->context,principal);
+       RETVAL = spp;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+kadm5_c_get_principals(handle,exp)
+     shandle_t *handle
+     char      *exp
+     PPCODE:
+     {
+       char **princs;
+       int num_princs,i;
+       kadm5_ret_t ret;
+
+       ret = kadm5_c_get_principals(handle->ptr,exp,&princs,&num_princs);
+       if (ret)
+        {
+          croak("[Heimdal::Kadm5] kadm5_c_get_principals failed for \"%s\": %s\n",
+                exp,krb5_get_err_text(handle->context, ret));
+        }
+       EXTEND(SP,num_princs);
+       for (i = 0; i < num_princs; i++)
+        {
+          PUSHs(sv_2mortal(newSVpv(princs[i],0)));
+        }
+       kadm5_free_name_list(handle->ptr,princs,&num_princs);
+     }
+
+int
+kadm5_c_get_privs(handle)
+     shandle_t *handle
+     CODE:
+     {
+       int privs;
+       kadm5_ret_t ret = kadm5_c_get_privs(handle->ptr,&privs);
+       if (ret)
+        {
+          croak("[Heimdal::Kadm5] kadm5_c_get_privs failed: %s\n",
+                krb5_get_err_text(handle->context, ret));
+        }
+       RETVAL = privs;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+kadm5_c_ext_keytab(handle,spp,keytab)
+     shandle_t   *handle
+     sprincipal_t *spp
+     char        *keytab
+     CODE:
+     {
+       int i;
+       krb5_keytab kt;
+       krb5_error_code ret;
+       
+       if(keytab)
+        ret = krb5_kt_resolve(handle->context, keytab, &kt);
+       else
+        ret = krb5_kt_default(handle->context, &kt);
+       
+       if (ret)
+        croak("[Heimdal::Kadm5] krb5_kt_resolv failed: %s\n",
+              krb5_get_err_text(handle->context, ret));
+       
+       for(i = 0; i < spp->principal.n_key_data; i++)
+        {
+          krb5_keytab_entry key;
+          krb5_key_data *k = &spp->principal.key_data[i];
+          
+          key.principal = spp->principal.principal;
+          key.vno = k->key_data_kvno;
+          key.keyblock.keytype = k->key_data_type[0];
+          key.keyblock.keyvalue.length = k->key_data_length[0];
+          key.keyblock.keyvalue.data = k->key_data_contents[0];
+          ret = krb5_kt_add_entry(handle->context, kt, &key);
+          if (ret)
+            croak("[Heimdal::Kadm5] krb5_kt_add_entry failed: %s\n",
+                  krb5_get_err_text(handle->context, ret));
+        }
+       
+       krb5_kt_close(handle->context, kt);
+     }
+
+MODULE = Heimdal::Kadm5::Principal         PACKAGE = Heimdal::Kadm5::Principal
+
+sprincipal_t *
+new(handle,name)
+     shandle_t *handle
+     char      *name
+     CODE: 
+     {
+       sprincipal_t *spp = create_sprincipal(handle);
+       RETVAL = spp;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+DESTROY(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       destroy_sprincipal(spp);
+     }
+
+SV *
+getPrincipal(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       char *p;
+       krb5_error_code ret;
+       
+       ret = krb5_unparse_name(spp->handle->context,spp->principal.principal,&p);
+       if (ret)
+        {
+          safefree(p);
+          croak("[Heimdal::Kadm5] krb5_unparse_name failed: %s\n",
+                krb5_get_err_text(spp->handle->context, ret));
+        }
+       RETVAL = newSVpv(p,0);
+     }
+     OUTPUT:
+     RETVAL
+
+void
+setPrincipal(spp,p)
+     sprincipal_t *spp
+     char         *p
+     CODE:
+     {
+       krb5_error_code ret;
+       
+       ret = krb5_parse_name(spp->handle->context,p,&spp->principal.principal);
+       if (ret)
+        {
+          croak("[Heimdal::Kadm5] krb5_parse_name failed for \"%s\": %s\n",
+                p,krb5_get_err_text(spp->handle->context, ret));
+        }
+       spp->mask |= KADM5_PRINCIPAL;
+     }
+
+int
+getPrincExpireTime(spp)
+     sprincipal_t *spp
+     PPCODE:
+     {
+       XPUSHi(spp->principal.princ_expire_time);
+     }
+
+void
+setPrincExpireTime(spp,val)
+     sprincipal_t *spp
+     IV            val
+     CODE:
+     {
+       spp->principal.princ_expire_time = val;
+       spp->mask |= KADM5_PRINC_EXPIRE_TIME;
+     }
+
+IV
+getLastPwdChange(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.last_pwd_change;
+     }
+     OUTPUT:
+     RETVAL
+
+IV
+getPwExpiration(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.pw_expiration;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+setPwExpiration(spp,val)
+     sprincipal_t *spp
+     IV            val
+     CODE:
+     {
+       spp->principal.pw_expiration = val;
+       spp->mask |= KADM5_PW_EXPIRATION;
+     }
+
+IV
+getMaxLife(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.max_life;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+setMaxLife(spp,val)
+     sprincipal_t *spp
+     IV            val
+     CODE:
+     {
+       spp->principal.max_life = val;
+       spp->mask |= KADM5_MAX_LIFE;
+     }
+
+SV *
+getModName(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       char *p;
+       krb5_error_code ret;
+       
+       ret = krb5_unparse_name(spp->handle->context,spp->principal.mod_name,&p);
+       if (ret)
+        {
+          safefree(p);
+          croak("[Heimdal::Kadm5] krb5_unparse_name failed: %s\n",
+                krb5_get_err_text(spp->handle->context, ret));
+        }
+       RETVAL = newSVpv(p,0);
+     }
+     OUTPUT:
+     RETVAL
+
+IV
+getModDate(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.mod_date;
+     }
+     OUTPUT:
+     RETVAL
+
+SV *
+getPolicy(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       if (spp->principal.policy)
+        RETVAL = newSVpv(spp->principal.policy,0);
+       else
+        RETVAL = &PL_sv_undef;
+     }
+     OUTPUT:
+     RETVAL
+
+IV
+getMaxRenewableLife(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.max_renewable_life;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+setMaxRenewableLife(spp,val)
+     sprincipal_t *spp
+     IV            val
+     CODE:
+     {
+       spp->principal.max_renewable_life = val;
+       spp->mask |= KADM5_MAX_RLIFE;
+     }
+
+IV
+getLastSuccess(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.last_success;
+     }
+     OUTPUT:
+     RETVAL
+
+IV
+getLastFailed(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.last_failed;
+     }
+     OUTPUT:
+     RETVAL
+
+IV
+getFailAuthCount(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.fail_auth_count;
+     }
+     OUTPUT:
+     RETVAL
+
+IV
+getAttributes(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       RETVAL = spp->principal.attributes;
+     }
+     OUTPUT:
+     RETVAL
+
+void
+setAttributes(spp,val)
+     sprincipal_t *spp
+     IV            val
+     CODE:
+     {
+       spp->principal.attributes = val;
+       spp->mask |= KADM5_ATTRIBUTES;
+     }
+
+SV *
+getKeytypes(spp)
+     sprincipal_t *spp
+     CODE:
+     {
+       int i;
+       AV *lst = newAV();
+       
+       for (i = 0; i < spp->principal.n_key_data; ++i) 
+        {
+          krb5_key_data *k = &spp->principal.key_data[i];
+          krb5_error_code ret;
+          char *e_string, *s_string;
+          SV *ksv[2];
+          
+          ret = krb5_enctype_to_string (spp->handle->context,
+                                        k->key_data_type[0],
+                                        &e_string);
+          if (ret)
+            asprintf (&e_string, "unknown(%d)", k->key_data_type[0]);
+          ksv[0] = newSVpv(e_string,0);
+          
+          ret = krb5_salttype_to_string (spp->handle->context,
+                                         k->key_data_type[0],
+                                         k->key_data_type[1],
+                                         &s_string);
+          if (ret)
+            asprintf (&s_string, "unknown(%d)", k->key_data_type[1]);
+          ksv[1] = newSVpv(s_string,0);
+          
+          av_push(lst,newRV_inc((SV *)av_make(2,ksv)));
+          free (e_string);
+          free (s_string);
+        }
+       RETVAL = newRV_inc((SV *)lst);
+     }
+     OUTPUT:
+     RETVAL
+
+MODULE = Heimdal::Kadm5                    PACKAGE = Heimdal::Kadm5
+
+double
+constant(name,arg)
+        char *          name
+        int             arg
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..92fa406
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,7 @@
+Changes
+Kadm5.pm
+Kadm5.xs
+Makefile.PL
+MANIFEST
+README
+test.pl
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..8df872a
--- /dev/null
@@ -0,0 +1,16 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+    'NAME'             => 'Heimdal::Kadm5',
+    'VERSION_FROM'     => 'Kadm5.pm', # finds $VERSION
+    'PREREQ_PM'                => {}, # e.g., Module::Name => 1.1
+    ($] >= 5.005 ?    ## Add these new keywords supported since 5.005
+      (ABSTRACT_FROM => 'Kadm5.pm', # retrieve abstract from module
+       AUTHOR     => 'A. U. Thor <a.u.thor@a.galaxy.far.far.away>') : ()),
+    'LIBS'      => ['-lresolv -L/pkg/heimdal/default/lib -lkrb5 -lroken -lasn1 -lkadm5clnt'],   # e.g., '-lm'
+    'INC'       => '-I/pkg/heimdal/default/include',     # e.g., '-I/usr/include/other'
+    'DEFINE'           => '', # e.g., '-DHAVE_SOMETHING'
+       # Insert -I. if you add *.h files later:
+    # 'OBJECT'         => '$(O_FILES)', # link all the C files too
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..361b57c
--- /dev/null
+++ b/README
@@ -0,0 +1,35 @@
+Heimdal/Kadm5 version 0.01
+==========================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+  blah blah blah
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2003 A. U. Thor blah blah blah
+
diff --git a/consts.h b/consts.h
new file mode 100644 (file)
index 0000000..e72fca5
--- /dev/null
+++ b/consts.h
@@ -0,0 +1,495 @@
+
+static double
+constant(name, arg)
+char *name;
+int arg;
+{
+    errno = 0;
+    switch (*name) {
+    case 'A':
+       break;
+    case 'B':
+       break;
+    case 'C':
+       break;
+    case 'D':
+       break;
+    case 'E':
+       break;
+    case 'F':
+       break;
+    case 'G':
+       break;
+    case 'H':
+       break;
+    case 'I':
+       break;
+    case 'J':
+       break;
+    case 'K':
+      if (strEQ(name, "KRB5_KDB_DISALLOW_ALL_TIX"))
+#ifdef KRB5_KDB_DISALLOW_ALL_TIX
+       return KRB5_KDB_DISALLOW_ALL_TIX;
+#else
+        goto not_there;
+#endif
+      if (strEQ(name, "KADM5_API_VERSION_1"))
+#ifdef KADM5_API_VERSION_1
+           return KADM5_API_VERSION_1;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_API_VERSION_2"))
+#ifdef KADM5_API_VERSION_2
+           return KADM5_API_VERSION_2;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_ATTRIBUTES"))
+#ifdef KADM5_ATTRIBUTES
+           return KADM5_ATTRIBUTES;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_AUX_ATTRIBUTES"))
+#ifdef KADM5_AUX_ATTRIBUTES
+           return KADM5_AUX_ATTRIBUTES;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ACL_FILE"))
+#ifdef KADM5_CONFIG_ACL_FILE
+           return KADM5_CONFIG_ACL_FILE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ADBNAME"))
+#ifdef KADM5_CONFIG_ADBNAME
+           return KADM5_CONFIG_ADBNAME;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ADB_LOCKFILE"))
+#ifdef KADM5_CONFIG_ADB_LOCKFILE
+           return KADM5_CONFIG_ADB_LOCKFILE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ADMIN_KEYTAB"))
+#ifdef KADM5_CONFIG_ADMIN_KEYTAB
+           return KADM5_CONFIG_ADMIN_KEYTAB;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ADMIN_SERVER"))
+#ifdef KADM5_CONFIG_ADMIN_SERVER
+           return KADM5_CONFIG_ADMIN_SERVER;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_DBNAME"))
+#ifdef KADM5_CONFIG_DBNAME
+           return KADM5_CONFIG_DBNAME;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_DICT_FILE"))
+#ifdef KADM5_CONFIG_DICT_FILE
+           return KADM5_CONFIG_DICT_FILE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ENCTYPE"))
+#ifdef KADM5_CONFIG_ENCTYPE
+           return KADM5_CONFIG_ENCTYPE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_ENCTYPES"))
+#ifdef KADM5_CONFIG_ENCTYPES
+           return KADM5_CONFIG_ENCTYPES;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_EXPIRATION"))
+#ifdef KADM5_CONFIG_EXPIRATION
+           return KADM5_CONFIG_EXPIRATION;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_FLAGS"))
+#ifdef KADM5_CONFIG_FLAGS
+           return KADM5_CONFIG_FLAGS;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_KADMIND_PORT"))
+#ifdef KADM5_CONFIG_KADMIND_PORT
+           return KADM5_CONFIG_KADMIND_PORT;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_MAX_LIFE"))
+#ifdef KADM5_CONFIG_MAX_LIFE
+           return KADM5_CONFIG_MAX_LIFE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_MAX_RLIFE"))
+#ifdef KADM5_CONFIG_MAX_RLIFE
+           return KADM5_CONFIG_MAX_RLIFE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_MKEY_FROM_KEYBOARD"))
+#ifdef KADM5_CONFIG_MKEY_FROM_KEYBOARD
+           return KADM5_CONFIG_MKEY_FROM_KEYBOARD;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_MKEY_NAME"))
+#ifdef KADM5_CONFIG_MKEY_NAME
+           return KADM5_CONFIG_MKEY_NAME;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_PROFILE"))
+#ifdef KADM5_CONFIG_PROFILE
+           return KADM5_CONFIG_PROFILE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_REALM"))
+#ifdef KADM5_CONFIG_REALM
+           return KADM5_CONFIG_REALM;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_CONFIG_STASH_FILE"))
+#ifdef KADM5_CONFIG_STASH_FILE
+           return KADM5_CONFIG_STASH_FILE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_FAIL_AUTH_COUNT"))
+#ifdef KADM5_FAIL_AUTH_COUNT
+           return KADM5_FAIL_AUTH_COUNT;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_KEY_DATA"))
+#ifdef KADM5_KEY_DATA
+           return KADM5_KEY_DATA;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_KVNO"))
+#ifdef KADM5_KVNO
+           return KADM5_KVNO;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_LAST_FAILED"))
+#ifdef KADM5_LAST_FAILED
+           return KADM5_LAST_FAILED;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_LAST_PWD_CHANGE"))
+#ifdef KADM5_LAST_PWD_CHANGE
+           return KADM5_LAST_PWD_CHANGE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_LAST_SUCCESS"))
+#ifdef KADM5_LAST_SUCCESS
+           return KADM5_LAST_SUCCESS;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_MAX_LIFE"))
+#ifdef KADM5_MAX_LIFE
+           return KADM5_MAX_LIFE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_MAX_RLIFE"))
+#ifdef KADM5_MAX_RLIFE
+           return KADM5_MAX_RLIFE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_MKVNO"))
+#ifdef KADM5_MKVNO
+           return KADM5_MKVNO;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_MOD_NAME"))
+#ifdef KADM5_MOD_NAME
+           return KADM5_MOD_NAME;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_MOD_TIME"))
+#ifdef KADM5_MOD_TIME
+           return KADM5_MOD_TIME;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_POLICY"))
+#ifdef KADM5_POLICY
+           return KADM5_POLICY;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_POLICY_CLR"))
+#ifdef KADM5_POLICY_CLR
+           return KADM5_POLICY_CLR;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_POLICY_NORMAL_MASK"))
+#ifdef KADM5_POLICY_NORMAL_MASK
+           return KADM5_POLICY_NORMAL_MASK;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRINCIPAL"))
+#ifdef KADM5_PRINCIPAL
+           return KADM5_PRINCIPAL;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRINCIPAL_NORMAL_MASK"))
+#ifdef KADM5_PRINCIPAL_NORMAL_MASK
+           return KADM5_PRINCIPAL_NORMAL_MASK;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRINC_EXPIRE_TIME"))
+#ifdef KADM5_PRINC_EXPIRE_TIME
+           return KADM5_PRINC_EXPIRE_TIME;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_ADD"))
+#ifdef KADM5_PRIV_ADD
+           return KADM5_PRIV_ADD;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_ALL"))
+#ifdef KADM5_PRIV_ALL
+           return KADM5_PRIV_ALL;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_CPW"))
+#ifdef KADM5_PRIV_CPW
+           return KADM5_PRIV_CPW;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_DELETE"))
+#ifdef KADM5_PRIV_DELETE
+           return KADM5_PRIV_DELETE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_GET"))
+#ifdef KADM5_PRIV_GET
+           return KADM5_PRIV_GET;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_LIST"))
+#ifdef KADM5_PRIV_LIST
+           return KADM5_PRIV_LIST;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PRIV_MODIFY"))
+#ifdef KADM5_PRIV_MODIFY
+           return KADM5_PRIV_MODIFY;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PW_EXPIRATION"))
+#ifdef KADM5_PW_EXPIRATION
+           return KADM5_PW_EXPIRATION;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PW_HISTORY_NUM"))
+#ifdef KADM5_PW_HISTORY_NUM
+           return KADM5_PW_HISTORY_NUM;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PW_MAX_LIFE"))
+#ifdef KADM5_PW_MAX_LIFE
+           return KADM5_PW_MAX_LIFE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PW_MIN_CLASSES"))
+#ifdef KADM5_PW_MIN_CLASSES
+           return KADM5_PW_MIN_CLASSES;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PW_MIN_LENGTH"))
+#ifdef KADM5_PW_MIN_LENGTH
+           return KADM5_PW_MIN_LENGTH;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_PW_MIN_LIFE"))
+#ifdef KADM5_PW_MIN_LIFE
+           return KADM5_PW_MIN_LIFE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_REF_COUNT"))
+#ifdef KADM5_REF_COUNT
+           return KADM5_REF_COUNT;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_STRUCT_VERSION"))
+#ifdef KADM5_STRUCT_VERSION
+           return KADM5_STRUCT_VERSION;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KADM5_TL_DATA"))
+#ifdef KADM5_TL_DATA
+           return KADM5_TL_DATA;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_ALL_TIX"))
+#ifdef KRB5_KDB_DISALLOW_ALL_TIX
+           return KRB5_KDB_DISALLOW_ALL_TIX;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_DUP_SKEY"))
+#ifdef KRB5_KDB_DISALLOW_DUP_SKEY
+           return KRB5_KDB_DISALLOW_DUP_SKEY;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_FORWARDABLE"))
+#ifdef KRB5_KDB_DISALLOW_FORWARDABLE
+           return KRB5_KDB_DISALLOW_FORWARDABLE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_POSTDATED"))
+#ifdef KRB5_KDB_DISALLOW_POSTDATED
+           return KRB5_KDB_DISALLOW_POSTDATED;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_PROXIABLE"))
+#ifdef KRB5_KDB_DISALLOW_PROXIABLE
+           return KRB5_KDB_DISALLOW_PROXIABLE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_RENEWABLE"))
+#ifdef KRB5_KDB_DISALLOW_RENEWABLE
+           return KRB5_KDB_DISALLOW_RENEWABLE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_SVR"))
+#ifdef KRB5_KDB_DISALLOW_SVR
+           return KRB5_KDB_DISALLOW_SVR;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_DISALLOW_TGT_BASED"))
+#ifdef KRB5_KDB_DISALLOW_TGT_BASED
+           return KRB5_KDB_DISALLOW_TGT_BASED;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_NEW_PRINC"))
+#ifdef KRB5_KDB_NEW_PRINC
+           return KRB5_KDB_NEW_PRINC;
+#else
+           goto not_there;
+#endif
+
+       if (strEQ(name, "KRB5_KDB_REQUIRES_HW_AUTH"))
+#ifdef KRB5_KDB_REQUIRES_HW_AUTH
+           return KRB5_KDB_REQUIRES_HW_AUTH;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_REQUIRES_PRE_AUTH"))
+#ifdef KRB5_KDB_REQUIRES_PRE_AUTH
+           return KRB5_KDB_REQUIRES_PRE_AUTH;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_REQUIRES_PWCHANGE"))
+#ifdef KRB5_KDB_REQUIRES_PWCHANGE
+           return KRB5_KDB_REQUIRES_PWCHANGE;
+#else
+           goto not_there;
+#endif
+       if (strEQ(name, "KRB5_KDB_SUPPORT_DESMD5"))
+#ifdef KRB5_KDB_SUPPORT_DESMD5
+           return KRB5_KDB_SUPPORT_DESMD5;
+#else
+           goto not_there;
+#endif
+       break;
+    case 'L':
+       break;
+    case 'M':
+       break;
+    case 'N':
+       break;
+    case 'O':
+       break;
+    case 'P':
+       break;
+    case 'Q':
+       break;
+    case 'R':
+       break;
+    case 'S':
+       break;
+    case 'T':
+       break;
+    case 'U':
+       if (strEQ(name, "USE_KADM5_API_VERSION"))
+#ifdef USE_KADM5_API_VERSION
+           return USE_KADM5_API_VERSION;
+#else
+           goto not_there;
+#endif
+       break;
+    case 'V':
+       break;
+    case 'W':
+       break;
+    case 'X':
+       break;
+    case 'Y':
+       break;
+    case 'Z':
+       break;
+    }
+    errno = EINVAL;
+    return 0;
+
+not_there:
+    errno = ENOENT;
+    return 0;
+}
diff --git a/test.pl b/test.pl
new file mode 100644 (file)
index 0000000..750c084
--- /dev/null
+++ b/test.pl
@@ -0,0 +1,56 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1; print "0..4\n"; }
+END {print "not ok 1\n" unless $loaded;}
+#use lib './blib/lib';
+use Heimdal::Kadm5  qw(/KADM5_/);
+$loaded = 1;
+
+print "ok 0\n";
+
+my $mask = KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA;
+print "ok 1\n";
+
+$client = Heimdal::Kadm5::Client->new(Server=>'localhost',Realm=>'EXAMPLE.COM',Principal=>'admin/admin@EXAMPLE.COM');
+print "ok 2\n";
+
+while (1) {
+my $princ = $client->getPrincipal('leifj@EXAMPLE.COM');
+print "ok 4\n";
+}
+warn $princ->getPrincipal;
+warn $princ->getLastPwdChange;
+my $hoho = $princ->getPolicy();
+print $hoho if defined $hoho;
+warn $princ->getLastSuccess;
+warn $princ->getLastFailed;
+warn $princ->getMaxRenewableLife;
+warn $princ->getFailAuthCount;
+for my $ks (@{$princ->getKeytypes}) 
+  {
+    print "Keytype: $ks->[0]\n";
+    print "Salt: $ks->[1]\n";
+  }
+
+#for my $name ($client->getPrincipals('*/admin')) 
+#  {
+#    my $princ = $client->getPrincipal($name);
+#    warn $princ->getPrincipal;
+#  }
+#$princ = $client->getPrincipal('host/njal.matematik.su.se');
+#$client->extractKeytab($princ,'/tmp/trurl.keytab');
+
+
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
diff --git a/typemap b/typemap
new file mode 100644 (file)
index 0000000..82e2388
--- /dev/null
+++ b/typemap
@@ -0,0 +1,20 @@
+TYPEMAP
+
+shandle_t                  * T_shandle_t
+sprincipal_t              * T_sprincipal_t
+
+INPUT
+
+T_shandle_t
+       $var = sv2server_handle($arg)
+
+T_sprincipal_t
+       $var = sv2sprincipal($arg)
+
+OUTPUT
+
+T_shandle_t    
+       sv_setref_pv($arg, \"Heimdal::Kadm5::SHandle\", (void *)$var);
+
+T_sprincipal_t
+       sv_setref_pv($arg, \"Heimdal::Kadm5::Principal\", (void *)$var);