2 * Copyright (c) 1997 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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 static struct port_desc
*ports
;
53 add_port(int family
, const char *port_str
, const char *protocol
)
60 sp
= roken_getservbyname(port_str
, protocol
);
65 port
= htons(strtol(port_str
, &end
, 0));
69 if(strcmp(protocol
, "udp") == 0)
71 else if(strcmp(protocol
, "tcp") == 0)
75 for(i
= 0; i
< num_ports
; i
++){
76 if(ports
[i
].type
== type
77 && ports
[i
].port
== port
78 && ports
[i
].family
== family
)
81 ports
= realloc(ports
, (num_ports
+ 1) * sizeof(*ports
));
82 ports
[num_ports
].family
= family
;
83 ports
[num_ports
].type
= type
;
84 ports
[num_ports
].port
= port
;
89 add_standard_ports (int family
)
91 add_port(family
, "kerberos", "udp");
92 add_port(family
, "kerberos", "tcp");
93 add_port(family
, "kerberos-sec", "udp");
94 add_port(family
, "kerberos-sec", "tcp");
95 add_port(family
, "kerberos-iv", "udp");
96 add_port(family
, "kerberos-iv", "tcp");
98 add_port(family
, "http", "tcp");
100 add_port(family
, "7004", "udp");
105 parse_ports(char *str
)
109 p
= strtok_r(str
, " \t", &pos
);
111 if(strcmp(p
, "+") == 0) {
112 #if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
113 add_standard_ports(AF_INET6
);
115 add_standard_ports(AF_INET
);
118 char *q
= strchr(p
, '/');
121 #if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
122 add_port(AF_INET6
, p
, q
);
124 add_port(AF_INET
, p
, q
);
127 #if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
128 add_port(AF_INET6
, p
, "udp");
129 add_port(AF_INET6
, p
, "tcp");
131 add_port(AF_INET
, p
, "udp");
132 add_port(AF_INET
, p
, "tcp");
137 p
= strtok_r(NULL
, " \t", &pos
);
151 init_socket(struct descr
*d
, int family
, int type
, int port
)
158 sa_size
= krb5_max_sockaddr_size ();
159 sa_buf
= malloc(sa_size
);
160 if (sa_buf
== NULL
) {
161 kdc_log(0, "Failed to allocate %u bytes", sa_size
);
164 sa
= (struct sockaddr
*)sa_buf
;
166 memset(d
, 0, sizeof(*d
));
167 d
->s
= socket(family
, type
, 0);
169 krb5_warn(context
, errno
, "socket(%d, %d, 0)", family
, type
);
173 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR)
176 setsockopt(d
->s
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
180 ret
= krb5_anyaddr (family
, sa
, &sa_size
, port
);
182 krb5_warn(context
, ret
, "krb5_anyaddr");
188 if(bind(d
->s
, sa
, sa_size
) < 0){
189 krb5_warn(context
, errno
, "bind(%d)", ntohs(port
));
194 if(type
== SOCK_STREAM
&& listen(d
->s
, SOMAXCONN
) < 0){
195 krb5_warn(context
, errno
, "listen");
204 init_sockets(struct descr
**desc
)
210 parse_ports(port_str
);
211 d
= malloc(num_ports
* sizeof(*d
));
213 krb5_errx(context
, 1, "malloc(%u) failed", num_ports
* sizeof(*d
));
215 for (i
= 0; i
< num_ports
; i
++){
216 init_socket(&d
[num
], ports
[i
].family
, ports
[i
].type
, ports
[i
].port
);
218 kdc_log(5, "listening to port %u/%s", ntohs(ports
[i
].port
),
219 (ports
[i
].type
== SOCK_STREAM
) ? "tcp" : "udp"); /* XXX */
223 d
= realloc(d
, num
* sizeof(*d
));
225 krb5_errx(context
, 1, "realloc(%u) failed", num
* sizeof(*d
));
232 process_request(unsigned char *buf
,
237 struct sockaddr
*addr
)
246 gettimeofday(&now
, NULL
);
247 if(decode_AS_REQ(buf
, len
, &req
, &i
) == 0){
248 ret
= as_rep(&req
, reply
, from
);
251 }else if(decode_TGS_REQ(buf
, len
, &req
, &i
) == 0){
252 ret
= tgs_rep(&req
, reply
, from
);
257 else if(maybe_version4(buf
, len
)){
258 *sendlength
= 0; /* elbitapmoc sdrawkcab XXX */
259 do_version4(buf
, len
, reply
, from
, (struct sockaddr_in
*)addr
);
260 }else if(decode_Ticket(buf
, len
, &ticket
, &i
) == 0){
261 ret
= do_524(&ticket
, reply
, from
);
262 free_Ticket(&ticket
);
268 ret
= do_kaserver (buf
, len
, reply
, from
, (struct sockaddr_in
*)addr
);
277 addr_to_string(struct sockaddr
*addr
, size_t addr_len
, char *str
, size_t len
)
279 switch(addr
->sa_family
){
281 strncpy(str
, inet_ntoa(((struct sockaddr_in
*)addr
)->sin_addr
), len
);
283 #if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6) && defined(HAVE_INET_NTOP)
285 inet_ntop(AF_INET6
, &((struct sockaddr_in6
*)addr
)->sin6_addr
,
290 snprintf(str
, len
, "<%d addr>", addr
->sa_family
);
296 do_request(void *buf
, size_t len
, int sendlength
,
297 int socket
, struct sockaddr
*from
, size_t from_len
)
303 addr_to_string(from
, from_len
, addr
, sizeof(addr
));
306 ret
= process_request(buf
, len
, &reply
, &sendlength
, addr
, from
);
308 kdc_log(5, "sending %d bytes to %s", reply
.length
, addr
);
310 unsigned char len
[4];
311 len
[0] = (reply
.length
>> 24) & 0xff;
312 len
[1] = (reply
.length
>> 16) & 0xff;
313 len
[2] = (reply
.length
>> 8) & 0xff;
314 len
[3] = reply
.length
& 0xff;
315 sendto(socket
, len
, sizeof(len
), 0, from
, from_len
);
317 sendto(socket
, reply
.data
, reply
.length
, 0, from
, from_len
);
318 krb5_data_free(&reply
);
321 kdc_log(0, "Failed processing %lu byte request from %s",
322 (unsigned long)len
, addr
);
326 handle_udp(struct descr
*d
)
335 sa_size
= krb5_max_sockaddr_size ();
336 sa_buf
= malloc(sa_size
);
337 if (sa_buf
== NULL
) {
338 kdc_log(0, "Failed to allocate %u bytes", sa_size
);
341 sa
= (struct sockaddr
*)sa_buf
;
343 buf
= malloc(max_request
);
345 kdc_log(0, "Failed to allocate %u bytes", max_request
);
351 n
= recvfrom(d
->s
, buf
, max_request
, 0,
354 krb5_warn(context
, errno
, "recvfrom");
360 do_request(buf
, n
, 0, d
->s
, sa
, from_len
);
367 clear_descr(struct descr
*d
)
370 memset(d
->buf
, 0, d
->size
);
377 #define TCP_TIMEOUT 4
380 handle_tcp(struct descr
*d
, int index
, int min_free
)
382 unsigned char buf
[1024];
390 sa_size
= krb5_max_sockaddr_size ();
391 sa_buf
= malloc(sa_size
);
392 if (sa_buf
== NULL
) {
393 kdc_log(0, "Failed to allocate %u bytes", sa_size
);
396 sa
= (struct sockaddr
*)sa_buf
;
398 if(d
[index
].timeout
== 0){
402 s
= accept(d
[index
].s
, sa
, &from_len
);
404 krb5_warn(context
, errno
, "accept");
413 d
[min_free
].timeout
= time(NULL
) + TCP_TIMEOUT
;
414 d
[min_free
].type
= SOCK_STREAM
;
418 n
= recvfrom(d
[index
].s
, buf
, sizeof(buf
), 0,
421 krb5_warn(context
, errno
, "recvfrom");
424 /* sometimes recvfrom doesn't return an address */
427 getpeername(d
[index
].s
, sa
, &from_len
);
429 addr_to_string(sa
, from_len
, addr
, sizeof(addr
));
430 if(d
[index
].size
- d
[index
].len
< n
){
432 d
[index
].size
+= 1024;
433 if(d
[index
].size
>= max_request
){
434 kdc_log(0, "Request exceeds max request size (%u bytes).",
436 clear_descr(d
+ index
);
439 tmp
= realloc(d
[index
].buf
, d
[index
].size
);
441 kdc_log(0, "Failed to re-allocate %u bytes.", d
[index
].size
);
442 clear_descr(d
+ index
);
447 memcpy(d
[index
].buf
+ d
[index
].len
, buf
, n
);
449 if(d
[index
].len
> 4 && d
[index
].buf
[0] == 0){
452 sp
= krb5_storage_from_mem(d
[index
].buf
, d
[index
].len
);
453 krb5_ret_int32(sp
, &len
);
454 krb5_storage_free(sp
);
455 if(d
[index
].len
- 4 >= len
){
456 memcpy(d
[index
].buf
, d
[index
].buf
+ 4, d
[index
].len
- 4);
460 else if(enable_http
&&
461 strncmp((char *)d
[index
].buf
, "GET ", 4) == 0 &&
462 strncmp((char *)d
[index
].buf
+ d
[index
].len
- 4,
463 "\r\n\r\n", 4) == 0){
467 s
= (char *)d
[index
].buf
;
468 p
= strstr(s
, "\r\n");
471 strtok_r(s
, " \t", &p
);
472 t
= strtok_r(NULL
, " \t", &p
);
474 kdc_log(0, "Malformed HTTP request from %s", addr
);
475 clear_descr(d
+ index
);
478 data
= malloc(strlen(t
));
480 kdc_log(0, "Failed to allocate %u bytes", strlen(t
));
485 len
= base64_decode(t
, data
);
488 "HTTP/1.1 404 Not found\r\n"
489 "Server: Heimdal/" VERSION
"\r\n"
490 "Content-type: text/html\r\n"
491 "Content-transfer-encoding: 8bit\r\n\r\n"
492 "<TITLE>404 Not found</TITLE>\r\n"
493 "<H1>404 Not found</H1>\r\n"
494 "That page doesn't exist, maybe you are looking for "
495 "<A HREF=\"http://www.pdc.kth.se/heimdal\">Heimdal</A>?\r\n";
496 write(d
[index
].s
, msg
, strlen(msg
));
498 clear_descr(d
+ index
);
499 kdc_log(0, "HTTP request from %s is non KDC request", addr
);
504 "HTTP/1.1 200 OK\r\n"
505 "Server: Heimdal/" VERSION
"\r\n"
506 "Content-type: application/octet-stream\r\n"
507 "Content-transfer-encoding: binary\r\n\r\n";
508 write(d
[index
].s
, msg
, strlen(msg
));
510 memcpy(d
[index
].buf
, data
, len
);
516 do_request(d
[index
].buf
, d
[index
].len
, 1,
517 d
[index
].s
, sa
, from_len
);
518 clear_descr(d
+ index
);
530 ndescr
= init_sockets(&d
);
532 krb5_errx(context
, 1, "No sockets!");
533 while(exit_flag
== 0){
534 struct timeval tmout
;
540 for(i
= 0; i
< ndescr
; i
++){
542 if(d
[i
].type
== SOCK_STREAM
&&
543 d
[i
].timeout
&& d
[i
].timeout
< time(NULL
)){
545 int salen
= sizeof(sa
);
548 getpeername(d
[i
].s
, &sa
, &salen
);
549 addr_to_string(&sa
, salen
, addr
, sizeof(addr
));
550 kdc_log(1, "TCP-connection from %s expired after %u bytes",
557 FD_SET(d
[i
].s
, &fds
);
558 }else if(min_free
< 0 || i
< min_free
)
563 tmp
= realloc(d
, (ndescr
+ 4) * sizeof(*d
));
565 krb5_warnx(context
, "No memory");
568 memset(d
+ ndescr
, 0, 4 * sizeof(*d
));
569 for(i
= ndescr
; i
< ndescr
+ 4; i
++)
576 tmout
.tv_sec
= TCP_TIMEOUT
;
578 switch(select(max_fd
+ 1, &fds
, 0, 0, &tmout
)){
582 krb5_warn(context
, errno
, "select");
585 for(i
= 0; i
< ndescr
; i
++)
586 if(d
[i
].s
>= 0 && FD_ISSET(d
[i
].s
, &fds
))
587 if(d
[i
].type
== SOCK_DGRAM
)
589 else if(d
[i
].type
== SOCK_STREAM
)
590 handle_tcp(d
, i
, min_free
);