svn commit: r310123 - in projects/ipsec/sys: conf netipsec
Andrey V. Elsukov
ae at FreeBSD.org
Thu Dec 15 17:34:19 UTC 2016
Author: ae
Date: Thu Dec 15 17:34:18 2016
New Revision: 310123
URL: https://svnweb.freebsd.org/changeset/base/310123
Log:
Add ipsec_pcb.c file and move all PCB-related function into it.
Added:
projects/ipsec/sys/netipsec/ipsec_pcb.c (contents, props changed)
Modified:
projects/ipsec/sys/conf/files
projects/ipsec/sys/netipsec/ipsec.c
Modified: projects/ipsec/sys/conf/files
==============================================================================
--- projects/ipsec/sys/conf/files Thu Dec 15 17:26:16 2016 (r310122)
+++ projects/ipsec/sys/conf/files Thu Dec 15 17:34:18 2016 (r310123)
@@ -4150,6 +4150,7 @@ netipsec/ipsec.c optional ipsec inet |
netipsec/ipsec_input.c optional ipsec inet | ipsec inet6
netipsec/ipsec_mbuf.c optional ipsec inet | ipsec inet6
netipsec/ipsec_output.c optional ipsec inet | ipsec inet6
+netipsec/ipsec_pcb.c optional ipsec inet | ipsec inet6
netipsec/key.c optional ipsec inet | ipsec inet6
netipsec/key_debug.c optional ipsec inet | ipsec inet6
netipsec/keysock.c optional ipsec inet | ipsec inet6
Modified: projects/ipsec/sys/netipsec/ipsec.c
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec.c Thu Dec 15 17:26:16 2016 (r310122)
+++ projects/ipsec/sys/netipsec/ipsec.c Thu Dec 15 17:34:18 2016 (r310123)
@@ -889,287 +889,6 @@ ipsec_run_hhooks(struct ipsec_ctx_data *
return (0);
}
-/* Initialize PCB policy. */
-int
-ipsec_init_pcbpolicy(struct inpcb *inp)
-{
-
- IPSEC_ASSERT(inp != NULL, ("null inp"));
- IPSEC_ASSERT(inp->inp_sp == NULL, ("inp_sp already initialized"));
-
- inp->inp_sp = malloc(sizeof(struct inpcbpolicy), M_IPSEC_INPCB,
- M_NOWAIT | M_ZERO);
- if (inp->inp_sp == NULL) {
- ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__));
- return (ENOBUFS);
- }
- return (0);
-}
-
-/* Delete PCB policy. */
-int
-ipsec_delete_pcbpolicy(struct inpcb *inp)
-{
-
- if (inp->inp_sp == NULL)
- return (0);
-
- if (inp->inp_sp->flags & INP_INBOUND_POLICY)
- key_freesp(&inp->inp_sp->sp_in);
-
- if (inp->inp_sp->flags & INP_OUTBOUND_POLICY)
- key_freesp(&inp->inp_sp->sp_out);
-
- free(inp->inp_sp, M_IPSEC_INPCB);
- inp->inp_sp = NULL;
- return (0);
-}
-
-/* Deep-copy a policy in PCB. */
-static struct secpolicy *
-ipsec_deepcopy_pcbpolicy(struct secpolicy *src)
-{
- struct secpolicy *dst;
- int i;
-
- if (src == NULL)
- return (NULL);
-
- IPSEC_ASSERT(src->state == IPSEC_SPSTATE_PCB, ("SP isn't PCB"));
-
- dst = key_newsp();
- if (dst == NULL)
- return (NULL);
-
- dst->policy = src->policy;
- dst->state = src->state;
- dst->priority = src->priority;
- /* Do not touch the refcnt field. */
-
- /* Copy IPsec request chain. */
- for (i = 0; i < src->tcount; i++) {
- dst->req[i] = ipsec_newisr();
- if (dst->req[i] == NULL) {
- key_freesp(&dst);
- return (NULL);
- }
- bcopy(src->req[i], dst->req[i], sizeof(struct ipsecrequest));
- dst->tcount++;
- }
- KEYDBG(IPSEC_DUMP,
- printf("%s: copied SP(%p) -> SP(%p)\n", __func__, src, dst);
- kdebug_secpolicy(dst));
- return (dst);
-}
-
-/* Copy old IPsec policy into new. */
-int
-ipsec_copy_pcbpolicy(struct inpcb *old, struct inpcb *new)
-{
- struct secpolicy *sp;
-
- /*
- * old->inp_sp can be NULL if PCB was created when an IPsec
- * support was unavailable. This is not an error, we don't have
- * policies in this PCB, so nothing to copy.
- */
- if (old->inp_sp == NULL)
- return (0);
-
- IPSEC_ASSERT(new->inp_sp != NULL, ("new inp_sp is NULL"));
- INP_WLOCK_ASSERT(new);
-
- if (old->inp_sp->flags & INP_INBOUND_POLICY) {
- sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_in);
- if (sp == NULL)
- return (ENOBUFS);
- } else
- sp = NULL;
-
- if (new->inp_sp->flags & INP_INBOUND_POLICY)
- key_freesp(&new->inp_sp->sp_in);
-
- new->inp_sp->sp_in = sp;
- if (sp != NULL)
- new->inp_sp->flags |= INP_INBOUND_POLICY;
- else
- new->inp_sp->flags &= ~INP_INBOUND_POLICY;
-
- if (old->inp_sp->flags & INP_OUTBOUND_POLICY) {
- sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_out);
- if (sp == NULL)
- return (ENOBUFS);
- } else
- sp = NULL;
-
- if (new->inp_sp->flags & INP_OUTBOUND_POLICY)
- key_freesp(&new->inp_sp->sp_out);
-
- new->inp_sp->sp_out = sp;
- if (sp != NULL)
- new->inp_sp->flags |= INP_OUTBOUND_POLICY;
- else
- new->inp_sp->flags &= ~INP_OUTBOUND_POLICY;
- return (0);
-}
-
-static int
-ipsec_set_pcbpolicy(struct inpcb *inp, struct ucred *cred,
- void *request, size_t len)
-{
- struct sadb_x_policy *xpl;
- struct secpolicy **spp, *newsp;
- int error, flags;
-
- xpl = (struct sadb_x_policy *)request;
- /* Select direction. */
- switch (xpl->sadb_x_policy_dir) {
- case IPSEC_DIR_INBOUND:
- spp = &inp->inp_sp->sp_in;
- flags = INP_INBOUND_POLICY;
- break;
- case IPSEC_DIR_OUTBOUND:
- spp = &inp->inp_sp->sp_out;
- flags = INP_OUTBOUND_POLICY;
- break;
- default:
- ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
- xpl->sadb_x_policy_dir));
- return (EINVAL);
- }
- /*
- * Privileged sockets are allowed to set own security policy
- * and configure IPsec bypass. Unprivileged sockets only can
- * have ENTRUST policy.
- */
- switch (xpl->sadb_x_policy_type) {
- case IPSEC_POLICY_IPSEC:
- case IPSEC_POLICY_BYPASS:
- if (cred != NULL &&
- priv_check_cred(cred, PRIV_NETINET_IPSEC, 0) != 0)
- return (EACCES);
- /* Allocate new SP entry. */
- newsp = key_msg2sp(xpl, len, &error);
- if (newsp == NULL)
- return (error);
- newsp->state = IPSEC_SPSTATE_PCB;
- break;
- case IPSEC_POLICY_ENTRUST:
- /* We just use NULL pointer for ENTRUST policy */
- newsp = NULL;
- break;
- default:
- /* Other security policy types aren't allowed for PCB */
- return (EINVAL);
- }
-
- /* Clear old SP and set new SP. */
- if (*spp != NULL)
- key_freesp(spp);
- *spp = newsp;
- KEYDBG(IPSEC_DUMP,
- printf("%s: new SP(%p)\n", __func__, newsp));
- if (newsp == NULL)
- inp->inp_sp->flags &= ~flags;
- else {
- inp->inp_sp->flags |= flags;
- KEYDBG(IPSEC_DUMP, kdebug_secpolicy(newsp));
- }
- return (0);
-}
-
-static int
-ipsec_get_pcbpolicy(struct inpcb *inp, void *request, size_t *len)
-{
- struct sadb_x_policy *xpl;
- struct secpolicy *sp;
- int error, flags;
-
- xpl = (struct sadb_x_policy *)request;
- flags = inp->inp_sp->flags;
- /* Select direction. */
- switch (xpl->sadb_x_policy_dir) {
- case IPSEC_DIR_INBOUND:
- sp = inp->inp_sp->sp_in;
- flags &= INP_INBOUND_POLICY;
- break;
- case IPSEC_DIR_OUTBOUND:
- sp = inp->inp_sp->sp_out;
- flags &= INP_OUTBOUND_POLICY;
- break;
- default:
- ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
- xpl->sadb_x_policy_dir));
- return (EINVAL);
- }
-
- if (flags == 0) {
- /* Return ENTRUST policy */
- xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
- xpl->sadb_x_policy_type = IPSEC_POLICY_ENTRUST;
- xpl->sadb_x_policy_id = 0;
- xpl->sadb_x_policy_priority = 0;
- xpl->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*xpl));
- *len = sizeof(*xpl);
- return (0);
- }
-
- IPSEC_ASSERT(sp != NULL,
- ("sp is NULL, but flags is 0x%04x", inp->inp_sp->flags));
-
- key_addref(sp);
- error = key_sp2msg(sp, request, len);
- key_freesp(&sp);
- if (error == EINVAL)
- return (error);
- /*
- * We return "success", but user should check *len.
- * *len will be set to size of valid data and
- * sadb_x_policy_len will contain needed size.
- */
- return (0);
-}
-
-/* Handle socket option control request for PCB */
-int
-ipsec_control_pcbpolicy(struct inpcb *inp, struct sockopt *sopt)
-{
- void *optdata;
- size_t optlen;
- int error;
-
- if (inp->inp_sp == NULL)
- return (ENOPROTOOPT);
-
- /* Limit maximum request size to PAGE_SIZE */
- optlen = sopt->sopt_valsize;
- if (optlen < sizeof(struct sadb_x_policy) || optlen > PAGE_SIZE)
- return (EINVAL);
-
- optdata = malloc(optlen, M_TEMP, sopt->sopt_td ? M_WAITOK: M_NOWAIT);
- if (optdata == NULL)
- return (ENOBUFS);
- /*
- * We need a hint from the user, what policy is requested - input
- * or output? User should specify it in the buffer, even for
- * setsockopt().
- */
- error = sooptcopyin(sopt, optdata, optlen, optlen);
- if (error == 0) {
- if (sopt->sopt_dir == SOPT_SET)
- error = ipsec_set_pcbpolicy(inp,
- sopt->sopt_td ? sopt->sopt_td->td_ucred: NULL,
- optdata, optlen);
- else {
- error = ipsec_get_pcbpolicy(inp, optdata, &optlen);
- if (error == 0)
- error = sooptcopyout(sopt, optdata, optlen);
- }
- }
- free(optdata, M_TEMP);
- return (error);
-}
-
struct ipsecrequest *
ipsec_newisr(void)
{
Added: projects/ipsec/sys/netipsec/ipsec_pcb.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/ipsec/sys/netipsec/ipsec_pcb.c Thu Dec 15 17:34:18 2016 (r310123)
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 2016 Andrey V. Elsukov <ae at FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/priv.h>
+#include <sys/socket.h>
+#include <sys/sockopt.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <netipsec/ipsec.h>
+#include <netipsec/key.h>
+#include <netipsec/key_debug.h>
+
+/* Initialize PCB policy. */
+int
+ipsec_init_pcbpolicy(struct inpcb *inp)
+{
+
+ IPSEC_ASSERT(inp != NULL, ("null inp"));
+ IPSEC_ASSERT(inp->inp_sp == NULL, ("inp_sp already initialized"));
+
+ inp->inp_sp = malloc(sizeof(struct inpcbpolicy), M_IPSEC_INPCB,
+ M_NOWAIT | M_ZERO);
+ if (inp->inp_sp == NULL) {
+ ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__));
+ return (ENOBUFS);
+ }
+ return (0);
+}
+
+/* Delete PCB policy. */
+int
+ipsec_delete_pcbpolicy(struct inpcb *inp)
+{
+
+ if (inp->inp_sp == NULL)
+ return (0);
+
+ if (inp->inp_sp->flags & INP_INBOUND_POLICY)
+ key_freesp(&inp->inp_sp->sp_in);
+
+ if (inp->inp_sp->flags & INP_OUTBOUND_POLICY)
+ key_freesp(&inp->inp_sp->sp_out);
+
+ free(inp->inp_sp, M_IPSEC_INPCB);
+ inp->inp_sp = NULL;
+ return (0);
+}
+
+/* Deep-copy a policy in PCB. */
+static struct secpolicy *
+ipsec_deepcopy_pcbpolicy(struct secpolicy *src)
+{
+ struct secpolicy *dst;
+ int i;
+
+ if (src == NULL)
+ return (NULL);
+
+ IPSEC_ASSERT(src->state == IPSEC_SPSTATE_PCB, ("SP isn't PCB"));
+
+ dst = key_newsp();
+ if (dst == NULL)
+ return (NULL);
+
+ dst->policy = src->policy;
+ dst->state = src->state;
+ dst->priority = src->priority;
+ /* Do not touch the refcnt field. */
+
+ /* Copy IPsec request chain. */
+ for (i = 0; i < src->tcount; i++) {
+ dst->req[i] = ipsec_newisr();
+ if (dst->req[i] == NULL) {
+ key_freesp(&dst);
+ return (NULL);
+ }
+ bcopy(src->req[i], dst->req[i], sizeof(struct ipsecrequest));
+ dst->tcount++;
+ }
+ KEYDBG(IPSEC_DUMP,
+ printf("%s: copied SP(%p) -> SP(%p)\n", __func__, src, dst);
+ kdebug_secpolicy(dst));
+ return (dst);
+}
+
+/* Copy old IPsec policy into new. */
+int
+ipsec_copy_pcbpolicy(struct inpcb *old, struct inpcb *new)
+{
+ struct secpolicy *sp;
+
+ /*
+ * old->inp_sp can be NULL if PCB was created when an IPsec
+ * support was unavailable. This is not an error, we don't have
+ * policies in this PCB, so nothing to copy.
+ */
+ if (old->inp_sp == NULL)
+ return (0);
+
+ IPSEC_ASSERT(new->inp_sp != NULL, ("new inp_sp is NULL"));
+ INP_WLOCK_ASSERT(new);
+
+ if (old->inp_sp->flags & INP_INBOUND_POLICY) {
+ sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_in);
+ if (sp == NULL)
+ return (ENOBUFS);
+ } else
+ sp = NULL;
+
+ if (new->inp_sp->flags & INP_INBOUND_POLICY)
+ key_freesp(&new->inp_sp->sp_in);
+
+ new->inp_sp->sp_in = sp;
+ if (sp != NULL)
+ new->inp_sp->flags |= INP_INBOUND_POLICY;
+ else
+ new->inp_sp->flags &= ~INP_INBOUND_POLICY;
+
+ if (old->inp_sp->flags & INP_OUTBOUND_POLICY) {
+ sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_out);
+ if (sp == NULL)
+ return (ENOBUFS);
+ } else
+ sp = NULL;
+
+ if (new->inp_sp->flags & INP_OUTBOUND_POLICY)
+ key_freesp(&new->inp_sp->sp_out);
+
+ new->inp_sp->sp_out = sp;
+ if (sp != NULL)
+ new->inp_sp->flags |= INP_OUTBOUND_POLICY;
+ else
+ new->inp_sp->flags &= ~INP_OUTBOUND_POLICY;
+ return (0);
+}
+
+static int
+ipsec_set_pcbpolicy(struct inpcb *inp, struct ucred *cred,
+ void *request, size_t len)
+{
+ struct sadb_x_policy *xpl;
+ struct secpolicy **spp, *newsp;
+ int error, flags;
+
+ xpl = (struct sadb_x_policy *)request;
+ /* Select direction. */
+ switch (xpl->sadb_x_policy_dir) {
+ case IPSEC_DIR_INBOUND:
+ spp = &inp->inp_sp->sp_in;
+ flags = INP_INBOUND_POLICY;
+ break;
+ case IPSEC_DIR_OUTBOUND:
+ spp = &inp->inp_sp->sp_out;
+ flags = INP_OUTBOUND_POLICY;
+ break;
+ default:
+ ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
+ xpl->sadb_x_policy_dir));
+ return (EINVAL);
+ }
+ /*
+ * Privileged sockets are allowed to set own security policy
+ * and configure IPsec bypass. Unprivileged sockets only can
+ * have ENTRUST policy.
+ */
+ switch (xpl->sadb_x_policy_type) {
+ case IPSEC_POLICY_IPSEC:
+ case IPSEC_POLICY_BYPASS:
+ if (cred != NULL &&
+ priv_check_cred(cred, PRIV_NETINET_IPSEC, 0) != 0)
+ return (EACCES);
+ /* Allocate new SP entry. */
+ newsp = key_msg2sp(xpl, len, &error);
+ if (newsp == NULL)
+ return (error);
+ newsp->state = IPSEC_SPSTATE_PCB;
+ break;
+ case IPSEC_POLICY_ENTRUST:
+ /* We just use NULL pointer for ENTRUST policy */
+ newsp = NULL;
+ break;
+ default:
+ /* Other security policy types aren't allowed for PCB */
+ return (EINVAL);
+ }
+
+ /* Clear old SP and set new SP. */
+ if (*spp != NULL)
+ key_freesp(spp);
+ *spp = newsp;
+ KEYDBG(IPSEC_DUMP,
+ printf("%s: new SP(%p)\n", __func__, newsp));
+ if (newsp == NULL)
+ inp->inp_sp->flags &= ~flags;
+ else {
+ inp->inp_sp->flags |= flags;
+ KEYDBG(IPSEC_DUMP, kdebug_secpolicy(newsp));
+ }
+ return (0);
+}
+
+static int
+ipsec_get_pcbpolicy(struct inpcb *inp, void *request, size_t *len)
+{
+ struct sadb_x_policy *xpl;
+ struct secpolicy *sp;
+ int error, flags;
+
+ xpl = (struct sadb_x_policy *)request;
+ flags = inp->inp_sp->flags;
+ /* Select direction. */
+ switch (xpl->sadb_x_policy_dir) {
+ case IPSEC_DIR_INBOUND:
+ sp = inp->inp_sp->sp_in;
+ flags &= INP_INBOUND_POLICY;
+ break;
+ case IPSEC_DIR_OUTBOUND:
+ sp = inp->inp_sp->sp_out;
+ flags &= INP_OUTBOUND_POLICY;
+ break;
+ default:
+ ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
+ xpl->sadb_x_policy_dir));
+ return (EINVAL);
+ }
+
+ if (flags == 0) {
+ /* Return ENTRUST policy */
+ xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ xpl->sadb_x_policy_type = IPSEC_POLICY_ENTRUST;
+ xpl->sadb_x_policy_id = 0;
+ xpl->sadb_x_policy_priority = 0;
+ xpl->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*xpl));
+ *len = sizeof(*xpl);
+ return (0);
+ }
+
+ IPSEC_ASSERT(sp != NULL,
+ ("sp is NULL, but flags is 0x%04x", inp->inp_sp->flags));
+
+ key_addref(sp);
+ error = key_sp2msg(sp, request, len);
+ key_freesp(&sp);
+ if (error == EINVAL)
+ return (error);
+ /*
+ * We return "success", but user should check *len.
+ * *len will be set to size of valid data and
+ * sadb_x_policy_len will contain needed size.
+ */
+ return (0);
+}
+
+/* Handle socket option control request for PCB */
+int
+ipsec_control_pcbpolicy(struct inpcb *inp, struct sockopt *sopt)
+{
+ void *optdata;
+ size_t optlen;
+ int error;
+
+ if (inp->inp_sp == NULL)
+ return (ENOPROTOOPT);
+
+ /* Limit maximum request size to PAGE_SIZE */
+ optlen = sopt->sopt_valsize;
+ if (optlen < sizeof(struct sadb_x_policy) || optlen > PAGE_SIZE)
+ return (EINVAL);
+
+ optdata = malloc(optlen, M_TEMP, sopt->sopt_td ? M_WAITOK: M_NOWAIT);
+ if (optdata == NULL)
+ return (ENOBUFS);
+ /*
+ * We need a hint from the user, what policy is requested - input
+ * or output? User should specify it in the buffer, even for
+ * setsockopt().
+ */
+ error = sooptcopyin(sopt, optdata, optlen, optlen);
+ if (error == 0) {
+ if (sopt->sopt_dir == SOPT_SET)
+ error = ipsec_set_pcbpolicy(inp,
+ sopt->sopt_td ? sopt->sopt_td->td_ucred: NULL,
+ optdata, optlen);
+ else {
+ error = ipsec_get_pcbpolicy(inp, optdata, &optlen);
+ if (error == 0)
+ error = sooptcopyout(sopt, optdata, optlen);
+ }
+ }
+ free(optdata, M_TEMP);
+ return (error);
+}
+
More information about the svn-src-projects
mailing list