1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 04/28/95"; 13 #endif /* not lint */ 14 15 #include <sys/param.h> 16 #include <sys/stat.h> 17 #include <fcntl.h> 18 #include <db.h> 19 #include <err.h> 20 #include <pwd.h> 21 #include <utmp.h> 22 #include <errno.h> 23 #include <unistd.h> 24 #include <stdio.h> 25 #include <ctype.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <paths.h> 29 #include "finger.h" 30 31 static void find_idle_and_ttywrite __P((WHERE *)); 32 static void userinfo __P((PERSON *, struct passwd *)); 33 static WHERE *walloc __P((PERSON *)); 34 35 int 36 match(pw, user) 37 struct passwd *pw; 38 char *user; 39 { 40 register char *p, *t; 41 char name[1024]; 42 43 if (!strcasecmp(pw->pw_name, user)) 44 return(1); 45 46 /* 47 * XXX 48 * Why do we skip asterisks!?!? 49 */ 50 (void)strcpy(p = tbuf, pw->pw_gecos); 51 if (*p == '*') 52 ++p; 53 54 /* Ampersands get replaced by the login name. */ 55 if ((p = strtok(p, ",")) == NULL) 56 return(0); 57 58 for (t = name; (*t = *p) != '\0'; ++p) 59 if (*t == '&') { 60 (void)strcpy(t, pw->pw_name); 61 while (*++t); 62 } 63 else 64 ++t; 65 for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) 66 if (!strcasecmp(p, user)) 67 return(1); 68 return(0); 69 } 70 71 void 72 enter_lastlog(pn) 73 register PERSON *pn; 74 { 75 register WHERE *w; 76 static int opened, fd; 77 struct lastlog ll; 78 char doit = 0; 79 80 /* some systems may not maintain lastlog, don't report errors. */ 81 if (!opened) { 82 fd = open(_PATH_LASTLOG, O_RDONLY, 0); 83 opened = 1; 84 } 85 if (fd == -1 || 86 lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 87 (long)pn->uid * sizeof(ll) || 88 read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 89 /* as if never logged in */ 90 ll.ll_line[0] = ll.ll_host[0] = NULL; 91 ll.ll_time = 0; 92 } 93 if ((w = pn->whead) == NULL) 94 doit = 1; 95 else if (ll.ll_time != 0) { 96 /* if last login is earlier than some current login */ 97 for (; !doit && w != NULL; w = w->next) 98 if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 99 doit = 1; 100 /* 101 * and if it's not any of the current logins 102 * can't use time comparison because there may be a small 103 * discrepency since login calls time() twice 104 */ 105 for (w = pn->whead; doit && w != NULL; w = w->next) 106 if (w->info == LOGGEDIN && 107 strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 108 doit = 0; 109 } 110 if (doit) { 111 w = walloc(pn); 112 w->info = LASTLOG; 113 bcopy(ll.ll_line, w->tty, UT_LINESIZE); 114 w->tty[UT_LINESIZE] = 0; 115 bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 116 w->host[UT_HOSTSIZE] = 0; 117 w->loginat = ll.ll_time; 118 } 119 } 120 121 void 122 enter_where(ut, pn) 123 struct utmp *ut; 124 PERSON *pn; 125 { 126 register WHERE *w; 127 128 w = walloc(pn); 129 w->info = LOGGEDIN; 130 bcopy(ut->ut_line, w->tty, UT_LINESIZE); 131 w->tty[UT_LINESIZE] = 0; 132 bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 133 w->host[UT_HOSTSIZE] = 0; 134 w->loginat = (time_t)ut->ut_time; 135 find_idle_and_ttywrite(w); 136 } 137 138 PERSON * 139 enter_person(pw) 140 register struct passwd *pw; 141 { 142 DBT data, key; 143 PERSON *pn; 144 145 if (db == NULL && 146 (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 147 err(1, NULL); 148 149 key.data = pw->pw_name; 150 key.size = strlen(pw->pw_name); 151 152 switch ((*db->get)(db, &key, &data, 0)) { 153 case 0: 154 memmove(&pn, data.data, sizeof pn); 155 return (pn); 156 default: 157 case -1: 158 err(1, "db get"); 159 /* NOTREACHED */ 160 case 1: 161 ++entries; 162 pn = palloc(); 163 userinfo(pn, pw); 164 pn->whead = NULL; 165 166 data.size = sizeof(PERSON *); 167 data.data = &pn; 168 if ((*db->put)(db, &key, &data, 0)) 169 err(1, "db put"); 170 return (pn); 171 } 172 } 173 174 PERSON * 175 find_person(name) 176 char *name; 177 { 178 register int cnt; 179 DBT data, key; 180 PERSON *p; 181 char buf[UT_NAMESIZE + 1]; 182 183 if (!db) 184 return(NULL); 185 186 /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 187 for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 188 buf[cnt] = *name; 189 buf[cnt] = '\0'; 190 key.data = buf; 191 key.size = cnt; 192 193 if ((*db->get)(db, &key, &data, 0)) 194 return (NULL); 195 memmove(&p, data.data, sizeof p); 196 return (p); 197 } 198 199 PERSON * 200 palloc() 201 { 202 PERSON *p; 203 204 if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 205 err(1, NULL); 206 return(p); 207 } 208 209 static WHERE * 210 walloc(pn) 211 register PERSON *pn; 212 { 213 register WHERE *w; 214 215 if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 216 err(1, NULL); 217 if (pn->whead == NULL) 218 pn->whead = pn->wtail = w; 219 else { 220 pn->wtail->next = w; 221 pn->wtail = w; 222 } 223 w->next = NULL; 224 return(w); 225 } 226 227 char * 228 prphone(num) 229 char *num; 230 { 231 register char *p; 232 int len; 233 static char pbuf[15]; 234 235 /* don't touch anything if the user has their own formatting */ 236 for (p = num; *p; ++p) 237 if (!isdigit(*p)) 238 return(num); 239 len = p - num; 240 p = pbuf; 241 switch(len) { 242 case 11: /* +0-123-456-7890 */ 243 *p++ = '+'; 244 *p++ = *num++; 245 *p++ = '-'; 246 /* FALLTHROUGH */ 247 case 10: /* 012-345-6789 */ 248 *p++ = *num++; 249 *p++ = *num++; 250 *p++ = *num++; 251 *p++ = '-'; 252 /* FALLTHROUGH */ 253 case 7: /* 012-3456 */ 254 *p++ = *num++; 255 *p++ = *num++; 256 *p++ = *num++; 257 break; 258 case 5: /* x0-1234 */ 259 *p++ = 'x'; 260 *p++ = *num++; 261 break; 262 default: 263 return(num); 264 } 265 *p++ = '-'; 266 *p++ = *num++; 267 *p++ = *num++; 268 *p++ = *num++; 269 *p++ = *num++; 270 *p = '\0'; 271 return(pbuf); 272 } 273 274 static void 275 find_idle_and_ttywrite(w) 276 register WHERE *w; 277 { 278 extern time_t now; 279 struct stat sb; 280 281 (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 282 if (stat(tbuf, &sb) < 0) { 283 warn(tbuf); 284 return; 285 } 286 w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 287 288 #define TALKABLE 0220 /* tty is writable if 220 mode */ 289 w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 290 } 291 292 static void 293 userinfo(pn, pw) 294 register PERSON *pn; 295 register struct passwd *pw; 296 { 297 register char *p, *t; 298 char *bp, name[1024]; 299 300 pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 301 302 pn->uid = pw->pw_uid; 303 pn->name = strdup(pw->pw_name); 304 pn->dir = strdup(pw->pw_dir); 305 pn->shell = strdup(pw->pw_shell); 306 307 /* why do we skip asterisks!?!? */ 308 (void)strcpy(bp = tbuf, pw->pw_gecos); 309 if (*bp == '*') 310 ++bp; 311 312 /* ampersands get replaced by the login name */ 313 if (!(p = strsep(&bp, ","))) 314 return; 315 for (t = name; (*t = *p) != '\0'; ++p) 316 if (*t == '&') { 317 (void)strcpy(t, pw->pw_name); 318 if (islower(*t)) 319 *t = toupper(*t); 320 while (*++t); 321 } 322 else 323 ++t; 324 pn->realname = strdup(name); 325 pn->office = ((p = strsep(&bp, ",")) && *p) ? 326 strdup(p) : NULL; 327 pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 328 strdup(p) : NULL; 329 pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 330 strdup(p) : NULL; 331 } 332