2 * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/types.h>
30 #include <sys/malloc.h>
32 #include <sys/sysctl.h>
33 #include <sys/syslog.h>
35 #include <libkern/crypto/sha1.h>
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>
46 #include <sys/kauth.h>
47 #include <security/mac_framework.h>
50 SYSCTL_DECL(_net_inet6
); /* Note: Not in any common header. */
52 SYSCTL_NODE(_net_inet6
, OID_AUTO
, send
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
53 "IPv6 Secure Neighbor Discovery");
55 static int nd6_send_opmode
= ND6_SEND_OPMODE_CGA_QUIET
;
56 SYSCTL_INT(_net_inet6_send
, OID_AUTO
, opstate
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
57 &nd6_send_opstate
, 0, "current SEND operating state");
59 int nd6_send_opstate
= ND6_SEND_OPMODE_DISABLED
;
60 SYSCTL_INT(_net_inet6_send
, OID_AUTO
, opmode
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
61 &nd6_send_opmode
, 0, "configured SEND operating mode");
63 static int sysctl_cga_parameters SYSCTL_HANDLER_ARGS
;
65 SYSCTL_PROC(_net_inet6_send
, OID_AUTO
, cga_parameters
,
66 CTLTYPE_OPAQUE
| CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, 0,
67 sysctl_cga_parameters
, "S,nd6_send_nodecfg", "");
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.
75 #define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
76 (2 * (sizeof (u_int16_t) + IN6_CGA_KEY_MAXSIZE) + \
77 sizeof (struct in6_cga_prepare))
80 sysctl_cga_parameters SYSCTL_HANDLER_ARGS
82 #pragma unused(oidp, arg1)
86 struct in6_cga_nodecfg cfg
;
97 log(LOG_ERR
, "%s: name length err [len=%u]\n", __func__
,
102 if (req
->newlen
> SYSCTL_CGA_PARAMETERS_BUFFER_SIZE
) {
103 log(LOG_ERR
, "%s: input buffer size error [len=%u]\n", __func__
,
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
);
113 log(LOG_ERR
, "%s: mac_system_check_info denied.\n", __func__
);
118 MALLOC(buffer
, char *, SYSCTL_CGA_PARAMETERS_BUFFER_SIZE
, M_IP6CGA
,
120 if (buffer
== NULL
) {
121 log(LOG_ERR
, "%s: could not allocate marshaling buffer.\n",
128 if (req
->oldptr
!= USER_ADDR_NULL
&& req
->oldlen
> 0) {
130 fin
= &buffer
[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE
];
131 if (req
->oldlen
< SYSCTL_CGA_PARAMETERS_BUFFER_SIZE
)
132 fin
= &buffer
[req
->oldlen
];
135 iov
= &cfg
.cga_pubkey
;
136 if (iov
->iov_len
> 0) {
137 VERIFY(iov
->iov_len
< UINT16_MAX
);
139 if (&oldp
[sizeof (cfg
.cga_prepare
)] <= fin
)
140 bcopy(&cfg
.cga_prepare
, oldp
,
141 sizeof (cfg
.cga_prepare
));
142 oldp
+= sizeof (cfg
.cga_prepare
);
144 if (&oldp
[sizeof (u16
)] < fin
) {
145 u16
= (u_int16_t
) iov
->iov_len
;
146 bcopy(&u16
, oldp
, sizeof (u16
));
148 oldp
+= sizeof (u16
);
150 if (&oldp
[iov
->iov_len
] < fin
)
151 bcopy(iov
->iov_base
, oldp
, iov
->iov_len
);
152 oldp
+= iov
->iov_len
;
155 req
->oldlen
= oldp
- buffer
;
156 log(LOG_ERR
, "%s: marshalled data too large.\n",
163 error
= SYSCTL_OUT(req
, buffer
, oldp
- buffer
);
168 if (req
->newptr
== USER_ADDR_NULL
)
171 error
= proc_suser(current_proc());
175 if (req
->newlen
== 0) {
177 nd6_send_opstate
= ND6_SEND_OPMODE_DISABLED
;
181 error
= SYSCTL_IN(req
, buffer
, req
->newlen
);
186 fin
= &buffer
[req
->newlen
];
188 bzero(&cfg
, sizeof cfg
);
190 if (&newp
[sizeof (cfg
.cga_prepare
)] <= fin
)
191 bcopy(newp
, &cfg
.cga_prepare
, sizeof (cfg
.cga_prepare
));
192 newp
+= sizeof (cfg
.cga_prepare
);
194 iov
= &cfg
.cga_privkey
;
195 if (&newp
[sizeof (u16
)] < fin
) {
196 bcopy(newp
, &u16
, sizeof (u16
));
199 if (iov
->iov_len
> IN6_CGA_KEY_MAXSIZE
) {
204 newp
+= sizeof (u16
);
206 iov
->iov_base
= newp
;
207 newp
+= iov
->iov_len
;
209 iov
= &cfg
.cga_pubkey
;
210 if (&newp
[sizeof (u16
)] < fin
) {
211 bcopy(newp
, &u16
, sizeof (u16
));
214 if (iov
->iov_len
> IN6_CGA_KEY_MAXSIZE
) {
219 newp
+= sizeof (u16
);
221 iov
->iov_base
= newp
;
222 newp
+= iov
->iov_len
;
225 log(LOG_ERR
, "%s: input too large [octets=%ld].\n", __func__
,
231 error
= in6_cga_start(&cfg
);
233 nd6_send_opstate
= nd6_send_opmode
;
235 log(LOG_ERR
, "%s: in6_cga_start error=%d.\n", __func__
,
239 in6_cga_node_unlock();
240 FREE(buffer
, M_IP6CGA
);