diff options
author | des <des@FreeBSD.org> | 2004-03-06 21:57:29 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2004-03-06 21:57:29 +0000 |
commit | 247bd59f13fc0777833da0ad618a144295b02e94 (patch) | |
tree | 304e0954e0c76195af5e139e035723c6e914ede8 /usr.bin/logins | |
parent | e82ea43f3939a4c4cdb2d93371a876038560f5b8 (diff) | |
download | FreeBSD-src-247bd59f13fc0777833da0ad618a144295b02e94.zip FreeBSD-src-247bd59f13fc0777833da0ad618a144295b02e94.tar.gz |
Add a logins(1) utility similar to that found in SVr4 derivatives. This
particular implementation is based on the Solaris logins(1) man page.
Diffstat (limited to 'usr.bin/logins')
-rw-r--r-- | usr.bin/logins/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/logins/logins.1 | 105 | ||||
-rw-r--r-- | usr.bin/logins/logins.c | 408 |
3 files changed, 519 insertions, 0 deletions
diff --git a/usr.bin/logins/Makefile b/usr.bin/logins/Makefile new file mode 100644 index 0000000..42840fb --- /dev/null +++ b/usr.bin/logins/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +PROG= logins +WARNS?= 6 + +.include <bsd.prog.mk> diff --git a/usr.bin/logins/logins.1 b/usr.bin/logins/logins.1 new file mode 100644 index 0000000..c6680b6 --- /dev/null +++ b/usr.bin/logins/logins.1 @@ -0,0 +1,105 @@ +.\"- +.\" Copyright (c) 2004 Dag-Erling Coïdan Smørgrav +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd March 6, 2004 +.Dt LOGINS 1 +.Os +.Sh NAME +.Nm logins +.Nd display account information +.Sh SYNOPSIS +.Nm +.Op Fl admopstux +.Op Fl g Ar groups +.Op Fl l Ar logins +.Sh DESCRIPTION +The +.Nm +utility displays information about user and system accounts. +.Pp +The following options are available: +.Bl -tag -width Fl +.It Fl a +Display information about the password change and account expiration +times for each account. +.It Fl d +Select accounts with duplicate UIDs. +.It Fl g Ar groups +Select accounts that are members of the specified groups. +If multiple group names are specified, they must be separated with +commas. +.It Fl l Ar logins +Select accounts matching the specified login names. +If multiple names are specified, they must be separated with commas. +.It Fl m +Show information about secondary groups. +.It Fl o +Display the information for each account on a single line of +colon-separated fields. +.It Fl p +Select accounts with no password. +.It Fl s +Select system accounts. +This is currently defined as accounts with UIDs below 1000, plus the +.Dq nobody +account (UID 65534). +.It Fl t +Sort selected accounts by name rather than by UID. +.It Fl u +Select user accounts. +These are currently defined as accounts with UIDs above 1000, except +the +.Dq nobody +account (UID 65534). +.It Fl x +Display information about each account's home directory and shell. +.El +.Pp +If multiple selection options are specified, all accounts matching any +of the selection criteria will be displayed. +.Pp +If no selection options are specified, all acounts will be displayed. +.Sh SEE ALSO +.Xr getgrent 3 , +.Xr getpwent 3 , +.Xr group 5 , +.Xr passwd 5 , +.Xr pw 8 +.Sh HISTORY +The +.Nm +command appeared in +.Fx 4.10 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org +based on similar utilities in other operating systems. diff --git a/usr.bin/logins/logins.c b/usr.bin/logins/logins.c new file mode 100644 index 0000000..abf342e --- /dev/null +++ b/usr.bin/logins/logins.c @@ -0,0 +1,408 @@ +/*- + * Copyright (c) 2004 Dag-Erling Coïdan Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <err.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +struct xpasswd { + char *pw_name; + char *pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + time_t pw_expire; + int pw_selected; +}; + +struct xgroup { + char *gr_name; + char *gr_passwd; + gid_t gr_gid; + char *gr_mem; +}; + +static int everything = 1; +static int a_flag; +static int d_flag; +static const char *g_args; +static const char *l_args; +static int m_flag; +static int o_flag; +static int p_flag; +static int s_flag; +static int t_flag; +static int u_flag; +static int x_flag; + +static int +member(const char *elem, const char *list) +{ + char *p; + int len; + + p = strstr(list, elem); + len = strlen(elem); + + return (p != NULL && + (p == list || p[-1] == ',') && + (p[len] == '\0' || p[len] == ',')); +} + +static void * +xmalloc(size_t size) +{ + void *newptr; + + if ((newptr = malloc(size)) == NULL) + err(1, "malloc()"); + return (newptr); +} + +static void * +xrealloc(void *ptr, size_t size) +{ + void *newptr; + + if ((newptr = realloc(ptr, size)) == NULL) + err(1, "realloc()"); + return (newptr); +} + +static char * +xstrdup(const char *str) +{ + char *dupstr; + + if ((dupstr = strdup(str)) == NULL) + err(1, "strdup()"); + return (dupstr); +} + +static struct xgroup *grps; +static size_t grpsz; +static size_t ngrps; + +static void +get_groups(void) +{ + struct group *grp; + size_t len; + int i; + + setgrent(); + for (;;) { + if (ngrps == grpsz) { + grpsz += grpsz ? grpsz : 128; + grps = xrealloc(grps, grpsz * sizeof *grps); + } + if ((grp = getgrent()) == NULL) + break; + grps[ngrps].gr_name = xstrdup(grp->gr_name); + grps[ngrps].gr_passwd = xstrdup(grp->gr_passwd); + grps[ngrps].gr_gid = grp->gr_gid; + grps[ngrps].gr_mem = xstrdup(""); + for (i = 0, len = 1; grp->gr_mem[i] != NULL; ++i) + len += strlen(grp->gr_mem[i]) + 1; + grps[ngrps].gr_mem = xmalloc(len); + for (i = 0, len = 0; grp->gr_mem[i] != NULL; ++i) + len += sprintf(grps[ngrps].gr_mem + len, + i ? ",%s" : "%s", grp->gr_mem[i]); + grps[ngrps].gr_mem[len] = '\0'; + ngrps++; + } + endgrent(); +} + +static struct xgroup * +find_group_bygid(gid_t gid) +{ + unsigned int i; + + for (i = 0; i < ngrps; ++i) + if (grps[i].gr_gid == gid) + return (&grps[i]); + return (NULL); +} + +#if 0 +static struct xgroup * +find_group_byname(const char *name) +{ + unsigned int i; + + for (i = 0; i < ngrps; ++i) + if (strcmp(grps[i].gr_name, name) == 0) + return (&grps[i]); + return (NULL); +} +#endif + +static struct xpasswd *pwds; +static size_t pwdsz; +static size_t npwds; + +static int +pwd_cmp_byname(const void *ap, const void *bp) +{ + const struct passwd *a = ap; + const struct passwd *b = bp; + + return (strcmp(a->pw_name, b->pw_name)); +} + +static int +pwd_cmp_byuid(const void *ap, const void *bp) +{ + const struct passwd *a = ap; + const struct passwd *b = bp; + + return (a->pw_uid - b->pw_uid); +} + +static void +get_users(void) +{ + struct passwd *pwd; + + setpwent(); + for (;;) { + if (npwds == pwdsz) { + pwdsz += pwdsz ? pwdsz : 128; + pwds = xrealloc(pwds, pwdsz * sizeof *pwds); + } + if ((pwd = getpwent()) == NULL) + break; + pwds[npwds].pw_name = xstrdup(pwd->pw_name); + pwds[npwds].pw_passwd = xstrdup(pwd->pw_passwd); + pwds[npwds].pw_uid = pwd->pw_uid; + pwds[npwds].pw_gid = pwd->pw_gid; + pwds[npwds].pw_change = pwd->pw_change; + pwds[npwds].pw_class = xstrdup(pwd->pw_class); + pwds[npwds].pw_gecos = xstrdup(pwd->pw_gecos); + pwds[npwds].pw_dir = xstrdup(pwd->pw_dir); + pwds[npwds].pw_shell = xstrdup(pwd->pw_shell); + pwds[npwds].pw_expire = pwd->pw_expire; + pwds[npwds].pw_selected = 0; + npwds++; + } + endpwent(); +} + +static void +select_users(void) +{ + unsigned int i, j; + struct xgroup *grp; + struct xpasswd *pwd; + + for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) { + if (everything) { + pwd->pw_selected = 1; + continue; + } + if (d_flag) + if ((i > 0 && pwd->pw_uid == pwd[-1].pw_uid) || + (i < npwds - 1 && pwd->pw_uid == pwd[1].pw_uid)) { + pwd->pw_selected = 1; + continue; + } + if (g_args) { + for (j = 0, grp = grps; j < ngrps; ++j, ++grp) { + if (member(grp->gr_name, g_args) && + member(pwd->pw_name, grp->gr_mem)) { + pwd->pw_selected = 1; + break; + } + } + if (pwd->pw_selected) + continue; + } + if (l_args) + if (member(pwd->pw_name, l_args)) { + pwd->pw_selected = 1; + continue; + } + if (p_flag) + if (pwd->pw_passwd[0] == '\0') { + pwd->pw_selected = 1; + continue; + } + if (s_flag) + if (pwd->pw_uid < 1000 || pwd->pw_uid == 65534) { + pwd->pw_selected = 1; + continue; + } + if (u_flag) + if (pwd->pw_uid >= 1000 && pwd->pw_uid != 65534) { + pwd->pw_selected = 1; + continue; + } + } +} + +static void +sort_users(void) +{ + if (t_flag) + mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byname); + else + mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byuid); +} + +static void +display_user(struct xpasswd *pwd) +{ + struct xgroup *grp; + unsigned int i; + char cbuf[16], ebuf[16]; + struct tm *tm; + + grp = find_group_bygid(pwd->pw_gid); + printf(o_flag ? "%s:%ld:%s:%ld:%s" : "%-15s %-7ld %-15s %-7ld %s\n", + pwd->pw_name, (long)pwd->pw_uid, grp ? grp->gr_name : "", + (long)pwd->pw_gid, pwd->pw_gecos); + if (m_flag) { + for (i = 0, grp = grps; i < ngrps; ++i, ++grp) { + if (grp->gr_gid == pwd->pw_gid || + !member(pwd->pw_name, grp->gr_mem)) + continue; + printf(o_flag ? "%s:%s:%ld" : "%24s%-15s %-7ld\n", + "", grp->gr_name, (long)grp->gr_gid); + } + } + if (x_flag) { + printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_dir); + printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_shell); + } + if (a_flag) { + tm = gmtime(&pwd->pw_change); + strftime(cbuf, sizeof(cbuf), pwd->pw_change ? "%F" : "0", tm); + tm = gmtime(&pwd->pw_expire); + strftime(ebuf, sizeof(ebuf), pwd->pw_expire ? "%F" : "0", tm); + printf(o_flag ? "%s:%s:%s" : "%24s%s %s\n", "", cbuf, ebuf); + } + if (o_flag) + printf("\n"); +} + +static void +list_users(void) +{ + struct xpasswd *pwd; + unsigned int i; + + for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) + if (pwd->pw_selected) + display_user(pwd); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: logins [-admopstux] [-g group] [-l login]\n"); + exit(1); +} + +int +main(int argc, char * const argv[]) +{ + int o; + + while ((o = getopt(argc, argv, "adg:l:mopstux")) != -1) + switch (o) { + case 'a': + a_flag = 1; + break; + case 'd': + everything = 0; + d_flag = 1; + break; + case 'g': + everything = 0; + g_args = optarg; + break; + case 'l': + everything = 0; + l_args = optarg; + break; + case 'm': + m_flag = 1; + break; + case 'o': + o_flag = 1; + break; + case 'p': + everything = 0; + p_flag = 1; + break; + case 's': + everything = 0; + s_flag = 1; + break; + case 't': + t_flag = 1; + break; + case 'u': + everything = 0; + u_flag = 1; + break; + case 'x': + x_flag = 1; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc > 0) + usage(); + + get_groups(); + get_users(); + select_users(); + sort_users(); + list_users(); + exit(0); +} |