1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/errno.h> 31 #include <sys/stat.h> 32 #include <ipsec_util.h> 33 #include <netdb.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <synch.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <syslog.h> 42 43 /* Globals... */ 44 static rwlock_t proto_rw = DEFAULTRWLOCK; /* Protects cached algorithm list. */ 45 static time_t proto_last_update; 46 static ipsec_proto_t *protos; 47 static int num_protos; 48 49 void 50 _clean_trash(ipsec_proto_t *proto, int num) 51 { 52 int alg_offset; 53 54 if (proto == NULL) 55 return; 56 57 while (num-- != 0) { 58 free(proto[num].proto_name); 59 free(proto[num].proto_pkg); 60 for (alg_offset = 0; alg_offset < proto[num].proto_numalgs; 61 alg_offset++) 62 freeipsecalgent(proto[num].proto_algs[alg_offset]); 63 free(proto[num].proto_algs); 64 for (alg_offset = 0; alg_offset < proto[num].proto_algs_npkgs; 65 alg_offset++) 66 free(proto[num].proto_algs_pkgs[alg_offset].pkg_name); 67 free(proto[num].proto_algs_pkgs); 68 } 69 70 free(proto); 71 } 72 73 static const char *pipechar = "|"; 74 static const char *comma = ","; 75 static const char *dash = "-"; 76 static const char *slash = "/"; 77 78 /* 79 * Returns >= 0 if success (and > 0 means "increment"). 80 * Returns -1 if failure. 81 */ 82 static int 83 build_keysizes(int **sizep, char *input_string) 84 { 85 char *lasts, *token; 86 int *key_sizes = NULL, num_sizes, key_low, key_high, key_default; 87 int key_increment = 0; 88 89 /* 90 * Okay, let's check the format of the key string. It'll be either: 91 * 92 * enumeration: size1,size2...,sizeN 93 * range: defaultSize/sizeLow-sizeHi,increment 94 * 95 * In the case of an enumeration, the default key size is the 96 * first one in the list. 97 */ 98 99 if (strchr(input_string, '/') != NULL) { 100 /* key sizes specified by range */ 101 102 /* default */ 103 token = strtok_r(input_string, slash, &lasts); 104 if (token == NULL || (key_default = atoi(token)) == 0) 105 return (-1); 106 107 /* low */ 108 token = strtok_r(NULL, dash, &lasts); 109 if (token == NULL || (key_low = atoi(token)) == 0) 110 return (-1); 111 112 /* high */ 113 token = strtok_r(NULL, comma, &lasts); 114 if (token == NULL || (key_high = atoi(token)) == 0 || 115 key_high <= key_low) 116 return (-1); 117 118 /* increment */ 119 token = strtok_r(NULL, "", &lasts); 120 if (token == NULL || (key_increment = atoi(token)) == 0) 121 return (-1); 122 123 key_sizes = (int *)malloc(LIBIPSEC_ALGS_KEY_NUM_VAL * 124 sizeof (int)); 125 if (key_sizes == NULL) 126 return (-1); 127 128 key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] = key_default; 129 key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] = key_low; 130 key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] = key_high; 131 key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX + 1] = 0; 132 } else { 133 /* key sizes specified by enumeration */ 134 135 key_sizes = (int *)malloc(sizeof (int)); 136 if (key_sizes == NULL) 137 return (-1); 138 num_sizes = 0; 139 140 token = strtok_r(input_string, comma, &lasts); 141 if (token == NULL || key_sizes == NULL) 142 return (-1); 143 *key_sizes = 0; 144 do { 145 int *nks; 146 147 nks = (int *)realloc(key_sizes, 148 sizeof (int) * ((++num_sizes) + 1)); 149 if (nks == NULL) { 150 free(key_sizes); 151 return (-1); 152 } 153 key_sizes = nks; 154 /* Can't check for atoi() == 0 here... */ 155 key_sizes[num_sizes - 1] = atoi(token); 156 key_sizes[num_sizes] = 0; 157 } while ((token = strtok_r(NULL, comma, &lasts)) != NULL); 158 } 159 160 *sizep = key_sizes; 161 162 return (key_increment); 163 } 164 165 /* 166 * Find the execution mode corresponding to the given string. 167 * Returns 0 on success, -1 on failure. 168 */ 169 int 170 _str_to_ipsec_exec_mode(char *str, ipsecalgs_exec_mode_t *exec_mode) 171 { 172 if (strcmp(str, "sync") == 0) { 173 *exec_mode = LIBIPSEC_ALGS_EXEC_SYNC; 174 return (0); 175 } else if (strcmp(str, "async") == 0) { 176 *exec_mode = LIBIPSEC_ALGS_EXEC_ASYNC; 177 return (0); 178 } 179 180 return (-1); 181 } 182 183 /* 184 * Given a file pointer, read all the text from the file and convert it into 185 * a bunch of ipsec_proto_t's, each with an array of struct ipsecalgent 186 * pointers - one for each algorithm. 187 */ 188 static ipsec_proto_t * 189 build_list(FILE *f, int *num) 190 { 191 char line[1024]; 192 char *token, *lasts, *alg_names, *ef_name, *key_string, *block_string; 193 char *proto_name; 194 ipsec_proto_t *rc = NULL, *new_proto = NULL; 195 int *block_sizes, *key_sizes; 196 int rc_num = 0, key_increment; 197 int new_num, alg_num, num_sizes; 198 struct ipsecalgent *curalg, **newalglist; 199 char cur_pkg[1024]; 200 boolean_t doing_pkg = B_FALSE; 201 ipsecalgs_exec_mode_t exec_mode; 202 char diag_buf[128]; 203 204 diag_buf[0] = '\0'; 205 206 while (fgets(line, sizeof (line), f) != NULL) { 207 if (strncasecmp(line, LIBIPSEC_ALGS_LINE_PROTO, 208 sizeof (LIBIPSEC_ALGS_LINE_PROTO) - 1) != 0 && 209 strncasecmp(line, LIBIPSEC_ALGS_LINE_ALG, 210 sizeof (LIBIPSEC_ALGS_LINE_ALG) - 1) != 0 && 211 strncasecmp(line, LIBIPSEC_ALGS_LINE_PKGSTART, 212 sizeof (LIBIPSEC_ALGS_LINE_PKGSTART) - 1) != 0 && 213 strncasecmp(line, LIBIPSEC_ALGS_LINE_PKGEND, 214 sizeof (LIBIPSEC_ALGS_LINE_PKGEND) - 1) != 0) { 215 if ((token = strtok_r(line, " \t\n", &lasts)) == NULL || 216 token[0] == '#') { 217 continue; 218 } else { 219 snprintf(diag_buf, sizeof (diag_buf), 220 "non-recognized start of line"); 221 goto bail; 222 } 223 } 224 225 if (strncasecmp(line, LIBIPSEC_ALGS_LINE_PROTO, 226 sizeof (LIBIPSEC_ALGS_LINE_PROTO) - 1) == 0) { 227 /* current line defines a new protocol */ 228 229 /* skip the protocol token */ 230 token = strtok_r(line, pipechar, &lasts); 231 232 /* protocol number */ 233 token = strtok_r(NULL, pipechar, &lasts); 234 if (token == NULL || (new_num = atoi(token)) == 0) { 235 snprintf(diag_buf, sizeof (diag_buf), 236 "invalid protocol number"); 237 goto bail; 238 } 239 240 /* protocol name */ 241 token = strtok_r(NULL, pipechar, &lasts); 242 if (token == NULL) { 243 snprintf(diag_buf, sizeof (diag_buf), 244 "cannot read protocol name"); 245 goto bail; 246 } 247 proto_name = token; 248 249 /* execution mode */ 250 token = strtok_r(NULL, pipechar, &lasts); 251 if (token == NULL) { 252 snprintf(diag_buf, sizeof (diag_buf), 253 "cannot read execution mode"); 254 goto bail; 255 } 256 /* remove trailing '\n' */ 257 token[strlen(token) - 1] = '\0'; 258 if (_str_to_ipsec_exec_mode(token, &exec_mode) != 0) { 259 snprintf(diag_buf, sizeof (diag_buf), 260 "invalid execution mode: \"%s\"", token); 261 goto bail; 262 } 263 264 /* initialize protocol structure */ 265 rc_num++; 266 new_proto = (ipsec_proto_t *)realloc(rc, 267 sizeof (ipsec_proto_t) * rc_num); 268 rc = new_proto; 269 if (new_proto == NULL) 270 goto bail; 271 new_proto += (rc_num - 1); 272 new_proto->proto_num = new_num; 273 new_proto->proto_algs = NULL; 274 new_proto->proto_numalgs = 0; 275 new_proto->proto_name = strdup(proto_name); 276 if (new_proto->proto_name == NULL) 277 goto bail; 278 new_proto->proto_exec_mode = exec_mode; 279 280 if (doing_pkg) { 281 /* record proto as being part of current pkg */ 282 new_proto->proto_pkg = strdup(cur_pkg); 283 if (new_proto->proto_pkg == NULL) 284 goto bail; 285 } else { 286 new_proto->proto_pkg = NULL; 287 } 288 289 new_proto->proto_algs_pkgs = NULL; 290 new_proto->proto_algs_npkgs = 0; 291 292 } else if (strncasecmp(line, LIBIPSEC_ALGS_LINE_ALG, 293 sizeof (LIBIPSEC_ALGS_LINE_ALG) - 1) == 0) { 294 /* current line defines a new algorithm */ 295 296 /* skip the algorithm token */ 297 token = strtok_r(line, pipechar, &lasts); 298 299 /* protocol number */ 300 token = strtok_r(NULL, pipechar, &lasts); 301 if (token == NULL || (new_num = atoi(token)) == 0) { 302 snprintf(diag_buf, sizeof (diag_buf), 303 "invalid algorithm number"); 304 goto bail; 305 } 306 307 /* We can be O(N) for now. There aren't that many. */ 308 for (new_proto = rc; new_proto < (rc + new_num); 309 new_proto++) 310 if (new_proto->proto_num == new_num) 311 break; 312 if (new_proto == (rc + new_num)) { 313 snprintf(diag_buf, sizeof (diag_buf), 314 "invalid protocol number %d for algorithm", 315 new_num); 316 goto bail; 317 } 318 319 /* algorithm number */ 320 token = strtok_r(NULL, pipechar, &lasts); 321 if (token == NULL) { 322 snprintf(diag_buf, sizeof (diag_buf), 323 "cannot read algorithm number"); 324 goto bail; 325 } 326 /* Can't check for 0 here. */ 327 alg_num = atoi(token); 328 329 /* algorithm names */ 330 token = strtok_r(NULL, pipechar, &lasts); 331 if (token == NULL) { 332 snprintf(diag_buf, sizeof (diag_buf), 333 "cannot read algorithm number"); 334 goto bail; 335 } 336 alg_names = token; 337 338 /* mechanism name */ 339 token = strtok_r(NULL, pipechar, &lasts); 340 if (token == NULL) { 341 snprintf(diag_buf, sizeof (diag_buf), 342 "cannot read mechanism name for alg %d " 343 "(proto %d)", alg_num, 344 new_proto->proto_num); 345 goto bail; 346 } 347 ef_name = token; 348 349 /* key sizes */ 350 token = strtok_r(NULL, pipechar, &lasts); 351 if (token == NULL) { 352 snprintf(diag_buf, sizeof (diag_buf), 353 "cannot read key sizes for alg %d " 354 "(proto %d)", alg_num, 355 new_proto->proto_num); 356 goto bail; 357 } 358 key_string = token; 359 360 /* block sizes */ 361 token = strtok_r(NULL, pipechar, &lasts); 362 if (token == NULL) { 363 snprintf(diag_buf, sizeof (diag_buf), 364 "cannot read mechanism name for alg %d " 365 "(proto %d)", alg_num, 366 new_proto->proto_num); 367 goto bail; 368 } 369 block_string = token; 370 371 /* extract key sizes */ 372 key_increment = build_keysizes(&key_sizes, key_string); 373 if (key_increment == -1) { 374 snprintf(diag_buf, sizeof (diag_buf), 375 "invalid key sizes for alg %d (proto %d)", 376 alg_num, new_proto->proto_num); 377 goto bail; 378 } 379 380 /* extract block sizes */ 381 block_sizes = (int *)malloc(sizeof (int)); 382 if (block_sizes == NULL) { 383 free(key_sizes); 384 goto bail; 385 } 386 num_sizes = 0; 387 token = strtok_r(block_string, comma, &lasts); 388 if (token == NULL) { 389 snprintf(diag_buf, sizeof (diag_buf), 390 "invalid block sizes for alg %d (proto %d)", 391 alg_num, new_proto->proto_num); 392 free(key_sizes); 393 goto bail; 394 } 395 *block_sizes = 0; 396 do { 397 int *nbk; 398 399 nbk = (int *)realloc(block_sizes, 400 sizeof (int) * ((++num_sizes) + 1)); 401 if (nbk == NULL) { 402 free(key_sizes); 403 free(block_sizes); 404 goto bail; 405 } 406 block_sizes = nbk; 407 /* Can't check for 0 here... */ 408 block_sizes[num_sizes - 1] = atoi(token); 409 block_sizes[num_sizes] = 0; 410 } while ((token = strtok_r(NULL, comma, &lasts)) != 411 NULL); 412 413 /* Allocate a new struct ipsecalgent. */ 414 curalg = (struct ipsecalgent *)calloc( 415 sizeof (struct ipsecalgent), 1); 416 if (curalg == NULL) { 417 free(key_sizes); 418 free(block_sizes); 419 goto bail; 420 } 421 curalg->a_proto_num = new_num; 422 curalg->a_alg_num = alg_num; 423 curalg->a_block_sizes = block_sizes; 424 curalg->a_key_sizes = key_sizes; 425 curalg->a_key_increment = key_increment; 426 if ((curalg->a_mech_name = strdup(ef_name)) == NULL) { 427 freeipsecalgent(curalg); 428 goto bail; 429 } 430 /* Set names. */ 431 curalg->a_names = (char **)malloc(sizeof (char *)); 432 num_sizes = 0; /* Recycle "sizes" */ 433 token = strtok_r(alg_names, comma, &lasts); 434 if (curalg->a_names == NULL || token == NULL) { 435 freeipsecalgent(curalg); 436 goto bail; 437 } 438 do { 439 char **nnames; 440 441 nnames = (char **)realloc(curalg->a_names, 442 sizeof (char *) * ((++num_sizes) + 1)); 443 if (nnames == NULL) { 444 freeipsecalgent(curalg); 445 goto bail; 446 } 447 curalg->a_names = nnames; 448 curalg->a_names[num_sizes] = NULL; 449 curalg->a_names[num_sizes - 1] = 450 strdup(token); 451 if (curalg->a_names[num_sizes - 1] == NULL) { 452 freeipsecalgent(curalg); 453 goto bail; 454 } 455 } while ((token = strtok_r(NULL, comma, &lasts)) != 456 NULL); 457 458 if (doing_pkg) { 459 /* record alg as being part of current pkg */ 460 int npkgs = new_proto->proto_algs_npkgs; 461 462 new_proto->proto_algs_pkgs = realloc( 463 new_proto->proto_algs_pkgs, 464 (npkgs + 1) * sizeof (ipsecalgs_pkg_t)); 465 if (new_proto->proto_algs_pkgs == NULL) 466 goto bail; 467 468 new_proto->proto_algs_pkgs[npkgs].alg_num = 469 curalg->a_alg_num; 470 new_proto->proto_algs_pkgs[npkgs].pkg_name = 471 strdup(cur_pkg); 472 if (new_proto->proto_algs_pkgs[npkgs].pkg_name 473 == NULL) 474 goto bail; 475 476 new_proto->proto_algs_npkgs = npkgs + 1; 477 } 478 479 /* add new alg to protocol */ 480 newalglist = realloc(new_proto->proto_algs, 481 (new_proto->proto_numalgs + 1) * 482 sizeof (struct ipsecalgent *)); 483 if (newalglist == NULL) { 484 freeipsecalgent(curalg); 485 goto bail; 486 } 487 newalglist[new_proto->proto_numalgs] = curalg; 488 new_proto->proto_numalgs++; 489 new_proto->proto_algs = newalglist; 490 491 } else if (strncasecmp(line, LIBIPSEC_ALGS_LINE_PKGSTART, 492 sizeof (LIBIPSEC_ALGS_LINE_PKGSTART) - 1) == 0) { 493 /* start of package delimiter */ 494 if (doing_pkg) { 495 snprintf(diag_buf, sizeof (diag_buf), 496 "duplicate package start delimiters"); 497 goto bail; 498 } 499 (void) strncpy(cur_pkg, line + 500 (sizeof (LIBIPSEC_ALGS_LINE_PKGSTART) - 1), 501 sizeof (cur_pkg)); 502 /* remove trailing '\n' */ 503 cur_pkg[strlen(cur_pkg) - 1] = '\0'; 504 doing_pkg = B_TRUE; 505 506 } else { 507 /* end of package delimiter */ 508 char tmp_pkg[1024]; 509 510 if (!doing_pkg) { 511 snprintf(diag_buf, sizeof (diag_buf), 512 "end package delimiter without start"); 513 goto bail; 514 } 515 /* 516 * Get specified pkg name, fail if it doesn't match 517 * the package specified by the last # Begin. 518 */ 519 (void) strncpy(tmp_pkg, line + 520 (sizeof (LIBIPSEC_ALGS_LINE_PKGEND) - 1), 521 sizeof (tmp_pkg)); 522 /* remove trailing '\n' */ 523 tmp_pkg[strlen(tmp_pkg) - 1] = '\0'; 524 if (strncmp(cur_pkg, tmp_pkg, sizeof (cur_pkg)) != 0) 525 goto bail; 526 doing_pkg = B_FALSE; 527 } 528 } 529 530 *num = rc_num; 531 return (rc); 532 533 bail: 534 if (strlen(diag_buf) > 0) { 535 syslog(LOG_ERR, "possibly corrupt %s file: %s\n", 536 INET_IPSECALGSFILE, diag_buf); 537 } 538 _clean_trash(rc, rc_num); 539 return (NULL); 540 } 541 542 /* 543 * If alg_context is NULL, update the library's cached copy of 544 * INET_IPSECALGSFILE. If alg_context is non-NULL, hang a 545 * library-internal representation of a cached copy. The latter is useful 546 * for routines in libipsecutil that _write_ the contents out. 547 */ 548 void 549 _build_internal_algs(ipsec_proto_t **alg_context, int *alg_nums) 550 { 551 FILE *f = NULL; 552 int fd, rc, trash_num; 553 ipsec_proto_t *new_protos = NULL, *trash; 554 time_t filetime; 555 struct stat statbuf; 556 557 /* 558 * Construct new_protos from the file. 559 */ 560 if (alg_context == NULL) { 561 /* 562 * Check the time w/o holding the lock. This is just a 563 * cache reality check. We'll do it again for real if this 564 * surface check fails. 565 */ 566 if (stat(INET_IPSECALGSFILE, &statbuf) == -1 || 567 (statbuf.st_mtime < proto_last_update && 568 protos != NULL)) 569 return; 570 rw_wrlock(&proto_rw); 571 } 572 573 fd = open(INET_IPSECALGSFILE, O_RDONLY); 574 if (fd != -1) { 575 f = fdopen(fd, "r"); 576 if (f == NULL) { 577 close(fd); 578 } else { 579 rc = fstat(fd, &statbuf); 580 if (rc != -1) { 581 /* 582 * Update if the file is newer than our 583 * last cached copy. 584 */ 585 filetime = statbuf.st_mtime; 586 if (alg_context != NULL || 587 filetime > proto_last_update) 588 new_protos = build_list(f, &rc); 589 } 590 } 591 } 592 593 if (alg_context == NULL) { 594 /* 595 * If we have failed anywhere above, new_protoss will be NULL. 596 * This way, the previous cached protos will still be intact. 597 */ 598 if (new_protos != NULL) { 599 proto_last_update = filetime; 600 trash = protos; 601 trash_num = num_protos; 602 protos = new_protos; 603 num_protos = rc; 604 } else { 605 /* 606 * Else the original protocols and algorithms lists 607 * remains the same. 608 */ 609 trash = NULL; 610 } 611 rw_unlock(&proto_rw); 612 _clean_trash(trash, trash_num); 613 } else { 614 /* 615 * Assume caller has done the appropriate locking, 616 * cleanup, etc. And if new_protos is NULL, it's the caller's 617 * problem. 618 */ 619 *alg_context = new_protos; 620 *alg_nums = rc; 621 } 622 623 /* Since f is read-only, can avoid all of the failures... */ 624 if (f != NULL) 625 (void) fclose(f); 626 } 627 628 /* 629 * Assume input is 0-terminated. 630 */ 631 static int * 632 duplicate_intarr(int *orig) 633 { 634 size_t allocsize = sizeof (int); 635 int *iwalker = orig; 636 637 if (orig == NULL) 638 return (NULL); 639 640 while (*iwalker != 0) { 641 allocsize += sizeof (int); 642 iwalker++; 643 } 644 645 iwalker = malloc(allocsize); 646 if (iwalker != NULL) 647 memcpy(iwalker, orig, allocsize); 648 649 return (iwalker); 650 } 651 652 /* 653 * Assume input is NULL terminated. 654 */ 655 static char ** 656 duplicate_strarr(char **orig) 657 { 658 int i; 659 char **swalker; 660 char **newbie; 661 662 if (orig == NULL) 663 return (NULL); 664 665 /* count number of elements in source array */ 666 for (swalker = orig; *swalker != NULL; swalker++); 667 668 /* use calloc() to get NULL-initialization */ 669 newbie = calloc(swalker - orig + 1, sizeof (char *)); 670 671 if (newbie != NULL) { 672 /* do the copy */ 673 for (i = 0; orig[i] != NULL; i++) { 674 newbie[i] = strdup(orig[i]); 675 if (newbie[i] == NULL) { 676 for (swalker = newbie; *swalker != NULL; 677 swalker++) 678 free(*swalker); 679 free(newbie); 680 return (NULL); 681 } 682 } 683 } 684 685 return (newbie); 686 } 687 688 struct ipsecalgent * 689 _duplicate_alg(struct ipsecalgent *orig) 690 { 691 struct ipsecalgent *rc; 692 693 /* use calloc() to get NULL-initialization. */ 694 rc = calloc(1, sizeof (struct ipsecalgent)); 695 if (rc == NULL) 696 return (NULL); 697 698 rc->a_proto_num = orig->a_proto_num; 699 rc->a_alg_num = orig->a_alg_num; 700 rc->a_key_increment = orig->a_key_increment; 701 rc->a_mech_name = strdup(orig->a_mech_name); 702 rc->a_block_sizes = duplicate_intarr(orig->a_block_sizes); 703 rc->a_key_sizes = duplicate_intarr(orig->a_key_sizes); 704 rc->a_names = duplicate_strarr(orig->a_names); 705 706 if (rc->a_mech_name == NULL || rc->a_block_sizes == NULL || 707 rc->a_key_sizes == NULL || rc->a_names == NULL) { 708 freeipsecalgent(rc); 709 return (NULL); 710 } 711 712 return (rc); 713 } 714 715 /* 716 * Assume the rwlock is held for reading. 717 */ 718 static ipsec_proto_t * 719 findprotobynum(int proto_num) 720 { 721 int i; 722 723 for (i = 0; i < num_protos; i++) { 724 if (protos[i].proto_num == proto_num) 725 return (protos + i); 726 } 727 728 return (NULL); 729 } 730 731 static ipsec_proto_t * 732 findprotobyname(const char *name) 733 { 734 int i; 735 736 if (name == NULL) 737 return (NULL); 738 739 for (i = 0; i < num_protos; i++) { 740 /* Can use strcasecmp because our proto_name is bounded. */ 741 if (strcasecmp(protos[i].proto_name, name) == 0) 742 return (protos + i); 743 } 744 745 return (NULL); 746 } 747 748 int * 749 _real_getipsecprotos(int *nentries) 750 { 751 int *rc, i; 752 753 if (nentries == NULL) 754 return (NULL); 755 756 _build_internal_algs(NULL, NULL); 757 758 rw_rdlock(&proto_rw); 759 *nentries = num_protos; 760 /* 761 * Allocate 1 byte if there are no protocols so a non-NULL return 762 * happens. 763 */ 764 rc = malloc((num_protos == 0) ? 1 : num_protos * sizeof (int)); 765 if (rc != NULL) { 766 for (i = 0; i < num_protos; i++) 767 rc[i] = protos[i].proto_num; 768 } 769 rw_unlock(&proto_rw); 770 return (rc); 771 } 772 773 int * 774 _real_getipsecalgs(int *nentries, int proto_num) 775 { 776 int *rc = NULL, i; 777 ipsec_proto_t *proto; 778 779 if (nentries == NULL) 780 return (NULL); 781 782 _build_internal_algs(NULL, NULL); 783 784 rw_rdlock(&proto_rw); 785 proto = findprotobynum(proto_num); 786 if (proto != NULL) { 787 *nentries = proto->proto_numalgs; 788 /* 789 * Allocate 1 byte if there are no algorithms so a non-NULL 790 * return happens. 791 */ 792 rc = malloc((proto->proto_numalgs == 0) ? 1 : 793 proto->proto_numalgs * sizeof (int)); 794 if (rc != NULL) { 795 for (i = 0; i < proto->proto_numalgs; i++) 796 rc[i] = proto->proto_algs[i]->a_alg_num; 797 } 798 } 799 rw_unlock(&proto_rw); 800 return (rc); 801 } 802 803 struct ipsecalgent * 804 getipsecalgbyname(const char *name, int proto_num, int *errnop) 805 { 806 ipsec_proto_t *proto; 807 struct ipsecalgent *rc = NULL; 808 int i, my_errno = ENOENT; 809 char **name_check; 810 811 _build_internal_algs(NULL, NULL); 812 if (name == NULL) { 813 my_errno = EFAULT; 814 goto bail; 815 } 816 817 rw_rdlock(&proto_rw); 818 proto = findprotobynum(proto_num); 819 if (proto != NULL) { 820 for (i = 0; i < proto->proto_numalgs; i++) { 821 for (name_check = proto->proto_algs[i]->a_names; 822 *name_check != NULL; name_check++) { 823 /* 824 * Can use strcasecmp because our name_check 825 * is bounded. 826 */ 827 if (strcasecmp(*name_check, name) == 0) { 828 /* found match */ 829 rc = _duplicate_alg( 830 proto->proto_algs[i]); 831 my_errno = (rc == NULL) ? ENOMEM : 0; 832 rw_unlock(&proto_rw); 833 goto bail; 834 } 835 } 836 } 837 } else { 838 my_errno = EINVAL; 839 } 840 841 rw_unlock(&proto_rw); 842 bail: 843 if (errnop != NULL) 844 *errnop = my_errno; 845 return (rc); 846 } 847 848 struct ipsecalgent * 849 getipsecalgbynum(int alg_num, int proto_num, int *errnop) 850 { 851 ipsec_proto_t *proto; 852 struct ipsecalgent *rc = NULL; 853 int i, my_errno = ENOENT; 854 855 _build_internal_algs(NULL, NULL); 856 857 rw_rdlock(&proto_rw); 858 859 proto = findprotobynum(proto_num); 860 if (proto != NULL) { 861 for (i = 0; i < proto->proto_numalgs; i++) { 862 if (proto->proto_algs[i]->a_alg_num == alg_num) { 863 rc = _duplicate_alg(proto->proto_algs[i]); 864 my_errno = (rc == NULL) ? ENOMEM : 0; 865 break; 866 } 867 } 868 } else { 869 my_errno = EINVAL; 870 } 871 872 rw_unlock(&proto_rw); 873 if (errnop != NULL) 874 *errnop = my_errno; 875 return (rc); 876 } 877 878 int 879 getipsecprotobyname(const char *proto_name) 880 { 881 int rc = -1; 882 ipsec_proto_t *proto; 883 884 _build_internal_algs(NULL, NULL); 885 886 rw_rdlock(&proto_rw); 887 proto = findprotobyname(proto_name); 888 if (proto != NULL) 889 rc = proto->proto_num; 890 rw_unlock(&proto_rw); 891 return (rc); 892 } 893 894 char * 895 getipsecprotobynum(int proto_num) 896 { 897 ipsec_proto_t *proto; 898 char *rc = NULL; 899 900 _build_internal_algs(NULL, NULL); 901 902 rw_rdlock(&proto_rw); 903 proto = findprotobynum(proto_num); 904 if (proto != NULL) 905 rc = strdup(proto->proto_name); 906 907 rw_unlock(&proto_rw); 908 return (rc); 909 } 910 911 void 912 freeipsecalgent(struct ipsecalgent *ptr) 913 { 914 char **walker; 915 916 if (ptr == NULL) 917 return; 918 919 if (ptr->a_names != NULL) { 920 for (walker = ptr->a_names; *walker != NULL; walker++) 921 free(*walker); 922 } 923 924 /* 925 * Remember folks, free(NULL) works. 926 */ 927 free(ptr->a_names); 928 free(ptr->a_mech_name); 929 free(ptr->a_block_sizes); 930 free(ptr->a_key_sizes); 931 free(ptr); 932 } 933