#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
use common::sense;

use File::Basename;
use lib dirname(__FILE__) . '/../../../lib/perl';
use OVH::Result;
use OVH::Bastion;
use OVH::Bastion::Plugin qw( :DEFAULT help );

my %modify;
my $remainingOptions = OVH::Bastion::Plugin::begin(
    argv    => \@ARGV,
    header  => "modify the configuration of an account",
    options => {
        "account=s"                         => \my $account,
        "mfa-password-required=s"           => \$modify{'mfa-password-required'},
        "mfa-totp-required=s"               => \$modify{'mfa-totp-required'},
        "pam-auth-bypass=s"                 => \$modify{'pam-auth-bypass'},
        "always-active=s"                   => \$modify{'always-active'},
        "egress-strict-host-key-checking=s" => \$modify{'egress-strict-host-key-checking'},
        "egress-session-multiplexing=s"     => \$modify{'egress-session-multiplexing'},
        "personal-egress-mfa-required=s"    => \$modify{'personal-egress-mfa-required'},
        "idle-ignore=s"                     => \$modify{'idle-ignore'},
        "max-inactive-days=i"               => \$modify{'max-inactive-days'},
        "osh-only=s"                        => \$modify{'osh-only'},
        "pubkey-auth-optional=s"            => \$modify{'pubkey-auth-optional'},
    },
    helptext => <<'EOF',
Modify an account configuration

Usage: --osh SCRIPT_NAME --account ACCOUNT [--option value [--option value [...]]]

  --account ACCOUNT                          Bastion account to work on
  --pam-auth-bypass yes|no                   Enable or disable PAM auth bypass for this account in addition to pubkey auth (default is 'no'),
                                               in that case sshd will not rely at all on PAM auth and /etc/pam.d/sshd configuration. This
                                               does not change the behaviour of the code, just the PAM auth handled by SSH itself
  --mfa-password-required yes|no|bypass      Enable or disable UNIX password requirement for this account in addition to pubkey auth (default is 'no'),
                                               this overrides the global bastion configuration 'accountMFAPolicy'. If 'bypass' is specified,
                                               no password will ever be asked, even for groups or plugins explicitly requiring it
  --mfa-totp-required yes|no|bypass          Enable or disable TOTP requirement for this account in addition to pubkey auth (default is 'no'),
                                               this overrides the global bastion configuration 'accountMFAPolicy'. If 'bypass' is specified,
                                               no OTP will ever be asked, even for groups or plugins explicitly requiring it
  --egress-strict-host-key-checking POLICY   Modify the egress SSH behavior of this account regarding ``StrictHostKeyChecking`` (see `man ssh_config`),
                                               POLICY can be 'yes', 'accept-new', 'no', 'ask', 'default' or 'bypass'.
                                               'bypass' means setting ``StrictHostKeyChecking=no`` and ``UserKnownHostsFile=/dev/null``,
                                               which will permit egress connections in all cases, even when host keys change all the time on the same target.
                                               This effectively suppress the host key checking entirely. Please don't enable this blindly.
                                               'default' will remove this account's ``StrictHostKeyChecking`` setting override.
                                               All the other policies carry the same meaning that what is documented in `man ssh_config`.
  --egress-session-multiplexing POLICY       Modify the egress SSH behavior of this account regarding ``ControlMaster`` and ``ControlPath``. POLICY can be:
                                               'yes', setting ``ControlMaster`` to 'auto' and setting ``ControlPath`` properly for session sharing,
                                               'no', setting ``ControlMaster`` to 'no' and ``ControlPath`` to 'none',
                                               'default', removing this account ``ControlMaster`` and ``ControlPath`` overrides altogether.
  --personal-egress-mfa-required POLICY      Enforce UNIX password requirement, or TOTP requirement, or any MFA requirement, when connecting to a server
                                               using the personal keys of the account, POLICY can be 'password', 'totp', 'any' or 'none'
  --always-active yes|no                     Set or unset the account as always active (i.e. disable the check of the 'active' status on this account)
  --idle-ignore yes|no                       If enabled, this account is immune to the idleLockTimeout and idleKillTimeout bastion-wide policy
  --max-inactive-days DAYS                   Set account expiration policy, overriding the global bastion configuration 'accountMaxInactiveDays'.
                                               Setting this option to zero disables account expiration. Setting this option to -1 removes this account
                                               expiration policy, i.e. the global bastion setting will apply.
  --osh-only yes|no                          If enabled, this account can only use ``--osh`` commands, and can't connect anywhere through the bastion
  --pubkey-auth-optional yes|no              Make the public key optional on ingress for the account (default is 'no').
                                               When enabled the public key part of the authentication becomes optional when a password and/or TOTP is defined,
                                               allowing to login with just the password/TOTP. If no password/TOTP is defined then the public key is the only way to authenticate,
                                               because some form of authentication is always required.
                                               When disabled, the public key is always required.
                                               Egress is not affected.

EOF
);

