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