示例#1
0
/**
 * radius_client_init - Initialize RADIUS client
 * @ctx: Callback context to be used in hostapd_logger() calls
 * @conf: RADIUS client configuration (RADIUS servers)
 * Returns: Pointer to private RADIUS client context or %NULL on failure
 *
 * The caller is responsible for keeping the configuration data available for
 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
 * called for the returned context pointer.
 */
struct radius_client_data *
radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
{
	struct radius_client_data *radius;

	radius = os_zalloc(sizeof(struct radius_client_data));
	if (radius == NULL)
		return NULL;

	radius->ctx = ctx;
	radius->conf = conf;
	radius->auth_serv_sock = radius->acct_serv_sock =
		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
		radius->auth_sock = radius->acct_sock = -1;

	if (conf->auth_server && radius_client_init_auth(radius)) {
		radius_client_deinit(radius);
		return NULL;
	}

	if (conf->acct_server && radius_client_init_acct(radius)) {
		radius_client_deinit(radius);
		return NULL;
	}

	if (conf->retry_primary_interval)
		eloop_register_timeout(conf->retry_primary_interval, 0,
				       radius_retry_primary_timer, radius,
				       NULL);

	return radius;
}
示例#2
0
/*
 * Returns >0 if message queue was flushed (i.e., the message that triggered
 * the error is not available anymore)
 */
static int radius_client_handle_send_error(struct radius_client_data *radius,
					   int s, RadiusType msg_type)
{
#ifndef CONFIG_NATIVE_WINDOWS
	int _errno = errno;
	wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
	    _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_INFO,
			       "Send failed - maybe interface status changed -"
			       " try to connect again");
		if (msg_type == RADIUS_ACCT ||
		    msg_type == RADIUS_ACCT_INTERIM) {
			radius_client_init_acct(radius);
			return 0;
		} else {
			radius_client_init_auth(radius);
			return 1;
		}
	}
#endif /* CONFIG_NATIVE_WINDOWS */

	return 0;
}
示例#3
0
struct radius_client_data * radius_client_init(struct hostapd_data *hapd)
{
    struct radius_client_data *radius;

    radius = malloc(sizeof(struct radius_client_data));
    if (radius == NULL)
        return NULL;

    memset(radius, 0, sizeof(struct radius_client_data));
    radius->hapd = hapd;
    radius->auth_serv_sock = radius->acct_serv_sock = -1;

    if (hapd->conf->auth_server && radius_client_init_auth(radius)) {
        radius_client_deinit(radius);
        return NULL;
    }

    if (hapd->conf->acct_server && radius_client_init_acct(radius)) {
        radius_client_deinit(radius);
        return NULL;
    }

    if (hapd->conf->radius_retry_primary_interval)
        eloop_register_timeout(hapd->conf->
                               radius_retry_primary_interval, 0,
                               radius_retry_primary_timer, radius,
                               NULL);