my $fnret;

if (!$account) {
    help();
    osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'account'";
}

$fnret = OVH::Bastion::is_bastion_account_valid_and_existing(account => $account, localOnly => 1);
$fnret or osh_exit $fnret;
$account = $fnret->value->{'account'};

if ((grep { defined } values %modify) == 0) {
    help();
    osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter to modify account";
}

foreach my $key (qw{ mfa-password-required mfa-totp-required }) {
    next unless $modify{$key};
    if (not grep { $modify{$key} eq $_ } qw{ yes no bypass }) {
        help();
        osh_exit 'ERR_INVALID_PARAMETER',
          "Expected '--$key yes' or '--$key no' or '--$key bypass' instead of '--$key $modify{$key}'";
    }
}
foreach my $key (qw{ always-active pam-auth-bypass idle-ignore osh-only pubkey-auth-optional }) {
    next unless $modify{$key};
    if (not grep { $modify{$key} eq $_ } qw{ yes no }) {
        help();
        osh_exit 'ERR_INVALID_PARAMETER', "Expected '--$key yes' or '--$key no' instead of '--$key $modify{$key}'";
    }
}
if ($modify{'egress-strict-host-key-checking'} && !grep { $modify{'egress-strict-host-key-checking'} eq $_ }
    qw{ yes accept-new no ask default bypass })
{
    help();
    osh_exit 'ERR_INVALID_PARAMETER',
      "Expected option 'yes', 'accept-new', 'no', 'ask', 'default' or 'bypass' to --egress-strict-host-key-checking";
}
if ($modify{'personal-egress-mfa-required'} && !grep { $modify{'personal-egress-mfa-required'} eq $_ }
    qw{ password totp any none })
{
    help();
    osh_exit 'ERR_INVALID_PARAMETER',
      "Expected option 'password', 'totp', 'any', 'none' to --personal-egress-mfa-required";
}
if ($modify{'egress-session-multiplexing'} && !grep { $modify{'egress-session-multiplexing'} eq $_ }
    qw{ yes no default })
{
    help();
    osh_exit 'ERR_INVALID_PARAMETER', "Expected option 'yes', 'no' or 'default' --egress-session-multiplexing";
}
if ($modify{'max-inactive-days'} && $modify{'max-inactive-days'} !~ /^(?:\d+|-1)$/) {
    help();
    osh_exit "ERR_INVALID_PARAMETER",
      "Expected -1, 0, or a strictly positive number of days as parameter to --max-inactive-days";
}

my @command = qw{ sudo -n -u root -- /usr/bin/env perl -T };
push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-accountModify';
push @command, '--account', $account;
foreach my $key (keys %modify) {
    push @command, '--modify', $key . '=' . $modify{$key} if defined $modify{$key};
}

osh_exit OVH::Bastion::helper(cmd => \@command);
