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 */
}