コード例 #1
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
int
tac_add_server(struct tac_handle *h, const char *host, int port,
    const char *secret, int timeout, int flags)
{
	struct tac_server *srvp;

	if (h->num_servers >= MAXSERVERS) {
		generr(h, "Too many TACACS+ servers specified");
		return -1;
	}
	srvp = &h->servers[h->num_servers];

	memset(&srvp->addr, 0, sizeof srvp->addr);
	srvp->addr.sin_len = sizeof srvp->addr;
	srvp->addr.sin_family = AF_INET;
	if (!inet_aton(host, &srvp->addr.sin_addr)) {
		struct hostent *hent;

		if ((hent = gethostbyname(host)) == NULL) {
			generr(h, "%s: host not found", host);
			return -1;
		}
		memcpy(&srvp->addr.sin_addr, hent->h_addr,
		    sizeof srvp->addr.sin_addr);
	}
	srvp->addr.sin_port = htons(port != 0 ? port : TACPLUS_PORT);
	if ((srvp->secret = xstrdup(h, secret)) == NULL)
		return -1;
	srvp->timeout = timeout;
	srvp->flags = flags;
	h->num_servers++;
	return 0;
}
コード例 #2
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
/*
 * Append some optional data to the current request, and store its
 * length into the 16-bit field (network byte order) referenced by
 * "fld".  Returns 0 on success, or -1 on failure.
 *
 * This function also frees the "cs" string data and initializes it
 * for the next time.
 */
static int
add_str_16(struct tac_handle *h, u_int16_t *fld, struct clnt_str *cs)
{
	size_t len;

	len = cs->len;
	if (cs->data == NULL)
		len = 0;
	if (len != 0) {
		int offset;

		if (len > 0xffff) {
			generr(h, "Field too long");
			return -1;
		}
		offset = ntohl(h->request.length);
		if (offset + len > BODYSIZE) {
			generr(h, "Message too long");
			return -1;
		}
		memcpy(h->request.u.body + offset, cs->data, len);
		h->request.length = htonl(offset + len);
	}
	*fld = htons(len);
	free_str(cs);
	return 0;
}
コード例 #3
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
int
rad_send_response(struct rad_handle *h)
{
	int n;

	if (h->type != RADIUS_SERVER) {
		generr(h, "denied function call");
		return (-1);
	}
	/* Fill in the length field in the message */
	h->out[POS_LENGTH] = h->out_len >> 8;
	h->out[POS_LENGTH+1] = h->out_len;

	insert_message_authenticator(h,
	    (h->in[POS_CODE] == RAD_ACCESS_REQUEST) ? 1 : 0);
	insert_request_authenticator(h, 1);

	/* Send the request */
	n = sendto(h->fd, h->out, h->out_len, 0,
	    (const struct sockaddr *)&h->servers[h->srv].addr,
	    sizeof h->servers[h->srv].addr);
	if (n != h->out_len) {
		if (n == -1)
			generr(h, "sendto: %s", strerror(errno));
		else
			generr(h, "sendto: short write");
		return -1;
	}

	return 0;
}
コード例 #4
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
int
rad_add_server_ex(struct rad_handle *h, const char *host, int port,
    const char *secret, int timeout, int tries, int dead_time,
    struct in_addr *bindto)
{
	struct rad_server *srvp;

	if (h->num_servers >= MAXSERVERS) {
		generr(h, "Too many RADIUS servers specified");
		return -1;
	}
	srvp = &h->servers[h->num_servers];

