kadm_conn.c revision 72445
172445Sassar/* 272445Sassar * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan 372445Sassar * (Royal Institute of Technology, Stockholm, Sweden). 472445Sassar * All rights reserved. 572445Sassar * 672445Sassar * Redistribution and use in source and binary forms, with or without 772445Sassar * modification, are permitted provided that the following conditions 872445Sassar * are met: 972445Sassar * 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 1272445Sassar * 1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1472445Sassar * notice, this list of conditions and the following disclaimer in the 1572445Sassar * documentation and/or other materials provided with the distribution. 1672445Sassar * 1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors 1872445Sassar * may be used to endorse or promote products derived from this software 1972445Sassar * without specific prior written permission. 2072445Sassar * 2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2472445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3172445Sassar * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#include "kadmin_locl.h" 3572445Sassar#ifdef HAVE_SYS_WAIT_H 3672445Sassar#include <sys/wait.h> 3772445Sassar#endif 3872445Sassar 3972445SassarRCSID("$Id: kadm_conn.c,v 1.11 2001/01/29 08:43:01 assar Exp $"); 4072445Sassar 4172445Sassarstruct kadm_port { 4272445Sassar char *port; 4372445Sassar unsigned short def_port; 4472445Sassar struct kadm_port *next; 4572445Sassar} *kadm_ports; 4672445Sassar 4772445Sassarstatic void 4872445Sassaradd_kadm_port(krb5_context context, const char *service, unsigned int port) 4972445Sassar{ 5072445Sassar struct kadm_port *p; 5172445Sassar p = malloc(sizeof(*p)); 5272445Sassar if(p == NULL) { 5372445Sassar krb5_warnx(context, "failed to allocate %lu bytes\n", 5472445Sassar (unsigned long)sizeof(*p)); 5572445Sassar return; 5672445Sassar } 5772445Sassar 5872445Sassar p->port = strdup(service); 5972445Sassar p->def_port = port; 6072445Sassar 6172445Sassar p->next = kadm_ports; 6272445Sassar kadm_ports = p; 6372445Sassar} 6472445Sassar 6572445Sassarstatic void 6672445Sassaradd_standard_ports (krb5_context context) 6772445Sassar{ 6872445Sassar add_kadm_port(context, "kerberos-adm", 749); 6972445Sassar#ifdef KRB4 7072445Sassar add_kadm_port(context, "kerberos-master", 751); 7172445Sassar#endif 7272445Sassar} 7372445Sassar 7472445Sassar/* 7572445Sassar * parse the set of space-delimited ports in `str' and add them. 7672445Sassar * "+" => all the standard ones 7772445Sassar * otherwise it's port|service[/protocol] 7872445Sassar */ 7972445Sassar 8072445Sassarvoid 8172445Sassarparse_ports(krb5_context context, const char *str) 8272445Sassar{ 8372445Sassar char p[128]; 8472445Sassar 8572445Sassar while(strsep_copy(&str, " \t", p, sizeof(p)) != -1) { 8672445Sassar if(strcmp(p, "+") == 0) 8772445Sassar add_standard_ports(context); 8872445Sassar else 8972445Sassar add_kadm_port(context, p, 0); 9072445Sassar } 9172445Sassar} 9272445Sassar 9372445Sassarstatic pid_t pgrp; 9472445Sassarsig_atomic_t term_flag, doing_useful_work; 9572445Sassar 9672445Sassarstatic RETSIGTYPE 9772445Sassarsigchld(int sig) 9872445Sassar{ 9972445Sassar int status; 10072445Sassar waitpid(-1, &status, 0); 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 12372445Sassarspawn_child(krb5_context context, int *socks, int num_socks, int this_sock) 12472445Sassar{ 12572445Sassar int e, i; 12672445Sassar struct sockaddr_storage __ss; 12772445Sassar struct sockaddr *sa = (struct sockaddr *)&__ss; 12872445Sassar socklen_t sa_size = sizeof(__ss); 12972445Sassar int s; 13072445Sassar pid_t pid; 13172445Sassar krb5_address addr; 13272445Sassar char buf[128]; 13372445Sassar size_t buf_len; 13472445Sassar 13572445Sassar s = accept(socks[this_sock], sa, &sa_size); 13672445Sassar if(s < 0) { 13772445Sassar krb5_warn(context, errno, "accept"); 13872445Sassar return 1; 13972445Sassar } 14072445Sassar e = krb5_sockaddr2address(sa, &addr); 14172445Sassar if(e) 14272445Sassar krb5_warn(context, e, "krb5_sockaddr2address"); 14372445Sassar else { 14472445Sassar e = krb5_print_address (&addr, buf, sizeof(buf), 14572445Sassar &buf_len); 14672445Sassar if(e) 14772445Sassar krb5_warn(context, e, "krb5_sockaddr2address"); 14872445Sassar else 14972445Sassar krb5_warnx(context, "connection from %s", buf); 15072445Sassar krb5_free_address(context, &addr); 15172445Sassar } 15272445Sassar 15372445Sassar pid = fork(); 15472445Sassar if(pid == 0) { 15572445Sassar for(i = 0; i < num_socks; i++) 15672445Sassar close(socks[i]); 15772445Sassar dup2(s, STDIN_FILENO); 15872445Sassar dup2(s, STDOUT_FILENO); 15972445Sassar if(s != STDIN_FILENO && s != STDOUT_FILENO) 16072445Sassar close(s); 16172445Sassar return 0; 16272445Sassar } else { 16372445Sassar close(s); 16472445Sassar } 16572445Sassar return 1; 16672445Sassar} 16772445Sassar 16872445Sassarstatic int 16972445Sassarwait_for_connection(krb5_context context, 17072445Sassar int *socks, int num_socks) 17172445Sassar{ 17272445Sassar int i, e; 17372445Sassar fd_set orig_read_set, read_set; 17472445Sassar int max_fd = -1; 17572445Sassar 17672445Sassar FD_ZERO(&orig_read_set); 17772445Sassar 17872445Sassar for(i = 0; i < num_socks; i++) { 17972445Sassar if (socks[i] >= FD_SETSIZE) 18072445Sassar errx (1, "fd too large"); 18172445Sassar FD_SET(socks[i], &orig_read_set); 18272445Sassar max_fd = max(max_fd, socks[i]); 18372445Sassar } 18472445Sassar 18572445Sassar pgrp = getpid(); 18672445Sassar 18772445Sassar if(setpgid(0, pgrp) < 0) 18872445Sassar err(1, "setpgid"); 18972445Sassar 19072445Sassar signal(SIGTERM, terminate); 19172445Sassar signal(SIGINT, terminate); 19272445Sassar signal(SIGCHLD, sigchld); 19372445Sassar 19472445Sassar while (term_flag == 0) { 19572445Sassar read_set = orig_read_set; 19672445Sassar e = select(max_fd + 1, &read_set, NULL, NULL, NULL); 19772445Sassar if(e < 0) { 19872445Sassar if(errno != EINTR) 19972445Sassar krb5_warn(context, errno, "select"); 20072445Sassar } else if(e == 0) 20172445Sassar krb5_warnx(context, "select returned 0"); 20272445Sassar else { 20372445Sassar for(i = 0; i < num_socks; i++) { 20472445Sassar if(FD_ISSET(socks[i], &read_set)) 20572445Sassar if(spawn_child(context, socks, num_socks, i) == 0) 20672445Sassar return 0; 20772445Sassar } 20872445Sassar } 20972445Sassar } 21072445Sassar signal(SIGCHLD, SIG_IGN); 21172445Sassar while(1) { 21272445Sassar int status; 21372445Sassar pid_t pid; 21472445Sassar pid = waitpid(-1, &status, 0); 21572445Sassar if(pid == -1 && errno == ECHILD) 21672445Sassar break; 21772445Sassar } 21872445Sassar exit(0); 21972445Sassar} 22072445Sassar 22172445Sassar 22272445Sassarint 22372445Sassarstart_server(krb5_context context) 22472445Sassar{ 22572445Sassar int e; 22672445Sassar struct kadm_port *p; 22772445Sassar 22872445Sassar int *socks = NULL, *tmp; 22972445Sassar int num_socks = 0; 23072445Sassar int i; 23172445Sassar 23272445Sassar for(p = kadm_ports; p; p = p->next) { 23372445Sassar struct addrinfo hints, *ai, *ap; 23472445Sassar char portstr[32]; 23572445Sassar memset (&hints, 0, sizeof(hints)); 23672445Sassar hints.ai_flags = AI_PASSIVE; 23772445Sassar hints.ai_socktype = SOCK_STREAM; 23872445Sassar 23972445Sassar e = getaddrinfo(NULL, p->port, &hints, &ai); 24072445Sassar if(e) { 24172445Sassar snprintf(portstr, sizeof(portstr), "%u", p->def_port); 24272445Sassar e = getaddrinfo(NULL, portstr, &hints, &ai); 24372445Sassar } 24472445Sassar 24572445Sassar if(e) { 24672445Sassar krb5_warn(context, krb5_eai_to_heim_errno(e), "%s", portstr); 24772445Sassar continue; 24872445Sassar } 24972445Sassar i = 0; 25072445Sassar for(ap = ai; ap; ap = ap->ai_next) 25172445Sassar i++; 25272445Sassar tmp = realloc(socks, (num_socks + i) * sizeof(*socks)); 25372445Sassar if(tmp == NULL) { 25472445Sassar krb5_warnx(context, "failed to reallocate %lu bytes", 25572445Sassar (unsigned long)(num_socks + i) * sizeof(*socks)); 25672445Sassar continue; 25772445Sassar } 25872445Sassar socks = tmp; 25972445Sassar for(ap = ai; ap; ap = ap->ai_next) { 26072445Sassar int one = 1; 26172445Sassar int s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); 26272445Sassar if(s < 0) { 26372445Sassar krb5_warn(context, errno, "socket"); 26472445Sassar continue; 26572445Sassar } 26672445Sassar#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT) 26772445Sassar if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, 26872445Sassar sizeof(one)) < 0) 26972445Sassar krb5_warn(context, errno, "setsockopt"); 27072445Sassar#endif 27172445Sassar if (bind (s, ap->ai_addr, ap->ai_addrlen) < 0) { 27272445Sassar krb5_warn(context, errno, "bind"); 27372445Sassar close(s); 27472445Sassar continue; 27572445Sassar } 27672445Sassar if (listen (s, SOMAXCONN) < 0) { 27772445Sassar krb5_warn(context, errno, "listen"); 27872445Sassar close(s); 27972445Sassar continue; 28072445Sassar } 28172445Sassar socks[num_socks++] = s; 28272445Sassar } 28372445Sassar freeaddrinfo (ai); 28472445Sassar } 28572445Sassar if(num_socks == 0) 28672445Sassar krb5_errx(context, 1, "no sockets to listen to - exiting"); 28772445Sassar return wait_for_connection(context, socks, num_socks); 28872445Sassar} 289