]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/logins/logins.c
cdn-patch: offer option to mount /etc/keys before attaching geli devices
[FreeBSD/FreeBSD.git] / usr.bin / logins / logins.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2004 Dag-Erling Coïdan Smørgrav
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <err.h>
37 #include <grp.h>
38 #include <pwd.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 struct xpasswd {
46         char            *pw_name;
47         char            *pw_passwd;
48         uid_t            pw_uid;
49         gid_t            pw_gid;
50         time_t           pw_change;
51         char            *pw_class;
52         char            *pw_gecos;
53         char            *pw_dir;
54         char            *pw_shell;
55         time_t           pw_expire;
56         int              pw_selected;
57 };
58
59 struct xgroup {
60         char            *gr_name;
61         char            *gr_passwd;
62         gid_t            gr_gid;
63         char            *gr_mem;
64 };
65
66 static int               everything = 1;
67 static int               a_flag;
68 static int               d_flag;
69 static const char       *g_args;
70 static const char       *l_args;
71 static int               m_flag;
72 static int               o_flag;
73 static int               p_flag;
74 static int               s_flag;
75 static int               t_flag;
76 static int               u_flag;
77 static int               x_flag;
78
79 static int
80 member(const char *elem, const char *list)
81 {
82         char *p;
83         int len;
84
85         p = strstr(list, elem);
86         len = strlen(elem);
87
88         return (p != NULL &&
89             (p == list || p[-1] == ',') &&
90             (p[len] == '\0' || p[len] == ','));
91 }
92
93 static void *
94 xmalloc(size_t size)
95 {
96         void *newptr;
97
98         if ((newptr = malloc(size)) == NULL)
99                 err(1, "malloc()");
100         return (newptr);
101 }
102
103 static void *
104 xrealloc(void *ptr, size_t size)
105 {
106         void *newptr;
107
108         if ((newptr = realloc(ptr, size)) == NULL)
109                 err(1, "realloc()");
110         return (newptr);
111 }
112
113 static char *
114 xstrdup(const char *str)
115 {
116         char *dupstr;
117
118         if ((dupstr = strdup(str)) == NULL)
119                 err(1, "strdup()");
120         return (dupstr);
121 }
122
123 static struct xgroup    *grps;
124 static size_t            grpsz;
125 static size_t            ngrps;
126
127 static void
128 get_groups(void)
129 {
130         struct group *grp;
131         size_t len;
132         int i;
133
134         setgrent();
135         for (;;) {
136                 if (ngrps == grpsz) {
137                         grpsz += grpsz ? grpsz : 128;
138                         grps = xrealloc(grps, grpsz * sizeof *grps);
139                 }
140                 if ((grp = getgrent()) == NULL)
141                         break;
142                 grps[ngrps].gr_name = xstrdup(grp->gr_name);
143                 grps[ngrps].gr_passwd = xstrdup(grp->gr_passwd);
144                 grps[ngrps].gr_gid = grp->gr_gid;
145                 grps[ngrps].gr_mem = xstrdup("");
146                 for (i = 0, len = 1; grp->gr_mem[i] != NULL; ++i)
147                         len += strlen(grp->gr_mem[i]) + 1;
148                 grps[ngrps].gr_mem = xmalloc(len);
149                 for (i = 0, len = 0; grp->gr_mem[i] != NULL; ++i)
150                         len += sprintf(grps[ngrps].gr_mem + len,
151                             i ? ",%s" : "%s", grp->gr_mem[i]);
152                 grps[ngrps].gr_mem[len] = '\0';
153                 ngrps++;
154         }
155         endgrent();
156 }
157
158 static struct xgroup *
159 find_group_bygid(gid_t gid)
160 {
161         unsigned int i;
162
163         for (i = 0; i < ngrps; ++i)
164                 if (grps[i].gr_gid == gid)
165                         return (&grps[i]);
166         return (NULL);
167 }
168
169 #if 0
170 static struct xgroup *
171 find_group_byname(const char *name)
172 {
173         unsigned int i;
174
175         for (i = 0; i < ngrps; ++i)
176                 if (strcmp(grps[i].gr_name, name) == 0)
177                         return (&grps[i]);
178         return (NULL);
179 }
180 #endif
181
182 static struct xpasswd   *pwds;
183 static size_t            pwdsz;
184 static size_t            npwds;
185
186 static int
187 pwd_cmp_byname(const void *ap, const void *bp)
188 {
189         const struct passwd *a = ap;
190         const struct passwd *b = bp;
191
192         return (strcmp(a->pw_name, b->pw_name));
193 }
194
195 static int
196 pwd_cmp_byuid(const void *ap, const void *bp)
197 {
198         const struct passwd *a = ap;
199         const struct passwd *b = bp;
200
201         return (a->pw_uid - b->pw_uid);
202 }
203
204 static void
205 get_users(void)
206 {
207         struct passwd *pwd;
208
209         setpwent();
210         for (;;) {
211                 if (npwds == pwdsz) {
212                         pwdsz += pwdsz ? pwdsz : 128;
213                         pwds = xrealloc(pwds, pwdsz * sizeof *pwds);
214                 }
215                 if ((pwd = getpwent()) == NULL)
216                         break;
217                 pwds[npwds].pw_name = xstrdup(pwd->pw_name);
218                 pwds[npwds].pw_passwd = xstrdup(pwd->pw_passwd);
219                 pwds[npwds].pw_uid = pwd->pw_uid;
220                 pwds[npwds].pw_gid = pwd->pw_gid;
221                 pwds[npwds].pw_change = pwd->pw_change;
222                 pwds[npwds].pw_class = xstrdup(pwd->pw_class);
223                 pwds[npwds].pw_gecos = xstrdup(pwd->pw_gecos);
224                 pwds[npwds].pw_dir = xstrdup(pwd->pw_dir);
225                 pwds[npwds].pw_shell = xstrdup(pwd->pw_shell);
226                 pwds[npwds].pw_expire = pwd->pw_expire;
227                 pwds[npwds].pw_selected = 0;
228                 npwds++;
229         }
230         endpwent();
231 }
232
233 static void
234 select_users(void)
235 {
236         unsigned int i, j;
237         struct xgroup *grp;
238         struct xpasswd *pwd;
239
240         for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) {
241                 if (everything) {
242                         pwd->pw_selected = 1;
243                         continue;
244                 }
245                 if (d_flag)
246                         if ((i > 0 && pwd->pw_uid == pwd[-1].pw_uid) ||
247                             (i < npwds - 1 && pwd->pw_uid == pwd[1].pw_uid)) {
248                                 pwd->pw_selected = 1;
249                                 continue;
250                         }
251                 if (g_args) {
252                         for (j = 0, grp = grps; j < ngrps; ++j, ++grp) {
253                                 if (member(grp->gr_name, g_args) &&
254                                     member(pwd->pw_name, grp->gr_mem)) {
255                                         pwd->pw_selected = 1;
256                                         break;
257                                 }
258                         }
259                         if (pwd->pw_selected)
260                                 continue;
261                 }
262                 if (l_args)
263                         if (member(pwd->pw_name, l_args)) {
264                                 pwd->pw_selected = 1;
265                                 continue;
266                         }
267                 if (p_flag)
268                         if (pwd->pw_passwd[0] == '\0') {
269                                 pwd->pw_selected = 1;
270                                 continue;
271                         }
272                 if (s_flag)
273                         if (pwd->pw_uid < 1000 || pwd->pw_uid == 65534) {
274                                 pwd->pw_selected = 1;
275                                 continue;
276                         }
277                 if (u_flag)
278                         if (pwd->pw_uid >= 1000 && pwd->pw_uid != 65534) {
279                                 pwd->pw_selected = 1;
280                                 continue;
281                         }
282         }
283 }
284
285 static void
286 sort_users(void)
287 {
288         if (t_flag)
289                 mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byname);
290         else
291                 mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byuid);
292 }
293
294 static void
295 display_user(struct xpasswd *pwd)
296 {
297         struct xgroup *grp;
298         unsigned int i;
299         char cbuf[16], ebuf[16];
300         struct tm *tm;
301
302         grp = find_group_bygid(pwd->pw_gid);
303         printf(o_flag ? "%s:%ld:%s:%ld:%s" : "%-15s %-7ld %-15s %-7ld %s\n",
304             pwd->pw_name, (long)pwd->pw_uid, grp ? grp->gr_name : "",
305             (long)pwd->pw_gid, pwd->pw_gecos);
306         if (m_flag) {
307                 for (i = 0, grp = grps; i < ngrps; ++i, ++grp) {
308                         if (grp->gr_gid == pwd->pw_gid ||
309                             !member(pwd->pw_name, grp->gr_mem))
310                                 continue;
311                         printf(o_flag ? "%s:%s:%ld" : "%24s%-15s %-7ld\n",
312                             "", grp->gr_name, (long)grp->gr_gid);
313                 }
314         }
315         if (x_flag) {
316                 printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_dir);
317                 printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_shell);
318         }
319         if (a_flag) {
320                 tm = gmtime(&pwd->pw_change);
321                 strftime(cbuf, sizeof(cbuf), pwd->pw_change ? "%F" : "0", tm);
322                 tm = gmtime(&pwd->pw_expire);
323                 strftime(ebuf, sizeof(ebuf), pwd->pw_expire ? "%F" : "0", tm);
324                 printf(o_flag ? "%s:%s:%s" : "%24s%s %s\n", "", cbuf, ebuf);
325         }
326         if (o_flag)
327                 printf("\n");
328 }
329
330 static void
331 list_users(void)
332 {
333         struct xpasswd *pwd;
334         unsigned int i;
335
336         for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd)
337                 if (pwd->pw_selected)
338                         display_user(pwd);
339 }
340
341 static void
342 usage(void)
343 {
344         fprintf(stderr, "usage: logins [-admopstux] [-g group] [-l login]\n");
345         exit(1);
346 }
347
348 int
349 main(int argc, char * const argv[])
350 {
351         int o;
352
353         while ((o = getopt(argc, argv, "adg:l:mopstux")) != -1)
354                 switch (o) {
355                 case 'a':
356                         a_flag = 1;
357                         break;
358                 case 'd':
359                         everything = 0;
360                         d_flag = 1;
361                         break;
362                 case 'g':
363                         everything = 0;
364                         g_args = optarg;
365                         break;
366                 case 'l':
367                         everything = 0;
368                         l_args = optarg;
369                         break;
370                 case 'm':
371                         m_flag = 1;
372                         break;
373                 case 'o':
374                         o_flag = 1;
375                         break;
376                 case 'p':
377                         everything = 0;
378                         p_flag = 1;
379                         break;
380                 case 's':
381                         everything = 0;
382                         s_flag = 1;
383                         break;
384                 case 't':
385                         t_flag = 1;
386                         break;
387                 case 'u':
388                         everything = 0;
389                         u_flag = 1;
390                         break;
391                 case 'x':
392                         x_flag = 1;
393                         break;
394                 default:
395                         usage();
396                 }
397
398         argc -= optind;
399         argv += optind;
400
401         if (argc > 0)
402                 usage();
403
404         get_groups();
405         get_users();
406         select_users();
407         sort_users();
408         list_users();
409         exit(0);
410 }