172445Sassar/* 2233294Sstas * Copyright (c) 2000 - 2004 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 572445Sassar * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 972445Sassar * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1272445Sassar * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1672445Sassar * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2072445Sassar * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#include "kadmin_locl.h" 3572445Sassar#ifdef HAVE_SYS_WAIT_H 3672445Sassar#include <sys/wait.h> 3772445Sassar#endif 3872445Sassar 3972445Sassarstruct kadm_port { 4072445Sassar char *port; 4172445Sassar unsigned short def_port; 4272445Sassar struct kadm_port *next; 4372445Sassar} *kadm_ports; 4472445Sassar 4572445Sassarstatic void 46233294Sstasadd_kadm_port(krb5_context contextp, const char *service, unsigned int port) 4772445Sassar{ 4872445Sassar struct kadm_port *p; 4972445Sassar p = malloc(sizeof(*p)); 5072445Sassar if(p == NULL) { 51233294Sstas krb5_warnx(contextp, "failed to allocate %lu bytes\n", 5272445Sassar (unsigned long)sizeof(*p)); 5372445Sassar return; 5472445Sassar } 55233294Sstas 5672445Sassar p->port = strdup(service); 5772445Sassar p->def_port = port; 5872445Sassar 5972445Sassar p->next = kadm_ports; 6072445Sassar kadm_ports = p; 6172445Sassar} 6272445Sassar 6372445Sassarstatic void 64233294Sstasadd_standard_ports (krb5_context contextp) 6572445Sassar{ 66233294Sstas add_kadm_port(contextp, "kerberos-adm", 749); 6772445Sassar} 6872445Sassar 6972445Sassar/* 7072445Sassar * parse the set of space-delimited ports in `str' and add them. 7172445Sassar * "+" => all the standard ones 7272445Sassar * otherwise it's port|service[/protocol] 7372445Sassar */ 7472445Sassar 7572445Sassarvoid 76233294Sstasparse_ports(krb5_context contextp, const char *str) 7772445Sassar{ 7872445Sassar char p[128]; 7972445Sassar 8072445Sassar while(strsep_copy(&str, " \t", p, sizeof(p)) != -1) { 8172445Sassar if(strcmp(p, "+") == 0) 82233294Sstas add_standard_ports(contextp); 8372445Sassar else 84233294Sstas add_kadm_port(contextp, p, 0); 8572445Sassar } 8672445Sassar} 8772445Sassar 8872445Sassarstatic pid_t pgrp; 8972445Sassarsig_atomic_t term_flag, doing_useful_work; 9072445Sassar 9172445Sassarstatic RETSIGTYPE 9272445Sassarsigchld(int sig) 9372445Sassar{ 9472445Sassar int status; 95233294Sstas /* 96233294Sstas * waitpid() is async safe. will return -1 or 0 on no more zombie 97233294Sstas * children 98233294Sstas */ 99233294Sstas while ((waitpid(-1, &status, WNOHANG)) > 0) 100233294Sstas ; 10172445Sassar SIGRETURN(0); 10272445Sassar} 10372445Sassar 10472445Sassarstatic RETSIGTYPE 10572445Sassarterminate(int sig) 10672445Sassar{ 10772445Sassar if(getpid() == pgrp) { 10872445Sassar /* parent */ 10972445Sassar term_flag = 1; 11072445Sassar signal(sig, SIG_IGN); 11172445Sassar killpg(pgrp, sig); 11272445Sassar } else { 11372445Sassar /* child */ 11472445Sassar if(doing_useful_work) 11572445Sassar term_flag = 1; 11672445Sassar else 11772445Sassar exit(0); 11872445Sassar } 11972445Sassar SIGRETURN(0); 12072445Sassar} 12172445Sassar 12272445Sassarstatic int 123233294Sstasspawn_child(krb5_context contextp, int *socks, 124233294Sstas unsigned int num_socks, int this_sock) 12572445Sassar{ 126233294Sstas int e; 127233294Sstas size_t i; 12872445Sassar struct sockaddr_storage __ss; 12972445Sassar struct sockaddr *sa = (struct sockaddr *)&__ss; 13072445Sassar socklen_t sa_size = sizeof(__ss); 131233294Sstas krb5_socket_t s; 13272445Sassar pid_t pid; 13372445Sassar krb5_address addr; 13472445Sassar char buf[128]; 13572445Sassar size_t buf_len; 13672445Sassar 13772445Sassar s = accept(socks[this_sock], sa, &sa_size); 138233294Sstas if(rk_IS_BAD_SOCKET(s)) { 139233294Sstas krb5_warn(contextp, rk_SOCK_ERRNO, "accept"); 14072445Sassar return 1; 14172445Sassar } 142233294Sstas e = krb5_sockaddr2address(contextp, sa, &addr); 14372445Sassar if(e) 144233294Sstas krb5_warn(contextp, e, "krb5_sockaddr2address"); 14572445Sassar else { 146233294Sstas e = krb5_print_address (&addr, buf, sizeof(buf), 14772445Sassar &buf_len); 148233294Sstas if(e) 149233294Sstas krb5_warn(contextp, e, "krb5_print_address"); 15072445Sassar else 151233294Sstas krb5_warnx(contextp, "connection from %s", buf); 152233294Sstas krb5_free_address(contextp, &addr); 15372445Sassar } 154233294Sstas 15572445Sassar pid = fork(); 15672445Sassar if(pid == 0) { 15772445Sassar for(i = 0; i < num_socks; i++) 158233294Sstas rk_closesocket(socks[i]); 15972445Sassar dup2(s, STDIN_FILENO); 16072445Sassar dup2(s, STDOUT_FILENO); 16172445Sassar if(s != STDIN_FILENO && s != STDOUT_FILENO) 162233294Sstas rk_closesocket(s); 16372445Sassar return 0; 16472445Sassar } else { 165233294Sstas rk_closesocket(s); 16672445Sassar } 16772445Sassar return 1; 16872445Sassar} 16972445Sassar 170233294Sstasstatic void 171233294Sstaswait_for_connection(krb5_context contextp, 172233294Sstas krb5_socket_t *socks, unsigned int num_socks) 17372445Sassar{ 174233294Sstas unsigned int i; 175233294Sstas int e; 17672445Sassar fd_set orig_read_set, read_set; 177233294Sstas int status, max_fd = -1; 178233294Sstas 17972445Sassar FD_ZERO(&orig_read_set); 180233294Sstas 18172445Sassar for(i = 0; i < num_socks; i++) { 182233294Sstas#ifdef FD_SETSIZE 18372445Sassar if (socks[i] >= FD_SETSIZE) 18472445Sassar errx (1, "fd too large"); 185233294Sstas#endif 18672445Sassar FD_SET(socks[i], &orig_read_set); 18772445Sassar max_fd = max(max_fd, socks[i]); 18872445Sassar } 189233294Sstas 19072445Sassar pgrp = getpid(); 19172445Sassar 19272445Sassar if(setpgid(0, pgrp) < 0) 19372445Sassar err(1, "setpgid"); 19472445Sassar 19572445Sassar signal(SIGTERM, terminate); 19672445Sassar signal(SIGINT, terminate); 19772445Sassar signal(SIGCHLD, sigchld); 19872445Sassar 19972445Sassar while (term_flag == 0) { 20072445Sassar read_set = orig_read_set; 20172445Sassar e = select(max_fd + 1, &read_set, NULL, NULL, NULL); 202233294Sstas if(rk_IS_SOCKET_ERROR(e)) { 203233294Sstas if(rk_SOCK_ERRNO != EINTR) 204233294Sstas krb5_warn(contextp, rk_SOCK_ERRNO, "select"); 20572445Sassar } else if(e == 0) 206233294Sstas krb5_warnx(contextp, "select returned 0"); 20772445Sassar else { 20872445Sassar for(i = 0; i < num_socks; i++) { 20972445Sassar if(FD_ISSET(socks[i], &read_set)) 210233294Sstas if(spawn_child(contextp, socks, num_socks, i) == 0) 211233294Sstas return; 21272445Sassar } 21372445Sassar } 21472445Sassar } 21572445Sassar signal(SIGCHLD, SIG_IGN); 216233294Sstas 217233294Sstas while ((waitpid(-1, &status, WNOHANG)) > 0) 218233294Sstas ; 219233294Sstas 22072445Sassar exit(0); 22172445Sassar} 22272445Sassar 22372445Sassar 224233294Sstasvoid 225233294Sstasstart_server(krb5_context contextp, const char *port_str) 22672445Sassar{ 22772445Sassar int e; 22872445Sassar struct kadm_port *p; 22972445Sassar 230233294Sstas krb5_socket_t *socks = NULL, *tmp; 231233294Sstas unsigned int num_socks = 0; 23272445Sassar int i; 23372445Sassar 234233294Sstas if (port_str == NULL) 235233294Sstas port_str = "+"; 236233294Sstas 237233294Sstas parse_ports(contextp, port_str); 238233294Sstas 23972445Sassar for(p = kadm_ports; p; p = p->next) { 24072445Sassar struct addrinfo hints, *ai, *ap; 24172445Sassar char portstr[32]; 24272445Sassar memset (&hints, 0, sizeof(hints)); 24372445Sassar hints.ai_flags = AI_PASSIVE; 24472445Sassar hints.ai_socktype = SOCK_STREAM; 24572445Sassar 24672445Sassar e = getaddrinfo(NULL, p->port, &hints, &ai); 24772445Sassar if(e) { 24872445Sassar snprintf(portstr, sizeof(portstr), "%u", p->def_port); 24972445Sassar e = getaddrinfo(NULL, portstr, &hints, &ai); 25072445Sassar } 25172445Sassar 25272445Sassar if(e) { 253233294Sstas krb5_warn(contextp, krb5_eai_to_heim_errno(e, errno), 25478527Sassar "%s", portstr); 25572445Sassar continue; 25672445Sassar } 25772445Sassar i = 0; 258233294Sstas for(ap = ai; ap; ap = ap->ai_next) 25972445Sassar i++; 26072445Sassar tmp = realloc(socks, (num_socks + i) * sizeof(*socks)); 26172445Sassar if(tmp == NULL) { 262233294Sstas krb5_warnx(contextp, "failed to reallocate %lu bytes", 26372445Sassar (unsigned long)(num_socks + i) * sizeof(*socks)); 26472445Sassar continue; 26572445Sassar } 26672445Sassar socks = tmp; 26772445Sassar for(ap = ai; ap; ap = ap->ai_next) { 268233294Sstas krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); 269233294Sstas if(rk_IS_BAD_SOCKET(s)) { 270233294Sstas krb5_warn(contextp, rk_SOCK_ERRNO, "socket"); 27172445Sassar continue; 27272445Sassar } 273178825Sdfr 274178825Sdfr socket_set_reuseaddr(s, 1); 275178825Sdfr socket_set_ipv6only(s, 1); 276178825Sdfr 277233294Sstas if (rk_IS_SOCKET_ERROR(bind (s, ap->ai_addr, ap->ai_addrlen))) { 278233294Sstas krb5_warn(contextp, rk_SOCK_ERRNO, "bind"); 279233294Sstas rk_closesocket(s); 28072445Sassar continue; 28172445Sassar } 282233294Sstas if (rk_IS_SOCKET_ERROR(listen (s, SOMAXCONN))) { 283233294Sstas krb5_warn(contextp, rk_SOCK_ERRNO, "listen"); 284233294Sstas rk_closesocket(s); 28572445Sassar continue; 28672445Sassar } 28772445Sassar socks[num_socks++] = s; 28872445Sassar } 28972445Sassar freeaddrinfo (ai); 29072445Sassar } 29172445Sassar if(num_socks == 0) 292233294Sstas krb5_errx(contextp, 1, "no sockets to listen to - exiting"); 293233294Sstas 294233294Sstas wait_for_connection(contextp, socks, num_socks); 29572445Sassar} 296