ATTRIBUTE TLS-Client-Cert-X509v3-Subject-Key-Identifier 1928 string
ATTRIBUTE TLS-Client-Cert-X509v3-Authority-Key-Identifier 1929 string
ATTRIBUTE TLS-Client-Cert-X509v3-Basic-Constraints 1930 string
- ATTRIBUTE TLS-PSK-Identity 1931 string
+ ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Dns 1931 string
+ ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Upn 1932 string
++ATTRIBUTE TLS-PSK-Identity 1933 string
- # 1932 - 1939: reserved for future cert attributes
-# 1933 - 1939: reserved for future cert attributes
++# 1934 - 1939: reserved for future cert attributes
#
# Range: 1940-2099
#define PW_DIGEST_RESPONSE 206
#define PW_DIGEST_ATTRIBUTES 207
- #define PW_FALL_THROUGH 500
- #define PW_RELAX_FILTER 501
- #define PW_EXEC_PROGRAM 502
- #define PW_EXEC_PROGRAM_WAIT 503
-
- #define PW_AUTH_TYPE 1000
- #define PW_PREFIX 1003
- #define PW_SUFFIX 1004
- #define PW_GROUP 1005
- #define PW_CRYPT_PASSWORD 1006
- #define PW_CONNECT_RATE 1007
- #define PW_ADD_PREFIX 1008
- #define PW_ADD_SUFFIX 1009
- #define PW_EXPIRATION 1010
- #define PW_AUTZ_TYPE 1011
- #define PW_ACCT_TYPE 1012
- #define PW_SESSION_TYPE 1013
- #define PW_POST_AUTH_TYPE 1014
- #define PW_PRE_PROXY_TYPE 1015
- #define PW_POST_PROXY_TYPE 1016
- #define PW_PRE_ACCT_TYPE 1017
- #define PW_EAP_TYPE 1018
- #define PW_EAP_TLS_REQUIRE_CLIENT_CERT 1019
- #define PW_EAP_MD5_PASSWORD 1022
- #define PW_CLIENT_SHORTNAME 1024
- #define PW_LOAD_BALANCE_KEY 1025
- #define PW_RAW_ATTRIBUTE 1026
- #define PW_TNC_VLAN_ACCESS 1027
- #define PW_TNC_VLAN_ISOLATE 1028
- #define PW_USER_CATEGORY 1029
- #define PW_GROUP_NAME 1030
- #define PW_HUNTGROUP_NAME 1031
- #define PW_SIMULTANEOUS_USE 1034
- #define PW_STRIP_USER_NAME 1035
- #define PW_HINT 1040
- #define PAM_AUTH_ATTR 1041
- #define PW_LOGIN_TIME 1042
- #define PW_STRIPPED_USER_NAME 1043
- #define PW_CURRENT_TIME 1044
- #define PW_REALM 1045
- #define PW_NO_SUCH_ATTRIBUTE 1046
- #define PW_PACKET_TYPE 1047
- #define PW_PROXY_TO_REALM 1048
- #define PW_REPLICATE_TO_REALM 1049
- #define PW_ACCT_SESSION_START_TIME 1050
- #define PW_ACCT_UNIQUE_SESSION_ID 1051
- #define PW_CLIENT_IP_ADDRESS 1052
- #define PW_LDAP_USERDN 1053
- #define PW_NS_MTA_MD5_PASSWORD 1054
- #define PW_SQL_USER_NAME 1055
- #define PW_LM_PASSWORD 1057
- #define PW_NT_PASSWORD 1058
- #define PW_SMB_ACCOUNT_CTRL 1059
- #define PW_SMB_ACCOUNT_CTRL_TEXT 1061
- #define PW_USER_PROFILE 1062
- #define PW_DIGEST_REALM 1063
- #define PW_DIGEST_NONCE 1064
- #define PW_DIGEST_METHOD 1065
- #define PW_DIGEST_URI 1066
- #define PW_DIGEST_QOP 1067
- #define PW_DIGEST_ALGORITHM 1068
- #define PW_DIGEST_BODY_DIGEST 1069
- #define PW_DIGEST_CNONCE 1070
- #define PW_DIGEST_NONCE_COUNT 1071
- #define PW_DIGEST_USER_NAME 1072
- #define PW_POOL_NAME 1073
- #define PW_LDAP_GROUP 1074
- #define PW_MODULE_SUCCESS_MESSAGE 1075
- #define PW_MODULE_FAILURE_MESSAGE 1076
- #if 0 /* no longer used */
- #define PW_X99_FAST 1077
- #endif
- #define PW_REWRITE_RULE 1078
- #define PW_SQL_GROUP 1079
- #define PW_RESPONSE_PACKET_TYPE 1080
- #define PW_DIGEST_HA1 1081
- #define PW_MS_CHAP_USE_NTLM_AUTH 1082
- #define PW_MS_CHAP_USER_NAME 1083
- #define PW_PACKET_SRC_IP_ADDRESS 1084
- #define PW_PACKET_DST_IP_ADDRESS 1085
- #define PW_PACKET_SRC_PORT 1086
- #define PW_PACKET_DST_PORT 1087
- #define PW_PACKET_AUTHENTICATION_VECTOR 1088
- #define PW_TIME_OF_DAY 1089
- #define PW_REQUEST_PROCESSING_STAGE 1090
-
- #define PW_SHA_PASSWORD 1093
- #define PW_SSHA_PASSWORD 1094
- #define PW_MD5_PASSWORD 1095
- #define PW_SMD5_PASSWORD 1096
-
- #define PW_PACKET_SRC_IPV6_ADDRESS 1097
- #define PW_PACKET_DST_IPV6_ADDRESS 1098
- #define PW_VIRTUAL_SERVER 1099
- #define PW_CLEARTEXT_PASSWORD 1100
- #define PW_PASSWORD_WITH_HEADER 1101
- #define PW_SEND_COA_REQUEST 1107
- #define PW_MODULE_RETURN_CODE 1108
- #define PW_PACKET_ORIGINAL_TIMESTAMP 1109
- #define PW_HOME_SERVER_POOL 1111
- #define PW_FREERADIUS_CLIENT_IP_ADDRESS 1120
- #define PW_FREERADIUS_CLIENT_IPV6_ADDRESS 1121
- #define PW_RECV_COA_TYPE 1131
- #define PW_SEND_COA_TYPE 1132
- #define PW_MSCHAP_PASSWORD 1133
- #define PW_PACKET_TRANSMIT_COUNTER 1134
- #define PW_CACHED_SESSION_POLICY 1135
- #define PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS 1143
- #define PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS 1144
-
- #define PW_OTP_CHALLENGE 1145
- #define PW_EAP_SESSION_ID 1146
+ /*
+ * All internal attributes are now defined in this file.
+ */
+ #include <freeradius-devel/attributes.h>
+#define PW_CHBIND_RESPONSE_CODE 1147
/*
* Integer Translations
*/
void realms_free(void);
REALM *realm_find(char const *name); /* name is from a packet */
REALM *realm_find2(char const *name); /* ... with name taken from realm_find */
- int realms_home_server_add(home_server *home, CONF_SECTION *cs, int dual);
++ int realms_home_server_add(home_server_t *home, CONF_SECTION *cs, int dual);
+ int realms_pool_add(home_pool_t *pool, CONF_SECTION *cs);
+ int realms_realm_add( REALM *r, CONF_SECTION *cs);
+
- void home_server_update_request(home_server *home, REQUEST *request);
- home_server *home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request);
- home_server *home_server_find(fr_ipaddr_t *ipaddr, int port, int proto);
+ void home_server_update_request(home_server_t *home, REQUEST *request);
+ home_server_t *home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request);
+ home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto);
#ifdef WITH_COA
- home_server *home_server_byname(char const *name, int type);
+ home_server_t *home_server_byname(char const *name, int type);
#endif
#ifdef WITH_STATS
- home_server *home_server_bynumber(int number);
+ home_server_t *home_server_bynumber(int number);
#endif
home_pool_t *home_pool_byname(char const *name, int type);
{
}
- int realms_home_server_add(home_server *home, CONF_SECTION *cs, int dual)
+
- if (home->max_outstanding < 8) home->max_outstanding = 8;
- if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16;
-
- if (home->ping_interval < 6) home->ping_interval = 6;
- if (home->ping_interval > 120) home->ping_interval = 120;
++int realms_home_server_add(home_server_t *home, CONF_SECTION *cs, int dual)
+{
+ CONF_SECTION *parent = NULL;
+ const char * name2 = home->name;
+
+ /*
+ * Make sure that this is set.
+ */
+ if (home->src_ipaddr.af == AF_UNSPEC) {
+ home->src_ipaddr.af = home->ipaddr.af;
+ }
+
+ hs_srcipaddr = NULL;
+
+ if (rbtree_finddata(home_servers_byname, home) != NULL) {
+ cf_log_err_cs(cs,
+ "Duplicate home server name %s.", name2);
+ goto error;
+ }
+
+ if (!home->server &&
+ (rbtree_finddata(home_servers_byaddr, home) != NULL)) {
+ cf_log_err_cs(cs,
+ "Duplicate home server IP %s.", name2);
+ goto error;
+ }
+
+ if (!rbtree_insert(home_servers_byname, home)) {
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name2);
+ goto error;
+ }
+
+ if (!home->server &&
+ !rbtree_insert(home_servers_byaddr, home)) {
+ rbtree_deletebydata(home_servers_byname, home);
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name2);
+ goto error;
+ }
+
+#ifdef WITH_STATS
+ home->number = home_server_max_number++;
+ if (!rbtree_insert(home_servers_bynumber, home)) {
+ rbtree_deletebydata(home_servers_byname, home);
+ if (home->ipaddr.af != AF_UNSPEC) {
+ rbtree_deletebydata(home_servers_byname, home);
+ }
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name2);
+ goto error;
+ }
+#endif
+
- if (home->response_window < 1) home->response_window = 1;
- if (home->response_window > 60) home->response_window = 60;
- if (home->response_window > mainconfig.max_request_time) home->response_window = mainconfig.max_request_time;
++ FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, >=, 8);
++ FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, <=, 65536*16);
+
- if (home->zombie_period < 1) home->zombie_period = 1;
- if (home->zombie_period > 120) home->zombie_period = 120;
++ FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, >=, 6);
++ FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, <=, 120);
+
- if (home->zombie_period < home->response_window) {
- home->zombie_period = home->response_window;
++ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, >=, 0, 1000);
++ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=, 60, 0);
++ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=,
++ main_config.max_request_time, 0);
+
- if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3;
- if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10;
++ /*
++ * Track the minimum response window, so that we can
++ * correctly set the timers in process.c
++ */
++ if (timercmp(&main_config.init_delay, &home->response_window, >)) {
++ main_config.init_delay = home->response_window;
+ }
+
- if (home->ping_timeout < 3) home->ping_timeout = 3;
- if (home->ping_timeout > 10) home->ping_timeout = 10;
++ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, 1);
++ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, <=, 120);
++ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, (uint32_t) home->response_window.tv_sec);
++
++ FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, >=, 3);
++ FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, <=, 10);
+
- if (home->revive_interval < 60) home->revive_interval = 60;
- if (home->revive_interval > 3600) home->revive_interval = 3600;
++ FR_INTEGER_BOUND_CHECK("ping_timeout", home->ping_timeout, >=, 3);
++ FR_INTEGER_BOUND_CHECK("ping_timeout", home->ping_timeout, <=, 10);
+
- if (home->coa_irt < 1) home->coa_irt = 1;
- if (home->coa_irt > 5) home->coa_irt = 5;
++ FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, >=, 60);
++ FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, <=, 3600);
+
+#ifdef WITH_COA
- if (home->coa_mrc < 0) home->coa_mrc = 0;
- if (home->coa_mrc > 20 ) home->coa_mrc = 20;
++ FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, >=, 1);
++ FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, <=, 5);
+
- if (home->coa_mrt < 0) home->coa_mrt = 0;
- if (home->coa_mrt > 30 ) home->coa_mrt = 30;
++ FR_INTEGER_BOUND_CHECK("coa_mrc", home->coa_mrc, <=, 20);
+
- if (home->coa_mrd < 5) home->coa_mrd = 5;
- if (home->coa_mrd > 60 ) home->coa_mrd = 60;
++ FR_INTEGER_BOUND_CHECK("coa_mrt", home->coa_mrt, <=, 30);
+
- if (home->limit.max_connections > 1024) home->limit.max_connections = 1024;
++ FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, >=, 5);
++ FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, <=, 60);
+#endif
+
- if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
++ FR_INTEGER_BOUND_CHECK("max_connections", home->limit.max_connections, <=, 1024);
+
+#ifdef WITH_TCP
+ /*
+ * UDP sockets can't be connection limited.
+ */
+ if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
+#endif
+
+ if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
+ home->limit.idle_timeout = 5;
+ if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
+ home->limit.lifetime = 5;
+ if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
+ home->limit.idle_timeout = 0;
+
+ parent = cf_item_parent(cf_sectiontoitem(cs));
- home_server *home2 = rad_malloc(sizeof(*home2));
++ if (strcmp(cf_section_name1(parent), "server") == 0) {
+ home->parent_server = cf_section_name2(parent);
+ }
+
+ if (dual) {
-
++ home_server_t *home2 = talloc(home, home_server_t);
+
+ memcpy(home2, home, sizeof(*home2));
+
+ home2->type = HOME_TYPE_ACCT;
+ home2->port++;
+ home2->ping_user_password = NULL;
+ home2->cs = cs;
+ home2->parent_server = home->parent_server;
+
+ if (!rbtree_insert(home_servers_byname, home2)) {
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name2);
+ free(home2);
+ return 0;
+ }
++
+ if (!home->server &&
+ !rbtree_insert(home_servers_byaddr, home2)) {
+ rbtree_deletebydata(home_servers_byname, home2);
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name2);
+ free(home2);
+ return 0;
+ }
+
+#ifdef WITH_STATS
+ home2->number = home_server_max_number++;
+ if (!rbtree_insert(home_servers_bynumber, home2)) {
+ rbtree_deletebydata(home_servers_byname, home2);
+ if (!home2->server) {
+ rbtree_deletebydata(home_servers_byname, home2);
+ }
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name2);
+ free(home2);
+ return 0;
+ }
+#endif
+ }
+
+ return 1;
+ error:
+ return 0;
+}
+
+
static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
{
char const *name2;
{
listen_socket_t *sock = listener->data;
+ SSL_shutdown(sock->ssn->ssl);
+
++
listener->status = RAD_LISTEN_STATUS_EOL;
listener->tls = NULL; /* parent owns this! */
--- /dev/null
- int rcode = PW_AUTHENTICATION_REJECT;
+/*
+ * eap_chbind.c
+ *
+ * Version: $Id$
+ *
+ * Copyright (c) 2012, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+RCSID("$Id$")
+
+#include "eap_chbind.h"
+
+#define MAX_PACKET_LEN 4096
+
+/*
+ * Process any channel bindings included in the request.
+ */
+CHBIND_REQ *chbind_allocate(void)
+{
+ CHBIND_REQ *ret;
+ ret = malloc(sizeof *ret);
+ if (0 != ret)
+ memset(ret, 0, sizeof *ret);
+ return ret;
+}
+
+void chbind_free(CHBIND_REQ *chbind)
+{
+ /* free the chbind response, if allocated by chbind_process */
+ if (chbind->chbind_resp)
+ free(chbind->chbind_resp);
+
+ free(chbind);
+}
+
+int chbind_process(REQUEST *req, CHBIND_REQ *chbind_req)
+{
- return PW_AUTHENTICATION_REJECT; /* Is this the right response? */
++ int rcode = PW_CODE_AUTHENTICATION_REJECT;
+ REQUEST *fake = NULL;
+ VALUE_PAIR *vp = NULL;
+ uint8_t *attr_data;
+ size_t datalen = 0;
+
+ /* check input parameters */
+ rad_assert((req != NULL) &&
+ (chbind_req != NULL) &&
+ (chbind_req->chbind_req_pkt != NULL));
+ if (chbind_req->chbind_req_len < 4)
- return PW_AUTHENTICATION_ACK;
++ return PW_CODE_AUTHENTICATION_REJECT; /* Is this the right response? */
+
+ /* Set-up NULL response for cases where channel bindings can't be processed */
+ chbind_req->chbind_resp = NULL;
+ chbind_req->chbind_resp_len = 0;
+
+ /* Set-up the fake request */
+ fake = request_alloc_fake(req);
+ rad_assert(fake->packet->vps == NULL);
+ pairmake(fake, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+
+ /* Add the username to the fake request */
+ if (chbind_req->username) {
+ uint8_t *octets = NULL;
+ vp = paircreate(fake, PW_USER_NAME, 0);
+ rad_assert(vp);
+ octets = talloc_array(vp, uint8_t, chbind_req->username_len+1);
+ rad_assert(octets);
+ memcpy(octets, chbind_req->username, chbind_req->username_len);
+ vp->vp_octets = octets;
+ vp->length = chbind_req->username_len;
+
+ pairadd(&fake->packet->vps, vp);
+ fake->username = pairfind(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
+
+ /* Copy the request state into the fake request */
+ /*xxx vp = paircopy(req->state);
+ if (vp)
+ pairadd(&fake->packet->vps, vp);*/
+
+ /* Add the channel binding attributes to the fake packet */
+ if (0 != (datalen = chbind_get_data((CHBIND_PACKET_T *)chbind_req->chbind_req_pkt,
+ chbind_req->chbind_req_len,
+ CHBIND_NSID_RADIUS, &attr_data))) {
+ while(datalen > 0) {
+ int mylen = rad_attr2vp(NULL, NULL, NULL, attr_data, datalen, &vp);
+ if (mylen <= 0) {
+ /* If radaddr2vp fails, return NULL string for
+ channel binding response */
+ request_free(&fake);
- rcode = rad_authenticate(fake);
++ return PW_CODE_AUTHENTICATION_ACK;
+ }
+ /* TODO: need to account for the possibility of rad_attr2vp generating
+ multiple vps */
+ if (vp)
+ pairadd(&fake->packet->vps, vp);
+ attr_data += mylen;
+ datalen -= mylen;
+ }
+ }
+
+ /* Set virtual server based on configuration for channel bindings,
+ this is hard-coded to "chbind" for now */
+ fake->server = "chbind";
+
+ /* Call rad_authenticate */
+ if ((debug_flag > 0) && fr_log_fp) {
+ DEBUG("prcoessing chbind request");
+
+ debug_pair_list(fake->packet->vps);
+
+ fprintf(fr_log_fp, "server %s {\n",
+ (fake->server == NULL) ? "" : fake->server);
+ }
- rcode = PW_AUTHENTICATION_ACK;
++ rcode = rad_virtual_server(fake);
+
+ switch(rcode) {
+ /* If rad_authenticate succeeded, build a reply */
+ case RLM_MODULE_OK:
+ case RLM_MODULE_HANDLED:
+ if ((chbind_req->chbind_resp = chbind_build_response(fake, &chbind_req->chbind_resp_len)) != NULL)
- rcode = PW_AUTHENTICATION_REJECT;
++ rcode = PW_CODE_AUTHENTICATION_ACK;
+ else
- rcode = PW_AUTHENTICATION_REJECT;
++ rcode = PW_CODE_AUTHENTICATION_REJECT;
+ break;
+
+ /* If we got any other response from rad_authenticate, it maps to a reject */
+ default:
++ rcode = PW_CODE_AUTHENTICATION_REJECT;
+ break;
+ }
+
+ request_free(&fake);
+
+ return rcode;
+}
+
+/*
+ * Parse channel binding packet to obtain data for a specific NSID.
+ * See http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.2:
+ */
+
+size_t chbind_get_data(CHBIND_PACKET_T *chbind_packet,
+ size_t chbind_packet_len,
+ int desired_nsid,
+ uint8_t **radbuf_data)
+{
+ size_t chbind_data_len = chbind_packet_len-1;
+ size_t pos=0;
+ if (chbind_packet->code != CHBIND_CODE_REQUEST)
+ return 0;
+ while (pos + 3 < chbind_data_len) {
+ size_t len = (chbind_packet->data[pos] << 8) +
+ chbind_packet->data[pos + 1];
+ uint8_t nsid = chbind_packet->data[pos + 2];
+ if (pos + 3 > chbind_data_len + len) {
+ /* malformed packet; warn here */
+ return 0;
+ }
+ if (nsid == desired_nsid) {
+ *radbuf_data = &chbind_packet->data[pos+3];
+ return len;
+ }
+ pos += 3 + len;
+ }
+ /* didn't find any data matching nsid */
+ if (pos != chbind_data_len) {
+ /* warn about malformed packet */
+ }
+
+ return 0;
+}
+
+uint8_t *chbind_build_response(REQUEST *req, size_t *resp_len)
+{
+ uint8_t *resp;
+ uint16_t pos, len = 0;
+ VALUE_PAIR *vp = NULL;
+
+ *resp_len = 0;
+ resp = malloc(MAX_PACKET_LEN + 4);
+ rad_assert(resp);
+
+ /* Set-up the chbind header fields (except length, computed later) */
+ vp = pairfind(req->config_items, PW_CHBIND_RESPONSE_CODE, 0, TAG_ANY);
+ if (vp)
+ resp[0] = vp->vp_integer;
+ else resp[0] = 3; /*failure*/
+
+
+ resp[3] = CHBIND_NSID_RADIUS;
+
+ if ((debug_flag > 0) && fr_log_fp) {
+ DEBUG("Sending chbind response: code %i\n", (int )(resp[0]));
+ debug_pair_list(req->reply->vps);
+ DEBUG("end chbind response\n");
+ }
+ /* Encode the chbind attributes into the response */
+ for (vp = req->reply->vps, pos = 4;
+ (vp != NULL) && (pos < MAX_PACKET_LEN + 4);
+ pos += len) {
+ len = rad_vp2attr(NULL, NULL, NULL, (const VALUE_PAIR **) &vp, &resp[pos], (MAX_PACKET_LEN + 4) - pos);
+ }
+
+ len = pos-4; /*length covers ns-specific only*/
+ /* Write the length field into the header */
+ resp[1] = (uint8_t)(len >> 8);
+ resp[2] = (uint8_t)(len & 0x00FF);
+
+ /* Output the length of the entire response (attrs + header) */
+ /* If there are no attributes, only send the code*/
+ if (req->reply->vps)
+ *resp_len = len + 4;
+ else *resp_len = 1;
+ return resp;
+}
RCSID("$Id$")
#include "eap_ttls.h"
+#include "eap_chbind.h"
/*
- * 0 1 2 3
+ * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | AVP Code |
+ * | AVP Code |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |V M r r r r r r| AVP Length |
+ * |V M r r r r r r| AVP Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Vendor-ID (opt) |
+ * | Vendor-ID (opt) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Data ...
* +-+-+-+-+-+-+-+-+
uint8_t const *data;
size_t data_len;
REQUEST *request = handler->request;
+ eap_chbind_packet_t *chbind_packet;
+ size_t chbind_len;
- rad_assert(request != NULL);
-
/*
* Just look at the buffer directly, without doing
* record_minus.
}
/*
- if (chbind_rcode != PW_AUTHENTICATION_ACK)
+ * Process channel binding here.
+ */
+ chbind_len = eap_chbind_vp2packet(fake->packet->vps, &chbind_packet);
+ if (chbind_len > 0) {
+ int chbind_rcode;
+ CHBIND_REQ *req = chbind_allocate();
+
+ RDEBUG("received chbind request");
+ req->chbind_req_pkt = (uint8_t *)chbind_packet;
+ req->chbind_req_len = chbind_len;
+ if (fake->username) {
+ req->username = fake->username->vp_octets;
+ req->username_len = fake->username->length;
+ } else {
+ req->username = NULL;
+ req->username_len = 0;
+ }
+ chbind_rcode = chbind_process(request, req);
+
+ /* free the chbind packet; we're done with it */
+ free(chbind_packet);
+
+ /* encapsulate response here */
+ if (req->chbind_resp_len > 0) {
+ RDEBUG("sending chbind response");
+ pairadd(&fake->reply->vps,
+ eap_chbind_packet2vp(fake, (eap_chbind_packet_t *)req->chbind_resp,
+ req->chbind_resp_len));
+ } else {
+ RDEBUG("no chbind response");
+ }
+
+ /* clean up chbind req */
+ chbind_free(req);
+
++ if (chbind_rcode != PW_CODE_AUTHENTICATION_ACK)
+ return chbind_rcode;
+ }
+
+ /*
* Call authentication recursively, which will
* do PAP, CHAP, MS-CHAP, etc.
*/
#define REALM_FORMAT_SUFFIX 1
typedef struct realm_config_t {
- int format;
- char *formatstring;
- char *delim;
- bool ignore_default;
- bool ignore_null;
- char *default_community;
- char *rp_realm;
- char *trust_router;
- unsigned int tr_port;
+ int format;
+ char const *format_string;
+ char const *delim;
+ bool ignore_default;
+ bool ignore_null;
++ char const *default_community;
++ char const *rp_realm;
++ char const *trust_router;
++ unsigned int tr_port;
} realm_config_t;
+#define stringify(s) #s
+
static CONF_PARSER module_config[] = {
- { "format", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,formatstring), NULL, "suffix" },
- { "delimiter", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,delim), NULL, "@" },
- { "ignore_default", PW_TYPE_BOOLEAN,
- offsetof(realm_config_t,ignore_default), NULL, "no" },
- { "ignore_null", PW_TYPE_BOOLEAN,
- offsetof(realm_config_t,ignore_null), NULL, "no" },
- { "default_community", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,default_community), NULL, "none" },
- { "rp_realm", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,rp_realm), NULL, "none" },
- { "trust_router", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,trust_router), NULL, "none" },
- { "tr_port", PW_TYPE_INTEGER,
- offsetof(realm_config_t,tr_port), NULL, "0" },
- // offsetof(realm_config_t,tr_port), NULL, (stringify(TID_PORT)) },
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING, realm_config_t, format_string), "suffix" },
+ { "delimiter", FR_CONF_OFFSET(PW_TYPE_STRING, realm_config_t, delim), "@" },
+ { "ignore_default", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, ignore_default), "no" },
+ { "ignore_null", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, ignore_null), "no" },
++{ "default_community", FR_CONF_OFFSET(PW_TYPE_STRING,
++ realm_config_t,default_community), "none" },
++{ "rp_realm", FR_CONF_OFFSET(PW_TYPE_STRING,
++ realm_config_t,rp_realm), "none" },
++{ "trust_router", FR_CONF_OFFSET(PW_TYPE_STRING,
++ realm_config_t,trust_router), "none" },
++{ "tr_port", FR_CONF_OFFSET(PW_TYPE_INTEGER,
++ realm_config_t,tr_port), "0" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
{
struct realm_config_t *inst = instance;
- if (strcasecmp(inst->formatstring, "suffix") == 0) {
-
+ /* initialize the trust router integration code */
+ if (tr_init() < 0)
+ return -1;
+ if (strcasecmp(inst->format_string, "suffix") == 0) {
inst->format = REALM_FORMAT_SUFFIX;
- } else if (strcasecmp(inst->formatstring, "prefix") == 0) {
+ } else if (strcasecmp(inst->format_string, "prefix") == 0) {
inst->format = REALM_FORMAT_PREFIX;
} else {
realm = realm_find(vp->vp_strvalue + 1);
if (!realm) return RLM_MODULE_NOTFOUND;
+
if (!realm->coa_pool) {
- RDEBUG2("CoA realm is LOCAL.");
+ RDEBUG2("CoA realm is LOCAL");
return RLM_MODULE_OK;
}
--- /dev/null
- home_server *hs,
+#include <trust_router/tid.h>
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include "trustrouter_integ.h"
+#include <trust_router/tr_dh.h>
+#include <freeradius-devel/realms.h>
+
+static TIDC_INSTANCE *global_tidc = NULL;
+
+
+struct resp_opaque {
+ REALM *output_realm;
+ TID_RC result;
+ char err_msg[1024];
+};
+
+
+int tr_init(void)
+{
+ if (NULL == (global_tidc = tidc_create())) {
+ fprintf(stderr, "tr_init: Error creating global TIDC instance.\n");
+ return -1;
+ }
+ if (NULL == (global_tidc->client_dh = tr_create_dh_params(NULL, 0))) {
+ fprintf(stderr, "tr_init: Error creating client DH params.\n");
+ return 1;
+ }
+ return 0;
+}
+
+static fr_tls_server_conf_t *construct_tls( TIDC_INSTANCE *inst,
- home_server *hs = NULL;
++ home_server_t *hs,
+ TID_SRVR_BLK *server)
+{
+ fr_tls_server_conf_t *tls = talloc_zero( hs, fr_tls_server_conf_t);
+ unsigned char *key_buf = NULL;
+ ssize_t keylen;
+ char *hexbuf = NULL;
+ int i;
+
+ if (tls == NULL)
+ goto error;
+ keylen = tr_compute_dh_key(&key_buf, server->aaa_server_dh->pub_key,
+ inst->client_dh);
+ if (keylen <= 0) {
+ DEBUG2("DH error");
+ goto error;
+ }
+ hexbuf = rad_malloc(keylen*2 + 1);
+ if (hexbuf == NULL)
+ goto error;
+ tr_bin_to_hex(key_buf, keylen, hexbuf,
+ 2*keylen + 1);
+ tls->psk_password = hexbuf;
+ tls->psk_identity = tr_name_strdup(server->key_name);
+
+ fprintf (stderr, "construct_tls: Client key generated (key name = %s):\n", tls->psk_identity);
+ for (i = 0; i < keylen; i++) {
+ printf("%.2x", key_buf[i]);
+ }
+ printf("\n");
+
+ tls->cipher_list = strdup("PSK");
+ tls->fragment_size = 4200;
+ tls->ctx = tls_init_ctx(tls, 1);
+ if (tls->ctx == NULL)
+ goto error;
+ memset(key_buf, 0, keylen);
+ free(key_buf);
+ return tls;
+ error:
+ if (key_buf) {
+ memset(key_buf, 0, keylen);
+ free(key_buf);
+ }
+ if (hexbuf) {
+ memset(hexbuf, 0, keylen*2);
+ free(hexbuf);
+ }
+ if (tls)
+ talloc_free(tls);
+ return NULL;
+}
+
+static void tr_response_func( TIDC_INSTANCE *inst,
+ UNUSED TID_REQ *req, TID_RESP *resp,
+ void *cookie)
+{
- pool = rad_malloc(sizeof(*pool) + num_servers *sizeof(home_server *));
++ home_server_t *hs = NULL;
+ TID_SRVR_BLK *server;
+ home_pool_t *pool = NULL;
+ REALM *nr = NULL;
+ char home_pool_name[256];
+ int pool_added = 0;
+ fr_ipaddr_t home_server_ip;
+ struct resp_opaque *opaque = (struct resp_opaque *) cookie;
+ size_t num_servers = 0;
+
+ /*xxx There's a race if this is called in two threads for the
+ same realm. Imagine if the home pool is not found in either
+ thread, is inserted in one thread and then the second
+ thread's insert fails. The second thread will fail. Probably
+ not a huge deal because a retransmit will make the world
+ great again.*/
+ if (resp->result != TID_SUCCESS) {
+ size_t err_msg_len;
+ opaque->result = resp->result;
+ memset(opaque->err_msg, 0, sizeof(opaque->err_msg));
+ if (resp->err_msg) {
+ err_msg_len = resp->err_msg->len+1;
+ if (err_msg_len > sizeof(opaque->err_msg))
+ err_msg_len = sizeof(opaque->err_msg);
+ strlcpy(opaque->err_msg, resp->err_msg->buf, err_msg_len);
+ }
+ return;
+ }
+ server = resp->servers;
+ while (server) {
+ num_servers++;
+ server = server->next;
+ }
+ strlcpy(home_pool_name, "hp-", sizeof(home_pool_name));
+ tr_name_strlcat(home_pool_name, resp->realm, sizeof(home_pool_name));
+ pool = home_pool_byname(home_pool_name, HOME_TYPE_AUTH);
+ if (pool == NULL) {
+ size_t i = 0;
- memset(pool, 0, sizeof(*pool));
++ pool = talloc_zero_size(NULL, sizeof(*pool) + num_servers *sizeof(home_server_t *));
+
+ if (pool == NULL) goto error;
- hs = talloc_zero(NULL, home_server);
+ pool->type = HOME_POOL_CLIENT_PORT_BALANCE;
+ pool->server_type = HOME_TYPE_AUTH;
+ pool->name = strdup(home_pool_name);
+ if (pool->name == NULL) goto error;
+ pool->num_home_servers = num_servers;
+
+ server = resp->servers;
+ while (server) {
+ home_server_ip.af = AF_INET;
+ home_server_ip.scope = 0;
+ home_server_ip.ipaddr.ip4addr = server->aaa_server_addr;
+
+ hs = home_server_find( &home_server_ip, 2083,
+ IPPROTO_TCP);
+ if (hs) {
+ DEBUG2("Found existing home_server %s", hs->name);
+ } else {
+ char nametemp[INET_ADDRSTRLEN];
+ inet_ntop(home_server_ip.af, &home_server_ip.ipaddr, nametemp, sizeof(nametemp));
- memset(hs, 0, sizeof(*hs));
++ hs = talloc_zero(pool, home_server_t);
+ if (!hs) return;
+ hs->type = HOME_TYPE_AUTH;
+ hs->ipaddr = home_server_ip;
+ hs->src_ipaddr.af = home_server_ip.af;
+ hs->name = strdup(nametemp);
+ hs->hostname = strdup(nametemp);
+ hs->port = 2083;
+ hs->proto = IPPROTO_TCP;
+ hs->secret = strdup("radsec");
+ hs->tls = construct_tls(inst, hs, server);
+ if (hs->tls == NULL) goto error;
+ if (!realms_home_server_add(hs, NULL, 0))
+ goto error;
+ }
+ pool->servers[i++] = hs;
+ hs = NULL;
+ server = server->next;
+ }
+
+ if (!realms_pool_add(pool, NULL)) goto error;
+ pool_added = 1;
+ }
+
+ nr = rad_malloc(sizeof (REALM));
+ if (nr == NULL) goto error;
+ memset(nr, 0, sizeof(REALM));
+ nr->name = tr_name_strdup(resp->realm);
+ nr->auth_pool = pool;
+ if (!realms_realm_add(nr, NULL)) goto error;
+ opaque->output_realm = nr;
+
+
+ return;
+
+ error:
+ if (hs)
+ free(hs);
+ if (pool && (!pool_added)) {
+ if (pool->name)
+ free((char *) pool->name);
+ free(pool);
+ }
+ if (nr)
+ free(nr);
+ return;
+}
+
+
+REALM *tr_query_realm(const char *q_realm,
+ const char *q_community,
+ const char *q_rprealm,
+ const char *q_trustrouter,
+ unsigned int q_trport)
+{
+ int conn = 0;
+ int rc;
+ gss_ctx_id_t gssctx;
+ struct resp_opaque *cookie;
+
+ /* clear the cookie structure */
+ cookie = malloc(sizeof(struct resp_opaque));
+ memset (cookie, 0, sizeof(struct resp_opaque));
+
+ /* Set-up TID connection */
+ printf("Openning TIDC connection to %s:%u", q_trustrouter, q_trport);
+ if (-1 == (conn = tidc_open_connection(global_tidc, (char *)q_trustrouter, q_trport, &gssctx))) {
+ /* Handle error */
+ printf("Error in tidc_open_connection.\n");
+ return NULL;
+ };
+
+ /* Send a TID request */
+ if (0 > (rc = tidc_send_request(global_tidc, conn, gssctx, (char *)q_rprealm,
+ (char *) q_realm, (char *)q_community,
+ &tr_response_func, cookie))) {
+ /* Handle error */
+ printf("Error in tidc_send_request, rc = %d.\n", rc);
+ return NULL;
+ }
+
+ return cookie->output_realm;
+}