Replace the legacy Go implementation as the production path, quarantine the reference tree, add deterministic release packaging and version metadata, and run verification through GitLab CI.
82 lines
1.7 KiB
Go
82 lines
1.7 KiB
Go
// auth — faillock integration.
|
|
//
|
|
// Reads /etc/security/faillock.conf for deny count, executes
|
|
// faillock --user to get tally, supports --reset via admin bypass.
|
|
package auth
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type FaillockStatus struct {
|
|
Enabled bool
|
|
Failures int
|
|
MaxTries int
|
|
Remaining int
|
|
LockedOut bool
|
|
}
|
|
|
|
func GetFaillockStatus(user string) (FaillockStatus, error) {
|
|
s := FaillockStatus{}
|
|
|
|
data, err := os.ReadFile("/etc/security/faillock.conf")
|
|
if err != nil {
|
|
return s, nil
|
|
}
|
|
s.Enabled = true
|
|
s.MaxTries = 3
|
|
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
line = strings.TrimSpace(line)
|
|
if strings.HasPrefix(line, "deny") {
|
|
parts := strings.Split(line, "=")
|
|
if len(parts) == 2 {
|
|
if n, err := strconv.Atoi(strings.TrimSpace(parts[1])); err == nil {
|
|
s.MaxTries = n
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var out bytes.Buffer
|
|
cmd := exec.Command("faillock", "--user", user)
|
|
cmd.Stdout = &out
|
|
cmd.Stderr = &out
|
|
if err := cmd.Run(); err != nil {
|
|
return s, fmt.Errorf("faillock: %w", err)
|
|
}
|
|
|
|
s.Failures = countFaillockLines(out.String())
|
|
s.Remaining = s.MaxTries - s.Failures
|
|
if s.Remaining < 0 {
|
|
s.Remaining = 0
|
|
}
|
|
s.LockedOut = s.Remaining <= 0
|
|
return s, nil
|
|
}
|
|
|
|
func ResetFaillock(user string) error {
|
|
return exec.Command("faillock", "--user", user, "--reset").Run()
|
|
}
|
|
|
|
func countFaillockLines(out string) int {
|
|
n := 0
|
|
for _, line := range strings.Split(out, "\n") {
|
|
line = strings.TrimSpace(line)
|
|
if line == "" || strings.HasPrefix(line, "When") ||
|
|
strings.HasPrefix(line, "Source") || strings.HasPrefix(line, "Date") {
|
|
continue
|
|
}
|
|
if strings.Contains(line, ":") {
|
|
continue
|
|
}
|
|
n++
|
|
}
|
|
return n
|
|
}
|