#!/usr/bin/perl -w
#
# Tests for basic k5start functionality.
#
# Written by Russ Allbery <eagle@eyrie.org>
# Copyright 2021 Russ Allbery <eagle@eyrie.org>
# Copyright 2008-2010
#     The Board of Trustees of the Leland Stanford Junior University
#
# SPDX-License-Identifier: MIT

use Test::More;

# The full path to the newly-built k5start client.
our $K5START = "$ENV{C_TAP_BUILD}/../commands/k5start";

# The path to our data directory, which contains the keytab to use to test.
our $DATA = "$ENV{C_TAP_BUILD}/data";

# Load our test utility programs.
require "$ENV{C_TAP_SOURCE}/libtest.pl";

# Decide whether we have the configuration to run the tests.
if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") {
    plan tests => 34;
} else {
    plan skip_all => "no keytab configuration";
    exit 0;
}
my $principal = contents ("$DATA/test.principal");

# We have to generate a local krb5.conf that gets forwardable and
# proxiable tickets by default.  Try to locate the local krb5.conf that
# we're supposed to use and bail if we can't find one.
my $krb5conf = $ENV{KRB5_CONFIG};
unless ($krb5conf) {
    for my $path ('/etc', '/usr/local/etc', "$ENV{C_TAP_BUILD}/data") {
        if (-r "$path/krb5.conf") {
            $krb5conf = "$path/krb5.conf";
            last;
        }
    }
}
if ($krb5conf) {
    open (CONF, '<', $krb5conf) or BAIL_OUT ("cannot open $krb5conf: $!");
    open (NEWCONF, '>', './krb5.conf')
        or BAIL_OUT ("cannot create krb5.conf: $!");
    print NEWCONF <CONF>;
    close CONF;
    print NEWCONF "\n";
    print NEWCONF "[libdefaults]\n";
    print NEWCONF "    forwardable = true\n";
    print NEWCONF "    proxiable   = true\n";
    close NEWCONF;
    $ENV{KRB5_CONFIG} = './krb5.conf';
} else {
    BAIL_OUT ("no krb5.conf found, set KRB5_CONFIG");
}

# Don't overwrite the user's ticket cache.
$ENV{KRB5CCNAME} = 'krb5cc_test';

# Basic authentication test with forwardable and proxiable tickets.
unlink 'krb5cc_test';
my ($out, $err, $status)
    = command ($K5START, '-f', "$DATA/test.keytab", $principal);
is ($status, 0, 'Basic k5start command succeeds');
is ($err, '', ' with no errors');
like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/,
      ' and the right output');
my ($default, $service, $flags) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
like ($flags, qr/F/, ' and has forwardable tickets');
like ($flags, qr/P/, ' and has proxiable tickets');

# Authentication without proxiable tickets.
unlink 'krb5cc_test';
($out, $err, $status)
    = command ($K5START, '-Pf', "$DATA/test.keytab", $principal);
is ($status, 0, 'k5start -P command succeeds');
is ($err, '', ' with no errors');
like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/,
      ' and the right output');
($default, $service, $flags) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
like ($flags, qr/F/, ' and has forwardable tickets');
unlike ($flags, qr/P/, ' but not proxiable tickets');

# Authentication without forwardable tickets.
unlink 'krb5cc_test';
($out, $err, $status)
    = command ($K5START, '-F', '-f', "$DATA/test.keytab", $principal);
is ($status, 0, 'k5start -F command succeeds');
is ($err, '', ' with no errors');
like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/,
      ' and the right output');
($default, $service, $flags) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
like ($flags, qr/P/, ' and has proxiable tickets');
unlike ($flags, qr/F/, ' but not forwardable tickets');

# Authentication with both flags flag.
unlink 'krb5cc_test';
($out, $err, $status)
    = command ($K5START, '-FPf', "$DATA/test.keytab", $principal);
is ($status, 0, 'k5start -F -P command succeeds');
is ($err, '', ' with no errors');
like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/,
      ' and the right output');
($default, $service, $flags) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
unlike ($flags, qr/P/, ' but not proxiable tickets');
unlike ($flags, qr/F/, ' and not forwardable tickets');

# Test -k with a fully-qualified ticket cache name.
unlink 'krb5cc_test', 'krb5cc_test2';
($out, $err, $status)
    = command ($K5START, '-k', 'FILE:krb5cc_test2', '-f',
               "$DATA/test.keytab", $principal);
is ($status, 0, 'k5start -k command with file succeeds');
is ($err, '', ' with no errors');
like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/,
      ' and the right output');
ok (!-f 'krb5cc_test', ' and does not use KRB5CCNAME');
$ENV{KRB5CCNAME} = 'krb5cc_test2';
($default, $service, $flags) = klist ();
like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal');
like ($service, qr%^krbtgt/%, ' and the right service');
$ENV{KRB5CCNAME} = 'krb5cc_test';
unlink 'krb5cc_test2';

# Clean up.
unlink 'krb5cc_test', 'krb5.conf';
