Path: blob/main/crypto/heimdal/kadmin/kadm_conn.c
107846 views
/*1* Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "kadmin_locl.h"34#ifdef HAVE_SYS_WAIT_H35#include <sys/wait.h>36#endif3738struct kadm_port {39char *port;40unsigned short def_port;41struct kadm_port *next;42} *kadm_ports;4344static void45add_kadm_port(krb5_context contextp, const char *service, unsigned int port)46{47struct kadm_port *p;48p = malloc(sizeof(*p));49if(p == NULL) {50krb5_warnx(contextp, "failed to allocate %lu bytes\n",51(unsigned long)sizeof(*p));52return;53}5455p->port = strdup(service);56p->def_port = port;5758p->next = kadm_ports;59kadm_ports = p;60}6162static void63add_standard_ports (krb5_context contextp)64{65add_kadm_port(contextp, "kerberos-adm", 749);66}6768/*69* parse the set of space-delimited ports in `str' and add them.70* "+" => all the standard ones71* otherwise it's port|service[/protocol]72*/7374void75parse_ports(krb5_context contextp, const char *str)76{77char p[128];7879while(strsep_copy(&str, " \t", p, sizeof(p)) != -1) {80if(strcmp(p, "+") == 0)81add_standard_ports(contextp);82else83add_kadm_port(contextp, p, 0);84}85}8687static pid_t pgrp;88sig_atomic_t term_flag, doing_useful_work;8990static RETSIGTYPE91sigchld(int sig)92{93int status;94/*95* waitpid() is async safe. will return -1 or 0 on no more zombie96* children97*/98while ((waitpid(-1, &status, WNOHANG)) > 0)99;100SIGRETURN(0);101}102103static RETSIGTYPE104terminate(int sig)105{106if(getpid() == pgrp) {107/* parent */108term_flag = 1;109signal(sig, SIG_IGN);110killpg(pgrp, sig);111} else {112/* child */113if(doing_useful_work)114term_flag = 1;115else116exit(0);117}118SIGRETURN(0);119}120121static int122spawn_child(krb5_context contextp, int *socks,123unsigned int num_socks, int this_sock)124{125int e;126size_t i;127struct sockaddr_storage __ss;128struct sockaddr *sa = (struct sockaddr *)&__ss;129socklen_t sa_size = sizeof(__ss);130krb5_socket_t s;131pid_t pid;132krb5_address addr;133char buf[128];134size_t buf_len;135136s = accept(socks[this_sock], sa, &sa_size);137if(rk_IS_BAD_SOCKET(s)) {138krb5_warn(contextp, rk_SOCK_ERRNO, "accept");139return 1;140}141e = krb5_sockaddr2address(contextp, sa, &addr);142if(e)143krb5_warn(contextp, e, "krb5_sockaddr2address");144else {145e = krb5_print_address (&addr, buf, sizeof(buf),146&buf_len);147if(e)148krb5_warn(contextp, e, "krb5_print_address");149else150krb5_warnx(contextp, "connection from %s", buf);151krb5_free_address(contextp, &addr);152}153154pid = fork();155if(pid == 0) {156for(i = 0; i < num_socks; i++)157rk_closesocket(socks[i]);158dup2(s, STDIN_FILENO);159dup2(s, STDOUT_FILENO);160if(s != STDIN_FILENO && s != STDOUT_FILENO)161rk_closesocket(s);162return 0;163} else {164rk_closesocket(s);165}166return 1;167}168169static void170wait_for_connection(krb5_context contextp,171krb5_socket_t *socks, unsigned int num_socks)172{173unsigned int i;174int e;175fd_set orig_read_set, read_set;176int status, max_fd = -1;177178FD_ZERO(&orig_read_set);179180for(i = 0; i < num_socks; i++) {181#ifdef FD_SETSIZE182if (socks[i] >= FD_SETSIZE)183errx (1, "fd too large");184#endif185FD_SET(socks[i], &orig_read_set);186max_fd = max(max_fd, socks[i]);187}188189pgrp = getpid();190191if(setpgid(0, pgrp) < 0)192err(1, "setpgid");193194signal(SIGTERM, terminate);195signal(SIGINT, terminate);196signal(SIGCHLD, sigchld);197198while (term_flag == 0) {199read_set = orig_read_set;200e = select(max_fd + 1, &read_set, NULL, NULL, NULL);201if(rk_IS_SOCKET_ERROR(e)) {202if(rk_SOCK_ERRNO != EINTR)203krb5_warn(contextp, rk_SOCK_ERRNO, "select");204} else if(e == 0)205krb5_warnx(contextp, "select returned 0");206else {207for(i = 0; i < num_socks; i++) {208if(FD_ISSET(socks[i], &read_set))209if(spawn_child(contextp, socks, num_socks, i) == 0)210return;211}212}213}214signal(SIGCHLD, SIG_IGN);215216while ((waitpid(-1, &status, WNOHANG)) > 0)217;218219exit(0);220}221222223void224start_server(krb5_context contextp, const char *port_str)225{226int e;227struct kadm_port *p;228229krb5_socket_t *socks = NULL, *tmp;230unsigned int num_socks = 0;231int i;232233if (port_str == NULL)234port_str = "+";235236parse_ports(contextp, port_str);237238for(p = kadm_ports; p; p = p->next) {239struct addrinfo hints, *ai, *ap;240char portstr[32];241memset (&hints, 0, sizeof(hints));242hints.ai_flags = AI_PASSIVE;243hints.ai_socktype = SOCK_STREAM;244245e = getaddrinfo(NULL, p->port, &hints, &ai);246if(e) {247snprintf(portstr, sizeof(portstr), "%u", p->def_port);248e = getaddrinfo(NULL, portstr, &hints, &ai);249}250251if(e) {252krb5_warn(contextp, krb5_eai_to_heim_errno(e, errno),253"%s", portstr);254continue;255}256i = 0;257for(ap = ai; ap; ap = ap->ai_next)258i++;259tmp = realloc(socks, (num_socks + i) * sizeof(*socks));260if(tmp == NULL) {261krb5_warnx(contextp, "failed to reallocate %lu bytes",262(unsigned long)(num_socks + i) * sizeof(*socks));263continue;264}265socks = tmp;266for(ap = ai; ap; ap = ap->ai_next) {267krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);268if(rk_IS_BAD_SOCKET(s)) {269krb5_warn(contextp, rk_SOCK_ERRNO, "socket");270continue;271}272273socket_set_reuseaddr(s, 1);274socket_set_ipv6only(s, 1);275276if (rk_IS_SOCKET_ERROR(bind (s, ap->ai_addr, ap->ai_addrlen))) {277krb5_warn(contextp, rk_SOCK_ERRNO, "bind");278rk_closesocket(s);279continue;280}281if (rk_IS_SOCKET_ERROR(listen (s, SOMAXCONN))) {282krb5_warn(contextp, rk_SOCK_ERRNO, "listen");283rk_closesocket(s);284continue;285}286socks[num_socks++] = s;287}288freeaddrinfo (ai);289}290if(num_socks == 0)291krb5_errx(contextp, 1, "no sockets to listen to - exiting");292293wait_for_connection(contextp, socks, num_socks);294}295296297