X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=userapps%2Fopensource%2Fipsec-tools%2Fsrc%2Fracoon%2Fisakmp_xauth.c;fp=userapps%2Fopensource%2Fipsec-tools%2Fsrc%2Fracoon%2Fisakmp_xauth.c;h=e4f7e72b178d418b32753b8acee9a0c1464e01be;hb=59e02c1be2c9b373846b0789fbd5b7ef46f0927f;hp=0000000000000000000000000000000000000000;hpb=3f05a9da74f56df22d185b66ee663a6fd8053cb3;p=bcm963xx.git diff --git a/userapps/opensource/ipsec-tools/src/racoon/isakmp_xauth.c b/userapps/opensource/ipsec-tools/src/racoon/isakmp_xauth.c new file mode 100755 index 00000000..e4f7e72b --- /dev/null +++ b/userapps/opensource/ipsec-tools/src/racoon/isakmp_xauth.c @@ -0,0 +1,795 @@ +/* $Id: isakmp_xauth.c,v 1.14 2004/11/30 00:46:09 manubsd Exp $ */ + +/* + * Copyright (C) 2004 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#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 "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 +#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; +} + +void +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; + } + + if (xst->status != XAUTHST_REQSENT) { + plog(LLV_ERROR, LOCATION, NULL, + "Xauth reply while Xauth state is %d\n", xst->status); + return; + } + + 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; + } + 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; + } + + 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 = xauth_login_system(iph1, usr, pwd); + break; +#ifdef HAVE_LIBRADIUS + case ISAKMP_CFG_AUTH_RADIUS: + res = xauth_login_radius(iph1, usr, pwd); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "Unexpected authentication source\n"); + res = -1; + break; + } + + /* + * 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"); + xauth_reply(iph1, port, id, res); + return; + } + + /* + * 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 { + xauth_reply(iph1, port, id, res); + } + } + + return; +} + +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) + 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; +} + +void +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; + } + + xst->status = XAUTHST_OK; + plog(LLV_INFO, LOCATION, NULL, + "login succeeded for user \"%s\"\n", usr); + + xauth_sendstatus(iph1, XAUTH_STATUS_OK, id); + + return; +} + +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_login_radius(iph1, usr, pwd) + struct ph1handle *iph1; + char *usr; + char *pwd; +{ + static struct rad_handle *radius_state = NULL; + int res; + const void *data; + size_t len; + int type; + + /* For first time use, initialize Radius */ + if (radius_state == NULL) { + if ((radius_state = rad_auth_open()) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot init librradius\n"); + return -1; + } + + if (rad_config(radius_state, NULL) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot open librarius config file: %s\n", + rad_strerror(radius_state)); + rad_close(radius_state); + radius_state = NULL; + return -1; + } + } + + if (rad_create_request(radius_state, RAD_ACCESS_REQUEST) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_create_request failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + if (rad_put_string(radius_state, RAD_USER_NAME, usr) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_string failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + if (rad_put_string(radius_state, RAD_USER_PASSWORD, pwd) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "rad_put_string failed: %s\n", + rad_strerror(radius_state)); + return -1; + } + + if (isakmp_cfg_radius_common(radius_state, iph1->mode_cfg->port) != 0) + return -1; + + switch (res = rad_send_request(radius_state)) { + case RAD_ACCESS_ACCEPT: + while ((type = rad_get_attr(radius_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_RADIUS; + break; + + case RAD_FRAMED_IP_NETMASK: + iph1->mode_cfg->mask4 = rad_cvt_addr(data); + iph1->mode_cfg->flags + |= ISAKMP_CFG_MASK4_RADIUS; + 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_state)); + return -1; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "rad_send_request returned %d\n", res); + return -1; + break; + } + + return -1; +} +#endif + +int +xauth_login_system(iph1, usr, pwd) + struct ph1handle *iph1; + char *usr; + char *pwd; +{ + struct passwd *pw; + char *cryptpwd; + + if ((pw = getpwnam(usr)) == NULL) + return -1; + + /* No root login. Ever. */ + if (pw->pw_uid == 0) + return -1; + + if ((cryptpwd = crypt(pwd, pw->pw_passwd)) == NULL) + return -1; + + if (strcmp(cryptpwd, pw->pw_passwd) == 0) + return 0; + + return -1; +} + +int +xauth_check(iph1) + struct ph1handle *iph1; +{ + struct xauth_state *xst = &iph1->mode_cfg->xauth; + + /* If we don't use Xauth, then we pass */ + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + /* The following are not yet implemented */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_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: + 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; +} + +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 *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->idvtype != IDTYPE_LOGIN) { + plog(LLV_ERROR, LOCATION, NULL, "Xauth performed " + "while identifier is not a login\n"); + return NULL; + } + + if (iph1->rmconf->idv == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Xauth performed " + "with no login supplied\n"); + return NULL; + } + + dlen = iph1->rmconf->idv->l; + break; + + case XAUTH_USER_PASSWORD: + if (iph1->rmconf->idvtype != IDTYPE_LOGIN) + return NULL; + + if (iph1->rmconf->idv == NULL) + return NULL; + + skip = sizeof(struct ipsecdoi_id_b); + if ((usr = vmalloc(iph1->rmconf->idv->l + skip)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate memory\n"); + return NULL; + } + + memset(usr->v, 0, skip); + memcpy(usr->v + skip, + iph1->rmconf->idv->v, + iph1->rmconf->idv->l); + + if (iph1->rmconf->key) { + /* A key given through racoonctl */ + pwd = iph1->rmconf->key; + } else { + if ((pwd = getpskbyname(usr)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "No password was found for login %s\n", + iph1->rmconf->idv->v); + vfree(usr); + return NULL; + } + /* We have to free it before returning */ + freepwd = 1; + } + vfree(usr); + + dlen = pwd->l; + + break; + + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored attribute %d\n", 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: + memcpy(data, iph1->rmconf->idv->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; + + 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: + /* 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; + default: + plog(LLV_WARNING, LOCATION, NULL, + "Ignored attribute %d\n", 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; + } + + return; +}