xref: /freebsd/crypto/heimdal/lib/roken/mini_inetd.c (revision b528cefc6b8f9670b31a865051741d946cb37085)
1 /*
2  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 RCSID("$Id: mini_inetd.c,v 1.21 1999/12/12 00:03:56 assar Exp $");
37 #endif
38 
39 #include <stdio.h>
40 
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47 #ifdef HAVE_SYS_TIME_H
48 #include <sys/time.h>
49 #endif
50 #ifdef HAVE_SYS_SOCKET_H
51 #include <sys/socket.h>
52 #endif
53 #ifdef HAVE_NETINET_IN_H
54 #include <netinet/in.h>
55 #endif
56 #ifdef HAVE_NETINET_IN6_H
57 #include <netinet/in6.h>
58 #endif
59 #ifdef HAVE_NETINET6_IN6_H
60 #include <netinet6/in6.h>
61 #endif
62 
63 #include <err.h>
64 #include <roken.h>
65 
66 /*
67  * accept a connection on `s' and pretend it's served by inetd.
68  */
69 
70 static void
71 accept_it (int s)
72 {
73     int s2;
74 
75     s2 = accept(s, NULL, 0);
76     if(s2 < 0)
77 	err (1, "accept");
78     close(s);
79     dup2(s2, STDIN_FILENO);
80     dup2(s2, STDOUT_FILENO);
81     /* dup2(s2, STDERR_FILENO); */
82     close(s2);
83 }
84 
85 /*
86  * Listen on `port' emulating inetd.
87  */
88 
89 void
90 mini_inetd (int port)
91 {
92     int error, ret;
93     struct addrinfo *ai, *a, hints;
94     char portstr[NI_MAXSERV];
95     int n, i;
96     int *fds;
97     fd_set orig_read_set, read_set;
98     int max_fd = -1;
99 
100     memset (&hints, 0, sizeof(hints));
101     hints.ai_flags    = AI_PASSIVE;
102     hints.ai_socktype = SOCK_STREAM;
103 
104     snprintf (portstr, sizeof(portstr), "%d", ntohs(port));
105 
106     error = getaddrinfo (NULL, portstr, &hints, &ai);
107     if (error)
108 	errx (1, "getaddrinfo: %s", gai_strerror (error));
109 
110     for (n = 0, a = ai; a != NULL; a = a->ai_next)
111 	++n;
112 
113     fds = malloc (n * sizeof(*fds));
114     if (fds == NULL)
115 	errx (1, "mini_inetd: out of memory");
116 
117     FD_ZERO(&orig_read_set);
118 
119     for (i = 0, a = ai; a != NULL; a = a->ai_next, ++i) {
120 	fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
121 	if (fds[i] < 0)
122 	    err (1, "socket");
123 	socket_set_reuseaddr (fds[i], 1);
124 	if (bind (fds[i], a->ai_addr, a->ai_addrlen) < 0)
125 	    err (1, "bind");
126 	if (listen (fds[i], SOMAXCONN) < 0)
127 	    err (1, "listen");
128 	FD_SET(fds[i], &orig_read_set);
129 	max_fd = max(max_fd, fds[i]);
130     }
131     freeaddrinfo (ai);
132 
133     do {
134 	read_set = orig_read_set;
135 
136 	ret = select (max_fd + 1, &read_set, NULL, NULL, NULL);
137 	if (ret < 0 && errno != EINTR)
138 	    err (1, "select");
139     } while (ret <= 0);
140 
141     for (i = 0; i < n; ++i)
142 	if (FD_ISSET (fds[i], &read_set)) {
143 	    accept_it (fds[i]);
144 	    return;
145 	}
146     abort ();
147 }
148