1 /* $NetBSD: ipsec_dump_policy.c,v 1.7.6.1 2007/08/01 11:52:17 vanhu Exp $ */ 2 3 /* Id: ipsec_dump_policy.c,v 1.10 2005/06/29 09:12:37 manubsd Exp */ 4 5 /* 6 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifdef HAVE_CONFIG_H 35 #include "config.h" 36 #endif 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/socket.h> 41 42 #include <netinet/in.h> 43 #include PATH_IPSEC_H 44 45 #include <arpa/inet.h> 46 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <netdb.h> 51 52 #include "ipsec_strerror.h" 53 #include "libpfkey.h" 54 55 static const char *ipsp_dir_strs[] = { 56 "any", "in", "out", "fwd" 57 }; 58 59 static const char *ipsp_policy_strs[] = { 60 "discard", "none", "ipsec", "entrust", "bypass", 61 }; 62 63 static char *ipsec_dump_ipsecrequest __P((char *, size_t, 64 struct sadb_x_ipsecrequest *, size_t, int)); 65 static char *ipsec_dump_policy1 __P((void *, const char *, int)); 66 static int set_addresses __P((char *, size_t, struct sockaddr *, 67 struct sockaddr *, int)); 68 static char *set_address __P((char *, size_t, struct sockaddr *, int)); 69 70 /* 71 * policy is sadb_x_policy buffer. 72 * Must call free() later. 73 * When delimiter == NULL, alternatively ' '(space) is applied. 74 */ 75 char * 76 ipsec_dump_policy(policy, delimiter) 77 ipsec_policy_t policy; 78 __ipsec_const char *delimiter; 79 { 80 return ipsec_dump_policy1(policy, delimiter, 0); 81 } 82 83 char * 84 ipsec_dump_policy_withports(policy, delimiter) 85 void *policy; 86 const char *delimiter; 87 { 88 return ipsec_dump_policy1(policy, delimiter, 1); 89 } 90 91 static char * 92 ipsec_dump_policy1(policy, delimiter, withports) 93 void *policy; 94 const char *delimiter; 95 int withports; 96 { 97 struct sadb_x_policy *xpl = policy; 98 struct sadb_x_ipsecrequest *xisr; 99 size_t off, buflen; 100 char *buf; 101 char isrbuf[1024]; 102 char *newbuf; 103 104 #ifdef HAVE_PFKEY_POLICY_PRIORITY 105 int32_t priority_offset; 106 char *priority_str; 107 char operator; 108 #endif 109 110 /* sanity check */ 111 if (policy == NULL) 112 return NULL; 113 if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { 114 __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 115 return NULL; 116 } 117 118 /* set delimiter */ 119 if (delimiter == NULL) 120 delimiter = " "; 121 122 #ifdef HAVE_PFKEY_POLICY_PRIORITY 123 if (xpl->sadb_x_policy_priority == 0) 124 { 125 priority_offset = 0; 126 priority_str = ""; 127 } 128 /* find which constant the priority is closest to */ 129 else if (xpl->sadb_x_policy_priority < 130 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3) 131 { 132 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH; 133 priority_str = "prio high"; 134 } 135 else if (xpl->sadb_x_policy_priority >= 136 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 && 137 xpl->sadb_x_policy_priority < 138 (u_int32_t) (PRIORITY_DEFAULT / 4) * 5) 139 { 140 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT; 141 priority_str = "prio def"; 142 } 143 else 144 { 145 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW; 146 priority_str = "prio low"; 147 } 148 149 /* fix sign to match the way it is input */ 150 priority_offset *= -1; 151 if (priority_offset < 0) 152 { 153 operator = '-'; 154 priority_offset *= -1; 155 } 156 else 157 { 158 operator = '+'; 159 } 160 #endif 161 162 switch (xpl->sadb_x_policy_dir) { 163 case IPSEC_DIR_ANY: 164 case IPSEC_DIR_INBOUND: 165 case IPSEC_DIR_OUTBOUND: 166 #ifdef HAVE_POLICY_FWD 167 case IPSEC_DIR_FWD: 168 #endif 169 break; 170 default: 171 __ipsec_errcode = EIPSEC_INVAL_DIR; 172 return NULL; 173 } 174 175 switch (xpl->sadb_x_policy_type) { 176 case IPSEC_POLICY_DISCARD: 177 case IPSEC_POLICY_NONE: 178 case IPSEC_POLICY_IPSEC: 179 case IPSEC_POLICY_BYPASS: 180 case IPSEC_POLICY_ENTRUST: 181 break; 182 default: 183 __ipsec_errcode = EIPSEC_INVAL_POLICY; 184 return NULL; 185 } 186 187 buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) 188 + 1 /* space */ 189 #ifdef HAVE_PFKEY_POLICY_PRIORITY 190 + strlen(priority_str) 191 + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */ 192 + ((strlen(priority_str) != 0) ? 1 : 0) /* space */ 193 #endif 194 + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) 195 + 1; /* NUL */ 196 197 if ((buf = malloc(buflen)) == NULL) { 198 __ipsec_errcode = EIPSEC_NO_BUFS; 199 return NULL; 200 } 201 #ifdef HAVE_PFKEY_POLICY_PRIORITY 202 if (priority_offset != 0) 203 { 204 snprintf(buf, buflen, "%s %s %c %u %s", 205 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator, 206 priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]); 207 } 208 else if (strlen (priority_str) != 0) 209 { 210 snprintf(buf, buflen, "%s %s %s", 211 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, 212 ipsp_policy_strs[xpl->sadb_x_policy_type]); 213 } 214 else 215 { 216 snprintf(buf, buflen, "%s %s", 217 ipsp_dir_strs[xpl->sadb_x_policy_dir], 218 ipsp_policy_strs[xpl->sadb_x_policy_type]); 219 } 220 #else 221 snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], 222 ipsp_policy_strs[xpl->sadb_x_policy_type]); 223 #endif 224 225 if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { 226 __ipsec_errcode = EIPSEC_NO_ERROR; 227 return buf; 228 } 229 230 /* count length of buffer for use */ 231 off = sizeof(*xpl); 232 while (off < PFKEY_EXTLEN(xpl)) { 233 xisr = (void *)((caddr_t)(void *)xpl + off); 234 off += xisr->sadb_x_ipsecrequest_len; 235 } 236 237 /* validity check */ 238 if (off != PFKEY_EXTLEN(xpl)) { 239 __ipsec_errcode = EIPSEC_INVAL_SADBMSG; 240 free(buf); 241 return NULL; 242 } 243 244 off = sizeof(*xpl); 245 while (off < PFKEY_EXTLEN(xpl)) { 246 int offset; 247 xisr = (void *)((caddr_t)(void *)xpl + off); 248 249 if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, 250 PFKEY_EXTLEN(xpl) - off, withports) == NULL) { 251 free(buf); 252 return NULL; 253 } 254 255 offset = strlen(buf); 256 buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1; 257 newbuf = (char *)realloc(buf, buflen); 258 if (newbuf == NULL) { 259 __ipsec_errcode = EIPSEC_NO_BUFS; 260 free(buf); 261 return NULL; 262 } 263 buf = newbuf; 264 snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf); 265 266 off += xisr->sadb_x_ipsecrequest_len; 267 } 268 269 __ipsec_errcode = EIPSEC_NO_ERROR; 270 return buf; 271 } 272 273 static char * 274 ipsec_dump_ipsecrequest(buf, len, xisr, bound, withports) 275 char *buf; 276 size_t len; 277 struct sadb_x_ipsecrequest *xisr; 278 size_t bound; /* boundary */ 279 int withports; 280 { 281 const char *proto, *mode, *level; 282 char abuf[NI_MAXHOST * 2 + 2]; 283 284 if (xisr->sadb_x_ipsecrequest_len > bound) { 285 __ipsec_errcode = EIPSEC_INVAL_PROTO; 286 return NULL; 287 } 288 289 switch (xisr->sadb_x_ipsecrequest_proto) { 290 case IPPROTO_ESP: 291 proto = "esp"; 292 break; 293 case IPPROTO_AH: 294 proto = "ah"; 295 break; 296 case IPPROTO_IPCOMP: 297 proto = "ipcomp"; 298 break; 299 default: 300 __ipsec_errcode = EIPSEC_INVAL_PROTO; 301 return NULL; 302 } 303 304 switch (xisr->sadb_x_ipsecrequest_mode) { 305 case IPSEC_MODE_ANY: 306 mode = "any"; 307 break; 308 case IPSEC_MODE_TRANSPORT: 309 mode = "transport"; 310 break; 311 case IPSEC_MODE_TUNNEL: 312 mode = "tunnel"; 313 break; 314 default: 315 __ipsec_errcode = EIPSEC_INVAL_MODE; 316 return NULL; 317 } 318 319 abuf[0] = '\0'; 320 if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { 321 struct sockaddr *sa1, *sa2; 322 caddr_t p; 323 324 p = (void *)(xisr + 1); 325 sa1 = (void *)p; 326 sa2 = (void *)(p + sysdep_sa_len(sa1)); 327 if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) != 328 xisr->sadb_x_ipsecrequest_len) { 329 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 330 return NULL; 331 } 332 if (set_addresses(abuf, sizeof(abuf), 333 sa1, sa2, withports) != 0) { 334 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 335 return NULL; 336 } 337 } 338 339 switch (xisr->sadb_x_ipsecrequest_level) { 340 case IPSEC_LEVEL_DEFAULT: 341 level = "default"; 342 break; 343 case IPSEC_LEVEL_USE: 344 level = "use"; 345 break; 346 case IPSEC_LEVEL_REQUIRE: 347 level = "require"; 348 break; 349 case IPSEC_LEVEL_UNIQUE: 350 level = "unique"; 351 break; 352 default: 353 __ipsec_errcode = EIPSEC_INVAL_LEVEL; 354 return NULL; 355 } 356 357 if (xisr->sadb_x_ipsecrequest_reqid == 0) 358 snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); 359 else { 360 int ch; 361 362 if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) 363 ch = '#'; 364 else 365 ch = ':'; 366 snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level, 367 ch, xisr->sadb_x_ipsecrequest_reqid); 368 } 369 370 return buf; 371 } 372 373 static int 374 set_addresses(buf, len, sa1, sa2, withports) 375 char *buf; 376 size_t len; 377 struct sockaddr *sa1; 378 struct sockaddr *sa2; 379 int withports; 380 { 381 char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; 382 383 if (set_address(tmp1, sizeof(tmp1), sa1, withports) == NULL || 384 set_address(tmp2, sizeof(tmp2), sa2, withports) == NULL) 385 return -1; 386 if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) 387 return -1; 388 snprintf(buf, len, "%s-%s", tmp1, tmp2); 389 return 0; 390 } 391 392 static char * 393 set_address(buf, len, sa, withports) 394 char *buf; 395 size_t len; 396 struct sockaddr *sa; 397 int withports; 398 { 399 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 400 char host[NI_MAXHOST]; 401 char serv[NI_MAXSERV]; 402 403 if (len < 1) 404 return NULL; 405 buf[0] = '\0'; 406 if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), host, sizeof(host), 407 serv, sizeof(serv), niflags) != 0) 408 return NULL; 409 410 if (withports) 411 snprintf(buf, len, "%s[%s]", host, serv); 412 else 413 snprintf(buf, len, "%s", host); 414 415 return buf; 416 } 417