    return radius;
}
示例#4
0
static void radius_client_handle_send_error(struct radius_client_data *radius,
        int s, RadiusType msg_type)
{
    struct hostapd_data *hapd = radius->hapd;
    int _errno = errno;
    perror("send[RADIUS]");
    if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
        hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
                       HOSTAPD_LEVEL_INFO,
                       "Send failed - maybe interface status changed -"
                       " try to connect again");
        eloop_unregister_read_sock(s);
        close(s);
        if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
            radius_client_init_acct(radius);
        else
            radius_client_init_auth(radius);
    }
}
int radius_client_init(hostapd *hapd)
{
	hapd->radius = malloc(sizeof(struct radius_client_data));
	if (hapd->radius == NULL)
		return -1;

	memset(hapd->radius, 0, sizeof(struct radius_client_data));
	hapd->radius->auth_serv_sock = hapd->radius->acct_serv_sock = -1;

	if (hapd->conf->auth_server && radius_client_init_auth(hapd))
		return -1;

	if (hapd->conf->acct_server && radius_client_init_acct(hapd))
		return -1;

	if (hapd->conf->radius_retry_primary_interval)
		eloop_register_timeout(hapd->conf->
				       radius_retry_primary_interval, 0,
				       radius_retry_primary_timer, hapd, NULL);

	return 0;
}
示例#6
0
int radius_client_init(struct wpa_supplicant *wpa_s)
{
	wpa_s->radius = malloc(sizeof(struct radius_client_data));
	if (wpa_s->radius == NULL)
		return -1;

	memset(wpa_s->radius, 0, sizeof(struct radius_client_data));
	wpa_s->radius->auth_serv_sock = wpa_s->radius->acct_serv_sock = -1;

	if (wpa_s->auth_server && radius_client_init_auth(wpa_s))
		return -1;

	if (wpa_s->acct_server && radius_client_init_acct(wpa_s))
		return -1;

	if (wpa_s->radius_retry_primary_interval)
		eloop_register_timeout(wpa_s->radius_retry_primary_interval, 0,
				       radius_retry_primary_timer, wpa_s,
				       NULL);

	return 0;
}
示例#7
0
/**
 * radius_client_send - Send a RADIUS request
 * @radius: RADIUS client context from radius_client_init()
 * @msg: RADIUS message to be sent
 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
 * @addr: MAC address of the device related to this message or %NULL
 * Returns: 0 on success, -1 on failure
 *
 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
 * between accounting and interim accounting messages is that the interim
 * message will not be retransmitted. Instead, a callback is used to indicate
 * that the transmission failed for the specific station @addr so that a new
 * interim accounting update message can be generated with up-to-date session
 * data instead of trying to resend old information.
 *
 * The message is added on the retransmission queue and will be retransmitted
 * automatically until a response is received or maximum number of retries
 * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
 * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
 * automatically on transmission failure.
 *
 * The related device MAC address can be used to identify pending messages that
 * can be removed with radius_client_flush_auth().
 */
