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