1 /*
2  * Copyright (C) 2005 International Business Machines Corporation
3  * Copyright (c) 2005 by Trusted Computer Solutions, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the project nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 
32 #include "config.h"
33 
34 #include <sys/types.h>
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 
40 #include <selinux/selinux.h>
41 #include <selinux/flask.h>
42 #include <selinux/av_permissions.h>
43 #include <selinux/avc.h>
44 #include <selinux/context.h>
45 
46 #include "var.h"
47 #include "vmbuf.h"
48 #include "misc.h"
49 #include "plog.h"
50 
51 #include "isakmp_var.h"
52 #include "isakmp.h"
53 #include "ipsec_doi.h"
54 #include "policy.h"
55 #include "proposal.h"
56 #include "strnames.h"
57 #include "handler.h"
58 
59 /*
60  * Get the security context information from SA.
61  */
62 int
get_security_context(sa,p)63 get_security_context(sa, p)
64           vchar_t *sa;
65           struct policyindex *p;
66 {
67           int len = 0;
68           int flag, type = 0;
69           uint16_t lorv;
70           caddr_t bp;
71           vchar_t *pbuf = NULL;
72           vchar_t *tbuf = NULL;
73           struct isakmp_parse_t *pa;
74           struct isakmp_parse_t *ta;
75           struct isakmp_pl_p *prop;
76           struct isakmp_pl_t *trns;
77           struct isakmp_data *d;
78           struct ipsecdoi_sa_b *sab = (struct ipsecdoi_sa_b *)sa->v;
79 
80           /* check SA payload size */
81           if (sa->l < sizeof(*sab)) {
82                     plog(LLV_ERROR, LOCATION, NULL,
83                               "Invalid SA length = %zu.\n", sa->l);
84                     return -1;
85           }
86 
87           bp = (caddr_t)(sab + 1); /* here bp points to first proposal payload */
88           len = sa->l - sizeof(*sab);
89 
90           pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, len);
91           if (pbuf == NULL)
92                     return -1;
93 
94           pa = (struct isakmp_parse_t *)pbuf->v;
95         /* check the value of next payload */
96           if (pa->type != ISAKMP_NPTYPE_P) {
97                     plog(LLV_ERROR, LOCATION, NULL,
98                               "Invalid payload type=%u\n", pa->type);
99                     vfree(pbuf);
100                     return -1;
101           }
102 
103           if (pa->len == 0) {
104                     plog(LLV_ERROR, LOCATION, NULL,
105                     "invalid proposal with length %d\n", pa->len);
106                     vfree(pbuf);
107                     return -1;
108           }
109 
110           /* our first proposal */
111           prop = (struct isakmp_pl_p *)pa->ptr;
112 
113           /* now get transform */
114           bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size;
115           len = ntohs(prop->h.len) -
116                     (sizeof(struct isakmp_pl_p) + prop->spi_size);
117           tbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, len);
118           if (tbuf == NULL)
119                     return -1;
120 
121           ta = (struct isakmp_parse_t *)tbuf->v;
122           if (ta->type != ISAKMP_NPTYPE_T) {
123                     plog(LLV_ERROR, LOCATION, NULL,
124                          "Invalid payload type=%u\n", ta->type);
125                     return -1;
126           }
127 
128           trns = (struct isakmp_pl_t *)ta->ptr;
129 
130           len = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
131           d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
132 
133           while (len > 0) {
134                     type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
135                     flag = ntohs(d->type) & ISAKMP_GEN_MASK;
136                     lorv = ntohs(d->lorv);
137 
138                     if (type != IPSECDOI_ATTR_SECCTX) {
139                               if (flag) {
140                                         len -= sizeof(*d);
141                                         d = (struct isakmp_data *)((char *)d
142                                              + sizeof(*d));
143                               } else {
144                                         len -= (sizeof(*d) + lorv);
145                                         d = (struct isakmp_data *)((caddr_t)d
146                                              + sizeof(*d) + lorv);
147                               }
148                     } else {
149                               flag = ntohs(d->type & ISAKMP_GEN_MASK);
150                               if (flag) {
151                                         plog(LLV_ERROR, LOCATION, NULL,
152                                              "SECCTX must be in TLV.\n");
153                                         return -1;
154                               }
155                               memcpy(&p->sec_ctx, d + 1, lorv);
156                               p->sec_ctx.ctx_strlen = ntohs(p->sec_ctx.ctx_strlen);
157                               return 0;
158                     }
159           }
160           return 0;
161 }
162 
163 void
set_secctx_in_proposal(iph2,spidx)164 set_secctx_in_proposal(iph2, spidx)
165           struct ph2handle *iph2;
166           struct policyindex spidx;
167 {
168           iph2->proposal->sctx.ctx_doi = spidx.sec_ctx.ctx_doi;
169           iph2->proposal->sctx.ctx_alg = spidx.sec_ctx.ctx_alg;
170           iph2->proposal->sctx.ctx_strlen = spidx.sec_ctx.ctx_strlen;
171                     memcpy(iph2->proposal->sctx.ctx_str, spidx.sec_ctx.ctx_str,
172                               spidx.sec_ctx.ctx_strlen);
173 }
174 
175 
176 /*
177  * function:        init_avc
178  * description:     function performs the steps necessary to initialize the
179  *                  userspace avc.
180  * input: void
181  * return:          0         if avc was successfully initialized
182  *                  1         if the avc could not be initialized
183  */
184 
185 static int mls_ready = 0;
186 
187 void
init_avc(void)188 init_avc(void)
189 {
190           if (!is_selinux_mls_enabled()) {
191                     plog(LLV_ERROR, LOCATION, NULL, "racoon: MLS support is not"
192                                         " enabled.\n");
193                     return;
194           }
195 
196           if (avc_init("racoon", NULL, NULL, NULL, NULL) == 0)
197                     mls_ready = 1;
198           else
199                     plog(LLV_ERROR, LOCATION, NULL,
200                          "racoon: could not initialize avc.\n");
201 }
202 
203 /*
204  * function:        within_range
205  * description:     function determines if the specified sl is within the
206  *                  configured range for a policy rule.
207  * input: security_context *sl                    SL
208  *                  char *range                   Range
209  * return:          1         if the sl is within the range
210  *                  0         if the sl is not within the range or an error
211  *                            occurred which prevented the determination
212  */
213 
214 int
within_range(security_context_t sl,security_context_t range)215 within_range(security_context_t sl, security_context_t range)
216 {
217           int rtn = 1;
218           security_id_t slsid;
219           security_id_t rangesid;
220           struct av_decision avd;
221           security_class_t tclass;
222           access_vector_t av;
223 
224           if (!*range)        /* This policy doesn't have security context */
225                     return 1;
226 
227           if (!mls_ready)  /* mls may not be enabled */
228                     return 0;
229 
230           /*
231            * Get the sids for the sl and range contexts
232            */
233           rtn = avc_context_to_sid(sl, &slsid);
234           if (rtn != 0) {
235                     plog(LLV_ERROR, LOCATION, NULL,
236                                         "within_range: Unable to retrieve "
237                                         "sid for sl context (%s).\n", sl);
238                     return 0;
239           }
240           rtn = avc_context_to_sid(range, &rangesid);
241           if (rtn != 0) {
242                     plog(LLV_ERROR, LOCATION, NULL,
243                                         "within_range: Unable to retrieve "
244                                         "sid for range context (%s).\n", range);
245                     sidput(slsid);
246                     return 0;
247           }
248 
249           /*
250            * Straight up test between sl and range
251            */
252           tclass = SECCLASS_ASSOCIATION;
253           av = ASSOCIATION__POLMATCH;
254           rtn = avc_has_perm(slsid, rangesid, tclass, av, NULL, &avd);
255           if (rtn != 0) {
256                     plog(LLV_INFO, LOCATION, NULL,
257                               "within_range: The sl is not within range\n");
258                     sidput(slsid);
259                     sidput(rangesid);
260                     return 0;
261           }
262           plog(LLV_DEBUG, LOCATION, NULL,
263                     "within_range: The sl (%s) is within range (%s)\n", sl, range);
264                     return 1;
265 }
266