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