1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* 2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * hostapd / RADIUS message processing 3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> 4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify 6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as 7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation. 8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license. 11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details. 13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h" 16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h" 18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "radius.h" 19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "md5.h" 20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "crypto.h" 21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_attr_hdr * 24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_get_attr_hdr(struct radius_msg *msg, int idx) 25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]); 27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_msg *radius_msg_new(u8 code, u8 identifier) 31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_msg *msg; 33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg = os_malloc(sizeof(*msg)); 35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL) 36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) { 39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(msg); 40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt radius_msg_set_hdr(msg, code, identifier); 44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return msg; 46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_initialize(struct radius_msg *msg, size_t init_len) 50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL || init_len < sizeof(struct radius_hdr)) 52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(msg, 0, sizeof(*msg)); 55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf = os_zalloc(init_len); 56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->buf == NULL) 57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf_size = init_len; 60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr = (struct radius_hdr *) msg->buf; 61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf_used = sizeof(*msg->hdr); 62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_pos = 64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos)); 65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->attr_pos == NULL) { 66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(msg->buf); 67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf = NULL; 68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr = NULL; 69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; 73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_used = 0; 74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) 80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->code = code; 82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->identifier = identifier; 83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_msg_free(struct radius_msg *msg) 87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(msg->buf); 89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf = NULL; 90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr = NULL; 91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf_size = msg->buf_used = 0; 92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(msg->attr_pos); 94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_pos = NULL; 95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_size = msg->attr_used = 0; 96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const char *radius_code_string(u8 code) 100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (code) { 102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; 103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; 104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; 105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; 106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; 107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; 108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; 109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; 110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_CODE_RESERVED: return "Reserved"; 111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt default: return "?Unknown?"; 112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_attr_type { 117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 type; 118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *name; 119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt enum { 120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, 121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } data_type; 123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}; 124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_attr_type radius_attrs[] = 126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, 128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, 129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, 130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, 131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, 132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, 133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, 134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, 135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, 136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, 137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, 138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", 139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", 141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_TEXT }, 142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", 143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_TEXT }, 144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, 145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, 146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", 147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, 149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", 150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", 152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, 154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, 155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", 156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", 158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", 160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", 162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", 164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_TEXT }, 165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, 166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", 169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", 171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, 173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, 174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", 175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_HEXDUMP }, 176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, 177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, 178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", 179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_UNDIST }, 180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", 181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_HEXDUMP }, 182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", 183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_INT32 }, 184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity", 185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_TEXT }, 186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}; 188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0])) 189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_attr_type *radius_get_attr_type(u8 type) 192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < RADIUS_ATTRS; i++) { 196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (type == radius_attrs[i].type) 197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return &radius_attrs[i]; 198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void print_char(char c) 205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (c >= 32 && c < 127) 207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("%c", c); 208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("<%02x>", c); 210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_type *attr; 216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int i, len; 217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *pos; 218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_get_attr_type(hdr->type); 220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Attribute %d (%s) length=%d\n", 222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr == NULL) 225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = hdr->length - sizeof(struct radius_attr_hdr); 228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (unsigned char *) (hdr + 1); 229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (attr->data_type) { 231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_TEXT: 232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Value: '"); 233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < len; i++) 234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt print_char(pos[i]); 235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("'\n"); 236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_IP: 239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len == 4) { 240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct in_addr addr; 241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(&addr, pos, 4); 242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Value: %s\n", inet_ntoa(addr)); 243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else 244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Invalid IP address length %d\n", len); 245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6 248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_IPV6: 249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len == 16) { 250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char buf[128]; 251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const char *atxt; 252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct in6_addr *addr = (struct in6_addr *) pos; 253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Value: %s\n", atxt ? atxt : "?"); 255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else 256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Invalid IPv6 address length %d\n", len); 257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */ 259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_HEXDUMP: 261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_UNDIST: 262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Value:"); 263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < len; i++) 264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" %02x", pos[i]); 265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("\n"); 266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_INT32: 269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len == 4) 270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Value: %u\n", WPA_GET_BE32(pos)); 271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf(" Invalid INT32 length %d\n", len); 273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt default: 276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_msg_dump(struct radius_msg *msg) 282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", 286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->code, radius_code_string(msg->hdr->code), 287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->identifier, ntohs(msg->hdr->length)); 288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt radius_msg_dump_attr(attr); 292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_finish(struct radius_msg *msg, const u8 *secret, 297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t secret_len) 298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (secret) { 300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 auth[MD5_MAC_LEN]; 301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_msg_add_attr(msg, 305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt auth, MD5_MAC_LEN); 307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr == NULL) { 308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("WARNING: Could not add " 309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Message-Authenticator\n"); 310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->length = htons(msg->buf_used); 313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hmac_md5(secret, secret_len, msg->buf, msg->buf_used, 314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (u8 *) (attr + 1)); 315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else 316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->length = htons(msg->buf_used); 317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->buf_used > 0xffff) { 319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("WARNING: too long RADIUS message (%lu)\n", 320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) msg->buf_used); 321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t secret_len, const u8 *req_authenticator) 329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 auth[MD5_MAC_LEN]; 331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[4]; 333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len[4]; 334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt auth, MD5_MAC_LEN); 338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr == NULL) { 339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("WARNING: Could not add Message-Authenticator\n"); 340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->length = htons(msg->buf_used); 343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, 344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sizeof(msg->hdr->authenticator)); 345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hmac_md5(secret, secret_len, msg->buf, msg->buf_used, 346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (u8 *) (attr + 1)); 347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = (u8 *) msg->hdr; 350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[0] = 1 + 1 + 2; 351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = req_authenticator; 352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[1] = MD5_MAC_LEN; 353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[2] = msg->buf_used - sizeof(*msg->hdr); 355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[3] = secret; 356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[3] = secret_len; 357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(4, addr, len, msg->hdr->authenticator); 358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->buf_used > 0xffff) { 360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("WARNING: too long RADIUS message (%lu)\n", 361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) msg->buf_used); 362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t secret_len) 370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[2]; 372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len[2]; 373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr->length = htons(msg->buf_used); 375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = msg->buf; 377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[0] = msg->buf_used; 378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = secret; 379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[1] = secret_len; 380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->buf_used > 0xffff) { 383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("WARNING: too long RADIUS messages (%lu)\n", 384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) msg->buf_used); 385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int radius_msg_add_attr_to_array(struct radius_msg *msg, 390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr) 391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->attr_used >= msg->attr_size) { 393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t *nattr_pos; 394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int nlen = msg->attr_size * 2; 395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt nattr_pos = os_realloc(msg->attr_pos, 397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt nlen * sizeof(*msg->attr_pos)); 398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (nattr_pos == NULL) 399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_pos = nattr_pos; 402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_size = nlen; 403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf; 406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *data, size_t data_len) 413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t buf_needed; 415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data_len > RADIUS_MAX_ATTR_LEN) { 418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", 419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) data_len); 420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf_needed = msg->buf_used + sizeof(*attr) + data_len; 424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg->buf_size < buf_needed) { 426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* allocate more space for message buffer */ 427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *nbuf; 428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t nlen = msg->buf_size; 429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (nlen < buf_needed) 431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt nlen *= 2; 432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt nbuf = os_realloc(msg->buf, nlen); 433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (nbuf == NULL) 434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf = nbuf; 436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->hdr = (struct radius_hdr *) msg->buf; 437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size); 438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf_size = nlen; 439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used); 442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr->type = type; 443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr->length = sizeof(*attr) + data_len; 444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data_len > 0) 445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(attr + 1, data, data_len); 446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf_used += sizeof(*attr) + data_len; 448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return attr; 453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_msg *radius_msg_parse(const u8 *data, size_t len) 457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_msg *msg; 459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_hdr *hdr; 460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t msg_len; 462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *pos, *end; 463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data == NULL || len < sizeof(*hdr)) 465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr = (struct radius_hdr *) data; 468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg_len = ntohs(hdr->length); 470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg_len < sizeof(*hdr) || msg_len > len) { 471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Invalid RADIUS message length\n"); 472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg_len < len) { 476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Ignored %lu extra bytes after RADIUS message\n", 477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) len - msg_len); 478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg = os_malloc(sizeof(*msg)); 481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL) 482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (radius_msg_initialize(msg, msg_len)) { 485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(msg); 486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(msg->buf, data, msg_len); 490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt msg->buf_size = msg->buf_used = msg_len; 491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* parse attributes */ 493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (unsigned char *) (msg->hdr + 1); 494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = msg->buf + msg->buf_used; 495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos < end) { 496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((size_t) (end - pos) < sizeof(*attr)) 497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto fail; 498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = (struct radius_attr_hdr *) pos; 500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + attr->length > end || attr->length < sizeof(*attr)) 502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto fail; 503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: check that attr->length is suitable for attr->type */ 505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto fail; 508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += attr->length; 510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return msg; 513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fail: 515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt radius_msg_free(msg); 516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(msg); 517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos = data; 524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t left = data_len; 525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (left > 0) { 527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int len; 528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left > RADIUS_MAX_ATTR_LEN) 529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = RADIUS_MAX_ATTR_LEN; 530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = left; 532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos, len)) 535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += len; 538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= len; 539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtu8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len) 546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *eap, *pos; 548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len, i; 549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL) 552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = 0; 555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE) 558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len += attr->length - sizeof(struct radius_attr_hdr); 559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len == 0) 562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt eap = os_malloc(len); 565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (eap == NULL) 566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = eap; 569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE) { 572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int flen = attr->length - sizeof(*attr); 573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(pos, attr + 1, flen); 574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += flen; 575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (eap_len) 579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *eap_len = len; 580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return eap; 582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t secret_len, const u8 *req_auth) 587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 orig_authenticator[16]; 590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr != NULL) { 597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Multiple Message-Authenticator " 598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "attributes in RADIUS message\n"); 599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = tmp; 602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr == NULL) { 606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("No Message-Authenticator attribute found\n"); 607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (req_auth) { 613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sizeof(orig_authenticator)); 615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_auth, 616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sizeof(msg->hdr->authenticator)); 617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth); 619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (req_auth) { 621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sizeof(orig_authenticator)); 623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { 626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Invalid Message-Authenticator!\n"); 627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_verify(struct radius_msg *msg, const u8 *secret, 635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t secret_len, struct radius_msg *sent_msg, int auth) 636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[4]; 638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len[4]; 639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 hash[MD5_MAC_LEN]; 640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sent_msg == NULL) { 642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("No matching Access-Request message found\n"); 643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (auth && 647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt radius_msg_verify_msg_auth(msg, secret, secret_len, 648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sent_msg->hdr->authenticator)) { 649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = (u8 *) msg->hdr; 654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[0] = 1 + 1 + 2; 655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[1] = MD5_MAC_LEN; 657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[2] = msg->buf_used - sizeof(*msg->hdr); 659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[3] = secret; 660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[3] = secret_len; 661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(4, addr, len, hash); 662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Response Authenticator invalid!\n"); 664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 type) 673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int count = 0; 677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < src->attr_used; i++) { 679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_get_attr_hdr(src, i); 680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->type == type) { 681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr->length - sizeof(*attr))) 683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt count++; 685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return count; 689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* Create Request Authenticator. The value should be unique over the lifetime 693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * of the shared secret between authenticator and authentication server. 694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Use one-way MD5 hash calculated from current timestamp and some data given 695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * by the caller. */ 696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_msg_make_authenticator(struct radius_msg *msg, 697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *data, size_t len) 698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct os_time tv; 700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long int l; 701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[3]; 702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t elen[3]; 703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_get_time(&tv); 705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt l = os_random(); 706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = (u8 *) &tv; 707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[0] = sizeof(tv); 708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = data; 709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[1] = len; 710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[2] = (u8 *) &l; 711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[2] = sizeof(l); 712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(3, addr, elen, msg->hdr->authenticator); 713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns the Attribute payload and sets alen to indicate the length of the 718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * payload if a vendor attribute with subtype is found, otherwise returns NULL. 719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * The returned payload is allocated with os_malloc() and caller must free it 720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * by calling os_free(). 721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 subtype, size_t *alen) 724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *data, *pos; 726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i, len; 727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL) 729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t left; 734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u32 vendor_id; 735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_vendor *vhdr; 736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC) 738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = attr->length - sizeof(*attr); 741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left < 4) 742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (u8 *) (attr + 1); 745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(&vendor_id, pos, 4); 747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 4; 748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= 4; 749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ntohl(vendor_id) != vendor) 751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (left >= sizeof(*vhdr)) { 754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (vhdr->vendor_length > left || 756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr->vendor_length < sizeof(*vhdr)) { 757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = 0; 758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (vhdr->vendor_type != subtype) { 761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += vhdr->vendor_length; 762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= vhdr->vendor_length; 763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = vhdr->vendor_length - sizeof(*vhdr); 767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data = os_malloc(len); 768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data == NULL) 769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(data, pos + sizeof(*vhdr), len); 771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (alen) 772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *alen = len; 773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return data; 774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * decrypt_ms_key(const u8 *key, size_t len, 782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *req_authenticator, 783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *secret, size_t secret_len, size_t *reslen) 784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *plain, *ppos, *res; 786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos; 787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t left, plen; 788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 hash[MD5_MAC_LEN]; 789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int i, first = 1; 790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[3]; 791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t elen[3]; 792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* key: 16-bit salt followed by encrypted key info */ 794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len < 2 + 16) 796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = key + 2; 799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = len - 2; 800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (left % 16) { 801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Invalid ms key len %lu\n", (unsigned long) left); 802526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 803526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt plen = left; 806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ppos = plain = os_malloc(plen); 807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (plain == NULL) 808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt plain[0] = 0; 810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (left > 0) { 812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = secret; 816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[0] = secret_len; 817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (first) { 818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = req_authenticator; 819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[1] = MD5_MAC_LEN; 820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[2] = key; 821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[2] = 2; /* Salt */ 822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt elen[1] = MD5_MAC_LEN; 825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(first ? 3 : 2, addr, elen, hash); 827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt first = 0; 828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *ppos++ = *pos++ ^ hash[i]; 831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left -= MD5_MAC_LEN; 832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (plain[0] == 0 || plain[0] > plen - 1) { 835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt printf("Failed to decrypt MPPE key\n"); 836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(plain); 837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = os_malloc(plain[0]); 841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res == NULL) { 842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(plain); 843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(res, plain + 1, plain[0]); 846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (reslen) 847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reslen = plain[0]; 848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(plain); 849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *req_authenticator, 855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *secret, size_t secret_len, 856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *ebuf, size_t *elen) 857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int i, len, first = 1; 859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[3]; 861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t _len[3]; 862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_BE16(saltbuf, salt); 864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = 1 + key_len; 866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len & 0x0f) { 867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = (len & 0xf0) + 16; 868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(ebuf, 0, len); 870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ebuf[0] = key_len; 871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(ebuf + 1, key, key_len); 872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *elen = len; 874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = ebuf; 876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (len > 0) { 877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 878526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 879526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = secret; 880526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _len[0] = secret_len; 881526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (first) { 882526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = req_authenticator; 883526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _len[1] = MD5_MAC_LEN; 884526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[2] = saltbuf; 885526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _len[2] = sizeof(saltbuf); 886526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 887526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 888526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _len[1] = MD5_MAC_LEN; 889526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 890526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(first ? 3 : 2, addr, _len, hash); 891526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt first = 0; 892526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 893526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 894526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ ^= hash[i]; 895526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 896526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len -= MD5_MAC_LEN; 897526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 898526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 899526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 900526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 901526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_ms_mppe_keys * 902526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 903526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *secret, size_t secret_len) 904526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 905526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *key; 906526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t keylen; 907526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_ms_mppe_keys *keys; 908526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 909526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL || sent_msg == NULL) 910526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 911526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 912526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt keys = os_zalloc(sizeof(*keys)); 913526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (keys == NULL) 914526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 915526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 916526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 917526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 918526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &keylen); 919526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (key) { 920526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt keys->send = decrypt_ms_key(key, keylen, 921526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sent_msg->hdr->authenticator, 922526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt secret, secret_len, 923526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &keys->send_len); 924526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(key); 925526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 926526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 927526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 928526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 929526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &keylen); 930526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (key) { 931526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt keys->recv = decrypt_ms_key(key, keylen, 932526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sent_msg->hdr->authenticator, 933526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt secret, secret_len, 934526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &keys->recv_len); 935526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(key); 936526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 937526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 938526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return keys; 939526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 940526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 941526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 942526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_ms_mppe_keys * 943526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 944526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *secret, size_t secret_len) 945526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 946526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *key; 947526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t keylen; 948526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_ms_mppe_keys *keys; 949526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 950526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (msg == NULL || sent_msg == NULL) 951526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 952526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 953526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt keys = os_zalloc(sizeof(*keys)); 954526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (keys == NULL) 955526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 956526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 957526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 958526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt RADIUS_CISCO_AV_PAIR, &keylen); 959526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (key && keylen == 51 && 960526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcmp(key, "leap:session-key=", 17) == 0) { 961526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt keys->recv = decrypt_ms_key(key + 17, keylen - 17, 962526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sent_msg->hdr->authenticator, 963526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt secret, secret_len, 964526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &keys->recv_len); 965526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 966526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(key); 967526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 968526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return keys; 969526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 970526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 971526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 972526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_add_mppe_keys(struct radius_msg *msg, 973526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *req_authenticator, 974526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *secret, size_t secret_len, 975526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *send_key, size_t send_key_len, 976526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *recv_key, size_t recv_key_len) 977526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 978526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr; 979526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 980526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *buf; 981526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_vendor *vhdr; 982526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *pos; 983526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t elen; 984526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int hlen; 985526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u16 salt; 986526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 987526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 988526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 989526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* MS-MPPE-Send-Key */ 990526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 991526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf == NULL) { 992526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 993526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 994526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf; 995526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 996526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += sizeof(vendor_id); 997526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 998526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 999526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (u8 *) (vhdr + 1); 1000526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt salt = os_random() | 0x8000; 1001526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_BE16(pos, salt); 1002526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 1003526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 1004526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt secret_len, pos, &elen); 1005526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1006526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1007526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1008526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, hlen + elen); 1009526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 1010526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr == NULL) { 1011526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1012526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1013526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1014526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* MS-MPPE-Recv-Key */ 1015526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 1016526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf == NULL) { 1017526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1018526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1019526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf; 1020526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1021526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += sizeof(vendor_id); 1022526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 1023526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 1024526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (u8 *) (vhdr + 1); 1025526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt salt ^= 1; 1026526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt WPA_PUT_BE16(pos, salt); 1027526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 1028526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 1029526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt secret_len, pos, &elen); 1030526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1031526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1032526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1033526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, hlen + elen); 1034526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 1035526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr == NULL) { 1036526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1037526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1038526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1039526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 1040526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1041526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1042526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1043526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* Add User-Password attribute to a RADIUS message and encrypt it as specified 1044526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * in RFC 2865, Chap. 5.2 */ 1045526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_attr_hdr * 1046526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_msg_add_attr_user_password(struct radius_msg *msg, 1047526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *data, size_t data_len, 1048526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *secret, size_t secret_len) 1049526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1050526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 buf[128]; 1051526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int padlen, i; 1052526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t buf_len, pos; 1053526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[2]; 1054526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len[2]; 1055526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 hash[16]; 1056526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1057526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data_len > 128) 1058526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1059526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1060526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(buf, data, data_len); 1061526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf_len = data_len; 1062526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1063526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt padlen = data_len % 16; 1064526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (padlen) { 1065526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt padlen = 16 - padlen; 1066526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(buf + data_len, 0, padlen); 1067526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf_len += padlen; 1068526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1069526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1070526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = secret; 1071526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[0] = secret_len; 1072526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = msg->hdr->authenticator; 1073526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[1] = 16; 1074526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(2, addr, len, hash); 1075526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1076526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < 16; i++) 1077526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[i] ^= hash[i]; 1078526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = 16; 1079526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1080526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos < buf_len) { 1081526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = secret; 1082526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[0] = secret_len; 1083526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = &buf[pos - 16]; 1084526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len[1] = 16; 1085526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(2, addr, len, hash); 1086526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1087526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < 16; i++) 1088526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[pos + i] ^= hash[i]; 1089526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1090526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 16; 1091526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1092526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1093526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 1094526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, buf_len); 1095526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1096526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1097526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1098526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 1099526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 1101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i, dlen; 1102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 1104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 1105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (tmp->type == type) { 1106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = tmp; 1107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!attr) 1112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dlen = attr->length - sizeof(*attr); 1115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf) 1116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 1117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return dlen; 1118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 1122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t *len, const u8 *start) 1123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 1125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 1126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 1128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 1129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (tmp->type == type && 1130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (start == NULL || (u8 *) tmp > start)) { 1131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = tmp; 1132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!attr) 1137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *buf = (u8 *) (attr + 1); 1140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *len = attr->length - sizeof(*attr); 1141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 1146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 1148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int count; 1149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (count = 0, i = 0; i < msg->attr_used; i++) { 1151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 1152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->type == type && 1153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr->length >= sizeof(struct radius_attr_hdr) + min_len) 1154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt count++; 1155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return count; 1158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_tunnel_attrs { 1162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int tag_used; 1163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int type; /* Tunnel-Type */ 1164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int medium_type; /* Tunnel-Medium-Type */ 1165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int vlanid; 1166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}; 1167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 1171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @msg: RADIUS message 1172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: VLAN ID for the first tunnel configuration of -1 if none is found 1173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_msg_get_vlanid(struct radius_msg *msg) 1175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 1177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t i; 1178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct radius_attr_hdr *attr = NULL; 1179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *data; 1180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char buf[10]; 1181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t dlen; 1182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(&tunnel, 0, sizeof(tunnel)); 1184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 1186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 1187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data = (const u8 *) (attr + 1); 1188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dlen = attr->length - sizeof(*attr); 1189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->length < 3) 1190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 1191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data[0] >= RADIUS_TUNNEL_TAGS) 1192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun = &tunnel[0]; 1193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 1194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun = &tunnel[data[0]]; 1195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (attr->type) { 1197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_TUNNEL_TYPE: 1198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->length != 6) 1199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->tag_used++; 1201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->type = WPA_GET_BE24(data + 1); 1202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 1204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (attr->length != 6) 1205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->tag_used++; 1207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->medium_type = WPA_GET_BE24(data + 1); 1208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 1210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data[0] < RADIUS_TUNNEL_TAGS) { 1211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data++; 1212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dlen--; 1213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (dlen >= sizeof(buf)) 1215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(buf, data, dlen); 1217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[dlen] = '\0'; 1218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->tag_used++; 1219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->vlanid = atoi(buf); 1220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 1225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun = &tunnel[i]; 1226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (tun->tag_used && 1227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->type == RADIUS_TUNNEL_TYPE_VLAN && 1228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 1229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt tun->vlanid > 0) 1230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return tun->vlanid; 1231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1235