2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 static char sccsid
[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
46 #include <sys/param.h>
47 #include <sys/socket.h>
62 #include "pathnames.h"
64 static void find_idle_and_ttywrite(WHERE
*);
65 static void userinfo(PERSON
*, struct passwd
*);
66 static WHERE
*walloc(PERSON
*);
69 match(struct passwd
*pw
, const char *user
)
74 if (!strcasecmp(pw
->pw_name
, user
))
79 * Why do we skip asterisks!?!?
81 (void)strncpy(p
= tbuf
, pw
->pw_gecos
, sizeof(tbuf
));
82 tbuf
[sizeof(tbuf
) - 1] = '\0';
86 /* Ampersands get replaced by the login name. */
87 if ((p
= strtok(p
, ",")) == NULL
)
90 for (t
= name
; t
< &name
[sizeof(name
) - 1] && (*t
= *p
) != '\0'; ++p
) {
92 (void)strncpy(t
, pw
->pw_name
,
93 sizeof(name
) - (t
- name
));
94 name
[sizeof(name
) - 1] = '\0';
95 while (t
< &name
[sizeof(name
) - 1] && *++t
)
102 for (t
= name
; (p
= strtok(t
, "\t ")) != NULL
; t
= NULL
)
103 if (!strcasecmp(p
, user
))
109 enter_lastlog(PERSON
*pn
)
112 static int opened
, fd
;
116 /* some systems may not maintain lastlog, don't report errors. */
118 fd
= open(_PATH_LASTLOG
, O_RDONLY
, 0);
122 lseek(fd
, (long)pn
->uid
* sizeof(ll
), SEEK_SET
) !=
123 (long)pn
->uid
* sizeof(ll
) ||
124 read(fd
, (char *)&ll
, sizeof(ll
)) != sizeof(ll
)) {
125 /* as if never logged in */
126 ll
.ll_line
[0] = ll
.ll_host
[0] = '\0';
129 if ((w
= pn
->whead
) == NULL
)
131 else if (ll
.ll_time
!= 0) {
132 /* if last login is earlier than some current login */
133 for (; !doit
&& w
!= NULL
; w
= w
->next
)
134 if (w
->info
== LOGGEDIN
&& w
->loginat
< ll
.ll_time
)
137 * and if it's not any of the current logins
138 * can't use time comparison because there may be a small
139 * discrepancy since login calls time() twice
141 for (w
= pn
->whead
; doit
&& w
!= NULL
; w
= w
->next
)
142 if (w
->info
== LOGGEDIN
&&
143 strncmp(w
->tty
, ll
.ll_line
, UT_LINESIZE
) == 0)
149 bcopy(ll
.ll_line
, w
->tty
, UT_LINESIZE
);
150 w
->tty
[UT_LINESIZE
] = 0;
151 bcopy(ll
.ll_host
, w
->host
, UT_HOSTSIZE
);
152 w
->host
[UT_HOSTSIZE
] = 0;
153 w
->loginat
= ll
.ll_time
;
158 enter_where(struct utmp
*ut
, PERSON
*pn
)
164 bcopy(ut
->ut_line
, w
->tty
, UT_LINESIZE
);
165 w
->tty
[UT_LINESIZE
] = 0;
166 bcopy(ut
->ut_host
, w
->host
, UT_HOSTSIZE
);
167 w
->host
[UT_HOSTSIZE
] = 0;
168 w
->loginat
= (time_t)ut
->ut_time
;
169 find_idle_and_ttywrite(w
);
173 enter_person(struct passwd
*pw
)
179 (db
= dbopen(NULL
, O_RDWR
, 0, DB_BTREE
, NULL
)) == NULL
)
182 key
.data
= pw
->pw_name
;
183 key
.size
= strlen(pw
->pw_name
);
185 switch ((*db
->get
)(db
, &key
, &data
, 0)) {
187 memmove(&pn
, data
.data
, sizeof pn
);
199 data
.size
= sizeof(PERSON
*);
201 if ((*db
->put
)(db
, &key
, &data
, 0))
208 find_person(const char *name
)
215 char buf
[UT_NAMESIZE
+ 1];
220 if ((pw
= getpwnam(name
)) && hide(pw
))
223 /* Name may be only UT_NAMESIZE long and not NUL terminated. */
224 for (cnt
= 0; cnt
< UT_NAMESIZE
&& *name
; ++name
, ++cnt
)
230 if ((*db
->get
)(db
, &key
, &data
, 0))
232 memmove(&p
, data
.data
, sizeof p
);
241 if ((p
= malloc(sizeof(PERSON
))) == NULL
)
251 if ((w
= malloc(sizeof(WHERE
))) == NULL
)
253 if (pn
->whead
== NULL
)
254 pn
->whead
= pn
->wtail
= w
;
268 static char pbuf
[20];
270 /* don't touch anything if the user has their own formatting */
271 for (p
= num
; *p
; ++p
)
277 case 11: /* +0-123-456-7890 */
282 case 10: /* 012-345-6789 */
288 case 7: /* 012-3456 */
293 case 5: /* x0-1234 */
313 find_idle_and_ttywrite(WHERE
*w
)
319 (void)snprintf(tbuf
, sizeof(tbuf
), "%s/%s", _PATH_DEV
, w
->tty
);
321 error
= stat(tbuf
, &sb
);
322 if (error
< 0 && errno
== ENOENT
) {
324 * The terminal listed is not actually a terminal (i.e.,
325 * ":0"). This is a failure, so we'll skip printing
326 * out the idle time, which is non-ideal but better
327 * than a bogus warning and idle time.
331 } else if (error
< 0) {
336 touched
= sb
.st_atime
;
337 if (touched
< w
->loginat
) {
338 /* tty untouched since before login */
339 touched
= w
->loginat
;
341 w
->idletime
= now
< touched
? 0 : now
- touched
;
343 #define TALKABLE 0220 /* tty is writable if 220 mode */
344 w
->writable
= ((sb
.st_mode
& TALKABLE
) == TALKABLE
);
348 userinfo(PERSON
*pn
, struct passwd
*pw
)
351 char *bp
, name
[1024];
354 pn
->realname
= pn
->office
= pn
->officephone
= pn
->homephone
= NULL
;
356 pn
->uid
= pw
->pw_uid
;
357 if ((pn
->name
= strdup(pw
->pw_name
)) == NULL
)
358 err(1, "strdup failed");
359 if ((pn
->dir
= strdup(pw
->pw_dir
)) == NULL
)
360 err(1, "strdup failed");
361 if ((pn
->shell
= strdup(pw
->pw_shell
)) == NULL
)
362 err(1, "strdup failed");
364 /* why do we skip asterisks!?!? */
365 (void)strncpy(bp
= tbuf
, pw
->pw_gecos
, sizeof(tbuf
));
366 tbuf
[sizeof(tbuf
) - 1] = '\0';
370 /* ampersands get replaced by the login name */
371 if (!(p
= strsep(&bp
, ",")))
373 for (t
= name
; t
< &name
[sizeof(name
) - 1] && (*t
= *p
) != '\0'; ++p
) {
375 (void)strncpy(t
, pw
->pw_name
,
376 sizeof(name
) - (t
- name
));
377 name
[sizeof(name
) - 1] = '\0';
380 while (t
< &name
[sizeof(name
) - 1] && *++t
)
387 if ((pn
->realname
= strdup(name
)) == NULL
)
388 err(1, "strdup failed");
389 pn
->office
= ((p
= strsep(&bp
, ",")) && *p
) ?
391 pn
->officephone
= ((p
= strsep(&bp
, ",")) && *p
) ?
393 pn
->homephone
= ((p
= strsep(&bp
, ",")) && *p
) ?
395 (void)snprintf(tbuf
, sizeof(tbuf
), "%s/%s", _PATH_MAILDIR
, pw
->pw_name
);
396 pn
->mailrecv
= -1; /* -1 == not_valid */
397 if (stat(tbuf
, &sb
) < 0) {
398 if (errno
!= ENOENT
) {
402 } else if (sb
.st_size
!= 0) {
403 pn
->mailrecv
= sb
.st_mtime
;
404 pn
->mailread
= sb
.st_atime
;
409 * Is this user hiding from finger?
410 * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide).
411 * Nobody can hide from root.
415 hide(struct passwd
*pw
)
418 char buf
[MAXPATHLEN
];
420 if (invoker_root
|| !pw
->pw_dir
)
423 snprintf(buf
, sizeof(buf
), "%s/%s", pw
->pw_dir
, _PATH_NOFINGER
);
425 if (stat(buf
, &st
) == 0)