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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <ipsec_util.h> 31 #include <stdlib.h> 32 #include <strings.h> 33 #include <netdb.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <libintl.h> 37 #include <errno.h> 38 39 static char *preamble = 40 "# /etc/inet/ipsecalgs output from ipsecalgs(1m)\n" 41 "#\n" 42 "# DO NOT EDIT OR PARSE THIS FILE!\n" 43 "#\n" 44 "# Use the ipsecalgs(1m) command to change the contents of this file.\n" 45 "\n"; 46 47 #define CFG_PERMS S_IRUSR | S_IRGRP | S_IROTH /* Perms 0444. */ 48 #define CFG_OWNER 0 /* root */ 49 #define CFG_GROUP 1 /* "other" */ 50 51 /* 52 * write_new_algfile() helper macros to check for write errors. 53 */ 54 55 #define FPRINTF_ERR(fcall) if ((fcall) < 0) { \ 56 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; \ 57 goto bail; \ 58 } 59 60 #define FPUT_ERR(fcall) if ((fcall) == EOF) { \ 61 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; \ 62 goto bail; \ 63 } 64 65 /* 66 * Helper macros to start and finish a list of entries that were added 67 * as part of a package installation. 68 */ 69 70 #define PKG_SEC_START(pkgname, doing_pkg, cur_pkg) { \ 71 (void) strcpy((cur_pkg), (pkgname)); \ 72 FPRINTF_ERR(fprintf(f, "%s%s\n", \ 73 LIBIPSEC_ALGS_LINE_PKGSTART, (cur_pkg))); \ 74 (doing_pkg) = B_TRUE; \ 75 } 76 77 #define PKG_SEC_END(doing_pkg, cur_pkg) { \ 78 if (doing_pkg) { \ 79 FPRINTF_ERR(fprintf(f, "%s%s\n", \ 80 LIBIPSEC_ALGS_LINE_PKGEND, (cur_pkg))); \ 81 (doing_pkg) = B_FALSE; \ 82 } \ 83 } 84 85 /* 86 * Take a zero-terminated int array and print int1,int2...,intN. 87 * If zero-only, then print a single '0'. 88 * Returns 0 on success, -1 if an error occurred while writing to 89 * the specified file. 90 */ 91 int 92 list_ints(FILE *f, int *floater) 93 { 94 boolean_t executed = B_FALSE; 95 96 while (*floater != 0) { 97 executed = B_TRUE; 98 if (fprintf(f, "%d", *floater) < 0) 99 return (-1); 100 if (*(++floater) != 0) 101 if (fputc(',', f) == EOF) 102 return (-1); 103 } 104 105 if (!executed) 106 if (fputc('0', f) == EOF) 107 return (-1); 108 109 return (0); 110 } 111 112 /* 113 * If the specified algorithm was defined within a package section, i.e. 114 * between the lines "# Start <pkgname>" and "# End <pkgname>", returns 115 * the value of <pkgname>. 116 */ 117 static char * 118 alg_has_pkg(ipsec_proto_t *proto, struct ipsecalgent *alg) 119 { 120 int i; 121 122 if (proto->proto_algs_pkgs == NULL) 123 return (NULL); 124 125 for (i = 0; i < proto->proto_algs_npkgs; i++) 126 if (proto->proto_algs_pkgs[i].alg_num == alg->a_alg_num) 127 return (proto->proto_algs_pkgs[i].pkg_name); 128 129 return (NULL); 130 } 131 132 /* 133 * Writes the package start/end delimiters according to the package 134 * name associated with the current protocol or algorithm, and 135 * the state of the packaging information already written to the file. 136 * Called by write_new_algfile(). Returns 0 on success, one of the 137 * LIBIPSEC_DIAG codes on failure. 138 */ 139 static int 140 pkg_section(FILE *f, char *pkg_name, boolean_t *doing_pkg, char *cur_pkg) 141 { 142 int rc = 0; 143 144 if (pkg_name != NULL) { 145 /* protocol or algorithm is associated with a package */ 146 if (!*doing_pkg) { 147 /* start of a new package section */ 148 PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg); 149 } else { 150 /* already in a package section */ 151 if (strcmp(pkg_name, cur_pkg) != 0) { 152 /* different package name */ 153 PKG_SEC_END(*doing_pkg, cur_pkg); 154 PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg); 155 } 156 } 157 } else if (*doing_pkg) { 158 /* in a package section when the entry isn't */ 159 PKG_SEC_END(*doing_pkg, cur_pkg); 160 } 161 bail: 162 return (rc); 163 } 164 165 /* 166 * Given a list of protocols and number, write them to a new algorithm file. 167 * This function takes num_protos + num_protos * dois-per-alg operations. 168 * Also free the protocol structure. 169 * 170 * Note that no locking spans the read/update/write phases that can be 171 * used by callers of this routine. This could cause this function to suffer 172 * from the "lost update" problem. Since updates to the IPsec protocols 173 * and algorithm tables are very infrequent, this should not be a issue in 174 * practice. 175 */ 176 static int 177 write_new_algfile(ipsec_proto_t *protos, int num_protos) 178 { 179 FILE *f; 180 int fd, i, j, k; 181 int rc = 0; 182 struct ipsecalgent *alg; 183 char cur_pkg[1024]; 184 boolean_t doing_pkg = B_FALSE; 185 char *alg_pkg; 186 char tmp_name_template[] = INET_IPSECALGSPATH "ipsecalgsXXXXXX"; 187 char *tmp_name; 188 189 /* 190 * In order to avoid potentially corrupting the configuration 191 * file on file system failure, write the new configuration info 192 * to a temporary file which is then renamed to the configuration 193 * file (INET_IPSECALGSFILE.) 194 */ 195 tmp_name = mktemp(tmp_name_template); 196 197 fd = open(tmp_name, O_WRONLY|O_CREAT|O_EXCL, CFG_PERMS); 198 if (fd == -1) { 199 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN; 200 goto bail; 201 } 202 203 f = fdopen(fd, "w"); 204 if (f == NULL) { 205 (void) close(fd); 206 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN; 207 goto bail; 208 } 209 210 FPUT_ERR(fputs(preamble, f)); 211 212 /* Write protocol entries. */ 213 for (i = 0; i < num_protos; i++) { 214 215 /* add package section delimiters if needed */ 216 rc = pkg_section(f, protos[i].proto_pkg, &doing_pkg, cur_pkg); 217 if (rc != 0) 218 goto bail; 219 220 FPRINTF_ERR(fprintf(f, "%s%d|%s|", 221 LIBIPSEC_ALGS_LINE_PROTO, 222 protos[i].proto_num, protos[i].proto_name)); 223 switch (protos[i].proto_exec_mode) { 224 case LIBIPSEC_ALGS_EXEC_SYNC: 225 FPRINTF_ERR(fprintf(f, "sync\n")); 226 break; 227 case LIBIPSEC_ALGS_EXEC_ASYNC: 228 FPRINTF_ERR(fprintf(f, "async\n")); 229 break; 230 } 231 } 232 233 /* terminate the package section for the protocols if needed */ 234 PKG_SEC_END(doing_pkg, cur_pkg); 235 236 FPUT_ERR(fputs("\n", f)); 237 238 /* Write algorithm entries. */ 239 240 for (i = 0; i < num_protos; i++) { 241 for (j = 0; j < protos[i].proto_numalgs; j++) { 242 alg = protos[i].proto_algs[j]; 243 244 /* add package section delimiters if needed */ 245 alg_pkg = alg_has_pkg(&protos[i], alg); 246 rc = pkg_section(f, alg_pkg, &doing_pkg, cur_pkg); 247 if (rc != 0) 248 goto bail; 249 250 /* protocol and algorithm numbers */ 251 FPRINTF_ERR(fprintf(f, "%s%d|%d|", 252 LIBIPSEC_ALGS_LINE_ALG, 253 alg->a_proto_num, alg->a_alg_num)); 254 255 /* algorithm names */ 256 for (k = 0; alg->a_names[k] != NULL; k++) { 257 FPRINTF_ERR(fprintf(f, "%s", alg->a_names[k])); 258 if (alg->a_names[k+1] != NULL) 259 FPRINTF_ERR(fprintf(f, ",")); 260 } 261 262 /* mechanism name */ 263 FPRINTF_ERR(fprintf(f, "|%s|", alg->a_mech_name)); 264 265 /* key sizes */ 266 if (alg->a_key_increment == 0) { 267 /* key sizes defined by enumeration */ 268 if (list_ints(f, alg->a_key_sizes) == -1) { 269 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; 270 goto bail; 271 } 272 } else { 273 /* key sizes defined by range */ 274 FPRINTF_ERR(fprintf(f, "%d/%d-%d,%d", 275 alg->a_key_sizes[0], alg->a_key_sizes[1], 276 alg->a_key_sizes[2], alg->a_key_increment)); 277 } 278 FPUT_ERR(fputc('|', f)); 279 280 /* block sizes */ 281 if (list_ints(f, alg->a_block_sizes) == -1) { 282 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; 283 goto bail; 284 } 285 FPUT_ERR(fputc('\n', f)); 286 } 287 } 288 289 /* terminate the package section for the algorithms if needed */ 290 PKG_SEC_END(doing_pkg, cur_pkg); 291 292 if (fchmod(fd, CFG_PERMS) == -1) { 293 rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD; 294 goto bail; 295 } 296 if (fchown(fd, CFG_OWNER, CFG_GROUP) == -1) { 297 rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN; 298 goto bail; 299 } 300 if (fclose(f) == EOF) { 301 rc = LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE; 302 goto bail; 303 } 304 305 if (rename(tmp_name, INET_IPSECALGSFILE) == -1) 306 rc = LIBIPSEC_ALGS_DIAG_ALGSFILERENAME; 307 308 bail: 309 _clean_trash(protos, num_protos); 310 return (rc); 311 } 312 313 /* 314 * Return a pointer to the protocol entry corresponding to the specified 315 * protocol num proto_num. Also builds the list of currently defined 316 * protocols. 317 */ 318 static ipsec_proto_t * 319 proto_setup(ipsec_proto_t **protos, int *num_protos, int proto_num, 320 boolean_t cleanup) 321 { 322 int i; 323 ipsec_proto_t *current_proto, *ret_proto = NULL; 324 325 _build_internal_algs(protos, num_protos); 326 327 if (*protos == NULL) 328 return (NULL); 329 330 for (i = 0; i < *num_protos; i++) { 331 current_proto = (*protos) + i; 332 if (current_proto->proto_num == proto_num) { 333 ret_proto = current_proto; 334 break; 335 } 336 } 337 338 if (ret_proto == NULL) { 339 if (cleanup) 340 _clean_trash(*protos, *num_protos); 341 /* else caller wants parsed /etc/inet/ipsecalgs anyway */ 342 } 343 344 return (ret_proto); 345 } 346 347 /* 348 * Delete the first found algorithm of the specified protocol which 349 * has the same name as the one specified by alg_name. Deletion of 350 * the entry takes place only if the delete_it flag is set. If an 351 * entry was found, return B_TRUE, otherwise return B_FALSE. 352 */ 353 static boolean_t 354 delipsecalgbyname_common(const char *name, ipsec_proto_t *proto, 355 boolean_t delete_it) 356 { 357 int i; 358 char **name_check; 359 boolean_t found_match = B_FALSE; 360 361 for (i = 0; i < proto->proto_numalgs; i++) { 362 if (!found_match) { 363 for (name_check = 364 proto->proto_algs[i]->a_names; 365 *name_check != NULL; name_check++) { 366 /* 367 * Can use strcmp because the algorithm names 368 * are bound. 369 */ 370 if (strcmp(*name_check, name) == 0) { 371 found_match = B_TRUE; 372 if (!delete_it) 373 return (found_match); 374 freeipsecalgent(proto->proto_algs[i]); 375 break; 376 } 377 } 378 } else { 379 proto->proto_algs[i - 1] = proto->proto_algs[i]; 380 } 381 } 382 383 if (found_match) 384 proto->proto_numalgs--; 385 386 return (found_match); 387 } 388 389 /* 390 * Returns B_TRUE if the specified 0-terminated lists of key or 391 * block sizes match, B_FALSE otherwise. 392 */ 393 static boolean_t 394 sizes_match(int *a1, int *a2) 395 { 396 int i; 397 398 for (i = 0; (a1[i] != 0) && (a2[i] != 0); i++) { 399 if (a1[i] != a2[i]) 400 return (B_FALSE); 401 } 402 if ((a1[i] != 0) || (a2[i] != 0)) 403 return (B_FALSE); 404 405 return (B_TRUE); 406 } 407 408 /* 409 * Returns B_TRUE if an _exact_ equivalent of the specified algorithm 410 * already exists, B_FALSE otherwise. 411 */ 412 static boolean_t 413 ipsecalg_exists(struct ipsecalgent *newbie, ipsec_proto_t *proto) 414 { 415 struct ipsecalgent *curalg; 416 char **curname, **newbiename; 417 int i; 418 boolean_t match; 419 420 for (i = 0; i < proto->proto_numalgs; i++) { 421 curalg = proto->proto_algs[i]; 422 423 if (curalg->a_alg_num != newbie->a_alg_num) 424 continue; 425 426 if (curalg->a_key_increment != newbie->a_key_increment) 427 continue; 428 429 if (strcmp(curalg->a_mech_name, newbie->a_mech_name) != 0) 430 continue; 431 432 curname = curalg->a_names; 433 newbiename = newbie->a_names; 434 match = B_TRUE; 435 while ((*curname != NULL) && (*newbiename != NULL) && match) { 436 match = (strcmp(*curname, *newbiename) == 0); 437 curname++; 438 newbiename++; 439 } 440 if (!match || (*curname != NULL) || (*newbiename != NULL)) 441 continue; 442 443 if (!sizes_match(curalg->a_block_sizes, newbie->a_block_sizes)) 444 continue; 445 446 if (!sizes_match(curalg->a_key_sizes, newbie->a_key_sizes)) 447 continue; 448 449 /* we found an exact match */ 450 return (B_TRUE); 451 } 452 453 return (B_FALSE); 454 } 455 456 /* 457 * Add a new algorithm to the /etc/inet/ipsecalgs file. Caller must free 458 * or otherwise address "newbie". 459 */ 460 int 461 addipsecalg(struct ipsecalgent *newbie, uint_t flags) 462 { 463 ipsec_proto_t *protos, *current_proto; 464 struct ipsecalgent *clone, **holder; 465 int num_protos, i; 466 char **name_check; 467 boolean_t forced_add = (flags & LIBIPSEC_ALGS_ADD_FORCE) != 0; 468 boolean_t found_match; 469 470 if ((current_proto = proto_setup(&protos, &num_protos, 471 newbie->a_proto_num, B_TRUE)) == NULL) 472 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 473 474 /* 475 * If an algorithm that matches _exactly_ the new algorithm 476 * already exists, we're done. 477 */ 478 if (ipsecalg_exists(newbie, current_proto)) 479 return (0); 480 481 /* 482 * We don't allow a new algorithm to be created if one of 483 * its names is already defined for an existing algorithm, 484 * unless the operation is forced, in which case existing 485 * algorithm entries that conflict with the new one are 486 * deleted. 487 */ 488 for (name_check = newbie->a_names; *name_check != NULL; name_check++) { 489 found_match = delipsecalgbyname_common(*name_check, 490 current_proto, forced_add); 491 if (found_match && !forced_add) { 492 /* 493 * Duplicate entry found, but the addition was 494 * not forced. 495 */ 496 _clean_trash(protos, num_protos); 497 return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS); 498 } 499 } 500 501 for (i = 0; i < current_proto->proto_numalgs; i++) { 502 if (current_proto->proto_algs[i]->a_alg_num == 503 newbie->a_alg_num) { 504 /* 505 * An algorithm with the same protocol number 506 * and algorithm number already exists. Fail 507 * addition unless the operation is forced. 508 */ 509 if (flags & LIBIPSEC_ALGS_ADD_FORCE) { 510 clone = _duplicate_alg(newbie); 511 if (clone != NULL) { 512 freeipsecalgent( 513 current_proto->proto_algs[i]); 514 current_proto->proto_algs[i] = clone; 515 return (write_new_algfile(protos, 516 num_protos)); 517 } else { 518 _clean_trash(protos, num_protos); 519 return (LIBIPSEC_ALGS_DIAG_NOMEM); 520 } 521 } else { 522 _clean_trash(protos, num_protos); 523 return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS); 524 } 525 } 526 } 527 528 /* append the new algorithm */ 529 holder = realloc(current_proto->proto_algs, 530 sizeof (struct ipsecalgent *) * (i + 1)); 531 if (holder == NULL) { 532 _clean_trash(protos, num_protos); 533 return (LIBIPSEC_ALGS_DIAG_NOMEM); 534 } 535 clone = _duplicate_alg(newbie); 536 if (clone == NULL) { 537 free(holder); 538 _clean_trash(protos, num_protos); 539 return (LIBIPSEC_ALGS_DIAG_NOMEM); 540 } 541 current_proto->proto_numalgs++; 542 current_proto->proto_algs = holder; 543 current_proto->proto_algs[i] = clone; 544 return (write_new_algfile(protos, num_protos)); 545 } 546 547 /* 548 * Delete an algorithm by name & protocol number from /etc/inet/ipsecalgs. 549 * Only deletes the first encountered instance. 550 */ 551 int 552 delipsecalgbyname(const char *name, int proto_num) 553 { 554 ipsec_proto_t *protos, *current_proto; 555 int num_protos; 556 557 if ((current_proto = proto_setup(&protos, &num_protos, proto_num, 558 B_TRUE)) == NULL) 559 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 560 561 if (delipsecalgbyname_common(name, current_proto, B_TRUE)) 562 return (write_new_algfile(protos, num_protos)); 563 564 _clean_trash(protos, num_protos); 565 return (LIBIPSEC_ALGS_DIAG_UNKN_ALG); 566 } 567 568 /* 569 * Delete an algorithm by num + protocol num from /etc/inet/ipsecalgs. 570 */ 571 int 572 delipsecalgbynum(int alg_num, int proto_num) 573 { 574 ipsec_proto_t *protos, *current_proto; 575 int i, num_protos; 576 boolean_t found_match = B_FALSE; 577 578 if ((current_proto = proto_setup(&protos, &num_protos, proto_num, 579 B_TRUE)) == NULL) 580 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 581 582 for (i = 0; i < current_proto->proto_numalgs; i++) { 583 if (!found_match) { 584 if (current_proto->proto_algs[i]->a_alg_num == 585 alg_num) { 586 found_match = B_TRUE; 587 freeipsecalgent(current_proto->proto_algs[i]); 588 } 589 } else { 590 current_proto->proto_algs[i - 1] = 591 current_proto->proto_algs[i]; 592 } 593 } 594 595 if (found_match) { 596 current_proto->proto_numalgs--; 597 return (write_new_algfile(protos, num_protos)); 598 } 599 600 _clean_trash(protos, num_protos); 601 return (LIBIPSEC_ALGS_DIAG_UNKN_ALG); 602 } 603 604 /* 605 * Remove the specified protocol entry from the list of protocols. 606 */ 607 static void 608 delipsecproto_common(ipsec_proto_t *protos, int num_protos, 609 ipsec_proto_t *proto) 610 { 611 int i; 612 613 /* free protocol storage */ 614 free(proto->proto_name); 615 for (i = 0; i < proto->proto_numalgs; i++) 616 freeipsecalgent(proto->proto_algs[i]); 617 618 /* remove from list of prototocols */ 619 for (i = (proto - protos + 1); i < num_protos; i++) 620 protos[i - 1] = protos[i]; 621 } 622 623 /* 624 * Add an IPsec protocol to /etc/inet/ipsecalgs. 625 */ 626 int 627 addipsecproto(const char *proto_name, int proto_num, 628 ipsecalgs_exec_mode_t proto_exec_mode, uint_t flags) 629 { 630 ipsec_proto_t *protos, *current_proto, *new_proto; 631 int i, num_protos; 632 633 /* 634 * NOTE:If build_internal_algs returns NULL for any 635 * reason, we will end up clobbering /etc/inet/ipsecalgs! 636 */ 637 638 current_proto = proto_setup(&protos, &num_protos, proto_num, B_FALSE); 639 640 /* check for protocol with duplicate id */ 641 if (current_proto != NULL) { 642 if ((strcmp(proto_name, current_proto->proto_name) == 0) && 643 (proto_exec_mode == current_proto->proto_exec_mode)) { 644 /* 645 * The current protocol being added matches 646 * exactly an existing protocol, we're done. 647 */ 648 return (0); 649 } 650 if (!(flags & LIBIPSEC_ALGS_ADD_FORCE)) 651 return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS); 652 delipsecproto_common(protos, num_protos--, current_proto); 653 } 654 655 /* check for protocol with duplicate name */ 656 for (i = 0; i < num_protos; i++) { 657 if (strcmp(protos[i].proto_name, proto_name) == 0) { 658 if (!(flags & LIBIPSEC_ALGS_ADD_FORCE)) 659 return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS); 660 delipsecproto_common(protos, num_protos--, &protos[i]); 661 break; 662 } 663 } 664 665 /* add new protocol */ 666 num_protos++; 667 new_proto = realloc(protos, num_protos * 668 sizeof (ipsec_proto_t)); 669 if (new_proto == NULL) { 670 _clean_trash(protos, num_protos - 1); 671 return (LIBIPSEC_ALGS_DIAG_NOMEM); 672 } 673 protos = new_proto; 674 new_proto += (num_protos - 1); 675 676 /* initialize protocol entry */ 677 new_proto->proto_num = proto_num; 678 new_proto->proto_numalgs = 0; 679 new_proto->proto_algs = NULL; 680 new_proto->proto_name = strdup(proto_name); 681 if (new_proto->proto_name == NULL) { 682 _clean_trash(protos, num_protos); 683 return (LIBIPSEC_ALGS_DIAG_NOMEM); 684 } 685 new_proto->proto_pkg = NULL; 686 new_proto->proto_algs_pkgs = NULL; 687 new_proto->proto_algs_npkgs = 0; 688 new_proto->proto_exec_mode = proto_exec_mode; 689 690 return (write_new_algfile(protos, num_protos)); 691 } 692 693 /* 694 * Delete an IPsec protocol entry from /etc/inet/ipsecalgs. This also 695 * nukes the associated algorithms. 696 */ 697 int 698 delipsecprotobynum(int proto_num) 699 { 700 ipsec_proto_t *protos, *current_proto; 701 int num_protos; 702 703 if ((current_proto = proto_setup(&protos, &num_protos, proto_num, 704 B_TRUE)) == NULL) 705 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 706 707 delipsecproto_common(protos, num_protos--, current_proto); 708 709 return (write_new_algfile(protos, num_protos)); 710 } 711 712 int 713 delipsecprotobyname(const char *proto_name) 714 { 715 int proto_num; 716 717 proto_num = getipsecprotobyname(proto_name); 718 if (proto_num == -1) 719 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 720 721 return (delipsecprotobynum(proto_num)); 722 } 723 724 /* 725 * Implement these in libnsl since these are read-only operations. 726 */ 727 int * 728 getipsecprotos(int *nentries) 729 { 730 return (_real_getipsecprotos(nentries)); 731 } 732 733 int * 734 getipsecalgs(int *nentries, int proto_num) 735 { 736 return (_real_getipsecalgs(nentries, proto_num)); 737 } 738 739 const char * 740 ipsecalgs_diag(int diag) 741 { 742 switch (diag) { 743 case LIBIPSEC_ALGS_DIAG_ALG_EXISTS: 744 return (gettext("Algorithm already exists")); 745 case LIBIPSEC_ALGS_DIAG_PROTO_EXISTS: 746 return (gettext("Protocol already exists")); 747 case LIBIPSEC_ALGS_DIAG_UNKN_PROTO: 748 return (gettext("Unknown protocol")); 749 case LIBIPSEC_ALGS_DIAG_UNKN_ALG: 750 return (gettext("Unknown algorithm")); 751 case LIBIPSEC_ALGS_DIAG_NOMEM: 752 return (gettext("Out of memory")); 753 case LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN: 754 return (gettext("open() failed")); 755 case LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN: 756 return (gettext("fdopen() failed")); 757 case LIBIPSEC_ALGS_DIAG_ALGSFILELOCK: 758 return (gettext("lockf() failed")); 759 case LIBIPSEC_ALGS_DIAG_ALGSFILERENAME: 760 return (gettext("rename() failed")); 761 case LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE: 762 return (gettext("write to file failed")); 763 case LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD: 764 return (gettext("chmod() failed")); 765 case LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN: 766 return (gettext("chown() failed")); 767 case LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE: 768 return (gettext("close() failed")); 769 default: 770 return (gettext("failed")); 771 } 772 } 773 774 /* 775 * Get the execution mode corresponding to the specified protocol. 776 * Returns 0 on success, one of the LIBIPSEC_ALGS_DIAG_* values on 777 * failure. 778 */ 779 int 780 ipsecproto_get_exec_mode(int proto_num, ipsecalgs_exec_mode_t *exec_mode) 781 { 782 ipsec_proto_t *protos, *current_proto; 783 int num_protos; 784 785 if ((current_proto = proto_setup(&protos, &num_protos, proto_num, 786 B_TRUE)) == NULL) 787 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 788 789 *exec_mode = current_proto->proto_exec_mode; 790 791 _clean_trash(protos, num_protos); 792 return (0); 793 } 794 795 /* 796 * Set the execution mode of the specified protocol. Returns 0 on success, 797 * or one of the LIBIPSEC_ALGS_DIAG_* values on failure. 798 */ 799 int 800 ipsecproto_set_exec_mode(int proto_num, ipsecalgs_exec_mode_t exec_mode) 801 { 802 ipsec_proto_t *protos, *current_proto; 803 int num_protos; 804 805 if ((current_proto = proto_setup(&protos, &num_protos, proto_num, 806 B_TRUE)) == NULL) 807 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); 808 809 current_proto->proto_exec_mode = exec_mode; 810 811 return (write_new_algfile(protos, num_protos)); 812 } 813