captive: add missing UAM/ACCT/rate features

Fixes: WIFI-10665
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin
2022-09-20 08:41:00 +02:00
parent 708fe70e75
commit cd2fbd11f2
20 changed files with 645 additions and 366 deletions

View File

@@ -97,7 +97,8 @@ static void client_set_id(struct interface *iface, struct client *cl, const char
}
int client_set(struct interface *iface, const void *addr, const char *id,
int state, int dns_state, int accounting, struct blob_attr *data)
int state, int dns_state, int accounting, struct blob_attr *data,
const char *device, bool flush)
{
struct cache_entry *c;
struct blob_attr *cur;
@@ -142,12 +143,21 @@ int client_set(struct interface *iface, const void *addr, const char *id,
kvlist_set(&cl->kvdata, blobmsg_name(cur), cur);
}
if (device)
cl->device = device;
if (state >= 0)
cl->data.cur_class = state;
if (dns_state >= 0)
cl->data.dns_class = dns_state;
if (accounting >= 0)
cl->data.flags = accounting;
if (flush) {
kvlist_free(&cl->kvdata);
cl->data.packets_ul = 0;
cl->data.packets_dl = 0;
cl->data.bytes_ul = 0;
cl->data.bytes_dl = 0;
}
spotfilter_bpf_set_client(iface, &cl->key, &cl->data);
if (new_client)

View File

@@ -17,10 +17,12 @@ struct client {
struct spotfilter_client_key key;
struct spotfilter_client_data data;
const char *device;
};
int client_set(struct interface *iface, const void *addr, const char *id,
int state, int dns_state, int accounting, struct blob_attr *data);
int state, int dns_state, int accounting, struct blob_attr *data,
const char *device, bool flush);
void client_free(struct interface *iface, struct client *cl);
void client_set_ipaddr(const void *mac, const void *addr, bool ipv6);
void client_init_interface(struct interface *iface);

View File

@@ -32,12 +32,6 @@ void interface_free(struct interface *iface)
free(iface);
}
static inline const char *
device_name(struct device *dev)
{
return dev->node.avl.key;
}
static void
interface_check_device(struct interface *iface, struct device *dev)
{

View File

@@ -64,6 +64,11 @@ static inline const char *interface_name(struct interface *iface)
return iface->node.key;
}
static inline const char *device_name(struct device *dev)
{
return dev->node.avl.key;
}
void interface_add(const char *name, struct blob_attr *config,
struct blob_attr *devices);
void interface_free(struct interface *iface);

View File

@@ -155,14 +155,12 @@ nl80211_interface_update(struct interface *iface)
struct client *cl, *tmp;
struct device *dev;
if (!iface->client_autoremove)
return;
avl_for_each_element_safe(&iface->clients, cl, node, tmp) {
if (cl->idle++ < iface->client_timeout)
continue;
client_free(iface, cl);
if (iface->client_autoremove)
client_free(iface, cl);
}
vlist_for_each_element(&iface->devices, dev, node)
@@ -218,7 +216,7 @@ found:
if (cl)
cl->idle = 0;
else if (iface->client_autocreate)
client_set(iface, addr, NULL, -1, -1, -1, NULL);
client_set(iface, addr, NULL, -1, -1, -1, NULL, device_name(dev), false);
return NL_SKIP;
}

View File

@@ -158,9 +158,9 @@ int spotfilter_out(struct __sk_buff *skb)
return TC_ACT_UNSPEC;
cl = bpf_map_lookup_elem(&client, eth->h_dest);
if (cl) {
if (cl->flags & SPOTFILTER_CLIENT_F_ACCT_DL)
cl->bytes_dl += skb->len;
if (cl && (cl->flags & SPOTFILTER_CLIENT_F_ACCT_DL)) {
cl->packets_dl++;
cl->bytes_dl += skb->len;
}
skb_parse_vlan(&info);
@@ -204,8 +204,10 @@ int spotfilter_in(struct __sk_buff *skb)
cl = bpf_map_lookup_elem(&client, eth->h_source);
if (cl) {
cldata = *cl;
if (cl->flags & SPOTFILTER_CLIENT_F_ACCT_UL)
if (cl->flags & SPOTFILTER_CLIENT_F_ACCT_UL) {
cl->packets_ul++;
cl->bytes_ul += skb->len;
}
}
has_vlan = !!skb_parse_vlan(&info);

View File

@@ -19,6 +19,8 @@ struct spotfilter_client_data {
uint8_t dns_class;
uint8_t flags;
uint64_t packets_ul;
uint64_t packets_dl;
uint64_t bytes_ul;
uint64_t bytes_dl;
};

View File

@@ -88,6 +88,7 @@ enum {
CLIENT_ATTR_DNS_STATE,
CLIENT_ATTR_ACCOUNTING,
CLIENT_ATTR_DATA,
CLIENT_ATTR_FLUSH,
__CLIENT_ATTR_MAX
};
@@ -99,6 +100,7 @@ static const struct blobmsg_policy client_policy[__CLIENT_ATTR_MAX] = {
[CLIENT_ATTR_DNS_STATE] = { "dns_state", BLOBMSG_TYPE_INT32 },
[CLIENT_ATTR_ACCOUNTING] = { "accounting", BLOBMSG_TYPE_ARRAY },
[CLIENT_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
[CLIENT_ATTR_FLUSH] = { "flush", BLOBMSG_TYPE_BOOL },
};
static int
@@ -176,6 +178,7 @@ client_ubus_update(struct ubus_context *ctx, struct ubus_object *obj,
const char *id = NULL;
int state = -1, dns_state = -1;
int accounting = -1;
bool flush = false;
int ret;
ret = client_ubus_init(msg, tb, &iface, &addr, &id, &cl);
@@ -203,8 +206,11 @@ client_ubus_update(struct ubus_context *ctx, struct ubus_object *obj,
if (!addr)
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[CLIENT_ATTR_FLUSH])
flush = blobmsg_get_bool(tb[CLIENT_ATTR_FLUSH]);
client_set(iface, addr, id, state, dns_state, accounting,
tb[CLIENT_ATTR_DATA]);
tb[CLIENT_ATTR_DATA], NULL, flush);
return 0;
}
@@ -241,8 +247,10 @@ static void client_dump(struct interface *iface, struct client *cl)
spotfilter_bpf_get_client(iface, &cl->key, &cl->data);
if (iface->client_autoremove)
blobmsg_add_u32(&b, "idle", cl->idle);
if (cl->device)
blobmsg_add_string(&b, "device", cl->device);
blobmsg_add_u32(&b, "idle", cl->idle);
blobmsg_add_u32(&b, "state", cl->data.cur_class);
blobmsg_add_u32(&b, "dns_state", cl->data.dns_class);
@@ -281,6 +289,8 @@ static void client_dump(struct interface *iface, struct client *cl)
interface_dump_action(&b, iface, cl->data.dns_class);
blobmsg_close_table(&b, c);
blobmsg_add_u64(&b, "packets_ul", cl->data.packets_ul);
blobmsg_add_u64(&b, "packets_dl", cl->data.packets_dl);
blobmsg_add_u64(&b, "bytes_ul", cl->data.bytes_ul);
blobmsg_add_u64(&b, "bytes_dl", cl->data.bytes_dl);
}