	memset(&srvp->addr, 0, sizeof srvp->addr);
	srvp->addr.sin_len = sizeof srvp->addr;
	srvp->addr.sin_family = AF_INET;
	if (!inet_aton(host, &srvp->addr.sin_addr)) {
		struct hostent *hent;

		if ((hent = gethostbyname(host)) == NULL) {
			generr(h, "%s: host not found", host);
			return -1;
		}
		memcpy(&srvp->addr.sin_addr, hent->h_addr,
		    sizeof srvp->addr.sin_addr);
	}
	if (port != 0)
		srvp->addr.sin_port = htons((u_short)port);
	else {
		struct servent *sent;

		if (h->type == RADIUS_AUTH)
			srvp->addr.sin_port =
			    (sent = getservbyname("radius", "udp")) != NULL ?
				sent->s_port : htons(RADIUS_PORT);
		else
			srvp->addr.sin_port =
			    (sent = getservbyname("radacct", "udp")) != NULL ?
				sent->s_port : htons(RADACCT_PORT);
	}
	if ((srvp->secret = strdup(secret)) == NULL) {
		generr(h, "Out of memory");
		return -1;
	}
	srvp->timeout = timeout;
	srvp->max_tries = tries;
	srvp->num_tries = 0;
	srvp->is_dead = 0;
	srvp->dead_time = dead_time;
	srvp->next_probe = 0;
	srvp->bindto = bindto->s_addr;
	h->num_servers++;
	return 0;
}
コード例 #5
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
/*
 * Receive a response from the server and decrypt it.  Returns 0 on
 * success, or -1 on failure.
 */
static int
recv_msg(struct tac_handle *h)
{
	struct timeval deadline;
	struct tac_msg *msg;
	u_int32_t len;

	msg = &h->response;
	gettimeofday(&deadline, NULL);
	deadline.tv_sec += h->servers[h->cur_server].timeout;

	/* Read the message header and make sure it is reasonable. */
	if (read_timed(h, msg, HDRSIZE, &deadline) == -1)
		return -1;
	if (memcmp(msg->session_id, h->request.session_id,
	    sizeof msg->session_id) != 0) {
		generr(h, "Invalid session ID in received message");
		return -1;
	}
	if (msg->type != h->request.type) {
		generr(h, "Invalid type in received message"
			  " (got %u, expected %u)",
			  msg->type, h->request.type);
		return -1;
	}
	len = ntohl(msg->length);
	if (len > BODYSIZE) {
		generr(h, "Received message too large (%u > %u)",
			  len, BODYSIZE);
		return -1;
	}
	if (msg->seq_no != ++h->last_seq_no) {
		generr(h, "Invalid sequence number in received message"
			  " (got %u, expected %u)",
			  msg->seq_no, h->last_seq_no);
		return -1;
	}

	/* Read the message body. */
	if (read_timed(h, msg->u.body, len, &deadline) == -1)
		return -1;

	/* Decrypt it. */
	crypt_msg(h, msg);

	/*
	 * Turn off single-connection mode if the server isn't amenable
	 * to it.
	 */
	if (!(msg->flags & TAC_SINGLE_CONNECT))
		h->single_connect = 0;
	return 0;
}
コード例 #6
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
static int
read_timed(struct tac_handle *h, void *buf, size_t len,
    const struct timeval *deadline)
{
	char *ptr;

	ptr = (char *)buf;
	while (len > 0) {
		int n;

		n = read(h->fd, ptr, len);
		if (n == -1) {
			struct timeval tv;
			int nfds;

			if (errno != EAGAIN) {
				generr(h, "Network read error: %s",
				    strerror(errno));
				return -1;
			}

			/* Wait until we can read more data. */
			gettimeofday(&tv, NULL);
			timersub(deadline, &tv, &tv);
			if (tv.tv_sec >= 0) {
				fd_set rfds;

				FD_ZERO(&rfds);
				FD_SET(h->fd, &rfds);
				nfds =
				    select(h->fd + 1, &rfds, NULL, NULL, &tv);
				if (nfds == -1) {
					generr(h, "select: %s",
					    strerror(errno));
					return -1;
				}
			} else
				nfds = 0;
			if (nfds == 0) {
				generr(h, "Network read timed out");
				return -1;
			}
		} else if (n == 0) {
			generr(h, "unexpected EOF from server");
			return -1;
		} else {
			ptr += n;
			len -= n;
		}
	}
	return 0;
}
コード例 #7
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
static int
establish_connection(struct tac_handle *h)
{
	int i;

	if (h->fd >= 0)		/* Already connected. */
		return 0;
	if (h->num_servers == 0) {
		generr(h, "No TACACS+ servers specified");
		return -1;
	}
	/*
         * Try the servers round-robin.  We begin with the one that
         * worked for us the last time.  That way, once we find a good
         * server, we won't waste any more time trying the bad ones.
	 */
	for (i = 0;  i < h->num_servers;  i++) {
		if (conn_server(h) == 0) {
			h->single_connect = (h->servers[h->cur_server].flags &
			    TAC_SRVR_SINGLE_CONNECT) != 0;
			return 0;
		}
		if (++h->cur_server >= h->num_servers)	/* Wrap around */
			h->cur_server = 0;
	}
	/* Just return whatever error was last reported by conn_server(). */
	return -1;
}
コード例 #8
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
static int
put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
{
	int padded_len;
	int pad_len;

	if (h->pass_pos != 0) {
		generr(h, "Multiple User-Password attributes specified");
		return -1;
	}
	if (len > PASSSIZE)
		len = PASSSIZE;
	padded_len = len == 0 ? 16 : (len+15) & ~0xf;
	pad_len = padded_len - len;

	/*
	 * Put in a place-holder attribute containing all zeros, and
	 * remember where it is so we can fill it in later.
	 */
	clear_password(h);
	put_raw_attr(h, type, h->pass, padded_len);
	h->pass_pos = h->out_len - padded_len;

	/* Save the cleartext password, padded as necessary */
	memcpy(h->pass, value, len);
	h->pass_len = len;
	memset(h->pass + len, 0, pad_len);
	return 0;
}
コード例 #9
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
static int
put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
{
	if (len > 253) {
		generr(h, "Attribute too long");
		return -1;
	}
	if (h->out_len + 2 + len > MSGSIZE) {
		generr(h, "Maximum message length exceeded");
		return -1;
	}
	h->out[h->out_len++] = type;
	h->out[h->out_len++] = len + 2;
	memcpy(&h->out[h->out_len], value, len);
	h->out_len += len;
	return 0;
}
コード例 #10
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
static int
get_srvr_str(struct tac_handle *h, const char *field,
	     struct srvr_str *ss, size_t len)
{
	if (h->srvr_pos + len > ntohl(h->response.length)) {
		generr(h, "Invalid length field in %s response from server "
		       "(%lu > %lu)", field, (u_long)(h->srvr_pos + len),
		       (u_long)ntohl(h->response.length));
		return -1;
	}
	ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL;
	ss->len = len;
	h->srvr_pos += len;
	return 0;
}
コード例 #11
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
/*
 * Verify that we are exactly at the end of the response message.
 * Returns 0 on success, -1 on failure.
 */
