]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - login-utils/lslogins.c
scriptreplay: cleanup usage()
[thirdparty/util-linux.git] / login-utils / lslogins.c
index 8b9933eb72923f297803d91c75115eb5150ea9a7..3d9c9b97a21b8f715c391726997a285df83208ec 100644 (file)
@@ -74,7 +74,7 @@ static int lslogins_flag;
 
 #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
@@ -115,6 +115,7 @@ struct lslogins_user {
        char *pwd_expire;
        char *pwd_ctime_min;
        char *pwd_ctime_max;
+       const char *pwd_method;
 
        char *last_login;
        char *last_tty;
@@ -166,6 +167,7 @@ enum {
        COL_PWDLOCK,
        COL_PWDEMPTY,
        COL_PWDDENY,
+       COL_PWDMETHOD,
        COL_GROUP,
        COL_GID,
        COL_SGROUPS,
@@ -219,6 +221,7 @@ static const struct lslogins_coldesc coldescs[] =
        [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 },
@@ -266,6 +269,7 @@ struct lslogins_control {
        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;
@@ -280,7 +284,7 @@ static struct libscols_table *tb;
  * 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)
 {
@@ -333,11 +337,10 @@ static char *make_time(int mode, time_t time)
                                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"));
@@ -430,7 +433,7 @@ static struct utmpx *get_last_wtmp(struct lslogins_control *ctl, const char *use
 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;
@@ -439,7 +442,7 @@ static int require_wtmp(void)
 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;
@@ -562,14 +565,90 @@ static int get_nprocs(const uid_t uid)
        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)
@@ -579,11 +658,12 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
        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;
@@ -606,12 +686,13 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
                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)
@@ -697,7 +778,6 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
                        } else
                                user->pwd_deny = STATUS_UNKNOWN;
                        break;
-
                case COL_PWDLOCK:
                        if (shadow) {
                                if (*shadow->sp_pwdp == '!' && valid_pwd(shadow->sp_pwdp + 1))
@@ -705,6 +785,16 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
                        } 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;
@@ -884,8 +974,8 @@ static int get_user(struct lslogins_control *ctl, struct lslogins_user **user,
 
 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);
 }
 
@@ -895,12 +985,17 @@ static int create_usertree(struct lslogins_control *ctl)
        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)))
@@ -912,7 +1007,7 @@ static int create_usertree(struct lslogins_control *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"));
@@ -965,8 +1060,8 @@ fail:
 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;
@@ -997,6 +1092,9 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
                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;
@@ -1225,7 +1323,7 @@ static void __attribute__((__noreturn__)) usage(void)
        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);
@@ -1243,6 +1341,7 @@ static void __attribute__((__noreturn__)) usage(void)
        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);
@@ -1253,21 +1352,21 @@ static void __attribute__((__noreturn__)) usage(void)
        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);
-       print_usage_help_options(26);
+       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;
@@ -1279,6 +1378,7 @@ int main(int argc, char *argv[])
                OPT_NOTRUNC,
                OPT_NOHEAD,
                OPT_TIME_FMT,
+               OPT_OUTPUT_ALL,
        };
 
        static const struct option longopts[] = {
@@ -1294,6 +1394,7 @@ int main(int argc, char *argv[])
                { "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' },
@@ -1324,7 +1425,7 @@ int main(int argc, char *argv[])
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        ctl->time_mode = TIME_SHORT;
 
@@ -1381,11 +1482,11 @@ int main(int argc, char *argv[])
                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;
@@ -1406,6 +1507,7 @@ int main(int argc, char *argv[])
                        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;
@@ -1426,8 +1528,7 @@ int main(int argc, char *argv[])
                        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
@@ -1450,6 +1551,7 @@ int main(int argc, char *argv[])
                        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."));
 
@@ -1459,13 +1561,13 @@ int main(int argc, char *argv[])
        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);
@@ -1473,6 +1575,10 @@ int main(int argc, char *argv[])
                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())