/* $NetBSD: isakmp_xauth.c,v 1.11.6.2 2009/04/20 13:35:36 tteras Exp $ */
|
|
/* Id: isakmp_xauth.c,v 1.38 2006/08/22 18:17:17 manubsd Exp */
|
|
/*
|
* Copyright (C) 2004-2005 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>
|
|
#include <netinet/in.h>
|
|
#include <stdlib.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <errno.h>
|
#include <pwd.h>
|
#include <grp.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
|
#include <ctype.h>
|
#include <resolv.h>
|
|
#ifdef HAVE_SHADOW_H
|
#include <shadow.h>
|
#endif
|
|
#include "var.h"
|
#include "misc.h"
|
#include "vmbuf.h"
|
#include "plog.h"
|
#include "sockmisc.h"
|
#include "schedule.h"
|
#include "debug.h"
|
|
#include "crypto_openssl.h"
|
#include "isakmp_var.h"
|
#include "isakmp.h"
|
#include "admin.h"
|
#include "privsep.h"
|
#include "evt.h"
|
#include "handler.h"
|
#include "throttle.h"
|
#include "remoteconf.h"
|
#include "isakmp_inf.h"
|
#include "isakmp_xauth.h"
|
#include "isakmp_unity.h"
|
#include "isakmp_cfg.h"
|
#include "strnames.h"
|
#include "ipsec_doi.h"
|
#include "remoteconf.h"
|
#include "localconf.h"
|
|
#ifdef HAVE_LIBRADIUS
|
#include <radlib.h>
|
|
struct rad_handle *radius_auth_state = NULL;
|
struct rad_handle *radius_acct_state = NULL;
|
#endif
|
|
#ifdef HAVE_LIBPAM
|
#include <security/pam_appl.h>
|
|
static char *PAM_usr = NULL;
|
static char *PAM_pwd = NULL;
|
static int PAM_conv(int, const struct pam_message **,
|
struct pam_response **, void *);
|
static struct pam_conv PAM_chat = { &PAM_conv, NULL };
|
#endif
|
|
#ifdef HAVE_LIBLDAP
|
#include "ldap.h"
|
#include <arpa/inet.h>
|
struct xauth_ldap_config xauth_ldap_config;
|
#endif
|
|
void
|
xauth_sendreq(iph1)
|
struct ph1handle *iph1;
|
{
|
vchar_t *buffer;
|
struct isakmp_pl_attr *attr;
|
struct isakmp_data *typeattr;
|
struct isakmp_data *usrattr;
|
struct isakmp_data *pwdattr;
|
struct xauth_state *xst = &iph1->mode_cfg->xauth;
|
size_t tlen;
|
|
/* Status checks */
|
if (iph1->status != PHASE1ST_ESTABLISHED) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth request while phase 1 is not completed\n");
|
return;
|
}
|
|
if (xst->status != XAUTHST_NOTYET) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth request whith Xauth state %d\n", xst->status);
|
return;
|
}
|
|
plog(LLV_INFO, LOCATION, NULL, "Sending Xauth request\n");
|
|
tlen = sizeof(*attr) +
|
+ sizeof(*typeattr) +
|
+ sizeof(*usrattr) +
|
+ sizeof(*pwdattr);
|
|
if ((buffer = vmalloc(tlen)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate buffer\n");
|
return;
|
}
|
|
attr = (struct isakmp_pl_attr *)buffer->v;
|
memset(attr, 0, tlen);
|
|
attr->h.len = htons(tlen);
|
attr->type = ISAKMP_CFG_REQUEST;
|
attr->id = htons(eay_random());
|
|
typeattr = (struct isakmp_data *)(attr + 1);
|
typeattr->type = htons(XAUTH_TYPE | ISAKMP_GEN_TV);
|
typeattr->lorv = htons(XAUTH_TYPE_GENERIC);
|
|
usrattr = (struct isakmp_data *)(typeattr + 1);
|
usrattr->type = htons(XAUTH_USER_NAME | ISAKMP_GEN_TLV);
|
usrattr->lorv = htons(0);
|
|
pwdattr = (struct isakmp_data *)(usrattr + 1);
|
pwdattr->type = htons(XAUTH_USER_PASSWORD | ISAKMP_GEN_TLV);
|
pwdattr->lorv = htons(0);
|
|
isakmp_cfg_send(iph1, buffer,
|
ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1);
|
|
vfree(buffer);
|
|
xst->status = XAUTHST_REQSENT;
|
|
return;
|
}
|
|
int
|
xauth_attr_reply(iph1, attr, id)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
int id;
|
{
|
char **outlet = NULL;
|
size_t alen = 0;
|
int type;
|
struct xauth_state *xst = &iph1->mode_cfg->xauth;
|
|
if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth reply but peer did not declare "
|
"itself as Xauth capable\n");
|
return -1;
|
}
|
|
if (xst->status != XAUTHST_REQSENT) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth reply while Xauth state is %d\n", xst->status);
|
return -1;
|
}
|
|
type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
|
switch (type) {
|
case XAUTH_TYPE:
|
switch (ntohs(attr->lorv)) {
|
case XAUTH_TYPE_GENERIC:
|
xst->authtype = XAUTH_TYPE_GENERIC;
|
break;
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Unexpected authentication type %d\n",
|
ntohs(type));
|
return -1;
|
}
|
break;
|
|
case XAUTH_USER_NAME:
|
outlet = &xst->authdata.generic.usr;
|
break;
|
|
case XAUTH_USER_PASSWORD:
|
outlet = &xst->authdata.generic.pwd;
|
break;
|
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"ignored Xauth attribute %d\n", type);
|
break;
|
}
|
|
if (outlet != NULL) {
|
alen = ntohs(attr->lorv);
|
|
if ((*outlet = racoon_malloc(alen + 1)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory for Xauth Data\n");
|
return -1;
|
}
|
|
memcpy(*outlet, attr + 1, alen);
|
(*outlet)[alen] = '\0';
|
outlet = NULL;
|
}
|
|
|
if ((xst->authdata.generic.usr != NULL) &&
|
(xst->authdata.generic.pwd != NULL)) {
|
int port;
|
int res;
|
char *usr = xst->authdata.generic.usr;
|
char *pwd = xst->authdata.generic.pwd;
|
time_t throttle_delay = 0;
|
|
#if 0 /* Real debug, don't do that at home */
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"Got username \"%s\", password \"%s\"\n", usr, pwd);
|
#endif
|
strncpy(iph1->mode_cfg->login, usr, LOGINLEN);
|
iph1->mode_cfg->login[LOGINLEN] = '\0';
|
|
res = -1;
|
if ((port = isakmp_cfg_getport(iph1)) == -1) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Port pool depleted\n");
|
goto skip_auth;
|
}
|
|
switch (isakmp_cfg_config.authsource) {
|
case ISAKMP_CFG_AUTH_SYSTEM:
|
res = privsep_xauth_login_system(usr, pwd);
|
break;
|
#ifdef HAVE_LIBRADIUS
|
case ISAKMP_CFG_AUTH_RADIUS:
|
res = xauth_login_radius(iph1, usr, pwd);
|
break;
|
#endif
|
#ifdef HAVE_LIBPAM
|
case ISAKMP_CFG_AUTH_PAM:
|
res = privsep_xauth_login_pam(iph1->mode_cfg->port,
|
iph1->remote, usr, pwd);
|
break;
|
#endif
|
#ifdef HAVE_LIBLDAP
|
case ISAKMP_CFG_AUTH_LDAP:
|
res = xauth_login_ldap(iph1, usr, pwd);
|
break;
|
#endif
|
default:
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unexpected authentication source\n");
|
res = -1;
|
break;
|
}
|
|
/*
|
* Optional group authentication
|
*/
|
if (!res && (isakmp_cfg_config.groupcount))
|
res = group_check(iph1,
|
isakmp_cfg_config.grouplist,
|
isakmp_cfg_config.groupcount);
|
|
/*
|
* On failure, throttle the connexion for the remote host
|
* in order to make password attacks more difficult.
|
*/
|
throttle_delay = throttle_host(iph1->remote, res) - time(NULL);
|
if (throttle_delay > 0) {
|
char *str;
|
|
str = saddrwop2str(iph1->remote);
|
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Throttling in action for %s: delay %lds\n",
|
str, (unsigned long)throttle_delay);
|
res = -1;
|
} else {
|
throttle_delay = 0;
|
}
|
|
skip_auth:
|
if (throttle_delay != 0) {
|
struct xauth_reply_arg *xra;
|
|
if ((xra = racoon_malloc(sizeof(*xra))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"malloc failed, bypass throttling\n");
|
return xauth_reply(iph1, port, id, res);
|
}
|
|
/*
|
* We need to store the ph1, but it might have
|
* disapeared when xauth_reply is called, so
|
* store the index instead.
|
*/
|
xra->index = iph1->index;
|
xra->port = port;
|
xra->id = id;
|
xra->res = res;
|
sched_new(throttle_delay, xauth_reply_stub, xra);
|
} else {
|
return xauth_reply(iph1, port, id, res);
|
}
|
}
|
|
return 0;
|
}
|
|
void
|
xauth_reply_stub(args)
|
void *args;
|
{
|
struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args;
|
struct ph1handle *iph1;
|
|
if ((iph1 = getph1byindex(&xra->index)) != NULL)
|
(void)xauth_reply(iph1, xra->port, xra->id, xra->res);
|
else
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Delayed Xauth reply: phase 1 no longer exists.\n");
|
|
racoon_free(xra);
|
return;
|
}
|
|
int
|
xauth_reply(iph1, port, id, res)
|
struct ph1handle *iph1;
|
int port;
|
int id;
|
#if defined(ANDROID_CHANGES)
|
int res;
|
#endif
|
{
|
struct xauth_state *xst = &iph1->mode_cfg->xauth;
|
char *usr = xst->authdata.generic.usr;
|
|
if (res != 0) {
|
if (port != -1)
|
isakmp_cfg_putport(iph1, port);
|
|
plog(LLV_INFO, LOCATION, NULL,
|
"login failed for user \"%s\"\n", usr);
|
|
xauth_sendstatus(iph1, XAUTH_STATUS_FAIL, id);
|
xst->status = XAUTHST_NOTYET;
|
|
/* Delete Phase 1 SA */
|
if (iph1->status == PHASE1ST_ESTABLISHED)
|
isakmp_info_send_d1(iph1);
|
remph1(iph1);
|
delph1(iph1);
|
|
return -1;
|
}
|
|
xst->status = XAUTHST_OK;
|
plog(LLV_INFO, LOCATION, NULL,
|
"login succeeded for user \"%s\"\n", usr);
|
|
xauth_sendstatus(iph1, XAUTH_STATUS_OK, id);
|
|
return 0;
|
}
|
|
void
|
xauth_sendstatus(iph1, status, id)
|
struct ph1handle *iph1;
|
int status;
|
int id;
|
{
|
vchar_t *buffer;
|
struct isakmp_pl_attr *attr;
|
struct isakmp_data *stattr;
|
size_t tlen;
|
|
tlen = sizeof(*attr) +
|
+ sizeof(*stattr);
|
|
if ((buffer = vmalloc(tlen)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate buffer\n");
|
return;
|
}
|
|
attr = (struct isakmp_pl_attr *)buffer->v;
|
memset(attr, 0, tlen);
|
|
attr->h.len = htons(tlen);
|
attr->type = ISAKMP_CFG_SET;
|
attr->id = htons(id);
|
|
stattr = (struct isakmp_data *)(attr + 1);
|
stattr->type = htons(XAUTH_STATUS | ISAKMP_GEN_TV);
|
stattr->lorv = htons(status);
|
|
isakmp_cfg_send(iph1, buffer,
|
ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1);
|
|
vfree(buffer);
|
|
return;
|
}
|
|
#ifdef HAVE_LIBRADIUS
|
int
|
xauth_radius_init(void)
|
{
|
/* For first time use, initialize Radius */
|
if ((isakmp_cfg_config.authsource == ISAKMP_CFG_AUTH_RADIUS) &&
|
(radius_auth_state == NULL)) {
|
if ((radius_auth_state = rad_auth_open()) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot init libradius\n");
|
return -1;
|
}
|
|
if (rad_config(radius_auth_state, NULL) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot open librarius config file: %s\n",
|
rad_strerror(radius_auth_state));
|
rad_close(radius_auth_state);
|
radius_auth_state = NULL;
|
return -1;
|
}
|
}
|
|
if ((isakmp_cfg_config.accounting == ISAKMP_CFG_ACCT_RADIUS) &&
|
(radius_acct_state == NULL)) {
|
if ((radius_acct_state = rad_acct_open()) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot init libradius\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;
|
}
|
}
|
|
return 0;
|
}
|
|
int
|
xauth_login_radius(iph1, usr, pwd)
|
struct ph1handle *iph1;
|
char *usr;
|
char *pwd;
|
{
|
int res;
|
const void *data;
|
size_t len;
|
int type;
|
|
if (rad_create_request(radius_auth_state, RAD_ACCESS_REQUEST) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_create_request failed: %s\n",
|
rad_strerror(radius_auth_state));
|
return -1;
|
}
|
|
if (rad_put_string(radius_auth_state, RAD_USER_NAME, usr) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_string failed: %s\n",
|
rad_strerror(radius_auth_state));
|
return -1;
|
}
|
|
if (rad_put_string(radius_auth_state, RAD_USER_PASSWORD, pwd) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_put_string failed: %s\n",
|
rad_strerror(radius_auth_state));
|
return -1;
|
}
|
|
if (isakmp_cfg_radius_common(radius_auth_state, iph1->mode_cfg->port) != 0)
|
return -1;
|
|
switch (res = rad_send_request(radius_auth_state)) {
|
case RAD_ACCESS_ACCEPT:
|
while ((type = rad_get_attr(radius_auth_state, &data, &len)) != 0) {
|
switch (type) {
|
case RAD_FRAMED_IP_ADDRESS:
|
iph1->mode_cfg->addr4 = rad_cvt_addr(data);
|
iph1->mode_cfg->flags
|
|= ISAKMP_CFG_ADDR4_EXTERN;
|
break;
|
|
case RAD_FRAMED_IP_NETMASK:
|
iph1->mode_cfg->mask4 = rad_cvt_addr(data);
|
iph1->mode_cfg->flags
|
|= ISAKMP_CFG_MASK4_EXTERN;
|
break;
|
|
default:
|
plog(LLV_INFO, LOCATION, NULL,
|
"Unexpected attribute: %d\n", type);
|
break;
|
}
|
}
|
|
return 0;
|
break;
|
|
case RAD_ACCESS_REJECT:
|
return -1;
|
break;
|
|
case -1:
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_send_request failed: %s\n",
|
rad_strerror(radius_auth_state));
|
return -1;
|
break;
|
default:
|
plog(LLV_ERROR, LOCATION, NULL,
|
"rad_send_request returned %d\n", res);
|
return -1;
|
break;
|
}
|
|
return -1;
|
}
|
#endif
|
|
#ifdef HAVE_LIBPAM
|
static int
|
PAM_conv(msg_count, msg, rsp, dontcare)
|
int msg_count;
|
const struct pam_message **msg;
|
struct pam_response **rsp;
|
void *dontcare;
|
{
|
int i;
|
int replies = 0;
|
struct pam_response *reply = NULL;
|
|
if ((reply = racoon_malloc(sizeof(*reply) * msg_count)) == NULL)
|
return PAM_CONV_ERR;
|
bzero(reply, sizeof(*reply) * msg_count);
|
|
for (i = 0; i < msg_count; i++) {
|
switch (msg[i]->msg_style) {
|
case PAM_PROMPT_ECHO_ON:
|
/* Send the username, libpam frees resp */
|
reply[i].resp_retcode = PAM_SUCCESS;
|
if ((reply[i].resp = strdup(PAM_usr)) == NULL) {
|
plog(LLV_ERROR, LOCATION,
|
NULL, "strdup failed\n");
|
exit(1);
|
}
|
break;
|
|
case PAM_PROMPT_ECHO_OFF:
|
/* Send the password, libpam frees resp */
|
reply[i].resp_retcode = PAM_SUCCESS;
|
if ((reply[i].resp = strdup(PAM_pwd)) == NULL) {
|
plog(LLV_ERROR, LOCATION,
|
NULL, "strdup failed\n");
|
exit(1);
|
}
|
break;
|
|
case PAM_TEXT_INFO:
|
case PAM_ERROR_MSG:
|
reply[i].resp_retcode = PAM_SUCCESS;
|
reply[i].resp = NULL;
|
break;
|
|
default:
|
if (reply != NULL)
|
racoon_free(reply);
|
return PAM_CONV_ERR;
|
break;
|
}
|
}
|
|
if (reply != NULL)
|
*rsp = reply;
|
|
return PAM_SUCCESS;
|
}
|
|
int
|
xauth_login_pam(port, raddr, usr, pwd)
|
int port;
|
struct sockaddr *raddr;
|
char *usr;
|
char *pwd;
|
{
|
int error;
|
int res;
|
const void *data;
|
size_t len;
|
int type;
|
char *remote = NULL;
|
pam_handle_t *pam = NULL;
|
|
if (isakmp_cfg_config.port_pool == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"isakmp_cfg_config.port_pool == NULL\n");
|
return -1;
|
}
|
|
if ((error = pam_start("racoon", usr,
|
&PAM_chat, &isakmp_cfg_config.port_pool[port].pam)) != 0) {
|
if (isakmp_cfg_config.port_pool[port].pam == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL, "pam_start failed\n");
|
return -1;
|
} else {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"pam_start failed: %s\n",
|
pam_strerror(isakmp_cfg_config.port_pool[port].pam,
|
error));
|
goto out;
|
}
|
}
|
pam = isakmp_cfg_config.port_pool[port].pam;
|
|
if ((remote = strdup(saddrwop2str(raddr))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"cannot allocate memory: %s\n", strerror(errno));
|
goto out;
|
}
|
|
if ((error = pam_set_item(pam, PAM_RHOST, remote)) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"pam_set_item failed: %s\n",
|
pam_strerror(pam, error));
|
goto out;
|
}
|
|
PAM_usr = usr;
|
PAM_pwd = pwd;
|
error = pam_authenticate(pam, 0);
|
PAM_usr = NULL;
|
PAM_pwd = NULL;
|
if (error != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"pam_authenticate failed: %s\n",
|
pam_strerror(pam, error));
|
goto out;
|
}
|
|
if ((error = pam_acct_mgmt(pam, 0)) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"pam_acct_mgmt failed: %s\n",
|
pam_strerror(pam, error));
|
goto out;
|
}
|
|
if ((error = pam_setcred(pam, 0)) != 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"pam_setcred failed: %s\n",
|
pam_strerror(pam, error));
|
goto out;
|
}
|
|
if (remote != NULL)
|
free(remote);
|
|
return 0;
|
|
out:
|
pam_end(pam, error);
|
isakmp_cfg_config.port_pool[port].pam = NULL;
|
if (remote != NULL)
|
free(remote);
|
return -1;
|
}
|
#endif
|
|
#ifdef HAVE_LIBLDAP
|
int
|
xauth_ldap_init(void)
|
{
|
int tmplen;
|
int error = -1;
|
|
xauth_ldap_config.pver = 3;
|
xauth_ldap_config.host = NULL;
|
xauth_ldap_config.port = LDAP_PORT;
|
xauth_ldap_config.base = NULL;
|
xauth_ldap_config.subtree = 0;
|
xauth_ldap_config.bind_dn = NULL;
|
xauth_ldap_config.bind_pw = NULL;
|
xauth_ldap_config.auth_type = LDAP_AUTH_SIMPLE;
|
xauth_ldap_config.attr_user = NULL;
|
xauth_ldap_config.attr_addr = NULL;
|
xauth_ldap_config.attr_mask = NULL;
|
xauth_ldap_config.attr_group = NULL;
|
xauth_ldap_config.attr_member = NULL;
|
|
/* set default host */
|
tmplen = strlen(LDAP_DFLT_HOST);
|
xauth_ldap_config.host = vmalloc(tmplen);
|
if (xauth_ldap_config.host == NULL)
|
goto out;
|
memcpy(xauth_ldap_config.host->v, LDAP_DFLT_HOST, tmplen);
|
|
/* set default user naming attribute */
|
tmplen = strlen(LDAP_DFLT_USER);
|
xauth_ldap_config.attr_user = vmalloc(tmplen);
|
if (xauth_ldap_config.attr_user == NULL)
|
goto out;
|
memcpy(xauth_ldap_config.attr_user->v, LDAP_DFLT_USER, tmplen);
|
|
/* set default address attribute */
|
tmplen = strlen(LDAP_DFLT_ADDR);
|
xauth_ldap_config.attr_addr = vmalloc(tmplen);
|
if (xauth_ldap_config.attr_addr == NULL)
|
goto out;
|
memcpy(xauth_ldap_config.attr_addr->v, LDAP_DFLT_ADDR, tmplen);
|
|
/* set default netmask attribute */
|
tmplen = strlen(LDAP_DFLT_MASK);
|
xauth_ldap_config.attr_mask = vmalloc(tmplen);
|
if (xauth_ldap_config.attr_mask == NULL)
|
goto out;
|
memcpy(xauth_ldap_config.attr_mask->v, LDAP_DFLT_MASK, tmplen);
|
|
/* set default group naming attribute */
|
tmplen = strlen(LDAP_DFLT_GROUP);
|
xauth_ldap_config.attr_group = vmalloc(tmplen);
|
if (xauth_ldap_config.attr_group == NULL)
|
goto out;
|
memcpy(xauth_ldap_config.attr_group->v, LDAP_DFLT_GROUP, tmplen);
|
|
/* set default member attribute */
|
tmplen = strlen(LDAP_DFLT_MEMBER);
|
xauth_ldap_config.attr_member = vmalloc(tmplen);
|
if (xauth_ldap_config.attr_member == NULL)
|
goto out;
|
memcpy(xauth_ldap_config.attr_member->v, LDAP_DFLT_MEMBER, tmplen);
|
|
error = 0;
|
out:
|
if (error != 0)
|
plog(LLV_ERROR, LOCATION, NULL, "cannot allocate memory\n");
|
|
return error;
|
}
|
|
int
|
xauth_login_ldap(iph1, usr, pwd)
|
struct ph1handle *iph1;
|
char *usr;
|
char *pwd;
|
{
|
int rtn = -1;
|
int res = -1;
|
LDAP *ld = NULL;
|
LDAPMessage *lr = NULL;
|
LDAPMessage *le = NULL;
|
struct berval cred;
|
struct berval **bv = NULL;
|
struct timeval timeout;
|
char *init = NULL;
|
char *filter = NULL;
|
char *atlist[3];
|
char *basedn = NULL;
|
char *userdn = NULL;
|
int tmplen = 0;
|
int ecount = 0;
|
int scope = LDAP_SCOPE_ONE;
|
|
atlist[0] = NULL;
|
atlist[1] = NULL;
|
atlist[2] = NULL;
|
|
/* build our initialization url */
|
tmplen = strlen("ldap://:") + 17;
|
tmplen += strlen(xauth_ldap_config.host->v);
|
init = racoon_malloc(tmplen);
|
if (init == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"unable to alloc ldap init url\n");
|
goto ldap_end;
|
}
|
sprintf(init,"ldap://%s:%d",
|
xauth_ldap_config.host->v,
|
xauth_ldap_config.port );
|
|
/* initialize the ldap handle */
|
res = ldap_initialize(&ld, init);
|
if (res != LDAP_SUCCESS) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_initialize failed: %s\n",
|
ldap_err2string(res));
|
goto ldap_end;
|
}
|
|
/* initialize the protocol version */
|
ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
|
&xauth_ldap_config.pver);
|
|
/*
|
* attempt to bind to the ldap server.
|
* default to anonymous bind unless a
|
* user dn and password has been
|
* specified in our configuration
|
*/
|
if ((xauth_ldap_config.bind_dn != NULL)&&
|
(xauth_ldap_config.bind_pw != NULL))
|
{
|
cred.bv_val = xauth_ldap_config.bind_pw->v;
|
cred.bv_len = strlen( cred.bv_val );
|
res = ldap_sasl_bind_s(ld,
|
xauth_ldap_config.bind_dn->v, NULL, &cred,
|
NULL, NULL, NULL);
|
}
|
else
|
{
|
res = ldap_sasl_bind_s(ld,
|
NULL, NULL, NULL,
|
NULL, NULL, NULL);
|
}
|
|
if (res!=LDAP_SUCCESS) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_sasl_bind_s (search) failed: %s\n",
|
ldap_err2string(res));
|
goto ldap_end;
|
}
|
|
/* build an ldap user search filter */
|
tmplen = strlen(xauth_ldap_config.attr_user->v);
|
tmplen += 1;
|
tmplen += strlen(usr);
|
tmplen += 1;
|
filter = racoon_malloc(tmplen);
|
if (filter == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"unable to alloc ldap search filter buffer\n");
|
goto ldap_end;
|
}
|
sprintf(filter, "%s=%s",
|
xauth_ldap_config.attr_user->v, usr);
|
|
/* build our return attribute list */
|
tmplen = strlen(xauth_ldap_config.attr_addr->v) + 1;
|
atlist[0] = racoon_malloc(tmplen);
|
tmplen = strlen(xauth_ldap_config.attr_mask->v) + 1;
|
atlist[1] = racoon_malloc(tmplen);
|
if ((atlist[0] == NULL)||(atlist[1] == NULL)) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"unable to alloc ldap attrib list buffer\n");
|
goto ldap_end;
|
}
|
strcpy(atlist[0],xauth_ldap_config.attr_addr->v);
|
strcpy(atlist[1],xauth_ldap_config.attr_mask->v);
|
|
/* attempt to locate the user dn */
|
if (xauth_ldap_config.base != NULL)
|
basedn = xauth_ldap_config.base->v;
|
if (xauth_ldap_config.subtree)
|
scope = LDAP_SCOPE_SUBTREE;
|
timeout.tv_sec = 15;
|
timeout.tv_usec = 0;
|
res = ldap_search_ext_s(ld, basedn, scope,
|
filter, atlist, 0, NULL, NULL,
|
&timeout, 2, &lr);
|
if (res != LDAP_SUCCESS) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_search_ext_s failed: %s\n",
|
ldap_err2string(res));
|
goto ldap_end;
|
}
|
|
/* check the number of ldap entries returned */
|
ecount = ldap_count_entries(ld, lr);
|
if (ecount < 1) {
|
plog(LLV_WARNING, LOCATION, NULL,
|
"no ldap results for filter \'%s\'\n",
|
filter);
|
goto ldap_end;
|
}
|
if (ecount > 1) {
|
plog(LLV_WARNING, LOCATION, NULL,
|
"multiple (%i) ldap results for filter \'%s\'\n",
|
ecount, filter);
|
}
|
|
/* obtain the dn from the first result */
|
le = ldap_first_entry(ld, lr);
|
if (le == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_first_entry failed: invalid entry returned\n");
|
goto ldap_end;
|
}
|
userdn = ldap_get_dn(ld, le);
|
if (userdn == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_get_dn failed: invalid string returned\n");
|
goto ldap_end;
|
}
|
|
/* cache the user dn in the xauth state */
|
iph1->mode_cfg->xauth.udn = racoon_malloc(strlen(userdn)+1);
|
strcpy(iph1->mode_cfg->xauth.udn,userdn);
|
|
/* retrieve modecfg address */
|
bv = ldap_get_values_len(ld, le, xauth_ldap_config.attr_addr->v);
|
if (bv != NULL) {
|
char tmpaddr[16];
|
/* sanity check for address value */
|
if ((bv[0]->bv_len < 7)||(bv[0]->bv_len > 15)) {
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"ldap returned invalid modecfg address\n");
|
ldap_value_free_len(bv);
|
goto ldap_end;
|
}
|
memcpy(tmpaddr,bv[0]->bv_val,bv[0]->bv_len);
|
tmpaddr[bv[0]->bv_len]=0;
|
iph1->mode_cfg->addr4.s_addr = inet_addr(tmpaddr);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_ADDR4_EXTERN;
|
plog(LLV_INFO, LOCATION, NULL,
|
"ldap returned modecfg address %s\n", tmpaddr);
|
ldap_value_free_len(bv);
|
}
|
|
/* retrieve modecfg netmask */
|
bv = ldap_get_values_len(ld, le, xauth_ldap_config.attr_mask->v);
|
if (bv != NULL) {
|
char tmpmask[16];
|
/* sanity check for netmask value */
|
if ((bv[0]->bv_len < 7)||(bv[0]->bv_len > 15)) {
|
plog(LLV_DEBUG, LOCATION, NULL,
|
"ldap returned invalid modecfg netmask\n");
|
ldap_value_free_len(bv);
|
goto ldap_end;
|
}
|
memcpy(tmpmask,bv[0]->bv_val,bv[0]->bv_len);
|
tmpmask[bv[0]->bv_len]=0;
|
iph1->mode_cfg->mask4.s_addr = inet_addr(tmpmask);
|
iph1->mode_cfg->flags |= ISAKMP_CFG_MASK4_EXTERN;
|
plog(LLV_INFO, LOCATION, NULL,
|
"ldap returned modecfg netmask %s\n", tmpmask);
|
ldap_value_free_len(bv);
|
}
|
|
/*
|
* finally, use the dn and the xauth
|
* password to check the users given
|
* credentials by attempting to bind
|
* to the ldap server
|
*/
|
plog(LLV_INFO, LOCATION, NULL,
|
"attempting ldap bind for dn \'%s\'\n", userdn);
|
cred.bv_val = pwd;
|
cred.bv_len = strlen( cred.bv_val );
|
res = ldap_sasl_bind_s(ld,
|
userdn, NULL, &cred,
|
NULL, NULL, NULL);
|
if(res==LDAP_SUCCESS)
|
rtn = 0;
|
|
ldap_end:
|
|
/* free ldap resources */
|
if (userdn != NULL)
|
ldap_memfree(userdn);
|
if (atlist[0] != NULL)
|
racoon_free(atlist[0]);
|
if (atlist[1] != NULL)
|
racoon_free(atlist[1]);
|
if (filter != NULL)
|
racoon_free(filter);
|
if (lr != NULL)
|
ldap_msgfree(lr);
|
if (init != NULL)
|
racoon_free(init);
|
|
ldap_unbind_ext_s(ld, NULL, NULL);
|
|
return rtn;
|
}
|
|
int
|
xauth_group_ldap(udn, grp)
|
char * udn;
|
char * grp;
|
{
|
int rtn = -1;
|
int res = -1;
|
LDAP *ld = NULL;
|
LDAPMessage *lr = NULL;
|
LDAPMessage *le = NULL;
|
struct berval cred;
|
struct timeval timeout;
|
char *init = NULL;
|
char *filter = NULL;
|
char *basedn = NULL;
|
char *groupdn = NULL;
|
int tmplen = 0;
|
int ecount = 0;
|
int scope = LDAP_SCOPE_ONE;
|
|
/* build our initialization url */
|
tmplen = strlen("ldap://:") + 17;
|
tmplen += strlen(xauth_ldap_config.host->v);
|
init = racoon_malloc(tmplen);
|
if (init == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"unable to alloc ldap init url\n");
|
goto ldap_group_end;
|
}
|
sprintf(init,"ldap://%s:%d",
|
xauth_ldap_config.host->v,
|
xauth_ldap_config.port );
|
|
/* initialize the ldap handle */
|
res = ldap_initialize(&ld, init);
|
if (res != LDAP_SUCCESS) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_initialize failed: %s\n",
|
ldap_err2string(res));
|
goto ldap_group_end;
|
}
|
|
/* initialize the protocol version */
|
ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
|
&xauth_ldap_config.pver);
|
|
/*
|
* attempt to bind to the ldap server.
|
* default to anonymous bind unless a
|
* user dn and password has been
|
* specified in our configuration
|
*/
|
if ((xauth_ldap_config.bind_dn != NULL)&&
|
(xauth_ldap_config.bind_pw != NULL))
|
{
|
cred.bv_val = xauth_ldap_config.bind_pw->v;
|
cred.bv_len = strlen( cred.bv_val );
|
res = ldap_sasl_bind_s(ld,
|
xauth_ldap_config.bind_dn->v, NULL, &cred,
|
NULL, NULL, NULL);
|
}
|
else
|
{
|
res = ldap_sasl_bind_s(ld,
|
NULL, NULL, NULL,
|
NULL, NULL, NULL);
|
}
|
|
if (res!=LDAP_SUCCESS) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_sasl_bind_s (search) failed: %s\n",
|
ldap_err2string(res));
|
goto ldap_group_end;
|
}
|
|
/* build an ldap group search filter */
|
tmplen = strlen("(&(=)(=))") + 1;
|
tmplen += strlen(xauth_ldap_config.attr_group->v);
|
tmplen += strlen(grp);
|
tmplen += strlen(xauth_ldap_config.attr_member->v);
|
tmplen += strlen(udn);
|
filter = racoon_malloc(tmplen);
|
if (filter == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"unable to alloc ldap search filter buffer\n");
|
goto ldap_group_end;
|
}
|
sprintf(filter, "(&(%s=%s)(%s=%s))",
|
xauth_ldap_config.attr_group->v, grp,
|
xauth_ldap_config.attr_member->v, udn);
|
|
/* attempt to locate the group dn */
|
if (xauth_ldap_config.base != NULL)
|
basedn = xauth_ldap_config.base->v;
|
if (xauth_ldap_config.subtree)
|
scope = LDAP_SCOPE_SUBTREE;
|
timeout.tv_sec = 15;
|
timeout.tv_usec = 0;
|
res = ldap_search_ext_s(ld, basedn, scope,
|
filter, NULL, 0, NULL, NULL,
|
&timeout, 2, &lr);
|
if (res != LDAP_SUCCESS) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_search_ext_s failed: %s\n",
|
ldap_err2string(res));
|
goto ldap_group_end;
|
}
|
|
/* check the number of ldap entries returned */
|
ecount = ldap_count_entries(ld, lr);
|
if (ecount < 1) {
|
plog(LLV_WARNING, LOCATION, NULL,
|
"no ldap results for filter \'%s\'\n",
|
filter);
|
goto ldap_group_end;
|
}
|
|
/* success */
|
rtn = 0;
|
|
/* obtain the dn from the first result */
|
le = ldap_first_entry(ld, lr);
|
if (le == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_first_entry failed: invalid entry returned\n");
|
goto ldap_group_end;
|
}
|
groupdn = ldap_get_dn(ld, le);
|
if (groupdn == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"ldap_get_dn failed: invalid string returned\n");
|
goto ldap_group_end;
|
}
|
|
plog(LLV_INFO, LOCATION, NULL,
|
"ldap membership group returned \'%s\'\n", groupdn);
|
ldap_group_end:
|
|
/* free ldap resources */
|
if (groupdn != NULL)
|
ldap_memfree(groupdn);
|
if (filter != NULL)
|
racoon_free(filter);
|
if (lr != NULL)
|
ldap_msgfree(lr);
|
if (init != NULL)
|
racoon_free(init);
|
|
ldap_unbind_ext_s(ld, NULL, NULL);
|
|
return rtn;
|
}
|
|
#endif
|
|
#ifndef ANDROID_PATCHED
|
|
int
|
xauth_login_system(usr, pwd)
|
char *usr;
|
char *pwd;
|
{
|
struct passwd *pw;
|
char *cryptpwd;
|
char *syscryptpwd;
|
#ifdef HAVE_SHADOW_H
|
struct spwd *spw;
|
|
if ((spw = getspnam(usr)) == NULL)
|
return -1;
|
|
syscryptpwd = spw->sp_pwdp;
|
#endif
|
|
if ((pw = getpwnam(usr)) == NULL)
|
return -1;
|
|
#ifndef HAVE_SHADOW_H
|
syscryptpwd = pw->pw_passwd;
|
#endif
|
|
/* No root login. Ever. */
|
if (pw->pw_uid == 0)
|
return -1;
|
|
if ((cryptpwd = crypt(pwd, syscryptpwd)) == NULL)
|
return -1;
|
|
if (strcmp(cryptpwd, syscryptpwd) == 0)
|
return 0;
|
|
return -1;
|
}
|
|
#endif
|
|
int
|
xauth_group_system(usr, grp)
|
char * usr;
|
char * grp;
|
{
|
struct group * gr;
|
char * member;
|
int index = 0;
|
|
gr = getgrnam(grp);
|
if (gr == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"the system group name \'%s\' is unknown\n",
|
grp);
|
return -1;
|
}
|
|
while ((member = gr->gr_mem[index++])!=NULL) {
|
if (!strcmp(member,usr)) {
|
plog(LLV_INFO, LOCATION, NULL,
|
"membership validated\n");
|
return 0;
|
}
|
}
|
|
return -1;
|
}
|
|
int
|
xauth_check(iph1)
|
struct ph1handle *iph1;
|
{
|
struct xauth_state *xst = &iph1->mode_cfg->xauth;
|
|
/*
|
* Only the server side (edge device) really check for Xauth
|
* status. It does it if the chose authmethod is using Xauth.
|
* On the client side (roadwarrior), we don't check anything.
|
*/
|
switch (AUTHMETHOD(iph1)) {
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
|
/* The following are not yet implemented */
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
|
if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Hybrid auth negotiated but peer did not "
|
"announced as Xauth capable\n");
|
return -1;
|
}
|
|
if (xst->status != XAUTHST_OK) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Hybrid auth negotiated but peer did not "
|
"succeed Xauth exchange\n");
|
return -1;
|
}
|
|
return 0;
|
break;
|
default:
|
return 0;
|
break;
|
}
|
|
return 0;
|
}
|
|
int
|
group_check(iph1, grp_list, grp_count)
|
struct ph1handle *iph1;
|
char **grp_list;
|
int grp_count;
|
{
|
int res = -1;
|
int grp_index = 0;
|
char * usr = NULL;
|
|
/* check for presence of modecfg data */
|
|
if(iph1->mode_cfg == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"xauth group specified but modecfg not found\n");
|
return res;
|
}
|
|
/* loop through our group list */
|
|
for(; grp_index < grp_count; grp_index++) {
|
|
/* check for presence of xauth data */
|
|
usr = iph1->mode_cfg->xauth.authdata.generic.usr;
|
|
if(usr == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"xauth group specified but xauth not found\n");
|
return res;
|
}
|
|
/* call appropriate group validation funtion */
|
|
switch (isakmp_cfg_config.groupsource) {
|
|
case ISAKMP_CFG_GROUP_SYSTEM:
|
res = xauth_group_system(
|
usr,
|
grp_list[grp_index]);
|
break;
|
|
#ifdef HAVE_LIBLDAP
|
case ISAKMP_CFG_GROUP_LDAP:
|
res = xauth_group_ldap(
|
iph1->mode_cfg->xauth.udn,
|
grp_list[grp_index]);
|
break;
|
#endif
|
|
default:
|
/* we should never get here */
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unknown group auth source\n");
|
break;
|
}
|
|
if( !res ) {
|
plog(LLV_INFO, LOCATION, NULL,
|
"user \"%s\" is a member of group \"%s\"\n",
|
usr,
|
grp_list[grp_index]);
|
break;
|
} else {
|
plog(LLV_INFO, LOCATION, NULL,
|
"user \"%s\" is not a member of group \"%s\"\n",
|
usr,
|
grp_list[grp_index]);
|
}
|
}
|
|
return res;
|
}
|
|
vchar_t *
|
isakmp_xauth_req(iph1, attr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
{
|
int type;
|
size_t dlen = 0;
|
int ashort = 0;
|
int value = 0;
|
vchar_t *buffer = NULL;
|
char *mraw = NULL, *mdata;
|
char *data;
|
vchar_t *usr = NULL;
|
vchar_t *pwd = NULL;
|
size_t skip = 0;
|
int freepwd = 0;
|
|
if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth mode config request but peer "
|
"did not declare itself as Xauth capable\n");
|
return NULL;
|
}
|
|
type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
|
|
/* Sanity checks */
|
switch(type) {
|
case XAUTH_TYPE:
|
if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unexpected long XAUTH_TYPE attribute\n");
|
return NULL;
|
}
|
if (ntohs(attr->lorv) != XAUTH_TYPE_GENERIC) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unsupported Xauth authentication %d\n",
|
ntohs(attr->lorv));
|
return NULL;
|
}
|
ashort = 1;
|
dlen = 0;
|
value = XAUTH_TYPE_GENERIC;
|
break;
|
|
case XAUTH_USER_NAME:
|
if (!iph1->rmconf->xauth || !iph1->rmconf->xauth->login) {
|
plog(LLV_ERROR, LOCATION, NULL, "Xauth performed "
|
"with no login supplied\n");
|
return NULL;
|
}
|
|
dlen = iph1->rmconf->xauth->login->l - 1;
|
iph1->rmconf->xauth->state |= XAUTH_SENT_USERNAME;
|
break;
|
|
#ifdef ANDROID_PATCHED
|
case XAUTH_PASSCODE:
|
#endif
|
case XAUTH_USER_PASSWORD:
|
if (!iph1->rmconf->xauth || !iph1->rmconf->xauth->login)
|
return NULL;
|
|
skip = sizeof(struct ipsecdoi_id_b);
|
usr = vmalloc(iph1->rmconf->xauth->login->l - 1 + skip);
|
if (usr == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory\n");
|
return NULL;
|
}
|
memset(usr->v, 0, skip);
|
memcpy(usr->v + skip,
|
iph1->rmconf->xauth->login->v,
|
iph1->rmconf->xauth->login->l - 1);
|
|
if (iph1->rmconf->xauth->pass) {
|
/* A key given through racoonctl */
|
pwd = iph1->rmconf->xauth->pass;
|
} else {
|
if ((pwd = getpskbyname(usr)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"No password was found for login %s\n",
|
iph1->rmconf->xauth->login->v);
|
vfree(usr);
|
return NULL;
|
}
|
/* We have to free it before returning */
|
freepwd = 1;
|
}
|
vfree(usr);
|
|
iph1->rmconf->xauth->state |= XAUTH_SENT_PASSWORD;
|
dlen = pwd->l;
|
|
break;
|
case XAUTH_MESSAGE:
|
if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) {
|
dlen = ntohs(attr->lorv);
|
if (dlen > 0) {
|
mraw = (char*)(attr + 1);
|
mdata = binsanitize(mraw, dlen);
|
if (mdata == NULL) {
|
plog(LLV_ERROR, LOCATION, iph1->remote,
|
"Cannot allocate memory\n");
|
return NULL;
|
}
|
plog(LLV_NOTIFY,LOCATION, iph1->remote,
|
"XAUTH Message: '%s'.\n",
|
mdata);
|
racoon_free(mdata);
|
}
|
}
|
return NULL;
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Ignored attribute %s\n", s_isakmp_cfg_type(type));
|
return NULL;
|
break;
|
}
|
|
if ((buffer = vmalloc(sizeof(*attr) + dlen)) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory\n");
|
goto out;
|
}
|
|
attr = (struct isakmp_data *)buffer->v;
|
if (ashort) {
|
attr->type = htons(type | ISAKMP_GEN_TV);
|
attr->lorv = htons(value);
|
goto out;
|
}
|
|
attr->type = htons(type | ISAKMP_GEN_TLV);
|
attr->lorv = htons(dlen);
|
data = (char *)(attr + 1);
|
|
switch(type) {
|
case XAUTH_USER_NAME:
|
/*
|
* iph1->rmconf->xauth->login->v is valid,
|
* we just checked it in the previous switch case
|
*/
|
memcpy(data, iph1->rmconf->xauth->login->v, dlen);
|
break;
|
#ifdef ANDROID_PATCHED
|
case XAUTH_PASSCODE:
|
#endif
|
case XAUTH_USER_PASSWORD:
|
memcpy(data, pwd->v, dlen);
|
break;
|
default:
|
break;
|
}
|
|
out:
|
if (freepwd)
|
vfree(pwd);
|
|
return buffer;
|
}
|
|
vchar_t *
|
isakmp_xauth_set(iph1, attr)
|
struct ph1handle *iph1;
|
struct isakmp_data *attr;
|
{
|
int type;
|
vchar_t *buffer = NULL;
|
char *data;
|
struct xauth_state *xst;
|
size_t dlen = 0;
|
char* mraw = NULL, *mdata;
|
|
if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth mode config set but peer "
|
"did not declare itself as Xauth capable\n");
|
return NULL;
|
}
|
|
type = ntohs(attr->type) & ~ISAKMP_GEN_MASK;
|
|
switch(type) {
|
case XAUTH_STATUS:
|
/*
|
* We should only receive ISAKMP mode_cfg SET XAUTH_STATUS
|
* when running as a client (initiator).
|
*/
|
xst = &iph1->mode_cfg->xauth;
|
switch(AUTHMETHOD(iph1)) {
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
|
case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
|
/* Not implemented ... */
|
case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I:
|
case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
|
break;
|
default:
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Unexpected XAUTH_STATUS_OK\n");
|
return NULL;
|
break;
|
}
|
|
/* If we got a failure, delete iph1 */
|
if (ntohs(attr->lorv) != XAUTH_STATUS_OK) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Xauth authentication failed\n");
|
|
EVT_PUSH(iph1->local, iph1->remote,
|
EVTT_XAUTH_FAILED, NULL);
|
|
iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1;
|
} else {
|
EVT_PUSH(iph1->local, iph1->remote,
|
EVTT_XAUTH_SUCCESS, NULL);
|
}
|
|
|
/* We acknowledge it */
|
break;
|
case XAUTH_MESSAGE:
|
if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) {
|
dlen = ntohs(attr->lorv);
|
if (dlen > 0) {
|
mraw = (char*)(attr + 1);
|
mdata = binsanitize(mraw, dlen);
|
if (mdata == NULL) {
|
plog(LLV_ERROR, LOCATION, iph1->remote,
|
"Cannot allocate memory\n");
|
return NULL;
|
}
|
plog(LLV_NOTIFY,LOCATION, iph1->remote,
|
"XAUTH Message: '%s'.\n",
|
mdata);
|
racoon_free(mdata);
|
}
|
}
|
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Ignored attribute %s\n", s_isakmp_cfg_type(type));
|
return NULL;
|
break;
|
}
|
|
if ((buffer = vmalloc(sizeof(*attr))) == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"Cannot allocate memory\n");
|
return NULL;
|
}
|
|
attr = (struct isakmp_data *)buffer->v;
|
attr->type = htons(type | ISAKMP_GEN_TV);
|
attr->lorv = htons(0);
|
|
return buffer;
|
}
|
|
|
void
|
xauth_rmstate(xst)
|
struct xauth_state *xst;
|
{
|
switch (xst->authtype) {
|
case XAUTH_TYPE_GENERIC:
|
if (xst->authdata.generic.usr)
|
racoon_free(xst->authdata.generic.usr);
|
|
if (xst->authdata.generic.pwd)
|
racoon_free(xst->authdata.generic.pwd);
|
|
break;
|
|
case XAUTH_TYPE_CHAP:
|
case XAUTH_TYPE_OTP:
|
case XAUTH_TYPE_SKEY:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Unsupported authtype %d\n", xst->authtype);
|
break;
|
|
default:
|
plog(LLV_WARNING, LOCATION, NULL,
|
"Unexpected authtype %d\n", xst->authtype);
|
break;
|
}
|
|
#ifdef HAVE_LIBLDAP
|
if (xst->udn != NULL)
|
racoon_free(xst->udn);
|
#endif
|
return;
|
}
|
|
int
|
xauth_rmconf_used(xauth_rmconf)
|
struct xauth_rmconf **xauth_rmconf;
|
{
|
if (*xauth_rmconf == NULL) {
|
*xauth_rmconf = racoon_malloc(sizeof(**xauth_rmconf));
|
if (*xauth_rmconf == NULL) {
|
plog(LLV_ERROR, LOCATION, NULL,
|
"xauth_rmconf_used: malloc failed\n");
|
return -1;
|
}
|
|
(*xauth_rmconf)->login = NULL;
|
(*xauth_rmconf)->pass = NULL;
|
(*xauth_rmconf)->state = 0;
|
}
|
|
return 0;
|
}
|
|
void
|
xauth_rmconf_delete(xauth_rmconf)
|
struct xauth_rmconf **xauth_rmconf;
|
{
|
if (*xauth_rmconf != NULL) {
|
if ((*xauth_rmconf)->login != NULL)
|
vfree((*xauth_rmconf)->login);
|
if ((*xauth_rmconf)->pass != NULL)
|
vfree((*xauth_rmconf)->pass);
|
|
racoon_free(*xauth_rmconf);
|
*xauth_rmconf = NULL;
|
}
|
|
return;
|
}
|