Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/kadmin/kadm_conn.c
34883 views
1
/*
2
* Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
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.
16
*
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.
20
*
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
31
* SUCH DAMAGE.
32
*/
33
34
#include "kadmin_locl.h"
35
#ifdef HAVE_SYS_WAIT_H
36
#include <sys/wait.h>
37
#endif
38
39
struct kadm_port {
40
char *port;
41
unsigned short def_port;
42
struct kadm_port *next;
43
} *kadm_ports;
44
45
static void
46
add_kadm_port(krb5_context contextp, const char *service, unsigned int port)
47
{
48
struct kadm_port *p;
49
p = malloc(sizeof(*p));
50
if(p == NULL) {
51
krb5_warnx(contextp, "failed to allocate %lu bytes\n",
52
(unsigned long)sizeof(*p));
53
return;
54
}
55
56
p->port = strdup(service);
57
p->def_port = port;
58
59
p->next = kadm_ports;
60
kadm_ports = p;
61
}
62
63
static void
64
add_standard_ports (krb5_context contextp)
65
{
66
add_kadm_port(contextp, "kerberos-adm", 749);
67
}
68
69
/*
70
* parse the set of space-delimited ports in `str' and add them.
71
* "+" => all the standard ones
72
* otherwise it's port|service[/protocol]
73
*/
74
75
void
76
parse_ports(krb5_context contextp, const char *str)
77
{
78
char p[128];
79
80
while(strsep_copy(&str, " \t", p, sizeof(p)) != -1) {
81
if(strcmp(p, "+") == 0)
82
add_standard_ports(contextp);
83
else
84
add_kadm_port(contextp, p, 0);
85
}
86
}
87
88
static pid_t pgrp;
89
sig_atomic_t term_flag, doing_useful_work;
90
91
static RETSIGTYPE
92
sigchld(int sig)
93
{
94
int status;
95
/*
96
* waitpid() is async safe. will return -1 or 0 on no more zombie
97
* children
98
*/
99
while ((waitpid(-1, &status, WNOHANG)) > 0)
100
;
101
SIGRETURN(0);
102
}
103
104
static RETSIGTYPE
105
terminate(int sig)
106
{
107
if(getpid() == pgrp) {
108
/* parent */
109
term_flag = 1;
110
signal(sig, SIG_IGN);
111
killpg(pgrp, sig);
112
} else {
113
/* child */
114
if(doing_useful_work)
115
term_flag = 1;
116
else
117
exit(0);
118
}
119
SIGRETURN(0);
120
}
121
122
static int
123
spawn_child(krb5_context contextp, int *socks,
124
unsigned int num_socks, int this_sock)
125
{
126
int e;
127
size_t i;
128
struct sockaddr_storage __ss;
129
struct sockaddr *sa = (struct sockaddr *)&__ss;
130
socklen_t sa_size = sizeof(__ss);
131
krb5_socket_t s;
132
pid_t pid;
133
krb5_address addr;
134
char buf[128];
135
size_t buf_len;
136
137
s = accept(socks[this_sock], sa, &sa_size);
138
if(rk_IS_BAD_SOCKET(s)) {
139
krb5_warn(contextp, rk_SOCK_ERRNO, "accept");
140
return 1;
141
}
142
e = krb5_sockaddr2address(contextp, sa, &addr);
143
if(e)
144
krb5_warn(contextp, e, "krb5_sockaddr2address");
145
else {
146
e = krb5_print_address (&addr, buf, sizeof(buf),
147
&buf_len);
148
if(e)
149
krb5_warn(contextp, e, "krb5_print_address");
150
else
151
krb5_warnx(contextp, "connection from %s", buf);
152
krb5_free_address(contextp, &addr);
153
}
154
155
pid = fork();
156
if(pid == 0) {
157
for(i = 0; i < num_socks; i++)
158
rk_closesocket(socks[i]);
159
dup2(s, STDIN_FILENO);
160
dup2(s, STDOUT_FILENO);
161
if(s != STDIN_FILENO && s != STDOUT_FILENO)
162
rk_closesocket(s);
163
return 0;
164
} else {
165
rk_closesocket(s);
166
}
167
return 1;
168
}
169
170
static void
171
wait_for_connection(krb5_context contextp,
172
krb5_socket_t *socks, unsigned int num_socks)
173
{
174
unsigned int i;
175
int e;
176
fd_set orig_read_set, read_set;
177
int status, max_fd = -1;
178
179
FD_ZERO(&orig_read_set);
180
181
for(i = 0; i < num_socks; i++) {
182
#ifdef FD_SETSIZE
183
if (socks[i] >= FD_SETSIZE)
184
errx (1, "fd too large");
185
#endif
186
FD_SET(socks[i], &orig_read_set);
187
max_fd = max(max_fd, socks[i]);
188
}
189
190
pgrp = getpid();
191
192
if(setpgid(0, pgrp) < 0)
193
err(1, "setpgid");
194
195
signal(SIGTERM, terminate);
196
signal(SIGINT, terminate);
197
signal(SIGCHLD, sigchld);
198
199
while (term_flag == 0) {
200
read_set = orig_read_set;
201
e = select(max_fd + 1, &read_set, NULL, NULL, NULL);
202
if(rk_IS_SOCKET_ERROR(e)) {
203
if(rk_SOCK_ERRNO != EINTR)
204
krb5_warn(contextp, rk_SOCK_ERRNO, "select");
205
} else if(e == 0)
206
krb5_warnx(contextp, "select returned 0");
207
else {
208
for(i = 0; i < num_socks; i++) {
209
if(FD_ISSET(socks[i], &read_set))
210
if(spawn_child(contextp, socks, num_socks, i) == 0)
211
return;
212
}
213
}
214
}
215
signal(SIGCHLD, SIG_IGN);
216
217
while ((waitpid(-1, &status, WNOHANG)) > 0)
218
;
219
220
exit(0);
221
}
222
223
224
void
225
start_server(krb5_context contextp, const char *port_str)
226
{
227
int e;
228
struct kadm_port *p;
229
230
krb5_socket_t *socks = NULL, *tmp;
231
unsigned int num_socks = 0;
232
int i;
233
234
if (port_str == NULL)
235
port_str = "+";
236
237
parse_ports(contextp, port_str);
238
239
for(p = kadm_ports; p; p = p->next) {
240
struct addrinfo hints, *ai, *ap;
241
char portstr[32];
242
memset (&hints, 0, sizeof(hints));
243
hints.ai_flags = AI_PASSIVE;
244
hints.ai_socktype = SOCK_STREAM;
245
246
e = getaddrinfo(NULL, p->port, &hints, &ai);
247
if(e) {
248
snprintf(portstr, sizeof(portstr), "%u", p->def_port);
249
e = getaddrinfo(NULL, portstr, &hints, &ai);
250
}
251
252
if(e) {
253
krb5_warn(contextp, krb5_eai_to_heim_errno(e, errno),
254
"%s", portstr);
255
continue;
256
}
257
i = 0;
258
for(ap = ai; ap; ap = ap->ai_next)
259
i++;
260
tmp = realloc(socks, (num_socks + i) * sizeof(*socks));
261
if(tmp == NULL) {
262
krb5_warnx(contextp, "failed to reallocate %lu bytes",
263
(unsigned long)(num_socks + i) * sizeof(*socks));
264
continue;
265
}
266
socks = tmp;
267
for(ap = ai; ap; ap = ap->ai_next) {
268
krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
269
if(rk_IS_BAD_SOCKET(s)) {
270
krb5_warn(contextp, rk_SOCK_ERRNO, "socket");
271
continue;
272
}
273
274
socket_set_reuseaddr(s, 1);
275
socket_set_ipv6only(s, 1);
276
277
if (rk_IS_SOCKET_ERROR(bind (s, ap->ai_addr, ap->ai_addrlen))) {
278
krb5_warn(contextp, rk_SOCK_ERRNO, "bind");
279
rk_closesocket(s);
280
continue;
281
}
282
if (rk_IS_SOCKET_ERROR(listen (s, SOMAXCONN))) {
283
krb5_warn(contextp, rk_SOCK_ERRNO, "listen");
284
rk_closesocket(s);
285
continue;
286
}
287
socks[num_socks++] = s;
288
}
289
freeaddrinfo (ai);
290
}
291
if(num_socks == 0)
292
krb5_errx(contextp, 1, "no sockets to listen to - exiting");
293
294
wait_for_connection(contextp, socks, num_socks);
295
}
296
297