fingerd.c revision 127560
169408Sache/*
259243Sobrien * Copyright (c) 1983, 1993
359243Sobrien *	The Regents of the University of California.  All rights reserved.
459243Sobrien *
559243Sobrien * Redistribution and use in source and binary forms, with or without
659243Sobrien * modification, are permitted provided that the following conditions
759243Sobrien * are met:
859243Sobrien * 1. Redistributions of source code must retain the above copyright
959243Sobrien *    notice, this list of conditions and the following disclaimer.
1059243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1169408Sache *    notice, this list of conditions and the following disclaimer in the
1259243Sobrien *    documentation and/or other materials provided with the distribution.
1359243Sobrien * 3. All advertising materials mentioning features or use of this software
1459243Sobrien *    must display the following acknowledgement:
1559243Sobrien *	This product includes software developed by the University of
1659243Sobrien *	California, Berkeley and its contributors.
1759243Sobrien * 4. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien
3459243Sobrien#ifndef lint
3559243Sobrienstatic const char copyright[] =
3659243Sobrien"@(#) Copyright (c) 1983, 1993\n\
3759243Sobrien	The Regents of the University of California.  All rights reserved.\n";
3859243Sobrien#endif /* not lint */
3959243Sobrien
4059243Sobrien#ifndef lint
4159243Sobrien#if 0
4259243Sobrienstatic char sccsid[] = "@(#)fingerd.c	8.1 (Berkeley) 6/4/93";
4359243Sobrien#endif
4459243Sobrienstatic const char rcsid[] =
4559243Sobrien  "$FreeBSD: head/libexec/fingerd/fingerd.c 127560 2004-03-29 09:29:51Z pjd $";
4659243Sobrien#endif /* not lint */
4759243Sobrien
4859243Sobrien#include <sys/types.h>
4959243Sobrien#include <sys/param.h>
5059243Sobrien#include <sys/socket.h>
5159243Sobrien#include <netinet/in.h>
5259243Sobrien#include <netinet/tcp.h>
5359243Sobrien#include <arpa/inet.h>
5459243Sobrien#include <errno.h>
5559243Sobrien
5659243Sobrien#include <unistd.h>
5759243Sobrien#include <syslog.h>
5859243Sobrien#include <libutil.h>
5959243Sobrien#include <netdb.h>
6059243Sobrien#include <stdio.h>
6159243Sobrien#include <stdlib.h>
6259243Sobrien#include <string.h>
6359243Sobrien#include "pathnames.h"
6459243Sobrien
6559243Sobrienvoid logerr(const char *, ...) __printflike(1, 2);
6659243Sobrien
6759243Sobrienint
6859243Sobrienmain(int argc, char *argv[])
6959243Sobrien{
7059243Sobrien	FILE *fp;
7159243Sobrien	int ch;
7259243Sobrien	char *lp;
7359243Sobrien	struct sockaddr_storage ss;
7459243Sobrien	int p[2], logging, pflag, secure, sval;
7559243Sobrien#define	ENTRIES	50
7659243Sobrien	char **ap, *av[ENTRIES + 1], **comp, line[1024], *prog;
7759243Sobrien	char rhost[MAXHOSTNAMELEN];
7859243Sobrien
7959243Sobrien	prog = _PATH_FINGER;
8059243Sobrien	logging = pflag = secure = 0;
8159243Sobrien	openlog("fingerd", LOG_PID | LOG_CONS, LOG_DAEMON);
8259243Sobrien	opterr = 0;
8359243Sobrien	while ((ch = getopt(argc, argv, "lp:s")) != -1)
8459243Sobrien		switch (ch) {
8559243Sobrien		case 'l':
8659243Sobrien			logging = 1;
8759243Sobrien			break;
8859243Sobrien		case 'p':
8959243Sobrien			prog = optarg;
9059243Sobrien			pflag = 1;
9159243Sobrien			break;
9259243Sobrien		case 's':
9359243Sobrien			secure = 1;
9459243Sobrien			break;
9559243Sobrien		case '?':
9659243Sobrien		default:
9759243Sobrien			logerr("illegal option -- %c", optopt);
9859243Sobrien		}
9959243Sobrien
10059243Sobrien	/*
10159243Sobrien	 * Enable server-side Transaction TCP.
10259243Sobrien	 */
10359243Sobrien	{
10459243Sobrien		int one = 1;
10559243Sobrien		if (setsockopt(STDOUT_FILENO, IPPROTO_TCP, TCP_NOPUSH, &one,
10659243Sobrien			       sizeof one) < 0) {
10759243Sobrien			logerr("setsockopt(TCP_NOPUSH) failed: %m");
10859243Sobrien		}
10959243Sobrien	}
11059243Sobrien
11159243Sobrien	if (!fgets(line, sizeof(line), stdin))
11259243Sobrien		exit(1);
11369408Sache
11469408Sache	if (logging || pflag) {
11569408Sache		sval = sizeof(ss);
11659243Sobrien		if (getpeername(0, (struct sockaddr *)&ss, &sval) < 0)
11759243Sobrien			logerr("getpeername: %s", strerror(errno));
11859243Sobrien		realhostname_sa(rhost, sizeof rhost - 1,
11959243Sobrien				(struct sockaddr *)&ss, sval);
12059243Sobrien		rhost[sizeof(rhost) - 1] = '\0';
12159243Sobrien		if (pflag)
12259243Sobrien			setenv("FINGERD_REMOTE_HOST", rhost, 1);
12359243Sobrien	}
12459243Sobrien
12559243Sobrien	if (logging) {
12659243Sobrien		char *t;
12759243Sobrien		char *end;
12859243Sobrien
12959243Sobrien		end = memchr(line, 0, sizeof(line));
13059243Sobrien		if (end == NULL) {
13159243Sobrien			if ((t = malloc(sizeof(line) + 1)) == NULL)
13259243Sobrien				logerr("malloc: %s", strerror(errno));
13359243Sobrien			memcpy(t, line, sizeof(line));
13459243Sobrien			t[sizeof(line)] = 0;
13559243Sobrien		} else {
13659243Sobrien			if ((t = strdup(line)) == NULL)
13759243Sobrien				logerr("strdup: %s", strerror(errno));
13859243Sobrien		}
13959243Sobrien		for (end = t; *end; end++)
14059243Sobrien			if (*end == '\n' || *end == '\r')
14159243Sobrien				*end = ' ';
14259243Sobrien		syslog(LOG_NOTICE, "query from %s: `%s'", rhost, t);
14359243Sobrien	}
14459243Sobrien
14559243Sobrien	comp = &av[1];
14659243Sobrien	av[2] = "--";
14759243Sobrien	for (lp = line, ap = &av[3];;) {
14859243Sobrien		*ap = strtok(lp, " \t\r\n");
14959243Sobrien		if (!*ap) {
15059243Sobrien			if (secure && ap == &av[3]) {
15159243Sobrien				puts("must provide username\r\n");
15259243Sobrien				exit(1);
15359243Sobrien			}
15459243Sobrien			break;
15559243Sobrien		}
15659243Sobrien		if (secure && strchr(*ap, '@')) {
15759243Sobrien			puts("forwarding service denied\r\n");
15859243Sobrien			exit(1);
15959243Sobrien		}
16059243Sobrien
16159243Sobrien		/* RFC742: "/[Ww]" == "-l" */
16259243Sobrien		if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) {
16359243Sobrien			av[1] = "-l";
16459243Sobrien			comp = &av[0];
16559243Sobrien		}
16659243Sobrien		else if (++ap == av + ENTRIES) {
16759243Sobrien			*ap = NULL;
16859243Sobrien			break;
16959243Sobrien		}
17059243Sobrien		lp = NULL;
17159243Sobrien	}
17259243Sobrien
17359243Sobrien	if ((lp = strrchr(prog, '/')) != NULL)
17459243Sobrien		*comp = ++lp;
17559243Sobrien	else
17659243Sobrien		*comp = prog;
17759243Sobrien	if (pipe(p) < 0)
17859243Sobrien		logerr("pipe: %s", strerror(errno));
17959243Sobrien
18059243Sobrien	switch(vfork()) {
18159243Sobrien	case 0:
18259243Sobrien		(void)close(p[0]);
18359243Sobrien		if (p[1] != STDOUT_FILENO) {
18459243Sobrien			(void)dup2(p[1], STDOUT_FILENO);
18559243Sobrien			(void)close(p[1]);
18659243Sobrien		}
18759243Sobrien		dup2(STDOUT_FILENO, STDERR_FILENO);
18859243Sobrien
18959243Sobrien		execv(prog, comp);
19059243Sobrien		write(STDERR_FILENO, prog, strlen(prog));
19159243Sobrien#define MSG ": cannot execute\n"
19259243Sobrien		write(STDERR_FILENO, MSG, strlen(MSG));
19359243Sobrien#undef MSG
19459243Sobrien		_exit(1);
19559243Sobrien	case -1:
19659243Sobrien		logerr("fork: %s", strerror(errno));
19759243Sobrien	}
19859243Sobrien	(void)close(p[1]);
19959243Sobrien	if (!(fp = fdopen(p[0], "r")))
20059243Sobrien		logerr("fdopen: %s", strerror(errno));
20159243Sobrien	while ((ch = getc(fp)) != EOF) {
20259243Sobrien		if (ch == '\n')
20359243Sobrien			putchar('\r');
20459243Sobrien		putchar(ch);
20559243Sobrien	}
20659243Sobrien	exit(0);
20759243Sobrien}
20859243Sobrien
20959243Sobrien#include <stdarg.h>
21059243Sobrien
21159243Sobrienvoid
21259243Sobrienlogerr(const char *fmt, ...)
21359243Sobrien{
21459243Sobrien	va_list ap;
21559243Sobrien	va_start(ap, fmt);
21659243Sobrien	(void)vsyslog(LOG_ERR, fmt, ap);
21759243Sobrien	va_end(ap);
21859243Sobrien	exit(1);
21959243Sobrien	/* NOTREACHED */
22059243Sobrien}
22159243Sobrien