Algorithm-ToNumberMunger
view release on metacpan or search on metacpan
lib/Algorithm/ToNumberMunger.pm view on Meta::CPAN
C<soft reject> 4, C<reject> 5. Both the space and underscore spellings rspamd
emits (C<no action>/C<no_action>, C<add header>/C<add_header>, ...) are
accepted. Numeric inputs are not passed through.
=head2 ssh_auth_method_enum
{ munger => 'ssh_auth_method_enum', default => -1 }
Named-map enum (lookup rules as L</dns_rcode_enum>) for the OpenSSH
authentication method logged by C<sshd> (the word after C<Accepted>/C<Failed>,
or the C<method=> field): C<none> 0, C<password> 1, C<keyboard-interactive> 2,
C<hostbased> 3, C<publickey> 4, C<gssapi-with-mic> 5, C<gssapi-keyex> 6, with
bare C<gssapi> aliased to C<gssapi-with-mic>. Numbered roughly
B<weakest-to-strongest> so "weaker credential than expected" is a monotone
feature; the ordering is a judgement call, not a registry. Numeric inputs are
not passed through.
=head2 amavis_category_enum
{ munger => 'amavis_category_enum', default => -1 }
lib/Algorithm/ToNumberMunger.pm view on Meta::CPAN
privilege than expected" is a monotone feature. Numeric inputs are not passed
through.
=head2 windows_logon_status_enum
{ munger => 'windows_logon_status_enum', default => -1 }
Named-map enum (lookup rules as L</dns_rcode_enum>) for the NTSTATUS
sub-status on a failed Windows logon (events 4625/4776), collapsed to a
compact B<reason category> rather than the raw 32-bit code: C<0xC0000064>
(no such user) 0, C<0xC000006A> (bad password) 1, C<0xC000006D> (generic bad
user/pass) 2, C<0xC000006F> (outside hours) 3, C<0xC0000070> (workstation
restriction) 4, C<0xC0000071> (password expired) 5, C<0xC0000072> (disabled)
6, C<0xC0000193> (account expired) 7, C<0xC0000133> (clock skew) 8,
C<0xC0000224> (must change password) 9, C<0xC0000234> (locked out) 10,
C<0xC000015B> (logon type not granted) 11. Keys are the hex codes exactly as
logged (matched case-insensitively); only the common logon subset is baked in,
so an unlisted code croaks unless a numeric C<default> is given. Numeric
inputs are not passed through.
=head2 windows_impersonation_level_enum
{ munger => 'windows_impersonation_level_enum', default => -1 }
Named-map enum (lookup rules as L</dns_rcode_enum>) for the event 4624
lib/Algorithm/ToNumberMunger.pm view on Meta::CPAN
C<impersonation> 2, C<delegation> 3. The C<%%1832> / C<%%1833> message tokens
Windows often emits in place of the words (Identification / Impersonation) are
accepted as aliases. Numeric inputs are not passed through.
=head2 aad_signin_error_enum
{ munger => 'aad_signin_error_enum', default => -1 }
Named-map enum for the Azure AD / Entra sign-in C<ResultType> error code,
collapsed to a compact B<reason category> rather than the raw code: C<0>
(success) 0, invalid-password (C<50126>, C<50056>) 1, no-such-user (C<50034>)
2, disabled (C<50057>) 3, locked / smart-lockout (C<50053>) 4, password-expired
(C<50055>, C<50144>) 5, MFA-required (C<50074>, C<50076>, C<50079>) 6,
MFA-failed (C<500121>, C<50158>) 7, blocked-by-conditional-access (C<53003>,
C<53000>, C<53001>, C<530032>) 8, session-expired (C<50173>) 9. Although
C<ResultType> is already numeric, the code space is huge and sparse and its
magnitude carries no signal -- this maps the common codes onto a handful of
meaningful buckets (and, unlike L</hash>, keeps related codes together). Keys
are the codes as logged; only the common subset is baked in, so an unlisted
code croaks unless a numeric C<default> is given. Because the output is a
category of our own numbering, numeric inputs are B<not> passed through.
lib/Algorithm/ToNumberMunger.pm view on Meta::CPAN
},
},
ssh_auth_method => {
numeric => 0,
map => {
# OpenSSH authentication method, ordered by credential strength
# (weakest first) so "weaker than expected" is monotone. The
# ordering is a judgement call, not an IANA registry.
do {
my @o = qw(
none password keyboard-interactive
hostbased publickey
gssapi-with-mic gssapi-keyex
);
my %m = map { $o[$_] => $_ } 0 .. $#o;
$m{'gssapi'} = $m{'gssapi-with-mic'};
%m;
},
},
},
amavis_category => {
lib/Algorithm/ToNumberMunger.pm view on Meta::CPAN
},
},
},
windows_logon_status => {
numeric => 0,
map => {
# Common NTSTATUS sub-status codes on failed logons (4625/4776),
# mapped to a compact reason category -- the raw 32-bit value is
# not itself a useful feature. Keys are the hex codes as logged.
'0xc0000064' => 0, # user name does not exist
'0xc000006a' => 1, # bad password
'0xc000006d' => 2, # bad user name or password (generic)
'0xc000006f' => 3, # outside authorized hours
'0xc0000070' => 4, # workstation restriction
'0xc0000071' => 5, # password expired
'0xc0000072' => 6, # account disabled
'0xc0000193' => 7, # account expired
'0xc0000133' => 8, # clock skew between client and server
'0xc0000224' => 9, # must change password at next logon
'0xc0000234' => 10, # account locked out
'0xc000015b' => 11, # logon type not granted
},
},
windows_impersonation_level => {
numeric => 0,
map => {
# 4624 ImpersonationLevel; ordinal by reach. Text labels plus the
# two "%%18xx" message tokens Windows most often emits in place.
anonymous => 0,
lib/Algorithm/ToNumberMunger.pm view on Meta::CPAN
},
aad_signin_error => {
numeric => 0,
map => {
# Azure AD / Entra sign-in ResultType codes collapsed to a compact
# reason category -- the raw code is a huge sparse space whose
# magnitude carries no signal. Keys are the numeric codes as
# logged; only the common subset is baked in, the rest take the
# default.
'0' => 0, # success
'50126' => 1, # invalid username or password
'50056' => 1, # invalid or null password
'50034' => 2, # user does not exist in directory
'50057' => 3, # account disabled
'50053' => 4, # account locked / smart lockout
'50055' => 5, # password expired
'50144' => 5, # AD password expired
'50074' => 6, # strong auth (MFA) required
'50076' => 6, # MFA required by conditional access
'50079' => 6, # user must enroll for MFA
'500121' => 7, # MFA denied / authentication failed
'50158' => 7, # external security challenge not satisfied
'53003' => 8, # blocked by conditional access
'53000' => 8, # device not compliant (CA)
'53001' => 8, # device not domain joined (CA)
'530032' => 8, # blocked by security policy (CA)
'50173' => 9, # fresh auth token required (session expired)
t/mungers.t view on Meta::CPAN
is( $ra->('greylist'), 1, 'rspamd greylist' );
is( $ra->('add header'), 2, 'rspamd add header' );
is( $ra->('add_header'), 2, 'rspamd add_header underscore alias' );
is( $ra->('rewrite subject'), 3, 'rspamd rewrite subject' );
is( $ra->('soft reject'), 4, 'rspamd soft reject' );
is( $ra->('reject'), 5, 'rspamd reject' );
ok( $ra->('greylist') < $ra->('reject'), 'rspamd_action ordered by severity' );
my $sm = $M->build( { munger => 'ssh_auth_method_enum', default => -1 } );
is( $sm->('none'), 0, 'ssh none' );
is( $sm->('password'), 1, 'ssh password' );
is( $sm->('keyboard-interactive'), 2, 'ssh keyboard-interactive' );
is( $sm->('publickey'), 4, 'ssh publickey' );
is( $sm->('gssapi'), $sm->('gssapi-with-mic'), 'ssh gssapi aliases gssapi-with-mic' );
ok( $sm->('password') < $sm->('publickey'), 'ssh_auth_method weakest-to-strongest' );
is( $sm->('magic'), -1, 'ssh_auth_method default for unlisted' );
my $am = $M->build( { munger => 'amavis_category_enum', default => -1 } );
is( $am->('clean'), 0, 'amavis clean' );
is( $am->('spam'), 4, 'amavis spam' );
is( $am->('bad-header'), $am->('badheader'), 'amavis bad-header aliases badheader' );
is( $am->('virus'), $am->('infected'), 'amavis virus aliases infected' );
ok( $am->('clean') < $am->('infected'), 'amavis_category ordered clean-to-worst' );
my $sr = $M->build( { munger => 'systemd_result_enum', default => -1 } );
t/mungers.t view on Meta::CPAN
is( $il->('Untrusted'), 0, 'integrity untrusted (case-insensitive)' );
is( $il->('Medium'), 2, 'integrity medium' );
is( $il->('System'), 4, 'integrity system' );
is( $il->('mediumplus'), 2, 'integrity mediumplus folds into medium' );
is( $il->('S-1-16-12288'), 3, 'integrity high mandatory-label SID' );
ok( $il->('Low') < $il->('System'), 'windows_integrity_level is ordinal' );
is( $il->('bogus'), -1, 'integrity default for unlisted' );
my $ls = $M->build( { munger => 'windows_logon_status_enum', default => -1 } );
is( $ls->('0xC0000064'), 0, 'logon_status no-such-user (case-insensitive hex)' );
is( $ls->('0xc000006a'), 1, 'logon_status bad password' );
is( $ls->('0xc0000234'), 10, 'logon_status locked out' );
is( $ls->('0xc000015b'), 11, 'logon_status type not granted' );
is( $ls->('0x0'), -1, 'logon_status default for a success/unlisted code' );
my $im = $M->build( { munger => 'windows_impersonation_level_enum', default => -1 } );
is( $im->('Anonymous'), 0, 'impersonation anonymous' );
is( $im->('Impersonation'), 2, 'impersonation impersonation' );
is( $im->('Delegation'), 3, 'impersonation delegation' );
is( $im->('%%1832'), 1, 'impersonation %%1832 token is identification' );
is( $im->('%%1833'), 2, 'impersonation %%1833 token is impersonation' );
t/mungers.t view on Meta::CPAN
eval { $M->build( { munger => 'windows_integrity_level_enum' } )->(3) };
like( $@, qr/no mapping for '3'/, 'windows ordinal enums do not pass a number through' );
}
# ---- O365 / Azure AD / AWS cloud named enums --------------------------------
{
# aad_signin_error: the sparse ResultType code space collapsed to reasons.
my $se = $M->build( { munger => 'aad_signin_error_enum', default => -1 } );
is( $se->('0'), 0, 'aad_signin_error 0 is success' );
is( $se->('50126'), 1, 'aad_signin_error 50126 bad-password' );
is( $se->('50056'), $se->('50126'), 'aad_signin_error 50056 shares bad-password bucket' );
is( $se->('50144'), $se->('50055'), 'aad_signin_error 50144 shares password-expired bucket' );
is( $se->('53000'), 8, 'aad_signin_error 53000 blocked-by-CA bucket' );
is( $se->(50053), 4, 'aad_signin_error accepts an integer code' );
is( $se->('99999'), -1, 'aad_signin_error default for an unlisted code' );
my $rl = $M->build( { munger => 'risk_level_enum', default => -1 } );
is( $rl->('none'), 0, 'risk_level none' );
is( $rl->('High'), 3, 'risk_level high (case-insensitive)' );
is( $rl->('hidden'), -1, 'risk_level hidden is off-scale (default)' );
ok( $rl->('low') < $rl->('high'), 'risk_level is ordinal' );
( run in 1.448 second using v1.01-cache-2.11-cpan-4ef0a570458 )