summaryrefslogtreecommitdiff
path: root/finger/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'finger/util.c')
-rw-r--r--finger/util.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/finger/util.c b/finger/util.c
new file mode 100644
index 0000000..d0498a7
--- /dev/null
+++ b/finger/util.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)util.c 5.14 (Berkeley) 1/17/91";*/
+char util_rcsid[] = "$Id: util.c,v 1.18 1999/09/28 22:53:58 netbug Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+/* #include <sys/param.h> <--- unused? */
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <paths.h>
+#include <errno.h>
+#include <lastlog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "finger.h"
+
+#define HBITS 8 /* number of bits in hash code */
+#define HSIZE (1 << 8) /* hash table size */
+#define HMASK (HSIZE - 1) /* hash code mask */
+static PERSON *htab[HSIZE]; /* the buckets */
+
+static int hash(const char *name);
+
+static void find_idle_and_ttywrite(register WHERE *w) {
+ struct stat sb;
+
+ /* No device for X console. Utmp entry by XDM login (":0"). */
+ if (w->tty[0] == ':') {
+ w->idletime = 0; /* would be nice to have it emit ??? */
+ w->writable = 0;
+ return;
+ }
+ snprintf(tbuf, TBUFLEN, "%s/%s", _PATH_DEV, w->tty);
+ if (stat(tbuf, &sb) < 0) {
+ eprintf("finger: %s: %s\n", tbuf, strerror(errno));
+ return;
+ }
+ w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
+
+#define TALKABLE 0220 /* tty is writable if 220 mode */
+ w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
+}
+
+static void userinfo(PERSON *pn, struct passwd *pw) {
+ char *p;
+ struct stat sb;
+ char *bp;
+ char *rname;
+ int i, j, ct;
+ char *fields[4];
+ int nfields;
+
+ pn->uid = pw->pw_uid;
+ pn->name = strdup(pw->pw_name);
+ pn->dir = strdup(pw->pw_dir);
+ pn->shell = strdup(pw->pw_shell);
+
+ /* make a private copy of gecos to munge */
+ strncpy(tbuf, pw->pw_gecos, TBUFLEN);
+ tbuf[TBUFLEN-1] = 0; /* ensure null termination */
+ bp = tbuf;
+
+ /* why do we skip asterisks!?!? */
+ if (*bp == '*') ++bp;
+
+ /*
+ * fields[0] -> real name
+ * fields[1] -> office
+ * fields[2] -> officephone
+ * fields[3] -> homephone
+ */
+ nfields = 0;
+ for (p = strtok(bp, ","); p; p = strtok(NULL, ",")) {
+ if (*p==0) p = NULL; // skip empties
+ if (nfields < 4) fields[nfields++] = p;
+ }
+ while (nfields<4) fields[nfields++] = NULL;
+
+ if (fields[0]) {
+ /*
+ * Ampersands in gecos get replaced by the capitalized login
+ * name. This is a major nuisance and whoever thought it up
+ * should be shot.
+ */
+ p = fields[0];
+
+ /* First, count the number of ampersands. */
+ for (ct=i=0; p[i]; i++) if (p[i]=='&') ct++;
+
+ /* This tells us how much space we need to copy the name. */
+ rname = malloc(strlen(p) + ct*strlen(pw->pw_name) + 1);
+ if (!rname) {
+ eprintf("finger: Out of space.\n");
+ exit(1);
+ }
+
+ /* Now, do it */
+ for (i=j=0; p[i]; i++) {
+ if (p[i]=='&') {
+ strcpy(rname + j, pw->pw_name);
+ if (islower(rname[j])) {
+ rname[j] = toupper(rname[j]);
+ }
+ j += strlen(pw->pw_name);
+ }
+ else {
+ rname[j++] = p[i];
+ }
+ }
+ rname[j] = 0;
+
+ pn->realname = rname;
+ }
+
+ pn->office = fields[1] ? strdup(fields[1]) : NULL;
+ pn->officephone = fields[2] ? strdup(fields[2]) : NULL;
+ pn->homephone = fields[3] ? strdup(fields[3]) : NULL;
+
+ pn->mailrecv = -1; /* -1 == not_valid */
+ pn->mailread = -1; /* -1 == not_valid */
+
+ snprintf(tbuf, TBUFLEN, "%s/%s", _PATH_MAILDIR, pw->pw_name);
+ if (stat(tbuf, &sb) < 0) {
+ if (errno != ENOENT) {
+ eprintf("finger: %s: %s\n", tbuf, strerror(errno));
+ return;
+ }
+ }
+ else if (sb.st_size != 0) {
+ pn->mailrecv = sb.st_mtime;
+ pn->mailread = sb.st_atime;
+ }
+}
+
+int
+match(struct passwd *pw, const char *user)
+{
+ char *p;
+ int i, j, ct, rv=0;
+ char *rname;
+
+ strncpy(tbuf, pw->pw_gecos, TBUFLEN);
+ tbuf[TBUFLEN-1] = 0; /* guarantee null termination */
+ p = tbuf;
+
+ /* why do we skip asterisks!?!? */
+ if (*p == '*') ++p;
+
+ /* truncate the uninteresting stuff off the end of gecos */
+ p = strtok(p, ",");
+ if (!p) return 0;
+
+ /*
+ * Ampersands get replaced by the login name.
+ */
+
+ /* First, count the number of ampersands. */
+ for (ct=i=0; p[i]; i++) if (p[i]=='&') ct++;
+
+ /* This tells us how much space we need to copy the name. */
+ rname = malloc(strlen(p) + ct*strlen(pw->pw_name) + 1);
+ if (!rname) {
+ eprintf("finger: Out of space.\n");
+ exit(1);
+ }
+
+ /* Now, do it */
+ for (i=j=0; p[i]; i++) {
+ if (p[i]=='&') {
+ strcpy(rname + j, pw->pw_name);
+ if (islower(rname[j])) rname[j] = toupper(rname[j]);
+ j += strlen(pw->pw_name);
+ }
+ else {
+ rname[j++] = p[i];
+ }
+ }
+ rname[j] = 0;
+
+ for (p = strtok(rname, "\t "); p && !rv; p = strtok(NULL, "\t ")) {
+ if (!strcasecmp(p, user))
+ rv = 1;
+ }
+ free(rname);
+
+ return rv;
+}
+
+static int get_lastlog(int fd, uid_t uid, struct lastlog *ll) {
+ loff_t pos;
+ if (fd == -1) return -1;
+ pos = (long)uid * sizeof(*ll);
+ if (lseek(fd, pos, L_SET) != pos) return -1;
+ if (read(fd, ll, sizeof(*ll)) != sizeof(*ll)) return -1;
+ return 0;
+}
+
+void enter_lastlog(PERSON *pn) {
+ static int opened = 0, fd = -1;
+
+ WHERE *w;
+ struct lastlog ll;
+ int doit = 0;
+
+ /* some systems may not maintain lastlog, don't report errors. */
+ if (!opened) {
+ fd = open(_PATH_LASTLOG, O_RDONLY, 0);
+ opened = 1;
+ }
+ if (get_lastlog(fd, pn->uid, &ll)) {
+ /* as if never logged in */
+ ll.ll_line[0] = ll.ll_host[0] = '\0';
+ ll.ll_time = 0;
+ }
+
+ if ((w = pn->whead) == NULL)
+ doit = 1;
+ else if (ll.ll_time != 0) {
+ /* if last login is earlier than some current login */
+ for (; !doit && w != NULL; w = w->next)
+ if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
+ doit = 1;
+ /*
+ * and if it's not any of the current logins
+ * can't use time comparison because there may be a small
+ * discrepency since login calls time() twice
+ */
+ for (w = pn->whead; doit && w != NULL; w = w->next)
+ if (w->info == LOGGEDIN &&
+ strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
+ doit = 0;
+ }
+ if (doit) {
+ w = walloc(pn);
+ w->info = LASTLOG;
+ bcopy(ll.ll_line, w->tty, UT_LINESIZE);
+ w->tty[UT_LINESIZE] = 0;
+ bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
+ w->host[UT_HOSTSIZE] = 0;
+ w->loginat = ll.ll_time;
+ }
+}
+
+void enter_where(struct utmp *ut, PERSON *pn) {
+ register WHERE *w = walloc(pn);
+
+ w->info = LOGGEDIN;
+ bcopy(ut->ut_line, w->tty, UT_LINESIZE);
+ w->tty[UT_LINESIZE] = 0;
+ bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
+ w->host[UT_HOSTSIZE] = 0;
+ w->loginat = ut->ut_time;
+ find_idle_and_ttywrite(w);
+}
+
+PERSON * enter_person(struct passwd *pw) {
+ register PERSON *pn, **pp;
+
+ for (pp = htab + hash(pw->pw_name);
+ *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
+ pp = &(*pp)->hlink)
+ ;
+ if ((pn = *pp) == NULL) {
+ pn = palloc();
+ entries++;
+ if (phead == NULL)
+ phead = ptail = pn;
+ else {
+ ptail->next = pn;
+ ptail = pn;
+ }
+ pn->next = NULL;
+ pn->hlink = NULL;
+ *pp = pn;
+ userinfo(pn, pw);
+ pn->whead = NULL;
+ }
+ return(pn);
+}
+
+PERSON *find_person(const char *name) {
+ register PERSON *pn;
+
+ /* name may be only UT_NAMESIZE long and not terminated */
+ for (pn = htab[hash(name)];
+ pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
+ pn = pn->hlink)
+ ;
+ return(pn);
+}
+
+static int hash(const char *name) {
+ register int h, i;
+
+ h = 0;
+ /* name may be only UT_NAMESIZE long and not terminated */
+ for (i = UT_NAMESIZE; --i >= 0 && *name;)
+ h = ((h << 2 | h >> (HBITS - 2)) ^ *name++) & HMASK;
+ return(h);
+}
+
+PERSON *palloc(void) {
+ PERSON *p;
+
+ if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) {
+ eprintf("finger: Out of space.\n");
+ exit(1);
+ }
+ return(p);
+}
+
+WHERE *
+walloc(PERSON *pn)
+{
+ register WHERE *w;
+
+ if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
+ eprintf("finger: Out of space.\n");
+ exit(1);
+ }
+ if (pn->whead == NULL)
+ pn->whead = pn->wtail = w;
+ else {
+ pn->wtail->next = w;
+ pn->wtail = w;
+ }
+ w->next = NULL;
+ return(w);
+}
+
+const char *
+prphone(const char *num)
+{
+ char *p;
+ const char *q;
+ int len;
+ static char pbuf[15];
+
+ /* don't touch anything if the user has their own formatting */
+ for (q = num; *q; ++q)
+ if (!isdigit(*q))
+ return(num);
+ len = q - num;
+ p = pbuf;
+ switch(len) {
+ case 11: /* +0-123-456-7890 */
+ *p++ = '+';
+ *p++ = *num++;
+ *p++ = '-';
+ /* FALLTHROUGH */
+ case 10: /* 012-345-6789 */
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = '-';
+ /* FALLTHROUGH */
+ case 7: /* 012-3456 */
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ break;
+ case 5: /* x0-1234 */
+ case 4: /* x1234 */
+ *p++ = 'x';
+ *p++ = *num++;
+ break;
+ default:
+ return num;
+ }
+ if (len != 4) {
+ *p++ = '-';
+ *p++ = *num++;
+ }
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ *p = '\0';
+ return(pbuf);
+}