util.c revision 1.30 1 1.30 kim /* $NetBSD: util.c,v 1.30 2020/05/07 13:40:20 kim Exp $ */
2 1.9 tls
3 1.1 cgd /*
4 1.11 mrg * Copyright (c) 1989, 1993
5 1.11 mrg * The Regents of the University of California. All rights reserved.
6 1.21 agc *
7 1.21 agc * This code is derived from software contributed to Berkeley by
8 1.21 agc * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
9 1.21 agc *
10 1.21 agc * Redistribution and use in source and binary forms, with or without
11 1.21 agc * modification, are permitted provided that the following conditions
12 1.21 agc * are met:
13 1.21 agc * 1. Redistributions of source code must retain the above copyright
14 1.21 agc * notice, this list of conditions and the following disclaimer.
15 1.21 agc * 2. Redistributions in binary form must reproduce the above copyright
16 1.21 agc * notice, this list of conditions and the following disclaimer in the
17 1.21 agc * documentation and/or other materials provided with the distribution.
18 1.21 agc * 3. Neither the name of the University nor the names of its contributors
19 1.21 agc * may be used to endorse or promote products derived from this software
20 1.21 agc * without specific prior written permission.
21 1.21 agc *
22 1.21 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.21 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.21 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.21 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.21 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.21 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.21 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.21 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.21 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.21 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.21 agc * SUCH DAMAGE.
33 1.21 agc */
34 1.21 agc
35 1.21 agc /*
36 1.7 lukem * Portions Copyright (c) 1983, 1995, 1996 Eric P. Allman
37 1.1 cgd *
38 1.1 cgd * This code is derived from software contributed to Berkeley by
39 1.1 cgd * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
40 1.1 cgd *
41 1.1 cgd * Redistribution and use in source and binary forms, with or without
42 1.1 cgd * modification, are permitted provided that the following conditions
43 1.1 cgd * are met:
44 1.1 cgd * 1. Redistributions of source code must retain the above copyright
45 1.1 cgd * notice, this list of conditions and the following disclaimer.
46 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
47 1.1 cgd * notice, this list of conditions and the following disclaimer in the
48 1.1 cgd * documentation and/or other materials provided with the distribution.
49 1.1 cgd * 3. All advertising materials mentioning features or use of this software
50 1.1 cgd * must display the following acknowledgement:
51 1.1 cgd * This product includes software developed by the University of
52 1.1 cgd * California, Berkeley and its contributors.
53 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
54 1.1 cgd * may be used to endorse or promote products derived from this software
55 1.1 cgd * without specific prior written permission.
56 1.1 cgd *
57 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 1.1 cgd * SUCH DAMAGE.
68 1.1 cgd */
69 1.1 cgd
70 1.11 mrg #include <sys/cdefs.h>
71 1.1 cgd #ifndef lint
72 1.11 mrg #if 0
73 1.11 mrg static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
74 1.11 mrg #else
75 1.30 kim __RCSID("$NetBSD: util.c,v 1.30 2020/05/07 13:40:20 kim Exp $");
76 1.11 mrg #endif
77 1.1 cgd #endif /* not lint */
78 1.1 cgd
79 1.1 cgd #include <sys/param.h>
80 1.1 cgd #include <sys/stat.h>
81 1.11 mrg
82 1.11 mrg #include <db.h>
83 1.11 mrg #include <ctype.h>
84 1.11 mrg #include <err.h>
85 1.11 mrg #include <errno.h>
86 1.11 mrg #include <fcntl.h>
87 1.11 mrg #include <paths.h>
88 1.11 mrg #include <pwd.h>
89 1.1 cgd #include <stdio.h>
90 1.5 cgd #include <stdlib.h>
91 1.1 cgd #include <string.h>
92 1.7 lukem #include <unistd.h>
93 1.11 mrg
94 1.18 christos #include "utmpentry.h"
95 1.18 christos
96 1.1 cgd #include "finger.h"
97 1.7 lukem #include "extern.h"
98 1.1 cgd
99 1.24 perry static void find_idle_and_ttywrite(WHERE *);
100 1.24 perry static void userinfo(PERSON *, struct passwd *);
101 1.24 perry static WHERE *walloc(PERSON *);
102 1.1 cgd
103 1.7 lukem int
104 1.24 perry match(struct passwd *pw, char *user)
105 1.1 cgd {
106 1.12 mycroft char *p;
107 1.12 mycroft char *bp, name[1024];
108 1.1 cgd
109 1.11 mrg if (!strcasecmp(pw->pw_name, user))
110 1.11 mrg return(1);
111 1.11 mrg
112 1.20 itojun (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
113 1.1 cgd
114 1.11 mrg /* Ampersands get replaced by the login name. */
115 1.12 mycroft if (!(p = strsep(&bp, ",")))
116 1.1 cgd return(0);
117 1.11 mrg
118 1.7 lukem expandusername(p, pw->pw_name, name, sizeof(name));
119 1.12 mycroft bp = name;
120 1.12 mycroft while ((p = strsep(&bp, "\t ")))
121 1.1 cgd if (!strcasecmp(p, user))
122 1.1 cgd return(1);
123 1.1 cgd return(0);
124 1.1 cgd }
125 1.1 cgd
126 1.7 lukem /* inspired by usr.sbin/sendmail/util.c::buildfname */
127 1.7 lukem void
128 1.24 perry expandusername(const char *gecos, const char *login, char *buf, int buflen)
129 1.7 lukem {
130 1.12 mycroft const char *p;
131 1.12 mycroft char *bp;
132 1.7 lukem
133 1.7 lukem /* why do we skip asterisks!?!? */
134 1.7 lukem if (*gecos == '*')
135 1.7 lukem gecos++;
136 1.7 lukem bp = buf;
137 1.7 lukem
138 1.7 lukem /* copy gecos, interpolating & to be full name */
139 1.7 lukem for (p = gecos; *p != '\0'; p++) {
140 1.7 lukem if (bp >= &buf[buflen - 1]) {
141 1.7 lukem /* buffer overflow - just use login name */
142 1.7 lukem snprintf(buf, buflen, "%s", login);
143 1.7 lukem buf[buflen - 1] = '\0';
144 1.7 lukem return;
145 1.7 lukem }
146 1.7 lukem if (*p == '&') {
147 1.7 lukem /* interpolate full name */
148 1.7 lukem snprintf(bp, buflen - (bp - buf), "%s", login);
149 1.22 dsl *bp = toupper((unsigned char)*bp);
150 1.7 lukem bp += strlen(bp);
151 1.7 lukem }
152 1.7 lukem else
153 1.7 lukem *bp++ = *p;
154 1.7 lukem }
155 1.7 lukem *bp = '\0';
156 1.7 lukem }
157 1.7 lukem
158 1.7 lukem void
159 1.24 perry enter_lastlog(PERSON *pn)
160 1.1 cgd {
161 1.7 lukem WHERE *w;
162 1.30 kim static int opened;
163 1.30 kim #ifdef SUPPORT_UTMPX
164 1.30 kim # define ll_time ll_tv.tv_sec
165 1.30 kim # define UT_LINESIZE _UTX_LINESIZE
166 1.30 kim # define UT_HOSTSIZE _UTX_HOSTSIZE
167 1.30 kim static DB *lldb = NULL;
168 1.30 kim DBT key, data;
169 1.30 kim struct lastlogx ll;
170 1.30 kim #else
171 1.30 kim static int fd;
172 1.1 cgd struct lastlog ll;
173 1.30 kim #endif
174 1.1 cgd char doit = 0;
175 1.1 cgd
176 1.30 kim (void)memset(&ll, 0, sizeof(ll));
177 1.30 kim
178 1.1 cgd /* some systems may not maintain lastlog, don't report errors. */
179 1.1 cgd if (!opened) {
180 1.30 kim #ifdef SUPPORT_UTMPX
181 1.30 kim lldb = dbopen(_PATH_LASTLOGX, O_RDONLY|O_SHLOCK, 0, DB_HASH, NULL);
182 1.30 kim #else
183 1.1 cgd fd = open(_PATH_LASTLOG, O_RDONLY, 0);
184 1.30 kim #endif
185 1.1 cgd opened = 1;
186 1.1 cgd }
187 1.30 kim #ifdef SUPPORT_UTMPX
188 1.30 kim if (lldb != NULL) {
189 1.30 kim key.data = &pn->uid;
190 1.30 kim key.size = sizeof(pn->uid);
191 1.30 kim if ((*lldb->get)(lldb, &key, &data, 0) == 0 &&
192 1.30 kim data.size == sizeof(ll))
193 1.30 kim (void)memcpy(&ll, data.data, sizeof(ll));
194 1.30 kim }
195 1.30 kim #else
196 1.1 cgd if (fd == -1 ||
197 1.11 mrg lseek(fd, (off_t)pn->uid * sizeof(ll), SEEK_SET) !=
198 1.28 lukem (off_t)pn->uid * (off_t)sizeof(ll) ||
199 1.1 cgd read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
200 1.1 cgd /* as if never logged in */
201 1.10 pk ll.ll_line[0] = ll.ll_host[0] = '\0';
202 1.1 cgd ll.ll_time = 0;
203 1.1 cgd }
204 1.30 kim #endif
205 1.1 cgd if ((w = pn->whead) == NULL)
206 1.1 cgd doit = 1;
207 1.1 cgd else if (ll.ll_time != 0) {
208 1.1 cgd /* if last login is earlier than some current login */
209 1.1 cgd for (; !doit && w != NULL; w = w->next)
210 1.1 cgd if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
211 1.1 cgd doit = 1;
212 1.1 cgd /*
213 1.1 cgd * and if it's not any of the current logins
214 1.1 cgd * can't use time comparison because there may be a small
215 1.1 cgd * discrepency since login calls time() twice
216 1.1 cgd */
217 1.1 cgd for (w = pn->whead; doit && w != NULL; w = w->next)
218 1.1 cgd if (w->info == LOGGEDIN &&
219 1.1 cgd strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
220 1.1 cgd doit = 0;
221 1.1 cgd }
222 1.1 cgd if (doit) {
223 1.1 cgd w = walloc(pn);
224 1.1 cgd w->info = LASTLOG;
225 1.26 rumble if ((w->tty = malloc(UT_LINESIZE + 1)) == NULL)
226 1.26 rumble err(1, NULL);
227 1.26 rumble memcpy(w->tty, ll.ll_line, UT_LINESIZE);
228 1.25 elad w->tty[UT_LINESIZE] = '\0';
229 1.26 rumble if ((w->host = malloc(UT_HOSTSIZE + 1)) == NULL)
230 1.26 rumble err(1, NULL);
231 1.26 rumble memcpy(w->host, ll.ll_host, UT_HOSTSIZE);
232 1.25 elad w->host[UT_HOSTSIZE] = '\0';
233 1.1 cgd w->loginat = ll.ll_time;
234 1.1 cgd }
235 1.1 cgd }
236 1.1 cgd
237 1.7 lukem void
238 1.24 perry enter_where(struct utmpentry *ep, PERSON *pn)
239 1.1 cgd {
240 1.18 christos WHERE *w = walloc(pn);
241 1.1 cgd
242 1.1 cgd w->info = LOGGEDIN;
243 1.18 christos w->tty = ep->line;
244 1.18 christos w->host = ep->host;
245 1.19 simonb w->loginat = (time_t)ep->tv.tv_sec;
246 1.1 cgd find_idle_and_ttywrite(w);
247 1.1 cgd }
248 1.1 cgd
249 1.1 cgd PERSON *
250 1.24 perry enter_person(struct passwd *pw)
251 1.1 cgd {
252 1.11 mrg DBT data, key;
253 1.11 mrg PERSON *pn;
254 1.1 cgd
255 1.11 mrg if (db == NULL &&
256 1.11 mrg (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
257 1.11 mrg err(1, NULL);
258 1.11 mrg
259 1.12 mycroft key.data = (char *)pw->pw_name;
260 1.11 mrg key.size = strlen(pw->pw_name);
261 1.11 mrg
262 1.11 mrg switch ((*db->get)(db, &key, &data, 0)) {
263 1.11 mrg case 0:
264 1.11 mrg memmove(&pn, data.data, sizeof pn);
265 1.11 mrg return (pn);
266 1.11 mrg default:
267 1.11 mrg case -1:
268 1.11 mrg err(1, "db get");
269 1.11 mrg /* NOTREACHED */
270 1.11 mrg case 1:
271 1.11 mrg ++entries;
272 1.1 cgd pn = palloc();
273 1.1 cgd userinfo(pn, pw);
274 1.1 cgd pn->whead = NULL;
275 1.11 mrg
276 1.11 mrg data.size = sizeof(PERSON *);
277 1.11 mrg data.data = &pn;
278 1.11 mrg if ((*db->put)(db, &key, &data, 0))
279 1.11 mrg err(1, "db put");
280 1.11 mrg return (pn);
281 1.1 cgd }
282 1.1 cgd }
283 1.1 cgd
284 1.1 cgd PERSON *
285 1.24 perry find_person(char *name)
286 1.1 cgd {
287 1.11 mrg DBT data, key;
288 1.11 mrg PERSON *p;
289 1.1 cgd
290 1.11 mrg if (!db)
291 1.11 mrg return(NULL);
292 1.1 cgd
293 1.18 christos key.data = name;
294 1.23 christos key.size = strlen(name);
295 1.11 mrg
296 1.11 mrg if ((*db->get)(db, &key, &data, 0))
297 1.11 mrg return (NULL);
298 1.11 mrg memmove(&p, data.data, sizeof p);
299 1.11 mrg return (p);
300 1.1 cgd }
301 1.1 cgd
302 1.1 cgd PERSON *
303 1.24 perry palloc(void)
304 1.1 cgd {
305 1.1 cgd PERSON *p;
306 1.1 cgd
307 1.11 mrg if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
308 1.11 mrg err(1, NULL);
309 1.1 cgd return(p);
310 1.1 cgd }
311 1.1 cgd
312 1.11 mrg static WHERE *
313 1.24 perry walloc(PERSON *pn)
314 1.1 cgd {
315 1.7 lukem WHERE *w;
316 1.1 cgd
317 1.11 mrg if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
318 1.11 mrg err(1, NULL);
319 1.1 cgd if (pn->whead == NULL)
320 1.1 cgd pn->whead = pn->wtail = w;
321 1.1 cgd else {
322 1.1 cgd pn->wtail->next = w;
323 1.1 cgd pn->wtail = w;
324 1.1 cgd }
325 1.1 cgd w->next = NULL;
326 1.1 cgd return(w);
327 1.1 cgd }
328 1.1 cgd
329 1.1 cgd char *
330 1.24 perry prphone(char *num)
331 1.1 cgd {
332 1.7 lukem char *p;
333 1.1 cgd int len;
334 1.1 cgd static char pbuf[15];
335 1.1 cgd
336 1.1 cgd /* don't touch anything if the user has their own formatting */
337 1.1 cgd for (p = num; *p; ++p)
338 1.14 christos if (!isdigit((unsigned char)*p))
339 1.1 cgd return(num);
340 1.1 cgd len = p - num;
341 1.1 cgd p = pbuf;
342 1.1 cgd switch(len) {
343 1.1 cgd case 11: /* +0-123-456-7890 */
344 1.1 cgd *p++ = '+';
345 1.1 cgd *p++ = *num++;
346 1.1 cgd *p++ = '-';
347 1.1 cgd /* FALLTHROUGH */
348 1.1 cgd case 10: /* 012-345-6789 */
349 1.1 cgd *p++ = *num++;
350 1.1 cgd *p++ = *num++;
351 1.1 cgd *p++ = *num++;
352 1.1 cgd *p++ = '-';
353 1.1 cgd /* FALLTHROUGH */
354 1.1 cgd case 7: /* 012-3456 */
355 1.1 cgd *p++ = *num++;
356 1.1 cgd *p++ = *num++;
357 1.1 cgd *p++ = *num++;
358 1.1 cgd break;
359 1.1 cgd case 5: /* x0-1234 */
360 1.3 brezak case 4: /* x1234 */
361 1.1 cgd *p++ = 'x';
362 1.1 cgd *p++ = *num++;
363 1.1 cgd break;
364 1.1 cgd default:
365 1.1 cgd return(num);
366 1.1 cgd }
367 1.3 brezak if (len != 4) {
368 1.3 brezak *p++ = '-';
369 1.3 brezak *p++ = *num++;
370 1.3 brezak }
371 1.1 cgd *p++ = *num++;
372 1.1 cgd *p++ = *num++;
373 1.1 cgd *p++ = *num++;
374 1.1 cgd *p = '\0';
375 1.1 cgd return(pbuf);
376 1.11 mrg }
377 1.11 mrg
378 1.11 mrg static void
379 1.24 perry find_idle_and_ttywrite(WHERE *w)
380 1.11 mrg {
381 1.11 mrg struct stat sb;
382 1.11 mrg
383 1.11 mrg (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
384 1.11 mrg if (stat(tbuf, &sb) < 0) {
385 1.16 itojun warn("%s", tbuf);
386 1.29 chs w->idletime = 0;
387 1.29 chs w->writable = 0;
388 1.11 mrg return;
389 1.11 mrg }
390 1.11 mrg w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
391 1.11 mrg
392 1.11 mrg #define TALKABLE 0220 /* tty is writable if 220 mode */
393 1.11 mrg w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
394 1.11 mrg }
395 1.11 mrg
396 1.11 mrg static void
397 1.24 perry userinfo(PERSON *pn, struct passwd *pw)
398 1.11 mrg {
399 1.11 mrg char *p;
400 1.11 mrg char *bp, name[1024];
401 1.11 mrg struct stat sb;
402 1.11 mrg
403 1.11 mrg pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
404 1.11 mrg
405 1.11 mrg pn->uid = pw->pw_uid;
406 1.11 mrg pn->name = strdup(pw->pw_name);
407 1.11 mrg pn->dir = strdup(pw->pw_dir);
408 1.11 mrg pn->shell = strdup(pw->pw_shell);
409 1.11 mrg
410 1.20 itojun (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
411 1.11 mrg
412 1.11 mrg /* ampersands get replaced by the login name */
413 1.11 mrg if (!(p = strsep(&bp, ",")))
414 1.11 mrg return;
415 1.11 mrg expandusername(p, pw->pw_name, name, sizeof(name));
416 1.11 mrg pn->realname = strdup(name);
417 1.11 mrg pn->office = ((p = strsep(&bp, ",")) && *p) ?
418 1.11 mrg strdup(p) : NULL;
419 1.11 mrg pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
420 1.11 mrg strdup(p) : NULL;
421 1.11 mrg pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
422 1.11 mrg strdup(p) : NULL;
423 1.27 christos (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR,
424 1.11 mrg pw->pw_name);
425 1.11 mrg pn->mailrecv = -1; /* -1 == not_valid */
426 1.11 mrg if (stat(tbuf, &sb) < 0) {
427 1.11 mrg if (errno != ENOENT) {
428 1.11 mrg (void)fprintf(stderr,
429 1.11 mrg "finger: %s: %s\n", tbuf, strerror(errno));
430 1.11 mrg return;
431 1.11 mrg }
432 1.11 mrg } else if (sb.st_size != 0) {
433 1.11 mrg pn->mailrecv = sb.st_mtime;
434 1.11 mrg pn->mailread = sb.st_atime;
435 1.11 mrg }
436 1.1 cgd }
437