Return to eap_radius_xauth.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / eap_radius |
1.1 misho 1: /* 2: * Copyright (C) 2013 Martin Willi 3: * Copyright (C) 2013 revosec AG 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "eap_radius_xauth.h" 17: #include "eap_radius_plugin.h" 18: #include "eap_radius.h" 19: #include "eap_radius_forward.h" 20: 21: #include <daemon.h> 22: #include <radius_client.h> 23: #include <collections/array.h> 24: 25: 26: typedef struct private_eap_radius_xauth_t private_eap_radius_xauth_t; 27: typedef struct xauth_round_t xauth_round_t; 28: 29: /** 30: * Configuration for an XAuth authentication exchange 31: */ 32: struct xauth_round_t { 33: /** XAuth message type to send */ 34: configuration_attribute_type_t type; 35: /** Message to present to user */ 36: char *message; 37: }; 38: 39: /** 40: * Private data of an eap_radius_xauth_t object. 41: */ 42: struct private_eap_radius_xauth_t { 43: 44: /** 45: * Public interface. 46: */ 47: eap_radius_xauth_t public; 48: 49: /** 50: * ID of the server 51: */ 52: identification_t *server; 53: 54: /** 55: * ID of the peer 56: */ 57: identification_t *peer; 58: 59: /** 60: * RADIUS connection 61: */ 62: radius_client_t *client; 63: 64: /** 65: * XAuth authentication rounds, as xauth_round_t 66: */ 67: array_t *rounds; 68: 69: /** 70: * XAuth round currently in progress 71: */ 72: xauth_round_t round; 73: 74: /** 75: * Concatenated password of all rounds 76: */ 77: chunk_t pass; 78: }; 79: 80: /** 81: * Fetch next XAuth round, add attributes to CP payload 82: */ 83: static bool build_round(private_eap_radius_xauth_t *this, cp_payload_t *cp) 84: { 85: if (!array_remove(this->rounds, ARRAY_HEAD, &this->round)) 86: { 87: return FALSE; 88: } 89: cp->add_attribute(cp, configuration_attribute_create_chunk( 90: PLV1_CONFIGURATION_ATTRIBUTE, this->round.type, chunk_empty)); 91: 92: if (this->round.message && strlen(this->round.message)) 93: { 94: cp->add_attribute(cp, configuration_attribute_create_chunk( 95: PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_MESSAGE, 96: chunk_from_str(this->round.message))); 97: } 98: return TRUE; 99: } 100: 101: METHOD(xauth_method_t, initiate, status_t, 102: private_eap_radius_xauth_t *this, cp_payload_t **out) 103: { 104: cp_payload_t *cp; 105: 106: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); 107: /* first message always comes with username */ 108: cp->add_attribute(cp, configuration_attribute_create_chunk( 109: PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty)); 110: 111: if (build_round(this, cp)) 112: { 113: *out = cp; 114: return NEED_MORE; 115: } 116: cp->destroy(cp); 117: return FAILED; 118: } 119: 120: /** 121: * Verify a password using RADIUS User-Name/User-Password attributes 122: */ 123: static status_t verify_radius(private_eap_radius_xauth_t *this) 124: { 125: radius_message_t *request, *response; 126: status_t status = FAILED; 127: 128: request = radius_message_create(RMC_ACCESS_REQUEST); 129: request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer)); 130: request->add(request, RAT_USER_PASSWORD, this->pass); 131: 132: eap_radius_build_attributes(request); 133: eap_radius_forward_from_ike(request); 134: 135: response = this->client->request(this->client, request); 136: if (response) 137: { 138: eap_radius_forward_to_ike(response); 139: switch (response->get_code(response)) 140: { 141: case RMC_ACCESS_ACCEPT: 142: eap_radius_process_attributes(response); 143: status = SUCCESS; 144: break; 145: case RMC_ACCESS_CHALLENGE: 146: DBG1(DBG_IKE, "RADIUS Access-Challenge not supported"); 147: /* FALL */ 148: case RMC_ACCESS_REJECT: 149: default: 150: DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed", 151: this->peer); 152: break; 153: } 154: response->destroy(response); 155: } 156: else 157: { 158: eap_radius_handle_timeout(NULL); 159: } 160: request->destroy(request); 161: return status; 162: } 163: 164: METHOD(xauth_method_t, process, status_t, 165: private_eap_radius_xauth_t *this, cp_payload_t *in, cp_payload_t **out) 166: { 167: configuration_attribute_t *attr; 168: enumerator_t *enumerator; 169: identification_t *id; 170: cp_payload_t *cp; 171: chunk_t user = chunk_empty, pass = chunk_empty; 172: 173: enumerator = in->create_attribute_enumerator(in); 174: while (enumerator->enumerate(enumerator, &attr)) 175: { 176: if (attr->get_type(attr) == XAUTH_USER_NAME) 177: { 178: user = attr->get_chunk(attr); 179: } 180: else if (attr->get_type(attr) == this->round.type) 181: { 182: pass = attr->get_chunk(attr); 183: /* trim password to any null termination. As User-Password 184: * uses null padding, we can't have any null in it, and some 185: * clients actually send null terminated strings (Android). */ 186: pass.len = strnlen(pass.ptr, pass.len); 187: } 188: } 189: enumerator->destroy(enumerator); 190: 191: if (!pass.ptr) 192: { 193: DBG1(DBG_IKE, "peer did not respond to our XAuth %N request", 194: configuration_attribute_type_names, this->round.type); 195: return FAILED; 196: } 197: this->pass = chunk_cat("mc", this->pass, pass); 198: if (user.len) 199: { 200: id = identification_create_from_data(user); 201: if (!id) 202: { 203: DBG1(DBG_IKE, "failed to parse provided XAuth username"); 204: return FAILED; 205: } 206: this->peer->destroy(this->peer); 207: this->peer = id; 208: } 209: 210: if (array_count(this->rounds) == 0) 211: { 212: return verify_radius(this); 213: } 214: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST); 215: if (build_round(this, cp)) 216: { 217: *out = cp; 218: return NEED_MORE; 219: } 220: cp->destroy(cp); 221: return FAILED; 222: } 223: 224: METHOD(xauth_method_t, get_identity, identification_t*, 225: private_eap_radius_xauth_t *this) 226: { 227: return this->peer; 228: } 229: 230: /** 231: * Parse XAuth round configuration 232: */ 233: static bool parse_rounds(private_eap_radius_xauth_t *this, char *profile) 234: { 235: struct { 236: char *str; 237: configuration_attribute_type_t type; 238: } map[] = { 239: { "password", XAUTH_USER_PASSWORD, }, 240: { "passcode", XAUTH_PASSCODE, }, 241: { "nextpin", XAUTH_NEXT_PIN, }, 242: { "answer", XAUTH_ANSWER, }, 243: }; 244: enumerator_t *enumerator; 245: char *type, *message; 246: xauth_round_t round; 247: int i; 248: 249: if (!profile || strlen(profile) == 0) 250: { 251: /* no config, fallback to password */ 252: round.type = XAUTH_USER_PASSWORD; 253: round.message = NULL; 254: array_insert(this->rounds, ARRAY_TAIL, &round); 255: return TRUE; 256: } 257: 258: enumerator = lib->settings->create_key_value_enumerator(lib->settings, 259: "%s.plugins.eap-radius.xauth.%s", lib->ns, profile); 260: while (enumerator->enumerate(enumerator, &type, &message)) 261: { 262: bool invalid = TRUE; 263: 264: for (i = 0; i < countof(map); i++) 265: { 266: if (strcaseeq(map[i].str, type)) 267: { 268: round.type = map[i].type; 269: round.message = message; 270: array_insert(this->rounds, ARRAY_TAIL, &round); 271: invalid = FALSE; 272: break; 273: } 274: } 275: if (invalid) 276: { 277: DBG1(DBG_CFG, "invalid XAuth round type: '%s'", type); 278: enumerator->destroy(enumerator); 279: return FALSE; 280: } 281: } 282: enumerator->destroy(enumerator); 283: 284: if (array_count(this->rounds) == 0) 285: { 286: DBG1(DBG_CFG, "XAuth configuration profile '%s' invalid", profile); 287: return FALSE; 288: } 289: return TRUE; 290: } 291: 292: METHOD(xauth_method_t, destroy, void, 293: private_eap_radius_xauth_t *this) 294: { 295: DESTROY_IF(this->client); 296: chunk_clear(&this->pass); 297: array_destroy(this->rounds); 298: this->server->destroy(this->server); 299: this->peer->destroy(this->peer); 300: free(this); 301: } 302: 303: /* 304: * Described in header. 305: */ 306: eap_radius_xauth_t *eap_radius_xauth_create_server(identification_t *server, 307: identification_t *peer, 308: char *profile) 309: { 310: private_eap_radius_xauth_t *this; 311: 312: INIT(this, 313: .public = { 314: .xauth_method = { 315: .initiate = _initiate, 316: .process = _process, 317: .get_identity = _get_identity, 318: .destroy = _destroy, 319: }, 320: }, 321: .server = server->clone(server), 322: .peer = peer->clone(peer), 323: .client = eap_radius_create_client(), 324: .rounds = array_create(sizeof(xauth_round_t), 0), 325: ); 326: 327: if (!parse_rounds(this, profile)) 328: { 329: destroy(this); 330: return NULL; 331: } 332: if (!this->client) 333: { 334: destroy(this); 335: return NULL; 336: } 337: return &this->public; 338: }