static int
get_srvr_end(struct tac_handle *h)
{
	int len;

	len = ntohl(h->response.length);

	if (h->srvr_pos != len) {
		generr(h, "Invalid length field in response "
		       "from server: end expected at %u, response length %u",
		       h->srvr_pos, len);
		return -1;
	}
	return 0;
}
コード例 #12
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
int
rad_create_request(struct rad_handle *h, int code)
{
	int i;

	if (h->type == RADIUS_SERVER) {
		generr(h, "denied function call");
		return (-1);
	}
	if (h->num_servers == 0) {
	    	generr(h, "No RADIUS servers specified");
		return (-1);
	}
	h->out[POS_CODE] = code;
	h->out[POS_IDENT] = ++h->ident;
	if (code == RAD_ACCESS_REQUEST) {
		/* Create a random authenticator */
		for (i = 0;  i < LEN_AUTH;  i += 2) {
			long r;
			r = random();
			h->out[POS_AUTH+i] = (u_char)r;
			h->out[POS_AUTH+i+1] = (u_char)(r >> 8);
		}
	} else
コード例 #13
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
int
rad_receive_request(struct rad_handle *h)
{
	struct sockaddr_in from;
	socklen_t fromlen;
	int n;

	if (h->type != RADIUS_SERVER) {
		generr(h, "denied function call");
		return (-1);
	}
	h->srv = -1;
	fromlen = sizeof(from);
	h->in_len = recvfrom(h->fd, h->in,
	    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
	if (h->in_len == -1) {
		generr(h, "recvfrom: %s", strerror(errno));
		return (-1);
	}
	for (n = 0; n < h->num_servers; n++) {
		if (h->servers[n].addr.sin_addr.s_addr == from.sin_addr.s_addr) {
			h->servers[n].addr.sin_port = from.sin_port;
			h->srv = n;
			break;
		}
	}
	if (h->srv == -1)
		return (-2);
	if (is_valid_request(h)) {
		h->in_len = h->in[POS_LENGTH] << 8 |
		    h->in[POS_LENGTH+1];
		h->in_pos = POS_ATTRS;
		return (h->in[POS_CODE]);
	}
	return (-3);
}
コード例 #14
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
/*
 * Append some optional data to the current request, and store its
 * length into the 8-bit field referenced by "fld".  Returns 0 on
 * success, or -1 on failure.
 *
 * This function also frees the "cs" string data and initializes it
 * for the next time.
 */
static int
add_str_8(struct tac_handle *h, u_int8_t *fld, struct clnt_str *cs)
{
	u_int16_t len;

	if (add_str_16(h, &len, cs) == -1)
		return -1;
	len = ntohs(len);
	if (len > 0xff) {
		generr(h, "Field too long");
		return -1;
	}
	*fld = len;
	return 0;
}
コード例 #15
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
static int
conn_server(struct tac_handle *h)
{
	const struct tac_server *srvp = &h->servers[h->cur_server];
	int flags;

	if ((h->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
		generr(h, "Cannot create socket: %s", strerror(errno));
		return -1;
	}
	if ((flags = fcntl(h->fd, F_GETFL, 0)) == -1 ||
	    fcntl(h->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
		generr(h, "Cannot set non-blocking mode on socket: %s",
		    strerror(errno));
		close(h->fd);
		h->fd = -1;
		return -1;
	}
	if (connect(h->fd, (struct sockaddr *)&srvp->addr,
	    sizeof srvp->addr) == 0)
		return 0;

	if (errno == EINPROGRESS) {
		fd_set wfds;
		struct timeval tv;
		int nfds;
		struct sockaddr peer;
		int peerlen;
		int err;
		int errlen;

		/* Wait for the connection to complete. */
		FD_ZERO(&wfds);
		FD_SET(h->fd, &wfds);
		tv.tv_sec = srvp->timeout;
		tv.tv_usec = 0;
		nfds = select(h->fd + 1, NULL, &wfds, NULL, &tv);
		if (nfds == -1) {
			generr(h, "select: %s", strerror(errno));
			close(h->fd);
			h->fd = -1;
			return -1;
		}
		if (nfds == 0) {
			generr(h, "connect: timed out");
			close(h->fd);
			h->fd = -1;
			return -1;
		}

		/* See whether we are connected now. */
		peerlen = sizeof peer;
		if (getpeername(h->fd, &peer, &peerlen) == 0)
			return 0;

		if (errno != ENOTCONN) {
			generr(h, "getpeername: %s", strerror(errno));
			close(h->fd);
			h->fd = -1;
			return -1;
		}

		/* Find out why the connect failed. */
		errlen = sizeof err;
		getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
		errno = err;
	}
	generr(h, "connect: %s", strerror(errno));
	close(h->fd);
	h->fd = -1;
	return -1;
}
コード例 #16
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
int
tac_config(struct tac_handle *h, const char *path)
{
	FILE *fp;
	char buf[MAXCONFLINE];
	int linenum;
	int retval;

	if (path == NULL)
		path = PATH_TACPLUS_CONF;
	if ((fp = fopen(path, "r")) == NULL) {
		generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
		return -1;
	}
	retval = 0;
	linenum = 0;
	while (fgets(buf, sizeof buf, fp) != NULL) {
		int len;
		char *fields[4];
		int nfields;
		char msg[ERRSIZE];
		char *host, *res;
		char *port_str;
		char *secret;
		char *timeout_str;
		char *options_str;
		char *end;
		unsigned long timeout;
		int port;
		int options;

		linenum++;
		len = strlen(buf);
		/* We know len > 0, else fgets would have returned NULL. */
		if (buf[len - 1] != '\n') {
			if (len >= sizeof buf - 1)
				generr(h, "%s:%d: line too long", path,
				    linenum);
			else
				generr(h, "%s:%d: missing newline", path,
				    linenum);
			retval = -1;
			break;
		}
		buf[len - 1] = '\0';

		/* Extract the fields from the line. */
		nfields = split(buf, fields, 4, msg, sizeof msg);
		if (nfields == -1) {
			generr(h, "%s:%d: %s", path, linenum, msg);
			retval = -1;
			break;
		}
		if (nfields == 0)
			continue;
		if (nfields < 2) {
			generr(h, "%s:%d: missing shared secret", path,
			    linenum);
			retval = -1;
			break;
		}
		host = fields[0];
		secret = fields[1];
		timeout_str = fields[2];
		options_str = fields[3];

		/* Parse and validate the fields. */
		res = host;
		host = strsep(&res, ":");
		port_str = strsep(&res, ":");
		if (port_str != NULL) {
			port = strtoul(port_str, &end, 10);
			if (port_str[0] == '\0' || *end != '\0') {
				generr(h, "%s:%d: invalid port", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
			port = 0;
		if (timeout_str != NULL) {
			timeout = strtoul(timeout_str, &end, 10);
			if (timeout_str[0] == '\0' || *end != '\0') {
				generr(h, "%s:%d: invalid timeout", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
			timeout = TIMEOUT;
		options = 0;
		if (options_str != NULL) {
			if (strcmp(options_str, "single-connection") == 0)
				options |= TAC_SRVR_SINGLE_CONNECT;
			else {
				generr(h, "%s:%d: invalid option \"%s\"",
				    path, linenum, options_str);
				retval = -1;
				break;
			}
		}

		if (tac_add_server(h, host, port, secret, timeout,
		    options) == -1) {
			char msg[ERRSIZE];

			strcpy(msg, h->errmsg);
			generr(h, "%s:%d: %s", path, linenum, msg);
			retval = -1;
			break;
		}
	}
	/* Clear out the buffer to wipe a possible copy of a shared secret */
	memset(buf, 0, sizeof buf);
	fclose(fp);
	return retval;
}
コード例 #17
0
ファイル: taclib.c プロジェクト: alexandermerritt/dragonfly
/*
 * Send the current request, after encrypting it.  Returns 0 on success,
 * or -1 on failure.
 */
static int
send_msg(struct tac_handle *h)
{
	struct timeval deadline;
	struct tac_msg *msg;
	char *ptr;
	int len;

	if (h->last_seq_no & 1) {
		generr(h, "Attempt to send message out of sequence");
		return -1;
	}

	if (establish_connection(h) == -1)
		return -1;

	msg = &h->request;
	msg->seq_no = ++h->last_seq_no;
	if (msg->seq_no == 1)
		gen_session_id(msg);
	crypt_msg(h, msg);

	if (h->single_connect)
		msg->flags |= TAC_SINGLE_CONNECT;
	else
		msg->flags &= ~TAC_SINGLE_CONNECT;
	gettimeofday(&deadline, NULL);
	deadline.tv_sec += h->servers[h->cur_server].timeout;
	len = HDRSIZE + ntohl(msg->length);
	ptr = (char *)msg;
	while (len > 0) {
		int n;

		n = write(h->fd, ptr, len);
		if (n == -1) {
			struct timeval tv;
			int nfds;

			if (errno != EAGAIN) {
				generr(h, "Network write error: %s",
				    strerror(errno));
				return -1;
			}

			/* Wait until we can write more data. */
			gettimeofday(&tv, NULL);
			timersub(&deadline, &tv, &tv);
			if (tv.tv_sec >= 0) {
				fd_set wfds;

				FD_ZERO(&wfds);
				FD_SET(h->fd, &wfds);
				nfds =
				    select(h->fd + 1, NULL, &wfds, NULL, &tv);
				if (nfds == -1) {
					generr(h, "select: %s",
					    strerror(errno));
					return -1;
				}
			} else
				nfds = 0;
			if (nfds == 0) {
				generr(h, "Network write timed out");
				return -1;
			}
		} else {
			ptr += n;
			len -= n;
		}
	}
	return 0;
}
コード例 #18
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
int
rad_config(struct rad_handle *h, const char *path)
{
	FILE *fp;
	char buf[MAXCONFLINE];
	int linenum;
	int retval;

	if (path == NULL)
		path = PATH_RADIUS_CONF;
	if ((fp = fopen(path, "r")) == NULL) {
		generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
		return -1;
	}
	retval = 0;
	linenum = 0;
	while (fgets(buf, sizeof buf, fp) != NULL) {
		int len;
		char *fields[MAX_FIELDS];
		int nfields;
		char msg[ERRSIZE];
		char *type;
		char *host, *res;
		char *port_str;
		char *secret;
		char *timeout_str;
		char *maxtries_str;
		char *dead_time_str;
		char *bindto_str;
		char *end;
		char *wanttype;
		unsigned long timeout;
		unsigned long maxtries;
		unsigned long dead_time;
		int port;
		struct in_addr bindto;
		int i;

		linenum++;
		len = strlen(buf);
		/* We know len > 0, else fgets would have returned NULL. */
		if (buf[len - 1] != '\n') {
			if (len == sizeof buf - 1)
				generr(h, "%s:%d: line too long", path,
				    linenum);
			else
				generr(h, "%s:%d: missing newline", path,
				    linenum);
			retval = -1;
			break;
		}
		buf[len - 1] = '\0';

		/* Extract the fields from the line. */
		nfields = split(buf, fields, MAX_FIELDS, msg, sizeof msg);
		if (nfields == -1) {
			generr(h, "%s:%d: %s", path, linenum, msg);
			retval = -1;
			break;
		}
		if (nfields == 0)
			continue;
		/*
		 * The first field should contain "auth" or "acct" for
		 * authentication or accounting, respectively.  But older
		 * versions of the file didn't have that field.  Default
		 * it to "auth" for backward compatibility.
		 */
		if (strcmp(fields[0], "auth") != 0 &&
		    strcmp(fields[0], "acct") != 0) {
			if (nfields >= MAX_FIELDS) {
				generr(h, "%s:%d: invalid service type", path,
				    linenum);
				retval = -1;
				break;
			}
			nfields++;
			for (i = nfields;  --i > 0;  )
				fields[i] = fields[i - 1];
			fields[0] = "auth";
		}
		if (nfields < 3) {
			generr(h, "%s:%d: missing shared secret", path,
			    linenum);
			retval = -1;
			break;
		}
		type = fields[0];
		host = fields[1];
		secret = fields[2];
		timeout_str = fields[3];
		maxtries_str = fields[4];
		dead_time_str = fields[5];
		bindto_str = fields[6];

		/* Ignore the line if it is for the wrong service type. */
		wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
		if (strcmp(type, wanttype) != 0)
			continue;

		/* Parse and validate the fields. */
		res = host;
		host = strsep(&res, ":");
		port_str = strsep(&res, ":");
		if (port_str != NULL) {
			port = strtoul(port_str, &end, 10);
			if (*end != '\0') {
				generr(h, "%s:%d: invalid port", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
			port = 0;
		if (timeout_str != NULL) {
			timeout = strtoul(timeout_str, &end, 10);
			if (*end != '\0') {
				generr(h, "%s:%d: invalid timeout", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
			timeout = TIMEOUT;
		if (maxtries_str != NULL) {
			maxtries = strtoul(maxtries_str, &end, 10);
			if (*end != '\0') {
				generr(h, "%s:%d: invalid maxtries", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
			maxtries = MAXTRIES;

		if (dead_time_str != NULL) {
			dead_time = strtoul(dead_time_str, &end, 10);
			if (*end != '\0') {
				generr(h, "%s:%d: invalid dead_time", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
		    	dead_time = DEAD_TIME;

		if (bindto_str != NULL) {
		    	bindto.s_addr = inet_addr(bindto_str);
			if (bindto.s_addr == INADDR_NONE) {
				generr(h, "%s:%d: invalid bindto", path,
				    linenum);
				retval = -1;
				break;
			}
		} else
		    	bindto.s_addr = INADDR_ANY;

		if (rad_add_server_ex(h, host, port, secret, timeout, maxtries,
			    dead_time, &bindto) == -1) {
			strcpy(msg, h->errmsg);
			generr(h, "%s:%d: %s", path, linenum, msg);
			retval = -1;
			break;
		}
	}
	/* Clear out the buffer to wipe a possible copy of a shared secret */
	memset(buf, 0, sizeof buf);
	fclose(fp);
	return retval;
}
コード例 #19
0
ファイル: radlib.c プロジェクト: hmatyschok/MeshBSD
/*
 * rad_init_send_request() must have previously been called.
 * Returns:
 *   0     The application should select on *fd with a timeout of tv before
 *         calling rad_continue_send_request again.
 *   < 0   Failure
 *   > 0   Success
 */
int
rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
                          struct timeval *tv)
{
	int n, cur_srv;
	time_t now;
	struct sockaddr_in sin;

	if (h->type == RADIUS_SERVER) {
		generr(h, "denied function call");
		return (-1);
	}
	if (selected) {
		struct sockaddr_in from;
		socklen_t fromlen;

		fromlen = sizeof from;
		h->in_len = recvfrom(h->fd, h->in,
		    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
		if (h->in_len == -1) {
			generr(h, "recvfrom: %s", strerror(errno));
			return -1;
		}
		if (is_valid_response(h, h->srv, &from)) {
			h->in_len = h->in[POS_LENGTH] << 8 |
			    h->in[POS_LENGTH+1];
			h->in_pos = POS_ATTRS;
			return h->in[POS_CODE];
		}
	}

	/*
         * Scan round-robin to the next server that has some
         * tries left.  There is guaranteed to be one, or we
         * would have exited this loop by now.
	 */
	cur_srv = h->srv;
	now = time(NULL);
	if (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries) {
		/* Set next probe time for this server */
		if (h->servers[h->srv].dead_time) {
			h->servers[h->srv].is_dead = 1;
			h->servers[h->srv].next_probe = now +
			    h->servers[h->srv].dead_time;
		}
		do {
		    	h->srv++;
			if (h->srv >= h->num_servers)
				h->srv = 0;
			if (h->servers[h->srv].is_dead == 0)
			    	break;
			if (h->servers[h->srv].dead_time &&
			    h->servers[h->srv].next_probe <= now) {
			    	h->servers[h->srv].is_dead = 0;
				h->servers[h->srv].num_tries = 0;
				break;
			}
		} while (h->srv != cur_srv);

		if (h->srv == cur_srv) {
			generr(h, "No valid RADIUS responses received");
			return (-1);
		}
	}

	/* Rebind */
	if (h->bindto != h->servers[h->srv].bindto) {
	    	h->bindto = h->servers[h->srv].bindto;
		close(h->fd);
		if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
			generr(h, "Cannot create socket: %s", strerror(errno));
			return -1;
		}
		memset(&sin, 0, sizeof sin);
		sin.sin_len = sizeof sin;
		sin.sin_family = AF_INET;
		sin.sin_addr.s_addr = h->bindto;
		sin.sin_port = 0;
		if (bind(h->fd, (const struct sockaddr *)&sin,
		    sizeof sin) == -1) {
			generr(h, "bind: %s", strerror(errno));
			close(h->fd);
			h->fd = -1;
			return (-1);
		}
	}

	if (h->out[POS_CODE] == RAD_ACCESS_REQUEST) {
		/* Insert the scrambled password into the request */
		if (h->pass_pos != 0)
			insert_scrambled_password(h, h->srv);
	}
	insert_message_authenticator(h, 0);

	if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) {
		/* Insert the request authenticator into the request */
		memset(&h->out[POS_AUTH], 0, LEN_AUTH);
		insert_request_authenticator(h, 0);
	}

	/* Send the request */
	n = sendto(h->fd, h->out, h->out_len, 0,
	    (const struct sockaddr *)&h->servers[h->srv].addr,
	    sizeof h->servers[h->srv].addr);
	if (n != h->out_len)
		tv->tv_sec = 1; /* Do not wait full timeout if send failed. */
	else
		tv->tv_sec = h->servers[h->srv].timeout;
	h->servers[h->srv].num_tries++;
	tv->tv_usec = 0;
	*fd = h->fd;

	return 0;
}