/*
* Copyright (C) 2005 International Business Machines Corporation
* Copyright (c) 2005 by Trusted Computer Solutions, Inc.
* 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <selinux/selinux.h>
#include <selinux/flask.h>
#include <selinux/av_permissions.h>
#include <selinux/avc.h>
#include <selinux/context.h>
#include "var.h"
#include "vmbuf.h"
#include "misc.h"
#include "plog.h"
#include "isakmp_var.h"
#include "isakmp.h"
#include "ipsec_doi.h"
#include "policy.h"
#include "proposal.h"
#include "strnames.h"
#include "handler.h"
/*
* Get the security context information from SA.
*/
int
get_security_context(sa, p)
vchar_t *sa;
struct policyindex *p;
{
int len = 0;
int flag, type = 0;
u_int16_t lorv;
caddr_t bp;
vchar_t *pbuf = NULL;
vchar_t *tbuf = NULL;
struct isakmp_parse_t *pa;
struct isakmp_parse_t *ta;
struct isakmp_pl_p *prop;
struct isakmp_pl_t *trns;
struct isakmp_data *d;
struct ipsecdoi_sa_b *sab = (struct ipsecdoi_sa_b *)sa->v;
/* check SA payload size */
if (sa->l < sizeof(*sab)) {
plog(LLV_ERROR, LOCATION, NULL,
"Invalid SA length = %zu.\n", sa->l);
return -1;
}
bp = (caddr_t)(sab + 1); /* here bp points to first proposal payload */
len = sa->l - sizeof(*sab);
pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, len);
if (pbuf == NULL)
return -1;
pa = (struct isakmp_parse_t *)pbuf->v;
/* check the value of next payload */
if (pa->type != ISAKMP_NPTYPE_P) {
plog(LLV_ERROR, LOCATION, NULL,
"Invalid payload type=%u\n", pa->type);
vfree(pbuf);
return -1;
}
if (pa->len == 0) {
plog(LLV_ERROR, LOCATION, NULL,
"invalid proposal with length %d\n", pa->len);
vfree(pbuf);
return -1;
}
/* our first proposal */
prop = (struct isakmp_pl_p *)pa->ptr;
/* now get transform */
bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size;
len = ntohs(prop->h.len) -
(sizeof(struct isakmp_pl_p) + prop->spi_size);
tbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, len);
if (tbuf == NULL)
return -1;
ta = (struct isakmp_parse_t *)tbuf->v;
if (ta->type != ISAKMP_NPTYPE_T) {
plog(LLV_ERROR, LOCATION, NULL,
"Invalid payload type=%u\n", ta->type);
return -1;
}
trns = (struct isakmp_pl_t *)ta->ptr;
len = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
while (len > 0) {
type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
flag = ntohs(d->type) & ISAKMP_GEN_MASK;
lorv = ntohs(d->lorv);
if (type != IPSECDOI_ATTR_SECCTX) {
if (flag) {
len -= sizeof(*d);
d = (struct isakmp_data *)((char *)d
+ sizeof(*d));
} else {
len -= (sizeof(*d) + lorv);
d = (struct isakmp_data *)((caddr_t)d
+ sizeof(*d) + lorv);
}
} else {
flag = ntohs(d->type & ISAKMP_GEN_MASK);
if (flag) {
plog(LLV_ERROR, LOCATION, NULL,
"SECCTX must be in TLV.\n");
return -1;
}
memcpy(&p->sec_ctx, d + 1, lorv);
p->sec_ctx.ctx_strlen = ntohs(p->sec_ctx.ctx_strlen);
return 0;
}
}
return 0;
}
void
set_secctx_in_proposal(iph2, spidx)
struct ph2handle *iph2;
struct policyindex spidx;
{
iph2->proposal->sctx.ctx_doi = spidx.sec_ctx.ctx_doi;
iph2->proposal->sctx.ctx_alg = spidx.sec_ctx.ctx_alg;
iph2->proposal->sctx.ctx_strlen = spidx.sec_ctx.ctx_strlen;
memcpy(iph2->proposal->sctx.ctx_str, spidx.sec_ctx.ctx_str,
spidx.sec_ctx.ctx_strlen);
}
/*
* function: init_avc
* description: function performs the steps necessary to initialize the
* userspace avc.
* input: void
* return: 0 if avc was successfully initialized
* 1 if the avc could not be initialized
*/
static int mls_ready = 0;
void
init_avc(void)
{
if (!is_selinux_mls_enabled()) {
plog(LLV_ERROR, LOCATION, NULL, "racoon: MLS support is not"
" enabled.\n");
return;
}
if (avc_init("racoon", NULL, NULL, NULL, NULL) == 0)
mls_ready = 1;
else
plog(LLV_ERROR, LOCATION, NULL,
"racoon: could not initialize avc.\n");
}
/*
* function: within_range
* description: function determines if the specified sl is within the
* configured range for a policy rule.
* input: security_context *sl SL
* char *range Range
* return: 1 if the sl is within the range
* 0 if the sl is not within the range or an error
* occurred which prevented the determination
*/
int
within_range(security_context_t sl, security_context_t range)
{
int rtn = 1;
security_id_t slsid;
security_id_t rangesid;
struct av_decision avd;
security_class_t tclass;
access_vector_t av;
if (!*range) /* This policy doesn't have security context */
return 1;
if (!mls_ready) /* mls may not be enabled */
return 0;
/*
* Get the sids for the sl and range contexts
*/
rtn = avc_context_to_sid(sl, &slsid);
if (rtn != 0) {
plog(LLV_ERROR, LOCATION, NULL,
"within_range: Unable to retrieve "
"sid for sl context (%s).\n", sl);
return 0;
}
rtn = avc_context_to_sid(range, &rangesid);
if (rtn != 0) {
plog(LLV_ERROR, LOCATION, NULL,
"within_range: Unable to retrieve "
"sid for range context (%s).\n", range);
sidput(slsid);
return 0;
}
/*
* Straight up test between sl and range
*/
tclass = SECCLASS_ASSOCIATION;
av = ASSOCIATION__POLMATCH;
rtn = avc_has_perm(slsid, rangesid, tclass, av, NULL, &avd);
if (rtn != 0) {
plog(LLV_INFO, LOCATION, NULL,
"within_range: The sl is not within range\n");
sidput(slsid);
sidput(rangesid);
return 0;
}
plog(LLV_DEBUG, LOCATION, NULL,
"within_range: The sl (%s) is within range (%s)\n", sl, range);
return 1;
}