Home | History | Annotate | Line # | Download | only in roken
      1 /*	$NetBSD: mini_inetd.c,v 1.2 2017/01/28 21:31:50 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 - 2001 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <config.h>
     37 
     38 #include <err.h>
     39 #include <krb5/roken.h>
     40 
     41 /*
     42  * accept a connection on `s' and pretend it's served by inetd.
     43  */
     44 
     45 static void
     46 accept_it (rk_socket_t s, rk_socket_t *ret_socket)
     47 {
     48     rk_socket_t as;
     49 
     50     as = accept(s, NULL, NULL);
     51     if(rk_IS_BAD_SOCKET(as))
     52 	err (1, "accept");
     53 
     54     if (ret_socket) {
     55 
     56 	*ret_socket = as;
     57 
     58     } else {
     59 	int fd = socket_to_fd(as, 0);
     60 
     61 	/* We would use _O_RDONLY for the socket_to_fd() call for
     62 	   STDIN, but there are instances where we assume that STDIN
     63 	   is a r/w socket. */
     64 
     65 	dup2(fd, STDIN_FILENO);
     66 	dup2(fd, STDOUT_FILENO);
     67 
     68 	rk_closesocket(as);
     69     }
     70 }
     71 
     72 /**
     73  * Listen on a specified addresses
     74  *
     75  * Listens on the specified addresses for incoming connections.  If
     76  * the \a ret_socket parameter is \a NULL, on return STDIN and STDOUT
     77  * will be connected to an accepted socket.  If the \a ret_socket
     78  * parameter is non-NULL, the accepted socket will be returned in
     79  * *ret_socket.  In the latter case, STDIN and STDOUT will be left
     80  * unmodified.
     81  *
     82  * This function does not return if there is an error or if no
     83  * connection is established.
     84  *
     85  * @param[in] ai Addresses to listen on
     86  * @param[out] ret_socket If non-NULL receives the accepted socket.
     87  *
     88  * @see mini_inetd()
     89  */
     90 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     91 mini_inetd_addrinfo (struct addrinfo *ai, rk_socket_t *ret_socket)
     92 {
     93     int ret;
     94     struct addrinfo *a;
     95     int n, nalloc, i;
     96     rk_socket_t *fds;
     97     fd_set orig_read_set, read_set;
     98     rk_socket_t max_fd = (rk_socket_t)-1;
     99 
    100     for (nalloc = 0, a = ai; a != NULL; a = a->ai_next)
    101 	++nalloc;
    102 
    103     fds = malloc (nalloc * sizeof(*fds));
    104     if (fds == NULL) {
    105 	errx (1, "mini_inetd: out of memory");
    106 	UNREACHABLE(return);
    107     }
    108 
    109     FD_ZERO(&orig_read_set);
    110 
    111     for (i = 0, a = ai; a != NULL; a = a->ai_next) {
    112 	fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
    113 	if (rk_IS_BAD_SOCKET(fds[i]))
    114 	    continue;
    115 	socket_set_reuseaddr (fds[i], 1);
    116 	socket_set_ipv6only(fds[i], 1);
    117 	if (rk_IS_SOCKET_ERROR(bind (fds[i], a->ai_addr, a->ai_addrlen))) {
    118 	    warn ("bind af = %d", a->ai_family);
    119 	    rk_closesocket(fds[i]);
    120 	    fds[i] = rk_INVALID_SOCKET;
    121 	    continue;
    122 	}
    123 	if (rk_IS_SOCKET_ERROR(listen (fds[i], SOMAXCONN))) {
    124 	    warn ("listen af = %d", a->ai_family);
    125 	    rk_closesocket(fds[i]);
    126 	    fds[i] = rk_INVALID_SOCKET;
    127 	    continue;
    128 	}
    129 #ifndef NO_LIMIT_FD_SETSIZE
    130 	if (fds[i] >= FD_SETSIZE)
    131 	    errx (1, "fd too large");
    132 #endif
    133 	FD_SET(fds[i], &orig_read_set);
    134 	max_fd = max(max_fd, fds[i]);
    135 	++i;
    136     }
    137     if (i == 0)
    138 	errx (1, "no sockets");
    139     n = i;
    140 
    141     do {
    142 	read_set = orig_read_set;
    143 
    144 	ret = select (max_fd + 1, &read_set, NULL, NULL, NULL);
    145 	if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR)
    146 	    err (1, "select");
    147     } while (ret <= 0);
    148 
    149     for (i = 0; i < n; ++i)
    150 	if (FD_ISSET (fds[i], &read_set)) {
    151 	    accept_it (fds[i], ret_socket);
    152 	    for (i = 0; i < n; ++i)
    153 	      rk_closesocket(fds[i]);
    154 	    free(fds);
    155 	    return;
    156 	}
    157     abort ();
    158 }
    159 
    160 /**
    161  * Listen on a specified port
    162  *
    163  * Listens on the specified port for incoming connections.  If the \a
    164  * ret_socket parameter is \a NULL, on return STDIN and STDOUT will be
    165  * connected to an accepted socket.  If the \a ret_socket parameter is
    166  * non-NULL, the accepted socket will be returned in *ret_socket.  In
    167  * the latter case, STDIN and STDOUT will be left unmodified.
    168  *
    169  * This function does not return if there is an error or if no
    170  * connection is established.
    171  *
    172  * @param[in] port Port to listen on
    173  * @param[out] ret_socket If non-NULL receives the accepted socket.
    174  *
    175  * @see mini_inetd_addrinfo()
    176  */
    177 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    178 mini_inetd(int port, rk_socket_t * ret_socket)
    179 {
    180     int error;
    181     struct addrinfo *ai, hints;
    182     char portstr[NI_MAXSERV];
    183 
    184     memset (&hints, 0, sizeof(hints));
    185     hints.ai_flags    = AI_PASSIVE;
    186     hints.ai_socktype = SOCK_STREAM;
    187     hints.ai_family   = PF_UNSPEC;
    188 
    189     snprintf (portstr, sizeof(portstr), "%d", ntohs(port));
    190 
    191     error = getaddrinfo (NULL, portstr, &hints, &ai);
    192     if (error)
    193 	errx (1, "getaddrinfo: %s", gai_strerror (error));
    194 
    195     mini_inetd_addrinfo(ai, ret_socket);
    196 
    197     freeaddrinfo(ai);
    198 }
    199 
    200