diff -Naur old/authconfig.py new/authconfig.py --- old/authconfig.py 2017-03-28 14:08:03.601258033 +0200 +++ new/authconfig.py 2017-03-28 14:10:35.055518926 +0200 @@ -353,6 +353,13 @@ help=_("require at least one other character in a password")) parser.add_option("--disablereqother", action="store_true", help=_("do not require other characters in a password")) + + parser.add_option("--enablefaillock", action="store_true", + help=_("enable account locking in case of too many consecutive authentication failures")) + parser.add_option("--disablefaillock", action="store_true", + help=_("disable account locking on too many consecutive authentication failures")) + parser.add_option("--faillockargs", metavar=_(""), + help=_("the pam_faillock module options")) parser.add_option("--nostart", action="store_true", help=_("do not start/stop portmap, ypbind, and nscd")) @@ -466,7 +473,8 @@ "reqlower":"passReqLower", "requpper":"passReqUpper", "reqdigit":"passReqDigit", - "reqother":"passReqOther"} + "reqother":"passReqOther", + "faillock":"enableFaillock"} string_settings = {"passalgo":"passwordAlgorithm", "hesiodlhs":"hesiodLHS", @@ -495,7 +503,8 @@ "passminlen":"passMinLen", "passminclass":"passMinClass", "passmaxrepeat":"passMaxRepeat", - "passmaxclassrepeat":"passMaxClassRepeat"} + "passmaxclassrepeat":"passMaxClassRepeat", + "faillockargs":"faillockArgs"} for opt, aival in bool_settings.iteritems(): if getattr(self.options, "enable"+opt): diff -Naur old/authinfo.py new/authinfo.py --- old/authinfo.py 2017-03-28 14:08:03.599258069 +0200 +++ new/authinfo.py 2017-03-28 14:25:31.403421162 +0200 @@ -489,6 +489,8 @@ "otp", argv_otp_auth], [False, AUTH, LOGIC_SUFFICIENT, "winbind", argv_winbind_auth], + [False, AUTH, LOGIC_REQUIRED, + "faillock", ["authfail"]], [True, AUTH, LOGIC_REQUIRED, "deny", []], # Account management is tricky. Because we've implicitly committed to @@ -508,6 +510,8 @@ # successful call to pam_permit at the end as a requirement. [False, ACCOUNT, LOGIC_REQUIRED, "access", []], + [False, ACCOUNT, LOGIC_REQUIRED, + "faillock", []], [True, ACCOUNT, LOGIC_REQUIRED, "unix", []], [False, ACCOUNT, LOGIC_SUFFICIENT, @@ -618,6 +622,8 @@ "deny", []], [False, ACCOUNT, LOGIC_REQUIRED, "access", []], + [False, ACCOUNT, LOGIC_REQUIRED, + "faillock", []], [True, ACCOUNT, LOGIC_REQUIRED, "unix", []], [False, ACCOUNT, LOGIC_SUFFICIENT, @@ -654,6 +660,8 @@ "ldap", argv_ldap_password], [False, PASSWORD, LOGIC_SUFFICIENT, "winbind", argv_winbind_password], + [False, AUTH, LOGIC_REQUIRED, + "faillock", ["authfail"]], [True, PASSWORD, LOGIC_REQUIRED, "deny", []], [True, SESSION, LOGIC_OPTIONAL, @@ -689,10 +697,14 @@ "deny", []], [False, AUTH, LOGIC_SUFFICIENT, "fprintd", []], + [False, AUTH, LOGIC_REQUIRED, + "faillock", ["authfail"]], [True, AUTH, LOGIC_REQUIRED, "deny", []], [False, ACCOUNT, LOGIC_REQUIRED, "access", []], + [False, ACCOUNT, LOGIC_REQUIRED, + "faillock", []], [True, ACCOUNT, LOGIC_REQUIRED, "unix", []], [False, ACCOUNT, LOGIC_SUFFICIENT, @@ -748,10 +760,14 @@ "krb5", argv_krb5_sc_auth], [False, AUTH, LOGIC_SUFFICIENT, "permit", []], + [False, AUTH, LOGIC_REQUIRED, + "faillock", ["authfail"]], [True, AUTH, LOGIC_REQUIRED, "deny", []], [False, ACCOUNT, LOGIC_REQUIRED, "access", []], + [False, ACCOUNT, LOGIC_REQUIRED, + "faillock", []], [True, ACCOUNT, LOGIC_REQUIRED, "unix", []], [False, ACCOUNT, LOGIC_SUFFICIENT, @@ -1392,6 +1408,11 @@ self.passReqDigit = None self.passReqOther = None + # Faillock + self.enableFaillock = None + self.faillockArgs = "deny=4 unlock_time=1200" + + # Not really options. self.joinUser = "" self.joinPassword = "" @@ -1453,6 +1474,7 @@ ("enableNIS3", "b"), ("enableNIS", "b"), ("enableIPAv2", "b"), ("enableSSSD", "b"), ("preferDNSinHosts", "b"), ("implicitSSSD", "b")]), SaveGroup(self.writePAM, None, [("pwqualityArgs", "c"), ("passwdqcArgs", "c"), + ("faillockArgs", "c"), ("enableFaillock", "b"), ("localuserArgs", "c"), ("pamAccessArgs", "c"), ("enablePAMAccess", "b"), ("mkhomedirArgs", "c"), ("enableMkHomeDir", "b"), ("algoRounds", "c"), ("passwordAlgorithm", "i"), ("enableShadow", "b"), ("enableNIS", "b"), @@ -1470,6 +1492,7 @@ ("enableEcryptfs", "b"), ("enableSmartcard", "b"), ("forceSmartcard", "b"), ("enableWinbindAuth", "b"), ("enableWinbind", "b"), ("winbindKrb5", "b"), ("enableDB", "b"), ("enableHesiod", "b"), ("enablePWQuality", "b"), ("enablePasswdQC", "b"), + ("enableFaillock", "b"), ("faillockArgs", "c"), ("enableLocAuthorize", "b"), ("enablePAMAccess", "b"), ("enableCacheCreds", "b"), ("enableMkHomeDir", "b"), ("enableSysNetAuth", "b"), ("enableFprintd", "b"), ("enableSSSD", "b"), ("enableSSSDAuth", "b"), ("enableForceLegacy", "b"), @@ -2247,6 +2270,12 @@ if stack == "auth": if module.startswith("pam_unix"): self.setParam("enableNullOk", args.find("nullok") >= 0, ref) + if module.startswith("pam_faillock"): + self.setParam("enableFaillock", True, ref) + if args: + args.replace('authfail', '').strip() + self.setParam("faillockArgs", args, ref) + continue if stack == "account": if module.startswith("pam_unix"): self.setParam("brokenShadow", args.find("broken_shadow") >= 0, ref) @@ -2305,6 +2334,11 @@ except ValueError: pass try: + self.enableFaillock = shv.getBoolValue("USEFAILLOCK") + self.faillockArgs = shv.getValue("FAILLOCKARGS") + except ValueError: + pass + try: self.enableEcryptfs = shv.getBoolValue("USEECRYPTFS") except ValueError: pass @@ -3912,6 +3946,8 @@ if (self.forceBrokenShadow or self.enableLDAPAuth or self.enableKerberos or self.enableWinbindAuth): output += " broken_shadow" + if name == "faillock" and stack == "auth": + args = " ".join(module[ARGV]) + " " + self.faillockArgs if args: output += " " + args output += "\n" @@ -3978,6 +4014,7 @@ (self.enableAFS and module[NAME] == "afs") or (self.enableAFSKerberos and module[NAME] == "afs.krb") or (self.enablePWQuality and module[NAME] == "pwquality") or + (self.enableFaillock and module[NAME] == "faillock") or (self.enableEcryptfs and module[NAME] == "ecryptfs") or (self.enableEPS and module[NAME] == "eps") or ((self.enableKerberos and not self.implicitSSSDAuth)and module[NAME] == "krb5" and @@ -4039,6 +4076,8 @@ return False shv.setBoolValue("USEPWQUALITY", self.enablePWQuality) + shv.setBoolValue("USEFAILLOCK", self.enableFaillock) + shv.setValue("FAILLOCKARGS", self.faillockArgs) shv.setBoolValue("USEDB", self.enableDB) shv.setBoolValue("USEHESIOD", self.enableHesiod) shv.setBoolValue("USELDAP", self.enableLDAP) @@ -4314,6 +4353,8 @@ self.passwdqcArgs) print "pam_access is %s (%s)" % (formatBool(self.enablePAMAccess), self.pamAccessArgs) + print "pam_faillock is %s (%s)" % (formatBool(self.enableFaillock), + self.faillockArgs) print "pam_mkhomedir or pam_oddjob_mkhomedir is %s (%s)" % (formatBool(self.enableMkHomeDir), self.mkhomedirArgs) print "Always authorize local users is %s (%s)" % (formatBool(self.enableLocAuthorize),