]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/nd6_send.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / nd6_send.c
CommitLineData
39236c6e 1/*
39037602 2 * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
39236c6e
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/types.h>
30#include <sys/malloc.h>
31#include <sys/proc.h>
32#include <sys/sysctl.h>
33#include <sys/syslog.h>
34
35#include <libkern/crypto/sha1.h>
36
37#include <net/if.h>
38
39#include <netinet/in.h>
40#include <netinet6/in6_var.h>
41#include <netinet/ip6.h>
42#include <netinet6/ip6_var.h>
43#include <netinet6/nd6.h>
44
fe8ab488
A
45#if CONFIG_MACF
46#include <sys/kauth.h>
47#include <security/mac_framework.h>
48#endif
49
0a7de745 50SYSCTL_DECL(_net_inet6); /* Note: Not in any common header. */
39236c6e
A
51
52SYSCTL_NODE(_net_inet6, OID_AUTO, send, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
0a7de745 53 "IPv6 Secure Neighbor Discovery");
39236c6e 54
39037602 55static int nd6_send_opmode = ND6_SEND_OPMODE_CGA_QUIET;
5ba3f43e
A
56SYSCTL_INT(_net_inet6_send, OID_AUTO, opmode, CTLFLAG_RW | CTLFLAG_LOCKED,
57 &nd6_send_opmode, 0, "configured SEND operating mode");
39236c6e
A
58
59int nd6_send_opstate = ND6_SEND_OPMODE_DISABLED;
5ba3f43e
A
60SYSCTL_INT(_net_inet6_send, OID_AUTO, opstate, CTLFLAG_RD | CTLFLAG_LOCKED,
61 &nd6_send_opstate, 0, "current SEND operating state");
39236c6e
A
62
63static int sysctl_cga_parameters SYSCTL_HANDLER_ARGS;
64
65SYSCTL_PROC(_net_inet6_send, OID_AUTO, cga_parameters,
0a7de745
A
66 CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
67 sysctl_cga_parameters, "S,nd6_send_nodecfg", "");
39236c6e
A
68
69/*
70 * The size of the buffer is sufficient to contain a public key, its size in
71 * machine binary type for the kernel, and the CGA precalc for the global
72 * scope. This interface is not a public API, so we don't anticipate that the
73 * userland and the kernel will be mismatched between ILP32 and LP64.
74 */
0a7de745 75#define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
39037602
A
76 (2 * (sizeof (u_int16_t) + IN6_CGA_KEY_MAXSIZE) + \
77 sizeof (struct in6_cga_prepare))
39236c6e
A
78
79static int
80sysctl_cga_parameters SYSCTL_HANDLER_ARGS
81{
82#pragma unused(oidp, arg1)
83 u_int namelen;
84 char *oldp, *newp;
85 const char *fin;
86 struct in6_cga_nodecfg cfg;
87 struct iovec *iov;
88 int error;
89 char *buffer;
90 u_int16_t u16;
fe8ab488
A
91#if CONFIG_MACF
92 kauth_cred_t cred;
93#endif
39236c6e
A
94
95 namelen = arg2;
96 if (namelen != 0) {
97 log(LOG_ERR, "%s: name length err [len=%u]\n", __func__,
98 namelen);
0a7de745 99 return EINVAL;
39236c6e
A
100 }
101
102 if (req->newlen > SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) {
103 log(LOG_ERR, "%s: input buffer size error [len=%u]\n", __func__,
104 req->newlen);
0a7de745 105 return EINVAL;
39236c6e
A
106 }
107
fe8ab488
A
108#if CONFIG_MACF
109 cred = kauth_cred_proc_ref(current_proc());
110 error = mac_system_check_info(cred, "net.inet6.send.cga_parameters");
111 kauth_cred_unref(&cred);
112 if (error != 0) {
113 log(LOG_ERR, "%s: mac_system_check_info denied.\n", __func__);
0a7de745 114 return EPERM;
fe8ab488
A
115 }
116#endif
117
39236c6e 118 MALLOC(buffer, char *, SYSCTL_CGA_PARAMETERS_BUFFER_SIZE, M_IP6CGA,
d9a64523 119 M_WAITOK | M_ZERO);
39236c6e
A
120 if (buffer == NULL) {
121 log(LOG_ERR, "%s: could not allocate marshaling buffer.\n",
122 __func__);
0a7de745 123 return ENOMEM;
39236c6e
A
124 }
125
126 in6_cga_node_lock();
127
128 if (req->oldptr != USER_ADDR_NULL && req->oldlen > 0) {
129 oldp = buffer;
130 fin = &buffer[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
0a7de745 131 if (req->oldlen < SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) {
39236c6e 132 fin = &buffer[req->oldlen];
0a7de745 133 }
39236c6e
A
134
135 in6_cga_query(&cfg);
136 iov = &cfg.cga_pubkey;
137 if (iov->iov_len > 0) {
138 VERIFY(iov->iov_len < UINT16_MAX);
139
0a7de745 140 if (&oldp[sizeof(cfg.cga_prepare)] <= fin) {
39236c6e 141 bcopy(&cfg.cga_prepare, oldp,
0a7de745
A
142 sizeof(cfg.cga_prepare));
143 }
144 oldp += sizeof(cfg.cga_prepare);
39236c6e 145
0a7de745 146 if (&oldp[sizeof(u16)] < fin) {
39236c6e 147 u16 = (u_int16_t) iov->iov_len;
0a7de745 148 bcopy(&u16, oldp, sizeof(u16));
39236c6e 149 }
0a7de745 150 oldp += sizeof(u16);
39236c6e 151
0a7de745 152 if (&oldp[iov->iov_len] < fin) {
39236c6e 153 bcopy(iov->iov_base, oldp, iov->iov_len);
0a7de745 154 }
39236c6e
A
155 oldp += iov->iov_len;
156
157 if (oldp > fin) {
158 req->oldlen = oldp - buffer;
159 log(LOG_ERR, "%s: marshalled data too large.\n",
160 __func__);
161 error = ENOMEM;
162 goto done;
163 }
164 }
165
166 error = SYSCTL_OUT(req, buffer, oldp - buffer);
0a7de745 167 if (error) {
39236c6e 168 goto done;
0a7de745 169 }
39236c6e
A
170 }
171
0a7de745 172 if (req->newptr == USER_ADDR_NULL) {
39236c6e 173 goto done;
0a7de745 174 }
39236c6e
A
175
176 error = proc_suser(current_proc());
0a7de745 177 if (error) {
39236c6e 178 goto done;
0a7de745 179 }
39236c6e
A
180
181 if (req->newlen == 0) {
182 in6_cga_stop();
183 nd6_send_opstate = ND6_SEND_OPMODE_DISABLED;
184 goto done;
185 }
186
187 error = SYSCTL_IN(req, buffer, req->newlen);
0a7de745 188 if (error) {
39236c6e 189 goto done;
0a7de745 190 }
39236c6e
A
191
192 newp = buffer;
193 fin = &buffer[req->newlen];
194
195 bzero(&cfg, sizeof cfg);
196
0a7de745
A
197 if (&newp[sizeof(cfg.cga_prepare)] <= fin) {
198 bcopy(newp, &cfg.cga_prepare, sizeof(cfg.cga_prepare));
199 }
200 newp += sizeof(cfg.cga_prepare);
39236c6e
A
201
202 iov = &cfg.cga_privkey;
0a7de745
A
203 if (&newp[sizeof(u16)] < fin) {
204 bcopy(newp, &u16, sizeof(u16));
39236c6e
A
205 iov->iov_len = u16;
206
207 if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) {
208 error = EINVAL;
209 goto done;
210 }
211 }
0a7de745 212 newp += sizeof(u16);
39236c6e
A
213
214 iov->iov_base = newp;
215 newp += iov->iov_len;
216
217 iov = &cfg.cga_pubkey;
0a7de745
A
218 if (&newp[sizeof(u16)] < fin) {
219 bcopy(newp, &u16, sizeof(u16));
39236c6e
A
220 iov->iov_len = u16;
221
222 if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) {
223 error = EINVAL;
224 goto done;
225 }
226 }
0a7de745 227 newp += sizeof(u16);
39236c6e
A
228
229 iov->iov_base = newp;
230 newp += iov->iov_len;
231
232 if (newp > fin) {
233 log(LOG_ERR, "%s: input too large [octets=%ld].\n", __func__,
234 newp - fin);
235 error = ENOMEM;
236 goto done;
237 }
238
239 error = in6_cga_start(&cfg);
0a7de745 240 if (!error) {
39236c6e 241 nd6_send_opstate = nd6_send_opmode;
0a7de745 242 } else {
39236c6e
A
243 log(LOG_ERR, "%s: in6_cga_start error=%d.\n", __func__,
244 error);
0a7de745 245 }
39236c6e
A
246
247done:
248 in6_cga_node_unlock();
249 FREE(buffer, M_IP6CGA);
0a7de745 250 return error;
39236c6e
A
251}
252
253/* End of file */