diff options
Diffstat (limited to 'ipsec-tools/src/racoon/isakmp_xauth.c')
-rw-r--r-- | ipsec-tools/src/racoon/isakmp_xauth.c | 1809 |
1 files changed, 1809 insertions, 0 deletions
diff --git a/ipsec-tools/src/racoon/isakmp_xauth.c b/ipsec-tools/src/racoon/isakmp_xauth.c new file mode 100644 index 00000000..94c72d6d --- /dev/null +++ b/ipsec-tools/src/racoon/isakmp_xauth.c @@ -0,0 +1,1809 @@ +/* $NetBSD: isakmp_xauth.c,v 1.22.2.1 2013/02/05 06:23:42 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 <assert.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; +struct xauth_rad_config xauth_rad_config; +#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); + 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_calloc(1, 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_schedule(&xra->sc, throttle_delay, + xauth_reply_stub); + } else { + return xauth_reply(iph1, port, id, res); + } + } + + return 0; +} + +void +xauth_reply_stub(sc) + struct sched *sc; +{ + struct xauth_reply_arg *xra = container_of(sc, struct xauth_reply_arg, sc); + 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); +} + +int +xauth_reply(iph1, port, id, res) + struct ph1handle *iph1; + int port; + int id; +{ + 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_conf(int free) +{ + /* free radius config resources */ + if (free) { + int i; + for (i = 0; i < xauth_rad_config.auth_server_count; i++) { + vfree(xauth_rad_config.auth_server_list[i].host); + vfree(xauth_rad_config.auth_server_list[i].secret); + } + for (i = 0; i < xauth_rad_config.acct_server_count; i++) { + vfree(xauth_rad_config.acct_server_list[i].host); + vfree(xauth_rad_config.acct_server_list[i].secret); + } + if (radius_auth_state != NULL) { + rad_close(radius_auth_state); + radius_auth_state = NULL; + } + if (radius_acct_state != NULL) { + rad_close(radius_acct_state); + radius_acct_state = NULL; + } + } + + /* initialize radius config */ + memset(&xauth_rad_config, 0, sizeof(xauth_rad_config)); + return 0; +} + +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; + } + + int auth_count = xauth_rad_config.auth_server_count; + int auth_added = 0; + if (auth_count) { + int i; + for (i = 0; i < auth_count; i++) { + if(!rad_add_server( + radius_auth_state, + xauth_rad_config.auth_server_list[i].host->v, + xauth_rad_config.auth_server_list[i].port, + xauth_rad_config.auth_server_list[i].secret->v, + xauth_rad_config.timeout, + xauth_rad_config.retries )) + auth_added++; + else + plog(LLV_WARNING, LOCATION, NULL, + "could not add radius auth server %s\n", + xauth_rad_config.auth_server_list[i].host->v); + } + } + + if (!auth_added) { + if (rad_config(radius_auth_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open libradius 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; + } + + int acct_count = xauth_rad_config.acct_server_count; + int acct_added = 0; + if (acct_count) { + int i; + for (i = 0; i < acct_count; i++) { + if(!rad_add_server( + radius_acct_state, + xauth_rad_config.acct_server_list[i].host->v, + xauth_rad_config.acct_server_list[i].port, + xauth_rad_config.acct_server_list[i].secret->v, + xauth_rad_config.timeout, + xauth_rad_config.retries )) + acct_added++; + else + plog(LLV_WARNING, LOCATION, NULL, + "could not add radius account server %s\n", + xauth_rad_config.acct_server_list[i].host->v); + } + } + + if (!acct_added) { + if (rad_config(radius_acct_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open libradius 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; + } + + if ((error = pam_set_item(pam, PAM_RUSER, usr)) != 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_conf(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 + +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; +} + +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 (iph1->approval->authmethod) { + 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; + + 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; + 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 (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_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_phase1(iph1, EVT_PHASE1_XAUTH_FAILED, NULL); + + iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1; + } else { + evt_phase1(iph1, EVT_PHASE1_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; +} + +struct xauth_rmconf * +xauth_rmconf_dup(xauth_rmconf) + struct xauth_rmconf *xauth_rmconf; +{ + struct xauth_rmconf *new; + + if (xauth_rmconf != NULL) { + new = racoon_malloc(sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "xauth_rmconf_dup: malloc failed\n"); + return NULL; + } + + memcpy(new, xauth_rmconf, sizeof(*new)); + + if (xauth_rmconf->login != NULL) { + new->login = vdup(xauth_rmconf->login); + if (new->login == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "xauth_rmconf_dup: malloc failed (login)\n"); + return NULL; + } + } + if (xauth_rmconf->pass != NULL) { + new->pass = vdup(xauth_rmconf->pass); + if (new->pass == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "xauth_rmconf_dup: malloc failed (password)\n"); + return NULL; + } + } + + return new; + } + + return NULL; +} |