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