2 * Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "kadmin_locl.h"
35 #ifdef HAVE_SYS_WAIT_H
39 extern int daemon_child
;
43 unsigned short def_port
;
44 struct kadm_port
*next
;
48 add_kadm_port(krb5_context contextp
, const char *service
, unsigned int port
)
51 p
= malloc(sizeof(*p
));
53 krb5_warnx(contextp
, "failed to allocate %lu bytes\n",
54 (unsigned long)sizeof(*p
));
58 p
->port
= strdup(service
);
66 add_standard_ports (krb5_context contextp
)
68 if (krb5_config_get_bool(context
, NULL
, "libdefaults", "block_dns",
70 add_kadm_port(contextp
, "749", 749);
72 add_kadm_port(contextp
, "kerberos-adm", 749);
76 * parse the set of space-delimited ports in `str' and add them.
77 * "+" => all the standard ones
78 * otherwise it's port|service[/protocol]
82 parse_ports(krb5_context contextp
, const char *str
)
86 while(strsep_copy(&str
, " \t", p
, sizeof(p
)) != -1) {
87 if(strcmp(p
, "+") == 0)
88 add_standard_ports(contextp
);
90 add_kadm_port(contextp
, p
, 0);
95 sig_atomic_t term_flag
, doing_useful_work
;
102 * waitpid() is async safe. will return -1 or 0 on no more zombie
105 while ((waitpid(-1, &status
, WNOHANG
)) > 0)
113 if(getpid() == pgrp
) {
116 signal(sig
, SIG_IGN
);
120 if(doing_useful_work
)
129 spawn_child(krb5_context contextp
, int *socks
,
130 unsigned int num_socks
, int this_sock
)
134 struct sockaddr_storage __ss
;
135 struct sockaddr
*sa
= (struct sockaddr
*)&__ss
;
136 socklen_t sa_size
= sizeof(__ss
);
143 s
= accept(socks
[this_sock
], sa
, &sa_size
);
144 if(rk_IS_BAD_SOCKET(s
)) {
145 krb5_warn(contextp
, rk_SOCK_ERRNO
, "accept");
148 e
= krb5_sockaddr2address(contextp
, sa
, &addr
);
150 krb5_warn(contextp
, e
, "krb5_sockaddr2address");
152 e
= krb5_print_address (&addr
, buf
, sizeof(buf
),
155 krb5_warn(contextp
, e
, "krb5_print_address");
157 krb5_warnx(contextp
, "connection from %s", buf
);
158 krb5_free_address(contextp
, &addr
);
163 for(i
= 0; i
< num_socks
; i
++)
164 rk_closesocket(socks
[i
]);
165 dup2(s
, STDIN_FILENO
);
166 dup2(s
, STDOUT_FILENO
);
167 if(s
!= STDIN_FILENO
&& s
!= STDOUT_FILENO
)
177 wait_for_connection(krb5_context contextp
,
178 krb5_socket_t
*socks
, unsigned int num_socks
)
182 fd_set orig_read_set
, read_set
;
183 int status
, max_fd
= -1;
185 FD_ZERO(&orig_read_set
);
187 for(i
= 0; i
< num_socks
; i
++) {
189 if (socks
[i
] >= FD_SETSIZE
)
190 errx (1, "fd too large");
192 FD_SET(socks
[i
], &orig_read_set
);
193 max_fd
= max(max_fd
, socks
[i
]);
198 /* systemd may cause setpgid to fail with EPERM */
199 if(setpgid(0, pgrp
) < 0 && errno
!= EPERM
)
202 signal(SIGTERM
, terminate
);
203 signal(SIGINT
, terminate
);
204 signal(SIGCHLD
, sigchld
);
206 while (term_flag
== 0) {
207 read_set
= orig_read_set
;
208 e
= select(max_fd
+ 1, &read_set
, NULL
, NULL
, NULL
);
209 if(rk_IS_SOCKET_ERROR(e
)) {
210 if(rk_SOCK_ERRNO
!= EINTR
)
211 krb5_warn(contextp
, rk_SOCK_ERRNO
, "select");
213 krb5_warnx(contextp
, "select returned 0");
215 for(i
= 0; i
< num_socks
; i
++) {
216 if(FD_ISSET(socks
[i
], &read_set
))
217 if(spawn_child(contextp
, socks
, num_socks
, i
) == 0)
222 signal(SIGCHLD
, SIG_IGN
);
224 while ((waitpid(-1, &status
, WNOHANG
)) > 0)
232 start_server(krb5_context contextp
, const char *port_str
)
237 krb5_socket_t
*socks
= NULL
, *tmp
;
238 unsigned int num_socks
= 0;
241 if (port_str
== NULL
)
244 parse_ports(contextp
, port_str
);
246 for(p
= kadm_ports
; p
; p
= p
->next
) {
247 struct addrinfo hints
, *ai
, *ap
;
249 memset (&hints
, 0, sizeof(hints
));
250 hints
.ai_flags
= AI_PASSIVE
;
251 hints
.ai_socktype
= SOCK_STREAM
;
253 if (krb5_config_get_bool(context
, NULL
, "libdefaults", "block_dns",
255 hints
.ai_flags
&= ~AI_CANONNAME
;
256 hints
.ai_flags
|= AI_NUMERICHOST
|AI_NUMERICSERV
;
258 e
= getaddrinfo(NULL
, p
->port
, &hints
, &ai
);
260 snprintf(portstr
, sizeof(portstr
), "%u", p
->def_port
);
261 e
= getaddrinfo(NULL
, portstr
, &hints
, &ai
);
265 krb5_warn(contextp
, krb5_eai_to_heim_errno(e
, errno
),
270 for(ap
= ai
; ap
; ap
= ap
->ai_next
)
272 tmp
= realloc(socks
, (num_socks
+ i
) * sizeof(*socks
));
274 krb5_err(contextp
, 1, errno
, "failed to reallocate %lu bytes",
275 (unsigned long)(num_socks
+ i
) * sizeof(*socks
));
277 for(ap
= ai
; ap
; ap
= ap
->ai_next
) {
278 krb5_socket_t s
= socket(ap
->ai_family
, ap
->ai_socktype
, ap
->ai_protocol
);
279 if(rk_IS_BAD_SOCKET(s
)) {
280 krb5_warn(contextp
, rk_SOCK_ERRNO
, "socket");
284 socket_set_reuseaddr(s
, 1);
285 socket_set_ipv6only(s
, 1);
287 if (rk_IS_SOCKET_ERROR(bind (s
, ap
->ai_addr
, ap
->ai_addrlen
))) {
288 krb5_warn(contextp
, rk_SOCK_ERRNO
, "bind");
292 if (rk_IS_SOCKET_ERROR(listen (s
, SOMAXCONN
))) {
293 krb5_warn(contextp
, rk_SOCK_ERRNO
, "listen");
298 socket_set_keepalive(s
, 1);
299 socks
[num_socks
++] = s
;
304 krb5_errx(contextp
, 1, "no sockets to listen to - exiting");
306 roken_detach_finish(NULL
, daemon_child
);
308 wait_for_connection(contextp
, socks
, num_socks
);