int radius_client_send(struct radius_client_data *radius,
		       struct radius_msg *msg, RadiusType msg_type,
		       const u8 *addr)
{
	struct hostapd_radius_servers *conf = radius->conf;
	const u8 *shared_secret;
	size_t shared_secret_len;
	char *name;
	int s, res;
	struct wpabuf *buf;

	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
		if (conf->acct_server && radius->acct_sock < 0)
			radius_client_init_acct(radius);

		if (conf->acct_server == NULL || radius->acct_sock < 0 ||
		    conf->acct_server->shared_secret == NULL) {
			hostapd_logger(radius->ctx, NULL,
				       HOSTAPD_MODULE_RADIUS,
				       HOSTAPD_LEVEL_INFO,
				       "No accounting server configured");
			return -1;
		}
		shared_secret = conf->acct_server->shared_secret;
		shared_secret_len = conf->acct_server->shared_secret_len;
		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
		name = "accounting";
		s = radius->acct_sock;
		conf->acct_server->requests++;
	} else {
		if (conf->auth_server && radius->auth_sock < 0)
			radius_client_init_auth(radius);

		if (conf->auth_server == NULL || radius->auth_sock < 0 ||
		    conf->auth_server->shared_secret == NULL) {
			hostapd_logger(radius->ctx, NULL,
				       HOSTAPD_MODULE_RADIUS,
				       HOSTAPD_LEVEL_INFO,
				       "No authentication server configured");
			return -1;
		}
		shared_secret = conf->auth_server->shared_secret;
		shared_secret_len = conf->auth_server->shared_secret_len;
		radius_msg_finish(msg, shared_secret, shared_secret_len);
		name = "authentication";
		s = radius->auth_sock;
		conf->auth_server->requests++;
	}

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
		       "server", name);
	if (conf->msg_dumps)
		radius_msg_dump(msg);

	buf = radius_msg_get_buf(msg);
	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
	if (res < 0)
		radius_client_handle_send_error(radius, s, msg_type);

	radius_client_list_add(radius, msg, msg_type, shared_secret,
			       shared_secret_len, addr);

	return 0;
}
示例#8
0
static int radius_client_retransmit(struct radius_client_data *radius,
				    struct radius_msg_list *entry,
				    os_time_t now)
{
	struct hostapd_radius_servers *conf = radius->conf;
	int s;
	struct wpabuf *buf;
	size_t prev_num_msgs;
	u8 *acct_delay_time;
	size_t acct_delay_time_len;

	if (entry->msg_type == RADIUS_ACCT ||
	    entry->msg_type == RADIUS_ACCT_INTERIM) {
		if (radius->acct_sock < 0)
			radius_client_init_acct(radius);
		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_acct_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->acct_sock;
		if (entry->attempts == 0)
			conf->acct_server->requests++;
		else {
			conf->acct_server->timeouts++;
			conf->acct_server->retransmissions++;
		}
	} else {
		if (radius->auth_sock < 0)
			radius_client_init_auth(radius);
		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_auth_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->auth_sock;
		if (entry->attempts == 0)
			conf->auth_server->requests++;
		else {
			conf->auth_server->timeouts++;
			conf->auth_server->retransmissions++;
		}
	}

	if (entry->msg_type == RADIUS_ACCT_INTERIM) {
		wpa_printf(MSG_DEBUG,
			   "RADIUS: Failed to transmit interim accounting update to "
			   MACSTR " - drop message and request a new update",
			   MAC2STR(entry->addr));
		if (radius->interim_error_cb)
			radius->interim_error_cb(entry->addr,
						 radius->interim_error_cb_ctx);
		return 1;
	}

	if (s < 0) {
		wpa_printf(MSG_INFO,
			   "RADIUS: No valid socket for retransmission");
		return 1;
	}

	if (entry->msg_type == RADIUS_ACCT &&
	    radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
				    &acct_delay_time, &acct_delay_time_len,
				    NULL) == 0 &&
	    acct_delay_time_len == 4) {
		struct radius_hdr *hdr;
		u32 delay_time;

		/*
		 * Need to assign a new identifier since attribute contents
		 * changes.
		 */
		hdr = radius_msg_get_hdr(entry->msg);
		hdr->identifier = radius_client_get_id(radius);

		/* Update Acct-Delay-Time to show wait time in queue */
		delay_time = now - entry->first_try;
		WPA_PUT_BE32(acct_delay_time, delay_time);

		wpa_printf(MSG_DEBUG,
			   "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
			   delay_time);
		radius_msg_finish_acct(entry->msg, entry->shared_secret,
				       entry->shared_secret_len);
		if (radius->conf->msg_dumps)
			radius_msg_dump(entry->msg);
	}

	/* retransmit; remove entry if too many attempts */
	entry->attempts++;
	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
		       radius_msg_get_hdr(entry->msg)->identifier);

	os_get_reltime(&entry->last_attempt);
	buf = radius_msg_get_buf(entry->msg);
	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
		if (radius_client_handle_send_error(radius, s, entry->msg_type)
		    > 0)
			return 0;
	}

	entry->next_try = now + entry->next_wait;
	entry->next_wait *= 2;
	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
		return 1;
	}

	return 0;
}
示例#9
0
static int radius_client_retransmit(struct radius_client_data *radius,
				    struct radius_msg_list *entry,
				    os_time_t now)
{
	struct hostapd_radius_servers *conf = radius->conf;
	int s;
	struct wpabuf *buf;
	size_t prev_num_msgs;

	if (entry->msg_type == RADIUS_ACCT ||
	    entry->msg_type == RADIUS_ACCT_INTERIM) {
		if (radius->acct_sock < 0)
			radius_client_init_acct(radius);
		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_acct_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->acct_sock;
		if (entry->attempts == 0)
			conf->acct_server->requests++;
		else {
			conf->acct_server->timeouts++;
			conf->acct_server->retransmissions++;
		}
	} else {
		if (radius->auth_sock < 0)
			radius_client_init_auth(radius);
		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_auth_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->auth_sock;
		if (entry->attempts == 0)
			conf->auth_server->requests++;
		else {
			conf->auth_server->timeouts++;
			conf->auth_server->retransmissions++;
		}
	}
	if (s < 0) {
		wpa_printf(MSG_INFO,
			   "RADIUS: No valid socket for retransmission");
		return 1;
	}

	/* retransmit; remove entry if too many attempts */
	entry->attempts++;
	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
		       radius_msg_get_hdr(entry->msg)->identifier);

	os_get_reltime(&entry->last_attempt);
	buf = radius_msg_get_buf(entry->msg);
	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
		if (radius_client_handle_send_error(radius, s, entry->msg_type)
		    > 0)
			return 0;
	}

	entry->next_try = now + entry->next_wait;
	entry->next_wait *= 2;
	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
		return 1;
	}

	return 0;
}