* column description
*/
struct lslogins_coldesc {
- const char *name;
+ const char * const name;
const char *help;
const char *pretty_name;
{
[COL_USER] = { "USER", N_("user name"), N_("Username"), 0.1, SCOLS_FL_NOEXTREMES },
[COL_UID] = { "UID", N_("user ID"), "UID", 1, SCOLS_FL_RIGHT},
- [COL_PWDEMPTY] = { "PWD-EMPTY", N_("password not required"), N_("Password not required"), 1, SCOLS_FL_RIGHT },
+ [COL_PWDEMPTY] = { "PWD-EMPTY", N_("password not defined"), N_("Password not required (empty)"), 1, SCOLS_FL_RIGHT },
[COL_PWDDENY] = { "PWD-DENY", N_("login by password disabled"), N_("Login by password disabled"), 1, SCOLS_FL_RIGHT },
[COL_PWDLOCK] = { "PWD-LOCK", N_("password defined, but locked"), N_("Password is locked"), 1, SCOLS_FL_RIGHT },
[COL_PWDMETHOD] = { "PWD-METHOD", N_("password encryption method"), N_("Password encryption method"), 0.1 },
static int parse_utmpx(const char *path, size_t *nrecords, struct utmpx **records)
{
- size_t i, imax = 0;
+ size_t i, imax = 1;
struct utmpx *ary = NULL;
struct stat st;
/* optimize allocation according to file size, the realloc() below is
* just fallback only */
- if (stat(path, &st) == 0 && (size_t) st.st_size > sizeof(struct utmpx)) {
+ if (stat(path, &st) == 0 && (size_t) st.st_size >= sizeof(struct utmpx)) {
imax = st.st_size / sizeof(struct utmpx);
- ary = xmalloc(imax * sizeof(struct utmpx));
+ ary = xreallocarray(NULL, imax, sizeof(struct utmpx));
}
for (i = 0; ; i++) {
break;
}
if (i == imax)
- ary = xrealloc(ary, (imax *= 2) * sizeof(struct utmpx));
+ ary = xreallocarray(ary, imax *= 2, sizeof(struct utmpx));
ary[i] = *u;
}
}
#endif
-static const char *get_pwd_method(const char *str, const char **next, unsigned int *sz)
+static const char *get_pwd_method(const char *str, const char **next)
{
const char *p = str;
const char *res = NULL;
if (!p || *p++ != '$')
return NULL;
- if (sz)
- *sz = 0;
-
switch (*p) {
case '1':
res = "MD5";
- if (sz)
- *sz = 22;
break;
case '2':
- p++;
- if (*p == 'a' || *p == 'y')
+ switch(*(p+1)) {
+ case 'a':
+ case 'y':
+ p++;
res = "Blowfish";
+ break;
+ case 'b':
+ p++;
+ res = "bcrypt";
+ break;
+ }
+ break;
+ case '3':
+ res = "NT";
break;
case '5':
res = "SHA-256";
- if (sz)
- *sz = 43;
break;
case '6':
res = "SHA-512";
- if (sz)
- *sz = 86;
+ break;
+ case '7':
+ res = "scrypt";
+ break;
+ case 'y':
+ res = "yescrypt";
+ break;
+ case 'g':
+ if (*(p + 1) == 'y') {
+ p++;
+ res = "gost-yescrypt";
+ }
+ break;
+ case '_':
+ res = "bsdicrypt";
break;
default:
- return NULL;
+ res = "unknown";
+ break;
}
p++;
return res;
}
-#define is_valid_pwd_char(x) (isalnum((unsigned char) (x)) || (x) == '.' || (x) == '/')
+#define is_invalid_pwd_char(x) (isspace((unsigned char) (x)) || \
+ (x) == ':' || (x) == ';' || (x) == '*' || \
+ (x) == '!' || (x) == '\\')
+#define is_valid_pwd_char(x) (isascii((unsigned char) (x)) && !is_invalid_pwd_char(x))
/*
* This function do not accept empty passwords or locked accouns.
static int valid_pwd(const char *str)
{
const char *p = str;
- unsigned int sz = 0, n;
if (!str || !*str)
return 0;
/* $id$ */
- if (get_pwd_method(str, &p, &sz) == NULL)
+ if (get_pwd_method(str, &p) == NULL)
return 0;
+
if (!p || !*p)
return 0;
-
/* salt$ */
for (; *p; p++) {
if (*p == '$') {
if (!is_valid_pwd_char(*p))
return 0;
}
+
if (!*p)
return 0;
-
/* encrypted */
- for (n = 0; *p; p++, n++) {
- if (!is_valid_pwd_char(*p))
+ for (; *p; p++) {
+ if (!is_valid_pwd_char(*p)) {
return 0;
+ }
}
-
- if (sz && n != sz)
- return 0;
return 1;
}
break;
case COL_PWDEMPTY:
if (shadow) {
- if (!*shadow->sp_pwdp) /* '\0' */
+ const char *p = shadow->sp_pwdp;
+
+ while (p && (*p == '!' || *p == '*'))
+ p++;
+
+ if (!p || !*p)
user->pwd_empty = STATUS_TRUE;
} else
user->pwd_empty = STATUS_UNKNOWN;
break;
case COL_PWDDENY:
if (shadow) {
- if ((*shadow->sp_pwdp == '!' ||
- *shadow->sp_pwdp == '*') &&
- !valid_pwd(shadow->sp_pwdp + 1))
+ const char *p = shadow->sp_pwdp;
+
+ while (p && (*p == '!' || *p == '*'))
+ p++;
+
+ if (p && *p && p != shadow->sp_pwdp && !valid_pwd(p))
user->pwd_deny = STATUS_TRUE;
} else
user->pwd_deny = STATUS_UNKNOWN;
break;
case COL_PWDLOCK:
if (shadow) {
- if (*shadow->sp_pwdp == '!' && valid_pwd(shadow->sp_pwdp + 1))
+ const char *p = shadow->sp_pwdp;
+ int i = 0;
+
+ /* 'passwd --lock' uses two exclamation marks,
+ * shadow(5) describes the lock as "field which
+ * starts with an exclamation mark". Let's
+ * support more '!' ...
+ */
+ while (p && *p == '!')
+ p++, i++;
+
+ if (i != 0 && (!*p || valid_pwd(p)))
user->pwd_lock = STATUS_TRUE;
} else
user->pwd_lock = STATUS_UNKNOWN;
if (shadow) {
const char *p = shadow->sp_pwdp;
- if (*p == '!' || *p == '*')
+ while (p && (*p == '!' || *p == '*'))
p++;
- user->pwd_method = get_pwd_method(p, NULL, NULL);
+ user->pwd_method = get_pwd_method(p, NULL);
} else
user->pwd_method = NULL;
break;
(*ar)[i++] = xstrdup(u);
if (i == *arsiz)
- *ar = xrealloc(*ar, sizeof(char *) * (*arsiz += 32));
+ *ar = xreallocarray(*ar, *arsiz += 32, sizeof(char *));
}
ctl->ulist_on = 1;
}
(*ar)[i++] = xstrdup(u);
if (i == *arsiz)
- *ar = xrealloc(*ar, sizeof(char *) * (*arsiz += 32));
+ *ar = xreallocarray(*ar, *arsiz += 32, sizeof(char *));
}
}
ctl->ulist_on = 1;
{
size_t n = 0;
+ if (!ctl)
+ return;
+
free(ctl->wtmp);
free(ctl->btmp);
fputs(_(" --btmp-file <path> set an alternate path for btmp\n"), out);
fputs(_(" --lastlog <path> set an alternate path for lastlog\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf(USAGE_HELP_OPTIONS(26));
+ fprintf(out, USAGE_HELP_OPTIONS(26));
fputs(USAGE_COLUMNS, out);
for (i = 0; i < ARRAY_SIZE(coldescs); i++)
fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help));
- printf(USAGE_MAN_TAIL("lslogins(1)"));
+ fprintf(out, USAGE_MAN_TAIL("lslogins(1)"));
exit(EXIT_SUCCESS);
}