--- /dev/null
+#include "config.h"
+
+#include "chkhash.h"
+
+#include <regex.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+
+/*
+ * match_regex - return true if match, false if not
+ */
+bool
+match_regex(const char *pattern, const char *string)
+{
+ regex_t regex;
+ int result;
+
+ if (regcomp(®ex, pattern, REG_EXTENDED) != 0)
+ return false;
+
+ result = regexec(®ex, string, 0, NULL, 0);
+ regfree(®ex);
+
+ return result == 0;
+}
+
+
+/*
+ * is_valid_hash - check if the given string is a valid password hash
+ *
+ * Returns true if the string appears to be a valid hash, false otherwise.
+ *
+ * regex from: https://man.archlinux.org/man/crypt.5.en
+ */
+bool
+is_valid_hash(const char *hash)
+{
+ // Minimum hash length
+ if (strlen(hash) < 13)
+ return false;
+
+ // Yescrypt: $y$ + algorithm parameters + $ + salt + $ + 43-char (minimum) hash
+ if (match_regex("^\\$y\\$[./A-Za-z0-9]+\\$[./A-Za-z0-9]{1,86}\\$[./A-Za-z0-9]{43}$", hash))
+ return true;
+
+ // Bcrypt: $2[abxy]$ + 2-digit cost + $ + 53-char hash
+ if (match_regex("^\\$2[abxy]\\$[0-9]{2}\\$[./A-Za-z0-9]{53}$", hash))
+ return true;
+
+ // SHA-512: $6$ + salt + $ + 86-char hash
+ if (match_regex("^\\$6\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\\n]{1,16}\\$[./A-Za-z0-9]{86}$", hash))
+ return true;
+
+ // SHA-256: $5$ + salt + $ + 43-char hash
+ if (match_regex("^\\$5\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\\n]{1,16}\\$[./A-Za-z0-9]{43}$", hash))
+ return true;
+
+ // MD5: $1$ + salt + $ + 22-char hash
+ if (match_regex("^\\$1\\$[^$:\\n]{1,8}\\$[./A-Za-z0-9]{22}$", hash))
+ return true;
+
+ // DES: exactly 13 characters from [A-Za-z0-9./]
+ if (match_regex("^[./A-Za-z0-9]{13}$", hash))
+ return true;
+
+ // Not a valid hash
+ return false;
+}
#include "pam_defs.h"
#endif /* USE_PAM */
#include "atoi/str2i.h"
+#include "chkhash.h"
#include "defines.h"
#include "nscd.h"
#include "sssd.h"
} else
#endif /* USE_PAM */
{
+
+ /*
+ * Prevent adding a non valid hash to /etc/shadow and
+ * potentialy lock account
+ */
+
+ if (eflg) {
+ if (!is_valid_hash(newpwd)) {
+ fprintf (stderr,
+ _("%s: (line %jd, user %s) invalid password hash\n"),
+ Prog, line, name);
+ errors = true;
+ continue;
+ }
+ }
const struct spwd *sp;
struct spwd newsp;
const struct passwd *pw;