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