diff --git a/lib/perl/OVH/Bastion.pm b/lib/perl/OVH/Bastion.pm index 1c6fd6a..4535f1a 100644 --- a/lib/perl/OVH/Bastion.pm +++ b/lib/perl/OVH/Bastion.pm @@ -57,7 +57,7 @@ use OVH::Result; use parent qw( Exporter ); our @EXPORT = ## no critic (AutomaticExportation) - qw( osh_header osh_footer osh_exit osh_debug osh_info osh_warn osh_crit osh_ok HEXIT warn_syslog ); + qw( osh_header osh_footer osh_exit osh_debug osh_info osh_warn osh_crit osh_ok warn_syslog ); our $AUTOLOAD; @@ -465,30 +465,6 @@ sub osh_ok { ## no critic (ArgUnpacking) exit OVH::Bastion::EXIT_OK; } -# HEXIT aka "helper exit", used by helper scripts found in helpers/ -# Can be used in several ways: -# With an R object: HEXIT(R('OK', value => {}, msg => "okey")) -# Or with 1 value, that will be taken as the R->err: HEXIT('OK') -# Or with 2 values, that will be taken as err, msg: HEXIT('ERR_UNKNOWN', 'Unexpected error') -# With more values, they'll be used as constructor for an R object -sub HEXIT { ## no critic (ArgUnpacking) - my $R; - - if (@_ == 1) { - $R = ref $_[0] eq 'OVH::Result' ? $_[0] : R($_[0]); - } - elsif (@_ == 2) { - my $err = shift || 'OK'; - my $msg = shift; - $R = R($err, msg => $msg); - } - else { - $R = R(@_); - } - OVH::Bastion::json_output($R, force_default => 1); - exit 0; -} - sub osh_debug { my $text = shift; if (($ENV{'PLUGIN_DEBUG'} or $ENV{'OSH_DEBUG'}) and not $ENV{'PLUGIN_QUIET'}) { diff --git a/lib/perl/OVH/Bastion/Helper.pm b/lib/perl/OVH/Bastion/Helper.pm index bd6311e..f613e9b 100644 --- a/lib/perl/OVH/Bastion/Helper.pm +++ b/lib/perl/OVH/Bastion/Helper.pm @@ -11,17 +11,47 @@ use OVH::Result; # We handle our importer's '$self' var, this is by design. use Exporter 'import'; our $self; ## no critic (ProhibitPackageVars) -our @EXPORT = qw( $self ); ## no critic (ProhibitAutomaticExportation) +our @EXPORT = qw( $self HEXIT ); ## no critic (ProhibitAutomaticExportation) + +# HEXIT aka "helper exit", used by helper scripts found in helpers/ +# Can be used in several ways: +# With an R object: HEXIT(R('OK', value => {}, msg => "okey")) +# Or with 1 value, that will be taken as the R->err: HEXIT('OK') +# Or with 2 values, that will be taken as err, msg: HEXIT('ERR_UNKNOWN', 'Unexpected error') +# With more values, they'll be used as constructor for an R object +sub HEXIT { ## no critic (ArgUnpacking) + my $R; + + if (@_ == 1) { + $R = ref $_[0] eq 'OVH::Result' ? $_[0] : R($_[0]); + } + elsif (@_ == 2) { + my $err = shift || 'OK'; + my $msg = shift; + $R = R($err, msg => $msg); + } + else { + $R = R(@_); + } + OVH::Bastion::json_output($R, force_default => 1); + exit 0; +} + +# +# This code has to be ran for all helpers before they attempt to do anything useful, +# and as we're only use'd by helpers, we include it here directly on top-level. +# $| = 1; -# -# This code has to be ran for all helpers so we include it here directly -# - +# Don't let helpers be interrupted too easily $SIG{'HUP'} = 'IGNORE'; # continue even when attached terminal is closed (we're called with setsid on supported systems anyway) $SIG{'PIPE'} = 'IGNORE'; # continue even if osh_info gets a SIGPIPE because there's no longer a terminal + +# Ensure the PATH is not tainted, and has sane values $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/pkg/bin'; + +# Build $self from SUDO_USER, as helpers are always run under sudo ($self) = $ENV{'SUDO_USER'} =~ m{^([a-zA-Z0-9._-]+)$}; if (not defined $self) { if ($< == 0) { diff --git a/lib/perl/OVH/Bastion/Plugin/generatePassword.pm b/lib/perl/OVH/Bastion/Plugin/generatePassword.pm index 75b1508..c8284a2 100644 --- a/lib/perl/OVH/Bastion/Plugin/generatePassword.pm +++ b/lib/perl/OVH/Bastion/Plugin/generatePassword.pm @@ -59,11 +59,11 @@ sub preconditions { if ($context eq 'account' && $self ne $account) { $fnret = OVH::Bastion::is_user_in_group(user => $self, group => "osh-accountGeneratePassword"); - $fnret or HEXIT('ERR_SECURITY_VIOLATION', msg => "You're not allowed to run this, dear $self"); + $fnret or return R('ERR_SECURITY_VIOLATION', msg => "You're not allowed to run this, dear $self"); } elsif ($context eq 'group') { $fnret = OVH::Bastion::is_group_owner(account => $self, group => $shortGroup, superowner => 1, sudo => $sudo); - $fnret or HEXIT('ERR_NOT_ALLOWED', msg => "You're not a group owner of $shortGroup, dear $self"); + $fnret or return R('ERR_NOT_ALLOWED', msg => "You're not a group owner of $shortGroup, dear $self"); } # return untainted values @@ -105,7 +105,7 @@ sub act { # get the corresponding hashes $fnret = OVH::Bastion::get_hashes_from_password(password => $pass); - $fnret or HEXIT($fnret); + $fnret or return $fnret; # verify that the hashes match this regex (some constructors need it) my $check_re = qr'^\$\d\$[a-zA-Z0-9]+\$[a-zA-Z0-9.\/]+$'; @@ -124,7 +124,7 @@ sub act { # push password in a file if (!-d $passhome) { if (!mkdir $passhome) { - HEXIT('ERR_INTERNAL', msg => "Couldn't create passwords directory in group home '$passhome' ($!)"); + return R('ERR_INTERNAL', msg => "Couldn't create passwords directory in group home '$passhome' ($!)"); } if ($context eq 'account') { if (my (undef, undef, $uid, $gid) = getpwnam($account)) { @@ -133,7 +133,7 @@ sub act { } } if (!-d $passhome) { - HEXIT('ERR_INTERNAL', msg => "Couldn't create passwords directory in group home"); + return R('ERR_INTERNAL', msg => "Couldn't create passwords directory in group home"); } chmod 0750, $passhome; if (-e $base) { @@ -146,19 +146,19 @@ sub act { if (-e "$base.$n") { osh_debug "renaming $base.$n to $base.$next"; if (!rename "$base.$n", "$base.$next") { - HEXIT('ERR_INTERNAL', msg => "Couldn't rename '$base.$n' to '$base.$next' ($!)"); + return R('ERR_INTERNAL', msg => "Couldn't rename '$base.$n' to '$base.$next' ($!)"); } if (-e "$base.$n.metadata" && !rename "$base.$n.metadata", "$base.$next.metadata") { - HEXIT('ERR_INTERNAL', msg => "Couldn't rename '$base.$n.metadata' to '$base.$next.metadata' ($!)"); + return R('ERR_INTERNAL', msg => "Couldn't rename '$base.$n.metadata' to '$base.$next.metadata' ($!)"); } } } osh_debug "renaming $base to $base.1"; if (!rename "$base", "$base.1") { - HEXIT('ERR_INTERNAL', msg => "Couldn't rename '$base' to '$base.1' ($!)"); + return R('ERR_INTERNAL', msg => "Couldn't rename '$base' to '$base.1' ($!)"); } if (-e "$base.metadata" && !rename "$base.metadata", "$base.1.metadata") { - HEXIT('ERR_INTERNAL', msg => "Couldn't rename '$base.metadata' to '$base.1.metadata' ($!)"); + return R('ERR_INTERNAL', msg => "Couldn't rename '$base.metadata' to '$base.1.metadata' ($!)"); } } if (open(my $fdout, '>', $base)) { @@ -172,7 +172,7 @@ sub act { chmod 0440, $base; } else { - HEXIT('ERR_INTERNAL', msg => "Couldn't create password file in $base ($!)"); + return R('ERR_INTERNAL', msg => "Couldn't create password file in $base ($!)"); } if (open(my $fdout, '>', "$base.metadata")) { diff --git a/lib/perl/OVH/Bastion/ssh.inc b/lib/perl/OVH/Bastion/ssh.inc index 66b9625..6c4b0b8 100644 --- a/lib/perl/OVH/Bastion/ssh.inc +++ b/lib/perl/OVH/Bastion/ssh.inc @@ -537,7 +537,7 @@ sub generate_ssh_key { my $sshKeyName = $folder . '/id_' . $algo . $size . '_' . $prefix . '.' . time(); if (-e $sshKeyName) { - HEXIT('ERR_KEY_ALREADY_EXISTS', msg => "Can't forge key, generated name already exists"); + return R('ERR_KEY_ALREADY_EXISTS', msg => "Can't forge key, generated name already exists"); } my $bastionName = OVH::Bastion::config('bastionName');