xref: /freebsd/crypto/heimdal/kadmin/kadm_conn.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
15e9cd1aeSAssar Westerlund /*
2*ae771770SStanislav Sedov  * Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan
35e9cd1aeSAssar Westerlund  * (Royal Institute of Technology, Stockholm, Sweden).
45e9cd1aeSAssar Westerlund  * All rights reserved.
55e9cd1aeSAssar Westerlund  *
65e9cd1aeSAssar Westerlund  * Redistribution and use in source and binary forms, with or without
75e9cd1aeSAssar Westerlund  * modification, are permitted provided that the following conditions
85e9cd1aeSAssar Westerlund  * are met:
95e9cd1aeSAssar Westerlund  *
105e9cd1aeSAssar Westerlund  * 1. Redistributions of source code must retain the above copyright
115e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer.
125e9cd1aeSAssar Westerlund  *
135e9cd1aeSAssar Westerlund  * 2. Redistributions in binary form must reproduce the above copyright
145e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer in the
155e9cd1aeSAssar Westerlund  *    documentation and/or other materials provided with the distribution.
165e9cd1aeSAssar Westerlund  *
175e9cd1aeSAssar Westerlund  * 3. Neither the name of the Institute nor the names of its contributors
185e9cd1aeSAssar Westerlund  *    may be used to endorse or promote products derived from this software
195e9cd1aeSAssar Westerlund  *    without specific prior written permission.
205e9cd1aeSAssar Westerlund  *
215e9cd1aeSAssar Westerlund  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
225e9cd1aeSAssar Westerlund  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
235e9cd1aeSAssar Westerlund  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
245e9cd1aeSAssar Westerlund  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
255e9cd1aeSAssar Westerlund  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
265e9cd1aeSAssar Westerlund  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
275e9cd1aeSAssar Westerlund  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
285e9cd1aeSAssar Westerlund  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
295e9cd1aeSAssar Westerlund  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
305e9cd1aeSAssar Westerlund  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315e9cd1aeSAssar Westerlund  * SUCH DAMAGE.
325e9cd1aeSAssar Westerlund  */
335e9cd1aeSAssar Westerlund 
345e9cd1aeSAssar Westerlund #include "kadmin_locl.h"
355e9cd1aeSAssar Westerlund #ifdef HAVE_SYS_WAIT_H
365e9cd1aeSAssar Westerlund #include <sys/wait.h>
375e9cd1aeSAssar Westerlund #endif
385e9cd1aeSAssar Westerlund 
395e9cd1aeSAssar Westerlund struct kadm_port {
405e9cd1aeSAssar Westerlund     char *port;
415e9cd1aeSAssar Westerlund     unsigned short def_port;
425e9cd1aeSAssar Westerlund     struct kadm_port *next;
435e9cd1aeSAssar Westerlund } *kadm_ports;
445e9cd1aeSAssar Westerlund 
455e9cd1aeSAssar Westerlund static void
add_kadm_port(krb5_context contextp,const char * service,unsigned int port)46*ae771770SStanislav Sedov add_kadm_port(krb5_context contextp, const char *service, unsigned int port)
475e9cd1aeSAssar Westerlund {
485e9cd1aeSAssar Westerlund     struct kadm_port *p;
495e9cd1aeSAssar Westerlund     p = malloc(sizeof(*p));
505e9cd1aeSAssar Westerlund     if(p == NULL) {
51*ae771770SStanislav Sedov 	krb5_warnx(contextp, "failed to allocate %lu bytes\n",
525e9cd1aeSAssar Westerlund 		   (unsigned long)sizeof(*p));
535e9cd1aeSAssar Westerlund 	return;
545e9cd1aeSAssar Westerlund     }
555e9cd1aeSAssar Westerlund 
565e9cd1aeSAssar Westerlund     p->port = strdup(service);
575e9cd1aeSAssar Westerlund     p->def_port = port;
585e9cd1aeSAssar Westerlund 
595e9cd1aeSAssar Westerlund     p->next = kadm_ports;
605e9cd1aeSAssar Westerlund     kadm_ports = p;
615e9cd1aeSAssar Westerlund }
625e9cd1aeSAssar Westerlund 
635e9cd1aeSAssar Westerlund static void
add_standard_ports(krb5_context contextp)64*ae771770SStanislav Sedov add_standard_ports (krb5_context contextp)
655e9cd1aeSAssar Westerlund {
66*ae771770SStanislav Sedov     add_kadm_port(contextp, "kerberos-adm", 749);
675e9cd1aeSAssar Westerlund }
685e9cd1aeSAssar Westerlund 
695e9cd1aeSAssar Westerlund /*
705e9cd1aeSAssar Westerlund  * parse the set of space-delimited ports in `str' and add them.
715e9cd1aeSAssar Westerlund  * "+" => all the standard ones
725e9cd1aeSAssar Westerlund  * otherwise it's port|service[/protocol]
735e9cd1aeSAssar Westerlund  */
745e9cd1aeSAssar Westerlund 
755e9cd1aeSAssar Westerlund void
parse_ports(krb5_context contextp,const char * str)76*ae771770SStanislav Sedov parse_ports(krb5_context contextp, const char *str)
775e9cd1aeSAssar Westerlund {
785e9cd1aeSAssar Westerlund     char p[128];
795e9cd1aeSAssar Westerlund 
805e9cd1aeSAssar Westerlund     while(strsep_copy(&str, " \t", p, sizeof(p)) != -1) {
815e9cd1aeSAssar Westerlund 	if(strcmp(p, "+") == 0)
82*ae771770SStanislav Sedov 	    add_standard_ports(contextp);
835e9cd1aeSAssar Westerlund 	else
84*ae771770SStanislav Sedov 	    add_kadm_port(contextp, p, 0);
855e9cd1aeSAssar Westerlund     }
865e9cd1aeSAssar Westerlund }
875e9cd1aeSAssar Westerlund 
885e9cd1aeSAssar Westerlund static pid_t pgrp;
895e9cd1aeSAssar Westerlund sig_atomic_t term_flag, doing_useful_work;
905e9cd1aeSAssar Westerlund 
915e9cd1aeSAssar Westerlund static RETSIGTYPE
sigchld(int sig)925e9cd1aeSAssar Westerlund sigchld(int sig)
935e9cd1aeSAssar Westerlund {
945e9cd1aeSAssar Westerlund     int status;
95*ae771770SStanislav Sedov     /*
96*ae771770SStanislav Sedov      * waitpid() is async safe. will return -1 or 0 on no more zombie
97*ae771770SStanislav Sedov      * children
98*ae771770SStanislav Sedov      */
99*ae771770SStanislav Sedov     while ((waitpid(-1, &status, WNOHANG)) > 0)
100*ae771770SStanislav Sedov 	;
1015e9cd1aeSAssar Westerlund     SIGRETURN(0);
1025e9cd1aeSAssar Westerlund }
1035e9cd1aeSAssar Westerlund 
1045e9cd1aeSAssar Westerlund static RETSIGTYPE
terminate(int sig)1055e9cd1aeSAssar Westerlund terminate(int sig)
1065e9cd1aeSAssar Westerlund {
1075e9cd1aeSAssar Westerlund     if(getpid() == pgrp) {
1085e9cd1aeSAssar Westerlund 	/* parent */
1095e9cd1aeSAssar Westerlund 	term_flag = 1;
1105e9cd1aeSAssar Westerlund 	signal(sig, SIG_IGN);
1115e9cd1aeSAssar Westerlund 	killpg(pgrp, sig);
1125e9cd1aeSAssar Westerlund     } else {
1135e9cd1aeSAssar Westerlund 	/* child */
1145e9cd1aeSAssar Westerlund 	if(doing_useful_work)
1155e9cd1aeSAssar Westerlund 	    term_flag = 1;
1165e9cd1aeSAssar Westerlund 	else
1175e9cd1aeSAssar Westerlund 	    exit(0);
1185e9cd1aeSAssar Westerlund     }
1195e9cd1aeSAssar Westerlund     SIGRETURN(0);
1205e9cd1aeSAssar Westerlund }
1215e9cd1aeSAssar Westerlund 
1225e9cd1aeSAssar Westerlund static int
spawn_child(krb5_context contextp,int * socks,unsigned int num_socks,int this_sock)123*ae771770SStanislav Sedov spawn_child(krb5_context contextp, int *socks,
124*ae771770SStanislav Sedov 	    unsigned int num_socks, int this_sock)
1255e9cd1aeSAssar Westerlund {
126*ae771770SStanislav Sedov     int e;
127*ae771770SStanislav Sedov     size_t i;
1285e9cd1aeSAssar Westerlund     struct sockaddr_storage __ss;
1295e9cd1aeSAssar Westerlund     struct sockaddr *sa = (struct sockaddr *)&__ss;
1305e9cd1aeSAssar Westerlund     socklen_t sa_size = sizeof(__ss);
131*ae771770SStanislav Sedov     krb5_socket_t s;
1325e9cd1aeSAssar Westerlund     pid_t pid;
1335e9cd1aeSAssar Westerlund     krb5_address addr;
1345e9cd1aeSAssar Westerlund     char buf[128];
1355e9cd1aeSAssar Westerlund     size_t buf_len;
1365e9cd1aeSAssar Westerlund 
1375e9cd1aeSAssar Westerlund     s = accept(socks[this_sock], sa, &sa_size);
138*ae771770SStanislav Sedov     if(rk_IS_BAD_SOCKET(s)) {
139*ae771770SStanislav Sedov 	krb5_warn(contextp, rk_SOCK_ERRNO, "accept");
1405e9cd1aeSAssar Westerlund 	return 1;
1415e9cd1aeSAssar Westerlund     }
142*ae771770SStanislav Sedov     e = krb5_sockaddr2address(contextp, sa, &addr);
1435e9cd1aeSAssar Westerlund     if(e)
144*ae771770SStanislav Sedov 	krb5_warn(contextp, e, "krb5_sockaddr2address");
1455e9cd1aeSAssar Westerlund     else {
1465e9cd1aeSAssar Westerlund 	e = krb5_print_address (&addr, buf, sizeof(buf),
1475e9cd1aeSAssar Westerlund 				&buf_len);
1485e9cd1aeSAssar Westerlund 	if(e)
149*ae771770SStanislav Sedov 	    krb5_warn(contextp, e, "krb5_print_address");
1505e9cd1aeSAssar Westerlund 	else
151*ae771770SStanislav Sedov 	    krb5_warnx(contextp, "connection from %s", buf);
152*ae771770SStanislav Sedov 	krb5_free_address(contextp, &addr);
1535e9cd1aeSAssar Westerlund     }
1545e9cd1aeSAssar Westerlund 
1555e9cd1aeSAssar Westerlund     pid = fork();
1565e9cd1aeSAssar Westerlund     if(pid == 0) {
1575e9cd1aeSAssar Westerlund 	for(i = 0; i < num_socks; i++)
158*ae771770SStanislav Sedov 	    rk_closesocket(socks[i]);
1595e9cd1aeSAssar Westerlund 	dup2(s, STDIN_FILENO);
1605e9cd1aeSAssar Westerlund 	dup2(s, STDOUT_FILENO);
1615e9cd1aeSAssar Westerlund 	if(s != STDIN_FILENO && s != STDOUT_FILENO)
162*ae771770SStanislav Sedov 	    rk_closesocket(s);
1635e9cd1aeSAssar Westerlund 	return 0;
1645e9cd1aeSAssar Westerlund     } else {
165*ae771770SStanislav Sedov 	rk_closesocket(s);
1665e9cd1aeSAssar Westerlund     }
1675e9cd1aeSAssar Westerlund     return 1;
1685e9cd1aeSAssar Westerlund }
1695e9cd1aeSAssar Westerlund 
170*ae771770SStanislav Sedov static void
wait_for_connection(krb5_context contextp,krb5_socket_t * socks,unsigned int num_socks)171*ae771770SStanislav Sedov wait_for_connection(krb5_context contextp,
172*ae771770SStanislav Sedov 		    krb5_socket_t *socks, unsigned int num_socks)
1735e9cd1aeSAssar Westerlund {
174*ae771770SStanislav Sedov     unsigned int i;
175*ae771770SStanislav Sedov     int e;
1765e9cd1aeSAssar Westerlund     fd_set orig_read_set, read_set;
177*ae771770SStanislav Sedov     int status, max_fd = -1;
1785e9cd1aeSAssar Westerlund 
1795e9cd1aeSAssar Westerlund     FD_ZERO(&orig_read_set);
1805e9cd1aeSAssar Westerlund 
1815e9cd1aeSAssar Westerlund     for(i = 0; i < num_socks; i++) {
182*ae771770SStanislav Sedov #ifdef FD_SETSIZE
1835e9cd1aeSAssar Westerlund 	if (socks[i] >= FD_SETSIZE)
1845e9cd1aeSAssar Westerlund 	    errx (1, "fd too large");
185*ae771770SStanislav Sedov #endif
1865e9cd1aeSAssar Westerlund 	FD_SET(socks[i], &orig_read_set);
1875e9cd1aeSAssar Westerlund 	max_fd = max(max_fd, socks[i]);
1885e9cd1aeSAssar Westerlund     }
1895e9cd1aeSAssar Westerlund 
1905e9cd1aeSAssar Westerlund     pgrp = getpid();
1915e9cd1aeSAssar Westerlund 
1925e9cd1aeSAssar Westerlund     if(setpgid(0, pgrp) < 0)
1935e9cd1aeSAssar Westerlund 	err(1, "setpgid");
1945e9cd1aeSAssar Westerlund 
1955e9cd1aeSAssar Westerlund     signal(SIGTERM, terminate);
1965e9cd1aeSAssar Westerlund     signal(SIGINT, terminate);
1975e9cd1aeSAssar Westerlund     signal(SIGCHLD, sigchld);
1985e9cd1aeSAssar Westerlund 
1995e9cd1aeSAssar Westerlund     while (term_flag == 0) {
2005e9cd1aeSAssar Westerlund 	read_set = orig_read_set;
2015e9cd1aeSAssar Westerlund 	e = select(max_fd + 1, &read_set, NULL, NULL, NULL);
202*ae771770SStanislav Sedov 	if(rk_IS_SOCKET_ERROR(e)) {
203*ae771770SStanislav Sedov 	    if(rk_SOCK_ERRNO != EINTR)
204*ae771770SStanislav Sedov 		krb5_warn(contextp, rk_SOCK_ERRNO, "select");
2055e9cd1aeSAssar Westerlund 	} else if(e == 0)
206*ae771770SStanislav Sedov 	    krb5_warnx(contextp, "select returned 0");
2075e9cd1aeSAssar Westerlund 	else {
2085e9cd1aeSAssar Westerlund 	    for(i = 0; i < num_socks; i++) {
2095e9cd1aeSAssar Westerlund 		if(FD_ISSET(socks[i], &read_set))
210*ae771770SStanislav Sedov 		    if(spawn_child(contextp, socks, num_socks, i) == 0)
211*ae771770SStanislav Sedov 			return;
2125e9cd1aeSAssar Westerlund 	    }
2135e9cd1aeSAssar Westerlund 	}
2145e9cd1aeSAssar Westerlund     }
2155e9cd1aeSAssar Westerlund     signal(SIGCHLD, SIG_IGN);
216*ae771770SStanislav Sedov 
217*ae771770SStanislav Sedov     while ((waitpid(-1, &status, WNOHANG)) > 0)
218*ae771770SStanislav Sedov 	;
219*ae771770SStanislav Sedov 
2205e9cd1aeSAssar Westerlund     exit(0);
2215e9cd1aeSAssar Westerlund }
2225e9cd1aeSAssar Westerlund 
2235e9cd1aeSAssar Westerlund 
224*ae771770SStanislav Sedov void
start_server(krb5_context contextp,const char * port_str)225*ae771770SStanislav Sedov start_server(krb5_context contextp, const char *port_str)
2265e9cd1aeSAssar Westerlund {
2275e9cd1aeSAssar Westerlund     int e;
2285e9cd1aeSAssar Westerlund     struct kadm_port *p;
2295e9cd1aeSAssar Westerlund 
230*ae771770SStanislav Sedov     krb5_socket_t *socks = NULL, *tmp;
231*ae771770SStanislav Sedov     unsigned int num_socks = 0;
2325e9cd1aeSAssar Westerlund     int i;
2335e9cd1aeSAssar Westerlund 
234*ae771770SStanislav Sedov     if (port_str == NULL)
235*ae771770SStanislav Sedov 	port_str = "+";
236*ae771770SStanislav Sedov 
237*ae771770SStanislav Sedov     parse_ports(contextp, port_str);
238*ae771770SStanislav Sedov 
2395e9cd1aeSAssar Westerlund     for(p = kadm_ports; p; p = p->next) {
2405e9cd1aeSAssar Westerlund 	struct addrinfo hints, *ai, *ap;
2415e9cd1aeSAssar Westerlund 	char portstr[32];
2425e9cd1aeSAssar Westerlund 	memset (&hints, 0, sizeof(hints));
2435e9cd1aeSAssar Westerlund 	hints.ai_flags    = AI_PASSIVE;
2445e9cd1aeSAssar Westerlund 	hints.ai_socktype = SOCK_STREAM;
2455e9cd1aeSAssar Westerlund 
2465e9cd1aeSAssar Westerlund 	e = getaddrinfo(NULL, p->port, &hints, &ai);
2475e9cd1aeSAssar Westerlund 	if(e) {
2485e9cd1aeSAssar Westerlund 	    snprintf(portstr, sizeof(portstr), "%u", p->def_port);
2495e9cd1aeSAssar Westerlund 	    e = getaddrinfo(NULL, portstr, &hints, &ai);
2505e9cd1aeSAssar Westerlund 	}
2515e9cd1aeSAssar Westerlund 
2525e9cd1aeSAssar Westerlund 	if(e) {
253*ae771770SStanislav Sedov 	    krb5_warn(contextp, krb5_eai_to_heim_errno(e, errno),
254adb0ddaeSAssar Westerlund 		      "%s", portstr);
2555e9cd1aeSAssar Westerlund 	    continue;
2565e9cd1aeSAssar Westerlund 	}
2575e9cd1aeSAssar Westerlund 	i = 0;
2585e9cd1aeSAssar Westerlund 	for(ap = ai; ap; ap = ap->ai_next)
2595e9cd1aeSAssar Westerlund 	    i++;
2605e9cd1aeSAssar Westerlund 	tmp = realloc(socks, (num_socks + i) * sizeof(*socks));
2615e9cd1aeSAssar Westerlund 	if(tmp == NULL) {
262*ae771770SStanislav Sedov 	    krb5_warnx(contextp, "failed to reallocate %lu bytes",
2635e9cd1aeSAssar Westerlund 		       (unsigned long)(num_socks + i) * sizeof(*socks));
2645e9cd1aeSAssar Westerlund 	    continue;
2655e9cd1aeSAssar Westerlund 	}
2665e9cd1aeSAssar Westerlund 	socks = tmp;
2675e9cd1aeSAssar Westerlund 	for(ap = ai; ap; ap = ap->ai_next) {
268*ae771770SStanislav Sedov 	    krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
269*ae771770SStanislav Sedov 	    if(rk_IS_BAD_SOCKET(s)) {
270*ae771770SStanislav Sedov 		krb5_warn(contextp, rk_SOCK_ERRNO, "socket");
2715e9cd1aeSAssar Westerlund 		continue;
2725e9cd1aeSAssar Westerlund 	    }
273c19800e8SDoug Rabson 
274c19800e8SDoug Rabson 	    socket_set_reuseaddr(s, 1);
275c19800e8SDoug Rabson 	    socket_set_ipv6only(s, 1);
276c19800e8SDoug Rabson 
277*ae771770SStanislav Sedov 	    if (rk_IS_SOCKET_ERROR(bind (s, ap->ai_addr, ap->ai_addrlen))) {
278*ae771770SStanislav Sedov 		krb5_warn(contextp, rk_SOCK_ERRNO, "bind");
279*ae771770SStanislav Sedov 		rk_closesocket(s);
2805e9cd1aeSAssar Westerlund 		continue;
2815e9cd1aeSAssar Westerlund 	    }
282*ae771770SStanislav Sedov 	    if (rk_IS_SOCKET_ERROR(listen (s, SOMAXCONN))) {
283*ae771770SStanislav Sedov 		krb5_warn(contextp, rk_SOCK_ERRNO, "listen");
284*ae771770SStanislav Sedov 		rk_closesocket(s);
2855e9cd1aeSAssar Westerlund 		continue;
2865e9cd1aeSAssar Westerlund 	    }
2875e9cd1aeSAssar Westerlund 	    socks[num_socks++] = s;
2885e9cd1aeSAssar Westerlund 	}
2895e9cd1aeSAssar Westerlund 	freeaddrinfo (ai);
2905e9cd1aeSAssar Westerlund     }
2915e9cd1aeSAssar Westerlund     if(num_socks == 0)
292*ae771770SStanislav Sedov 	krb5_errx(contextp, 1, "no sockets to listen to - exiting");
293*ae771770SStanislav Sedov 
294*ae771770SStanislav Sedov     wait_for_connection(contextp, socks, num_socks);
2955e9cd1aeSAssar Westerlund }
296