]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/logins/logins.c
pmap: move the smp_targeted_tlb_shutdown pointer stuff to amd64 pmap.h
[FreeBSD/FreeBSD.git] / usr.bin / logins / logins.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2004 Dag-Erling 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
31 #include <sys/cdefs.h>
32 #include <err.h>
33 #include <grp.h>
34 #include <pwd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <unistd.h>
40
41 struct xpasswd {
42         char            *pw_name;
43         char            *pw_passwd;
44         uid_t            pw_uid;
45         gid_t            pw_gid;
46         time_t           pw_change;
47         char            *pw_class;
48         char            *pw_gecos;
49         char            *pw_dir;
50         char            *pw_shell;
51         time_t           pw_expire;
52         int              pw_selected;
53 };
54
55 struct xgroup {
56         char            *gr_name;
57         char            *gr_passwd;
58         gid_t            gr_gid;
59         char            *gr_mem;
60 };
61
62 static int               everything = 1;
63 static int               a_flag;
64 static int               d_flag;
65 static const char       *g_args;
66 static const char       *l_args;
67 static int               m_flag;
68 static int               o_flag;
69 static int               p_flag;
70 static int               s_flag;
71 static int               t_flag;
72 static int               u_flag;
73 static int               x_flag;
74
75 static int
76 member(const char *elem, const char *list)
77 {
78         char *p;
79         int len;
80
81         p = strstr(list, elem);
82         len = strlen(elem);
83
84         return (p != NULL &&
85             (p == list || p[-1] == ',') &&
86             (p[len] == '\0' || p[len] == ','));
87 }
88
89 static void *
90 xmalloc(size_t size)
91 {
92         void *newptr;
93
94         if ((newptr = malloc(size)) == NULL)
95                 err(1, "malloc()");
96         return (newptr);
97 }
98
99 static void *
100 xrealloc(void *ptr, size_t size)
101 {
102         void *newptr;
103
104         if ((newptr = realloc(ptr, size)) == NULL)
105                 err(1, "realloc()");
106         return (newptr);
107 }
108
109 static char *
110 xstrdup(const char *str)
111 {
112         char *dupstr;
113
114         if ((dupstr = strdup(str)) == NULL)
115                 err(1, "strdup()");
116         return (dupstr);
117 }
118
119 static struct xgroup    *grps;
120 static size_t            grpsz;
121 static size_t            ngrps;
122
123 static void
124 get_groups(void)
125 {
126         struct group *grp;
127         size_t len;
128         int i;
129
130         setgrent();
131         for (;;) {
132                 if (ngrps == grpsz) {
133                         grpsz += grpsz ? grpsz : 128;
134                         grps = xrealloc(grps, grpsz * sizeof *grps);
135                 }
136                 if ((grp = getgrent()) == NULL)
137                         break;
138                 grps[ngrps].gr_name = xstrdup(grp->gr_name);
139                 grps[ngrps].gr_passwd = xstrdup(grp->gr_passwd);
140                 grps[ngrps].gr_gid = grp->gr_gid;
141                 grps[ngrps].gr_mem = xstrdup("");
142                 for (i = 0, len = 1; grp->gr_mem[i] != NULL; ++i)
143                         len += strlen(grp->gr_mem[i]) + 1;
144                 grps[ngrps].gr_mem = xmalloc(len);
145                 for (i = 0, len = 0; grp->gr_mem[i] != NULL; ++i)
146                         len += sprintf(grps[ngrps].gr_mem + len,
147                             i ? ",%s" : "%s", grp->gr_mem[i]);
148                 grps[ngrps].gr_mem[len] = '\0';
149                 ngrps++;
150         }
151         endgrent();
152 }
153
154 static struct xgroup *
155 find_group_bygid(gid_t gid)
156 {
157         unsigned int i;
158
159         for (i = 0; i < ngrps; ++i)
160                 if (grps[i].gr_gid == gid)
161                         return (&grps[i]);
162         return (NULL);
163 }
164
165 #if 0
166 static struct xgroup *
167 find_group_byname(const char *name)
168 {
169         unsigned int i;
170
171         for (i = 0; i < ngrps; ++i)
172                 if (strcmp(grps[i].gr_name, name) == 0)
173                         return (&grps[i]);
174         return (NULL);
175 }
176 #endif
177
178 static struct xpasswd   *pwds;
179 static size_t            pwdsz;
180 static size_t            npwds;
181
182 static int
183 pwd_cmp_byname(const void *ap, const void *bp)
184 {
185         const struct passwd *a = ap;
186         const struct passwd *b = bp;
187
188         return (strcmp(a->pw_name, b->pw_name));
189 }
190
191 static int
192 pwd_cmp_byuid(const void *ap, const void *bp)
193 {
194         const struct passwd *a = ap;
195         const struct passwd *b = bp;
196
197         return (a->pw_uid - b->pw_uid);
198 }
199
200 static void
201 get_users(void)
202 {
203         struct passwd *pwd;
204
205         setpwent();
206         for (;;) {
207                 if (npwds == pwdsz) {
208                         pwdsz += pwdsz ? pwdsz : 128;
209                         pwds = xrealloc(pwds, pwdsz * sizeof *pwds);
210                 }
211                 if ((pwd = getpwent()) == NULL)
212                         break;
213                 pwds[npwds].pw_name = xstrdup(pwd->pw_name);
214                 pwds[npwds].pw_passwd = xstrdup(pwd->pw_passwd);
215                 pwds[npwds].pw_uid = pwd->pw_uid;
216                 pwds[npwds].pw_gid = pwd->pw_gid;
217                 pwds[npwds].pw_change = pwd->pw_change;
218                 pwds[npwds].pw_class = xstrdup(pwd->pw_class);
219                 pwds[npwds].pw_gecos = xstrdup(pwd->pw_gecos);
220                 pwds[npwds].pw_dir = xstrdup(pwd->pw_dir);
221                 pwds[npwds].pw_shell = xstrdup(pwd->pw_shell);
222                 pwds[npwds].pw_expire = pwd->pw_expire;
223                 pwds[npwds].pw_selected = 0;
224                 npwds++;
225         }
226         endpwent();
227 }
228
229 static void
230 select_users(void)
231 {
232         unsigned int i, j;
233         struct xgroup *grp;
234         struct xpasswd *pwd;
235
236         for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) {
237                 if (everything) {
238                         pwd->pw_selected = 1;
239                         continue;
240                 }
241                 if (d_flag)
242                         if ((i > 0 && pwd->pw_uid == pwd[-1].pw_uid) ||
243                             (i < npwds - 1 && pwd->pw_uid == pwd[1].pw_uid)) {
244                                 pwd->pw_selected = 1;
245                                 continue;
246                         }
247                 if (g_args) {
248                         for (j = 0, grp = grps; j < ngrps; ++j, ++grp) {
249                                 if (member(grp->gr_name, g_args) &&
250                                     member(pwd->pw_name, grp->gr_mem)) {
251                                         pwd->pw_selected = 1;
252                                         break;
253                                 }
254                         }
255                         if (pwd->pw_selected)
256                                 continue;
257                 }
258                 if (l_args)
259                         if (member(pwd->pw_name, l_args)) {
260                                 pwd->pw_selected = 1;
261                                 continue;
262                         }
263                 if (p_flag)
264                         if (pwd->pw_passwd[0] == '\0') {
265                                 pwd->pw_selected = 1;
266                                 continue;
267                         }
268                 if (s_flag)
269                         if (pwd->pw_uid < 1000 || pwd->pw_uid == 65534) {
270                                 pwd->pw_selected = 1;
271                                 continue;
272                         }
273                 if (u_flag)
274                         if (pwd->pw_uid >= 1000 && pwd->pw_uid != 65534) {
275                                 pwd->pw_selected = 1;
276                                 continue;
277                         }
278         }
279 }
280
281 static void
282 sort_users(void)
283 {
284         if (t_flag)
285                 mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byname);
286         else
287                 mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byuid);
288 }
289
290 static void
291 display_user(struct xpasswd *pwd)
292 {
293         struct xgroup *grp;
294         unsigned int i;
295         char cbuf[16], ebuf[16];
296         struct tm *tm;
297
298         grp = find_group_bygid(pwd->pw_gid);
299         printf(o_flag ? "%s:%ld:%s:%ld:%s" : "%-15s %-7ld %-15s %-7ld %s\n",
300             pwd->pw_name, (long)pwd->pw_uid, grp ? grp->gr_name : "",
301             (long)pwd->pw_gid, pwd->pw_gecos);
302         if (m_flag) {
303                 for (i = 0, grp = grps; i < ngrps; ++i, ++grp) {
304                         if (grp->gr_gid == pwd->pw_gid ||
305                             !member(pwd->pw_name, grp->gr_mem))
306                                 continue;
307                         printf(o_flag ? "%s:%s:%ld" : "%24s%-15s %-7ld\n",
308                             "", grp->gr_name, (long)grp->gr_gid);
309                 }
310         }
311         if (x_flag) {
312                 printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_dir);
313                 printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_shell);
314         }
315         if (a_flag) {
316                 tm = gmtime(&pwd->pw_change);
317                 strftime(cbuf, sizeof(cbuf), pwd->pw_change ? "%F" : "0", tm);
318                 tm = gmtime(&pwd->pw_expire);
319                 strftime(ebuf, sizeof(ebuf), pwd->pw_expire ? "%F" : "0", tm);
320                 printf(o_flag ? "%s:%s:%s" : "%24s%s %s\n", "", cbuf, ebuf);
321         }
322         if (o_flag)
323                 printf("\n");
324 }
325
326 static void
327 list_users(void)
328 {
329         struct xpasswd *pwd;
330         unsigned int i;
331
332         for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd)
333                 if (pwd->pw_selected)
334                         display_user(pwd);
335 }
336
337 static void
338 usage(void)
339 {
340         fprintf(stderr, "usage: logins [-admopstux] [-g group] [-l login]\n");
341         exit(1);
342 }
343
344 int
345 main(int argc, char * const argv[])
346 {
347         int o;
348
349         while ((o = getopt(argc, argv, "adg:l:mopstux")) != -1)
350                 switch (o) {
351                 case 'a':
352                         a_flag = 1;
353                         break;
354                 case 'd':
355                         everything = 0;
356                         d_flag = 1;
357                         break;
358                 case 'g':
359                         everything = 0;
360                         g_args = optarg;
361                         break;
362                 case 'l':
363                         everything = 0;
364                         l_args = optarg;
365                         break;
366                 case 'm':
367                         m_flag = 1;
368                         break;
369                 case 'o':
370                         o_flag = 1;
371                         break;
372                 case 'p':
373                         everything = 0;
374                         p_flag = 1;
375                         break;
376                 case 's':
377                         everything = 0;
378                         s_flag = 1;
379                         break;
380                 case 't':
381                         t_flag = 1;
382                         break;
383                 case 'u':
384                         everything = 0;
385                         u_flag = 1;
386                         break;
387                 case 'x':
388                         x_flag = 1;
389                         break;
390                 default:
391                         usage();
392                 }
393
394         argc -= optind;
395         argv += optind;
396
397         if (argc > 0)
398                 usage();
399
400         get_groups();
401         get_users();
402         select_users();
403         sort_users();
404         list_users();
405         exit(0);
406 }