/* $NetBSD: isakmp_cfg.c,v 1.12.6.4 2008/11/27 15:25:20 vanhu Exp $ */
|
|
/* Id: isakmp_cfg.c,v 1.55 2006/08/22 18:17:17 manubsd Exp */
|
|
/*
|
* Copyright (C) 2004-2006 Emmanuel Dreyfus
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions
|
* are met:
|
* 1. Redistributions of source code must retain the above copyright
|
* notice, this list of conditions and the following disclaimer.
|
* 2. Redistributions in binary form must reproduce the above copyright
|
* notice, this list of conditions and the following disclaimer in the
|
* documentation and/or other materials provided with the distribution.
|
* 3. Neither the name of the project nor the names of its contributors
|
* may be used to endorse or promote products derived from this software
|
* without specific prior written permission.
|
*
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* SUCH DAMAGE.
|
*/
|
|
#include "config.h"
|
|
#include <sys/types.h>
|
#include <sys/param.h>
|
#include <sys/socket.h>
|
#include <sys/queue.h>
|
|
#ifndef ANDROID_PATCHED
|
#include <utmp.h>
|
#endif
|
#if defined(__APPLE__) && defined(__MACH__)
|
#include <util.h>
|
#endif
|
|
#ifdef __FreeBSD__
|
# include <libutil.h>
|
#endif
|
#ifdef __NetBSD__
|
# include <util.h>
|
#endif
|
|
#include <netinet/in.h>
|
#include <arpa/inet.h>
|
|
#include <stdlib.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <errno.h>
|
#if TIME_WITH_SYS_TIME
|
# include <sys/time.h>
|
# include <time.h>
|
#else
|
# if HAVE_SYS_TIME_H
|
# include <sys/time.h>
|
# else
|
# include <time.h>
|
# endif
|
#endif
|
#include <netdb.h>
|
#ifdef HAVE_UNISTD_H
|
#include <unistd.h>
|
#endif
|
#if HAVE_STDINT_H
|
#include <stdint.h>
|
#endif
|
#include <ctype.h>
|
#include <resolv.h>
|
|
#ifdef HAVE_LIBRADIUS
|
#include <sys/utsname.h>
|
#include <radlib.h>
|
#endif
|
|
#include "var.h"
|
#include "misc.h"
|
#include "vmbuf.h"
|
#include "plog.h"
|
#include "sockmisc.h"
|
#include "schedule.h"
|
#include "debug.h"
|
|
#include "isakmp_var.h"
|
#include "isakmp.h"
|
#include "handler.h"
|
#include "evt.h"
|
#include "throttle.h"
|
#include "remoteconf.h"
|
#include "crypto_openssl.h"
|
#include "isakmp_inf.h"
|
#include "isakmp_xauth.h"
|
#include "isakmp_unity.h"
|
#include "isakmp_cfg.h"
|
#include "strnames.h"
|
#include "admin.h"
|
#include "privsep.h"
|
|
struct isakmp_cfg_config isakmp_cfg_config;
|
|
static vchar_t *buffer_cat(vchar_t *s, vchar_t *append);
|
static vchar_t *isakmp_cfg_net(struct ph1handle *, struct isakmp_data *);
|
#if 0
|
static vchar_t *isakmp_cfg_void(struct ph1handle *, struct isakmp_data *);
|
#endif
|
static vchar_t *isakmp_cfg_addr4(struct ph1handle *,
|
struct isakmp_data *, in_addr_t *);
|
static void isakmp_cfg_getaddr4(struct isakmp_data *, struct in_addr *);
|
static vchar_t *isakmp_cfg_addr4_list(struct ph1handle *,
|
struct isakmp_data *, in_addr_t *, int);
|
static void isakmp_cfg_appendaddr4(struct isakmp_data *,
|
struct in_addr *, int *, int);
|
static void isakmp_cfg_getstring(struct isakmp_data *,char *);
|
void isakmp_cfg_iplist_to_str(char *, int, void *, int);
|
|
#define ISAKMP_CFG_LOGIN 1
|
#define ISAKMP_CFG_LOGOUT 2
|
static int isakmp_cfg_accounting(struct ph1handle *, int);
|
#ifdef HAVE_LIBRADIUS
|
static int isakmp_cfg_accounting_radius(struct ph1handle *, int);
|
#endif
|
|
/*
|
* Handle an ISAKMP config mode packet
|
* We expect HDR, HASH, ATTR
|
*/
|
void
|
isakmp_cfg_r(iph1, msg)
|
struct ph1handle *iph1;
|
vchar_t *msg;
|
{
|
struct isakmp *packet;
|
struct isakmp_gen *ph;
|
int tlen;
|
char *npp;
|
int np;
|
vchar_t *dmsg;
|
struct isakmp_ivm *ivm;
|
|
/* Check that the packet is long enough to have a header */
|
if (msg->l < sizeof(*packet)) {
|
plog(LLV_ERROR, LOCATION, NULL, "Unexpected short packet\n");
|
return;
|
}
|
|
packet = (struct isakmp *)msg->v;
|
|
/* Is it encrypted? It should be encrypted */
|
if ((packet->flags & ISAKMP_FLAG_E) == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"User credentials sent in cleartext!\n");
|
return;
|
}
|
|
/*
|
* Decrypt the packet. If this is the beginning of a new
|
* exchange, reinitialize the IV
|
*/
|
if (iph1->mode_cfg->ivm == NULL ||
|
iph1->mode_cfg->last_msgid != packet->msgid )
|
iph1->mode_cfg->ivm =
|
isakmp_cfg_newiv(iph1, packet->msgid);
|
ivm = iph1->mode_cfg->ivm;
|
|
dmsg = oakley_do_decrypt(iph1, msg, ivm->iv, ivm->ive);
|
if (dmsg == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"failed to decrypt message\n");
|
return;
|
}
|
|
plog(LLV_DEBUG, LOCATION, NULL, "MODE_CFG packet\n");
|
plogdump(LLV_DEBUG, dmsg->v, dmsg->l);
|
|
/* Now work with the decrypted packet */
|
packet = (struct isakmp *)dmsg->v;
|
tlen = dmsg->l - sizeof(*packet);
|
ph = (struct isakmp_gen *)(packet + 1);
|
|
np = packet->np;
|
while ((tlen > 0) && (np != ISAKMP_NPTYPE_NONE)) {
|
/* Check that the payload header fits in the packet */
|
if (tlen < sizeof(*ph)) {
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Short payload header\n");
|
goto out;
|
}
|
|
/* Check that the payload fits in the packet */
|
if (tlen < ntohs(ph->len)) {
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Short payload\n");
|
goto out;
|
}
|
|
plog(LLV_DEBUG, LOCATION, NULL, "Seen payload %d\n", np);
|
plogdump(LLV_DEBUG, ph, ntohs(ph->len));
|
|
switch(np) {
|
case ISAKMP_NPTYPE_HASH: {
|
vchar_t *check;
|
vchar_t *payload;
|
size_t plen;
|
struct isakmp_gen *nph;
|
|
plen = ntohs(ph->len);
|
nph = (struct isakmp_gen *)((char *)ph + plen);
|
plen = ntohs(nph->len);
|
|
if ((payload = vmalloc(plen)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory\n");
|
goto out;
|
}
|
memcpy(payload->v, nph, plen);
|
|
if ((check = oakley_compute_hash1(iph1,
|
packet->msgid, payload)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot compute hash\n");
|
vfree(payload);
|
goto out;
|
}
|
|
if (memcmp(ph + 1, check->v, check->l) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Hash verification failed\n");
|
vfree(payload);
|
vfree(check);
|
goto out;
|
}
|
vfree(payload);
|
vfree(check);
|
break;
|
}
|
case ISAKMP_NPTYPE_ATTR: {
|
struct isakmp_pl_attr *attrpl;
|
|
attrpl = (struct isakmp_pl_attr *)ph;
|
isakmp_cfg_attr_r(iph1, packet->msgid, attrpl);
|
|
break;
|
}
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Unexpected next payload %d\n", np);
|
/* Skip to the next payload */
|
break;
|
}
|
|
/* Move to the next payload */
|
np = ph->np;
|
tlen -= ntohs(ph->len);
|
npp = (char *)ph;
|
ph = (struct isakmp_gen *)(npp + ntohs(ph->len));
|
}
|
|
out:
|
vfree(dmsg);
|
}
|
|
int
|
isakmp_cfg_attr_r(iph1, msgid, attrpl)
|
struct ph1handle *iph1;
|
u_int32_t msgid;
|
struct isakmp_pl_attr *attrpl;
|
{
|
int type = attrpl->type;
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Configuration exchange type %s\n", s_isakmp_cfg_ptype(type));
|
switch (type) {
|
case ISAKMP_CFG_ACK:
|
/* ignore, but this is the time to reinit the IV */
|
oakley_delivm(iph1->mode_cfg->ivm);
|
iph1->mode_cfg->ivm = NULL;
|
return 0;
|
break;
|
|
case ISAKMP_CFG_REPLY:
|
return isakmp_cfg_reply(iph1, attrpl);
|
break;
|
|
case ISAKMP_CFG_REQUEST:
|
iph1->msgid = msgid;
|
return isakmp_cfg_request(iph1, attrpl);
|
break;
|
|
case ISAKMP_CFG_SET:
|
iph1->msgid = msgid;
|
return isakmp_cfg_set(iph1, attrpl);
|
break;
|
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Unepected configuration exchange type %d\n", type);
|
return -1;
|
break;
|
}
|
|
return 0;
|
}
|
|
int
|
isakmp_cfg_reply(iph1, attrpl)
|
struct ph1handle *iph1;
|
struct isakmp_pl_attr *attrpl;
|
{
|
struct isakmp_data *attr;
|
int tlen;
|
size_t alen;
|
char *npp;
|
int type;
|
struct sockaddr_in *sin;
|
int error;
|
|
tlen = ntohs(attrpl->h.len);
|
attr = (struct isakmp_data *)(attrpl + 1);
|
tlen -= sizeof(*attrpl);
|
|
while (tlen > 0) {
|
type = ntohs(attr->type);
|
|
/* Handle short attributes */
|
if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
|
type &= ~ISAKMP_GEN_MASK;
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Short attribute %s = %d\n",
|
s_isakmp_cfg_type(type), ntohs(attr->lorv));
|
|
switch (type) {
|
case XAUTH_TYPE:
|
if ((error = xauth_attr_reply(iph1,
|
attr, ntohs(attrpl->id))) != 0)
|
return error;
|
break;
|
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Ignored short attribute %s\n",
|
s_isakmp_cfg_type(type));
|
break;
|
}
|
|
tlen -= sizeof(*attr);
|
attr++;
|
continue;
|
}
|
|
type = ntohs(attr->type);
|
alen = ntohs(attr->lorv);
|
|
/* Check that the attribute fit in the packet */
|
if (tlen < alen) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Short attribute %s\n",
|
s_isakmp_cfg_type(type));
|
return -1;
|
}
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Attribute %s, len %zu\n",
|
s_isakmp_cfg_type(type), alen);
|
|
switch(type) {
|
case XAUTH_TYPE:
|
case XAUTH_USER_NAME:
|
case XAUTH_USER_PASSWORD:
|
case XAUTH_PASSCODE:
|
case XAUTH_MESSAGE:
|
case XAUTH_CHALLENGE:
|
case XAUTH_DOMAIN:
|
case XAUTH_STATUS:
|
case XAUTH_NEXT_PIN:
|
case XAUTH_ANSWER:
|
if ((error = xauth_attr_reply(iph1,
|
attr, ntohs(attrpl->id))) != 0)
|
return error;
|
break;
|
case INTERNAL_IP4_ADDRESS:
|
isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->addr4);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_ADDR4;
|
break;
|
case INTERNAL_IP4_NETMASK:
|
isakmp_cfg_getaddr4(attr, &iph1->mode_cfg->mask4);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_MASK4;
|
break;
|
case INTERNAL_IP4_DNS:
|
isakmp_cfg_appendaddr4(attr,
|
&iph1->mode_cfg->dns4[iph1->mode_cfg->dns4_index],
|
&iph1->mode_cfg->dns4_index, MAXNS);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_DNS4;
|
break;
|
case INTERNAL_IP4_NBNS:
|
isakmp_cfg_appendaddr4(attr,
|
&iph1->mode_cfg->wins4[iph1->mode_cfg->wins4_index],
|
&iph1->mode_cfg->wins4_index, MAXNS);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_WINS4;
|
break;
|
case UNITY_DEF_DOMAIN:
|
isakmp_cfg_getstring(attr,
|
iph1->mode_cfg->default_domain);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_GOT_DEFAULT_DOMAIN;
|
break;
|
case UNITY_SPLIT_INCLUDE:
|
case UNITY_LOCAL_LAN:
|
case UNITY_SPLITDNS_NAME:
|
case UNITY_BANNER:
|
case UNITY_SAVE_PASSWD:
|
case UNITY_NATT_PORT:
|
case UNITY_PFS:
|
case UNITY_FW_TYPE:
|
case UNITY_BACKUP_SERVERS:
|
case UNITY_DDNS_HOSTNAME:
|
isakmp_unity_reply(iph1, attr);
|
break;
|
case INTERNAL_IP4_SUBNET:
|
case INTERNAL_ADDRESS_EXPIRY:
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Ignored attribute %s\n",
|
s_isakmp_cfg_type(type));
|
break;
|
}
|
|
npp = (char *)attr;
|
attr = (struct isakmp_data *)(npp + sizeof(*attr) + alen);
|
tlen -= (sizeof(*attr) + alen);
|
}
|
|
/*
|
* Call the SA up script hook now that we have the configuration
|
* It is done at the end of phase 1 if ISAKMP mode config is not
|
* requested.
|
*/
|
|
if ((iph1->status == PHASE1ST_ESTABLISHED) &&
|
iph1->rmconf->mode_cfg) {
|
switch (AUTHMETHOD(iph1)) {
|
case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
|
/* Unimplemented */
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
|
script_hook(iph1, SCRIPT_PHASE1_UP);
|
break;
|
default:
|
break;
|
}
|
}
|
|
|
#ifdef ENABLE_ADMINPORT
|
{
|
vchar_t *buf;
|
|
alen = ntohs(attrpl->h.len) - sizeof(*attrpl);
|
if ((buf = vmalloc(alen)) == NULL) {
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Cannot allocate memory: %s\n", strerror(errno));
|
} else {
|
memcpy(buf->v, attrpl + 1, buf->l);
|
EVT_PUSH(iph1->local, iph1->remote,
|
EVTT_ISAKMP_CFG_DONE, buf);
|
vfree(buf);
|
}
|
}
|
#endif
|
|
return 0;
|
}
|
|
int
|
isakmp_cfg_request(iph1, attrpl)
|
struct ph1handle *iph1;
|
struct isakmp_pl_attr *attrpl;
|
{
|
struct isakmp_data *attr;
|
int tlen;
|
size_t alen;
|
char *npp;
|
vchar_t *payload;
|
struct isakmp_pl_attr *reply;
|
vchar_t *reply_attr;
|
int type;
|
int error = -1;
|
|
if ((payload = vmalloc(sizeof(*reply))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return -1;
|
}
|
memset(payload->v, 0, sizeof(*reply));
|
|
tlen = ntohs(attrpl->h.len);
|
attr = (struct isakmp_data *)(attrpl + 1);
|
tlen -= sizeof(*attrpl);
|
|
while (tlen > 0) {
|
reply_attr = NULL;
|
type = ntohs(attr->type);
|
|
/* Handle short attributes */
|
if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
|
type &= ~ISAKMP_GEN_MASK;
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Short attribute %s = %d\n",
|
s_isakmp_cfg_type(type), ntohs(attr->lorv));
|
|
switch (type) {
|
case XAUTH_TYPE:
|
reply_attr = isakmp_xauth_req(iph1, attr);
|
break;
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Ignored short attribute %s\n",
|
s_isakmp_cfg_type(type));
|
break;
|
}
|
|
tlen -= sizeof(*attr);
|
attr++;
|
|
if (reply_attr != NULL) {
|
payload = buffer_cat(payload, reply_attr);
|
vfree(reply_attr);
|
}
|
|
continue;
|
}
|
|
type = ntohs(attr->type);
|
alen = ntohs(attr->lorv);
|
|
/* Check that the attribute fit in the packet */
|
if (tlen < alen) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Short attribute %s\n",
|
s_isakmp_cfg_type(type));
|
goto end;
|
}
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Attribute %s, len %zu\n",
|
s_isakmp_cfg_type(type), alen);
|
|
switch(type) {
|
case INTERNAL_IP4_ADDRESS:
|
case INTERNAL_IP4_NETMASK:
|
case INTERNAL_IP4_DNS:
|
case INTERNAL_IP4_NBNS:
|
case INTERNAL_IP4_SUBNET:
|
reply_attr = isakmp_cfg_net(iph1, attr);
|
break;
|
|
case XAUTH_TYPE:
|
case XAUTH_USER_NAME:
|
case XAUTH_USER_PASSWORD:
|
case XAUTH_PASSCODE:
|
case XAUTH_MESSAGE:
|
case XAUTH_CHALLENGE:
|
case XAUTH_DOMAIN:
|
case XAUTH_STATUS:
|
case XAUTH_NEXT_PIN:
|
case XAUTH_ANSWER:
|
reply_attr = isakmp_xauth_req(iph1, attr);
|
break;
|
|
case APPLICATION_VERSION:
|
reply_attr = isakmp_cfg_string(iph1,
|
attr, ISAKMP_CFG_RACOON_VERSION);
|
break;
|
|
case UNITY_BANNER:
|
case UNITY_PFS:
|
case UNITY_SAVE_PASSWD:
|
case UNITY_DEF_DOMAIN:
|
case UNITY_DDNS_HOSTNAME:
|
case UNITY_FW_TYPE:
|
case UNITY_SPLITDNS_NAME:
|
case UNITY_SPLIT_INCLUDE:
|
case UNITY_LOCAL_LAN:
|
case UNITY_NATT_PORT:
|
case UNITY_BACKUP_SERVERS:
|
reply_attr = isakmp_unity_req(iph1, attr);
|
break;
|
|
case INTERNAL_ADDRESS_EXPIRY:
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Ignored attribute %s\n",
|
s_isakmp_cfg_type(type));
|
break;
|
}
|
|
npp = (char *)attr;
|
attr = (struct isakmp_data *)(npp + sizeof(*attr) + alen);
|
tlen -= (sizeof(*attr) + alen);
|
|
if (reply_attr != NULL) {
|
payload = buffer_cat(payload, reply_attr);
|
vfree(reply_attr);
|
}
|
|
}
|
|
reply = (struct isakmp_pl_attr *)payload->v;
|
reply->h.len = htons(payload->l);
|
reply->type = ISAKMP_CFG_REPLY;
|
reply->id = attrpl->id;
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Sending MODE_CFG REPLY\n");
|
|
error = isakmp_cfg_send(iph1, payload,
|
ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0);
|
|
if (iph1->status == PHASE1ST_ESTABLISHED) {
|
switch (AUTHMETHOD(iph1)) {
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
|
/* Unimplemented */
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
|
script_hook(iph1, SCRIPT_PHASE1_UP);
|
break;
|
default:
|
break;
|
}
|
}
|
|
end:
|
vfree(payload);
|
|
return error;
|
}
|
|
int
|
isakmp_cfg_set(iph1, attrpl)
|
struct ph1handle *iph1;
|
struct isakmp_pl_attr *attrpl;
|
{
|
struct isakmp_data *attr;
|
int tlen;
|
size_t alen;
|
char *npp;
|
vchar_t *payload;
|
struct isakmp_pl_attr *reply;
|
vchar_t *reply_attr;
|
int type;
|
int error = -1;
|
|
if ((payload = vmalloc(sizeof(*reply))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return -1;
|
}
|
memset(payload->v, 0, sizeof(*reply));
|
|
tlen = ntohs(attrpl->h.len);
|
attr = (struct isakmp_data *)(attrpl + 1);
|
tlen -= sizeof(*attrpl);
|
|
/*
|
* We should send ack for the attributes we accepted
|
*/
|
while (tlen > 0) {
|
reply_attr = NULL;
|
type = ntohs(attr->type);
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Attribute %s\n",
|
s_isakmp_cfg_type(type & ~ISAKMP_GEN_MASK));
|
|
switch (type & ~ISAKMP_GEN_MASK) {
|
case XAUTH_STATUS:
|
reply_attr = isakmp_xauth_set(iph1, attr);
|
break;
|
default:
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Unexpected SET attribute %s\n",
|
s_isakmp_cfg_type(type & ~ISAKMP_GEN_MASK));
|
break;
|
}
|
|
if (reply_attr != NULL) {
|
payload = buffer_cat(payload, reply_attr);
|
vfree(reply_attr);
|
}
|
|
/*
|
* Move to next attribute. If we run out of the packet,
|
* tlen becomes negative and we exit.
|
*/
|
if ((type & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
|
tlen -= sizeof(*attr);
|
attr++;
|
} else {
|
alen = ntohs(attr->lorv);
|
tlen -= (sizeof(*attr) + alen);
|
npp = (char *)attr;
|
attr = (struct isakmp_data *)
|
(npp + sizeof(*attr) + alen);
|
}
|
}
|
|
reply = (struct isakmp_pl_attr *)payload->v;
|
reply->h.len = htons(payload->l);
|
reply->type = ISAKMP_CFG_ACK;
|
reply->id = attrpl->id;
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Sending MODE_CFG ACK\n");
|
|
error = isakmp_cfg_send(iph1, payload,
|
ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0);
|
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_DELETE_PH1) {
|
if (iph1->status == PHASE1ST_ESTABLISHED)
|
isakmp_info_send_d1(iph1);
|
remph1(iph1);
|
delph1(iph1);
|
iph1 = NULL;
|
}
|
end:
|
vfree(payload);
|
|
/*
|
* If required, request ISAKMP mode config information
|
*/
|
if ((iph1 != NULL) && (iph1->rmconf->mode_cfg) && (error == 0))
|
error = isakmp_cfg_getconfig(iph1);
|
|
return error;
|
}
|
|
|
static vchar_t *
|
buffer_cat(s, append)
|
vchar_t *s;
|
vchar_t *append;
|
{
|
vchar_t *new;
|
|
new = vmalloc(s->l + append->l);
|
if (new == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory\n");
|
return s;
|
}
|
|
memcpy(new->v, s->v, s->l);
|
memcpy(new->v + s->l, append->v, append->l);
|
|
vfree(s);
|
return new;
|
}
|
|
static vchar_t *
|
isakmp_cfg_net(iph1, attr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
{
|
int type;
|
int confsource;
|
in_addr_t addr4;
|
|
type = ntohs(attr->type);
|
|
/*
|
* Don't give an address to a peer that did not succeed Xauth
|
*/
|
if (xauth_check(iph1) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Attempt to start phase config whereas Xauth failed\n");
|
return NULL;
|
}
|
|
confsource = isakmp_cfg_config.confsource;
|
/*
|
* If we have to fall back to a local
|
* configuration source, we will jump
|
* back to this point.
|
*/
|
retry_source:
|
|
switch(type) {
|
case INTERNAL_IP4_ADDRESS:
|
switch(confsource) {
|
#ifdef HAVE_LIBLDAP
|
case ISAKMP_CFG_CONF_LDAP:
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_EXTERN)
|
break;
|
plog(LLV_INFO, LOCATION, NULL,
|
"No IP from LDAP, using local pool\n");
|
/* FALLTHROUGH */
|
confsource = ISAKMP_CFG_CONF_LOCAL;
|
goto retry_source;
|
#endif
|
#ifdef HAVE_LIBRADIUS
|
case ISAKMP_CFG_CONF_RADIUS:
|
if ((iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_EXTERN)
|
&& (iph1->mode_cfg->addr4.s_addr != htonl(-2)))
|
/*
|
* -2 is 255.255.255.254, RADIUS uses that
|
* to instruct the NAS to use a local pool
|
*/
|
break;
|
plog(LLV_INFO, LOCATION, NULL,
|
"No IP from RADIUS, using local pool\n");
|
/* FALLTHROUGH */
|
confsource = ISAKMP_CFG_CONF_LOCAL;
|
goto retry_source;
|
#endif
|
case ISAKMP_CFG_CONF_LOCAL:
|
if (isakmp_cfg_getport(iph1) == -1) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Port pool depleted\n");
|
break;
|
}
|
|
iph1->mode_cfg->addr4.s_addr =
|
htonl(ntohl(isakmp_cfg_config.network4)
|
+ iph1->mode_cfg->port);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_ADDR4_LOCAL;
|
break;
|
|
default:
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unexpected confsource\n");
|
}
|
|
if (isakmp_cfg_accounting(iph1, ISAKMP_CFG_LOGIN) != 0)
|
plog(LLV_ERROR, LOCATION, NULL, "Accounting failed\n");
|
|
return isakmp_cfg_addr4(iph1,
|
attr, &iph1->mode_cfg->addr4.s_addr);
|
break;
|
|
case INTERNAL_IP4_NETMASK:
|
switch(confsource) {
|
#ifdef HAVE_LIBLDAP
|
case ISAKMP_CFG_CONF_LDAP:
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_MASK4_EXTERN)
|
break;
|
plog(LLV_INFO, LOCATION, NULL,
|
"No mask from LDAP, using local pool\n");
|
/* FALLTHROUGH */
|
confsource = ISAKMP_CFG_CONF_LOCAL;
|
goto retry_source;
|
#endif
|
#ifdef HAVE_LIBRADIUS
|
case ISAKMP_CFG_CONF_RADIUS:
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_MASK4_EXTERN)
|
break;
|
plog(LLV_INFO, LOCATION, NULL,
|
"No mask from RADIUS, using local pool\n");
|
/* FALLTHROUGH */
|
confsource = ISAKMP_CFG_CONF_LOCAL;
|
goto retry_source;
|
#endif
|
case ISAKMP_CFG_CONF_LOCAL:
|
iph1->mode_cfg->mask4.s_addr
|
= isakmp_cfg_config.netmask4;
|
iph1->mode_cfg->flags |= ISAKMP_CFG_MASK4_LOCAL;
|
break;
|
|
default:
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unexpected confsource\n");
|
}
|
return isakmp_cfg_addr4(iph1, attr,
|
&iph1->mode_cfg->mask4.s_addr);
|
break;
|
|
case INTERNAL_IP4_DNS:
|
return isakmp_cfg_addr4_list(iph1,
|
attr, &isakmp_cfg_config.dns4[0],
|
isakmp_cfg_config.dns4_index);
|
break;
|
|
case INTERNAL_IP4_NBNS:
|
return isakmp_cfg_addr4_list(iph1,
|
attr, &isakmp_cfg_config.nbns4[0],
|
isakmp_cfg_config.nbns4_index);
|
break;
|
|
case INTERNAL_IP4_SUBNET:
|
return isakmp_cfg_addr4(iph1,
|
attr, &isakmp_cfg_config.network4);
|
break;
|
|
default:
|
plog(LLV_ERROR, LOCATION, NULL, "Unexpected type %d\n", type);
|
break;
|
}
|
return NULL;
|
}
|
|
#if 0
|
static vchar_t *
|
isakmp_cfg_void(iph1, attr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
{
|
vchar_t *buffer;
|
struct isakmp_data *new;
|
|
if ((buffer = vmalloc(sizeof(*attr))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return NULL;
|
}
|
|
new = (struct isakmp_data *)buffer->v;
|
|
new->type = attr->type;
|
new->lorv = htons(0);
|
|
return buffer;
|
}
|
#endif
|
|
vchar_t *
|
isakmp_cfg_copy(iph1, attr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
{
|
vchar_t *buffer;
|
size_t len = 0;
|
|
if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TLV)
|
len = ntohs(attr->lorv);
|
|
if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return NULL;
|
}
|
|
memcpy(buffer->v, attr, sizeof(*attr) + ntohs(attr->lorv));
|
|
return buffer;
|
}
|
|
vchar_t *
|
isakmp_cfg_short(iph1, attr, value)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
int value;
|
{
|
vchar_t *buffer;
|
struct isakmp_data *new;
|
int type;
|
|
if ((buffer = vmalloc(sizeof(*attr))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return NULL;
|
}
|
|
new = (struct isakmp_data *)buffer->v;
|
type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
|
|
new->type = htons(type | ISAKMP_GEN_TV);
|
new->lorv = htons(value);
|
|
return buffer;
|
}
|
|
vchar_t *
|
isakmp_cfg_varlen(iph1, attr, string, len)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
char *string;
|
size_t len;
|
{
|
vchar_t *buffer;
|
struct isakmp_data *new;
|
char *data;
|
|
if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return NULL;
|
}
|
|
new = (struct isakmp_data *)buffer->v;
|
|
new->type = attr->type;
|
new->lorv = htons(len);
|
data = (char *)(new + 1);
|
|
memcpy(data, string, len);
|
|
return buffer;
|
}
|
vchar_t *
|
isakmp_cfg_string(iph1, attr, string)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
char *string;
|
{
|
size_t len = strlen(string);
|
return isakmp_cfg_varlen(iph1, attr, string, len);
|
}
|
|
static vchar_t *
|
isakmp_cfg_addr4(iph1, attr, addr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
in_addr_t *addr;
|
{
|
vchar_t *buffer;
|
struct isakmp_data *new;
|
size_t len;
|
|
len = sizeof(*addr);
|
if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return NULL;
|
}
|
|
new = (struct isakmp_data *)buffer->v;
|
|
new->type = attr->type;
|
new->lorv = htons(len);
|
memcpy(new + 1, addr, len);
|
|
return buffer;
|
}
|
|
static vchar_t *
|
isakmp_cfg_addr4_list(iph1, attr, addr, nbr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
in_addr_t *addr;
|
int nbr;
|
{
|
int error = -1;
|
vchar_t *buffer = NULL;
|
vchar_t *bufone = NULL;
|
struct isakmp_data *new;
|
size_t len;
|
int i;
|
|
len = sizeof(*addr);
|
if ((buffer = vmalloc(0)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
goto out;
|
}
|
for(i = 0; i < nbr; i++) {
|
if ((bufone = vmalloc(sizeof(*attr) + len)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory\n");
|
goto out;
|
}
|
new = (struct isakmp_data *)bufone->v;
|
new->type = attr->type;
|
new->lorv = htons(len);
|
memcpy(new + 1, &addr[i], len);
|
new += (len + sizeof(*attr));
|
buffer = buffer_cat(buffer, bufone);
|
vfree(bufone);
|
}
|
|
error = 0;
|
|
out:
|
if ((error != 0) && (buffer != NULL)) {
|
vfree(buffer);
|
buffer = NULL;
|
}
|
|
return buffer;
|
}
|
|
struct isakmp_ivm *
|
isakmp_cfg_newiv(iph1, msgid)
|
struct ph1handle *iph1;
|
u_int32_t msgid;
|
{
|
struct isakmp_cfg_state *ics = iph1->mode_cfg;
|
|
if (ics == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"isakmp_cfg_newiv called without mode config state\n");
|
return NULL;
|
}
|
|
if (ics->ivm != NULL)
|
oakley_delivm(ics->ivm);
|
|
ics->ivm = oakley_newiv2(iph1, msgid);
|
ics->last_msgid = msgid;
|
|
return ics->ivm;
|
}
|
|
/* Derived from isakmp_info_send_common */
|
int
|
isakmp_cfg_send(iph1, payload, np, flags, new_exchange)
|
struct ph1handle *iph1;
|
vchar_t *payload;
|
u_int32_t np;
|
int flags;
|
int new_exchange;
|
{
|
struct ph2handle *iph2 = NULL;
|
vchar_t *hash = NULL;
|
struct isakmp *isakmp;
|
struct isakmp_gen *gen;
|
char *p;
|
int tlen;
|
int error = -1;
|
struct isakmp_cfg_state *ics = iph1->mode_cfg;
|
|
/* Check if phase 1 is established */
|
if ((iph1->status != PHASE1ST_ESTABLISHED) ||
|
(iph1->local == NULL) ||
|
(iph1->remote == NULL)) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ISAKMP mode config exchange with immature phase 1\n");
|
goto end;
|
}
|
|
/* add new entry to isakmp status table */
|
iph2 = newph2();
|
if (iph2 == NULL)
|
goto end;
|
|
iph2->dst = dupsaddr(iph1->remote);
|
if (iph2->dst == NULL) {
|
delph2(iph2);
|
goto end;
|
}
|
iph2->src = dupsaddr(iph1->local);
|
if (iph2->src == NULL) {
|
delph2(iph2);
|
goto end;
|
}
|
|
#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT))
|
if (set_port(iph2->dst, 0) == NULL ||
|
set_port(iph2->src, 0) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"invalid family: %d\n", iph1->remote->sa_family);
|
delph2(iph2);
|
goto end;
|
}
|
#endif
|
iph2->ph1 = iph1;
|
iph2->side = INITIATOR;
|
iph2->status = PHASE2ST_START;
|
|
if (new_exchange)
|
iph2->msgid = isakmp_newmsgid2(iph1);
|
else
|
iph2->msgid = iph1->msgid;
|
|
/* get IV and HASH(1) if skeyid_a was generated. */
|
if (iph1->skeyid_a != NULL) {
|
if (new_exchange) {
|
if (isakmp_cfg_newiv(iph1, iph2->msgid) == NULL) {
|
delph2(iph2);
|
goto end;
|
}
|
}
|
|
/* generate HASH(1) */
|
hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload);
|
if (hash == NULL) {
|
delph2(iph2);
|
goto end;
|
}
|
|
/* initialized total buffer length */
|
tlen = hash->l;
|
tlen += sizeof(*gen);
|
} else {
|
/* IKE-SA is not established */
|
hash = NULL;
|
|
/* initialized total buffer length */
|
tlen = 0;
|
}
|
if ((flags & ISAKMP_FLAG_A) == 0)
|
iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E);
|
else
|
iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A);
|
|
insph2(iph2);
|
bindph12(iph1, iph2);
|
|
tlen += sizeof(*isakmp) + payload->l;
|
|
/* create buffer for isakmp payload */
|
iph2->sendbuf = vmalloc(tlen);
|
if (iph2->sendbuf == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"failed to get buffer to send.\n");
|
goto err;
|
}
|
|
/* create isakmp header */
|
isakmp = (struct isakmp *)iph2->sendbuf->v;
|
memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t));
|
memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t));
|
isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH;
|
isakmp->v = iph1->version;
|
isakmp->etype = ISAKMP_ETYPE_CFG;
|
isakmp->flags = iph2->flags;
|
memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid));
|
isakmp->len = htonl(tlen);
|
p = (char *)(isakmp + 1);
|
|
/* create HASH payload */
|
if (hash != NULL) {
|
gen = (struct isakmp_gen *)p;
|
gen->np = np & 0xff;
|
gen->len = htons(sizeof(*gen) + hash->l);
|
p += sizeof(*gen);
|
memcpy(p, hash->v, hash->l);
|
p += hash->l;
|
}
|
|
/* add payload */
|
memcpy(p, payload->v, payload->l);
|
p += payload->l;
|
|
#ifdef HAVE_PRINT_ISAKMP_C
|
isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1);
|
#endif
|
|
plog(LLV_DEBUG, LOCATION, NULL, "MODE_CFG packet to send\n");
|
plogdump(LLV_DEBUG, iph2->sendbuf->v, iph2->sendbuf->l);
|
|
/* encoding */
|
if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) {
|
vchar_t *tmp;
|
|
tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf,
|
ics->ivm->ive, ics->ivm->iv);
|
VPTRINIT(iph2->sendbuf);
|
if (tmp == NULL)
|
goto err;
|
iph2->sendbuf = tmp;
|
}
|
|
/* HDR*, HASH(1), ATTR */
|
if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) {
|
VPTRINIT(iph2->sendbuf);
|
goto err;
|
}
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"sendto mode config %s.\n", s_isakmp_nptype(np));
|
|
/*
|
* XXX We might need to resend the message...
|
*/
|
|
error = 0;
|
VPTRINIT(iph2->sendbuf);
|
|
err:
|
if (iph2->sendbuf != NULL)
|
vfree(iph2->sendbuf);
|
|
unbindph12(iph2);
|
remph2(iph2);
|
delph2(iph2);
|
end:
|
if (hash)
|
vfree(hash);
|
return error;
|
}
|
|
|
void
|
isakmp_cfg_rmstate(iph1)
|
struct ph1handle *iph1;
|
{
|
struct isakmp_cfg_state *state = iph1->mode_cfg;
|
|
if (isakmp_cfg_accounting(iph1, ISAKMP_CFG_LOGOUT) != 0)
|
plog(LLV_ERROR, LOCATION, NULL, "Accounting failed\n");
|
|
if (state->flags & ISAKMP_CFG_PORT_ALLOCATED)
|
isakmp_cfg_putport(iph1, state->port);
|
|
/* Delete the IV if it's still there */
|
if(iph1->mode_cfg->ivm) {
|
oakley_delivm(iph1->mode_cfg->ivm);
|
iph1->mode_cfg->ivm = NULL;
|
}
|
|
/* Free any allocated splitnet lists */
|
if(iph1->mode_cfg->split_include != NULL)
|
splitnet_list_free(iph1->mode_cfg->split_include,
|
&iph1->mode_cfg->include_count);
|
if(iph1->mode_cfg->split_local != NULL)
|
splitnet_list_free(iph1->mode_cfg->split_local,
|
&iph1->mode_cfg->local_count);
|
|
xauth_rmstate(&state->xauth);
|
|
racoon_free(state);
|
iph1->mode_cfg = NULL;
|
|
return;
|
}
|
|
struct isakmp_cfg_state *
|
isakmp_cfg_mkstate(void)
|
{
|
struct isakmp_cfg_state *state;
|
|
if ((state = racoon_malloc(sizeof(*state))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory for mode config state\n");
|
return NULL;
|
}
|
memset(state, 0, sizeof(*state));
|
|
return state;
|
}
|
|
int
|
isakmp_cfg_getport(iph1)
|
struct ph1handle *iph1;
|
{
|
unsigned int i;
|
size_t size = isakmp_cfg_config.pool_size;
|
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_PORT_ALLOCATED)
|
return iph1->mode_cfg->port;
|
|
if (isakmp_cfg_config.port_pool == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"isakmp_cfg_config.port_pool == NULL\n");
|
return -1;
|
}
|
|
for (i = 0; i < size; i++) {
|
if (isakmp_cfg_config.port_pool[i].used == 0)
|
break;
|
}
|
|
if (i == size) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"No more addresses available\n");
|
return -1;
|
}
|
|
isakmp_cfg_config.port_pool[i].used = 1;
|
|
plog(LLV_INFO, LOCATION, NULL, "Using port %d\n", i);
|
|
iph1->mode_cfg->flags |= ISAKMP_CFG_PORT_ALLOCATED;
|
iph1->mode_cfg->port = i;
|
|
return i;
|
}
|
|
int
|
isakmp_cfg_putport(iph1, index)
|
struct ph1handle *iph1;
|
unsigned int index;
|
{
|
if (isakmp_cfg_config.port_pool == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"isakmp_cfg_config.port_pool == NULL\n");
|
return -1;
|
}
|
|
if (isakmp_cfg_config.port_pool[index].used == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Attempt to release an unallocated address (port %d)\n",
|
index);
|
return -1;
|
}
|
|
#ifdef HAVE_LIBPAM
|
/* Cleanup PAM status associated with the port */
|
if (isakmp_cfg_config.authsource == ISAKMP_CFG_AUTH_PAM)
|
privsep_cleanup_pam(index);
|
#endif
|
isakmp_cfg_config.port_pool[index].used = 0;
|
iph1->mode_cfg->flags &= ISAKMP_CFG_PORT_ALLOCATED;
|
|
plog(LLV_INFO, LOCATION, NULL, "Released port %d\n", index);
|
|
return 0;
|
}
|
|
#ifdef HAVE_LIBPAM
|
void
|
cleanup_pam(port)
|
int port;
|
{
|
if (isakmp_cfg_config.port_pool[port].pam != NULL) {
|
pam_end(isakmp_cfg_config.port_pool[port].pam, PAM_SUCCESS);
|
isakmp_cfg_config.port_pool[port].pam = NULL;
|
}
|
|
return;
|
}
|
#endif
|
|
/* Accounting, only for RADIUS or PAM */
|
static int
|
isakmp_cfg_accounting(iph1, inout)
|
struct ph1handle *iph1;
|
int inout;
|
{
|
#ifdef HAVE_LIBPAM
|
if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_PAM)
|
return privsep_accounting_pam(iph1->mode_cfg->port,
|
inout);
|
#endif
|
#ifdef HAVE_LIBRADIUS
|
if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_RADIUS)
|
return isakmp_cfg_accounting_radius(iph1, inout);
|
#endif
|
if (isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_SYSTEM)
|
return privsep_accounting_system(iph1->mode_cfg->port,
|
iph1->remote, iph1->mode_cfg->login, inout);
|
return 0;
|
}
|
|
#ifdef HAVE_LIBPAM
|
int
|
isakmp_cfg_accounting_pam(port, inout)
|
int port;
|
int inout;
|
{
|
int error = 0;
|
pam_handle_t *pam;
|
|
if (isakmp_cfg_config.port_pool == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"isakmp_cfg_config.port_pool == NULL\n");
|
return -1;
|
}
|
|
pam = isakmp_cfg_config.port_pool[port].pam;
|
if (pam == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "pam handle is NULL\n");
|
return -1;
|
}
|
|
switch (inout) {
|
case ISAKMP_CFG_LOGIN:
|
error = pam_open_session(pam, 0);
|
break;
|
case ISAKMP_CFG_LOGOUT:
|
error = pam_close_session(pam, 0);
|
pam_end(pam, error);
|
isakmp_cfg_config.port_pool[port].pam = NULL;
|
break;
|
default:
|
plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n");
|
break;
|
}
|
|
if (error != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"pam_open_session/pam_close_session failed: %s\n",
|
pam_strerror(pam, error));
|
return -1;
|
}
|
|
return 0;
|
}
|
#endif /* HAVE_LIBPAM */
|
|
#ifdef HAVE_LIBRADIUS
|
static int
|
isakmp_cfg_accounting_radius(iph1, inout)
|
struct ph1handle *iph1;
|
int inout;
|
{
|
/* For first time use, initialize Radius */
|
if (radius_acct_state == NULL) {
|
if ((radius_acct_state = rad_acct_open()) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot init librradius\n");
|
return -1;
|
}
|
|
if (rad_config(radius_acct_state, NULL) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot open librarius config file: %s\n",
|
rad_strerror(radius_acct_state));
|
rad_close(radius_acct_state);
|
radius_acct_state = NULL;
|
return -1;
|
}
|
}
|
|
if (rad_create_request(radius_acct_state,
|
RAD_ACCOUNTING_REQUEST) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_create_request failed: %s\n",
|
rad_strerror(radius_acct_state));
|
return -1;
|
}
|
|
if (rad_put_string(radius_acct_state, RAD_USER_NAME,
|
iph1->mode_cfg->login) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_string failed: %s\n",
|
rad_strerror(radius_acct_state));
|
return -1;
|
}
|
|
switch (inout) {
|
case ISAKMP_CFG_LOGIN:
|
inout = RAD_START;
|
break;
|
case ISAKMP_CFG_LOGOUT:
|
inout = RAD_STOP;
|
break;
|
default:
|
plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n");
|
break;
|
}
|
|
if (rad_put_addr(radius_acct_state,
|
RAD_FRAMED_IP_ADDRESS, iph1->mode_cfg->addr4) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_addr failed: %s\n",
|
rad_strerror(radius_acct_state));
|
return -1;
|
}
|
|
if (rad_put_addr(radius_acct_state,
|
RAD_LOGIN_IP_HOST, iph1->mode_cfg->addr4) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_addr failed: %s\n",
|
rad_strerror(radius_acct_state));
|
return -1;
|
}
|
|
if (rad_put_int(radius_acct_state, RAD_ACCT_STATUS_TYPE, inout) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_int failed: %s\n",
|
rad_strerror(radius_acct_state));
|
return -1;
|
}
|
|
if (isakmp_cfg_radius_common(radius_acct_state,
|
iph1->mode_cfg->port) != 0)
|
return -1;
|
|
if (rad_send_request(radius_acct_state) != RAD_ACCOUNTING_RESPONSE) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_send_request failed: %s\n",
|
rad_strerror(radius_acct_state));
|
return -1;
|
}
|
|
return 0;
|
}
|
#endif /* HAVE_LIBRADIUS */
|
|
/*
|
* Attributes common to all RADIUS requests
|
*/
|
#ifdef HAVE_LIBRADIUS
|
int
|
isakmp_cfg_radius_common(radius_state, port)
|
struct rad_handle *radius_state;
|
int port;
|
{
|
struct utsname name;
|
static struct hostent *host = NULL;
|
struct in_addr nas_addr;
|
|
/*
|
* Find our own IP by resolving our nodename
|
*/
|
if (host == NULL) {
|
if (uname(&name) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"uname failed: %s\n", strerror(errno));
|
return -1;
|
}
|
|
if ((host = gethostbyname(name.nodename)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"gethostbyname failed: %s\n", strerror(errno));
|
return -1;
|
}
|
}
|
|
memcpy(&nas_addr, host->h_addr, sizeof(nas_addr));
|
if (rad_put_addr(radius_state, RAD_NAS_IP_ADDRESS, nas_addr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_addr failed: %s\n",
|
rad_strerror(radius_state));
|
return -1;
|
}
|
|
if (rad_put_int(radius_state, RAD_NAS_PORT, port) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_int failed: %s\n",
|
rad_strerror(radius_state));
|
return -1;
|
}
|
|
if (rad_put_int(radius_state, RAD_NAS_PORT_TYPE, RAD_VIRTUAL) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_int failed: %s\n",
|
rad_strerror(radius_state));
|
return -1;
|
}
|
|
if (rad_put_int(radius_state, RAD_SERVICE_TYPE, RAD_FRAMED) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_int failed: %s\n",
|
rad_strerror(radius_state));
|
return -1;
|
}
|
|
return 0;
|
}
|
#endif
|
|
#ifndef ANDROID_PATCHED
|
|
/*
|
Logs the user into the utmp system files.
|
*/
|
|
int
|
isakmp_cfg_accounting_system(port, raddr, usr, inout)
|
int port;
|
struct sockaddr *raddr;
|
char *usr;
|
int inout;
|
{
|
int error = 0;
|
struct utmp ut;
|
char term[UT_LINESIZE];
|
char addr[NI_MAXHOST];
|
|
if (usr == NULL || usr[0]=='\0') {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"system accounting : no login found\n");
|
return -1;
|
}
|
|
sprintf(term, TERMSPEC, port);
|
|
switch (inout) {
|
case ISAKMP_CFG_LOGIN:
|
strncpy(ut.ut_name, usr, UT_NAMESIZE);
|
ut.ut_name[UT_NAMESIZE - 1] = '\0';
|
|
strncpy(ut.ut_line, term, UT_LINESIZE);
|
ut.ut_line[UT_LINESIZE - 1] = '\0';
|
|
GETNAMEINFO_NULL(raddr, addr);
|
strncpy(ut.ut_host, addr, UT_HOSTSIZE);
|
ut.ut_host[UT_HOSTSIZE - 1] = '\0';
|
|
ut.ut_time = time(NULL);
|
|
plog(LLV_INFO, LOCATION, NULL,
|
"Accounting : '%s' logging on '%s' from %s.\n",
|
ut.ut_name, ut.ut_line, ut.ut_host);
|
|
login(&ut);
|
|
break;
|
case ISAKMP_CFG_LOGOUT:
|
|
plog(LLV_INFO, LOCATION, NULL,
|
"Accounting : '%s' unlogging from '%s'.\n",
|
usr, term);
|
|
logout(term);
|
|
break;
|
default:
|
plog(LLV_ERROR, LOCATION, NULL, "Unepected inout\n");
|
break;
|
}
|
|
return 0;
|
}
|
|
#endif
|
|
int
|
isakmp_cfg_getconfig(iph1)
|
struct ph1handle *iph1;
|
{
|
vchar_t *buffer;
|
struct isakmp_pl_attr *attrpl;
|
struct isakmp_data *attr;
|
size_t len;
|
int error;
|
int attrcount;
|
int i;
|
int attrlist[] = {
|
INTERNAL_IP4_ADDRESS,
|
INTERNAL_IP4_NETMASK,
|
INTERNAL_IP4_DNS,
|
INTERNAL_IP4_NBNS,
|
UNITY_BANNER,
|
UNITY_DEF_DOMAIN,
|
UNITY_SPLITDNS_NAME,
|
UNITY_SPLIT_INCLUDE,
|
UNITY_LOCAL_LAN,
|
APPLICATION_VERSION,
|
};
|
|
attrcount = sizeof(attrlist) / sizeof(*attrlist);
|
len = sizeof(*attrpl) + sizeof(*attr) * attrcount;
|
|
if ((buffer = vmalloc(len)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
|
return -1;
|
}
|
|
attrpl = (struct isakmp_pl_attr *)buffer->v;
|
attrpl->h.len = htons(len);
|
attrpl->type = ISAKMP_CFG_REQUEST;
|
attrpl->id = htons((u_int16_t)(eay_random() & 0xffff));
|
|
attr = (struct isakmp_data *)(attrpl + 1);
|
|
for (i = 0; i < attrcount; i++) {
|
attr->type = htons(attrlist[i]);
|
attr->lorv = htons(0);
|
attr++;
|
}
|
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Sending MODE_CFG REQUEST\n");
|
|
error = isakmp_cfg_send(iph1, buffer,
|
ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1);
|
|
vfree(buffer);
|
|
return error;
|
}
|
|
static void
|
isakmp_cfg_getaddr4(attr, ip)
|
struct isakmp_data *attr;
|
struct in_addr *ip;
|
{
|
size_t alen = ntohs(attr->lorv);
|
in_addr_t *addr;
|
|
if (alen != sizeof(*ip)) {
|
plog(LLV_ERROR, LOCATION, NULL, "Bad IPv4 address len\n");
|
return;
|
}
|
|
addr = (in_addr_t *)(attr + 1);
|
ip->s_addr = *addr;
|
|
return;
|
}
|
|
static void
|
isakmp_cfg_appendaddr4(attr, ip, num, max)
|
struct isakmp_data *attr;
|
struct in_addr *ip;
|
int *num;
|
int max;
|
{
|
size_t alen = ntohs(attr->lorv);
|
in_addr_t *addr;
|
|
if (alen != sizeof(*ip)) {
|
plog(LLV_ERROR, LOCATION, NULL, "Bad IPv4 address len\n");
|
return;
|
}
|
if (*num == max) {
|
plog(LLV_ERROR, LOCATION, NULL, "Too many addresses given\n");
|
return;
|
}
|
|
addr = (in_addr_t *)(attr + 1);
|
ip->s_addr = *addr;
|
(*num)++;
|
|
return;
|
}
|
|
static void
|
isakmp_cfg_getstring(attr, str)
|
struct isakmp_data *attr;
|
char *str;
|
{
|
size_t alen = ntohs(attr->lorv);
|
char *src;
|
src = (char *)(attr + 1);
|
|
memcpy(str, src, (alen > MAXPATHLEN ? MAXPATHLEN : alen));
|
|
return;
|
}
|
|
#define IP_MAX 40
|
|
void
|
isakmp_cfg_iplist_to_str(dest, count, addr, withmask)
|
char *dest;
|
int count;
|
void *addr;
|
int withmask;
|
{
|
int i;
|
int p;
|
int l;
|
struct unity_network tmp;
|
for(i = 0, p = 0; i < count; i++) {
|
if(withmask == 1)
|
l = sizeof(struct unity_network);
|
else
|
l = sizeof(struct in_addr);
|
memcpy(&tmp, addr, l);
|
#if defined(ANDROID_CHANGES)
|
addr = ((uint8_t*) addr) + l;
|
#else
|
addr += l;
|
#endif
|
if((uint32_t)tmp.addr4.s_addr == 0)
|
break;
|
|
inet_ntop(AF_INET, &tmp.addr4, dest + p, IP_MAX);
|
p += strlen(dest + p);
|
if(withmask == 1) {
|
dest[p] = '/';
|
p++;
|
inet_ntop(AF_INET, &tmp.mask4, dest + p, IP_MAX);
|
p += strlen(dest + p);
|
}
|
dest[p] = ' ';
|
p++;
|
}
|
if(p > 0)
|
dest[p-1] = '\0';
|
else
|
dest[0] = '\0';
|
}
|
|
int
|
isakmp_cfg_setenv(iph1, envp, envc)
|
struct ph1handle *iph1;
|
char ***envp;
|
int *envc;
|
{
|
char addrstr[IP_MAX];
|
char addrlist[IP_MAX * MAXNS + MAXNS];
|
char *splitlist = addrlist;
|
char *splitlist_cidr;
|
char defdom[MAXPATHLEN + 1];
|
int cidr, tmp;
|
char cidrstr[4];
|
int i, p;
|
int test;
|
|
plog(LLV_DEBUG, LOCATION, NULL, "Starting a script.\n");
|
|
/*
|
* Internal IPv4 address, either if
|
* we are a client or a server.
|
*/
|
if ((iph1->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) ||
|
#ifdef HAVE_LIBLDAP
|
(iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_EXTERN) ||
|
#endif
|
#ifdef HAVE_LIBRADIUS
|
(iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_EXTERN) ||
|
#endif
|
(iph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_LOCAL)) {
|
inet_ntop(AF_INET, &iph1->mode_cfg->addr4,
|
addrstr, IP_MAX);
|
} else
|
addrstr[0] = '\0';
|
|
if (script_env_append(envp, envc, "INTERNAL_ADDR4", addrstr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_ADDR4\n");
|
return -1;
|
}
|
|
if (iph1->mode_cfg->xauth.authdata.generic.usr != NULL) {
|
if (script_env_append(envp, envc, "XAUTH_USER",
|
iph1->mode_cfg->xauth.authdata.generic.usr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set XAUTH_USER\n");
|
return -1;
|
}
|
}
|
|
/* Internal IPv4 mask */
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_MASK4)
|
inet_ntop(AF_INET, &iph1->mode_cfg->mask4,
|
addrstr, IP_MAX);
|
else
|
addrstr[0] = '\0';
|
|
/*
|
* During several releases, documentation adverised INTERNAL_NETMASK4
|
* while code was using INTERNAL_MASK4. We now do both.
|
*/
|
|
if (script_env_append(envp, envc, "INTERNAL_MASK4", addrstr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_MASK4\n");
|
return -1;
|
}
|
|
if (script_env_append(envp, envc, "INTERNAL_NETMASK4", addrstr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set INTERNAL_NETMASK4\n");
|
return -1;
|
}
|
|
tmp = ntohl(iph1->mode_cfg->mask4.s_addr);
|
for (cidr = 0; tmp != 0; cidr++)
|
tmp <<= 1;
|
snprintf(cidrstr, 3, "%d", cidr);
|
|
if (script_env_append(envp, envc, "INTERNAL_CIDR4", cidrstr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_CIDR4\n");
|
return -1;
|
}
|
|
/* Internal IPv4 DNS */
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_DNS4) {
|
/* First Internal IPv4 DNS (for compatibilty with older code */
|
inet_ntop(AF_INET, &iph1->mode_cfg->dns4[0],
|
addrstr, IP_MAX);
|
|
/* Internal IPv4 DNS - all */
|
isakmp_cfg_iplist_to_str(addrlist, iph1->mode_cfg->dns4_index,
|
(void *)iph1->mode_cfg->dns4, 0);
|
} else {
|
addrstr[0] = '\0';
|
addrlist[0] = '\0';
|
}
|
|
if (script_env_append(envp, envc, "INTERNAL_DNS4", addrstr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot set INTERNAL_DNS4\n");
|
return -1;
|
}
|
if (script_env_append(envp, envc, "INTERNAL_DNS4_LIST", addrlist) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set INTERNAL_DNS4_LIST\n");
|
return -1;
|
}
|
|
/* Internal IPv4 WINS */
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_WINS4) {
|
/*
|
* First Internal IPv4 WINS
|
* (for compatibilty with older code
|
*/
|
inet_ntop(AF_INET, &iph1->mode_cfg->wins4[0],
|
addrstr, IP_MAX);
|
|
/* Internal IPv4 WINS - all */
|
isakmp_cfg_iplist_to_str(addrlist, iph1->mode_cfg->wins4_index,
|
(void *)iph1->mode_cfg->wins4, 0);
|
} else {
|
addrstr[0] = '\0';
|
addrlist[0] = '\0';
|
}
|
|
if (script_env_append(envp, envc, "INTERNAL_WINS4", addrstr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set INTERNAL_WINS4\n");
|
return -1;
|
}
|
if (script_env_append(envp, envc,
|
"INTERNAL_WINS4_LIST", addrlist) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set INTERNAL_WINS4_LIST\n");
|
return -1;
|
}
|
|
/* Deault domain */
|
if(iph1->mode_cfg->flags & ISAKMP_CFG_GOT_DEFAULT_DOMAIN)
|
strncpy(defdom,
|
iph1->mode_cfg->default_domain,
|
MAXPATHLEN + 1);
|
else
|
defdom[0] = '\0';
|
|
if (script_env_append(envp, envc, "DEFAULT_DOMAIN", defdom) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set DEFAULT_DOMAIN\n");
|
return -1;
|
}
|
|
/* Split networks */
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_INCLUDE) {
|
splitlist =
|
splitnet_list_2str(iph1->mode_cfg->split_include, NETMASK);
|
splitlist_cidr =
|
splitnet_list_2str(iph1->mode_cfg->split_include, CIDR);
|
} else {
|
splitlist = addrlist;
|
splitlist_cidr = addrlist;
|
addrlist[0] = '\0';
|
}
|
|
if (script_env_append(envp, envc, "SPLIT_INCLUDE", splitlist) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot set SPLIT_INCLUDE\n");
|
return -1;
|
}
|
if (script_env_append(envp, envc,
|
"SPLIT_INCLUDE_CIDR", splitlist_cidr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set SPLIT_INCLUDE_CIDR\n");
|
return -1;
|
}
|
if (splitlist != addrlist)
|
racoon_free(splitlist);
|
if (splitlist_cidr != addrlist)
|
racoon_free(splitlist_cidr);
|
|
if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_LOCAL) {
|
splitlist =
|
splitnet_list_2str(iph1->mode_cfg->split_local, NETMASK);
|
splitlist_cidr =
|
splitnet_list_2str(iph1->mode_cfg->split_local, CIDR);
|
} else {
|
splitlist = addrlist;
|
splitlist_cidr = addrlist;
|
addrlist[0] = '\0';
|
}
|
|
if (script_env_append(envp, envc, "SPLIT_LOCAL", splitlist) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot set SPLIT_LOCAL\n");
|
return -1;
|
}
|
if (script_env_append(envp, envc,
|
"SPLIT_LOCAL_CIDR", splitlist_cidr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot set SPLIT_LOCAL_CIDR\n");
|
return -1;
|
}
|
if (splitlist != addrlist)
|
racoon_free(splitlist);
|
if (splitlist_cidr != addrlist)
|
racoon_free(splitlist_cidr);
|
|
return 0;
|
}
|
|
int
|
isakmp_cfg_resize_pool(size)
|
int size;
|
{
|
struct isakmp_cfg_port *new_pool;
|
size_t len;
|
int i;
|
|
if (size == isakmp_cfg_config.pool_size)
|
return 0;
|
|
plog(LLV_INFO, LOCATION, NULL,
|
"Resize address pool from %zu to %d\n",
|
isakmp_cfg_config.pool_size, size);
|
|
/* If a pool already exists, check if we can shrink it */
|
if ((isakmp_cfg_config.port_pool != NULL) &&
|
(size < isakmp_cfg_config.pool_size)) {
|
for (i = isakmp_cfg_config.pool_size-1; i >= size; --i) {
|
if (isakmp_cfg_config.port_pool[i].used) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"resize pool from %zu to %d impossible "
|
"port %d is in use\n",
|
isakmp_cfg_config.pool_size, size, i);
|
size = i;
|
break;
|
}
|
}
|
}
|
|
len = size * sizeof(*isakmp_cfg_config.port_pool);
|
new_pool = racoon_realloc(isakmp_cfg_config.port_pool, len);
|
if (new_pool == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"resize pool from %zu to %d impossible: %s",
|
isakmp_cfg_config.pool_size, size, strerror(errno));
|
return -1;
|
}
|
|
/* If size increase, intialize correctly the new records */
|
if (size > isakmp_cfg_config.pool_size) {
|
size_t unit;
|
size_t old_size;
|
|
unit = sizeof(*isakmp_cfg_config.port_pool);
|
old_size = isakmp_cfg_config.pool_size;
|
|
bzero((char *)new_pool + (old_size * unit),
|
(size - old_size) * unit);
|
}
|
|
isakmp_cfg_config.port_pool = new_pool;
|
isakmp_cfg_config.pool_size = size;
|
|
return 0;
|
}
|
|
int
|
isakmp_cfg_init(cold)
|
int cold;
|
{
|
int i;
|
int error;
|
|
isakmp_cfg_config.network4 = (in_addr_t)0x00000000;
|
isakmp_cfg_config.netmask4 = (in_addr_t)0x00000000;
|
for (i = 0; i < MAXNS; i++)
|
isakmp_cfg_config.dns4[i] = (in_addr_t)0x00000000;
|
isakmp_cfg_config.dns4_index = 0;
|
for (i = 0; i < MAXWINS; i++)
|
isakmp_cfg_config.nbns4[i] = (in_addr_t)0x00000000;
|
isakmp_cfg_config.nbns4_index = 0;
|
if (cold == ISAKMP_CFG_INIT_COLD)
|
isakmp_cfg_config.port_pool = NULL;
|
isakmp_cfg_config.authsource = ISAKMP_CFG_AUTH_SYSTEM;
|
isakmp_cfg_config.groupsource = ISAKMP_CFG_GROUP_SYSTEM;
|
if (cold == ISAKMP_CFG_INIT_COLD) {
|
if (isakmp_cfg_config.grouplist != NULL) {
|
for (i = 0; i < isakmp_cfg_config.groupcount; i++)
|
racoon_free(isakmp_cfg_config.grouplist[i]);
|
racoon_free(isakmp_cfg_config.grouplist);
|
}
|
}
|
isakmp_cfg_config.grouplist = NULL;
|
isakmp_cfg_config.groupcount = 0;
|
isakmp_cfg_config.confsource = ISAKMP_CFG_CONF_LOCAL;
|
isakmp_cfg_config.accounting = ISAKMP_CFG_ACCT_NONE;
|
if (cold == ISAKMP_CFG_INIT_COLD)
|
isakmp_cfg_config.pool_size = 0;
|
isakmp_cfg_config.auth_throttle = THROTTLE_PENALTY;
|
strlcpy(isakmp_cfg_config.default_domain, ISAKMP_CFG_DEFAULT_DOMAIN,
|
MAXPATHLEN);
|
strlcpy(isakmp_cfg_config.motd, ISAKMP_CFG_MOTD, MAXPATHLEN);
|
|
if (cold != ISAKMP_CFG_INIT_COLD )
|
if (isakmp_cfg_config.splitnet_list != NULL)
|
splitnet_list_free(isakmp_cfg_config.splitnet_list,
|
&isakmp_cfg_config.splitnet_count);
|
isakmp_cfg_config.splitnet_list = NULL;
|
isakmp_cfg_config.splitnet_count = 0;
|
isakmp_cfg_config.splitnet_type = 0;
|
|
isakmp_cfg_config.pfs_group = 0;
|
isakmp_cfg_config.save_passwd = 0;
|
|
if (cold != ISAKMP_CFG_INIT_COLD )
|
if (isakmp_cfg_config.splitdns_list != NULL)
|
racoon_free(isakmp_cfg_config.splitdns_list);
|
isakmp_cfg_config.splitdns_list = NULL;
|
isakmp_cfg_config.splitdns_len = 0;
|
|
#if 0
|
if (cold == ISAKMP_CFG_INIT_COLD) {
|
if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0)
|
return error;
|
}
|
#endif
|
|
return 0;
|
}
|