Deleted Added
full compact
connect.c (57419) connect.c (57422)
1/*
2 * Copyright (c) 1997-2000 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 "kdc_locl.h"
35
1/*
2 * Copyright (c) 1997-2000 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 "kdc_locl.h"
35
36RCSID("$Id: connect.c,v 1.69 2000/02/11 17:45:45 assar Exp $");
36RCSID("$Id: connect.c,v 1.70 2000/02/19 18:41:24 assar Exp $");
37
38/*
39 * a tuple describing on what to listen
40 */
41
42struct port_desc{
43 int family;
44 int type;
45 int port;
46};
47
48/* the current ones */
49
50static struct port_desc *ports;
51static int num_ports;
52
53/*
54 * add `family, port, protocol' to the list with duplicate suppresion.
55 */
56
57static void
58add_port(int family, int port, const char *protocol)
59{
60 int type;
61 int i;
62
63 if(strcmp(protocol, "udp") == 0)
64 type = SOCK_DGRAM;
65 else if(strcmp(protocol, "tcp") == 0)
66 type = SOCK_STREAM;
67 else
68 return;
69 for(i = 0; i < num_ports; i++){
70 if(ports[i].type == type
71 && ports[i].port == port
72 && ports[i].family == family)
73 return;
74 }
75 ports = realloc(ports, (num_ports + 1) * sizeof(*ports));
76 if (ports == NULL)
77 krb5_err (context, 1, errno, "realloc");
78 ports[num_ports].family = family;
79 ports[num_ports].type = type;
80 ports[num_ports].port = port;
81 num_ports++;
82}
83
84/*
85 * add a triple but with service -> port lookup
86 * (this prints warnings for stuff that does not exist)
87 */
88
89static void
90add_port_service(int family, const char *service, int port,
91 const char *protocol)
92{
93 port = krb5_getportbyname (context, service, protocol, port);
94 add_port (family, port, protocol);
95}
96
97/*
98 * add the port with service -> port lookup or string -> number
99 * (no warning is printed)
100 */
101
102static void
103add_port_string (int family, const char *port_str, const char *protocol)
104{
105 struct servent *sp;
106 int port;
107
108 sp = roken_getservbyname (port_str, protocol);
109 if (sp != NULL) {
110 port = sp->s_port;
111 } else {
112 char *end;
113
114 port = htons(strtol(port_str, &end, 0));
115 if (end == port_str)
116 return;
117 }
118 add_port (family, port, protocol);
119}
120
121/*
122 * add the standard collection of ports for `family'
123 */
124
125static void
126add_standard_ports (int family)
127{
128 add_port_service(family, "kerberos", 88, "udp");
129 add_port_service(family, "kerberos", 88, "tcp");
130 add_port_service(family, "kerberos-sec", 88, "udp");
131 add_port_service(family, "kerberos-sec", 88, "tcp");
132 add_port_service(family, "kerberos-iv", 750, "udp");
133 add_port_service(family, "kerberos-iv", 750, "tcp");
134 if(enable_http)
135 add_port_service(family, "http", 80, "tcp");
136#ifdef KASERVER
137 if (enable_kaserver)
138 add_port_service(family, "afs3-kaserver", 7004, "udp");
139#endif
140}
141
142/*
143 * parse the set of space-delimited ports in `str' and add them.
144 * "+" => all the standard ones
145 * otherwise it's port|service[/protocol]
146 */
147
148static void
149parse_ports(const char *str)
150{
151 char *pos = NULL;
152 char *p;
153 char *str_copy = strdup (str);
154
155 p = strtok_r(str_copy, " \t", &pos);
156 while(p != NULL) {
157 if(strcmp(p, "+") == 0) {
158#ifdef HAVE_IPV6
159 add_standard_ports(AF_INET6);
160#endif
161 add_standard_ports(AF_INET);
162 } else {
163 char *q = strchr(p, '/');
164 if(q){
165 *q++ = 0;
166#ifdef HAVE_IPV6
167 add_port_string(AF_INET6, p, q);
168#endif
169 add_port_string(AF_INET, p, q);
170 }else {
171#ifdef HAVE_IPV6
172 add_port_string(AF_INET6, p, "udp");
173 add_port_string(AF_INET6, p, "tcp");
174#endif
175 add_port_string(AF_INET, p, "udp");
176 add_port_string(AF_INET, p, "tcp");
177 }
178 }
179
180 p = strtok_r(NULL, " \t", &pos);
181 }
182 free (str_copy);
183}
184
185/*
186 * every socket we listen on
187 */
188
189struct descr {
190 int s;
191 int type;
192 unsigned char *buf;
193 size_t size;
194 size_t len;
195 time_t timeout;
37
38/*
39 * a tuple describing on what to listen
40 */
41
42struct port_desc{
43 int family;
44 int type;
45 int port;
46};
47
48/* the current ones */
49
50static struct port_desc *ports;
51static int num_ports;
52
53/*
54 * add `family, port, protocol' to the list with duplicate suppresion.
55 */
56
57static void
58add_port(int family, int port, const char *protocol)
59{
60 int type;
61 int i;
62
63 if(strcmp(protocol, "udp") == 0)
64 type = SOCK_DGRAM;
65 else if(strcmp(protocol, "tcp") == 0)
66 type = SOCK_STREAM;
67 else
68 return;
69 for(i = 0; i < num_ports; i++){
70 if(ports[i].type == type
71 && ports[i].port == port
72 && ports[i].family == family)
73 return;
74 }
75 ports = realloc(ports, (num_ports + 1) * sizeof(*ports));
76 if (ports == NULL)
77 krb5_err (context, 1, errno, "realloc");
78 ports[num_ports].family = family;
79 ports[num_ports].type = type;
80 ports[num_ports].port = port;
81 num_ports++;
82}
83
84/*
85 * add a triple but with service -> port lookup
86 * (this prints warnings for stuff that does not exist)
87 */
88
89static void
90add_port_service(int family, const char *service, int port,
91 const char *protocol)
92{
93 port = krb5_getportbyname (context, service, protocol, port);
94 add_port (family, port, protocol);
95}
96
97/*
98 * add the port with service -> port lookup or string -> number
99 * (no warning is printed)
100 */
101
102static void
103add_port_string (int family, const char *port_str, const char *protocol)
104{
105 struct servent *sp;
106 int port;
107
108 sp = roken_getservbyname (port_str, protocol);
109 if (sp != NULL) {
110 port = sp->s_port;
111 } else {
112 char *end;
113
114 port = htons(strtol(port_str, &end, 0));
115 if (end == port_str)
116 return;
117 }
118 add_port (family, port, protocol);
119}
120
121/*
122 * add the standard collection of ports for `family'
123 */
124
125static void
126add_standard_ports (int family)
127{
128 add_port_service(family, "kerberos", 88, "udp");
129 add_port_service(family, "kerberos", 88, "tcp");
130 add_port_service(family, "kerberos-sec", 88, "udp");
131 add_port_service(family, "kerberos-sec", 88, "tcp");
132 add_port_service(family, "kerberos-iv", 750, "udp");
133 add_port_service(family, "kerberos-iv", 750, "tcp");
134 if(enable_http)
135 add_port_service(family, "http", 80, "tcp");
136#ifdef KASERVER
137 if (enable_kaserver)
138 add_port_service(family, "afs3-kaserver", 7004, "udp");
139#endif
140}
141
142/*
143 * parse the set of space-delimited ports in `str' and add them.
144 * "+" => all the standard ones
145 * otherwise it's port|service[/protocol]
146 */
147
148static void
149parse_ports(const char *str)
150{
151 char *pos = NULL;
152 char *p;
153 char *str_copy = strdup (str);
154
155 p = strtok_r(str_copy, " \t", &pos);
156 while(p != NULL) {
157 if(strcmp(p, "+") == 0) {
158#ifdef HAVE_IPV6
159 add_standard_ports(AF_INET6);
160#endif
161 add_standard_ports(AF_INET);
162 } else {
163 char *q = strchr(p, '/');
164 if(q){
165 *q++ = 0;
166#ifdef HAVE_IPV6
167 add_port_string(AF_INET6, p, q);
168#endif
169 add_port_string(AF_INET, p, q);
170 }else {
171#ifdef HAVE_IPV6
172 add_port_string(AF_INET6, p, "udp");
173 add_port_string(AF_INET6, p, "tcp");
174#endif
175 add_port_string(AF_INET, p, "udp");
176 add_port_string(AF_INET, p, "tcp");
177 }
178 }
179
180 p = strtok_r(NULL, " \t", &pos);
181 }
182 free (str_copy);
183}
184
185/*
186 * every socket we listen on
187 */
188
189struct descr {
190 int s;
191 int type;
192 unsigned char *buf;
193 size_t size;
194 size_t len;
195 time_t timeout;
196 struct sockaddr_storage __ss;
197 struct sockaddr *sa;
198 int sock_len;
199 char addr_string[128];
196};
197
198/*
199 * Create the socket (family, type, port) in `d'
200 */
201
202static void
203init_socket(struct descr *d, krb5_address *a, int family, int type, int port)
204{
205 krb5_error_code ret;
206 struct sockaddr_storage __ss;
207 struct sockaddr *sa = (struct sockaddr *)&__ss;
208 int sa_size;
209
210 memset(d, 0, sizeof(*d));
200};
201
202/*
203 * Create the socket (family, type, port) in `d'
204 */
205
206static void
207init_socket(struct descr *d, krb5_address *a, int family, int type, int port)
208{
209 krb5_error_code ret;
210 struct sockaddr_storage __ss;
211 struct sockaddr *sa = (struct sockaddr *)&__ss;
212 int sa_size;
213
214 memset(d, 0, sizeof(*d));
215 d->sa = (struct sockaddr *)&d->__ss;
211 d->s = -1;
212
213 ret = krb5_addr2sockaddr (a, sa, &sa_size, port);
214 if (ret) {
215 krb5_warn(context, ret, "krb5_addr2sockaddr");
216 close(d->s);
217 d->s = -1;
218 return;
219 }
220
221 if (sa->sa_family != family)
222 return;
223
224 d->s = socket(family, type, 0);
225 if(d->s < 0){
226 krb5_warn(context, errno, "socket(%d, %d, 0)", family, type);
227 d->s = -1;
228 return;
229 }
230#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR)
231 {
232 int one = 1;
233 setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
234 }
235#endif
236 d->type = type;
237
238 if(bind(d->s, sa, sa_size) < 0){
239 char a_str[256];
240 size_t len;
241
242 krb5_print_address (a, a_str, sizeof(a_str), &len);
243 krb5_warn(context, errno, "bind %s/%d", a_str, ntohs(port));
244 close(d->s);
245 d->s = -1;
246 return;
247 }
248 if(type == SOCK_STREAM && listen(d->s, SOMAXCONN) < 0){
249 char a_str[256];
250 size_t len;
251
252 krb5_print_address (a, a_str, sizeof(a_str), &len);
253 krb5_warn(context, errno, "listen %s/%d", a_str, ntohs(port));
254 close(d->s);
255 d->s = -1;
256 return;
257 }
258}
259
260/*
261 * Allocate descriptors for all the sockets that we should listen on
262 * and return the number of them.
263 */
264
265static int
266init_sockets(struct descr **desc)
267{
268 krb5_error_code ret;
269 int i, j;
270 struct descr *d;
271 int num = 0;
272 krb5_addresses addresses;
273
274 if (explicit_addresses.len) {
275 addresses = explicit_addresses;
276 } else {
277 ret = krb5_get_all_server_addrs (context, &addresses);
278 if (ret)
279 krb5_err (context, 1, ret, "krb5_get_all_server_addrs");
280 }
281 parse_ports(port_str);
282 d = malloc(addresses.len * num_ports * sizeof(*d));
283 if (d == NULL)
284 krb5_errx(context, 1, "malloc(%u) failed", num_ports * sizeof(*d));
285
286 for (i = 0; i < num_ports; i++){
287 for (j = 0; j < addresses.len; ++j) {
288 init_socket(&d[num], &addresses.val[j],
289 ports[i].family, ports[i].type, ports[i].port);
290 if(d[num].s != -1){
291 char a_str[80];
292 size_t len;
293
294 krb5_print_address (&addresses.val[j], a_str,
295 sizeof(a_str), &len);
296
297 kdc_log(5, "listening on %s port %u/%s",
298 a_str,
299 ntohs(ports[i].port),
300 (ports[i].type == SOCK_STREAM) ? "tcp" : "udp");
301 /* XXX */
302 num++;
303 }
304 }
305 }
306 krb5_free_addresses (context, &addresses);
307 d = realloc(d, num * sizeof(*d));
308 if (d == NULL && num != 0)
309 krb5_errx(context, 1, "realloc(%u) failed", num * sizeof(*d));
310 *desc = d;
311 return num;
312}
313
314/*
315 * handle the request in `buf, len', from `addr' (or `from' as a string),
316 * sending a reply in `reply'.
317 */
318
319static int
320process_request(unsigned char *buf,
321 size_t len,
322 krb5_data *reply,
323 int *sendlength,
324 const char *from,
325 struct sockaddr *addr)
326{
327 KDC_REQ req;
328#ifdef KRB4
329 Ticket ticket;
330#endif
331 krb5_error_code ret;
332 size_t i;
333
334 gettimeofday(&now, NULL);
335 if(decode_AS_REQ(buf, len, &req, &i) == 0){
336 ret = as_rep(&req, reply, from, addr);
337 free_AS_REQ(&req);
338 return ret;
339 }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
340 ret = tgs_rep(&req, reply, from, addr);
341 free_TGS_REQ(&req);
342 return ret;
343 }
344#ifdef KRB4
345 else if(maybe_version4(buf, len)){
346 *sendlength = 0; /* elbitapmoc sdrawkcab XXX */
347 do_version4(buf, len, reply, from, (struct sockaddr_in*)addr);
348 return 0;
349 }else if(decode_Ticket(buf, len, &ticket, &i) == 0){
350 ret = do_524(&ticket, reply, from, addr);
351 free_Ticket(&ticket);
352 return ret;
353 }
354#endif
355#ifdef KASERVER
356 else if (enable_kaserver) {
357 ret = do_kaserver (buf, len, reply, from, (struct sockaddr_in*)addr);
358 return ret;
359 }
360#endif
361
362 return -1;
363}
364
365static void
366addr_to_string(struct sockaddr *addr, size_t addr_len, char *str, size_t len)
367{
368 krb5_address a;
369 krb5_sockaddr2address(addr, &a);
370 if(krb5_print_address(&a, str, len, &len) == 0) {
371 krb5_free_address(context, &a);
372 return;
373 }
374 krb5_free_address(context, &a);
375 snprintf(str, len, "<family=%d>", addr->sa_family);
376}
377
216 d->s = -1;
217
218 ret = krb5_addr2sockaddr (a, sa, &sa_size, port);
219 if (ret) {
220 krb5_warn(context, ret, "krb5_addr2sockaddr");
221 close(d->s);
222 d->s = -1;
223 return;
224 }
225
226 if (sa->sa_family != family)
227 return;
228
229 d->s = socket(family, type, 0);
230 if(d->s < 0){
231 krb5_warn(context, errno, "socket(%d, %d, 0)", family, type);
232 d->s = -1;
233 return;
234 }
235#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR)
236 {
237 int one = 1;
238 setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
239 }
240#endif
241 d->type = type;
242
243 if(bind(d->s, sa, sa_size) < 0){
244 char a_str[256];
245 size_t len;
246
247 krb5_print_address (a, a_str, sizeof(a_str), &len);
248 krb5_warn(context, errno, "bind %s/%d", a_str, ntohs(port));
249 close(d->s);
250 d->s = -1;
251 return;
252 }
253 if(type == SOCK_STREAM && listen(d->s, SOMAXCONN) < 0){
254 char a_str[256];
255 size_t len;
256
257 krb5_print_address (a, a_str, sizeof(a_str), &len);
258 krb5_warn(context, errno, "listen %s/%d", a_str, ntohs(port));
259 close(d->s);
260 d->s = -1;
261 return;
262 }
263}
264
265/*
266 * Allocate descriptors for all the sockets that we should listen on
267 * and return the number of them.
268 */
269
270static int
271init_sockets(struct descr **desc)
272{
273 krb5_error_code ret;
274 int i, j;
275 struct descr *d;
276 int num = 0;
277 krb5_addresses addresses;
278
279 if (explicit_addresses.len) {
280 addresses = explicit_addresses;
281 } else {
282 ret = krb5_get_all_server_addrs (context, &addresses);
283 if (ret)
284 krb5_err (context, 1, ret, "krb5_get_all_server_addrs");
285 }
286 parse_ports(port_str);
287 d = malloc(addresses.len * num_ports * sizeof(*d));
288 if (d == NULL)
289 krb5_errx(context, 1, "malloc(%u) failed", num_ports * sizeof(*d));
290
291 for (i = 0; i < num_ports; i++){
292 for (j = 0; j < addresses.len; ++j) {
293 init_socket(&d[num], &addresses.val[j],
294 ports[i].family, ports[i].type, ports[i].port);
295 if(d[num].s != -1){
296 char a_str[80];
297 size_t len;
298
299 krb5_print_address (&addresses.val[j], a_str,
300 sizeof(a_str), &len);
301
302 kdc_log(5, "listening on %s port %u/%s",
303 a_str,
304 ntohs(ports[i].port),
305 (ports[i].type == SOCK_STREAM) ? "tcp" : "udp");
306 /* XXX */
307 num++;
308 }
309 }
310 }
311 krb5_free_addresses (context, &addresses);
312 d = realloc(d, num * sizeof(*d));
313 if (d == NULL && num != 0)
314 krb5_errx(context, 1, "realloc(%u) failed", num * sizeof(*d));
315 *desc = d;
316 return num;
317}
318
319/*
320 * handle the request in `buf, len', from `addr' (or `from' as a string),
321 * sending a reply in `reply'.
322 */
323
324static int
325process_request(unsigned char *buf,
326 size_t len,
327 krb5_data *reply,
328 int *sendlength,
329 const char *from,
330 struct sockaddr *addr)
331{
332 KDC_REQ req;
333#ifdef KRB4
334 Ticket ticket;
335#endif
336 krb5_error_code ret;
337 size_t i;
338
339 gettimeofday(&now, NULL);
340 if(decode_AS_REQ(buf, len, &req, &i) == 0){
341 ret = as_rep(&req, reply, from, addr);
342 free_AS_REQ(&req);
343 return ret;
344 }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
345 ret = tgs_rep(&req, reply, from, addr);
346 free_TGS_REQ(&req);
347 return ret;
348 }
349#ifdef KRB4
350 else if(maybe_version4(buf, len)){
351 *sendlength = 0; /* elbitapmoc sdrawkcab XXX */
352 do_version4(buf, len, reply, from, (struct sockaddr_in*)addr);
353 return 0;
354 }else if(decode_Ticket(buf, len, &ticket, &i) == 0){
355 ret = do_524(&ticket, reply, from, addr);
356 free_Ticket(&ticket);
357 return ret;
358 }
359#endif
360#ifdef KASERVER
361 else if (enable_kaserver) {
362 ret = do_kaserver (buf, len, reply, from, (struct sockaddr_in*)addr);
363 return ret;
364 }
365#endif
366
367 return -1;
368}
369
370static void
371addr_to_string(struct sockaddr *addr, size_t addr_len, char *str, size_t len)
372{
373 krb5_address a;
374 krb5_sockaddr2address(addr, &a);
375 if(krb5_print_address(&a, str, len, &len) == 0) {
376 krb5_free_address(context, &a);
377 return;
378 }
379 krb5_free_address(context, &a);
380 snprintf(str, len, "<family=%d>", addr->sa_family);
381}
382
383/*
384 * Handle the request in `buf, len' to socket `d'
385 */
386
378static void
379do_request(void *buf, size_t len, int sendlength,
387static void
388do_request(void *buf, size_t len, int sendlength,
380 int socket, struct sockaddr *from, size_t from_len)
389 struct descr *d)
381{
382 krb5_error_code ret;
383 krb5_data reply;
390{
391 krb5_error_code ret;
392 krb5_data reply;
384 char addr[128];
385
393
386 addr_to_string(from, from_len, addr, sizeof(addr));
387
388 reply.length = 0;
394 reply.length = 0;
389 ret = process_request(buf, len, &reply, &sendlength, addr, from);
395 ret = process_request(buf, len, &reply, &sendlength,
396 d->addr_string, d->sa);
390 if(reply.length){
397 if(reply.length){
391 kdc_log(5, "sending %d bytes to %s", reply.length, addr);
398 kdc_log(5, "sending %d bytes to %s", reply.length, d->addr_string);
392 if(sendlength){
393 unsigned char len[4];
394 len[0] = (reply.length >> 24) & 0xff;
395 len[1] = (reply.length >> 16) & 0xff;
396 len[2] = (reply.length >> 8) & 0xff;
397 len[3] = reply.length & 0xff;
399 if(sendlength){
400 unsigned char len[4];
401 len[0] = (reply.length >> 24) & 0xff;
402 len[1] = (reply.length >> 16) & 0xff;
403 len[2] = (reply.length >> 8) & 0xff;
404 len[3] = reply.length & 0xff;
398 if(sendto(socket, len, sizeof(len), 0, from, from_len) < 0) {
399 kdc_log (0, "sendto(%s): %s", addr, strerror(errno));
405 if(sendto(d->s, len, sizeof(len), 0, d->sa, d->sock_len) < 0) {
406 kdc_log (0, "sendto(%s): %s", d->addr_string, strerror(errno));
400 krb5_data_free(&reply);
401 return;
402 }
403 }
407 krb5_data_free(&reply);
408 return;
409 }
410 }
404 if(sendto(socket, reply.data, reply.length, 0, from, from_len) < 0) {
405 kdc_log (0, "sendto(%s): %s", addr, strerror(errno));
411 if(sendto(d->s, reply.data, reply.length, 0, d->sa, d->sock_len) < 0) {
412 kdc_log (0, "sendto(%s): %s", d->addr_string, strerror(errno));
406 krb5_data_free(&reply);
407 return;
408 }
409 krb5_data_free(&reply);
410 }
411 if(ret)
412 kdc_log(0, "Failed processing %lu byte request from %s",
413 krb5_data_free(&reply);
414 return;
415 }
416 krb5_data_free(&reply);
417 }
418 if(ret)
419 kdc_log(0, "Failed processing %lu byte request from %s",
413 (unsigned long)len, addr);
420 (unsigned long)len, d->addr_string);
414}
415
421}
422
423/*
424 * Handle incoming data to the UDP socket in `d'
425 */
426
416static void
417handle_udp(struct descr *d)
418{
419 unsigned char *buf;
427static void
428handle_udp(struct descr *d)
429{
430 unsigned char *buf;
420 struct sockaddr_storage __ss;
421 struct sockaddr *sa = (struct sockaddr *)&__ss;
422 int from_len;
423 int n;
424
425 buf = malloc(max_request);
426 if(buf == NULL){
427 kdc_log(0, "Failed to allocate %u bytes", max_request);
428 return;
429 }
430
431 int n;
432
433 buf = malloc(max_request);
434 if(buf == NULL){
435 kdc_log(0, "Failed to allocate %u bytes", max_request);
436 return;
437 }
438
431 from_len = sizeof(__ss);
432 n = recvfrom(d->s, buf, max_request, 0,
433 sa, &from_len);
434 if(n < 0){
439 d->sock_len = sizeof(d->__ss);
440 n = recvfrom(d->s, buf, max_request, 0, d->sa, &d->sock_len);
441 if(n < 0)
435 krb5_warn(context, errno, "recvfrom");
442 krb5_warn(context, errno, "recvfrom");
436 goto out;
443 else {
444 addr_to_string (d->sa, d->sock_len,
445 d->addr_string, sizeof(d->addr_string));
446 do_request(buf, n, 0, d);
437 }
447 }
438 if(n == 0) {
439 goto out;
440 }
441 do_request(buf, n, 0, d->s, sa, from_len);
442out:
443 free (buf);
444}
445
446static void
447clear_descr(struct descr *d)
448{
449 if(d->buf)
450 memset(d->buf, 0, d->size);
451 d->len = 0;
452 if(d->s != -1)
453 close(d->s);
454 d->s = -1;
455}
456
457
458/* remove HTTP %-quoting from buf */
459static int
460de_http(char *buf)
461{
462 char *p, *q;
463 for(p = q = buf; *p; p++, q++) {
464 if(*p == '%') {
465 unsigned int x;
466 if(sscanf(p + 1, "%2x", &x) != 1)
467 return -1;
468 *q = x;
469 p += 2;
470 } else
471 *q = *p;
472 }
473 *q = '\0';
474 return 0;
475}
476
477#define TCP_TIMEOUT 4
478
479/*
480 * accept a new TCP connection on `d[index]'
481 */
482
483static void
484add_new_tcp (struct descr *d, int index, int min_free)
485{
448 free (buf);
449}
450
451static void
452clear_descr(struct descr *d)
453{
454 if(d->buf)
455 memset(d->buf, 0, d->size);
456 d->len = 0;
457 if(d->s != -1)
458 close(d->s);
459 d->s = -1;
460}
461
462
463/* remove HTTP %-quoting from buf */
464static int
465de_http(char *buf)
466{
467 char *p, *q;
468 for(p = q = buf; *p; p++, q++) {
469 if(*p == '%') {
470 unsigned int x;
471 if(sscanf(p + 1, "%2x", &x) != 1)
472 return -1;
473 *q = x;
474 p += 2;
475 } else
476 *q = *p;
477 }
478 *q = '\0';
479 return 0;
480}
481
482#define TCP_TIMEOUT 4
483
484/*
485 * accept a new TCP connection on `d[index]'
486 */
487
488static void
489add_new_tcp (struct descr *d, int index, int min_free)
490{
486 struct sockaddr_storage __ss;
487 struct sockaddr *sa = (struct sockaddr *)&__ss;
488 int s;
491 int s;
489 int from_len;
490
492
491 from_len = sizeof(__ss);
492 s = accept(d[index].s, sa, &from_len);
493 if(s < 0){
493 d->sock_len = sizeof(d->__ss);
494 s = accept(d[index].s, d->sa, &d->sock_len);
495 if(s < 0) {
494 krb5_warn(context, errno, "accept");
495 return;
496 }
497 if(min_free == -1){
498 close(s);
499 return;
500 }
501
502 d[min_free].s = s;
503 d[min_free].timeout = time(NULL) + TCP_TIMEOUT;
504 d[min_free].type = SOCK_STREAM;
496 krb5_warn(context, errno, "accept");
497 return;
498 }
499 if(min_free == -1){
500 close(s);
501 return;
502 }
503
504 d[min_free].s = s;
505 d[min_free].timeout = time(NULL) + TCP_TIMEOUT;
506 d[min_free].type = SOCK_STREAM;
507 addr_to_string (d[min_free].sa, d[min_free].sock_len,
508 d[min_free].addr_string, sizeof(d[min_free].addr_string));
505}
506
507/*
508 * Grow `d' to handle at least `n'.
509 * Return != 0 if fails
510 */
511
512static int
513grow_descr (struct descr *d, size_t n)
514{
515 if (d->size - d->len < n) {
516 unsigned char *tmp;
517
518 d->size += max(1024, d->len + n);
519 if (d->size >= max_request) {
520 kdc_log(0, "Request exceeds max request size (%u bytes).",
521 d->size);
522 clear_descr(d);
523 return -1;
524 }
525 tmp = realloc (d->buf, d->size);
526 if (tmp == NULL) {
527 kdc_log(0, "Failed to re-allocate %u bytes.", d->size);
528 clear_descr(d);
529 return -1;
530 }
531 d->buf = tmp;
532 }
533 return 0;
534}
535
536/*
537 * Try to handle the TCP data at `d->buf, d->len'.
538 * Return -1 if failed, 0 if succesful, and 1 if data is complete.
539 */
540
541static int
542handle_vanilla_tcp (struct descr *d)
543{
544 krb5_storage *sp;
545 int32_t len;
546
547 sp = krb5_storage_from_mem(d->buf, d->len);
548 if (sp == NULL) {
549 kdc_log (0, "krb5_storage_from_mem failed");
550 return -1;
551 }
552 krb5_ret_int32(sp, &len);
553 krb5_storage_free(sp);
554 if(d->len - 4 >= len) {
555 memcpy(d->buf, d->buf + 4, d->len - 4);
556 return 1;
557 }
558 return 0;
559}
560
561/*
562 * Try to handle the TCP/HTTP data at `d->buf, d->len'.
563 * Return -1 if failed, 0 if succesful, and 1 if data is complete.
564 */
565
566static int
509}
510
511/*
512 * Grow `d' to handle at least `n'.
513 * Return != 0 if fails
514 */
515
516static int
517grow_descr (struct descr *d, size_t n)
518{
519 if (d->size - d->len < n) {
520 unsigned char *tmp;
521
522 d->size += max(1024, d->len + n);
523 if (d->size >= max_request) {
524 kdc_log(0, "Request exceeds max request size (%u bytes).",
525 d->size);
526 clear_descr(d);
527 return -1;
528 }
529 tmp = realloc (d->buf, d->size);
530 if (tmp == NULL) {
531 kdc_log(0, "Failed to re-allocate %u bytes.", d->size);
532 clear_descr(d);
533 return -1;
534 }
535 d->buf = tmp;
536 }
537 return 0;
538}
539
540/*
541 * Try to handle the TCP data at `d->buf, d->len'.
542 * Return -1 if failed, 0 if succesful, and 1 if data is complete.
543 */
544
545static int
546handle_vanilla_tcp (struct descr *d)
547{
548 krb5_storage *sp;
549 int32_t len;
550
551 sp = krb5_storage_from_mem(d->buf, d->len);
552 if (sp == NULL) {
553 kdc_log (0, "krb5_storage_from_mem failed");
554 return -1;
555 }
556 krb5_ret_int32(sp, &len);
557 krb5_storage_free(sp);
558 if(d->len - 4 >= len) {
559 memcpy(d->buf, d->buf + 4, d->len - 4);
560 return 1;
561 }
562 return 0;
563}
564
565/*
566 * Try to handle the TCP/HTTP data at `d->buf, d->len'.
567 * Return -1 if failed, 0 if succesful, and 1 if data is complete.
568 */
569
570static int
567handle_http_tcp (struct descr *d, const char *addr)
571handle_http_tcp (struct descr *d)
568{
569 char *s, *p, *t;
570 void *data;
571 char *proto;
572 int len;
573
574 s = (char *)d->buf;
575
576 p = strstr(s, "\r\n");
577 if (p == NULL) {
572{
573 char *s, *p, *t;
574 void *data;
575 char *proto;
576 int len;
577
578 s = (char *)d->buf;
579
580 p = strstr(s, "\r\n");
581 if (p == NULL) {
578 kdc_log(0, "Malformed HTTP request from %s", addr);
582 kdc_log(0, "Malformed HTTP request from %s", d->addr_string);
579 return -1;
580 }
581 *p = 0;
582
583 p = NULL;
584 t = strtok_r(s, " \t", &p);
585 if (t == NULL) {
583 return -1;
584 }
585 *p = 0;
586
587 p = NULL;
588 t = strtok_r(s, " \t", &p);
589 if (t == NULL) {
586 kdc_log(0, "Malformed HTTP request from %s", addr);
590 kdc_log(0, "Malformed HTTP request from %s", d->addr_string);
587 return -1;
588 }
589 t = strtok_r(NULL, " \t", &p);
590 if(t == NULL) {
591 return -1;
592 }
593 t = strtok_r(NULL, " \t", &p);
594 if(t == NULL) {
591 kdc_log(0, "Malformed HTTP request from %s", addr);
595 kdc_log(0, "Malformed HTTP request from %s", d->addr_string);
592 return -1;
593 }
594 data = malloc(strlen(t));
595 if (data == NULL) {
596 kdc_log(0, "Failed to allocate %u bytes", strlen(t));
597 return -1;
598 }
599 if(*t == '/')
600 t++;
601 if(de_http(t) != 0) {
596 return -1;
597 }
598 data = malloc(strlen(t));
599 if (data == NULL) {
600 kdc_log(0, "Failed to allocate %u bytes", strlen(t));
601 return -1;
602 }
603 if(*t == '/')
604 t++;
605 if(de_http(t) != 0) {
602 kdc_log(0, "Malformed HTTP request from %s", addr);
606 kdc_log(0, "Malformed HTTP request from %s", d->addr_string);
603 kdc_log(5, "Request: %s", t);
604 free(data);
605 return -1;
606 }
607 proto = strtok_r(NULL, " \t", &p);
608 if (proto == NULL) {
607 kdc_log(5, "Request: %s", t);
608 free(data);
609 return -1;
610 }
611 proto = strtok_r(NULL, " \t", &p);
612 if (proto == NULL) {
609 kdc_log(0, "Malformed HTTP request from %s", addr);
613 kdc_log(0, "Malformed HTTP request from %s", d->addr_string);
610 free(data);
611 return -1;
612 }
613 len = base64_decode(t, data);
614 if(len <= 0){
615 const char *msg =
616 " 404 Not found\r\n"
617 "Server: Heimdal/" VERSION "\r\n"
618 "Content-type: text/html\r\n"
619 "Content-transfer-encoding: 8bit\r\n\r\n"
620 "<TITLE>404 Not found</TITLE>\r\n"
621 "<H1>404 Not found</H1>\r\n"
622 "That page doesn't exist, maybe you are looking for "
623 "<A HREF=\"http://www.pdc.kth.se/heimdal\">Heimdal</A>?\r\n";
624 write(d->s, proto, strlen(proto));
625 write(d->s, msg, strlen(msg));
614 free(data);
615 return -1;
616 }
617 len = base64_decode(t, data);
618 if(len <= 0){
619 const char *msg =
620 " 404 Not found\r\n"
621 "Server: Heimdal/" VERSION "\r\n"
622 "Content-type: text/html\r\n"
623 "Content-transfer-encoding: 8bit\r\n\r\n"
624 "<TITLE>404 Not found</TITLE>\r\n"
625 "<H1>404 Not found</H1>\r\n"
626 "That page doesn't exist, maybe you are looking for "
627 "<A HREF=\"http://www.pdc.kth.se/heimdal\">Heimdal</A>?\r\n";
628 write(d->s, proto, strlen(proto));
629 write(d->s, msg, strlen(msg));
626 kdc_log(0, "HTTP request from %s is non KDC request", addr);
630 kdc_log(0, "HTTP request from %s is non KDC request", d->addr_string);
627 kdc_log(5, "Request: %s", t);
628 free(data);
629 return -1;
630 }
631 {
632 const char *msg =
633 " 200 OK\r\n"
634 "Server: Heimdal/" VERSION "\r\n"
635 "Content-type: application/octet-stream\r\n"
636 "Content-transfer-encoding: binary\r\n\r\n";
637 write(d->s, proto, strlen(proto));
638 write(d->s, msg, strlen(msg));
639 }
640 memcpy(d->buf, data, len);
641 d->len = len;
642 free(data);
643 return 1;
644}
645
646/*
647 * Handle incoming data to the TCP socket in `d[index]'
648 */
649
650static void
651handle_tcp(struct descr *d, int index, int min_free)
652{
653 unsigned char buf[1024];
631 kdc_log(5, "Request: %s", t);
632 free(data);
633 return -1;
634 }
635 {
636 const char *msg =
637 " 200 OK\r\n"
638 "Server: Heimdal/" VERSION "\r\n"
639 "Content-type: application/octet-stream\r\n"
640 "Content-transfer-encoding: binary\r\n\r\n";
641 write(d->s, proto, strlen(proto));
642 write(d->s, msg, strlen(msg));
643 }
644 memcpy(d->buf, data, len);
645 d->len = len;
646 free(data);
647 return 1;
648}
649
650/*
651 * Handle incoming data to the TCP socket in `d[index]'
652 */
653
654static void
655handle_tcp(struct descr *d, int index, int min_free)
656{
657 unsigned char buf[1024];
654 char addr[32];
655 struct sockaddr_storage __ss;
656 struct sockaddr *sa = (struct sockaddr *)&__ss;
657 int from_len;
658 int n;
659 int ret = 0;
660
661 if (d[index].timeout == 0) {
662 add_new_tcp (d, index, min_free);
663 return;
664 }
665
658 int n;
659 int ret = 0;
660
661 if (d[index].timeout == 0) {
662 add_new_tcp (d, index, min_free);
663 return;
664 }
665
666 /*
667 * We can't trust recvfrom to return an address so we always call
668 * getpeername.
669 */
670
671 n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL);
672 if(n < 0){
673 krb5_warn(context, errno, "recvfrom");
674 return;
675 }
666 n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL);
667 if(n < 0){
668 krb5_warn(context, errno, "recvfrom");
669 return;
670 }
676 from_len = sizeof(__ss);
677 if (getpeername(d[index].s, sa, &from_len) < 0) {
678 krb5_warn(context, errno, "getpeername");
679 return;
680 }
681 addr_to_string(sa, from_len, addr, sizeof(addr));
682 if (grow_descr (&d[index], n))
683 return;
684 memcpy(d[index].buf + d[index].len, buf, n);
685 d[index].len += n;
686 if(d[index].len > 4 && d[index].buf[0] == 0) {
687 ret = handle_vanilla_tcp (&d[index]);
688 } else if(enable_http &&
689 d[index].len >= 4 &&
690 strncmp((char *)d[index].buf, "GET ", 4) == 0 &&
691 strncmp((char *)d[index].buf + d[index].len - 4,
692 "\r\n\r\n", 4) == 0) {
671 if (grow_descr (&d[index], n))
672 return;
673 memcpy(d[index].buf + d[index].len, buf, n);
674 d[index].len += n;
675 if(d[index].len > 4 && d[index].buf[0] == 0) {
676 ret = handle_vanilla_tcp (&d[index]);
677 } else if(enable_http &&
678 d[index].len >= 4 &&
679 strncmp((char *)d[index].buf, "GET ", 4) == 0 &&
680 strncmp((char *)d[index].buf + d[index].len - 4,
681 "\r\n\r\n", 4) == 0) {
693 ret = handle_http_tcp (&d[index], addr);
682 ret = handle_http_tcp (&d[index]);
694 if (ret < 0)
695 clear_descr (d + index);
696 } else if (d[index].len > 4) {
683 if (ret < 0)
684 clear_descr (d + index);
685 } else if (d[index].len > 4) {
697 kdc_log (0, "TCP data of strange type from %s", addr);
686 kdc_log (0, "TCP data of strange type from %s", d[index].addr_string);
698 return;
699 }
700 if (ret < 0)
701 return;
702 else if (ret == 1) {
687 return;
688 }
689 if (ret < 0)
690 return;
691 else if (ret == 1) {
703 do_request(d[index].buf, d[index].len, 1,
704 d[index].s, sa, from_len);
692 do_request(d[index].buf, d[index].len, 1, &d[index]);
705 clear_descr(d + index);
706 }
707}
708
709void
710loop(void)
711{
712 struct descr *d;
713 int ndescr;
714
715 ndescr = init_sockets(&d);
716 if(ndescr <= 0)
717 krb5_errx(context, 1, "No sockets!");
718 while(exit_flag == 0){
719 struct timeval tmout;
720 fd_set fds;
721 int min_free = -1;
722 int max_fd = 0;
723 int i;
724 FD_ZERO(&fds);
725 for(i = 0; i < ndescr; i++){
726 if(d[i].s >= 0){
727 if(d[i].type == SOCK_STREAM &&
693 clear_descr(d + index);
694 }
695}
696
697void
698loop(void)
699{
700 struct descr *d;
701 int ndescr;
702
703 ndescr = init_sockets(&d);
704 if(ndescr <= 0)
705 krb5_errx(context, 1, "No sockets!");
706 while(exit_flag == 0){
707 struct timeval tmout;
708 fd_set fds;
709 int min_free = -1;
710 int max_fd = 0;
711 int i;
712 FD_ZERO(&fds);
713 for(i = 0; i < ndescr; i++){
714 if(d[i].s >= 0){
715 if(d[i].type == SOCK_STREAM &&
728 d[i].timeout && d[i].timeout < time(NULL)){
729 struct sockaddr sa;
730 int salen = sizeof(sa);
731 char addr[32];
732
733 getpeername(d[i].s, &sa, &salen);
734 addr_to_string(&sa, salen, addr, sizeof(addr));
716 d[i].timeout && d[i].timeout < time(NULL)) {
735 kdc_log(1, "TCP-connection from %s expired after %u bytes",
717 kdc_log(1, "TCP-connection from %s expired after %u bytes",
736 addr, d[i].len);
718 d[i].addr_string, d[i].len);
737 clear_descr(&d[i]);
738 continue;
739 }
740 if(max_fd < d[i].s)
741 max_fd = d[i].s;
742 FD_SET(d[i].s, &fds);
743 }else if(min_free < 0 || i < min_free)
744 min_free = i;
745 }
746 if(min_free == -1){
747 struct descr *tmp;
748 tmp = realloc(d, (ndescr + 4) * sizeof(*d));
749 if(tmp == NULL)
750 krb5_warnx(context, "No memory");
751 else{
752 d = tmp;
753 memset(d + ndescr, 0, 4 * sizeof(*d));
754 for(i = ndescr; i < ndescr + 4; i++)
755 d[i].s = -1;
756 min_free = ndescr;
757 ndescr += 4;
758 }
759 }
760
761 tmout.tv_sec = TCP_TIMEOUT;
762 tmout.tv_usec = 0;
763 switch(select(max_fd + 1, &fds, 0, 0, &tmout)){
764 case 0:
765 break;
766 case -1:
767 if (errno != EINTR)
768 krb5_warn(context, errno, "select");
769 break;
770 default:
771 for(i = 0; i < ndescr; i++)
772 if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) {
773 if(d[i].type == SOCK_DGRAM)
774 handle_udp(&d[i]);
775 else if(d[i].type == SOCK_STREAM)
776 handle_tcp(d, i, min_free);
777 }
778 }
779 }
780 free (d);
781}
719 clear_descr(&d[i]);
720 continue;
721 }
722 if(max_fd < d[i].s)
723 max_fd = d[i].s;
724 FD_SET(d[i].s, &fds);
725 }else if(min_free < 0 || i < min_free)
726 min_free = i;
727 }
728 if(min_free == -1){
729 struct descr *tmp;
730 tmp = realloc(d, (ndescr + 4) * sizeof(*d));
731 if(tmp == NULL)
732 krb5_warnx(context, "No memory");
733 else{
734 d = tmp;
735 memset(d + ndescr, 0, 4 * sizeof(*d));
736 for(i = ndescr; i < ndescr + 4; i++)
737 d[i].s = -1;
738 min_free = ndescr;
739 ndescr += 4;
740 }
741 }
742
743 tmout.tv_sec = TCP_TIMEOUT;
744 tmout.tv_usec = 0;
745 switch(select(max_fd + 1, &fds, 0, 0, &tmout)){
746 case 0:
747 break;
748 case -1:
749 if (errno != EINTR)
750 krb5_warn(context, errno, "select");
751 break;
752 default:
753 for(i = 0; i < ndescr; i++)
754 if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) {
755 if(d[i].type == SOCK_DGRAM)
756 handle_udp(&d[i]);
757 else if(d[i].type == SOCK_STREAM)
758 handle_tcp(d, i, min_free);
759 }
760 }
761 }
762 free (d);
763}