*BSD News Article 40933


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!constellation!news.uoknor.edu!ns1.nodak.edu!netnews.nwnet.net!henson!reuter.cse.ogi.edu!uwm.edu!spool.mu.edu!howland.reston.ans.net!swrinde!sgiblab!sgigate.sgi.com!fido.asd.sgi.com!slovax!lm
From: lm@slovax.engr.sgi.com (Larry McVoy)
Newsgroups: comp.unix.bsd
Subject: Fingerd revision
Date: 13 Jan 1995 01:37:30 GMT
Organization: Silicon Graphics Inc., Mountain View, CA
Lines: 281
Message-ID: <3f4lgq$3u2@fido.asd.sgi.com>
Reply-To: lm@slovax.engr.sgi.com
NNTP-Posting-Host: slovax.engr.sgi.com
X-Newsreader: TIN [version 1.2 PL2]

I had to fix a bug in SGI's finger and I extended the fingerd protocol
to allow remote sites to pass through options in a (some what) backwards
compatible way.  Trailing options will now get passed through as shown
below.  

This is most useful for the widely implemented -m option which forces
exact matches on names.  The 4.4lite revised code is included below.
The SGI code will be in a forthcoming IRIX 6.x release.  Could NetBSD
and FreeBSD and BSDI take a look at this?  It would be nice if we all 
had it.  By the way - the fingerd below works just fine on SunOS :-)

telnet fubar finger
Trying 150.166.75.39...
Connected to fubar.engr.sgi.com.
Escape character is '^]'.
greg -m
Login name: greg                        In real life: Greg Chesson
Office: 9U-510,  x3496
Directory: /usr/people/greg             Shell: /bin/sh
Mail to greg goes to greg@xtp.engr.sgi.com
Never logged in.
No Plan.
Connection closed by foreign host.

/*
 * Copyright (c) 1983, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * 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 copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
	The Regents of the University of California.  All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)fingerd.c	8.1 (Berkeley) 6/4/93";
#endif /* not lint */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#include <unistd.h>
#include <syslog.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define	_PATH_FINGER	"/usr/ucb/finger"

void err(const char *, ...);
extern char *strtok();
extern char *strchr();
extern char *strrchr();

#define SUNOS
#ifdef	SUNOS
extern char * sys_errlist[];

char * strerror(n)
{
	return (sys_errlist[n]);
}
#endif

int
main(argc, argv)
	int argc;
	char *argv[];
{
	register FILE *fp;
	register int ch;
	register char *lp;
	struct hostent *hp;
	struct sockaddr_in sin;
	int p[2], logging, secure, sval;
#define	ENTRIES	50
	char **ap, *av[ENTRIES + 1], line[1024], *prog;
	extern char *optarg;
	extern int opterr;

	prog = _PATH_FINGER;
	logging = secure = 0;
	openlog("fingerd", LOG_PID | LOG_CONS, LOG_DAEMON);
	opterr = 0;
	while ((ch = getopt(argc, argv, "slp:")) != EOF) {
		switch (ch) {
		case 'l':
			logging = 1;
			break;
		case 'p':
			prog = optarg;
			break;
		case 's':
			secure = 1;
			break;
		case '?':
		default:
			err("illegal option -- %c", ch);
		}
	}

	if (logging) {
		sval = sizeof(sin);
		if (getpeername(0, (struct sockaddr *)&sin, &sval) < 0)
			err("getpeername: %s", strerror(errno));
		if (hp = gethostbyaddr((char *)&sin.sin_addr.s_addr,
		    sizeof(sin.sin_addr.s_addr), AF_INET))
			lp = hp->h_name;
		else
			lp = inet_ntoa(sin.sin_addr);
		syslog(LOG_NOTICE, "query from %s", lp);
	}

	if (!fgets(line, sizeof(line), stdin))
		exit(1);
	
	/*
	 * SGI/McVoy extended finger protocol:
	 *
	 * [/W] user [user2 user3 user4] [-a [-b [-c [-d]]]]
	 *
	 * where user may be user@host and the options are intended
	 * for the local finger.
	 */

	/*
	 * Get rid of that /w, it complicates things.
	 * We pick it up if it is there and translate to white space.
	 */
	av[argc = 1] = 0;
	for (lp = line; *lp && *lp != '/'; lp++) {
		if ((lp == line || isspace(lp[-1])) &&
		    (lp[1] == 'w' || lp[1] == 'W') && 
		    (lp[2] == 0 || isspace(lp[2]))) {
			av[argc++] = "-l";
			lp[0] = lp[1] = ' ';
		}
	}

	/*
	 * Pull options from the tail first.
	 *
	 * Careful to find an option that is not part of a user name.
	 */
	for (lp = &line[-1]; lp[1] && (lp = strchr(&lp[1], '-')); ) {
		/*
		 * Options at the beginning or w/o a preceeding space are 
		 * not options.
		 */
		if ((lp == line) || !isspace(lp[-1]))
			continue;

		lp[-1] = 0;
		for (ap = &av[argc]; ; ) {
			*ap = strtok(lp, " \t\r\n");
			if (!*ap || ++ap == av + ENTRIES)
				break;
			argc++;
			lp = NULL;
		}
		break;		/* we wanted the first valid one only */
	}

	/*
	 * Snarf up the users.
	 */
	for (lp = line, ap = &av[argc];;) {
		*ap = strtok(lp, " \t\r\n");
		if (!*ap) {
			if (secure && ap == &av[argc]) {
				puts("must provide username\r\n");
				exit(1);
			}
			break;
		}
		if (secure && strchr(*ap, '@')) {
			puts("fowarding service denied\r\n");
			exit(1);
		}
		if (++ap == av + ENTRIES)
			break;
		lp = NULL;
	}

	if (lp = strrchr(prog, '/'))
		av[0] = ++lp;
	else
		av[0] = prog;
	if (pipe(p) < 0)
		err("pipe: %s", strerror(errno));

	switch(vfork()) {
	case 0:
		(void)close(p[0]);
		if (p[1] != 1) {
			(void)dup2(p[1], 1);
			(void)close(p[1]);
		}
#if 1
		write(0, "<<", 2);
		for (argc = 0; av[argc]; ++argc) {
			write(0, av[argc], strlen(av[argc]));
			if (av[argc+1]) write(0, " ", 1);
		}
		write(0, ">>\n\r", 4);
#endif
		execv(prog, av);
		err("execv: %s: %s", prog, strerror(errno));
		_exit(1);
	case -1:
		err("fork: %s", strerror(errno));
	}
	(void)close(p[1]);
	if (!(fp = fdopen(p[0], "r")))
		err("fdopen: %s", strerror(errno));
	while ((ch = getc(fp)) != EOF) {
		if (ch == '\n')
			putchar('\r');
		putchar(ch);
	}
	exit(0);
}

#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
	char *fmt;
        va_dcl
#endif
{
	va_list ap;
#if __STDC__
	va_start(ap, fmt);
#else
	va_start(ap);
#endif
	(void)vsyslog(LOG_ERR, fmt, ap);
	va_end(ap);
	exit(1);
	/* NOTREACHED */
}