main netmisc / finger / finger.c
  1/*	$NetBSD: finger.c,v 1.31 2021/10/30 09:12:09 nia 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 * Luke Mewburn <lukem@NetBSD.org> added the following on 961121:
 37 *    - mail status ("No Mail", "Mail read:...", or "New Mail ...,
 38 *	Unread since ...".)
 39 *    - 4 digit phone extensions (3210 is printed as x3210.)
 40 *    - host/office toggling in short format with -h & -o.
 41 *    - short day names (`Tue' printed instead of `Jun 21' if the
 42 *	login time is < 6 days.
 43 */
 44
 45#include <sys/cdefs.h>
 46#ifndef lint
 47__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
 48 The Regents of the University of California.  All rights reserved.");
 49#endif /* not lint */
 50
 51#ifndef lint
 52#if 0
 53static char sccsid[] = "@(#)finger.c	8.5 (Berkeley) 5/4/95";
 54#else
 55__RCSID("$NetBSD: finger.c,v 1.31 2021/10/30 09:12:09 nia Exp $");
 56#endif
 57#endif /* not lint */
 58
 59/*
 60 * Finger prints out information about users.  It is not portable since
 61 * certain fields (e.g. the full user name, office, and phone numbers) are
 62 * extracted from the gecos field of the passwd file which other UNIXes
 63 * may not have or may use for other things.
 64 *
 65 * There are currently two output formats; the short format is one line
 66 * per user and displays login name, tty, login time, real name, idle time,
 67 * and either remote host information (default) or office location/phone
 68 * number, depending on if -h or -o is used respectively.
 69 * The long format gives the same information (in a more legible format) as
 70 * well as home directory, shell, mail info, and .plan/.project files.
 71 */
 72
 73#include <sys/param.h>
 74
 75#include <db.h>
 76#include <err.h>
 77#include <errno.h>
 78#include <fcntl.h>
 79#include <pwd.h>
 80#include <stdio.h>
 81#include <stdlib.h>
 82#include <string.h>
 83#include <time.h>
 84#include <unistd.h>
 85
 86#include <locale.h>
 87#include <langinfo.h>
 88
 89#include "utmpentry.h"
 90
 91#include "finger.h"
 92#include "extern.h"
 93
 94DB *db;
 95time_t now;
 96int entries, gflag, lflag, mflag, oflag, sflag, eightflag, pplan;
 97char tbuf[1024];
 98struct utmpentry *ehead;
 99
