1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1983, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33static const char copyright[] =
34"@(#) Copyright (c) 1983, 1993\n\
35	The Regents of the University of California.  All rights reserved.\n";
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)fingerd.c	8.1 (Berkeley) 6/4/93";
41#endif
42static const char rcsid[] =
43  "$FreeBSD$";
44#endif /* not lint */
45
46#include <sys/types.h>
47#include <sys/param.h>
48#include <sys/socket.h>
49#include <netinet/in.h>
50#include <netinet/tcp.h>
51#include <arpa/inet.h>
52#include <errno.h>
53
54#include <unistd.h>
55#include <syslog.h>
56#include <libutil.h>
57#include <netdb.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include "pathnames.h"
62#ifdef USE_BLACKLIST
63#include <blacklist.h>
64#endif
65
66void logerr(const char *, ...) __printflike(1, 2) __dead2;
67
68int
69main(int argc, char *argv[])
70{
71	FILE *fp;
72	int ch;
73	char *lp;
74	struct sockaddr_storage ss;
75	socklen_t sval;
76	int p[2], debug, kflag, logging, pflag, secure;
77#define	ENTRIES	50
78	char **ap, *av[ENTRIES + 1], **comp, line[1024], *prog;
79	char rhost[MAXHOSTNAMELEN];
80
81	prog = _PATH_FINGER;
82	debug = logging = kflag = pflag = secure = 0;
83	openlog("fingerd", LOG_PID | LOG_CONS, LOG_DAEMON);
84	opterr = 0;
85	while ((ch = getopt(argc, argv, "dklp:s")) != -1)
86		switch (ch) {
87		case 'd':
88			debug = 1;
89			break;
90		case 'k':
91			kflag = 1;
92			break;
93		case 'l':
94			logging = 1;
95			break;
96		case 'p':
97			prog = optarg;
98			pflag = 1;
99			break;
100		case 's':
101			secure = 1;
102			break;
103		case '?':
104		default:
105			logerr("illegal option -- %c", optopt);
106		}
107
108	/*
109	 * Enable server-side Transaction TCP.
110	 */
111	if (!debug) {
112		int one = 1;
113		if (setsockopt(STDOUT_FILENO, IPPROTO_TCP, TCP_NOPUSH, &one,
114			       sizeof one) < 0) {
115			logerr("setsockopt(TCP_NOPUSH) failed: %m");
116		}
117	}
118
119	if (!fgets(line, sizeof(line), stdin))
120		exit(1);
121
122	if (!debug && (logging || pflag)) {
123		sval = sizeof(ss);
124		if (getpeername(0, (struct sockaddr *)&ss, &sval) < 0)
125			logerr("getpeername: %s", strerror(errno));
126		realhostname_sa(rhost, sizeof rhost - 1,
127				(struct sockaddr *)&ss, sval);
128		rhost[sizeof(rhost) - 1] = '\0';
129		if (pflag)
130			setenv("FINGERD_REMOTE_HOST", rhost, 1);
131	}
132
133	if (logging) {
134		char *t;
135		char *end;
136
137		end = memchr(line, 0, sizeof(line));
138		if (end == NULL) {
139			if ((t = malloc(sizeof(line) + 1)) == NULL)
140				logerr("malloc: %s", strerror(errno));
141			memcpy(t, line, sizeof(line));
142			t[sizeof(line)] = 0;
143		} else {
144			if ((t = strdup(line)) == NULL)
145				logerr("strdup: %s", strerror(errno));
146		}
147		for (end = t; *end; end++)
148			if (*end == '\n' || *end == '\r')
149				*end = ' ';
150		syslog(LOG_NOTICE, "query from %s: `%s'", rhost, t);
151	}
152
153	comp = &av[2];
154	av[3] = "--";
155	if (kflag)
156		*comp-- = "-k";
157	for (lp = line, ap = &av[4];;) {
158		*ap = strtok(lp, " \t\r\n");
159		if (!*ap) {
160			if (secure && ap == &av[4]) {
161#ifdef USE_BLACKLIST
162				blacklist(1, STDIN_FILENO, "nousername");
163#endif
164				puts("must provide username\r\n");
165				exit(1);
166			}
167			break;
168		}
169		if (secure && strchr(*ap, '@')) {
170#ifdef USE_BLACKLIST
171			blacklist(1, STDIN_FILENO, "noforwarding");
172#endif
173			puts("forwarding service denied\r\n");
174			exit(1);
175		}
176
177		/* RFC742: "/[Ww]" == "-l" */
178		if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) {
179			*comp-- = "-l";
180		}
181		else if (++ap == av + ENTRIES) {
182			*ap = NULL;
183			break;
184		}
185		lp = NULL;
186	}
187
188	if ((lp = strrchr(prog, '/')) != NULL)
189		*comp = ++lp;
190	else
191		*comp = prog;
192	if (pipe(p) < 0)
193		logerr("pipe: %s", strerror(errno));
194
195	if (debug) {
196		fprintf(stderr, "%s", prog);
197		for (ap = comp; *ap != NULL; ++ap)
198			fprintf(stderr, " %s", *ap);
199		fprintf(stderr, "\n");
200	}
201
202	switch(vfork()) {
203	case 0:
204		(void)close(p[0]);
205		if (p[1] != STDOUT_FILENO) {
206			(void)dup2(p[1], STDOUT_FILENO);
207			(void)close(p[1]);
208		}
209		dup2(STDOUT_FILENO, STDERR_FILENO);
210
211#ifdef USE_BLACKLIST
212		blacklist(0, STDIN_FILENO, "success");
213#endif
214		execv(prog, comp);
215		write(STDERR_FILENO, prog, strlen(prog));
216#define MSG ": cannot execute\n"
217		write(STDERR_FILENO, MSG, strlen(MSG));
218#undef MSG
219		_exit(1);
220	case -1:
221		logerr("fork: %s", strerror(errno));
222	}
223	(void)close(p[1]);
224	if (!(fp = fdopen(p[0], "r")))
225		logerr("fdopen: %s", strerror(errno));
226	while ((ch = getc(fp)) != EOF) {
227		if (ch == '\n')
228			putchar('\r');
229		putchar(ch);
230	}
231	exit(0);
232}
233
234#include <stdarg.h>
235
236void
237logerr(const char *fmt, ...)
238{
239	va_list ap;
240	va_start(ap, fmt);
241	(void)vsyslog(LOG_ERR, fmt, ap);
242	va_end(ap);
243	exit(1);
244	/* NOTREACHED */
245}
246