1 |
|
|
/* $OpenBSD: util.c,v 1.32 2015/12/26 20:51:35 guenther Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1989 The Regents of the University of California. |
5 |
|
|
* All rights reserved. |
6 |
|
|
* Portions Copyright (c) 1983, 1995, 1996 Eric P. Allman (woof!) |
7 |
|
|
* |
8 |
|
|
* This code is derived from software contributed to Berkeley by |
9 |
|
|
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or without |
12 |
|
|
* modification, are permitted provided that the following conditions |
13 |
|
|
* are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in the |
18 |
|
|
* documentation and/or other materials provided with the distribution. |
19 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
20 |
|
|
* may be used to endorse or promote products derived from this software |
21 |
|
|
* without specific prior written permission. |
22 |
|
|
* |
23 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
24 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 |
|
|
* SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
#include <sys/types.h> |
37 |
|
|
#include <sys/uio.h> |
38 |
|
|
#include <sys/stat.h> |
39 |
|
|
#include <err.h> |
40 |
|
|
#include <stdio.h> |
41 |
|
|
#include <stdlib.h> |
42 |
|
|
#include <ctype.h> |
43 |
|
|
#include <string.h> |
44 |
|
|
#include <paths.h> |
45 |
|
|
#include <errno.h> |
46 |
|
|
#include <fcntl.h> |
47 |
|
|
#include <unistd.h> |
48 |
|
|
#include <vis.h> |
49 |
|
|
#include "finger.h" |
50 |
|
|
#include "extern.h" |
51 |
|
|
|
52 |
|
|
char *estrdup(char *); |
53 |
|
|
WHERE *walloc(PERSON *pn); |
54 |
|
|
void find_idle_and_ttywrite(WHERE *); |
55 |
|
|
void userinfo(PERSON *, struct passwd *); |
56 |
|
|
|
57 |
|
|
void |
58 |
|
|
find_idle_and_ttywrite(WHERE *w) |
59 |
|
|
{ |
60 |
|
|
struct stat sb; |
61 |
|
|
|
62 |
|
|
(void)snprintf(tbuf, sizeof(tbuf), "%s%s", _PATH_DEV, w->tty); |
63 |
|
|
if (stat(tbuf, &sb) < 0) { |
64 |
|
|
/* Don't bitch about it, just handle it... */ |
65 |
|
|
w->idletime = 0; |
66 |
|
|
w->writable = 0; |
67 |
|
|
|
68 |
|
|
return; |
69 |
|
|
} |
70 |
|
|
w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; |
71 |
|
|
|
72 |
|
|
#define TALKABLE 0220 /* tty is writable if 220 mode */ |
73 |
|
|
w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); |
74 |
|
|
} |
75 |
|
|
|
76 |
|
|
char * |
77 |
|
|
estrdup(char *s) |
78 |
|
|
{ |
79 |
|
|
char *p = strdup(s); |
80 |
|
|
if (!p) |
81 |
|
|
err(1, "strdup"); |
82 |
|
|
return (p); |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
void |
86 |
|
|
userinfo(PERSON *pn, struct passwd *pw) |
87 |
|
|
{ |
88 |
|
|
char *p; |
89 |
|
|
char *bp, name[1024]; |
90 |
|
|
struct stat sb; |
91 |
|
|
int len; |
92 |
|
|
|
93 |
|
|
pn->realname = pn->office = pn->officephone = pn->homephone = NULL; |
94 |
|
|
pn->mailrecv = -1; /* -1 == not_valid */ |
95 |
|
|
|
96 |
|
|
pn->uid = pw->pw_uid; |
97 |
|
|
pn->name = estrdup(pw->pw_name); |
98 |
|
|
pn->dir = estrdup(pw->pw_dir); |
99 |
|
|
pn->shell = estrdup(pw->pw_shell); |
100 |
|
|
|
101 |
|
|
(void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); |
102 |
|
|
|
103 |
|
|
/* ampersands get replaced by the login name */ |
104 |
|
|
if (!(p = strsep(&bp, ","))) |
105 |
|
|
return; |
106 |
|
|
expandusername(p, pw->pw_name, name, sizeof(name)); |
107 |
|
|
if (stravis(&pn->realname, p, VIS_SAFE|VIS_NOSLASH) == -1) |
108 |
|
|
err(1, "stravis"); |
109 |
|
|
if ((p = strsep(&bp, ",")) && *p) { |
110 |
|
|
if (stravis(&pn->office, p, VIS_SAFE|VIS_NOSLASH) == -1) |
111 |
|
|
err(1, "stravis"); |
112 |
|
|
} |
113 |
|
|
if ((p = strsep(&bp, ",")) && *p) { |
114 |
|
|
if (stravis(&pn->officephone, p, VIS_SAFE|VIS_NOSLASH) == -1) |
115 |
|
|
err(1, "stravis"); |
116 |
|
|
} |
117 |
|
|
if ((p = strsep(&bp, ",")) && *p) { |
118 |
|
|
if (stravis(&pn->homephone, p, VIS_SAFE|VIS_NOSLASH) == -1) |
119 |
|
|
err(1, "stravis"); |
120 |
|
|
} |
121 |
|
|
len = snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILSPOOL, |
122 |
|
|
pw->pw_name); |
123 |
|
|
if (len != -1 && len < sizeof(tbuf)) { |
124 |
|
|
if (stat(tbuf, &sb) < 0) { |
125 |
|
|
if (errno != ENOENT) { |
126 |
|
|
warn("%s", tbuf); |
127 |
|
|
return; |
128 |
|
|
} |
129 |
|
|
} else if (sb.st_size != 0) { |
130 |
|
|
pn->mailrecv = sb.st_mtime; |
131 |
|
|
pn->mailread = sb.st_atime; |
132 |
|
|
} |
133 |
|
|
} |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
int |
137 |
|
|
match(struct passwd *pw, char *user) |
138 |
|
|
{ |
139 |
|
|
char *p, *t; |
140 |
|
|
char name[1024]; |
141 |
|
|
|
142 |
|
|
(void)strlcpy(p = tbuf, pw->pw_gecos, sizeof(tbuf)); |
143 |
|
|
|
144 |
|
|
/* ampersands get replaced by the login name */ |
145 |
|
|
if (!(p = strtok(p, ","))) |
146 |
|
|
return (0); |
147 |
|
|
expandusername(p, pw->pw_name, name, sizeof(name)); |
148 |
|
|
for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) |
149 |
|
|
if (!strcasecmp(p, user)) |
150 |
|
|
return (1); |
151 |
|
|
return (0); |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
/* inspired by usr.sbin/sendmail/util.c::buildfname */ |
155 |
|
|
void |
156 |
|
|
expandusername(char *gecos, char *login, char *buf, int buflen) |
157 |
|
|
{ |
158 |
|
|
char *p, *bp; |
159 |
|
|
|
160 |
|
|
/* why do we skip asterisks!?!? */ |
161 |
|
|
if (*gecos == '*') |
162 |
|
|
gecos++; |
163 |
|
|
bp = buf; |
164 |
|
|
|
165 |
|
|
/* copy gecos, interpolating & to be full name */ |
166 |
|
|
for (p = gecos; *p != '\0'; p++) { |
167 |
|
|
if (bp >= &buf[buflen - 1]) { |
168 |
|
|
/* buffer overflow - just use login name */ |
169 |
|
|
strlcpy(buf, login, buflen); |
170 |
|
|
buf[buflen - 1] = '\0'; |
171 |
|
|
return; |
172 |
|
|
} |
173 |
|
|
if (*p == '&') { |
174 |
|
|
/* interpolate full name */ |
175 |
|
|
strlcpy(bp, login, buflen - (bp - buf)); |
176 |
|
|
*bp = toupper((unsigned char)*bp); |
177 |
|
|
bp += strlen(bp); |
178 |
|
|
} |
179 |
|
|
else |
180 |
|
|
*bp++ = *p; |
181 |
|
|
} |
182 |
|
|
*bp = '\0'; |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
void |
186 |
|
|
enter_lastlog(PERSON *pn) |
187 |
|
|
{ |
188 |
|
|
WHERE *w; |
189 |
|
|
static int opened, fd; |
190 |
|
|
struct lastlog ll; |
191 |
|
|
char doit = 0; |
192 |
|
|
|
193 |
|
|
/* some systems may not maintain lastlog, don't report errors. */ |
194 |
|
|
if (!opened) { |
195 |
|
|
fd = open(_PATH_LASTLOG, O_RDONLY); |
196 |
|
|
opened = 1; |
197 |
|
|
} |
198 |
|
|
if (fd == -1 || |
199 |
|
|
pread(fd, &ll, sizeof(ll), (off_t)pn->uid * sizeof(ll)) != |
200 |
|
|
sizeof(ll)) { |
201 |
|
|
/* as if never logged in */ |
202 |
|
|
ll.ll_line[0] = ll.ll_host[0] = '\0'; |
203 |
|
|
ll.ll_time = 0; |
204 |
|
|
} |
205 |
|
|
if ((w = pn->whead) == NULL) |
206 |
|
|
doit = 1; |
207 |
|
|
else if (ll.ll_time != 0) { |
208 |
|
|
/* if last login is earlier than some current login */ |
209 |
|
|
for (; !doit && w != NULL; w = w->next) |
210 |
|
|
if (w->info == LOGGEDIN && w->loginat < ll.ll_time) |
211 |
|
|
doit = 1; |
212 |
|
|
/* |
213 |
|
|
* and if it's not any of the current logins |
214 |
|
|
* can't use time comparison because there may be a small |
215 |
|
|
* discrepency since login calls time() twice |
216 |
|
|
*/ |
217 |
|
|
for (w = pn->whead; doit && w != NULL; w = w->next) |
218 |
|
|
if (w->info == LOGGEDIN && |
219 |
|
|
strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) |
220 |
|
|
doit = 0; |
221 |
|
|
} |
222 |
|
|
if (doit) { |
223 |
|
|
w = walloc(pn); |
224 |
|
|
w->info = LASTLOG; |
225 |
|
|
bcopy(ll.ll_line, w->tty, UT_LINESIZE); |
226 |
|
|
w->tty[UT_LINESIZE] = 0; |
227 |
|
|
bcopy(ll.ll_host, w->host, UT_HOSTSIZE); |
228 |
|
|
w->host[UT_HOSTSIZE] = 0; |
229 |
|
|
w->loginat = ll.ll_time; |
230 |
|
|
} |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
void |
234 |
|
|
enter_where(struct utmp *ut, PERSON *pn) |
235 |
|
|
{ |
236 |
|
|
WHERE *w = walloc(pn); |
237 |
|
|
|
238 |
|
|
w->info = LOGGEDIN; |
239 |
|
|
bcopy(ut->ut_line, w->tty, UT_LINESIZE); |
240 |
|
|
w->tty[UT_LINESIZE] = 0; |
241 |
|
|
bcopy(ut->ut_host, w->host, UT_HOSTSIZE); |
242 |
|
|
w->host[UT_HOSTSIZE] = 0; |
243 |
|
|
w->loginat = (time_t)ut->ut_time; |
244 |
|
|
find_idle_and_ttywrite(w); |
245 |
|
|
} |
246 |
|
|
|
247 |
|
|
PERSON * |
248 |
|
|
enter_person(struct passwd *pw) |
249 |
|
|
{ |
250 |
|
|
PERSON *pn, **pp; |
251 |
|
|
|
252 |
|
|
for (pp = htab + hash(pw->pw_name); |
253 |
|
|
*pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0; |
254 |
|
|
pp = &(*pp)->hlink) |
255 |
|
|
; |
256 |
|
|
if ((pn = *pp) == NULL) { |
257 |
|
|
pn = palloc(); |
258 |
|
|
entries++; |
259 |
|
|
if (phead == NULL) |
260 |
|
|
phead = ptail = pn; |
261 |
|
|
else { |
262 |
|
|
ptail->next = pn; |
263 |
|
|
ptail = pn; |
264 |
|
|
} |
265 |
|
|
pn->next = NULL; |
266 |
|
|
pn->hlink = NULL; |
267 |
|
|
*pp = pn; |
268 |
|
|
userinfo(pn, pw); |
269 |
|
|
pn->whead = NULL; |
270 |
|
|
} |
271 |
|
|
return (pn); |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
PERSON * |
275 |
|
|
find_person(char *name) |
276 |
|
|
{ |
277 |
|
|
PERSON *pn; |
278 |
|
|
|
279 |
|
|
/* name may be only UT_NAMESIZE long and not terminated */ |
280 |
|
|
for (pn = htab[hash(name)]; |
281 |
|
|
pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0; |
282 |
|
|
pn = pn->hlink) |
283 |
|
|
; |
284 |
|
|
return (pn); |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
int |
288 |
|
|
hash(char *name) |
289 |
|
|
{ |
290 |
|
|
int h, i; |
291 |
|
|
|
292 |
|
|
h = 0; |
293 |
|
|
/* name may be only UT_NAMESIZE long and not terminated */ |
294 |
|
|
for (i = UT_NAMESIZE; --i >= 0 && *name;) |
295 |
|
|
h = ((h << 2 | h >> (HBITS - 2)) ^ *name++) & HMASK; |
296 |
|
|
return (h); |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
PERSON * |
300 |
|
|
palloc(void) |
301 |
|
|
{ |
302 |
|
|
PERSON *p; |
303 |
|
|
|
304 |
|
|
if ((p = malloc((u_int) sizeof(PERSON))) == NULL) |
305 |
|
|
err(1, "malloc"); |
306 |
|
|
return (p); |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
WHERE * |
310 |
|
|
walloc(PERSON *pn) |
311 |
|
|
{ |
312 |
|
|
WHERE *w; |
313 |
|
|
|
314 |
|
|
if ((w = malloc((u_int) sizeof(WHERE))) == NULL) |
315 |
|
|
err(1, "malloc"); |
316 |
|
|
if (pn->whead == NULL) |
317 |
|
|
pn->whead = pn->wtail = w; |
318 |
|
|
else { |
319 |
|
|
pn->wtail->next = w; |
320 |
|
|
pn->wtail = w; |
321 |
|
|
} |
322 |
|
|
w->next = NULL; |
323 |
|
|
return (w); |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
char * |
327 |
|
|
prphone(char *num) |
328 |
|
|
{ |
329 |
|
|
char *p; |
330 |
|
|
int len; |
331 |
|
|
static char pbuf[15]; |
332 |
|
|
|
333 |
|
|
/* don't touch anything if the user has their own formatting */ |
334 |
|
|
for (p = num; *p; ++p) |
335 |
|
|
if (!isdigit((unsigned char)*p)) |
336 |
|
|
return (num); |
337 |
|
|
len = p - num; |
338 |
|
|
p = pbuf; |
339 |
|
|
switch (len) { |
340 |
|
|
case 11: /* +0-123-456-7890 */ |
341 |
|
|
*p++ = '+'; |
342 |
|
|
*p++ = *num++; |
343 |
|
|
*p++ = '-'; |
344 |
|
|
/* FALLTHROUGH */ |
345 |
|
|
case 10: /* 012-345-6789 */ |
346 |
|
|
*p++ = *num++; |
347 |
|
|
*p++ = *num++; |
348 |
|
|
*p++ = *num++; |
349 |
|
|
*p++ = '-'; |
350 |
|
|
/* FALLTHROUGH */ |
351 |
|
|
case 7: /* 012-3456 */ |
352 |
|
|
*p++ = *num++; |
353 |
|
|
*p++ = *num++; |
354 |
|
|
*p++ = *num++; |
355 |
|
|
break; |
356 |
|
|
case 5: /* x0-1234 */ |
357 |
|
|
case 4: /* x1234 */ |
358 |
|
|
*p++ = 'x'; |
359 |
|
|
*p++ = *num++; |
360 |
|
|
break; |
361 |
|
|
default: |
362 |
|
|
return (num); |
363 |
|
|
} |
364 |
|
|
if (len != 4) { |
365 |
|
|
*p++ = '-'; |
366 |
|
|
*p++ = *num++; |
367 |
|
|
} |
368 |
|
|
*p++ = *num++; |
369 |
|
|
*p++ = *num++; |
370 |
|
|
*p++ = *num++; |
371 |
|
|
*p = '\0'; |
372 |
|
|
return (pbuf); |
373 |
|
|
} |