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