@@ -327,6 +327,24 @@ bool parse_ssh_accepted_message(std::string_view message, Event& event) {
327327 return true ;
328328}
329329
330+ bool parse_ssh_accepted_publickey_message (std::string_view message, Event& event) {
331+ static constexpr std::string_view accepted_prefix = " Accepted publickey for " ;
332+ if (!message.starts_with (accepted_prefix)) {
333+ return false ;
334+ }
335+
336+ auto remaining = message.substr (accepted_prefix.size ());
337+ const auto username = consume_token (remaining);
338+ if (username.empty ()) {
339+ return false ;
340+ }
341+
342+ event.username .assign (username);
343+ event.source_ip = extract_token_after (message, " from " );
344+ event.event_type = EventType::SshAcceptedPublicKey;
345+ return true ;
346+ }
347+
330348bool parse_ssh_failed_publickey_message (std::string_view message, Event& event) {
331349 static constexpr std::string_view publickey_prefix = " Failed publickey for " ;
332350 if (!message.starts_with (publickey_prefix)) {
@@ -367,6 +385,25 @@ bool parse_ssh_invalid_user_message(std::string_view message, Event& event) {
367385 return true ;
368386}
369387
388+ bool parse_pam_named_user_failure_message (std::string_view message,
389+ std::string_view prefix,
390+ Event& event) {
391+ if (!message.starts_with (prefix)) {
392+ return false ;
393+ }
394+
395+ auto remaining = message.substr (prefix.size ());
396+ const auto username = consume_token (remaining);
397+ if (username.empty ()) {
398+ return false ;
399+ }
400+
401+ event.username .assign (username);
402+ event.source_ip = extract_token_after (message, " from " );
403+ event.event_type = EventType::PamAuthFailure;
404+ return true ;
405+ }
406+
370407bool parse_pam_auth_failure_message (std::string_view message, Event& event) {
371408 static constexpr std::string_view auth_failure_prefix = " authentication failure;" ;
372409 if (!message.starts_with (auth_failure_prefix)) {
@@ -379,6 +416,30 @@ bool parse_pam_auth_failure_message(std::string_view message, Event& event) {
379416 return true ;
380417}
381418
419+ bool parse_pam_sss_received_failure_message (std::string_view message, Event& event) {
420+ static constexpr std::string_view received_prefix = " received for user " ;
421+ static constexpr std::string_view failure_marker = " (Authentication failure)" ;
422+
423+ if (!message.starts_with (received_prefix) || message.find (failure_marker) == std::string_view::npos) {
424+ return false ;
425+ }
426+
427+ auto remaining = message.substr (received_prefix.size ());
428+ const auto separator = remaining.find (' :' );
429+ if (separator == std::string_view::npos) {
430+ return false ;
431+ }
432+
433+ const auto username = trim (remaining.substr (0 , separator));
434+ if (username.empty ()) {
435+ return false ;
436+ }
437+
438+ event.username .assign (username);
439+ event.event_type = EventType::PamAuthFailure;
440+ return true ;
441+ }
442+
382443bool parse_session_opened_message (std::string_view message, Event& event) {
383444 static constexpr std::string_view session_prefix = " session opened for user " ;
384445 if (!message.starts_with (session_prefix)) {
@@ -423,6 +484,38 @@ bool parse_sudo_message(std::string_view message, Event& event) {
423484 return true ;
424485}
425486
487+ bool parse_pam_faillock_message (std::string_view message, Event& event) {
488+ if (parse_pam_named_user_failure_message (message, " Consecutive login failures for user " , event)) {
489+ return true ;
490+ }
491+
492+ if (parse_pam_named_user_failure_message (message, " Authentication failure for user " , event)) {
493+ return true ;
494+ }
495+
496+ return false ;
497+ }
498+
499+ std::string classify_unknown_pam_faillock_pattern (std::string_view message) {
500+ if (message.starts_with (" User " ) && message.find (" successfully authenticated" ) != std::string_view::npos) {
501+ return " pam_faillock_authsucc" ;
502+ }
503+
504+ return " pam_faillock_other" ;
505+ }
506+
507+ std::string classify_unknown_pam_sss_pattern (std::string_view message) {
508+ if (message.find (" User not known to the underlying authentication module" ) != std::string_view::npos) {
509+ return " pam_sss_unknown_user" ;
510+ }
511+
512+ if (message.find (" Authentication service cannot retrieve authentication info" ) != std::string_view::npos) {
513+ return " pam_sss_authinfo_unavail" ;
514+ }
515+
516+ return " pam_sss_other" ;
517+ }
518+
426519std::string classify_unknown_auth_pattern (const Event& event) {
427520 const auto message = std::string_view{event.message };
428521 if (event.program == " sshd" ) {
@@ -444,6 +537,14 @@ std::string classify_unknown_auth_pattern(const Event& event) {
444537 return " pam_unix_other" ;
445538 }
446539
540+ if (event.program .starts_with (" pam_faillock(" )) {
541+ return classify_unknown_pam_faillock_pattern (message);
542+ }
543+
544+ if (event.program .starts_with (" pam_sss(" )) {
545+ return classify_unknown_pam_sss_pattern (message);
546+ }
547+
447548 if (event.program == " sudo" ) {
448549 return " sudo_other" ;
449550 }
@@ -460,6 +561,9 @@ bool classify_event(Event& event) {
460561 if (parse_ssh_accepted_message (message, event)) {
461562 return true ;
462563 }
564+ if (parse_ssh_accepted_publickey_message (message, event)) {
565+ return true ;
566+ }
463567 if (parse_ssh_failed_publickey_message (message, event)) {
464568 return true ;
465569 }
@@ -479,6 +583,20 @@ bool classify_event(Event& event) {
479583 return false ;
480584 }
481585
586+ if (event.program .starts_with (" pam_faillock(" )) {
587+ return parse_pam_faillock_message (message, event);
588+ }
589+
590+ if (event.program .starts_with (" pam_sss(" )) {
591+ if (parse_pam_auth_failure_message (message, event)) {
592+ return true ;
593+ }
594+ if (parse_pam_sss_received_failure_message (message, event)) {
595+ return true ;
596+ }
597+ return false ;
598+ }
599+
482600 if (event.program == " sudo" ) {
483601 return parse_sudo_message (message, event);
484602 }
0 commit comments