#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/rad_assert.h>
#include "ike_conf.h"
#include "eap.h"
#include "logging_impl.h"
static int rad_load_transforms(struct Protocol *prot,CONF_SECTION *cf);
struct config_transform
{
const char *name;
u_int8_t type;
int exist_flag;
};
enum {
OPT_INTEGRITY = 0x01,
OPT_PRF = 0x02,
OPT_ENCRYPTION = 0x04,
OPT_DHGROUP = 0x08,
OPT_NEEDED = OPT_INTEGRITY | OPT_PRF | OPT_ENCRYPTION | OPT_DHGROUP
};
static struct config_transform config_transforms[] =
{
{"integrity", IKEv2_TRT_INTEGRITY_ALGORITHM, OPT_INTEGRITY},
{"prf", IKEv2_TRT_PSEUDO_RANDOM_FUNCTION, OPT_PRF},
{"encryption", IKEv2_TRT_ENCRYPTION_ALGORITHM, OPT_ENCRYPTION},
{"dhgroup", IKEv2_TRT_DIFFIE_HELLMAN_GROUP, OPT_DHGROUP },
{NULL,0,0}
};
int getusersfile(const char *filename, PAIR_LIST **pair_list, const char *compat_mode_str)
{
int rcode;
PAIR_LIST *users = NULL;
rcode = pairlist_read(filename, &users, 1);
if (rcode < 0) {
return -1;
}
if ((debug_flag) ||
(strcmp(compat_mode_str, "cistron") == 0)) {
PAIR_LIST *entry;
VALUE_PAIR *vp;
int compat_mode = FALSE;
if (strcmp(compat_mode_str, "cistron") == 0) {
compat_mode = TRUE;
}
entry = users;
while (entry) {
if (compat_mode) {
DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...",
filename, entry->lineno,
entry->name);
}
for (vp = entry->check; vp != NULL; vp = vp->next) {
if (vp->operator != T_OP_EQ) {
continue;
}
if (((vp->attribute & ~0xffff) != 0) ||
(vp->attribute < 0x100)) {
if (!compat_mode) {
DEBUG("[%s]:%d WARNING! Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
filename, entry->lineno,
vp->name, vp->name,
entry->name);
} else {
DEBUG("\tChanging '%s =' to '%s =='",
vp->name, vp->name);
}
vp->operator = T_OP_CMP_EQ;
continue;
}
if (compat_mode) {
if ((vp->attribute >= 0x100) &&
(vp->attribute <= 0xffff) &&
(vp->attribute != PW_HINT) &&
(vp->attribute != PW_HUNTGROUP_NAME)) {
DEBUG("\tChanging '%s =' to '%s +='",
vp->name, vp->name);
vp->operator = T_OP_ADD;
} else {
DEBUG("\tChanging '%s =' to '%s =='",
vp->name, vp->name);
vp->operator = T_OP_CMP_EQ;
}
}
}
for (vp = entry->reply; vp != NULL; vp = vp->next) {
if (!(vp->attribute & ~0xffff) &&
(vp->attribute > 0xff) &&
(vp->attribute > 1000)) {
log_debug("[%s]:%d WARNING! Check item \"%s\"\n"
"\tfound in reply item list for user \"%s\".\n"
"\tThis attribute MUST go on the first line"
" with the other check items",
filename, entry->lineno, vp->name,
entry->name);
}
}
entry = entry->next;
}
}
*pair_list = users;
return 0;
}
int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf)
{
rad_assert(i2!=NULL && cf!=NULL);
CONF_SECTION *cf_prop=NULL;
cf=cf_subsection_find_next(cf,NULL,"proposals");
if(!cf) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Can't find proposals section");
return -1;
}
int nprop=0;
for(
cf_prop=cf_subsection_find_next(cf,NULL,"proposal");
cf_prop;
cf_prop=cf_subsection_find_next(cf,cf_prop,"proposal")
) {
nprop++;
struct Proposal *prop;
struct Protocol *prot;
prop=AddProposal(&i2->suppProp);
prot=AddProtocol(prop,IKEv2_PID_IKE_SA,0,0);
if(rad_load_transforms(prot,cf_prop)) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Failed to load proposal (%d)",
nprop);
return -1;
}
}
if(!nprop) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Can't find any proposal");
return -1;
}
return 0;
}
static int rad_load_transforms(struct Protocol *prot,CONF_SECTION *cf)
{
rad_assert(prot!=NULL && cf!=NULL);
radlog(L_DBG,IKEv2_LOG_PREFIX "Begin load transforms");
CONF_PAIR *cp;
int option_exists=0;
int i=0;
while(config_transforms[i].name) {
uint8_t id;
uint16_t keylen;
for(
cp=cf_pair_find(cf,config_transforms[i].name);
cp;
cp=cf_pair_find_next(cf,cp,config_transforms[i].name)
) {
if(TransformFromName(cf_pair_value(cp),config_transforms[i].type,&id,&keylen)) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Unsupported %s transform: %s ",
config_transforms[i].name,cf_pair_value(cp));
return -1;
}
if(!AddTransform(prot,config_transforms[i].type,id,keylen)) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Problem with transform %s:%s",
config_transforms[i].name,cf_pair_value(cp));
return -1;
}
option_exists|=config_transforms[i].exist_flag;
}
i++;
}
if((option_exists & OPT_NEEDED) != OPT_NEEDED ) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Not all mandatory transforms are set properly");
radlog(L_DBG,IKEv2_LOG_PREFIX "Option flags: 0x%02X",option_exists);
return -1;
}
return 0;
}
void rad_update_shared_seclist(struct sharedSecList **list,char *id,VALUE_PAIR *items,int default_client_authtype)
{
rad_assert(list && id);
char *secret=NULL;
int id_type=0;
int authtype=default_client_authtype;
if(items) {
VALUE_PAIR *vp;
vp=pairfind(items,RAD_EAP_IKEV2_IDTYPE);
if(!vp) {
radlog(L_DBG,IKEv2_LOG_PREFIX "[%s] -- Id type not set",id);
} else {
if(!(id_type=vp->lvalue)) {
radlog(L_DBG,IKEv2_LOG_PREFIX "[%s] -- Not valid id type",id);
}
}
vp=pairfind(items,RAD_EAP_IKEV2_SECRET);
if(!vp || !vp->length) {
radlog(L_DBG,IKEv2_LOG_PREFIX "[%s] -- Secret not set",id);
} else {
secret=vp->vp_strvalue;
}
vp=pairfind(items,RAD_EAP_IKEV2_AUTHTYPE);
if(vp && vp->length) {
authtype=AuthtypeFromName(vp->vp_strvalue);
if(authtype==-1) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Unsupported 'EAP-IKEv2-AuthType' value (%s),using 'both'",vp->vp_strvalue);
authtype=IKEv2_AUTH_BOTH;
}
}
AddSharedSec(list,id_type,id,secret,authtype);
} else {
AddSharedSec(list,0,id,NULL,default_client_authtype);
}
}
int rad_load_credentials(ikev2_ctx *i2,char *filename,char *authtype_name)
{
rad_assert(i2 && filename && authtype_name);
int authtype;
authtype=AuthtypeFromName(authtype_name);
if(authtype==-1) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Unsupported 'default_auth_type' value (%s), using both",authtype_name);
authtype=IKEv2_AUTH_BOTH;
}
PAIR_LIST *users=NULL;
if(getusersfile(filename,&users,"no")!=0) {
radlog(L_ERR,IKEv2_LOG_PREFIX "Error while loading %s userfile",filename);
return -1;
}
PAIR_LIST *tusers=users;
while(tusers) {
if(strcmp(tusers->name,"DEFAULT")) {
rad_update_shared_seclist(&i2->sslist,tusers->name,tusers->check,authtype);
}
tusers=tusers->next;
}
pairlist_free(&users);
return 0;
}
int rad_get_authtype(char* authtype_name)
{
rad_assert(authtype_name);
if(!strcmp(authtype_name,"cert")) {
radlog(L_DBG,IKEv2_LOG_PREFIX "Using server auth type: cert");
return IKEv2_AUTH_CERT;
}
if(!strcmp(authtype_name,"secret")) {
radlog(L_DBG,IKEv2_LOG_PREFIX "Using server auth type: secret");
return IKEv2_AUTH_SK;
}
radlog(L_AUTH,IKEv2_LOG_PREFIX "Unsupported server auth type: %s",authtype_name);
radlog(L_AUTH,IKEv2_LOG_PREFIX "Using server auth type: secret (default)");
return IKEv2_AUTH_SK;
}
int file_exists(char *filename)
{
int result=0;
FILE *fp=fopen(filename,"r");
if(fp) {
result=1;
fclose(fp);
}
return result;
}