17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b5a2d845SHai-May Chao  * Common Development and Distribution License (the "License").
6b5a2d845SHai-May Chao  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22b5a2d845SHai-May Chao  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26bbbb143bSmcpowers #include <ctype.h>
277c478bd9Sstevel@tonic-gate #include <strings.h>
28b5a2d845SHai-May Chao #include <libintl.h>
29b5a2d845SHai-May Chao #include <stdio.h>
30b5a2d845SHai-May Chao #include <sys/stat.h>
317c478bd9Sstevel@tonic-gate #include "cryptoadm.h"
32b5a2d845SHai-May Chao #include <cryptoutil.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Create one item of type mechlist_t with the mechanism name.  A null is
367c478bd9Sstevel@tonic-gate  * returned to indicate that the storage space available is insufficient.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate mechlist_t *
create_mech(char * name)397c478bd9Sstevel@tonic-gate create_mech(char *name)
407c478bd9Sstevel@tonic-gate {
417c478bd9Sstevel@tonic-gate 	mechlist_t *pres = NULL;
42bbbb143bSmcpowers 	char *first, *last;
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate 	if (name == NULL) {
457c478bd9Sstevel@tonic-gate 		return (NULL);
467c478bd9Sstevel@tonic-gate 	}
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 	pres = malloc(sizeof (mechlist_t));
497c478bd9Sstevel@tonic-gate 	if (pres == NULL) {
507c478bd9Sstevel@tonic-gate 		cryptodebug("out of memory.");
517c478bd9Sstevel@tonic-gate 		return (NULL);
527c478bd9Sstevel@tonic-gate 	}
537c478bd9Sstevel@tonic-gate 
54bbbb143bSmcpowers 	first = name;
55bbbb143bSmcpowers 	while (isspace(*first)) /* nuke leading whitespace */
56b5a2d845SHai-May Chao 		first++;
57bbbb143bSmcpowers 	(void) strlcpy(pres->name, first, sizeof (pres->name));
58bbbb143bSmcpowers 
59bbbb143bSmcpowers 	last = strrchr(pres->name, '\0');
60bbbb143bSmcpowers 	last--;
61bbbb143bSmcpowers 	while (isspace(*last))  /* nuke trailing whitespace */
62b5a2d845SHai-May Chao 		*last-- = '\0';
63bbbb143bSmcpowers 
647c478bd9Sstevel@tonic-gate 	pres->next = NULL;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	return (pres);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate void
free_mechlist(mechlist_t * plist)727c478bd9Sstevel@tonic-gate free_mechlist(mechlist_t *plist)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	mechlist_t *pnext;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	while (plist != NULL) {
777c478bd9Sstevel@tonic-gate 		pnext = plist->next;
787c478bd9Sstevel@tonic-gate 		free(plist);
797c478bd9Sstevel@tonic-gate 		plist = pnext;
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Check if the mechanism is in the mechanism list.
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate boolean_t
is_in_list(char * mechname,mechlist_t * plist)897c478bd9Sstevel@tonic-gate is_in_list(char *mechname, mechlist_t *plist)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	boolean_t found = B_FALSE;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if (mechname == NULL) {
947c478bd9Sstevel@tonic-gate 		return (B_FALSE);
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	while (plist != NULL) {
987c478bd9Sstevel@tonic-gate 		if (strcmp(plist->name, mechname) == 0) {
997c478bd9Sstevel@tonic-gate 			found = B_TRUE;
1007c478bd9Sstevel@tonic-gate 			break;
1017c478bd9Sstevel@tonic-gate 		}
1027c478bd9Sstevel@tonic-gate 		plist = plist->next;
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	return (found);
1067c478bd9Sstevel@tonic-gate }
107b5a2d845SHai-May Chao 
108b5a2d845SHai-May Chao int
update_conf(char * conf_file,char * entry)109b5a2d845SHai-May Chao update_conf(char *conf_file, char *entry)
110b5a2d845SHai-May Chao {
111b5a2d845SHai-May Chao 
112b5a2d845SHai-May Chao 	boolean_t	found;
113*d616ad8eSHai-May Chao 	boolean_t	fips_entry = B_FALSE;
114b5a2d845SHai-May Chao 	FILE	*pfile;
115b5a2d845SHai-May Chao 	FILE	*pfile_tmp;
116b5a2d845SHai-May Chao 	char	tmpfile_name[MAXPATHLEN];
117b5a2d845SHai-May Chao 	char	*ptr;
118b5a2d845SHai-May Chao 	char	*name;
119b5a2d845SHai-May Chao 	char	buffer[BUFSIZ];
120b5a2d845SHai-May Chao 	char	buffer2[BUFSIZ];
121b5a2d845SHai-May Chao 	int		found_count;
122b5a2d845SHai-May Chao 	int		rc = SUCCESS;
123b5a2d845SHai-May Chao 	int		err;
124b5a2d845SHai-May Chao 
125b5a2d845SHai-May Chao 	if ((pfile = fopen(conf_file, "r+")) == NULL) {
126b5a2d845SHai-May Chao 		err = errno;
127b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR,
128b5a2d845SHai-May Chao 		    gettext("failed to update the configuration - %s"),
129b5a2d845SHai-May Chao 		    strerror(err));
130b5a2d845SHai-May Chao 		cryptodebug("failed to open %s for write.", conf_file);
131b5a2d845SHai-May Chao 		return (FAILURE);
132b5a2d845SHai-May Chao 	}
133b5a2d845SHai-May Chao 
134b5a2d845SHai-May Chao 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
135b5a2d845SHai-May Chao 		err = errno;
136b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR,
137b5a2d845SHai-May Chao 		    gettext("failed to lock the configuration - %s"),
138b5a2d845SHai-May Chao 		    strerror(err));
139b5a2d845SHai-May Chao 		(void) fclose(pfile);
140b5a2d845SHai-May Chao 		return (FAILURE);
141b5a2d845SHai-May Chao 	}
142b5a2d845SHai-May Chao 
143b5a2d845SHai-May Chao 	/*
144b5a2d845SHai-May Chao 	 * Create a temporary file in the /etc/crypto directory.
145b5a2d845SHai-May Chao 	 */
146b5a2d845SHai-May Chao 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
147b5a2d845SHai-May Chao 	if (mkstemp(tmpfile_name) == -1) {
148b5a2d845SHai-May Chao 		err = errno;
149b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR,
150b5a2d845SHai-May Chao 		    gettext("failed to create a temporary file - %s"),
151b5a2d845SHai-May Chao 		    strerror(err));
152b5a2d845SHai-May Chao 		(void) fclose(pfile);
153b5a2d845SHai-May Chao 		return (FAILURE);
154b5a2d845SHai-May Chao 	}
155b5a2d845SHai-May Chao 
156b5a2d845SHai-May Chao 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
157b5a2d845SHai-May Chao 		err = errno;
158b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
159b5a2d845SHai-May Chao 		    tmpfile_name, strerror(err));
160b5a2d845SHai-May Chao 		(void) fclose(pfile);
161b5a2d845SHai-May Chao 		return (FAILURE);
162b5a2d845SHai-May Chao 	}
163b5a2d845SHai-May Chao 
164b5a2d845SHai-May Chao 
165b5a2d845SHai-May Chao 	/*
166b5a2d845SHai-May Chao 	 * Loop thru the config file. If the provider was reserved within a
167b5a2d845SHai-May Chao 	 * package bracket, just uncomment it.  Otherwise, append it at
168b5a2d845SHai-May Chao 	 * the end.  The resulting file will be saved in the temp file first.
169b5a2d845SHai-May Chao 	 */
170b5a2d845SHai-May Chao 	found_count = 0;
171b5a2d845SHai-May Chao 	rc = SUCCESS;
172b5a2d845SHai-May Chao 
173b5a2d845SHai-May Chao 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
174b5a2d845SHai-May Chao 		found = B_FALSE;
175b5a2d845SHai-May Chao 		if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) {
176b5a2d845SHai-May Chao 			if (buffer[0] == '#') {
177b5a2d845SHai-May Chao 				ptr = buffer;
178b5a2d845SHai-May Chao 				ptr++;
179b5a2d845SHai-May Chao 				if (strcmp(entry, ptr) == 0) {
180b5a2d845SHai-May Chao 					found = B_TRUE;
181b5a2d845SHai-May Chao 					found_count++;
182b5a2d845SHai-May Chao 				}
183*d616ad8eSHai-May Chao 			} else {
184*d616ad8eSHai-May Chao 				(void) strlcpy(buffer2, buffer, BUFSIZ);
185*d616ad8eSHai-May Chao 				ptr = buffer2;
186*d616ad8eSHai-May Chao 				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
187*d616ad8eSHai-May Chao 					rc = FAILURE;
188*d616ad8eSHai-May Chao 					break;
189*d616ad8eSHai-May Chao 				} else if (strcmp(FIPS_KEYWORD, name) == 0) {
190*d616ad8eSHai-May Chao 					found = B_TRUE;
191*d616ad8eSHai-May Chao 					found_count++;
192*d616ad8eSHai-May Chao 					fips_entry = B_TRUE;
193*d616ad8eSHai-May Chao 				}
194b5a2d845SHai-May Chao 			}
195b5a2d845SHai-May Chao 		} else { /* _PATH_KCF_CONF */
196b5a2d845SHai-May Chao 			if (buffer[0] == '#') {
197b5a2d845SHai-May Chao 				(void) strlcpy(buffer2, buffer, BUFSIZ);
198b5a2d845SHai-May Chao 				ptr = buffer2;
199b5a2d845SHai-May Chao 				ptr++; /* skip # */
200b5a2d845SHai-May Chao 				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
201b5a2d845SHai-May Chao 					rc = FAILURE;
202b5a2d845SHai-May Chao 					break;
203b5a2d845SHai-May Chao 				}
204b5a2d845SHai-May Chao 			} else {
205b5a2d845SHai-May Chao 				(void) strlcpy(buffer2, buffer, BUFSIZ);
206b5a2d845SHai-May Chao 				ptr = buffer2;
207b5a2d845SHai-May Chao 				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
208b5a2d845SHai-May Chao 					rc = FAILURE;
209b5a2d845SHai-May Chao 					break;
210b5a2d845SHai-May Chao 				}
211b5a2d845SHai-May Chao 			}
212b5a2d845SHai-May Chao 		}
213b5a2d845SHai-May Chao 
214b5a2d845SHai-May Chao 		if (found == B_FALSE) {
215b5a2d845SHai-May Chao 			if (fputs(buffer, pfile_tmp) == EOF) {
216b5a2d845SHai-May Chao 				rc = FAILURE;
217b5a2d845SHai-May Chao 			}
218b5a2d845SHai-May Chao 		} else {
219b5a2d845SHai-May Chao 			if (found_count == 1) {
220b5a2d845SHai-May Chao 				if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) {
221*d616ad8eSHai-May Chao 					if (fips_entry == B_TRUE) {
222*d616ad8eSHai-May Chao 						if (fputs(entry, pfile_tmp) ==
223*d616ad8eSHai-May Chao 						    EOF) {
224*d616ad8eSHai-May Chao 							rc = FAILURE;
225*d616ad8eSHai-May Chao 						}
226*d616ad8eSHai-May Chao 						fips_entry = B_FALSE;
227*d616ad8eSHai-May Chao 					} else {
228*d616ad8eSHai-May Chao 						if (fputs(ptr, pfile_tmp) ==
229*d616ad8eSHai-May Chao 						    EOF) {
230*d616ad8eSHai-May Chao 							rc = FAILURE;
231*d616ad8eSHai-May Chao 						}
232b5a2d845SHai-May Chao 					}
233b5a2d845SHai-May Chao 				} else {
234b5a2d845SHai-May Chao 					if (fputs(entry, pfile_tmp) == EOF) {
235b5a2d845SHai-May Chao 						rc = FAILURE;
236b5a2d845SHai-May Chao 					}
237b5a2d845SHai-May Chao 				}
238b5a2d845SHai-May Chao 			} else {
239b5a2d845SHai-May Chao 				/*
240b5a2d845SHai-May Chao 				 * Found a second entry with same tag name.
241b5a2d845SHai-May Chao 				 * Should not happen. The config file
242b5a2d845SHai-May Chao 				 * is corrupted. Give a warning and skip
243b5a2d845SHai-May Chao 				 * this entry.
244b5a2d845SHai-May Chao 				 */
245b5a2d845SHai-May Chao 				cryptoerror(LOG_STDERR, gettext(
246b5a2d845SHai-May Chao 				    "(Warning) Found an additional reserved "
247b5a2d845SHai-May Chao 				    "entry for %s."), entry);
248b5a2d845SHai-May Chao 			}
249b5a2d845SHai-May Chao 		}
250b5a2d845SHai-May Chao 
251b5a2d845SHai-May Chao 		if (rc == FAILURE) {
252b5a2d845SHai-May Chao 			break;
253b5a2d845SHai-May Chao 		}
254b5a2d845SHai-May Chao 	}
255b5a2d845SHai-May Chao 
256b5a2d845SHai-May Chao 	(void) fclose(pfile);
257b5a2d845SHai-May Chao 
258b5a2d845SHai-May Chao 	if (rc == FAILURE) {
259b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR, gettext("write error."));
260b5a2d845SHai-May Chao 		(void) fclose(pfile_tmp);
261b5a2d845SHai-May Chao 		if (unlink(tmpfile_name) != 0) {
262b5a2d845SHai-May Chao 			err = errno;
263b5a2d845SHai-May Chao 			cryptoerror(LOG_STDERR, gettext(
264b5a2d845SHai-May Chao 			    "(Warning) failed to remove %s: %s"), tmpfile_name,
265b5a2d845SHai-May Chao 			    strerror(err));
266b5a2d845SHai-May Chao 		}
267b5a2d845SHai-May Chao 		return (FAILURE);
268b5a2d845SHai-May Chao 	}
269b5a2d845SHai-May Chao 
270b5a2d845SHai-May Chao 	if (found_count == 0) {
271b5a2d845SHai-May Chao 		/*
272b5a2d845SHai-May Chao 		 * The entry was not in config file before, append it to the
273b5a2d845SHai-May Chao 		 * end of the temp file.
274b5a2d845SHai-May Chao 		 */
275b5a2d845SHai-May Chao 		if (fputs(entry, pfile_tmp) == EOF) {
276b5a2d845SHai-May Chao 			cryptoerror(LOG_STDERR, gettext(
277b5a2d845SHai-May Chao 			    "failed to write to %s: %s"), tmpfile_name,
278b5a2d845SHai-May Chao 			    strerror(errno));
279b5a2d845SHai-May Chao 			(void) fclose(pfile_tmp);
280b5a2d845SHai-May Chao 			if (unlink(tmpfile_name) != 0) {
281b5a2d845SHai-May Chao 				err = errno;
282b5a2d845SHai-May Chao 				cryptoerror(LOG_STDERR, gettext(
283b5a2d845SHai-May Chao 				    "(Warning) failed to remove %s: %s"),
284b5a2d845SHai-May Chao 				    tmpfile_name, strerror(err));
285b5a2d845SHai-May Chao 			}
286b5a2d845SHai-May Chao 			return (FAILURE);
287b5a2d845SHai-May Chao 		}
288b5a2d845SHai-May Chao 	}
289b5a2d845SHai-May Chao 
290b5a2d845SHai-May Chao 	if (fclose(pfile_tmp) != 0) {
291b5a2d845SHai-May Chao 		err = errno;
292b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR,
293b5a2d845SHai-May Chao 		    gettext("failed to close %s: %s"), tmpfile_name,
294b5a2d845SHai-May Chao 		    strerror(err));
295b5a2d845SHai-May Chao 		return (FAILURE);
296b5a2d845SHai-May Chao 	}
297b5a2d845SHai-May Chao 
298b5a2d845SHai-May Chao 	if (rename(tmpfile_name, conf_file) == -1) {
299b5a2d845SHai-May Chao 		err = errno;
300b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR,
301b5a2d845SHai-May Chao 		    gettext("failed to update the configuration - %s"),
302b5a2d845SHai-May Chao 		    strerror(err));
303b5a2d845SHai-May Chao 		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
304b5a2d845SHai-May Chao 		    conf_file, strerror(err));
305b5a2d845SHai-May Chao 		rc = FAILURE;
306b5a2d845SHai-May Chao 	} else if (chmod(conf_file,
307b5a2d845SHai-May Chao 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
308b5a2d845SHai-May Chao 		err = errno;
309b5a2d845SHai-May Chao 		cryptoerror(LOG_STDERR,
310b5a2d845SHai-May Chao 		    gettext("failed to update the configuration - %s"),
311b5a2d845SHai-May Chao 		    strerror(err));
312b5a2d845SHai-May Chao 		cryptodebug("failed to chmod to %s: %s", conf_file,
313b5a2d845SHai-May Chao 		    strerror(err));
314b5a2d845SHai-May Chao 		rc = FAILURE;
315b5a2d845SHai-May Chao 	} else {
316b5a2d845SHai-May Chao 		rc = SUCCESS;
317b5a2d845SHai-May Chao 	}
318b5a2d845SHai-May Chao 
319b5a2d845SHai-May Chao 	if (rc == FAILURE) {
320b5a2d845SHai-May Chao 		if (unlink(tmpfile_name) != 0) {
321b5a2d845SHai-May Chao 			err = errno;
322b5a2d845SHai-May Chao 			cryptoerror(LOG_STDERR, gettext(
323b5a2d845SHai-May Chao 			    "(Warning) failed to remove %s: %s"),
324b5a2d845SHai-May Chao 			    tmpfile_name, strerror(err));
325b5a2d845SHai-May Chao 		}
326b5a2d845SHai-May Chao 	}
327b5a2d845SHai-May Chao 
328b5a2d845SHai-May Chao 	return (rc);
329b5a2d845SHai-May Chao 
330b5a2d845SHai-May Chao }
331