10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 510500SHai-May.Chao@Sun.COM * Common Development and Distribution License (the "License"). 610500SHai-May.Chao@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 2210500SHai-May.Chao@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 26991Smcpowers #include <ctype.h> 270Sstevel@tonic-gate #include <strings.h> 2810500SHai-May.Chao@Sun.COM #include <libintl.h> 2910500SHai-May.Chao@Sun.COM #include <stdio.h> 3010500SHai-May.Chao@Sun.COM #include <sys/stat.h> 310Sstevel@tonic-gate #include "cryptoadm.h" 3210500SHai-May.Chao@Sun.COM #include <cryptoutil.h> 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 350Sstevel@tonic-gate * Create one item of type mechlist_t with the mechanism name. A null is 360Sstevel@tonic-gate * returned to indicate that the storage space available is insufficient. 370Sstevel@tonic-gate */ 380Sstevel@tonic-gate mechlist_t * 390Sstevel@tonic-gate create_mech(char *name) 400Sstevel@tonic-gate { 410Sstevel@tonic-gate mechlist_t *pres = NULL; 42991Smcpowers char *first, *last; 430Sstevel@tonic-gate 440Sstevel@tonic-gate if (name == NULL) { 450Sstevel@tonic-gate return (NULL); 460Sstevel@tonic-gate } 470Sstevel@tonic-gate 480Sstevel@tonic-gate pres = malloc(sizeof (mechlist_t)); 490Sstevel@tonic-gate if (pres == NULL) { 500Sstevel@tonic-gate cryptodebug("out of memory."); 510Sstevel@tonic-gate return (NULL); 520Sstevel@tonic-gate } 530Sstevel@tonic-gate 54991Smcpowers first = name; 55991Smcpowers while (isspace(*first)) /* nuke leading whitespace */ 5610500SHai-May.Chao@Sun.COM first++; 57991Smcpowers (void) strlcpy(pres->name, first, sizeof (pres->name)); 58991Smcpowers 59991Smcpowers last = strrchr(pres->name, '\0'); 60991Smcpowers last--; 61991Smcpowers while (isspace(*last)) /* nuke trailing whitespace */ 6210500SHai-May.Chao@Sun.COM *last-- = '\0'; 63991Smcpowers 640Sstevel@tonic-gate pres->next = NULL; 650Sstevel@tonic-gate 660Sstevel@tonic-gate return (pres); 670Sstevel@tonic-gate } 680Sstevel@tonic-gate 690Sstevel@tonic-gate 700Sstevel@tonic-gate 710Sstevel@tonic-gate void 720Sstevel@tonic-gate free_mechlist(mechlist_t *plist) 730Sstevel@tonic-gate { 740Sstevel@tonic-gate mechlist_t *pnext; 750Sstevel@tonic-gate 760Sstevel@tonic-gate while (plist != NULL) { 770Sstevel@tonic-gate pnext = plist->next; 780Sstevel@tonic-gate free(plist); 790Sstevel@tonic-gate plist = pnext; 800Sstevel@tonic-gate } 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * Check if the mechanism is in the mechanism list. 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate boolean_t 890Sstevel@tonic-gate is_in_list(char *mechname, mechlist_t *plist) 900Sstevel@tonic-gate { 910Sstevel@tonic-gate boolean_t found = B_FALSE; 920Sstevel@tonic-gate 930Sstevel@tonic-gate if (mechname == NULL) { 940Sstevel@tonic-gate return (B_FALSE); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate 970Sstevel@tonic-gate while (plist != NULL) { 980Sstevel@tonic-gate if (strcmp(plist->name, mechname) == 0) { 990Sstevel@tonic-gate found = B_TRUE; 1000Sstevel@tonic-gate break; 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate plist = plist->next; 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate return (found); 1060Sstevel@tonic-gate } 10710500SHai-May.Chao@Sun.COM 10810500SHai-May.Chao@Sun.COM int 10910500SHai-May.Chao@Sun.COM update_conf(char *conf_file, char *entry) 11010500SHai-May.Chao@Sun.COM { 11110500SHai-May.Chao@Sun.COM 11210500SHai-May.Chao@Sun.COM boolean_t found; 113*10979SHai-May.Chao@Sun.COM boolean_t fips_entry = B_FALSE; 11410500SHai-May.Chao@Sun.COM FILE *pfile; 11510500SHai-May.Chao@Sun.COM FILE *pfile_tmp; 11610500SHai-May.Chao@Sun.COM char tmpfile_name[MAXPATHLEN]; 11710500SHai-May.Chao@Sun.COM char *ptr; 11810500SHai-May.Chao@Sun.COM char *name; 11910500SHai-May.Chao@Sun.COM char buffer[BUFSIZ]; 12010500SHai-May.Chao@Sun.COM char buffer2[BUFSIZ]; 12110500SHai-May.Chao@Sun.COM int found_count; 12210500SHai-May.Chao@Sun.COM int rc = SUCCESS; 12310500SHai-May.Chao@Sun.COM int err; 12410500SHai-May.Chao@Sun.COM 12510500SHai-May.Chao@Sun.COM if ((pfile = fopen(conf_file, "r+")) == NULL) { 12610500SHai-May.Chao@Sun.COM err = errno; 12710500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, 12810500SHai-May.Chao@Sun.COM gettext("failed to update the configuration - %s"), 12910500SHai-May.Chao@Sun.COM strerror(err)); 13010500SHai-May.Chao@Sun.COM cryptodebug("failed to open %s for write.", conf_file); 13110500SHai-May.Chao@Sun.COM return (FAILURE); 13210500SHai-May.Chao@Sun.COM } 13310500SHai-May.Chao@Sun.COM 13410500SHai-May.Chao@Sun.COM if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { 13510500SHai-May.Chao@Sun.COM err = errno; 13610500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, 13710500SHai-May.Chao@Sun.COM gettext("failed to lock the configuration - %s"), 13810500SHai-May.Chao@Sun.COM strerror(err)); 13910500SHai-May.Chao@Sun.COM (void) fclose(pfile); 14010500SHai-May.Chao@Sun.COM return (FAILURE); 14110500SHai-May.Chao@Sun.COM } 14210500SHai-May.Chao@Sun.COM 14310500SHai-May.Chao@Sun.COM /* 14410500SHai-May.Chao@Sun.COM * Create a temporary file in the /etc/crypto directory. 14510500SHai-May.Chao@Sun.COM */ 14610500SHai-May.Chao@Sun.COM (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); 14710500SHai-May.Chao@Sun.COM if (mkstemp(tmpfile_name) == -1) { 14810500SHai-May.Chao@Sun.COM err = errno; 14910500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, 15010500SHai-May.Chao@Sun.COM gettext("failed to create a temporary file - %s"), 15110500SHai-May.Chao@Sun.COM strerror(err)); 15210500SHai-May.Chao@Sun.COM (void) fclose(pfile); 15310500SHai-May.Chao@Sun.COM return (FAILURE); 15410500SHai-May.Chao@Sun.COM } 15510500SHai-May.Chao@Sun.COM 15610500SHai-May.Chao@Sun.COM if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { 15710500SHai-May.Chao@Sun.COM err = errno; 15810500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), 15910500SHai-May.Chao@Sun.COM tmpfile_name, strerror(err)); 16010500SHai-May.Chao@Sun.COM (void) fclose(pfile); 16110500SHai-May.Chao@Sun.COM return (FAILURE); 16210500SHai-May.Chao@Sun.COM } 16310500SHai-May.Chao@Sun.COM 16410500SHai-May.Chao@Sun.COM 16510500SHai-May.Chao@Sun.COM /* 16610500SHai-May.Chao@Sun.COM * Loop thru the config file. If the provider was reserved within a 16710500SHai-May.Chao@Sun.COM * package bracket, just uncomment it. Otherwise, append it at 16810500SHai-May.Chao@Sun.COM * the end. The resulting file will be saved in the temp file first. 16910500SHai-May.Chao@Sun.COM */ 17010500SHai-May.Chao@Sun.COM found_count = 0; 17110500SHai-May.Chao@Sun.COM rc = SUCCESS; 17210500SHai-May.Chao@Sun.COM 17310500SHai-May.Chao@Sun.COM while (fgets(buffer, BUFSIZ, pfile) != NULL) { 17410500SHai-May.Chao@Sun.COM found = B_FALSE; 17510500SHai-May.Chao@Sun.COM if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { 17610500SHai-May.Chao@Sun.COM if (buffer[0] == '#') { 17710500SHai-May.Chao@Sun.COM ptr = buffer; 17810500SHai-May.Chao@Sun.COM ptr++; 17910500SHai-May.Chao@Sun.COM if (strcmp(entry, ptr) == 0) { 18010500SHai-May.Chao@Sun.COM found = B_TRUE; 18110500SHai-May.Chao@Sun.COM found_count++; 18210500SHai-May.Chao@Sun.COM } 183*10979SHai-May.Chao@Sun.COM } else { 184*10979SHai-May.Chao@Sun.COM (void) strlcpy(buffer2, buffer, BUFSIZ); 185*10979SHai-May.Chao@Sun.COM ptr = buffer2; 186*10979SHai-May.Chao@Sun.COM if ((name = strtok(ptr, SEP_COLON)) == NULL) { 187*10979SHai-May.Chao@Sun.COM rc = FAILURE; 188*10979SHai-May.Chao@Sun.COM break; 189*10979SHai-May.Chao@Sun.COM } else if (strcmp(FIPS_KEYWORD, name) == 0) { 190*10979SHai-May.Chao@Sun.COM found = B_TRUE; 191*10979SHai-May.Chao@Sun.COM found_count++; 192*10979SHai-May.Chao@Sun.COM fips_entry = B_TRUE; 193*10979SHai-May.Chao@Sun.COM } 19410500SHai-May.Chao@Sun.COM } 19510500SHai-May.Chao@Sun.COM } else { /* _PATH_KCF_CONF */ 19610500SHai-May.Chao@Sun.COM if (buffer[0] == '#') { 19710500SHai-May.Chao@Sun.COM (void) strlcpy(buffer2, buffer, BUFSIZ); 19810500SHai-May.Chao@Sun.COM ptr = buffer2; 19910500SHai-May.Chao@Sun.COM ptr++; /* skip # */ 20010500SHai-May.Chao@Sun.COM if ((name = strtok(ptr, SEP_COLON)) == NULL) { 20110500SHai-May.Chao@Sun.COM rc = FAILURE; 20210500SHai-May.Chao@Sun.COM break; 20310500SHai-May.Chao@Sun.COM } 20410500SHai-May.Chao@Sun.COM } else { 20510500SHai-May.Chao@Sun.COM (void) strlcpy(buffer2, buffer, BUFSIZ); 20610500SHai-May.Chao@Sun.COM ptr = buffer2; 20710500SHai-May.Chao@Sun.COM if ((name = strtok(ptr, SEP_COLON)) == NULL) { 20810500SHai-May.Chao@Sun.COM rc = FAILURE; 20910500SHai-May.Chao@Sun.COM break; 21010500SHai-May.Chao@Sun.COM } 21110500SHai-May.Chao@Sun.COM } 21210500SHai-May.Chao@Sun.COM } 21310500SHai-May.Chao@Sun.COM 21410500SHai-May.Chao@Sun.COM if (found == B_FALSE) { 21510500SHai-May.Chao@Sun.COM if (fputs(buffer, pfile_tmp) == EOF) { 21610500SHai-May.Chao@Sun.COM rc = FAILURE; 21710500SHai-May.Chao@Sun.COM } 21810500SHai-May.Chao@Sun.COM } else { 21910500SHai-May.Chao@Sun.COM if (found_count == 1) { 22010500SHai-May.Chao@Sun.COM if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { 221*10979SHai-May.Chao@Sun.COM if (fips_entry == B_TRUE) { 222*10979SHai-May.Chao@Sun.COM if (fputs(entry, pfile_tmp) == 223*10979SHai-May.Chao@Sun.COM EOF) { 224*10979SHai-May.Chao@Sun.COM rc = FAILURE; 225*10979SHai-May.Chao@Sun.COM } 226*10979SHai-May.Chao@Sun.COM fips_entry = B_FALSE; 227*10979SHai-May.Chao@Sun.COM } else { 228*10979SHai-May.Chao@Sun.COM if (fputs(ptr, pfile_tmp) == 229*10979SHai-May.Chao@Sun.COM EOF) { 230*10979SHai-May.Chao@Sun.COM rc = FAILURE; 231*10979SHai-May.Chao@Sun.COM } 23210500SHai-May.Chao@Sun.COM } 23310500SHai-May.Chao@Sun.COM } else { 23410500SHai-May.Chao@Sun.COM if (fputs(entry, pfile_tmp) == EOF) { 23510500SHai-May.Chao@Sun.COM rc = FAILURE; 23610500SHai-May.Chao@Sun.COM } 23710500SHai-May.Chao@Sun.COM } 23810500SHai-May.Chao@Sun.COM } else { 23910500SHai-May.Chao@Sun.COM /* 24010500SHai-May.Chao@Sun.COM * Found a second entry with same tag name. 24110500SHai-May.Chao@Sun.COM * Should not happen. The config file 24210500SHai-May.Chao@Sun.COM * is corrupted. Give a warning and skip 24310500SHai-May.Chao@Sun.COM * this entry. 24410500SHai-May.Chao@Sun.COM */ 24510500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext( 24610500SHai-May.Chao@Sun.COM "(Warning) Found an additional reserved " 24710500SHai-May.Chao@Sun.COM "entry for %s."), entry); 24810500SHai-May.Chao@Sun.COM } 24910500SHai-May.Chao@Sun.COM } 25010500SHai-May.Chao@Sun.COM 25110500SHai-May.Chao@Sun.COM if (rc == FAILURE) { 25210500SHai-May.Chao@Sun.COM break; 25310500SHai-May.Chao@Sun.COM } 25410500SHai-May.Chao@Sun.COM } 25510500SHai-May.Chao@Sun.COM 25610500SHai-May.Chao@Sun.COM (void) fclose(pfile); 25710500SHai-May.Chao@Sun.COM 25810500SHai-May.Chao@Sun.COM if (rc == FAILURE) { 25910500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext("write error.")); 26010500SHai-May.Chao@Sun.COM (void) fclose(pfile_tmp); 26110500SHai-May.Chao@Sun.COM if (unlink(tmpfile_name) != 0) { 26210500SHai-May.Chao@Sun.COM err = errno; 26310500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext( 26410500SHai-May.Chao@Sun.COM "(Warning) failed to remove %s: %s"), tmpfile_name, 26510500SHai-May.Chao@Sun.COM strerror(err)); 26610500SHai-May.Chao@Sun.COM } 26710500SHai-May.Chao@Sun.COM return (FAILURE); 26810500SHai-May.Chao@Sun.COM } 26910500SHai-May.Chao@Sun.COM 27010500SHai-May.Chao@Sun.COM if (found_count == 0) { 27110500SHai-May.Chao@Sun.COM /* 27210500SHai-May.Chao@Sun.COM * The entry was not in config file before, append it to the 27310500SHai-May.Chao@Sun.COM * end of the temp file. 27410500SHai-May.Chao@Sun.COM */ 27510500SHai-May.Chao@Sun.COM if (fputs(entry, pfile_tmp) == EOF) { 27610500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext( 27710500SHai-May.Chao@Sun.COM "failed to write to %s: %s"), tmpfile_name, 27810500SHai-May.Chao@Sun.COM strerror(errno)); 27910500SHai-May.Chao@Sun.COM (void) fclose(pfile_tmp); 28010500SHai-May.Chao@Sun.COM if (unlink(tmpfile_name) != 0) { 28110500SHai-May.Chao@Sun.COM err = errno; 28210500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext( 28310500SHai-May.Chao@Sun.COM "(Warning) failed to remove %s: %s"), 28410500SHai-May.Chao@Sun.COM tmpfile_name, strerror(err)); 28510500SHai-May.Chao@Sun.COM } 28610500SHai-May.Chao@Sun.COM return (FAILURE); 28710500SHai-May.Chao@Sun.COM } 28810500SHai-May.Chao@Sun.COM } 28910500SHai-May.Chao@Sun.COM 29010500SHai-May.Chao@Sun.COM if (fclose(pfile_tmp) != 0) { 29110500SHai-May.Chao@Sun.COM err = errno; 29210500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, 29310500SHai-May.Chao@Sun.COM gettext("failed to close %s: %s"), tmpfile_name, 29410500SHai-May.Chao@Sun.COM strerror(err)); 29510500SHai-May.Chao@Sun.COM return (FAILURE); 29610500SHai-May.Chao@Sun.COM } 29710500SHai-May.Chao@Sun.COM 29810500SHai-May.Chao@Sun.COM if (rename(tmpfile_name, conf_file) == -1) { 29910500SHai-May.Chao@Sun.COM err = errno; 30010500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, 30110500SHai-May.Chao@Sun.COM gettext("failed to update the configuration - %s"), 30210500SHai-May.Chao@Sun.COM strerror(err)); 30310500SHai-May.Chao@Sun.COM cryptodebug("failed to rename %s to %s: %s", tmpfile_name, 30410500SHai-May.Chao@Sun.COM conf_file, strerror(err)); 30510500SHai-May.Chao@Sun.COM rc = FAILURE; 30610500SHai-May.Chao@Sun.COM } else if (chmod(conf_file, 30710500SHai-May.Chao@Sun.COM S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 30810500SHai-May.Chao@Sun.COM err = errno; 30910500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, 31010500SHai-May.Chao@Sun.COM gettext("failed to update the configuration - %s"), 31110500SHai-May.Chao@Sun.COM strerror(err)); 31210500SHai-May.Chao@Sun.COM cryptodebug("failed to chmod to %s: %s", conf_file, 31310500SHai-May.Chao@Sun.COM strerror(err)); 31410500SHai-May.Chao@Sun.COM rc = FAILURE; 31510500SHai-May.Chao@Sun.COM } else { 31610500SHai-May.Chao@Sun.COM rc = SUCCESS; 31710500SHai-May.Chao@Sun.COM } 31810500SHai-May.Chao@Sun.COM 31910500SHai-May.Chao@Sun.COM if (rc == FAILURE) { 32010500SHai-May.Chao@Sun.COM if (unlink(tmpfile_name) != 0) { 32110500SHai-May.Chao@Sun.COM err = errno; 32210500SHai-May.Chao@Sun.COM cryptoerror(LOG_STDERR, gettext( 32310500SHai-May.Chao@Sun.COM "(Warning) failed to remove %s: %s"), 32410500SHai-May.Chao@Sun.COM tmpfile_name, strerror(err)); 32510500SHai-May.Chao@Sun.COM } 32610500SHai-May.Chao@Sun.COM } 32710500SHai-May.Chao@Sun.COM 32810500SHai-May.Chao@Sun.COM return (rc); 32910500SHai-May.Chao@Sun.COM 33010500SHai-May.Chao@Sun.COM } 331