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