xref: /freebsd/libexec/fingerd/fingerd.c (revision 42249ef2)
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
33 static 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
40 static char sccsid[] = "@(#)fingerd.c	8.1 (Berkeley) 6/4/93";
41 #endif
42 static 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 
66 void logerr(const char *, ...) __printflike(1, 2) __dead2;
67 
68 int
69 main(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 
236 void
237 logerr(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