/* * 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; }