View File

@@ -18,7 +18,7 @@ endef
define Package/uspot/install
$(INSTALL_DIR) $(1)/usr/bin/ $(1)/usr/lib/ucode
$(INSTALL_BIN) $(PKG_BUILD_DIR)/radius-client $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/radius-client $(1)/usr/bin/radius-client
$(INSTALL_DATA) $(PKG_BUILD_DIR)/libuam.so $(1)/usr/lib/ucode/uam.so
$(CP) ./files/* $(1)
endef

View File

@@ -1,25 +1,6 @@
config uspot config
#option auth_mode 'uam'
#option auth_mode 'radius'
#option auth_mode 'credentials'
option auth_mode 'click-to-continue'
config radius radius
# option auth_server 212.24.98.232
# option auth_port 1812
# option auth_secret secret
config uam uam
# option port 3990
# option nasid AlmondLabs
# option nasmac 903cb3bb25e3
# option server https://customer.hotspotsystem.com/customer/hotspotlogin.php
# option secret hotsys123
#config credential
# option username abc
# option password def
#config credential
# option username 123
# option password 456

View File

@@ -0,0 +1,13 @@
#!/bin/sh /etc/rc.common
START=80
USE_PROCD=1
PROG=/usr/share/uspot/accounting.uc
start_service() {
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn
procd_close_instance
}

View File

@@ -0,0 +1,53 @@
#!/usr/bin/ucode
let ubus = require('ubus').connect();
let uci = require('uci').cursor();
function restart() {
system('/etc/init.d/spotfilter restart');
system('/etc/init.d/uhttpd restart');
}
switch(ARGV[0]) {
case 'dump':
let clients = ubus.call('spotfilter', 'client_list', { interface: 'hotspot'});
printf('%.J\n', clients);
break;
case 'clients':
let clients = ubus.call('spotfilter', 'client_list', { interface: 'hotspot'});
let res = {};
let t = time();
for (let c, val in clients) {
res[c] = {
status: val.state ? 'Authenticated' : 'Garden',
idle: val.idle || 0,
time: val.data.connect ? t - val.data.connect : 0,
ip4addr: val.ip4addr || '',
ip6addr: val.ip6addr || '',
packets_ul: val.packets_ul || 0,
bytes_ul: val.bytes_ul || 0,
packets_dl: val.packets_dl || 0,
bytes_dl: val.bytes_dl || 0,
};
}
printf('%.J\n', res);
break;
case 'remove':
ubus.call('spotfilter', 'client_remove', { interface: 'hotspot', address: ARGV[1] || ''});
break;
case 'restart':
restart();
break;
case 'log':
system('logread -f | grep uspot:');
break;
case 'debugon':
case 'debugoff':
uci.set('uspot', 'config', 'debug', 1);
uci.commit();
restart();
break;
default:
break;
}

View File

@@ -0,0 +1,211 @@
#!/usr/bin/ucode
'use strict';
let fs = require('fs');
let uloop = require('uloop');
let ubus = require('ubus').connect();
let uci = require('uci').cursor();
let config = uci.get_all('uspot');
let clients = {};
let acct_interval = config.radius?.acct_interval || 600;
let idle_timeout = config.config.idle_timeout || 600;
let session_timeout = config.config.session_timeout || 0;
function syslog(mac, msg) {
let log = sprintf('uspot: %s %s', mac, msg);
system('logger ' + log);
warn(log + '\n');
}
function debug(mac, msg) {
if (config.config.debug)
syslog(mac, msg);
}
function get_idle_timeout(mac) {
if (clients[mac])
return clients[mac].idle;
return idle_timeout;
}
function get_session_timeout(mac) {
if (clients[mac]?.session_timeout)
return clients[mac].session_timeout;
return session_timeout;
}
function radius_init(mac, payload) {
for (let key in [ 'server', 'acct_server', 'acct_session', 'client_ip', 'called_station', 'calling_station', 'nas_ip', 'nas_id', 'username' ])
if (clients[mac].radius[key])
payload[key] = clients[mac].radius[key];
return payload;
}
function radius_call(mac, payload) {
let cfg = fs.open('/tmp/acct' + mac + '.json', 'w');
cfg.write(payload);
cfg.close();
system('/usr/bin/radius-client /tmp/acct' + mac + '.json');
}
function radius_stop(mac) {
debug(mac, 'stopping accounting');
let payload = {
acct: true,
acct_type: 8,
terminate_cause: 0,
};
radius_init(mac, payload);
radius_call(mac, payload);
}
function radius_acct(mac, payload) {
let state = ubus.call('spotfilter', 'client_get', {
interface: 'hotspot',
address: mac
});
if (!state) {
return false;
}
payload = radius_init(mac, payload);
payload.acct = true;
payload.session_time = time() - state.data.connect;
payload.output_octets = state.bytes_dl & 0xffffffff;
payload.input_octets = state.bytes_ul & 0xffffffff;
payload.output_gigawords = state.bytes_dl >> 32;
payload.input_gigawords = state.bytes_ul >> 32;
payload.output_packets = state.packets_dl;
payload.input_packets = state.packets_ul;
radius_call(mac, payload);
return true;
}
function radius_idle_time(mac) {
let payload = {
acct_type: 2,
terminate_cause: 4,
};
radius_acct(mac, payload);
}
function radius_session_time(mac) {
let payload = {
acct_type: 2,
terminate_cause: 5,
};
radius_acct(mac, payload);
}
function radius_disconnect(mac) {
let payload = {
acct_type: 2,
terminate_cause: 1,
};
radius_acct(mac, payload);
}
function radius_interim(mac) {
let payload = {
acct_type: 3,
};
if (radius_acct(mac, payload))
debug(mac, 'iterim acct call');
else
syslog(mac, 'failed to sent interim accounting frame\n');
clients[mac].timeout.set(clients[mac].interval);
}
function client_add(mac, state) {
if (state.state != 1)
return;
let interval = (state.data?.radius?.reply['Acct-Interim-Interval'] || acct_interval) * 1000;
let idle = (state.data?.radius?.reply['Idle-Timeout'] || idle_timeout);
let session = (state.data?.radius?.reply['Session-Timeout'] || session_timeout);
let accounting = (config.radius?.acct_server && config.radius?.acct_secret);
clients[mac] = {
accounting,
radius: state.data.radius.request,
interval,
idle,
};
syslog(mac, 'adding client');
if (accounting)
clients[mac].timeout = uloop.timer(interval, () => radius_interim(mac));
}
function client_remove(mac, reason) {
syslog(mac, reason);
if (clients[mac]) {
radius_stop(mac);
if (clients[mac].accounting)
clients[mac].timeout.cancel();
delete clients[mac];
}
ubus.call('spotfilter', 'client_remove', {
interface: "hotspot",
address: mac
});
}
function client_timeout(mac) {
syslog(mac, 'session timeout');
if (clients[mac]) {
radius_stop(mac);
if (clients[mac].accounting)
clients[mac].timeout.cancel();
delete clients[mac];
}
ubus.call('spotfilter', 'client_set', {
interface: "hotspot",
state: 0,
address: mac,
accounting: [],
flush: true,
});
}
uloop.init();
uloop.timer(1000, function() {
let list = ubus.call('spotfilter', 'client_list', { interface: 'hotspot'});
let t = time();
for (let k, v in list)
if (!clients[k])
client_add(k, v);
for (let k, v in clients)
if (!list[k] || !list[k].state) {
radius_disconnect(k);
client_remove(k, 'disconnect event');
}
for (let k, v in list) {
if (v.idle > get_idle_timeout(k)) {
if (clients[k])
radius_idle_time(k);
client_remove(k, 'idle event');
}
let timeout = get_session_timeout(k);
if (timeout && ((t - v.data.connect) > timeout)) {
if (clients[k])
radius_session_time(k);
client_timeout(k);
}
}
this.set(5000);
});
uloop.run();

View File

@@ -26,6 +26,46 @@ return {
header,
footer,
// syslog helper
syslog: function(ctx, msg) {
warn('uspot: ' + ctx.env.REMOTE_ADDR + ' - ' + msg + '\n');
},
debug: function(ctx, msg) {
if (config.config.debug)
this.syslog(ctx, msg);
},
// mac re-formater
format_mac: function(mac) {
switch(config.uam.mac_format) {
case 'aabbccddeeff':
case 'AABBCCDDEEFF':
mac = replace(mac, ':', '');
break;
case 'aa-bb-cc-dd-ee-ff':
case 'AA-BB-CC-DD-EE-FF':
mac = replace(mac, ':', '-');
warn('uspot: ' + ctx.env.REMOTE_ADDR + ' - ' + msg + '\n');
break;
}
switch(config.uam.mac_format) {
case 'aabbccddeeff':
case 'aa-bb-cc-dd-ee-ff':
case 'aa:bb:cc:dd:ee:ff':
mac = lc(mac);
break;
case 'AABBCCDDEEFF':
case 'AA:BB:CC:DD:EE:FF':
case 'AA-BB-CC-DD-EE-FF':
mac = uc(mac);
break;
}
return mac;
},
// wrapper for scraping external tools stdout
fs_popen: function(cmd) {
let stdout = fs.popen(cmd);
@@ -43,45 +83,79 @@ return {
},
// give a client access to the internet
allow_client: function(ctx) {
allow_client: function(ctx, data) {
this.syslog(ctx, 'allow client to pass traffic');
ctx.ubus.call('spotfilter', 'client_set', {
"interface": "hotspot",
"address": replace(ctx.mac, '-', ':'),
"address": ctx.mac,
"state": 1,
"dns_state": 1,
"accounting": [ "dl", "ul"],
"data": {
"connect": time()
... data || {},
"connect": time(),
}
});
if (ctx.query_string.userurl)
include('redir.uc', { redir_location: ctx.query_string.userurl });
else
include('allow.uc', ctx);
//data.radius.reply['WISPr-Bandwidth-Max-Up'] = "20000000";
//data.radius.reply['WISPr-Bandwidth-Max-Down'] = "10000000";
if (data?.radius?.reply && (+data.radius.reply['WISPr-Bandwidth-Max-Up'] && +data.radius.reply['WISPr-Bandwidth-Max-Down']))
ctx.ubus.call('ratelimit', 'client_set', {
device: ctx.device,
address: ctx.mac,
rate_egress: sprintf('%s', data.radius.reply['WISPr-Bandwidth-Max-Down']),
rate_ingress: sprintf('%s', data.radius.reply['WISPr-Bandwidth-Max-Up']),
});
},
// put a client back into pre-auth state
logoff: function(ctx, data) {
this.syslog(ctx, 'logging client off');
ctx.ubus.call('spotfilter', 'client_set', {
interface: 'hotspot',
address: ctx.mac,
state: 0,
dns_state: 1,
accounting: [],
flush: true,
});
include('logoff.uc', ctx);
},
// generate the default radius auth payload
radius_init: function(ctx) {
radius_init: function(ctx, acct_session) {
let math = require('math');
if (!acct_session) {
acct_session = '';
for (let i = 0; i < 16; i++)
acct_session += sprintf('%d', math.rand() % 10);
}
return {
server: sprintf('%s:%s:%s', this.config.radius.auth_server, this.config.radius.auth_port, this.config.radius.auth_secret),
acct_session: "0123456789",
acct_server: sprintf('%s:%s:%s', this.config.radius.acct_server, this.config.radius.acct_port, this.config.radius.acct_secret),
acct_session,
client_ip: ctx.env.REMOTE_ADDR,
called_station: ctx.mac,
calling_station: this.config.uam.nasmac,
called_station: this.config.uam.nasmac,
calling_station: this.format_mac(ctx.mac),
nas_ip: ctx.env.SERVER_ADDR,
nas_id: this.config.uam.nasid
};
},
radius_call: function(ctx, payload) {
let cfg = fs.open('/tmp/' + ctx.mac + '.json', 'w');
let cfg = fs.open('/tmp/auth' + ctx.mac + '.json', 'w');
cfg.write(payload);
cfg.close();
return this.fs_popen('/usr/bin/radius-client /tmp/' + ctx.mac + '.json');
return this.fs_popen('/usr/bin/radius-client /tmp/auth' + ctx.mac + '.json');
},
handle_request: function(env) {
handle_request: function(env, uam) {
let mac;
let form_data = {};
let query_string = {};
@@ -91,25 +165,39 @@ return {
// lookup the peers MAC
let macs = this.rtnl.request(this.rtnl.const.RTM_GETNEIGH, this.rtnl.const.NLM_F_DUMP, { });
for (let m in macs)
if (m.dst == env.REMOTE_HOST)
ctx.mac = replace(m.lladdr, ':', '-');
if (m.dst == env.REMOTE_HOST && m.lladdr)
ctx.mac = m.lladdr;
// if the MAC lookup failed, go to the error page
if (!ctx.mac) {
this.syslog(ctx, 'failed to look up mac');
include('error.uc', ctx);
return NULL;
}
ctx.format_mac = this.format_mac(ctx.mac);
// check if a client is already connected
ctx.ubus = ubus.connect();
let connected = ctx.ubus.call('spotfilter', 'client_get', {
'interface': 'hotspot',
'address': ctx.mac
interface: 'hotspot',
address: ctx.mac,
});
if (connected?.state) {
if (!uam && connected?.state) {
include('connected.uc', ctx);
return NULL;
}
if (!connected.data.ssid) {
let hapd = ctx.ubus.call('hostapd.' + connected.device, 'get_status');
ctx.ubus.call('spotfilter', 'client_set', {
interface: 'hotspot',
address: ctx.mac,
data: {
ssid: hapd.ssid || 'unknown'
}
});
}
ctx.device = connected.device;
ctx.ssid = connected.data.ssid;
// split QUERY_STRING
if (env.QUERY_STRING)

View File

@@ -1,14 +1,4 @@
Status: 200 OK
Status: 302 Found
Location: http://{{env.SERVER_ADDR}}/hotspot/?redir={{env.headers.host}}
Content-Type: text/html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="refresh" content="0; URL=http://{{env.SERVER_ADDR}}/hotspot/?redir={{env.headers.host}}" />
</head>
<body style="background-color: white">
<a style="color: black; font-family: arial, helvetica, sans-serif;" href="http://{{env.SERVER_ADDR}}/hotspot">HotSpot Login</a>
</body>
</html>

View File

@@ -2,7 +2,12 @@
'use strict';
let uci = require('uci').cursor();
let config = uci.get_all('uspot');
global.handle_request = function(env) {
if (env.REMOTE_ADDR && config.config.debug)
warn('uspot: ' + env.REMOTE_ADDR + ' - CPD redirect\n');
include('cpd.uc', { env });
};
%}

View File

@@ -12,10 +12,10 @@ function auth_client(ctx) {
let password;
let payload = portal.radius_init(ctx);
payload.logoff_url = sprintf('http://%s:3990/logoff', ctx.env.SERVER_ADDR);
if (ctx.query_string.username && ctx.query_string.response) {
let challenge = uam.md5(portal.config.uam.challenge, ctx.mac);
let challenge = uam.md5(portal.config.uam.challenge, ctx.format_mac);
payload.type = 'uam-chap-auth';
payload.username = ctx.query_string.username;
payload.chap_password = ctx.query_string.response;
if (portal.config.uam.secret)
@@ -23,24 +23,44 @@ function auth_client(ctx) {
else
payload.chap_challenge = challenge;
} else if (ctx.query_string.username && ctx.query_string.password) {
payload.type = 'uam-auth';
payload.username = ctx.mac;
payload.password = uam.password(uam.md5(portal.config.uam.challenge, ctx.mac), ctx.query_string.password, portal.config.uam.uam_secret);
}
payload.username = ctx.query_string.username;
payload.password = uam.password(uam.md5(portal.config.uam.challenge, ctx.format_mac), ctx.query_string.password, portal.config.uam.uam_secret);
} else
include('error.uc', ctx);
let reply = portal.radius_call(ctx, payload);
if (reply['access-accept']) {
portal.allow_client(ctx);
return;
}
let radius = portal.radius_call(ctx, payload);
if (radius['access-accept']) {
portal.allow_client(ctx, { radius: { reply: radius.reply, request: payload } } );
payload = portal.radius_init(ctx, payload.acct_session);
payload.acct = true;
payload.username = ctx.query_string.username;
payload.acct_type = 1;
portal.radius_call(ctx, payload);
return;
}
include('error.uc', ctx);
}
global.handle_request = function(env) {
let ctx = portal.handle_request(env);
// disconnect client
function deauth_client(ctx) {
portal.logoff(ctx);
}
if (ctx)
global.handle_request = function(env) {
let ctx = portal.handle_request(env, true);
switch (split(ctx.env.REQUEST_URI, '?')[0] || '') {
case '/logon':
auth_client(ctx);
break;
case '/logoff':
deauth_client(ctx);
break;
default:
include('error.uc', ctx);
break;
}
};
%}

View File

@@ -7,6 +7,7 @@ let portal = require('common');
// delegate an initial connection to the correct handler
function request_start(ctx) {
portal.debug(ctx, 'start ' + (portal.config?.config?.auth_mode || '') + ' flow');
switch (portal.config?.config?.auth_mode) {
case 'click-to-continue':
include('click.uc', ctx);
@@ -22,12 +23,14 @@ function request_start(ctx) {
'?res=notyet' +
'&uamip=' + ctx.env.SERVER_ADDR +
'&uamport=' + portal.config.uam.uam_port +
'&challenge=' + portal.uam.md5(portal.config.uam.challenge, ctx.mac) +
'&mac=' + replace(ctx.mac, ':', '-') +
'&challenge=' + portal.uam.md5(portal.config.uam.challenge, ctx.format_mac) +
'&mac=' + ctx.format_mac +
'&ip=' + ctx.env.REMOTE_ADDR +
'&called=' + portal.config.uam.nasmac +
'&nasid=' + portal.config.uam.nasid;
ctx.redir_location += '&md=' + portal.uam.md5(ctx.uam_location, portal.config.uam.uam_secret);
'&nasid=' + portal.config.uam.nasid +
'&ssid=' + ctx.ssid;
if (portal.config.uam.uam_secret)
ctx.redir_location += '&md=' + portal.uam.md5(ctx.redir_location, portal.config.uam.uam_secret);
include('redir.uc', ctx);
return;
default:
@@ -46,6 +49,7 @@ function request_click(ctx) {
// check if a username and password was provided
if (ctx.form_data.accept_terms != 'clicked') {
portal.debug(ctx, 'user did not accept conditions');
request_start({ ...ctx, error: 1 });
return;
}
@@ -62,6 +66,7 @@ function request_credentials(ctx) {
// check if a username and password was provided
if (!ctx.form_data.username || !ctx.form_data.password) {
portal.debug(ctx, 'missing credentials\n');
request_start({ ...ctx, error: 1 });
return;
}
@@ -76,11 +81,12 @@ function request_credentials(ctx) {
ctx.form_data.password != cred.password)
continue;
portal.allow_client(ctx);
portal.allow_client(ctx, { username: ctx.form_data.username });
return;
}
// auth failed
portal.debug(ctx, 'invalid credentials\n');
request_start({ ...ctx, error: 1 });
}
@@ -94,23 +100,25 @@ function request_radius(ctx) {
// check if a username and password was provided
if (!ctx.form_data.username || !ctx.form_data.password) {
portal.debug(ctx, 'missing credentials\n');
request_start({ ...ctx, error: 1 });
return;
}
// trigger the radius auth
let payload = radius_init(ctx);
let payload = portal.radius_init(ctx);
payload.type = 'auth';
payload.username = ctx.form_data.username;
payload.password = ctx.form_data.password;
let reply = portal.radius_call(ctx, payload);
if (reply['access-accept']) {
portal.allow_client(ctx);
let radius = portal.radius_call(ctx, payload);
if (radius['access-accept']) {
portal.allow_client(ctx, { username: ctx.form_data.username, radius: { reply: radius.reply, request: payload } } );
return;
}
// auth failed
portal.debug(ctx, 'invalid credentials\n');
request_start({ ...ctx, error: 1 });
}

View File

@@ -0,0 +1,4 @@
Status: 200 OK
Content-Type: text/html
<h1> You are now logged-off </h1>

View File

@@ -9,8 +9,10 @@
#include <libubox/blobmsg_json.h>
enum {
RADIUS_TYPE,
RADIUS_ACCT,
RADIUS_SERVER,
RADIUS_ACCT_SERVER,
RADIUS_ACCT_TYPE,
RADIUS_USERNAME,
RADIUS_PASSWORD,
RADIUS_CHAP_PASSWORD,
@@ -21,12 +23,23 @@ enum {
RADIUS_CALLING_STATION,
RADIUS_NAS_IP,
RADIUS_NAS_ID,
RADIUS_TERMINATE_CAUSE,
RADIUS_SESSION_TIME,
RADIUS_INPUT_OCTETS,
RADIUS_OUTPUT_OCTETS,
RADIUS_INPUT_GIGAWORDS,
RADIUS_OUTPUT_GIGAWORDS,
RADIUS_INPUT_PACKETS,
RADIUS_OUTPUT_PACKETS,
RADIUS_LOGOFF_URL,
__RADIUS_MAX,
};
static const struct blobmsg_policy radius_policy[__RADIUS_MAX] = {
[RADIUS_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
[RADIUS_ACCT] = { .name = "acct", .type = BLOBMSG_TYPE_BOOL },
[RADIUS_SERVER] = { .name = "server", .type = BLOBMSG_TYPE_STRING },
[RADIUS_ACCT_SERVER] = { .name = "acct_server", .type = BLOBMSG_TYPE_STRING },
[RADIUS_ACCT_TYPE] = { .name = "acct_type", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING },
[RADIUS_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
[RADIUS_CHAP_PASSWORD] = { .name = "chap_password", .type = BLOBMSG_TYPE_STRING },
@@ -37,23 +50,17 @@ static const struct blobmsg_policy radius_policy[__RADIUS_MAX] = {
[RADIUS_CALLING_STATION] = { .name = "calling_station", .type = BLOBMSG_TYPE_STRING },
[RADIUS_NAS_IP] = { .name = "nas_ip", .type = BLOBMSG_TYPE_STRING },
[RADIUS_NAS_ID] = { .name = "nas_id", .type = BLOBMSG_TYPE_STRING },
[RADIUS_TERMINATE_CAUSE] = { .name = "terminate_cause", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_SESSION_TIME] = { .name = "session_time", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_INPUT_OCTETS] = { .name = "input_octets", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_OUTPUT_OCTETS] = { .name = "output_octets", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_INPUT_GIGAWORDS] = { .name = "input_gigawords", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_OUTPUT_GIGAWORDS] = { .name = "output_gigawords", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_INPUT_PACKETS] = { .name = "input_packets", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_OUTPUT_PACKETS] = { .name = "output_packets", .type = BLOBMSG_TYPE_INT32 },
[RADIUS_LOGOFF_URL] = { .name = "logoff_url", .type = BLOBMSG_TYPE_STRING },
};
static struct config {
char *type;
char *server;
char *username;
char *password;
char chap_password[17];
char chap_challenge[16];
char *acct_session;
struct sockaddr_in client_ip;
char *called_station;
char *calling_station;
struct sockaddr_in nas_ip;
char *nas_id;
} config;
static struct blob_buf b = {};
static struct blob_attr *tb[__RADIUS_MAX] = {};
@@ -104,266 +111,158 @@ result(rc_handle const *rh, int accept, VALUE_PAIR *pair)
return accept;
}
static void
config_load(void)
{
if (tb[RADIUS_TYPE])
config.type = blobmsg_get_string(tb[RADIUS_TYPE]);
if (tb[RADIUS_SERVER])
config.server = blobmsg_get_string(tb[RADIUS_SERVER]);
if (tb[RADIUS_USERNAME])
config.username = blobmsg_get_string(tb[RADIUS_USERNAME]);
if (tb[RADIUS_PASSWORD])
config.password = blobmsg_get_string(tb[RADIUS_PASSWORD]);
if (tb[RADIUS_CHAP_PASSWORD]) {
*config.chap_password = '\0';
str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_PASSWORD]), &config.chap_password[1], 16);
}
if (tb[RADIUS_CHAP_CHALLENGE])
str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_CHALLENGE]), config.chap_challenge, 16);
if (tb[RADIUS_ACCT_SESSION])
config.acct_session = blobmsg_get_string(tb[RADIUS_ACCT_SESSION]);
if (tb[RADIUS_CLIENT_IP]) {
inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_CLIENT_IP]), &(config.client_ip.sin_addr));
config.client_ip.sin_addr.s_addr = ntohl(config.client_ip.sin_addr.s_addr);
}
if (tb[RADIUS_CALLED_STATION])
config.called_station = blobmsg_get_string(tb[RADIUS_CALLED_STATION]);
if (tb[RADIUS_CALLING_STATION])
config.calling_station = blobmsg_get_string(tb[RADIUS_CALLING_STATION]);
if (tb[RADIUS_NAS_IP]) {
inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_NAS_IP]), &(config.nas_ip.sin_addr));
config.nas_ip.sin_addr.s_addr = ntohl(config.nas_ip.sin_addr.s_addr);
}
if (tb[RADIUS_NAS_ID])
config.nas_id = blobmsg_get_string(tb[RADIUS_NAS_ID]);
}
static rc_handle *
radius_init(void)
static int
radius(void)
{
VALUE_PAIR *send = NULL, *received;
struct sockaddr_in client_ip = {};
struct sockaddr_in nas_ip = {};
char chap_challenge[16] = {};
char chap_password[17] = {};
rc_handle *rh = rc_new();
uint32_t val;
if (rh == NULL)
return NULL;
return result(rh, 0, NULL);;
rh = rc_config_init(rh);
if (rh == NULL)
return NULL;
return result(rh, 0, NULL);;
rc_add_config(rh, "authserver", config.server, "code", __LINE__);
if (tb[RADIUS_SERVER])
rc_add_config(rh, "authserver", blobmsg_get_string(tb[RADIUS_SERVER]), "code", __LINE__);
if (tb[RADIUS_ACCT_SERVER])
rc_add_config(rh, "acctserver", blobmsg_get_string(tb[RADIUS_ACCT_SERVER]), "code", __LINE__);
rc_add_config(rh, "servers", "/tmp/radius.servers", "code", __LINE__);
rc_add_config(rh, "dictionary", "/etc/radcli/dictionary", "code", __LINE__);
rc_add_config(rh, "radius_timeout", "5", "code", __LINE__);
rc_add_config(rh, "radius_timeout", "2", "code", __LINE__);
rc_add_config(rh, "radius_retries", "1", "code", __LINE__);
rc_add_config(rh, "bindaddr", "*", "code", __LINE__);
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0)
return NULL;
return rh;
}
static int
auth(void)
{
VALUE_PAIR *send = NULL, *received;
rc_handle *rh = NULL;
if (!config.server || !config.username || !config.password)
return result(NULL, 0, NULL);
rh = radius_init();
if (!rh)
return result(NULL, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, config.password, -1, 0) == NULL)
if (tb[RADIUS_ACCT_TYPE]) {
val = blobmsg_get_u32(tb[RADIUS_ACCT_TYPE]);
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_USERNAME])
if (rc_avpair_add(rh, &send, PW_USER_NAME, blobmsg_get_string(tb[RADIUS_USERNAME]), -1, 0) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_PASSWORD])
if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, blobmsg_get_string(tb[RADIUS_PASSWORD]), -1, 0) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_CHAP_PASSWORD]) {
str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_PASSWORD]), &chap_password[1], 16);
if (rc_avpair_add(rh, &send, PW_CHAP_PASSWORD, chap_password, 17, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_CHAP_CHALLENGE]) {
str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_CHALLENGE]), chap_challenge, 16);
if (rc_avpair_add(rh, &send, PW_CHAP_CHALLENGE, chap_challenge, 16, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_ACCT_SESSION])
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, blobmsg_get_string(tb[RADIUS_ACCT_SESSION]), -1, 0) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_CLIENT_IP]) {
inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_CLIENT_IP]), &(client_ip.sin_addr));
client_ip.sin_addr.s_addr = ntohl(client_ip.sin_addr.s_addr);
if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &client_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_CALLED_STATION])
if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, blobmsg_get_string(tb[RADIUS_CALLED_STATION]), -1, 0) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_LOGOFF_URL])
if (rc_avpair_add(rh, &send, 3, blobmsg_get_string(tb[RADIUS_LOGOFF_URL]), -1, 14122) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_CALLING_STATION])
if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, blobmsg_get_string(tb[RADIUS_CALLING_STATION]), -1, 0) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_NAS_IP]) {
inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_NAS_IP]), &(nas_ip.sin_addr));
nas_ip.sin_addr.s_addr = ntohl(nas_ip.sin_addr.s_addr);
if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &nas_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_NAS_ID])
if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, blobmsg_get_string(tb[RADIUS_NAS_ID]), -1, 0) == NULL)
return result(rh, 0, NULL);
if (tb[RADIUS_TERMINATE_CAUSE]) {
val = blobmsg_get_u32(tb[RADIUS_TERMINATE_CAUSE]);
if (rc_avpair_add(rh, &send, PW_ACCT_TERMINATE_CAUSE, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_SESSION_TIME]) {
val = blobmsg_get_u32(tb[RADIUS_SESSION_TIME]);
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_TIME, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_INPUT_OCTETS]) {
val = blobmsg_get_u32(tb[RADIUS_INPUT_OCTETS]);
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_OCTETS, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_OUTPUT_OCTETS]) {
val = blobmsg_get_u32(tb[RADIUS_OUTPUT_OCTETS]);
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_OCTETS, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_INPUT_GIGAWORDS]) {
val = blobmsg_get_u32(tb[RADIUS_INPUT_GIGAWORDS]);
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_GIGAWORDS, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_OUTPUT_GIGAWORDS]) {
val = blobmsg_get_u32(tb[RADIUS_OUTPUT_GIGAWORDS]);
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_GIGAWORDS, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_INPUT_PACKETS]) {
val = blobmsg_get_u32(tb[RADIUS_INPUT_PACKETS]);
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_PACKETS, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
if (tb[RADIUS_OUTPUT_PACKETS]) {
val = blobmsg_get_u32(tb[RADIUS_OUTPUT_PACKETS]);
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_PACKETS, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
}
val = 19;
if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, &val, 4, 0) == NULL)
return result(rh, 0, NULL);
rc_apply_config(rh);
if (rc_auth(rh, 0, send, &received, NULL) == OK_RC)
return result(rh, 1, received);
return result(rh, 0, NULL);
}
static int
uam_auth(void)
{
VALUE_PAIR *send = NULL, *received;
rc_handle *rh = NULL;
if (!config.server || !config.username || !config.password ||
!config.acct_session || !config.called_station ||
!config.calling_station || !config.nas_id)
return result(NULL, 0, NULL);
rh = radius_init();
if (!rh)
return result(NULL, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, config.password, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, config.acct_session, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &config.client_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
//if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, , -1, 0) == NULL)
// return result(rh, 0, NULL);
//if (rc_avpair_add(rh, &send, PW_NAS_PORT, , -1, 0) == NULL)
// return result(rh, 0, NULL);
// if (rc_avpair_add(rh, &send, PW_NAS_PORT_ID_STRING, , -1, 0) == NULL)
// return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, config.called_station, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, config.calling_station, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &config.nas_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, config.nas_id, -1, 0) == NULL)
return result(rh, 0, NULL);
rc_apply_config(rh);
if (rc_auth(rh, 0, send, &received, NULL) == OK_RC)
return result(rh, 1, received);
return result(rh, 0, NULL);
}
static int
uam_chap_auth(void)
{
VALUE_PAIR *send = NULL, *received;
rc_handle *rh = NULL;
if (!config.server || !config.username ||
!config.acct_session || !config.called_station ||
!config.calling_station || !config.nas_id)
return result(NULL, 0, NULL);
rh = radius_init();
if (!rh)
return result(NULL, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CHAP_PASSWORD, config.chap_password, 17, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CHAP_CHALLENGE, config.chap_challenge, 16, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, config.acct_session, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &config.client_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
//if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, , -1, 0) == NULL)
// return result(rh, 0, NULL);
//if (rc_avpair_add(rh, &send, PW_NAS_PORT, , -1, 0) == NULL)
// return result(rh, 0, NULL);
// if (rc_avpair_add(rh, &send, PW_NAS_PORT_ID_STRING, , -1, 0) == NULL)
// return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, config.called_station, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, config.calling_station, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &config.nas_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, config.nas_id, -1, 0) == NULL)
return result(rh, 0, NULL);
rc_apply_config(rh);
if (rc_auth(rh, 0, send, &received, NULL) == OK_RC)
return result(rh, 1, received);
return result(rh, 0, NULL);
}
static int
uam_acct(void)
{
VALUE_PAIR *send = NULL, *received;
rc_handle *rh = NULL;
if (!config.server || !config.username || !config.password ||
!config.acct_session || !config.called_station ||
!config.calling_station || !config.nas_id)
return result(NULL, 0, NULL);
rh = radius_init();
if (!rh)
return result(NULL, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, config.password, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, config.acct_session, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &config.client_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
//if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, , -1, 0) == NULL)
// return result(rh, 0, NULL);
//if (rc_avpair_add(rh, &send, PW_NAS_PORT, , -1, 0) == NULL)
// return result(rh, 0, NULL);
// if (rc_avpair_add(rh, &send, PW_NAS_PORT_ID_STRING, , -1, 0) == NULL)
// return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, config.called_station, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, config.calling_station, -1, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &config.nas_ip.sin_addr, 4, 0) == NULL)
return result(rh, 0, NULL);
if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, config.nas_id, -1, 0) == NULL)
return result(rh, 0, NULL);
rc_apply_config(rh);
if (rc_auth(rh, 0, send, &received, NULL) == OK_RC)
return result(rh, 1, received);
if (tb[RADIUS_ACCT] && blobmsg_get_bool(tb[RADIUS_ACCT])) {
if (rc_acct(rh, 0, send) == OK_RC)
return result(rh, 1, NULL);
} else {
if (rc_auth(rh, 0, send, &received, NULL) == OK_RC)
return result(rh, 1, received);
}
return result(rh, 0, NULL);
}
@@ -380,21 +279,5 @@ main(int argc, char **argv)
blobmsg_parse(radius_policy, __RADIUS_MAX, tb, blob_data(b.head), blob_len(b.head));
config_load();
if (!config.type)
return result(NULL, 0, NULL);
if (!strcmp(config.type, "auth"))
return auth();
if (!strcmp(config.type, "uam-auth"))
return uam_auth();
if (!strcmp(config.type, "uam-chap-auth"))
return uam_chap_auth();
if (!strcmp(config.type, "uam-acct"))
return uam_acct();
return result(NULL, 0, NULL);
return radius();
}