#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
#include <freeradius-devel/dhcp.h>
#include <freeradius-devel/soh.h>
typedef struct rlm_soh_t {
const char *xlat_name;
int dhcp;
} rlm_soh_t;
static size_t soh_xlat(UNUSED void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, UNUSED RADIUS_ESCAPE_STRING func) {
VALUE_PAIR* vp[6];
const char *osname;
vp[0] = pairfind(request->packet->vps, 2119);
if (!vp[0])
return 0;
if (strncasecmp(fmt, "OS", 2) == 0) {
vp[0] = pairfind(request->packet->vps, 2100);
vp[1] = pairfind(request->packet->vps, 2101);
vp[2] = pairfind(request->packet->vps, 2102);
vp[3] = pairfind(request->packet->vps, 2103);
vp[4] = pairfind(request->packet->vps, 2104);
vp[5] = pairfind(request->packet->vps, 2105);
if (vp[0] && vp[0]->vp_integer == 311) {
if (!vp[1]) {
snprintf(out, outlen, "Windows unknown");
} else {
switch (vp[1]->vp_integer) {
case 7:
osname = "7";
break;
case 6:
osname = "Vista";
break;
case 5:
osname = "XP";
break;
default:
osname = "Other";
break;
}
snprintf(out, outlen, "Windows %s %d.%d.%d sp %d.%d", osname, vp[1]->vp_integer,
vp[2] ? vp[2]->vp_integer : 0,
vp[3] ? vp[3]->vp_integer : 0,
vp[4] ? vp[4]->vp_integer : 0,
vp[5] ? vp[5]->vp_integer : 0
);
}
return strlen(out);
}
}
return 0;
}
static const CONF_PARSER module_config[] = {
{ "dhcp", PW_TYPE_BOOLEAN, offsetof(rlm_soh_t,dhcp), NULL, "no" },
{ NULL, -1, 0, NULL, NULL }
};
static int soh_detach(void *instance) {
rlm_soh_t *inst = instance;
if (inst->xlat_name) {
xlat_unregister(inst->xlat_name, soh_xlat);
free(inst->xlat_name);
}
free(instance);
return 0;
}
static int soh_instantiate(CONF_SECTION *conf, void **instance) {
rlm_soh_t *inst;
inst = *instance = rad_malloc(sizeof(*inst));
if (!inst) {
return -1;
}
memset(inst, 0, sizeof(*inst));
if (cf_section_parse(conf, inst, module_config) < 0) {
free(inst);
return -1;
}
inst->xlat_name = cf_section_name2(conf);
if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
inst->xlat_name = strdup(inst->xlat_name);
xlat_register(inst->xlat_name, soh_xlat, inst);
return 0;
}
static int soh_postauth(UNUSED void * instance, REQUEST *request)
{
#ifdef WITH_DHCP
int rcode;
VALUE_PAIR *vp;
vp = pairfind(request->packet->vps, DHCP2ATTR(43));
if (vp) {
uint8_t vopt, vlen, *data;
data = vp->vp_octets;
while (data < vp->vp_octets + vp->length) {
vopt = *data++;
vlen = *data++;
switch (vopt) {
case 220:
if (vlen <= 1) {
RDEBUG("SoH adding NAP marker to DHCP reply");
vp = paircreate(DHCP2ATTR(43), PW_TYPE_OCTETS);
vp->vp_octets[0] = 220;
vp->vp_octets[1] = 3;
vp->vp_octets[4] = 'N';
vp->vp_octets[3] = 'A';
vp->vp_octets[2] = 'P';
vp->length = 5;
pairadd(&request->reply->vps, vp);
} else {
RDEBUG("SoH decoding NAP from DHCP request");
rcode = soh_verify(request, request->packet->vps, data, vlen);
if (rcode < 0) {
return RLM_MODULE_FAIL;
}
}
break;
default:
break;
}
data += vlen;
}
return RLM_MODULE_OK;
}
#endif
return RLM_MODULE_NOOP;
}
static int soh_authorize(UNUSED void * instance, REQUEST *request)
{
VALUE_PAIR *vp;
int rv;
vp = pairfind(request->packet->vps, (311 << 16) | 55);
if (!vp) {
RDEBUG("SoH radius VP not found");
return RLM_MODULE_NOOP;
}
RDEBUG("SoH radius VP found");
rv = soh_verify(request, request->packet->vps, vp->vp_octets, vp->length);
if (rv < 0) {
return RLM_MODULE_FAIL;
}
return RLM_MODULE_OK;
}
module_t rlm_soh = {
RLM_MODULE_INIT,
"SoH",
RLM_TYPE_THREAD_SAFE,
soh_instantiate,
soh_detach,
{
NULL,
soh_authorize,
NULL,
NULL,
NULL,
NULL,
NULL,
soh_postauth
},
};