1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
|
package Debian::AdduserLogging 3.139;
use 5.36.0;
use utf8;
# Adduser logging Subroutines
#
# Subroutines shared by the "adduser" and "deluser" utilities.
#
# Copyright (C) 2024-2025 Marc Haber <mh+debian-packages@zugschlus.de>
#
# License: GPL-2+
use parent qw(Exporter);
use vars qw(@EXPORT $VAR1);
sub progname {
$0 =~ m|(.*/)?(.*)|;
return ($2);
}
BEGIN {
local $ENV{PERL_DL_NONLAZY}=1;
eval {
require Locale::gettext;
Locale::gettext->import(qw(gettext textdomain LC_MESSAGES));
};
if ($@) {
*gettext = sub { shift };
*textdomain = sub { "" };
*LC_MESSAGES = sub { 5 };
} else {
Locale::gettext::textdomain("adduser");
}
}
@EXPORT = (
'gtx',
'mtx',
'log_trace',
'log_debug',
'log_info',
'log_warn',
'log_err',
'log_fatal',
'set_msglevel'
);
my $stderrmsglevel="error";
my $stdoutmsglevel="error";
my $logmsglevel="info";;
my $loggerparms="";
my $has_sys_admin;
my $logger_id_option;
my $logtrace=$ENV{"ADDUSER_LOGTRACE"};
sub gtx {
return gettext( shift );
}
# this is used as a marker for a string that should be translated
# it returns the untranslated string
# use this for a message that is passed to messagef
sub mtx {
return shift;
}
sub numeric_msglevel {
# map from symbolic value to numerical order
my ($msglevel) = @_;
# error values from Log4perl::Level
my %map = (
logtrace => 1000,
trace => 5000,
debug => 10000,
info => 20000,
warn => 30000,
err => 40000,
error => 40000,
fatal => 50000
);
logtrace( sprintf( 'numeric_msglevel("%s") called', $msglevel ) );
if( defined($map{$msglevel}) ) {
my $ret = $map{$msglevel};
logtrace( sprintf( 'numeric_msglevel("%s") returns %s', $msglevel, $ret ) );
return $ret;
} else {
# this should be croak(), but we'd need perl-modules for that
die("undefined msglevel: $msglevel handed to numeric_msglevel");
}
};
sub logmsglevel {
# map log message level from symbolic value to string
my ($msglevel) = @_;
my %map = (
logtrace => "debug",
trace => "debug",
debug => "debug",
info => "info",
warn => "warning",
err => "error",
error => "error",
fatal => "crit"
);
if( defined($map{$msglevel}) ) {
return $map{$msglevel};
} else {
# this shuld be croak(), but we'd need perl-modules for that
die("undefined msglevel: $msglevel handed to logmsglevel");
}
};
sub check_sys_admin {
# this checks for SYS_ADMIN privilege, see #1074567
return $has_sys_admin if defined $has_sys_admin;
open my $fh, '<', '/proc/self/status' or return 0;
while (my $line = <$fh>) {
if ($line =~ /^CapEff:\s+[0-9a-fA-F]{10}([0-9a-fA-F]+)/) {
my $cap_eff = hex($1);
# Check if the CAP_SYS_ADMIN bit (21st bit) is set
$has_sys_admin = $cap_eff & (1 << 21);
last;
}
}
close $fh;
return $has_sys_admin;
}
sub log_to_syslog {
# use a pipe or system to logger, which is in bsdutils and thus essential
# use --id=adduser[pid]
# make logger parameters configurable (--udp, --journald, for example)
my ($prio, $data) = @_;
my $facility = 'user';
if( ! defined $logger_id_option ) {
# $$ would be $PID of we had English.pm
$logger_id_option="--id=". $$;
$logger_id_option="" if ! check_sys_admin;
}
$facility =~ /([a-zA-Z0-9]*)/;
my $utfacility = $1;
$prio =~ /([a-zA-Z0-9]*)/;
my $utprio = $1;
$loggerparms =~ /([-\sa-zA-Z0-9]*)/;
my $utloggerparms = $1;
my $utdata="";
# note that the two regexps are differnt in [^ and [
$data =~ s/[^-`'\s()\]\[{}?*+#\.:,;!"$%&\/=a-zA-Z0-9]/_/g;
if ($data =~ /^([-`'\s()\]\[{}?*+#\.:,;!"$%&\/=a-zA-Z0-9]+)$/) {
$utdata = $1;
}
my @command= ("logger",
$logger_id_option,
"--tag=". progname(),
"--priority=". $utfacility.".".$utprio,
$utloggerparms, "--",
$utdata);
system(@command) == 0
or printf STDERR ( gtx("logging to syslog failed: command line %s returned error: %s\n"), join(' ', @command), $?);
}
sub logtrace {
my ($fmt, @data ) = @_;
my $outstring = sprintf($fmt, @data);
if ($logtrace) {
printf STDOUT ( "logtrace: %s\n", $outstring );
log_to_syslog( "debug", "logtrace: ". $outstring. "\n" );
} else {
if ( $stderrmsglevel eq "logtrace" ) {
printf STDERR ( "logtrace: ". $outstring. "\n" );
} elsif ( $stdoutmsglevel eq "logtrace" ) {
printf STDOUT ( "logtrace: ". $outstring. "\n" );
}
if ( $logmsglevel eq "logtrace" ) {
log_to_syslog( "debug", "logtrace: ". $outstring );
}
}
}
sub logf {
my ($msglevel, @data ) = @_;
my $outstring;
my $loutstring;
# outstring is what we log to syslog
# loutstring (language outstring) is what we print to the console
if ( scalar(@data) == 1 ) {
logtrace("single element data");
$outstring = join(" ", @data);
$loutstring = gettext($outstring);
} else {
my $fmt=shift(@data),
my @dta= map( $_ // "(undef)", @data );
my $outfmt = $fmt;
chomp($outfmt);
logtrace("multiple element data: format %s, data %s", $outfmt, join("-", @dta));
$outstring = sprintf( $fmt, @dta );
$loutstring = sprintf( gettext($fmt), @dta );
}
logtrace("outstring %s", $outstring);
logtrace("loutstring %s", $loutstring);
logtrace("msglevel %s (%d), stdoutmsglevel %s (%d), stderrmsglevel %s (%d), logmsglevel %s (%d)", $msglevel, numeric_msglevel($msglevel), $stdoutmsglevel, numeric_msglevel($stdoutmsglevel), $stderrmsglevel, numeric_msglevel($stderrmsglevel), $logmsglevel, numeric_msglevel($logmsglevel));
if ( numeric_msglevel($msglevel) >= numeric_msglevel($stderrmsglevel) ) {
printf STDERR ( "%s: %s\n", $msglevel, $loutstring );
} elsif ( numeric_msglevel($msglevel) >= numeric_msglevel($stdoutmsglevel) ) {
printf STDOUT ( "%s: %s\n", $msglevel, $loutstring );
}
if ( numeric_msglevel($msglevel) >= numeric_msglevel($logmsglevel) ) {
log_to_syslog( logmsglevel($msglevel), $outstring );
}
};
sub log_trace {
my (@data) = @_;
logf( "trace", @data);
}
sub log_debug {
my (@data) = @_;
logf( "debug", @data);
}
sub log_info {
my (@data) = @_;
logf( "info", @data );
}
sub log_warn {
my (@data) = @_;
logf( "warn", @data );
}
sub log_err {
my (@data) = @_;
logf( "err", @data );
}
sub log_fatal {
my (@data) = @_;
logf( "fatal", @data );
}
sub set_msglevel {
($stderrmsglevel, $stdoutmsglevel, $logmsglevel) = @_;
logtrace("set_msglevel %s (%d) %s (%d) %s (%d)", $stdoutmsglevel, numeric_msglevel($stdoutmsglevel), $stderrmsglevel, numeric_msglevel($stderrmsglevel), $logmsglevel, numeric_msglevel($logmsglevel));
}
sub set_loggerparms {
($loggerparms) = @_;
}
1;
# Local Variables:
# mode:cperl
# End:
# vim: tabstop=4 shiftwidth=4 expandtab
|