crypt_make_salt to force the crypt method and number of rounds.
* libmisc/salt.c: Add parameter to SHA_salt_rounds to force the
number of rounds.
* libmisc/salt.c, lib/getdef.c: ENCRYPT_METHOD and MD5_CRYPT_ENAB
are needed also when USE_PAM (e.g. for chpasswd).
* src/newusers.c, src/gpasswd.c: Use the new crypt_make_salt prototype.
* src/chpasswd.c, src/chgpasswd.c: Add option -c, --crypt-method
and -s, --sha-rounds to specify the crypt method and number of
rounds in case of one of the SHA methods. The new prototype of
crypt_make_salt simplifies the handling of -m, --md5.
+2007-11-20 Nicolas François <nicolas.francois@centraliens.net>
+
+ * lib/prototypes.h, libmisc/salt.c: Add parameters to
+ crypt_make_salt to force the crypt method and number of rounds.
+ * libmisc/salt.c: Add parameter to SHA_salt_rounds to force the
+ number of rounds.
+ * libmisc/salt.c, lib/getdef.c: ENCRYPT_METHOD and MD5_CRYPT_ENAB
+ are needed also when USE_PAM (e.g. for chpasswd).
+ * src/newusers.c, src/gpasswd.c: Use the new crypt_make_salt prototype
+ * src/chpasswd.c, src/chgpasswd.c: Add option -c, --crypt-method
+ and -s, --sha-rounds to specify the crypt method and number of
+ rounds in case of one of the SHA methods. The new prototype of
+ crypt_make_salt simplifies the handling of -m, --md5.
+
2007-11-19 Nicolas François <nicolas.francois@centraliens.net>
* libmisc/salt.c: The salt has a random size (between 8 and 16
{"CONSOLE", NULL},
{"CREATE_HOME", NULL},
{"DEFAULT_HOME", NULL},
+ {"ENCRYPT_METHOD", NULL},
{"ENV_PATH", NULL},
{"ENV_SUPATH", NULL},
{"ERASECHAR", NULL},
{"LOG_UNKFAIL_ENAB", NULL},
{"MAIL_DIR", NULL},
{"MAIL_FILE", NULL},
+ {"MD5_CRYPT_ENAB", NULL},
{"PASS_MAX_DAYS", NULL},
{"PASS_MIN_DAYS", NULL},
{"PASS_WARN_AGE", NULL},
+ {"SHA_CRYPT_MAX_ROUNDS", NULL},
+ {"SHA_CRYPT_MIN_ROUNDS", NULL},
{"SULOG_FILE", NULL},
{"SU_NAME", NULL},
{"TTYGROUP", NULL},
{"CHFN_AUTH", NULL},
{"CHSH_AUTH", NULL},
{"CRACKLIB_DICTPATH", NULL},
- {"ENCRYPT_METHOD", NULL},
{"ENV_HZ", NULL},
{"ENVIRON_FILE", NULL},
{"ENV_TZ", NULL},
{"LASTLOG_ENAB", NULL},
{"LOGIN_STRING", NULL},
{"MAIL_CHECK_ENAB", NULL},
- {"MD5_CRYPT_ENAB", NULL},
{"MOTD_FILE", NULL},
{"NOLOGINS_FILE", NULL},
{"OBSCURE_CHECKS_ENAB", NULL},
{"PASS_MIN_LEN", NULL},
{"PORTTIME_CHECKS_ENAB", NULL},
{"QUOTAS_ENAB", NULL},
- {"SHA_CRYPT_MAX_ROUNDS", NULL},
- {"SHA_CRYPT_MIN_ROUNDS", NULL},
{"SU_WHEEL_ONLY", NULL},
{"ULIMIT", NULL},
#endif
extern int do_rlogin (const char *, char *, int, char *, int);
/* salt.c */
-extern char *crypt_make_salt (void);
+extern char *crypt_make_salt (char *meth, void *arg);
/* setugid.c */
extern int setup_groups (const struct passwd *);
/*
* Return a salt prefix specifying the rounds number for the SHA crypt methods.
*/
-static char *SHA_salt_rounds (void)
+static char *SHA_salt_rounds (int *prefered_rounds)
{
- static char *rounds_prefix[18];
- long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
- long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
+ static char rounds_prefix[18];
long rounds;
- if (-1 == min_rounds && -1 == max_rounds)
- return "";
+ if (NULL == prefered_rounds) {
+ long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
+ long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
- if (-1 == min_rounds)
- min_rounds = max_rounds;
+ if (-1 == min_rounds && -1 == max_rounds)
+ return "";
- if (-1 == max_rounds)
- max_rounds = min_rounds;
+ if (-1 == min_rounds)
+ min_rounds = max_rounds;
- if (min_rounds > max_rounds)
- max_rounds = min_rounds;
+ if (-1 == max_rounds)
+ max_rounds = min_rounds;
- srand (time (NULL));
- rounds = min_rounds +
- (double)rand () * (max_rounds-min_rounds+1)/RAND_MAX;
+ if (min_rounds > max_rounds)
+ max_rounds = min_rounds;
+
+ srand (time (NULL));
+ rounds = min_rounds +
+ (double)rand () * (max_rounds-min_rounds+1)/RAND_MAX;
+ } else if (0 == *prefered_rounds)
+ return "";
/* Sanity checks. The libc should also check this, but this
* protects against a rounds_prefix overflow. */
* (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible
* version of crypt() instead of the standard one.
* Other methods can be set with ENCRYPT_METHOD
+ *
+ * The method can be forced with the meth parameter.
+ * If NULL, the method will be defined according to the MD5_CRYPT_ENAB and
+ * ENCRYPT_METHOD login.defs variables.
+ *
+ * If meth is specified, an additional parameter can be provided.
+ * * For the SHA256 and SHA512 method, this specifies the number of rounds
+ * (if not NULL).
*/
-char *crypt_make_salt (void)
+char *crypt_make_salt (char *meth, void *arg)
{
struct timeval tv;
/* Max result size for the SHA methods:
*/
static char result[40];
int max_salt_len = 8;
- char *method;
+ char *method = "DES";
result[0] = '\0';
-#ifndef USE_PAM
+ if (NULL != meth)
+ method = meth;
+ else
#ifdef ENCRYPTMETHOD_SELECT
- if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL) {
+ if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL)
#endif
- if (getdef_bool ("MD5_CRYPT_ENAB")) {
- MAGNUM(result,'1');
- max_salt_len = 11;
- }
+ if (getdef_bool ("MD5_CRYPT_ENAB"))
+ method = "MD5";
+
+ if (!strncmp (method, "MD5", 3)) {
+ MAGNUM(result, '1');
+ max_salt_len = 11;
#ifdef ENCRYPTMETHOD_SELECT
- } else {
- if (!strncmp (method, "MD5", 3)) {
- MAGNUM(result, '1');
- max_salt_len = 11;
- } else if (!strncmp (method, "SHA256", 6)) {
- MAGNUM(result, '5');
- strcat(result, SHA_salt_rounds());
- max_salt_len = strlen(result) + SHA_salt_size();
- } else if (!strncmp (method, "SHA512", 6)) {
- MAGNUM(result, '6');
- strcat(result, SHA_salt_rounds());
- max_salt_len = strlen(result) + SHA_salt_size();
- } else if (0 != strncmp (method, "DES", 3)) {
- fprintf (stderr,
- _("Invalid ENCRYPT_METHOD value: '%s'.\n"
- "Defaulting to DES.\n"),
- method);
- result[0] = '\0';
- }
+ } else if (!strncmp (method, "SHA256", 6)) {
+ MAGNUM(result, '5');
+ strcat(result, SHA_salt_rounds((int *)arg));
+ max_salt_len = strlen(result) + SHA_salt_size();
+ } else if (!strncmp (method, "SHA512", 6)) {
+ MAGNUM(result, '6');
+ strcat(result, SHA_salt_rounds((int *)arg));
+ max_salt_len = strlen(result) + SHA_salt_size();
+#endif
+ } else if (0 != strncmp (method, "DES", 3)) {
+ fprintf (stderr,
+ _("Invalid ENCRYPT_METHOD value: '%s'.\n"
+ "Defaulting to DES.\n"),
+ method);
+ result[0] = '\0';
}
-#endif /* ENCRYPTMETHOD_SELECT */
-#endif /* USE_PAM */
/*
* Concatenate a pseudo random salt.
* Global variables
*/
static char *Prog;
+static int cflg = 0;
static int eflg = 0;
static int md5flg = 0;
+static int sflg = 0;
+
+static char *crypt_method = NULL;
+static int sha_rounds = 5000;
#ifdef SHADOWGRP
static int is_shadow_grp;
fprintf (stderr, _("Usage: chgpasswd [options]\n"
"\n"
"Options:\n"
+ " -c, --crypt-method the crypt method (one of %s)\n"
" -e, --encrypted supplied passwords are encrypted\n"
" -h, --help display this help message and exit\n"
" -m, --md5 use MD5 encryption instead DES when the supplied\n"
" passwords are not encrypted\n"
- "\n"));
+ "\n"),
+#ifndef ENCRYPTMETHOD_SELECT
+ "DES MD5"
+#else
+ "DES MD5 SHA256 SHA512"
+#endif
+ );
exit (1);
}
+static long getnumber (const char *numstr)
+{
+ long val;
+ char *errptr;
+
+ val = strtol (numstr, &errptr, 10);
+ if (*errptr || errno == ERANGE) {
+ fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog,
+ numstr);
+ exit (1);
+ }
+
+ return val;
+}
+
int main (int argc, char **argv)
{
char buf[BUFSIZ];
int option_index = 0;
int c;
static struct option long_options[] = {
+ {"crypt-method", required_argument, NULL, 'c'},
{"encrypted", no_argument, NULL, 'e'},
{"help", no_argument, NULL, 'h'},
{"md5", no_argument, NULL, 'm'},
+ {"sha-rounds", required_argument, NULL, 's'},
{NULL, 0, NULL, '\0'}
};
while ((c =
- getopt_long (argc, argv, "ehm", long_options,
+ getopt_long (argc, argv, "c:ehms:", long_options,
&option_index)) != -1) {
switch (c) {
+ case 'c':
+ cflg = 1;
+ crypt_method = optarg;
+ break;
case 'e':
eflg = 1;
break;
case 'm':
md5flg = 1;
break;
+ case 's':
+ sflg = 1;
+ sha_rounds = getnumber(optarg);
+ break;
case 0:
/* long option */
break;
}
}
+ /* validate options */
+ if (sflg && !cflg) {
+ fprintf (stderr,
+ _("%s: %s flag is ONLY allowed with the %s flag\n"),
+ Prog, "-s", "-c");
+ usage ();
+ }
+ if (md5flg && cflg) {
+ fprintf (stderr,
+ _("%s: the -m and -c flags are exclusive\n"),
+ Prog);
+ usage ();
+ }
+ if (cflg) {
+ if (0 != strcmp (method, "DES") &&
+ 0 != strcmp (method, "MD5") &&
+#ifdef ENCRYPTMETHOD_SELECT
+ 0 != strcmp (method, "SHA256") &&
+ 0 != strcmp (method, "SHA512")
+#endif
+ ) {
+ fprintf (stderr,
+ _("%s: unsupported crypt method: %s\n"),
+ Prog, method);
+ usage ();
+ }
+ }
+
#ifdef USE_PAM
retval = PAM_SUCCESS;
}
newpwd = cp;
if (!eflg) {
- if (md5flg) {
- char md5salt[12] = "$1$";
- char *salt = crypt_make_salt ();
-
- if (strncmp (salt, "$1$", 3) == 0) {
- strncpy (md5salt, salt, 11);
- } else {
- strncat (md5salt, salt, 8);
- }
- cp = pw_encrypt (newpwd, md5salt);
+ void *arg = NULL;
+ if (md5flg)
+ crypt_method = "MD5";
+ else if (crypt_method != NULL) {
+ if (sflg)
+ arg = &sha_rounds;
} else
- cp = pw_encrypt (newpwd, crypt_make_salt ());
+ crypt_method = "DES";
+ cp = pw_encrypt (newpwd,
+ crypt_make_salt(crypt_method, arg));
}
/*
* Global variables
*/
static char *Prog;
+static int cflg = 0;
static int eflg = 0;
static int md5flg = 0;
+static int sflg = 0;
+
+static char *crypt_method = NULL;
+static int sha_rounds = 5000;
static int is_shadow_pwd;
fprintf (stderr, _("Usage: chpasswd [options]\n"
"\n"
"Options:\n"
+ " -c, --crypt-method the crypt method (one of %s)\n"
" -e, --encrypted supplied passwords are encrypted\n"
" -h, --help display this help message and exit\n"
" -m, --md5 use MD5 encryption instead DES when the supplied\n"
" passwords are not encrypted\n"
- "\n"));
+ "\n"),
+#ifndef ENCRYPTMETHOD_SELECT
+ "DES MD5"
+#else
+ "DES MD5 SHA256 SHA512"
+#endif
+ );
exit (E_USAGE);
}
+static long getnumber (const char *numstr)
+{
+ long val;
+ char *errptr;
+
+ val = strtol (numstr, &errptr, 10);
+ if (*errptr || errno == ERANGE) {
+ fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog,
+ numstr);
+ exit (1);
+ }
+
+ return val;
+}
+
int main (int argc, char **argv)
{
char buf[BUFSIZ];
int option_index = 0;
int c;
static struct option long_options[] = {
+ {"crypt-method", required_argument, NULL, 'c'},
{"encrypted", no_argument, NULL, 'e'},
{"help", no_argument, NULL, 'h'},
{"md5", no_argument, NULL, 'm'},
+ {"sha-rounds", required_argument, NULL, 's'},
{NULL, 0, NULL, '\0'}
};
while ((c =
- getopt_long (argc, argv, "ehm", long_options,
+ getopt_long (argc, argv, "c:ehms:", long_options,
&option_index)) != -1) {
switch (c) {
+ case 'c':
+ cflg = 1;
+ crypt_method = optarg;
+ break;
case 'e':
eflg = 1;
break;
case 'm':
md5flg = 1;
break;
+ case 's':
+ sflg = 1;
+ sha_rounds = getnumber(optarg);
+ break;
case 0:
/* long option */
break;
}
}
+ /* validate options */
+ if (sflg && !cflg) {
+ fprintf (stderr,
+ _("%s: %s flag is ONLY allowed with the %s flag\n"),
+ Prog, "-s", "-c");
+ usage ();
+ }
+ if (md5flg && cflg) {
+ fprintf (stderr,
+ _("%s: the -m and -c flags are exclusive\n"),
+ Prog);
+ usage ();
+ }
+ if (cflg) {
+ if (0 != strcmp (method, "DES") &&
+ 0 != strcmp (method, "MD5") &&
+#ifdef ENCRYPTMETHOD_SELECT
+ 0 != strcmp (method, "SHA256") &&
+ 0 != strcmp (method, "SHA512")
+#endif
+ ) {
+ fprintf (stderr,
+ _("%s: unsupported crypt method: %s\n"),
+ Prog, method);
+ usage ();
+ }
+ }
+
#ifdef USE_PAM
retval = PAM_SUCCESS;
}
newpwd = cp;
if (!eflg) {
- if (md5flg) {
- char md5salt[12] = "$1$";
- char *salt = crypt_make_salt ();
-
- if (strncmp (salt, "$1$", 3) == 0) {
- strncpy (md5salt, salt, 11);
- } else {
- strncat (md5salt, salt, 8);
- }
- cp = pw_encrypt (newpwd, salt);
+ void *arg = NULL;
+ if (md5flg)
+ crypt_method = "MD5";
+ else if (crypt_method != NULL) {
+ if (sflg)
+ arg = &sha_rounds;
} else
- cp = pw_encrypt (newpwd, crypt_make_salt ());
+ crypt_method = "DES";
+ cp = pw_encrypt (newpwd,
+ crypt_make_salt(crypt_method, arg));
}
/*
exit (1);
}
- cp = pw_encrypt (pass, crypt_make_salt ());
+ cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
memzero (pass, sizeof pass);
#ifdef SHADOWGRP
if (is_shadowgrp)
static void update_passwd (struct passwd *pwd, const char *passwd)
{
- pwd->pw_passwd = pw_encrypt (passwd, crypt_make_salt ());
+ pwd->pw_passwd = pw_encrypt (passwd, crypt_make_salt (NULL, NULL));
}
/*
*/
if ((sp = spw_locate (pwd->pw_name))) {
spent = *sp;
- spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt ());
+ spent.sp_pwdp = pw_encrypt (passwd,
+ crypt_make_salt (NULL, NULL));
return !spw_update (&spent);
}
* shadow password file entry.
*/
spent.sp_namp = pwd->pw_name;
- spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt ());
+ spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt (NULL, NULL));
spent.sp_lstchg = time ((time_t *) 0) / SCALE;
spent.sp_min = getdef_num ("PASS_MIN_DAYS", 0);
/* 10000 is infinity this week */