+2010-08-17 Thorsten Kukuk <kukuk@thkukuk.de>
+
+ * modules/pam_unix/pam_unix_passwd.c: Implement minlen option.
+ * modules/pam_unix/support.c: Likewise.
+ * modules/pam_unix/support.h: Likewise.
+
+ * modules/pam_unix/pam_unix_acct.c (pam_sm_acct_mgmt): Adjust
+ arguments for _set_ctrl call.
+ * modules/pam_unix/pam_unix_auth.c (pam_sm_authenticate): Likewise.
+ * modules/pam_unix/pam_unix_session.c: Likewise.
+
+ * modules/pam_unix/pam_unix.8.xml: Document minlen option.
+ Based on patch by Steve Langasek.
+
2010-08-12 Thorsten Kukuk <kukuk@thkukuk.de>
* modules/pam_mail/pam_mail.c: Check for mail only with user
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>minlen=<replaceable>n</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ Set a minimum password length of <replaceable>n</replaceable>
+ characters. The max. for DES crypt based passwords are 8
+ characters.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>
Invalid arguments are logged with <citerefentry>
D(("called."));
- ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv);
+ ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
retval = pam_get_item(pamh, PAM_USER, &void_uname);
uname = void_uname;
D(("called."));
- ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv);
+ ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
/* Get a few bytes so we can pass our return value to
pam_sm_setcred(). */
static int _pam_unix_approve_pass(pam_handle_t * pamh
,unsigned int ctrl
,const char *pass_old
- ,const char *pass_new)
+ ,const char *pass_new,
+ int pass_min_len)
{
const void *user;
const char *remark = NULL;
}
}
if (off(UNIX__IAMROOT, ctrl)) {
+ if (strlen(pass_new) < pass_min_len)
+ remark = _("You must choose a longer password");
+ D(("length check [%s]", remark));
if (on(UNIX_REMEMBER_PASSWD, ctrl)) {
if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR)
remark = _("Password has been already used. Choose another.");
int retval;
int remember = -1;
int rounds = -1;
+ int pass_min_len = 0;
/* <DO NOT free() THESE> */
const char *user;
D(("called."));
- ctrl = _set_ctrl(pamh, flags, &remember, &rounds, argc, argv);
+ ctrl = _set_ctrl(pamh, flags, &remember, &rounds, &pass_min_len,
+ argc, argv);
/*
* First get the name of a user
if (*(const char *)pass_new == '\0') { /* "\0" password = NULL */
pass_new = NULL;
}
- retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
+ retval = _pam_unix_approve_pass(pamh, ctrl, pass_old,
+ pass_new, pass_min_len);
if (retval != PAM_SUCCESS && off(UNIX_NOT_SET_PASS, ctrl)) {
pam_set_item(pamh, PAM_AUTHTOK, NULL);
return retval;
}
- retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
+ retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new,
+ pass_min_len);
if (retval != PAM_SUCCESS) {
pam_syslog(pamh, LOG_NOTICE,
"new password not acceptable 2");
D(("called."));
- ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv);
+ ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
retval = pam_get_item(pamh, PAM_USER, (void *) &user_name);
if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) {
D(("called."));
- ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv);
+ ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
retval = pam_get_item(pamh, PAM_USER, (void *) &user_name);
if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) {
*/
int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds,
- int argc, const char **argv)
+ int *pass_min_len, int argc, const char **argv)
{
unsigned int ctrl;
ctrl &= unix_args[j].mask; /* for turning things off */
ctrl |= unix_args[j].flag; /* for turning things on */
- if (remember != NULL) {
- if (j == UNIX_REMEMBER_PASSWD) {
- *remember = strtol(*argv + 9, NULL, 10);
- if ((*remember == INT_MIN) || (*remember == INT_MAX))
- *remember = -1;
- if (*remember > 400)
- *remember = 400;
- }
- }
+ /* special cases */
+ if (remember != NULL && j == UNIX_REMEMBER_PASSWD) {
+ *remember = strtol(*argv + 9, NULL, 10);
+ if ((*remember == INT_MIN) || (*remember == INT_MAX))
+ *remember = -1;
+ if (*remember > 400)
+ *remember = 400;
+ } else if (pass_min_len && j == UNIX_MIN_PASS_LEN) {
+ *pass_min_len = atoi(*argv + 7);
+ }
if (rounds != NULL && j == UNIX_ALGO_ROUNDS)
*rounds = strtol(*argv + 7, NULL, 10);
}
++argv; /* step to next argument */
}
+ if (UNIX_DES_CRYPT(ctrl)
+ && pass_min_len && *pass_min_len > 8)
+ {
+ pam_syslog (pamh, LOG_NOTICE, "Password minlen reset to 8 characters");
+ *pass_min_len = 8;
+ }
+
if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
D(("DISALLOW_NULL_AUTHTOK"));
set(UNIX__NONULL, ctrl);
* information during acct management */
#define UNIX_SHA256_PASS 23 /* new password hashes will use SHA256 */
#define UNIX_SHA512_PASS 24 /* new password hashes will use SHA512 */
-#define UNIX_ALGO_ROUNDS 25 /* optional number of rounds for new
+#define UNIX_ALGO_ROUNDS 25 /* optional number of rounds for new
password hash algorithms */
#define UNIX_BLOWFISH_PASS 26 /* new password hashes will use blowfish */
+#define UNIX_MIN_PASS_LEN 27 /* min length for password */
/* -------------- */
-#define UNIX_CTRLS_ 27 /* number of ctrl arguments defined */
+#define UNIX_CTRLS_ 28 /* number of ctrl arguments defined */
+
+#define UNIX_DES_CRYPT(ctrl) (off(UNIX_MD5_PASS,ctrl)&&off(UNIX_BIGCRYPT,ctrl)&&off(UNIX_SHA256_PASS,ctrl)&&off(UNIX_SHA512_PASS,ctrl)&&off(UNIX_BLOWFISH_PASS,ctrl))
static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
{
/* UNIX_SHA512_PASS */ {"sha512", _ALL_ON_^(0260420000), 040000000},
/* UNIX_ALGO_ROUNDS */ {"rounds=", _ALL_ON_, 0100000000},
/* UNIX_BLOWFISH_PASS */ {"blowfish", _ALL_ON_^(0260420000), 0200000000},
+/* UNIX_MIN_PASS_LEN */ {"minlen=", _ALL_ON_, 0400000000},
};
#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl
,int type, const char *text);
extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int *rounds,
- int argc, const char **argv);
+ int *pass_min_len, int argc, const char **argv);
extern int _unix_getpwnam (pam_handle_t *pamh,
const char *name, int files, int nis,
struct passwd **ret);