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