1 |
|
|
/* $OpenBSD: finger.c,v 1.26 2015/11/03 05:13:35 mmcc Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1989 The Regents of the University of California. |
5 |
|
|
* All rights reserved. |
6 |
|
|
* |
7 |
|
|
* This code is derived from software contributed to Berkeley by |
8 |
|
|
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
19 |
|
|
* may be used to endorse or promote products derived from this software |
20 |
|
|
* without specific prior written permission. |
21 |
|
|
* |
22 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 |
|
|
* SUCH DAMAGE. |
33 |
|
|
*/ |
34 |
|
|
|
35 |
|
|
/* |
36 |
|
|
* Luke Mewburn <lukem@netbsd.org> added the following on 961121: |
37 |
|
|
* - mail status ("No Mail", "Mail read:...", or "New Mail ..., |
38 |
|
|
* Unread since ...".) |
39 |
|
|
* - 4 digit phone extensions (3210 is printed as x3210.) |
40 |
|
|
* - host/office toggling in short format with -h & -o. |
41 |
|
|
* - short day names (`Tue' printed instead of `Jun 21' if the |
42 |
|
|
* login time is < 6 days. |
43 |
|
|
*/ |
44 |
|
|
|
45 |
|
|
/* |
46 |
|
|
* Finger prints out information about users. It is not portable since |
47 |
|
|
* certain fields (e.g. the full user name, office, and phone numbers) are |
48 |
|
|
* extracted from the gecos field of the passwd file which other UNIXes |
49 |
|
|
* may not have or may use for other things. |
50 |
|
|
* |
51 |
|
|
* There are currently two output formats; the short format is one line |
52 |
|
|
* per user and displays login name, tty, login time, real name, idle time, |
53 |
|
|
* and either remote host information (default) or office location/phone |
54 |
|
|
* number, depending on if -h or -o is used respectively. |
55 |
|
|
* The long format gives the same information (in a more legible format) as |
56 |
|
|
* well as home directory, shell, mail info, and .plan/.project files. |
57 |
|
|
*/ |
58 |
|
|
|
59 |
|
|
#include <sys/file.h> |
60 |
|
|
#include <sys/stat.h> |
61 |
|
|
#include <stdio.h> |
62 |
|
|
#include <stdlib.h> |
63 |
|
|
#include <string.h> |
64 |
|
|
#include <time.h> |
65 |
|
|
#include <unistd.h> |
66 |
|
|
#include <limits.h> |
67 |
|
|
#include <err.h> |
68 |
|
|
#include "finger.h" |
69 |
|
|
#include "extern.h" |
70 |
|
|
|
71 |
|
|
time_t now; |
72 |
|
|
int entries, lflag, sflag, mflag, oflag, pplan, Mflag; |
73 |
|
|
char tbuf[1024]; |
74 |
|
|
PERSON *htab[HSIZE]; |
75 |
|
|
PERSON *phead, *ptail; |
76 |
|
|
|
77 |
|
|
int |
78 |
|
|
main(int argc, char *argv[]) |
79 |
|
|
{ |
80 |
|
|
extern int optind; |
81 |
|
|
extern char *__progname; |
82 |
|
|
int ch; |
83 |
|
|
char domain[HOST_NAME_MAX+1]; |
84 |
|
|
struct stat sb; |
85 |
|
|
|
86 |
|
|
oflag = 1; /* default to old "office" behavior */ |
87 |
|
|
|
88 |
|
|
while ((ch = getopt(argc, argv, "lmMpsho")) != -1) |
89 |
|
|
switch(ch) { |
90 |
|
|
case 'l': |
91 |
|
|
lflag = 1; /* long format */ |
92 |
|
|
break; |
93 |
|
|
case 'm': |
94 |
|
|
mflag = 1; /* force exact match of names */ |
95 |
|
|
break; |
96 |
|
|
case 'M': |
97 |
|
|
Mflag = 1; /* allow name matching */ |
98 |
|
|
break; |
99 |
|
|
case 'p': |
100 |
|
|
pplan = 1; /* don't show .plan/.project */ |
101 |
|
|
break; |
102 |
|
|
case 's': |
103 |
|
|
sflag = 1; /* short format */ |
104 |
|
|
break; |
105 |
|
|
case 'h': |
106 |
|
|
oflag = 0; /* remote host info */ |
107 |
|
|
break; |
108 |
|
|
case 'o': |
109 |
|
|
oflag = 1; /* office info */ |
110 |
|
|
break; |
111 |
|
|
case '?': |
112 |
|
|
default: |
113 |
|
|
(void)fprintf(stderr, |
114 |
|
|
"usage: %s [-hlMmops] [login ...]\n", __progname); |
115 |
|
|
exit(1); |
116 |
|
|
} |
117 |
|
|
argc -= optind; |
118 |
|
|
argv += optind; |
119 |
|
|
|
120 |
|
|
/* If a domainname is set, increment mflag. */ |
121 |
|
|
if ((getdomainname(domain, sizeof(domain)) == 0) && domain[0]) |
122 |
|
|
mflag++; |
123 |
|
|
/* If _PATH_MP_DB is larger than 1MB, increment mflag. */ |
124 |
|
|
if (stat(_PATH_MP_DB, &sb) == 0) { |
125 |
|
|
if (sb.st_size > 1048576) |
126 |
|
|
mflag++; |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
if (pledge("stdio rpath getpw dns inet wpath cpath", NULL) == -1) |
130 |
|
|
err(1, "pledge"); |
131 |
|
|
|
132 |
|
|
(void)time(&now); |
133 |
|
|
if (!*argv) { |
134 |
|
|
/* |
135 |
|
|
* Assign explicit "small" format if no names given and -l |
136 |
|
|
* not selected. Force the -s BEFORE we get names so proper |
137 |
|
|
* screening will be done. |
138 |
|
|
*/ |
139 |
|
|
if (pledge("stdio rpath getpw wpath cpath", NULL) == -1) |
140 |
|
|
err(1, "pledge"); |
141 |
|
|
|
142 |
|
|
if (!lflag) |
143 |
|
|
sflag = 1; /* if -l not explicit, force -s */ |
144 |
|
|
loginlist(); |
145 |
|
|
if (entries == 0) |
146 |
|
|
(void)printf("No one logged on.\n"); |
147 |
|
|
} else { |
148 |
|
|
userlist(argc, argv); |
149 |
|
|
/* |
150 |
|
|
* Assign explicit "large" format if names given and -s not |
151 |
|
|
* explicitly stated. Force the -l AFTER we get names so any |
152 |
|
|
* remote finger attempts specified won't be mishandled. |
153 |
|
|
*/ |
154 |
|
|
if (!sflag) |
155 |
|
|
lflag = 1; /* if -s not explicit, force -l */ |
156 |
|
|
} |
157 |
|
|
if (entries != 0) { |
158 |
|
|
if (lflag) |
159 |
|
|
lflag_print(); |
160 |
|
|
else |
161 |
|
|
sflag_print(); |
162 |
|
|
} |
163 |
|
|
exit(0); |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
void |
167 |
|
|
loginlist(void) |
168 |
|
|
{ |
169 |
|
|
PERSON *pn; |
170 |
|
|
struct passwd *pw; |
171 |
|
|
struct utmp user; |
172 |
|
|
char name[UT_NAMESIZE + 1]; |
173 |
|
|
|
174 |
|
|
if (!freopen(_PATH_UTMP, "r", stdin)) |
175 |
|
|
err(2, _PATH_UTMP); |
176 |
|
|
name[UT_NAMESIZE] = '\0'; |
177 |
|
|
setpassent(1); |
178 |
|
|
while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { |
179 |
|
|
if (!user.ut_name[0]) |
180 |
|
|
continue; |
181 |
|
|
if ((pn = find_person(user.ut_name)) == NULL) { |
182 |
|
|
bcopy(user.ut_name, name, UT_NAMESIZE); |
183 |
|
|
if ((pw = getpwnam(name)) == NULL) |
184 |
|
|
continue; |
185 |
|
|
pn = enter_person(pw); |
186 |
|
|
} |
187 |
|
|
enter_where(&user, pn); |
188 |
|
|
} |
189 |
|
|
endpwent(); |
190 |
|
|
for (pn = phead; lflag && pn != NULL; pn = pn->next) |
191 |
|
|
enter_lastlog(pn); |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
void |
195 |
|
|
userlist(int argc, char **argv) |
196 |
|
|
{ |
197 |
|
|
int i; |
198 |
|
|
PERSON *pn; |
199 |
|
|
PERSON *nethead, **nettail; |
200 |
|
|
struct utmp user; |
201 |
|
|
struct passwd *pw; |
202 |
|
|
int dolocal, *used; |
203 |
|
|
|
204 |
|
|
if (!(used = calloc((u_int)argc, (u_int)sizeof(int)))) |
205 |
|
|
err(2, "malloc"); |
206 |
|
|
|
207 |
|
|
/* pull out all network requests */ |
208 |
|
|
for (i = 0, dolocal = 0, nettail = &nethead; i < argc; i++) { |
209 |
|
|
if (!strchr(argv[i], '@')) { |
210 |
|
|
dolocal = 1; |
211 |
|
|
continue; |
212 |
|
|
} |
213 |
|
|
pn = palloc(); |
214 |
|
|
*nettail = pn; |
215 |
|
|
nettail = &pn->next; |
216 |
|
|
pn->name = argv[i]; |
217 |
|
|
used[i] = -1; |
218 |
|
|
} |
219 |
|
|
*nettail = NULL; |
220 |
|
|
|
221 |
|
|
if (!dolocal) |
222 |
|
|
goto net; |
223 |
|
|
|
224 |
|
|
if (nettail == &nethead) |
225 |
|
|
if (pledge("stdio rpath getpw wpath cpath", NULL) == -1) |
226 |
|
|
err(1, "pledge"); |
227 |
|
|
|
228 |
|
|
/* |
229 |
|
|
* traverse the list of possible login names and check the login name |
230 |
|
|
* and real name against the name specified by the user. |
231 |
|
|
*/ |
232 |
|
|
setpassent(1); |
233 |
|
|
if ((mflag - Mflag) > 0) { |
234 |
|
|
for (i = 0; i < argc; i++) |
235 |
|
|
if (used[i] >= 0 && (pw = getpwnam(argv[i]))) { |
236 |
|
|
enter_person(pw); |
237 |
|
|
used[i] = 1; |
238 |
|
|
} |
239 |
|
|
} else while ((pw = getpwent()) != NULL) |
240 |
|
|
for (i = 0; i < argc; i++) |
241 |
|
|
if (used[i] >= 0 && |
242 |
|
|
(!strcasecmp(pw->pw_name, argv[i]) || |
243 |
|
|
match(pw, argv[i]))) { |
244 |
|
|
enter_person(pw); |
245 |
|
|
used[i] = 1; |
246 |
|
|
} |
247 |
|
|
endpwent(); |
248 |
|
|
|
249 |
|
|
/* list errors */ |
250 |
|
|
for (i = 0; i < argc; i++) |
251 |
|
|
if (!used[i]) |
252 |
|
|
warnx("%s: no such user.", argv[i]); |
253 |
|
|
|
254 |
|
|
/* handle network requests */ |
255 |
|
|
net: for (pn = nethead; pn; pn = pn->next) { |
256 |
|
|
netfinger(pn->name); |
257 |
|
|
if (pn->next || entries) |
258 |
|
|
putchar('\n'); |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
free(used); |
262 |
|
|
if (entries == 0) |
263 |
|
|
return; |
264 |
|
|
|
265 |
|
|
/* |
266 |
|
|
* Scan thru the list of users currently logged in, saving |
267 |
|
|
* appropriate data whenever a match occurs. |
268 |
|
|
*/ |
269 |
|
|
if (!freopen(_PATH_UTMP, "r", stdin)) |
270 |
|
|
err(1, _PATH_UTMP); |
271 |
|
|
while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { |
272 |
|
|
if (!user.ut_name[0]) |
273 |
|
|
continue; |
274 |
|
|
if ((pn = find_person(user.ut_name)) == NULL) |
275 |
|
|
continue; |
276 |
|
|
enter_where(&user, pn); |
277 |
|
|
} |
278 |
|
|
for (pn = phead; pn != NULL; pn = pn->next) |
279 |
|
|
enter_lastlog(pn); |
280 |
|
|
} |