#define UL_UID_MIN 1000
#define UL_UID_MAX 60000
-#define UL_SYS_UID_MIN 201
+#define UL_SYS_UID_MIN 101
#define UL_SYS_UID_MAX 999
/* we use the value of outmode to determine
char *pwd_expire;
char *pwd_ctime_min;
char *pwd_ctime_max;
+ const char *pwd_method;
char *last_login;
char *last_tty;
COL_PWDLOCK,
COL_PWDEMPTY,
COL_PWDDENY,
+ COL_PWDMETHOD,
COL_GROUP,
COL_GID,
COL_SGROUPS,
[COL_PWDEMPTY] = { "PWD-EMPTY", N_("password not required"), N_("Password not required"), 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 },
[COL_NOLOGIN] = { "NOLOGIN", N_("log in disabled by nologin(8) or pam_nologin(8)"), N_("No login"), 1, SCOLS_FL_RIGHT },
[COL_GROUP] = { "GROUP", N_("primary group name"), N_("Primary group"), 0.1 },
[COL_GID] = { "GID", N_("primary group ID"), "GID", 1, SCOLS_FL_RIGHT },
const char *journal_path;
unsigned int selinux_enabled : 1,
+ fail_on_unknown : 1, /* fail if user does not exist */
ulist_on : 1,
noheadings : 1,
notrunc : 1;
* column twice. That's enough, dynamically allocated array of the columns is
* unnecessary overkill and over-engineering in this case */
static int columns[ARRAY_SIZE(coldescs) * 2];
-static int ncolumns;
+static size_t ncolumns;
static inline size_t err_columns_index(size_t arysz, size_t idx)
{
buf, sizeof(buf));
break;
case TIME_ISO:
- rc = strtime_iso(&time, ISO_8601_DATE|ISO_8601_TIME|ISO_8601_TIMEZONE,
- buf, sizeof(buf));
+ rc = strtime_iso(&time, ISO_TIMESTAMP_T, buf, sizeof(buf));
break;
case TIME_ISO_SHORT:
- rc = strtime_iso(&time, ISO_8601_DATE, buf, sizeof(buf));
+ rc = strtime_iso(&time, ISO_DATE, buf, sizeof(buf));
break;
default:
errx(EXIT_FAILURE, _("unsupported time type"));
static int require_wtmp(void)
{
size_t i;
- for (i = 0; i < (size_t) ncolumns; i++)
+ for (i = 0; i < ncolumns; i++)
if (is_wtmp_col(columns[i]))
return 1;
return 0;
static int require_btmp(void)
{
size_t i;
- for (i = 0; i < (size_t) ncolumns; i++)
+ for (i = 0; i < ncolumns; i++)
if (is_btmp_col(columns[i]))
return 1;
return 0;
return nprocs;
}
+static const char *get_pwd_method(const char *str, const char **next, unsigned int *sz)
+{
+ 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')
+ res = "Blowfish";
+ break;
+ case '5':
+ res = "SHA-256";
+ if (sz)
+ *sz = 43;
+ break;
+ case '6':
+ res = "SHA-512";
+ if (sz)
+ *sz = 86;
+ break;
+ default:
+ return NULL;
+ }
+ p++;
+
+ if (*p != '$')
+ return NULL;
+ if (next)
+ *next = ++p;
+ return res;
+}
+
+#define is_valid_pwd_char(x) (isalnum((unsigned char) (x)) || (x) == '.' || (x) == '/')
+
+/*
+ * This function do not accept empty passwords or locked accouns.
+ */
static int valid_pwd(const char *str)
{
- const char *p;
+ const char *p = str;
+ unsigned int sz = 0, n;
+
+ if (!str || !*str)
+ return 0;
+
+ /* $id$ */
+ if (get_pwd_method(str, &p, &sz) == NULL)
+ return 0;
+ if (!p || !*p)
+ return 0;
+
+ /* salt$ */
+ for (; *p; p++) {
+ if (*p == '$') {
+ p++;
+ break;
+ }
+ if (!is_valid_pwd_char(*p))
+ return 0;
+ }
+ if (!*p)
+ return 0;
- for (p = str; p && *p; p++)
- if (!isalnum((unsigned char) *p))
+ /* encrypted */
+ for (n = 0; *p; p++, n++) {
+ if (!is_valid_pwd_char(*p))
return 0;
- return p > str ? 1 : 0;
+ }
+
+ if (sz && n != sz)
+ return 0;
+ return 1;
}
static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const char *username)
struct group *grp;
struct spwd *shadow;
struct utmpx *user_wtmp = NULL, *user_btmp = NULL;
- int n = 0;
+ size_t n = 0;
time_t time;
uid_t uid;
errno = 0;
+ errno = 0;
pwd = username ? getpwnam(username) : getpwent();
if (!pwd)
return NULL;
return NULL;
}
- user = xcalloc(1, sizeof(struct lslogins_user));
-
+ errno = 0;
grp = getgrgid(pwd->pw_gid);
if (!grp)
return NULL;
+ user = xcalloc(1, sizeof(struct lslogins_user));
+
if (ctl->wtmp)
user_wtmp = get_last_wtmp(ctl, pwd->pw_name);
if (ctl->btmp)
} else
user->pwd_deny = STATUS_UNKNOWN;
break;
-
case COL_PWDLOCK:
if (shadow) {
if (*shadow->sp_pwdp == '!' && valid_pwd(shadow->sp_pwdp + 1))
} else
user->pwd_lock = STATUS_UNKNOWN;
break;
+ case COL_PWDMETHOD:
+ if (shadow) {
+ const char *p = shadow->sp_pwdp;
+
+ if (*p == '!' || *p == '*')
+ p++;
+ user->pwd_method = get_pwd_method(p, NULL, NULL);
+ } else
+ user->pwd_method = NULL;
+ break;
case COL_NOLOGIN:
if (strstr(pwd->pw_shell, "nologin"))
user->nologin = 1;
static int cmp_uid(const void *a, const void *b)
{
- uid_t x = ((struct lslogins_user *)a)->uid;
- uid_t z = ((struct lslogins_user *)b)->uid;
+ uid_t x = ((const struct lslogins_user *)a)->uid;
+ uid_t z = ((const struct lslogins_user *)b)->uid;
return x > z ? 1 : (x < z ? -1 : 0);
}
size_t n = 0;
if (ctl->ulist_on) {
- while (n < ctl->ulsiz) {
- if (get_user(ctl, &user, ctl->ulist[n]))
+ for (n = 0; n < ctl->ulsiz; n++) {
+ int rc = get_user(ctl, &user, ctl->ulist[n]);
+
+ if (ctl->fail_on_unknown && !user) {
+ warnx(_("cannot found '%s'"), ctl->ulist[n]);
return -1;
- if (user) /* otherwise an invalid user name has probably been given */
- tsearch(user, &ctl->usertree, cmp_uid);
- ++n;
+ }
+ if (rc || !user)
+ continue;
+
+ tsearch(user, &ctl->usertree, cmp_uid);
}
} else {
while ((user = get_next_user(ctl)))
static struct libscols_table *setup_table(struct lslogins_control *ctl)
{
struct libscols_table *table = scols_new_table();
- int n = 0;
+ size_t n = 0;
if (!table)
err(EXIT_FAILURE, _("failed to allocate output table"));
static void fill_table(const void *u, const VISIT which, const int depth __attribute__((unused)))
{
struct libscols_line *ln;
- struct lslogins_user *user = *(struct lslogins_user **)u;
- int n = 0;
+ const struct lslogins_user *user = *(struct lslogins_user * const *)u;
+ size_t n = 0;
if (which == preorder || which == endorder)
return;
case COL_PWDDENY:
rc = scols_line_set_data(ln, n, get_status(user->pwd_deny));
break;
+ case COL_PWDMETHOD:
+ rc = scols_line_set_data(ln, n, user->pwd_method);
+ break;
case COL_GROUP:
rc = scols_line_set_data(ln, n, user->group);
break;
size_t i;
fputs(USAGE_HEADER, out);
- fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
+ fprintf(out, _(" %s [options] [<username>]\n"), program_invocation_short_name);
fputs(USAGE_SEPARATOR, out);
fputs(_("Display information about known users in the system.\n"), out);
fputs(_(" --noheadings don't print headings\n"), out);
fputs(_(" --notruncate don't truncate output\n"), out);
fputs(_(" -o, --output[=<list>] define the columns to output\n"), out);
+ fputs(_(" --output-all output all columns\n"), out);
fputs(_(" -p, --pwd display information related to login by password.\n"), out);
fputs(_(" -r, --raw display in raw mode\n"), out);
fputs(_(" -s, --system-accs display system accounts\n"), out);
fputs(_(" --wtmp-file <path> set an alternate path for wtmp\n"), out);
fputs(_(" --btmp-file <path> set an alternate path for btmp\n"), out);
fputs(USAGE_SEPARATOR, out);
- fputs(USAGE_HELP, out);
- fputs(USAGE_VERSION, out);
+ printf(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));
- fprintf(out, USAGE_MAN_TAIL("lslogins(1)"));
+ printf(USAGE_MAN_TAIL("lslogins(1)"));
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
- int c, opt_o = 0;
- char *logins = NULL, *groups = NULL;
+ int c;
+ char *logins = NULL, *groups = NULL, *outarg = NULL;
char *path_wtmp = _PATH_WTMP, *path_btmp = _PATH_BTMP;
struct lslogins_control *ctl = xcalloc(1, sizeof(struct lslogins_control));
size_t i;
OPT_NOTRUNC,
OPT_NOHEAD,
OPT_TIME_FMT,
+ OPT_OUTPUT_ALL,
};
static const struct option longopts[] = {
{ "notruncate", no_argument, 0, OPT_NOTRUNC },
{ "noheadings", no_argument, 0, OPT_NOHEAD },
{ "output", required_argument, 0, 'o' },
+ { "output-all", no_argument, 0, OPT_OUTPUT_ALL },
{ "last", no_argument, 0, 'L', },
{ "raw", no_argument, 0, 'r' },
{ "system-accs", no_argument, 0, 's' },
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- atexit(close_stdout);
+ close_stdout_atexit();
ctl->time_mode = TIME_SHORT;
case 'o':
if (*optarg == '=')
optarg++;
- ncolumns = string_to_idarray(optarg, columns,
- ARRAY_SIZE(columns), column_name_to_id);
- if (ncolumns < 0)
- return EXIT_FAILURE;
- opt_o = 1;
+ outarg = optarg;
+ break;
+ case OPT_OUTPUT_ALL:
+ for (ncolumns = 0; ncolumns < ARRAY_SIZE(coldescs); ncolumns++)
+ columns[ncolumns] = ncolumns;
break;
case 'r':
outmode = OUT_RAW;
add_column(columns, ncolumns++, COL_PWDDENY);
add_column(columns, ncolumns++, COL_NOLOGIN);
add_column(columns, ncolumns++, COL_HUSH_STATUS);
+ add_column(columns, ncolumns++, COL_PWDMETHOD);
break;
case 'z':
outmode = OUT_NUL;
ctl->time_mode = parse_time_mode(optarg);
break;
case 'V':
- printf(UTIL_LINUX_VERSION);
- return EXIT_SUCCESS;
+ print_version(EXIT_SUCCESS);
case 'Z':
{
#ifdef HAVE_LIBSELINUX
errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users."));
logins = argv[optind];
outmode = OUT_PRETTY;
+ ctl->fail_on_unknown = 1;
} else if (argc != optind)
errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users."));
if (lslogins_flag & F_USRAC && lslogins_flag & F_SYSAC)
lslogins_flag &= ~(F_USRAC | F_SYSAC);
- if (outmode == OUT_PRETTY && !opt_o) {
+ if (outmode == OUT_PRETTY) {
/* all columns for lslogins <username> */
for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++)
columns[ncolumns++] = i;
- } else if (ncolumns == 2 && !opt_o) {
- /* default colummns */
+ } else if (ncolumns == 2) {
+ /* default columns */
add_column(columns, ncolumns++, COL_NPROCS);
add_column(columns, ncolumns++, COL_PWDLOCK);
add_column(columns, ncolumns++, COL_PWDDENY);
add_column(columns, ncolumns++, COL_GECOS);
}
+ if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
+ &ncolumns, column_name_to_id) < 0)
+ return EXIT_FAILURE;
+
if (require_wtmp())
parse_wtmp(ctl, path_wtmp);
if (require_btmp())