100static void loginlist(void);
101static void userlist(int, char **);
102
103int
104main(int argc, char **argv)
105{
106	int ch;
107
108	/* Allow user's locale settings to affect character output. */
109	setlocale(LC_CTYPE, "");
110
111	/*
112	 * Reset back to the C locale, unless we are using a known
113	 * single-byte 8-bit locale.
114	 */
115	if (strncmp(nl_langinfo(CODESET), "ISO8859-", 8))
116		setlocale(LC_CTYPE, "C");
117
118	oflag = 1;		/* default to old "office" behavior */
119
120	while ((ch = getopt(argc, argv, "lmpshog8")) != -1)
121		switch(ch) {
122		case 'l':
123			lflag = 1;		/* long format */
124			break;
125		case 'm':
126			mflag = 1;		/* force exact match of names */
127			break;
128		case 'p':
129			pplan = 1;		/* don't show .plan/.project */
130			break;
131		case 's':
132			sflag = 1;		/* short format */
133			break;
134		case 'h':
135			oflag = 0;		/* remote host info */
136			break;
137		case 'o':
138			oflag = 1;		/* office info */
139			break;
140		case 'g':
141			gflag = 1;		/* no gecos info, besides name */
142			break;
143		case '8':
144			eightflag = 1;		/* 8-bit pass-through */
145			break;
146		case '?':
147		default:
148			(void)fprintf(stderr,
149			    "usage: finger [-lmpshog8] [login ...]\n");
150			exit(1);
151		}
152	argc -= optind;
153	argv += optind;
154
155	(void)time(&now);
156	setpassent(1);
157	entries = getutentries(NULL, &ehead);
158	if (argc == 0) {
159		/*
160		 * Assign explicit "small" format if no names given and -l
161		 * not selected.  Force the -s BEFORE we get names so proper
162		 * screening will be done.
163		 */
164		if (!lflag)
165			sflag = 1;	/* if -l not explicit, force -s */
166		loginlist();
167		if (entries == 0)
168			(void)printf("No one logged on.\n");
169	} else {
170		userlist(argc, argv);
171		/*
172		 * Assign explicit "large" format if names given and -s not
173		 * explicitly stated.  Force the -l AFTER we get names so any
174		 * remote finger attempts specified won't be mishandled.
175		 */
176		if (!sflag)
177			lflag = 1;	/* if -s not explicit, force -l */
178	}
179	if (entries) {
180		if (lflag)
181			lflag_print();
182		else
183			sflag_print();
184	}
185	return (0);
186}
187
188static void
189loginlist(void)
190{
191	PERSON *pn;
192	DBT data, key;
193	struct passwd *pw;
194	int r, seqflag;
195	struct utmpentry *ep;
196
197	for (ep = ehead; ep; ep = ep->next) {
198		if ((pn = find_person(ep->name)) == NULL) {
199			if ((pw = getpwnam(ep->name)) == NULL)
200				continue;
201			pn = enter_person(pw);
202		}
203		enter_where(ep, pn);
204	}
205	if (db && lflag)
206		for (seqflag = R_FIRST;; seqflag = R_NEXT) {
207			PERSON *tmp;
208
209			r = (*db->seq)(db, &key, &data, seqflag);
210			if (r == -1)
211				err(1, "db seq");
212			if (r == 1)
213				break;
214			memmove(&tmp, data.data, sizeof tmp);
215			enter_lastlog(tmp);
216		}
217}
218
219static void
220userlist(int argc, char **argv)
221{
222	PERSON *pn;
223	DBT data, key;
224	struct passwd *pw;
225	int r, seqflag, *used, *ip;
226	char **ap, **nargv, **np, **p;
227	struct utmpentry *ep;
228
229	nargv = NULL;
230	if (reallocarr(&nargv, argc + 1, sizeof(char *)) != 0)
231		err(1, NULL);
232	if ((used = calloc(argc, sizeof(int))) == NULL)
233		err(1, NULL);
234
235	/* Pull out all network requests. */
236	for (ap = p = argv, np = nargv; *p; ++p)
237		if (strchr(*p, '@'))
238			*np++ = *p;
239		else
240			*ap++ = *p;
241
242	*np++ = NULL;
243	*ap++ = NULL;
244
245	if (!*argv)
246		goto net;
247
248	/*
249	 * Traverse the list of possible login names and check the login name
250	 * and real name against the name specified by the user.
251	 */
252	if (mflag) {
253		for (p = argv; *p; ++p)
254			if ((pw = getpwnam(*p)) != NULL)
255				enter_person(pw);
256			else
257				warnx("%s: no such user", *p);
258	} else {
259		while ((pw = getpwent()) != NULL)
260			for (p = argv, ip = used; *p; ++p, ++ip)
261				if (match(pw, *p)) {
262					enter_person(pw);
263					*ip = 1;
264				}
265		for (p = argv, ip = used; *p; ++p, ++ip)
266			if (!*ip)
267				warnx("%s: no such user", *p);
268	}
269
270	/* Handle network requests. */
271net:
272	for (p = nargv; *p;)
273		netfinger(*p++);
274
275	if (entries == 0)
276		goto done;
277
278	/*
279	 * Scan thru the list of users currently logged in, saving
280	 * appropriate data whenever a match occurs.
281	 */
282	for (ep = ehead; ep; ep = ep->next) {
283		if ((pn = find_person(ep->name)) == NULL)
284			continue;
285		enter_where(ep, pn);
286	}
287	if (db != NULL)
288		for (seqflag = R_FIRST;; seqflag = R_NEXT) {
289			PERSON *tmp;
290
291			r = (*db->seq)(db, &key, &data, seqflag);
292			if (r == -1)
293				err(1, "db seq");
294			if (r == 1)
295				break;
296			memmove(&tmp, data.data, sizeof tmp);
297			enter_lastlog(tmp);
298		}
299done:
300	free(nargv);
301	free(used);
302}