144743Smarkm /*
244743Smarkm  * General front end for stream and datagram IP services. This program logs
344743Smarkm  * the remote host name and then invokes the real daemon. For example,
444743Smarkm  * install as /usr/etc/{tftpd,fingerd,telnetd,ftpd,rlogind,rshd,rexecd},
544743Smarkm  * after saving the real daemons in the directory specified with the
644743Smarkm  * REAL_DAEMON_DIR macro. This arrangement requires that the network daemons
744743Smarkm  * are started by inetd or something similar. Connections and diagnostics
844743Smarkm  * are logged through syslog(3).
944743Smarkm  *
1044743Smarkm  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
1156977Sshin  *
1256977Sshin  * $FreeBSD$
1344743Smarkm  */
1444743Smarkm
1544743Smarkm#ifndef lint
1644743Smarkmstatic char sccsid[] = "@(#) tcpd.c 1.10 96/02/11 17:01:32";
1744743Smarkm#endif
1844743Smarkm
1944743Smarkm/* System libraries. */
2044743Smarkm
2144743Smarkm#include <sys/types.h>
2244743Smarkm#include <sys/param.h>
2344743Smarkm#include <sys/stat.h>
2444743Smarkm#include <sys/socket.h>
2544743Smarkm#include <netinet/in.h>
2644743Smarkm#include <stdio.h>
2744743Smarkm#include <syslog.h>
2844743Smarkm#include <string.h>
2944743Smarkm
3044743Smarkm#ifndef MAXPATHNAMELEN
3144743Smarkm#define MAXPATHNAMELEN	BUFSIZ
3244743Smarkm#endif
3344743Smarkm
3444743Smarkm#ifndef STDIN_FILENO
3544743Smarkm#define STDIN_FILENO	0
3644743Smarkm#endif
3744743Smarkm
3844743Smarkm/* Local stuff. */
3944743Smarkm
4044743Smarkm#include "patchlevel.h"
4144743Smarkm#include "tcpd.h"
4244743Smarkm
4344743Smarkmint     allow_severity = SEVERITY;	/* run-time adjustable */
4444743Smarkmint     deny_severity = LOG_WARNING;	/* ditto */
4544743Smarkm
4644743Smarkmmain(argc, argv)
4744743Smarkmint     argc;
4844743Smarkmchar  **argv;
4944743Smarkm{
5044743Smarkm    struct request_info request;
5144743Smarkm    char    path[MAXPATHNAMELEN];
5244743Smarkm
5344743Smarkm    /* Attempt to prevent the creation of world-writable files. */
5444743Smarkm
5544743Smarkm#ifdef DAEMON_UMASK
5644743Smarkm    umask(DAEMON_UMASK);
5744743Smarkm#endif
5844743Smarkm
5944743Smarkm    /*
6044743Smarkm     * If argv[0] is an absolute path name, ignore REAL_DAEMON_DIR, and strip
6144743Smarkm     * argv[0] to its basename.
6244743Smarkm     */
6344743Smarkm
6444743Smarkm    if (argv[0][0] == '/') {
6544743Smarkm	strcpy(path, argv[0]);
6644743Smarkm	argv[0] = strrchr(argv[0], '/') + 1;
6744743Smarkm    } else {
6844743Smarkm	sprintf(path, "%s/%s", REAL_DAEMON_DIR, argv[0]);
6944743Smarkm    }
7044743Smarkm
7144743Smarkm    /*
7244743Smarkm     * Open a channel to the syslog daemon. Older versions of openlog()
7344743Smarkm     * require only two arguments.
7444743Smarkm     */
7544743Smarkm
7644743Smarkm#ifdef LOG_MAIL
7744743Smarkm    (void) openlog(argv[0], LOG_PID, FACILITY);
7844743Smarkm#else
7944743Smarkm    (void) openlog(argv[0], LOG_PID);
8044743Smarkm#endif
8144743Smarkm
8244743Smarkm    /*
8344743Smarkm     * Find out the endpoint addresses of this conversation. Host name
8444743Smarkm     * lookups and double checks will be done on demand.
8544743Smarkm     */
8644743Smarkm
8744743Smarkm    request_init(&request, RQ_DAEMON, argv[0], RQ_FILE, STDIN_FILENO, 0);
8844743Smarkm    fromhost(&request);
8944743Smarkm
9044743Smarkm    /*
9144743Smarkm     * Optionally look up and double check the remote host name. Sites
9244743Smarkm     * concerned with security may choose to refuse connections from hosts
9344743Smarkm     * that pretend to have someone elses host name.
9444743Smarkm     */
9544743Smarkm
9644743Smarkm#ifdef PARANOID
9744743Smarkm    if (STR_EQ(eval_hostname(request.client), paranoid))
9844743Smarkm	refuse(&request);
9944743Smarkm#endif
10044743Smarkm
10144743Smarkm    /*
10244743Smarkm     * The BSD rlogin and rsh daemons that came out after 4.3 BSD disallow
10344743Smarkm     * socket options at the IP level. They do so for a good reason.
10444743Smarkm     * Unfortunately, we cannot use this with SunOS 4.1.x because the
10544743Smarkm     * getsockopt() system call can panic the system.
10644743Smarkm     */
10744743Smarkm
10844743Smarkm#ifdef KILL_IP_OPTIONS
10944743Smarkm    fix_options(&request);
11044743Smarkm#endif
11144743Smarkm
11244743Smarkm    /*
11344743Smarkm     * Check whether this host can access the service in argv[0]. The
11444743Smarkm     * access-control code invokes optional shell commands as specified in
11544743Smarkm     * the access-control tables.
11644743Smarkm     */
11744743Smarkm
11844743Smarkm#ifdef HOSTS_ACCESS
11944743Smarkm    if (!hosts_access(&request))
12044743Smarkm	refuse(&request);
12144743Smarkm#endif
12244743Smarkm
12344743Smarkm    /* Report request and invoke the real daemon program. */
12444743Smarkm
12556977Sshin#ifdef INET6
12656977Sshin    syslog(allow_severity, "connect from %s (%s)",
12756977Sshin	   eval_client(&request), eval_hostaddr(request.client));
12856977Sshin#else
12944743Smarkm    syslog(allow_severity, "connect from %s", eval_client(&request));
13056977Sshin#endif
13144743Smarkm    closelog();
13244743Smarkm    (void) execv(path, argv);
13344743Smarkm    syslog(LOG_ERR, "error: cannot execute %s: %m", path);
13444743Smarkm    clean_exit(&request);
13544743Smarkm    /* NOTREACHED */
13644743Smarkm}
137