1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char copyright[] =
13 "@(#) Copyright (c) 1989, 1993\n\
14 The Regents of the University of California. All rights reserved.\n";
15 #endif /* not lint */
16
17 #ifndef lint
18 static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 05/04/95";
19 #endif /* not lint */
20
21 /*
22 * Finger prints out information about users. It is not portable since
23 * certain fields (e.g. the full user name, office, and phone numbers) are
24 * extracted from the gecos field of the passwd file which other UNIXes
25 * may not have or may use for other things.
26 *
27 * There are currently two output formats; the short format is one line
28 * per user and displays login name, tty, login time, real name, idle time,
29 * and office location/phone number. The long format gives the same
30 * information (in a more legible format) as well as home directory, shell,
31 * mail info, and .plan/.project files.
32 */
33
34 #include <sys/param.h>
35
36 #include <db.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <utmp.h>
47
48 #include "finger.h"
49
50 DB *db;
51 time_t now;
52 int entries, lflag, mflag, pplan, sflag;
53 char tbuf[1024];
54
55 static void loginlist __P((void));
56 static void userlist __P((int, char **));
57
58 int
main(argc,argv)59 main(argc, argv)
60 int argc;
61 char **argv;
62 {
63 int ch;
64
65 while ((ch = getopt(argc, argv, "lmps")) != EOF)
66 switch(ch) {
67 case 'l':
68 lflag = 1; /* long format */
69 break;
70 case 'm':
71 mflag = 1; /* force exact match of names */
72 break;
73 case 'p':
74 pplan = 1; /* don't show .plan/.project */
75 break;
76 case 's':
77 sflag = 1; /* short format */
78 break;
79 case '?':
80 default:
81 (void)fprintf(stderr,
82 "usage: finger [-lmps] [login ...]\n");
83 exit(1);
84 }
85 argc -= optind;
86 argv += optind;
87
88 (void)time(&now);
89 setpassent(1);
90 if (!*argv) {
91 /*
92 * Assign explicit "small" format if no names given and -l
93 * not selected. Force the -s BEFORE we get names so proper
94 * screening will be done.
95 */
96 if (!lflag)
97 sflag = 1; /* if -l not explicit, force -s */
98 loginlist();
99 if (entries == 0)
100 (void)printf("No one logged on.\n");
101 } else {
102 userlist(argc, argv);
103 /*
104 * Assign explicit "large" format if names given and -s not
105 * explicitly stated. Force the -l AFTER we get names so any
106 * remote finger attempts specified won't be mishandled.
107 */
108 if (!sflag)
109 lflag = 1; /* if -s not explicit, force -l */
110 }
111 if (entries)
112 if (lflag)
113 lflag_print();
114 else
115 sflag_print();
116 return (0);
117 }
118
119 static void
loginlist()120 loginlist()
121 {
122 register PERSON *pn;
123 DBT data, key;
124 struct passwd *pw;
125 struct utmp user;
126 int r, sflag;
127 char name[UT_NAMESIZE + 1];
128
129 if (!freopen(_PATH_UTMP, "r", stdin))
130 err(1, "%s", _PATH_UTMP);
131 name[UT_NAMESIZE] = NULL;
132 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
133 if (!user.ut_name[0])
134 continue;
135 if ((pn = find_person(user.ut_name)) == NULL) {
136 bcopy(user.ut_name, name, UT_NAMESIZE);
137 if ((pw = getpwnam(name)) == NULL)
138 continue;
139 pn = enter_person(pw);
140 }
141 enter_where(&user, pn);
142 }
143 if (db && lflag)
144 for (sflag = R_FIRST;; sflag = R_NEXT) {
145 PERSON *tmp;
146
147 r = (*db->seq)(db, &key, &data, sflag);
148 if (r == -1)
149 err(1, "db seq");
150 if (r == 1)
151 break;
152 memmove(&tmp, data.data, sizeof tmp);
153 enter_lastlog(tmp);
154 }
155 }
156
157 static void
userlist(argc,argv)158 userlist(argc, argv)
159 register int argc;
160 register char **argv;
161 {
162 register PERSON *pn;
163 DBT data, key;
164 struct utmp user;
165 struct passwd *pw;
166 int r, sflag, *used, *ip;
167 char **ap, **nargv, **np, **p;
168
169 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
170 (used = calloc(argc, sizeof(int))) == NULL)
171 err(1, NULL);
172
173 /* Pull out all network requests. */
174 for (ap = p = argv, np = nargv; *p; ++p)
175 if (index(*p, '@'))
176 *np++ = *p;
177 else
178 *ap++ = *p;
179
180 *np++ = NULL;
181 *ap++ = NULL;
182
183 if (!*argv)
184 goto net;
185
186 /*
187 * Traverse the list of possible login names and check the login name
188 * and real name against the name specified by the user.
189 */
190 if (mflag)
191 for (p = argv; *p; ++p)
192 if ((pw = getpwnam(*p)) != NULL)
193 enter_person(pw);
194 else
195 (void)fprintf(stderr,
196 "finger: %s: no such user\n", *p);
197 else {
198 while ((pw = getpwent()) != NULL)
199 for (p = argv, ip = used; *p; ++p, ++ip)
200 if (match(pw, *p)) {
201 enter_person(pw);
202 *ip = 1;
203 }
204 for (p = argv, ip = used; *p; ++p, ++ip)
205 if (!*ip)
206 (void)fprintf(stderr,
207 "finger: %s: no such user\n", *p);
208 }
209
210 /* Handle network requests. */
211 net: for (p = nargv; *p;)
212 netfinger(*p++);
213
214 if (entries == 0)
215 return;
216
217 /*
218 * Scan thru the list of users currently logged in, saving
219 * appropriate data whenever a match occurs.
220 */
221 if (!freopen(_PATH_UTMP, "r", stdin))
222 err(1, "%s", _PATH_UTMP);
223 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
224 if (!user.ut_name[0])
225 continue;
226 if ((pn = find_person(user.ut_name)) == NULL)
227 continue;
228 enter_where(&user, pn);
229 }
230 if (db)
231 for (sflag = R_FIRST;; sflag = R_NEXT) {
232 PERSON *tmp;
233
234 r = (*db->seq)(db, &key, &data, sflag);
235 if (r == -1)
236 err(1, "db seq");
237 if (r == 1)
238 break;
239 memmove(&tmp, data.data, sizeof tmp);
240 enter_lastlog(tmp);
241 }
242 }
243