Home | History | Annotate | Download | only in radius
      1 /*
      2  * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
      3  * Copyright (c) 2012-2013, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 #include <net/if.h>
     11 
     12 #include "utils/common.h"
     13 #include "utils/eloop.h"
     14 #include "utils/ip_addr.h"
     15 #include "radius.h"
     16 #include "radius_das.h"
     17 
     18 
     19 struct radius_das_data {
     20 	int sock;
     21 	u8 *shared_secret;
     22 	size_t shared_secret_len;
     23 	struct hostapd_ip_addr client_addr;
     24 	unsigned int time_window;
     25 	int require_event_timestamp;
     26 	int require_message_authenticator;
     27 	void *ctx;
     28 	enum radius_das_res (*disconnect)(void *ctx,
     29 					  struct radius_das_attrs *attr);
     30 	enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
     31 };
     32 
     33 
     34 static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
     35 						 struct radius_msg *msg,
     36 						 const char *abuf,
     37 						 int from_port)
     38 {
     39 	struct radius_hdr *hdr;
     40 	struct radius_msg *reply;
     41 	u8 allowed[] = {
     42 		RADIUS_ATTR_USER_NAME,
     43 		RADIUS_ATTR_NAS_IP_ADDRESS,
     44 		RADIUS_ATTR_CALLING_STATION_ID,
     45 		RADIUS_ATTR_NAS_IDENTIFIER,
     46 		RADIUS_ATTR_ACCT_SESSION_ID,
     47 		RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
     48 		RADIUS_ATTR_EVENT_TIMESTAMP,
     49 		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
     50 		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
     51 #ifdef CONFIG_IPV6
     52 		RADIUS_ATTR_NAS_IPV6_ADDRESS,
     53 #endif /* CONFIG_IPV6 */
     54 		0
     55 	};
     56 	int error = 405;
     57 	u8 attr;
     58 	enum radius_das_res res;
     59 	struct radius_das_attrs attrs;
     60 	u8 *buf;
     61 	size_t len;
     62 	char tmp[100];
     63 	u8 sta_addr[ETH_ALEN];
     64 
     65 	hdr = radius_msg_get_hdr(msg);
     66 
     67 	attr = radius_msg_find_unlisted_attr(msg, allowed);
     68 	if (attr) {
     69 		wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in "
     70 			   "Disconnect-Request from %s:%d", attr,
     71 			   abuf, from_port);
     72 		error = 401;
     73 		goto fail;
     74 	}
     75 
     76 	os_memset(&attrs, 0, sizeof(attrs));
     77 
     78 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
     79 				    &buf, &len, NULL) == 0) {
     80 		if (len != 4) {
     81 			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
     82 				   abuf, from_port);
     83 			error = 407;
     84 			goto fail;
     85 		}
     86 		attrs.nas_ip_addr = buf;
     87 	}
     88 
     89 #ifdef CONFIG_IPV6
     90 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
     91 				    &buf, &len, NULL) == 0) {
     92 		if (len != 16) {
     93 			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
     94 				   abuf, from_port);
     95 			error = 407;
     96 			goto fail;
     97 		}
     98 		attrs.nas_ipv6_addr = buf;
     99 	}
    100 #endif /* CONFIG_IPV6 */
    101 
    102 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
    103 				    &buf, &len, NULL) == 0) {
    104 		attrs.nas_identifier = buf;
    105 		attrs.nas_identifier_len = len;
    106 	}
    107 
    108 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
    109 				    &buf, &len, NULL) == 0) {
    110 		if (len >= sizeof(tmp))
    111 			len = sizeof(tmp) - 1;
    112 		os_memcpy(tmp, buf, len);
    113 		tmp[len] = '\0';
    114 		if (hwaddr_aton2(tmp, sta_addr) < 0) {
    115 			wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
    116 				   "'%s' from %s:%d", tmp, abuf, from_port);
    117 			error = 407;
    118 			goto fail;
    119 		}
    120 		attrs.sta_addr = sta_addr;
    121 	}
    122 
    123 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
    124 				    &buf, &len, NULL) == 0) {
    125 		attrs.user_name = buf;
    126 		attrs.user_name_len = len;
    127 	}
    128 
    129 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
    130 				    &buf, &len, NULL) == 0) {
    131 		attrs.acct_session_id = buf;
    132 		attrs.acct_session_id_len = len;
    133 	}
    134 
    135 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
    136 				    &buf, &len, NULL) == 0) {
    137 		attrs.acct_multi_session_id = buf;
    138 		attrs.acct_multi_session_id_len = len;
    139 	}
    140 
    141 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
    142 				    &buf, &len, NULL) == 0) {
    143 		attrs.cui = buf;
    144 		attrs.cui_len = len;
    145 	}
    146 
    147 	res = das->disconnect(das->ctx, &attrs);
    148 	switch (res) {
    149 	case RADIUS_DAS_NAS_MISMATCH:
    150 		wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
    151 			   abuf, from_port);
    152 		error = 403;
    153 		break;
    154 	case RADIUS_DAS_SESSION_NOT_FOUND:
    155 		wpa_printf(MSG_INFO, "DAS: Session not found for request from "
    156 			   "%s:%d", abuf, from_port);
    157 		error = 503;
    158 		break;
    159 	case RADIUS_DAS_MULTI_SESSION_MATCH:
    160 		wpa_printf(MSG_INFO,
    161 			   "DAS: Multiple sessions match for request from %s:%d",
    162 			   abuf, from_port);
    163 		error = 508;
    164 		break;
    165 	case RADIUS_DAS_COA_FAILED:
    166 		/* not used with Disconnect-Request */
    167 		error = 405;
    168 		break;
    169 	case RADIUS_DAS_SUCCESS:
    170 		error = 0;
    171 		break;
    172 	}
    173 
    174 fail:
    175 	reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
    176 			       RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
    177 	if (reply == NULL)
    178 		return NULL;
    179 
    180 	if (error) {
    181 		if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
    182 					       error)) {
    183 			radius_msg_free(reply);
    184 			return NULL;
    185 		}
    186 	}
    187 
    188 	return reply;
    189 }
    190 
    191 
    192 static struct radius_msg * radius_das_coa(struct radius_das_data *das,
    193 					  struct radius_msg *msg,
    194 					  const char *abuf, int from_port)
    195 {
    196 	struct radius_hdr *hdr;
    197 	struct radius_msg *reply;
    198 	u8 allowed[] = {
    199 		RADIUS_ATTR_USER_NAME,
    200 		RADIUS_ATTR_NAS_IP_ADDRESS,
    201 		RADIUS_ATTR_CALLING_STATION_ID,
    202 		RADIUS_ATTR_NAS_IDENTIFIER,
    203 		RADIUS_ATTR_ACCT_SESSION_ID,
    204 		RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
    205 		RADIUS_ATTR_EVENT_TIMESTAMP,
    206 		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
    207 		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
    208 #ifdef CONFIG_HS20
    209 		RADIUS_ATTR_VENDOR_SPECIFIC,
    210 #endif /* CONFIG_HS20 */
    211 #ifdef CONFIG_IPV6
    212 		RADIUS_ATTR_NAS_IPV6_ADDRESS,
    213 #endif /* CONFIG_IPV6 */
    214 		0
    215 	};
    216 	int error = 405;
    217 	u8 attr;
    218 	enum radius_das_res res;
    219 	struct radius_das_attrs attrs;
    220 	u8 *buf;
    221 	size_t len;
    222 	char tmp[100];
    223 	u8 sta_addr[ETH_ALEN];
    224 
    225 	hdr = radius_msg_get_hdr(msg);
    226 
    227 	if (!das->coa) {
    228 		wpa_printf(MSG_INFO, "DAS: CoA not supported");
    229 		goto fail;
    230 	}
    231 
    232 	attr = radius_msg_find_unlisted_attr(msg, allowed);
    233 	if (attr) {
    234 		wpa_printf(MSG_INFO,
    235 			   "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
    236 			   attr, abuf, from_port);
    237 		error = 401;
    238 		goto fail;
    239 	}
    240 
    241 	os_memset(&attrs, 0, sizeof(attrs));
    242 
    243 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
    244 				    &buf, &len, NULL) == 0) {
    245 		if (len != 4) {
    246 			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
    247 				   abuf, from_port);
    248 			error = 407;
    249 			goto fail;
    250 		}
    251 		attrs.nas_ip_addr = buf;
    252 	}
    253 
    254 #ifdef CONFIG_IPV6
    255 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
    256 				    &buf, &len, NULL) == 0) {
    257 		if (len != 16) {
    258 			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
    259 				   abuf, from_port);
    260 			error = 407;
    261 			goto fail;
    262 		}
    263 		attrs.nas_ipv6_addr = buf;
    264 	}
    265 #endif /* CONFIG_IPV6 */
    266 
    267 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
    268 				    &buf, &len, NULL) == 0) {
    269 		attrs.nas_identifier = buf;
    270 		attrs.nas_identifier_len = len;
    271 	}
    272 
    273 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
    274 				    &buf, &len, NULL) == 0) {
    275 		if (len >= sizeof(tmp))
    276 			len = sizeof(tmp) - 1;
    277 		os_memcpy(tmp, buf, len);
    278 		tmp[len] = '\0';
    279 		if (hwaddr_aton2(tmp, sta_addr) < 0) {
    280 			wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
    281 				   "'%s' from %s:%d", tmp, abuf, from_port);
    282 			error = 407;
    283 			goto fail;
    284 		}
    285 		attrs.sta_addr = sta_addr;
    286 	}
    287 
    288 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
    289 				    &buf, &len, NULL) == 0) {
    290 		attrs.user_name = buf;
    291 		attrs.user_name_len = len;
    292 	}
    293 
    294 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
    295 				    &buf, &len, NULL) == 0) {
    296 		attrs.acct_session_id = buf;
    297 		attrs.acct_session_id_len = len;
    298 	}
    299 
    300 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
    301 				    &buf, &len, NULL) == 0) {
    302 		attrs.acct_multi_session_id = buf;
    303 		attrs.acct_multi_session_id_len = len;
    304 	}
    305 
    306 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
    307 				    &buf, &len, NULL) == 0) {
    308 		attrs.cui = buf;
    309 		attrs.cui_len = len;
    310 	}
    311 
    312 #ifdef CONFIG_HS20
    313 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
    314 				    &buf, &len, NULL) == 0) {
    315 		if (len < 10 || WPA_GET_BE32(buf) != RADIUS_VENDOR_ID_WFA ||
    316 		    buf[4] != RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING ||
    317 		    buf[5] < 6) {
    318 			wpa_printf(MSG_INFO,
    319 				   "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
    320 				   attr, abuf, from_port);
    321 			error = 401;
    322 			goto fail;
    323 		}
    324 		attrs.hs20_t_c_filtering = &buf[6];
    325 	}
    326 
    327 	if (!attrs.hs20_t_c_filtering) {
    328 			wpa_printf(MSG_INFO,
    329 				   "DAS: No supported authorization change attribute in CoA-Request from %s:%d",
    330 				   abuf, from_port);
    331 			error = 402;
    332 			goto fail;
    333 	}
    334 #endif /* CONFIG_HS20 */
    335 
    336 	res = das->coa(das->ctx, &attrs);
    337 	switch (res) {
    338 	case RADIUS_DAS_NAS_MISMATCH:
    339 		wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
    340 			   abuf, from_port);
    341 		error = 403;
    342 		break;
    343 	case RADIUS_DAS_SESSION_NOT_FOUND:
    344 		wpa_printf(MSG_INFO,
    345 			   "DAS: Session not found for request from %s:%d",
    346 			   abuf, from_port);
    347 		error = 503;
    348 		break;
    349 	case RADIUS_DAS_MULTI_SESSION_MATCH:
    350 		wpa_printf(MSG_INFO,
    351 			   "DAS: Multiple sessions match for request from %s:%d",
    352 			   abuf, from_port);
    353 		error = 508;
    354 		break;
    355 	case RADIUS_DAS_COA_FAILED:
    356 		wpa_printf(MSG_INFO, "DAS: CoA failed for request from %s:%d",
    357 			   abuf, from_port);
    358 		error = 407;
    359 		break;
    360 	case RADIUS_DAS_SUCCESS:
    361 		error = 0;
    362 		break;
    363 	}
    364 
    365 fail:
    366 	reply = radius_msg_new(error ? RADIUS_CODE_COA_NAK :
    367 			       RADIUS_CODE_COA_ACK, hdr->identifier);
    368 	if (!reply)
    369 		return NULL;
    370 
    371 	if (error &&
    372 	    !radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) {
    373 		radius_msg_free(reply);
    374 		return NULL;
    375 	}
    376 
    377 	return reply;
    378 }
    379 
    380 
    381 static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
    382 {
    383 	struct radius_das_data *das = eloop_ctx;
    384 	u8 buf[1500];
    385 	union {
    386 		struct sockaddr_storage ss;
    387 		struct sockaddr_in sin;
    388 #ifdef CONFIG_IPV6
    389 		struct sockaddr_in6 sin6;
    390 #endif /* CONFIG_IPV6 */
    391 	} from;
    392 	char abuf[50];
    393 	int from_port = 0;
    394 	socklen_t fromlen;
    395 	int len;
    396 	struct radius_msg *msg, *reply = NULL;
    397 	struct radius_hdr *hdr;
    398 	struct wpabuf *rbuf;
    399 	u32 val;
    400 	int res;
    401 	struct os_time now;
    402 
    403 	fromlen = sizeof(from);
    404 	len = recvfrom(sock, buf, sizeof(buf), 0,
    405 		       (struct sockaddr *) &from.ss, &fromlen);
    406 	if (len < 0) {
    407 		wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
    408 		return;
    409 	}
    410 
    411 	os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
    412 	from_port = ntohs(from.sin.sin_port);
    413 
    414 	wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
    415 		   len, abuf, from_port);
    416 	if (das->client_addr.u.v4.s_addr &&
    417 	    das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
    418 		wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
    419 		return;
    420 	}
    421 
    422 	msg = radius_msg_parse(buf, len);
    423 	if (msg == NULL) {
    424 		wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
    425 			   "from %s:%d failed", abuf, from_port);
    426 		return;
    427 	}
    428 
    429 	if (wpa_debug_level <= MSG_MSGDUMP)
    430 		radius_msg_dump(msg);
    431 
    432 	if (radius_msg_verify_das_req(msg, das->shared_secret,
    433 				       das->shared_secret_len,
    434 				       das->require_message_authenticator)) {
    435 		wpa_printf(MSG_DEBUG,
    436 			   "DAS: Invalid authenticator or Message-Authenticator in packet from %s:%d - drop",
    437 			   abuf, from_port);
    438 		goto fail;
    439 	}
    440 
    441 	os_get_time(&now);
    442 	res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
    443 				  (u8 *) &val, 4);
    444 	if (res == 4) {
    445 		u32 timestamp = ntohl(val);
    446 		if ((unsigned int) abs((int) (now.sec - timestamp)) >
    447 		    das->time_window) {
    448 			wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
    449 				   "Event-Timestamp (%u; local time %u) in "
    450 				   "packet from %s:%d - drop",
    451 				   timestamp, (unsigned int) now.sec,
    452 				   abuf, from_port);
    453 			goto fail;
    454 		}
    455 	} else if (das->require_event_timestamp) {
    456 		wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet "
    457 			   "from %s:%d - drop", abuf, from_port);
    458 		goto fail;
    459 	}
    460 
    461 	hdr = radius_msg_get_hdr(msg);
    462 
    463 	switch (hdr->code) {
    464 	case RADIUS_CODE_DISCONNECT_REQUEST:
    465 		reply = radius_das_disconnect(das, msg, abuf, from_port);
    466 		break;
    467 	case RADIUS_CODE_COA_REQUEST:
    468 		reply = radius_das_coa(das, msg, abuf, from_port);
    469 		break;
    470 	default:
    471 		wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
    472 			   "packet from %s:%d",
    473 			   hdr->code, abuf, from_port);
    474 	}
    475 
    476 	if (reply) {
    477 		wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);
    478 
    479 		if (!radius_msg_add_attr_int32(reply,
    480 					       RADIUS_ATTR_EVENT_TIMESTAMP,
    481 					       now.sec)) {
    482 			wpa_printf(MSG_DEBUG, "DAS: Failed to add "
    483 				   "Event-Timestamp attribute");
    484 		}
    485 
    486 		if (radius_msg_finish_das_resp(reply, das->shared_secret,
    487 					       das->shared_secret_len, hdr) <
    488 		    0) {
    489 			wpa_printf(MSG_DEBUG, "DAS: Failed to add "
    490 				   "Message-Authenticator attribute");
    491 		}
    492 
    493 		if (wpa_debug_level <= MSG_MSGDUMP)
    494 			radius_msg_dump(reply);
    495 
    496 		rbuf = radius_msg_get_buf(reply);
    497 		res = sendto(das->sock, wpabuf_head(rbuf),
    498 			     wpabuf_len(rbuf), 0,
    499 			     (struct sockaddr *) &from.ss, fromlen);
    500 		if (res < 0) {
    501 			wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
    502 				   abuf, from_port, strerror(errno));
    503 		}
    504 	}
    505 
    506 fail:
    507 	radius_msg_free(msg);
    508 	radius_msg_free(reply);
    509 }
    510 
    511 
    512 static int radius_das_open_socket(int port)
    513 {
    514 	int s;
    515 	struct sockaddr_in addr;
    516 
    517 	s = socket(PF_INET, SOCK_DGRAM, 0);
    518 	if (s < 0) {
    519 		wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno));
    520 		return -1;
    521 	}
    522 
    523 	os_memset(&addr, 0, sizeof(addr));
    524 	addr.sin_family = AF_INET;
    525 	addr.sin_port = htons(port);
    526 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    527 		wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno));
    528 		close(s);
    529 		return -1;
    530 	}
    531 
    532 	return s;
    533 }
    534 
    535 
    536 struct radius_das_data *
    537 radius_das_init(struct radius_das_conf *conf)
    538 {
    539 	struct radius_das_data *das;
    540 
    541 	if (conf->port == 0 || conf->shared_secret == NULL ||
    542 	    conf->client_addr == NULL)
    543 		return NULL;
    544 
    545 	das = os_zalloc(sizeof(*das));
    546 	if (das == NULL)
    547 		return NULL;
    548 
    549 	das->time_window = conf->time_window;
    550 	das->require_event_timestamp = conf->require_event_timestamp;
    551 	das->require_message_authenticator =
    552 		conf->require_message_authenticator;
    553 	das->ctx = conf->ctx;
    554 	das->disconnect = conf->disconnect;
    555 	das->coa = conf->coa;
    556 
    557 	os_memcpy(&das->client_addr, conf->client_addr,
    558 		  sizeof(das->client_addr));
    559 
    560 	das->shared_secret = os_memdup(conf->shared_secret,
    561 				       conf->shared_secret_len);
    562 	if (das->shared_secret == NULL) {
    563 		radius_das_deinit(das);
    564 		return NULL;
    565 	}
    566 	das->shared_secret_len = conf->shared_secret_len;
    567 
    568 	das->sock = radius_das_open_socket(conf->port);
    569 	if (das->sock < 0) {
    570 		wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
    571 			   "DAS");
    572 		radius_das_deinit(das);
    573 		return NULL;
    574 	}
    575 
    576 	if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
    577 	{
    578 		radius_das_deinit(das);
    579 		return NULL;
    580 	}
    581 
    582 	return das;
    583 }
    584 
    585 
    586 void radius_das_deinit(struct radius_das_data *das)
    587 {
    588 	if (das == NULL)
    589 		return;
    590 
    591 	if (das->sock >= 0) {
    592 		eloop_unregister_read_sock(das->sock);
    593 		close(das->sock);
    594 	}
    595 
    596 	os_free(das->shared_secret);
    597 	os_free(das);
    598 }
    599