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