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}
|