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 <fcntl.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <unistd.h> 31 #include <locale.h> 32 #include <libgen.h> 33 #include <sys/types.h> 34 #include <zone.h> 35 #include <sys/crypto/ioctladmin.h> 36 #include "cryptoadm.h" 37 38 #define DEFAULT_DEV_NUM 5 39 #define DEFAULT_SOFT_NUM 10 40 41 static crypto_get_soft_info_t *setup_get_soft_info(char *, int); 42 43 /* 44 * Prepare the argument for the LOAD_SOFT_CONFIG ioctl call for the 45 * provider pointed by pent. Return NULL if out of memory. 46 */ 47 crypto_load_soft_config_t * 48 setup_soft_conf(entry_t *pent) 49 { 50 crypto_load_soft_config_t *pload_soft_conf; 51 mechlist_t *plist; 52 uint_t sup_count; 53 size_t extra_mech_size = 0; 54 int i; 55 56 if (pent == NULL) { 57 return (NULL); 58 } 59 60 sup_count = pent->sup_count; 61 if (sup_count > 1) { 62 extra_mech_size = sizeof (crypto_mech_name_t) * 63 (sup_count - 1); 64 } 65 66 pload_soft_conf = malloc(sizeof (crypto_load_soft_config_t) + 67 extra_mech_size); 68 if (pload_soft_conf == NULL) { 69 cryptodebug("out of memory."); 70 return (NULL); 71 } 72 73 (void) strlcpy(pload_soft_conf->sc_name, pent->name, MAXNAMELEN); 74 pload_soft_conf->sc_count = sup_count; 75 76 i = 0; 77 plist = pent->suplist; 78 while (i < sup_count) { 79 (void) strlcpy(pload_soft_conf->sc_list[i++], 80 plist->name, CRYPTO_MAX_MECH_NAME); 81 plist = plist->next; 82 } 83 84 return (pload_soft_conf); 85 } 86 87 88 /* 89 * Prepare the argument for the LOAD_SOFT_DISABLED ioctl call for the 90 * provider pointed by pent. Return NULL if out of memory. 91 */ 92 crypto_load_soft_disabled_t * 93 setup_soft_dis(entry_t *pent) 94 { 95 crypto_load_soft_disabled_t *pload_soft_dis = NULL; 96 mechlist_t *plist = NULL; 97 size_t extra_mech_size = 0; 98 uint_t dis_count; 99 int i; 100 101 if (pent == NULL) { 102 return (NULL); 103 } 104 105 dis_count = pent->dis_count; 106 if (dis_count > 1) { 107 extra_mech_size = sizeof (crypto_mech_name_t) * 108 (dis_count - 1); 109 } 110 111 pload_soft_dis = malloc(sizeof (crypto_load_soft_disabled_t) + 112 extra_mech_size); 113 if (pload_soft_dis == NULL) { 114 cryptodebug("out of memory."); 115 return (NULL); 116 } 117 118 (void) strlcpy(pload_soft_dis->sd_name, pent->name, MAXNAMELEN); 119 pload_soft_dis->sd_count = dis_count; 120 121 i = 0; 122 plist = pent->dislist; 123 while (i < dis_count) { 124 (void) strlcpy(pload_soft_dis->sd_list[i++], 125 plist->name, CRYPTO_MAX_MECH_NAME); 126 plist = plist->next; 127 } 128 129 return (pload_soft_dis); 130 } 131 132 133 /* 134 * Prepare the argument for the LOAD_DEV_DISABLED ioctl call for the 135 * provider pointed by pent. Return NULL if out of memory. 136 */ 137 crypto_load_dev_disabled_t * 138 setup_dev_dis(entry_t *pent) 139 { 140 crypto_load_dev_disabled_t *pload_dev_dis = NULL; 141 mechlist_t *plist = NULL; 142 size_t extra_mech_size = 0; 143 uint_t dis_count; 144 int i; 145 char pname[MAXNAMELEN]; 146 int inst_num; 147 148 if (pent == NULL) { 149 return (NULL); 150 } 151 152 /* get the device name and the instance number */ 153 if (split_hw_provname(pent->name, pname, &inst_num) == FAILURE) { 154 return (NULL); 155 } 156 157 /* allocate space for pload_dev_des */ 158 dis_count = pent->dis_count; 159 if (dis_count > 1) { 160 extra_mech_size = sizeof (crypto_mech_name_t) * 161 (dis_count - 1); 162 } 163 164 pload_dev_dis = malloc(sizeof (crypto_load_dev_disabled_t) + 165 extra_mech_size); 166 if (pload_dev_dis == NULL) { 167 cryptodebug("out of memory."); 168 return (NULL); 169 } 170 171 /* set the values for pload_dev_dis */ 172 (void) strlcpy(pload_dev_dis->dd_dev_name, pname, MAXNAMELEN); 173 pload_dev_dis->dd_dev_instance = inst_num; 174 pload_dev_dis->dd_count = dis_count; 175 176 i = 0; 177 plist = pent->dislist; 178 while (i < dis_count) { 179 (void) strlcpy(pload_dev_dis->dd_list[i++], 180 plist->name, CRYPTO_MAX_MECH_NAME); 181 plist = plist->next; 182 } 183 184 return (pload_dev_dis); 185 } 186 187 188 /* 189 * Prepare the calling argument of the UNLOAD_SOFT_MODULE ioctl call for the 190 * provider pointed by pent. Return NULL if out of memory. 191 */ 192 crypto_unload_soft_module_t * 193 setup_unload_soft(entry_t *pent) 194 { 195 crypto_unload_soft_module_t *punload_soft; 196 197 if (pent == NULL) { 198 return (NULL); 199 } 200 201 punload_soft = malloc(sizeof (crypto_unload_soft_module_t)); 202 if (punload_soft == NULL) { 203 cryptodebug("out of memory."); 204 return (NULL); 205 } 206 207 (void) strlcpy(punload_soft->sm_name, pent->name, MAXNAMELEN); 208 209 return (punload_soft); 210 } 211 212 213 /* 214 * Prepare the calling argument for the GET_SOFT_INFO call for the provider 215 * with the number of mechanisms specified in the second argument. 216 * 217 * Called by get_soft_info(). 218 */ 219 static crypto_get_soft_info_t * 220 setup_get_soft_info(char *provname, int count) 221 { 222 crypto_get_soft_info_t *psoft_info; 223 size_t extra_mech_size = 0; 224 225 if (provname == NULL) { 226 return (NULL); 227 } 228 229 if (count > 1) { 230 extra_mech_size = sizeof (crypto_mech_name_t) * (count - 1); 231 } 232 233 psoft_info = malloc(sizeof (crypto_get_soft_info_t) + extra_mech_size); 234 if (psoft_info == NULL) { 235 cryptodebug("out of memory."); 236 return (NULL); 237 } 238 239 (void) strlcpy(psoft_info->si_name, provname, MAXNAMELEN); 240 psoft_info->si_count = count; 241 242 return (psoft_info); 243 } 244 245 246 /* 247 * Get the device list from kernel. 248 */ 249 int 250 get_dev_list(crypto_get_dev_list_t **ppdevlist) 251 { 252 crypto_get_dev_list_t *pdevlist; 253 int fd = -1; 254 int count = DEFAULT_DEV_NUM; 255 256 pdevlist = malloc(sizeof (crypto_get_dev_list_t) + 257 sizeof (crypto_dev_list_entry_t) * (count - 1)); 258 if (pdevlist == NULL) { 259 cryptodebug("out of memory."); 260 return (FAILURE); 261 } 262 263 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 264 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 265 ADMIN_IOCTL_DEVICE, strerror(errno)); 266 return (FAILURE); 267 } 268 269 pdevlist->dl_dev_count = count; 270 if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { 271 cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", 272 strerror(errno)); 273 free(pdevlist); 274 (void) close(fd); 275 return (FAILURE); 276 } 277 278 /* BUFFER is too small, get the number of devices and retry it. */ 279 if (pdevlist->dl_return_value == CRYPTO_BUFFER_TOO_SMALL) { 280 count = pdevlist->dl_dev_count; 281 free(pdevlist); 282 pdevlist = malloc(sizeof (crypto_get_dev_list_t) + 283 sizeof (crypto_dev_list_entry_t) * (count - 1)); 284 if (pdevlist == NULL) { 285 cryptodebug("out of memory."); 286 (void) close(fd); 287 return (FAILURE); 288 } 289 290 if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { 291 cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", 292 strerror(errno)); 293 free(pdevlist); 294 (void) close(fd); 295 return (FAILURE); 296 } 297 } 298 299 if (pdevlist->dl_return_value != CRYPTO_SUCCESS) { 300 cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed, " 301 "return_value = %d", pdevlist->dl_return_value); 302 free(pdevlist); 303 (void) close(fd); 304 return (FAILURE); 305 } 306 307 *ppdevlist = pdevlist; 308 (void) close(fd); 309 return (SUCCESS); 310 } 311 312 313 /* 314 * Get all the mechanisms supported by the hardware provider. 315 * The result will be stored in the second argument. 316 */ 317 int 318 get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist) 319 { 320 crypto_get_dev_info_t *dev_info; 321 mechlist_t *phead; 322 mechlist_t *pcur; 323 mechlist_t *pmech; 324 int fd = -1; 325 int i; 326 int rc; 327 328 if (devname == NULL || count < 1) { 329 cryptodebug("get_dev_info(): devname is NULL or bogus count"); 330 return (FAILURE); 331 } 332 333 /* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */ 334 dev_info = malloc(sizeof (crypto_get_dev_info_t) + 335 sizeof (crypto_mech_name_t) * (count - 1)); 336 if (dev_info == NULL) { 337 cryptodebug("out of memory."); 338 return (FAILURE); 339 } 340 (void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN); 341 dev_info->di_dev_instance = inst_num; 342 dev_info->di_count = count; 343 344 /* Open the ioctl device */ 345 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 346 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 347 ADMIN_IOCTL_DEVICE, strerror(errno)); 348 free(dev_info); 349 return (FAILURE); 350 } 351 352 if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) { 353 cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s", 354 strerror(errno)); 355 free(dev_info); 356 (void) close(fd); 357 return (FAILURE); 358 } 359 360 if (dev_info->di_return_value != CRYPTO_SUCCESS) { 361 cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, " 362 "return_value = %d", dev_info->di_return_value); 363 free(dev_info); 364 (void) close(fd); 365 return (FAILURE); 366 } 367 368 phead = pcur = NULL; 369 rc = SUCCESS; 370 for (i = 0; i < dev_info->di_count; i++) { 371 pmech = create_mech(&dev_info->di_list[i][0]); 372 if (pmech == NULL) { 373 rc = FAILURE; 374 break; 375 } else { 376 if (phead == NULL) { 377 phead = pcur = pmech; 378 } else { 379 pcur->next = pmech; 380 pcur = pmech; 381 } 382 } 383 } 384 385 if (rc == SUCCESS) { 386 *ppmechlist = phead; 387 } else { 388 free_mechlist(phead); 389 } 390 391 free(dev_info); 392 (void) close(fd); 393 return (rc); 394 } 395 396 397 /* 398 * Get the supported mechanism list of the software provider from kernel. 399 * 400 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). 401 * If NULL, this function calls get_kcfconf_info() internally. 402 */ 403 int 404 get_soft_info(char *provname, mechlist_t **ppmechlist, 405 entrylist_t *phardlist, entrylist_t *psoftlist, 406 entrylist_t *pfipslist) 407 { 408 boolean_t in_kernel = B_FALSE; 409 crypto_get_soft_info_t *psoft_info; 410 mechlist_t *phead; 411 mechlist_t *pmech; 412 mechlist_t *pcur; 413 entry_t *pent = NULL; 414 int count; 415 int fd = -1; 416 int rc; 417 int i; 418 419 if (provname == NULL) { 420 return (FAILURE); 421 } 422 423 if (getzoneid() == GLOBAL_ZONEID) { 424 /* use kcf.conf for kernel software providers in global zone */ 425 if ((pent = getent_kef(provname, phardlist, psoftlist, 426 pfipslist)) == NULL) { 427 428 /* No kcf.conf entry for this provider */ 429 if (check_kernel_for_soft(provname, NULL, &in_kernel) 430 == FAILURE) { 431 return (FAILURE); 432 } else if (in_kernel == B_FALSE) { 433 cryptoerror(LOG_STDERR, 434 gettext("%s does not exist."), provname); 435 return (FAILURE); 436 } 437 438 /* 439 * Set mech count to 1. It will be reset to the 440 * correct value later if the setup buffer is too small. 441 */ 442 count = 1; 443 } else { 444 count = pent->sup_count; 445 free_entry(pent); 446 } 447 } else { 448 /* 449 * kcf.conf not there in non-global zone: set mech count to 1. 450 * It will be reset to the correct value later if the setup 451 * buffer is too small. 452 */ 453 count = 1; 454 } 455 456 if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) { 457 return (FAILURE); 458 } 459 460 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 461 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 462 ADMIN_IOCTL_DEVICE, strerror(errno)); 463 free(psoft_info); 464 return (FAILURE); 465 } 466 467 /* make GET_SOFT_INFO ioctl call */ 468 if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) { 469 cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s", 470 strerror(errno)); 471 (void) close(fd); 472 free(psoft_info); 473 return (FAILURE); 474 } 475 476 /* BUFFER is too small, get the number of mechanisms and retry it. */ 477 if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) { 478 count = psoft_info->si_count; 479 free(psoft_info); 480 if ((psoft_info = setup_get_soft_info(provname, count)) 481 == NULL) { 482 (void) close(fd); 483 return (FAILURE); 484 } else { 485 rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info); 486 if (rc == -1) { 487 cryptodebug("CRYPTO_GET_SOFT_INFO ioctl " 488 "failed: %s", strerror(errno)); 489 (void) close(fd); 490 free(psoft_info); 491 return (FAILURE); 492 } 493 } 494 } 495 496 (void) close(fd); 497 if (psoft_info->si_return_value != CRYPTO_SUCCESS) { 498 cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, " 499 "return_value = %d", psoft_info->si_return_value); 500 free(psoft_info); 501 return (FAILURE); 502 } 503 504 505 /* Build the mechanism linked list and return it */ 506 rc = SUCCESS; 507 phead = pcur = NULL; 508 for (i = 0; i < psoft_info->si_count; i++) { 509 pmech = create_mech(&psoft_info->si_list[i][0]); 510 if (pmech == NULL) { 511 rc = FAILURE; 512 break; 513 } else { 514 if (phead == NULL) { 515 phead = pcur = pmech; 516 } else { 517 pcur->next = pmech; 518 pcur = pmech; 519 } 520 } 521 } 522 523 if (rc == FAILURE) { 524 free_mechlist(phead); 525 } else { 526 *ppmechlist = phead; 527 } 528 529 free(psoft_info); 530 return (rc); 531 } 532 533 534 /* 535 * Get the kernel software provider list from kernel. 536 */ 537 int 538 get_soft_list(crypto_get_soft_list_t **ppsoftlist) 539 { 540 crypto_get_soft_list_t *psoftlist = NULL; 541 int count = DEFAULT_SOFT_NUM; 542 int len; 543 int fd = -1; 544 545 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 546 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 547 ADMIN_IOCTL_DEVICE, strerror(errno)); 548 return (FAILURE); 549 } 550 551 len = MAXNAMELEN * count; 552 psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); 553 if (psoftlist == NULL) { 554 cryptodebug("out of memory."); 555 (void) close(fd); 556 return (FAILURE); 557 } 558 psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); 559 psoftlist->sl_soft_count = count; 560 psoftlist->sl_soft_len = len; 561 562 if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { 563 cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s", 564 strerror(errno)); 565 free(psoftlist); 566 (void) close(fd); 567 return (FAILURE); 568 } 569 570 /* 571 * if BUFFER is too small, get the number of software providers and 572 * the minimum length needed for names and length and retry it. 573 */ 574 if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) { 575 count = psoftlist->sl_soft_count; 576 len = psoftlist->sl_soft_len; 577 free(psoftlist); 578 psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); 579 if (psoftlist == NULL) { 580 cryptodebug("out of memory."); 581 (void) close(fd); 582 return (FAILURE); 583 } 584 psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); 585 psoftlist->sl_soft_count = count; 586 psoftlist->sl_soft_len = len; 587 588 if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { 589 cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:" 590 "%s", strerror(errno)); 591 free(psoftlist); 592 (void) close(fd); 593 return (FAILURE); 594 } 595 } 596 597 if (psoftlist->sl_return_value != CRYPTO_SUCCESS) { 598 cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, " 599 "return_value = %d", psoftlist->sl_return_value); 600 free(psoftlist); 601 (void) close(fd); 602 return (FAILURE); 603 } 604 605 *ppsoftlist = psoftlist; 606 (void) close(fd); 607 return (SUCCESS); 608 } 609 610 /* 611 * Perform the FIPS related actions 612 */ 613 int 614 do_fips_actions(int action, int caller) 615 { 616 617 crypto_fips140_t fips_info; 618 int fd; 619 int rc = SUCCESS; 620 int kcf_fips_mode = 0; 621 622 /* Get FIPS-140 status from kcf.conf */ 623 fips_status_kcfconf(&kcf_fips_mode); 624 625 if (action == FIPS140_STATUS) { 626 if (kcf_fips_mode == CRYPTO_FIPS_MODE_ENABLED) 627 (void) printf(gettext( 628 "\tFIPS-140 mode is enabled.\n")); 629 else 630 (void) printf(gettext( 631 "\tFIPS-140 mode is disabled.\n")); 632 return (SUCCESS); 633 } 634 635 if (caller == NOT_REFRESH) { 636 /* Is it a duplicate operation? */ 637 if ((action == FIPS140_ENABLE) && 638 (kcf_fips_mode == CRYPTO_FIPS_MODE_ENABLED)) { 639 cryptoerror(LOG_STDERR, 640 gettext("FIPS-140 mode has already " 641 "been enabled.\n")); 642 return (FAILURE); 643 } 644 645 if ((action == FIPS140_DISABLE) && 646 (kcf_fips_mode == CRYPTO_FIPS_MODE_DISABLED)) { 647 cryptoerror(LOG_STDERR, 648 gettext("FIPS-140 mode has already " 649 "been disabled.\n")); 650 return (FAILURE); 651 } 652 653 if ((action == FIPS140_ENABLE) || (action == FIPS140_DISABLE)) { 654 /* Update kcf.conf */ 655 if ((rc = fips_update_kcfconf(action)) != SUCCESS) 656 return (rc); 657 } 658 659 /* No need to inform kernel */ 660 if (action == FIPS140_ENABLE) { 661 (void) printf(gettext( 662 "FIPS-140 mode was enabled successfully.\n")); 663 (void) printf(gettext( 664 "Warning: In this release, the Cryptographic " 665 "Framework has not been FIPS 140-2 " 666 "certified.\n\n")); 667 } else { 668 (void) printf(gettext( 669 "FIPS-140 mode was disabled successfully.\n")); 670 } 671 672 (void) printf(gettext( 673 "The FIPS-140 mode has changed.\n")); 674 (void) printf(gettext( 675 "The system will require a reboot.\n\n")); 676 return (SUCCESS); 677 678 } 679 680 /* This is refresh, need to inform kernel */ 681 (void) memset(&fips_info, 0, sizeof (crypto_fips140_t)); 682 683 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { 684 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), 685 ADMIN_IOCTL_DEVICE, strerror(errno)); 686 return (FAILURE); 687 } 688 689 switch (action) { 690 case FIPS140_ENABLE: 691 /* make CRYPTO_FIPS_SET ioctl call */ 692 fips_info.fips140_op = FIPS140_ENABLE; 693 if ((rc = ioctl(fd, CRYPTO_FIPS140_SET, &fips_info)) == -1) { 694 cryptodebug("CRYPTO_FIPS140_ENABLE ioctl failed: %s", 695 strerror(errno)); 696 rc = FAILURE; 697 goto out; 698 } 699 700 if (fips_info.fips140_return_value != CRYPTO_SUCCESS) { 701 cryptodebug("CRYPTO_FIPS140_ENABLE ioctl failed, " 702 "return_value = %d", 703 fips_info.fips140_return_value); 704 rc = FAILURE; 705 } 706 707 break; 708 709 case FIPS140_DISABLE: 710 /* make CRYPTO_FIPS140_SET ioctl call */ 711 fips_info.fips140_op = FIPS140_DISABLE; 712 if ((rc = ioctl(fd, CRYPTO_FIPS140_SET, &fips_info)) == -1) { 713 cryptodebug("CRYPTO_FIPS140_DISABLE ioctl failed: %s", 714 strerror(errno)); 715 rc = FAILURE; 716 goto out; 717 } 718 719 if (fips_info.fips140_return_value != CRYPTO_SUCCESS) { 720 cryptodebug("CRYPTO_FIPS140_DISABLE ioctl failed, " 721 "return_value = %d", 722 fips_info.fips140_return_value); 723 rc = FAILURE; 724 } 725 726 break; 727 728 default: 729 rc = FAILURE; 730 break; 731 }; 732 733 out: 734 (void) close(fd); 735 return (rc); 736 } 737