1/* 2 * Copyright (c) 2013 Apple Inc. All rights reserved. 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 45#if CONFIG_MACF 46#include <sys/kauth.h> 47#include <security/mac_framework.h> 48#endif 49 50SYSCTL_DECL(_net_inet6); /* Note: Not in any common header. */ 51 52SYSCTL_NODE(_net_inet6, OID_AUTO, send, CTLFLAG_RW | CTLFLAG_LOCKED, 0, 53 "IPv6 Secure Neighbor Discovery"); 54 55static int nd6_send_opmode = ND6_SEND_OPMODE_DISABLED; 56 57SYSCTL_INT(_net_inet6_send, OID_AUTO, opstate, CTLFLAG_RD | CTLFLAG_LOCKED, 58 &nd6_send_opstate, 0, "current SEND operating state"); 59 60int nd6_send_opstate = ND6_SEND_OPMODE_DISABLED; 61SYSCTL_INT(_net_inet6_send, OID_AUTO, opmode, CTLFLAG_RW | CTLFLAG_LOCKED, 62 &nd6_send_opmode, 0, "configured SEND operating mode"); 63 64static int sysctl_cga_parameters SYSCTL_HANDLER_ARGS; 65 66SYSCTL_PROC(_net_inet6_send, OID_AUTO, cga_parameters, 67 CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, 68 sysctl_cga_parameters, "S,nd6_send_nodecfg", ""); 69 70/* 71 * The size of the buffer is sufficient to contain a public key, its size in 72 * machine binary type for the kernel, and the CGA precalc for the global 73 * scope. This interface is not a public API, so we don't anticipate that the 74 * userland and the kernel will be mismatched between ILP32 and LP64. 75 */ 76#define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \ 77 2 * (sizeof (u_int16_t) + IN6_CGA_KEY_MAXSIZE) + \ 78 sizeof (struct in6_cga_prepare) 79 80static int 81sysctl_cga_parameters SYSCTL_HANDLER_ARGS 82{ 83#pragma unused(oidp, arg1) 84 u_int namelen; 85 char *oldp, *newp; 86 const char *fin; 87 struct in6_cga_nodecfg cfg; 88 struct iovec *iov; 89 int error; 90 char *buffer; 91 u_int16_t u16; 92#if CONFIG_MACF 93 kauth_cred_t cred; 94#endif 95 96 namelen = arg2; 97 if (namelen != 0) { 98 log(LOG_ERR, "%s: name length err [len=%u]\n", __func__, 99 namelen); 100 return (EINVAL); 101 } 102 103 if (req->newlen > SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) { 104 log(LOG_ERR, "%s: input buffer size error [len=%u]\n", __func__, 105 req->newlen); 106 return (EINVAL); 107 } 108 109#if CONFIG_MACF 110 cred = kauth_cred_proc_ref(current_proc()); 111 error = mac_system_check_info(cred, "net.inet6.send.cga_parameters"); 112 kauth_cred_unref(&cred); 113 if (error != 0) { 114 log(LOG_ERR, "%s: mac_system_check_info denied.\n", __func__); 115 return (EPERM); 116 } 117#endif 118 119 MALLOC(buffer, char *, SYSCTL_CGA_PARAMETERS_BUFFER_SIZE, M_IP6CGA, 120 M_WAITOK); 121 if (buffer == NULL) { 122 log(LOG_ERR, "%s: could not allocate marshaling buffer.\n", 123 __func__); 124 return (ENOMEM); 125 } 126 127 in6_cga_node_lock(); 128 129 if (req->oldptr != USER_ADDR_NULL && req->oldlen > 0) { 130 oldp = buffer; 131 fin = &buffer[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE]; 132 if (req->oldlen < SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) 133 fin = &buffer[req->oldlen]; 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 140 if (&oldp[sizeof (cfg.cga_prepare)] <= fin) 141 bcopy(&cfg.cga_prepare, oldp, 142 sizeof (cfg.cga_prepare)); 143 oldp += sizeof (cfg.cga_prepare); 144 145 if (&oldp[sizeof (u16)] < fin) { 146 u16 = (u_int16_t) iov->iov_len; 147 bcopy(&u16, oldp, sizeof (u16)); 148 } 149 oldp += sizeof (u16); 150 151 if (&oldp[iov->iov_len] < fin) 152 bcopy(iov->iov_base, oldp, iov->iov_len); 153 oldp += iov->iov_len; 154 155 if (oldp > fin) { 156 req->oldlen = oldp - buffer; 157 log(LOG_ERR, "%s: marshalled data too large.\n", 158 __func__); 159 error = ENOMEM; 160 goto done; 161 } 162 } 163 164 error = SYSCTL_OUT(req, buffer, oldp - buffer); 165 if (error) 166 goto done; 167 } 168 169 if (req->newptr == USER_ADDR_NULL) 170 goto done; 171 172 error = proc_suser(current_proc()); 173 if (error) 174 goto done; 175 176 if (req->newlen == 0) { 177 in6_cga_stop(); 178 nd6_send_opstate = ND6_SEND_OPMODE_DISABLED; 179 goto done; 180 } 181 182 error = SYSCTL_IN(req, buffer, req->newlen); 183 if (error) 184 goto done; 185 186 newp = buffer; 187 fin = &buffer[req->newlen]; 188 189 bzero(&cfg, sizeof cfg); 190 191 if (&newp[sizeof (cfg.cga_prepare)] <= fin) 192 bcopy(newp, &cfg.cga_prepare, sizeof (cfg.cga_prepare)); 193 newp += sizeof (cfg.cga_prepare); 194 195 iov = &cfg.cga_privkey; 196 if (&newp[sizeof (u16)] < fin) { 197 bcopy(newp, &u16, sizeof (u16)); 198 iov->iov_len = u16; 199 200 if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) { 201 error = EINVAL; 202 goto done; 203 } 204 } 205 newp += sizeof (u16); 206 207 iov->iov_base = newp; 208 newp += iov->iov_len; 209 210 iov = &cfg.cga_pubkey; 211 if (&newp[sizeof (u16)] < fin) { 212 bcopy(newp, &u16, sizeof (u16)); 213 iov->iov_len = u16; 214 215 if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) { 216 error = EINVAL; 217 goto done; 218 } 219 } 220 newp += sizeof (u16); 221 222 iov->iov_base = newp; 223 newp += iov->iov_len; 224 225 if (newp > fin) { 226 log(LOG_ERR, "%s: input too large [octets=%ld].\n", __func__, 227 newp - fin); 228 error = ENOMEM; 229 goto done; 230 } 231 232 error = in6_cga_start(&cfg); 233 if (!error) 234 nd6_send_opstate = nd6_send_opmode; 235 else 236 log(LOG_ERR, "%s: in6_cga_start error=%d.\n", __func__, 237 error); 238 239done: 240 in6_cga_node_unlock(); 241 FREE(buffer, M_IP6CGA); 242 return (error); 243} 244 245/* End of file */ 246