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
5*10500SHai-May.Chao@Sun.COM  * Common Development and Distribution License (the "License").
6*10500SHai-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 /*
22*10500SHai-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>
28*10500SHai-May.Chao@Sun.COM #include <libintl.h>
29*10500SHai-May.Chao@Sun.COM #include <stdio.h>
30*10500SHai-May.Chao@Sun.COM #include <sys/stat.h>
310Sstevel@tonic-gate #include "cryptoadm.h"
32*10500SHai-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 */
56*10500SHai-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 */
62*10500SHai-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 }
107*10500SHai-May.Chao@Sun.COM 
108*10500SHai-May.Chao@Sun.COM int
109*10500SHai-May.Chao@Sun.COM update_conf(char *conf_file, char *entry)
110*10500SHai-May.Chao@Sun.COM {
111*10500SHai-May.Chao@Sun.COM 
112*10500SHai-May.Chao@Sun.COM 	boolean_t	found;
113*10500SHai-May.Chao@Sun.COM 	FILE	*pfile;
114*10500SHai-May.Chao@Sun.COM 	FILE	*pfile_tmp;
115*10500SHai-May.Chao@Sun.COM 	char	tmpfile_name[MAXPATHLEN];
116*10500SHai-May.Chao@Sun.COM 	char	*ptr;
117*10500SHai-May.Chao@Sun.COM 	char	*name;
118*10500SHai-May.Chao@Sun.COM 	char	buffer[BUFSIZ];
119*10500SHai-May.Chao@Sun.COM 	char	buffer2[BUFSIZ];
120*10500SHai-May.Chao@Sun.COM 	int		found_count;
121*10500SHai-May.Chao@Sun.COM 	int		rc = SUCCESS;
122*10500SHai-May.Chao@Sun.COM 	int		err;
123*10500SHai-May.Chao@Sun.COM 
124*10500SHai-May.Chao@Sun.COM 	if ((pfile = fopen(conf_file, "r+")) == NULL) {
125*10500SHai-May.Chao@Sun.COM 		err = errno;
126*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR,
127*10500SHai-May.Chao@Sun.COM 		    gettext("failed to update the configuration - %s"),
128*10500SHai-May.Chao@Sun.COM 		    strerror(err));
129*10500SHai-May.Chao@Sun.COM 		cryptodebug("failed to open %s for write.", conf_file);
130*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
131*10500SHai-May.Chao@Sun.COM 	}
132*10500SHai-May.Chao@Sun.COM 
133*10500SHai-May.Chao@Sun.COM 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
134*10500SHai-May.Chao@Sun.COM 		err = errno;
135*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR,
136*10500SHai-May.Chao@Sun.COM 		    gettext("failed to lock the configuration - %s"),
137*10500SHai-May.Chao@Sun.COM 		    strerror(err));
138*10500SHai-May.Chao@Sun.COM 		(void) fclose(pfile);
139*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
140*10500SHai-May.Chao@Sun.COM 	}
141*10500SHai-May.Chao@Sun.COM 
142*10500SHai-May.Chao@Sun.COM 	/*
143*10500SHai-May.Chao@Sun.COM 	 * Create a temporary file in the /etc/crypto directory.
144*10500SHai-May.Chao@Sun.COM 	 */
145*10500SHai-May.Chao@Sun.COM 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
146*10500SHai-May.Chao@Sun.COM 	if (mkstemp(tmpfile_name) == -1) {
147*10500SHai-May.Chao@Sun.COM 		err = errno;
148*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR,
149*10500SHai-May.Chao@Sun.COM 		    gettext("failed to create a temporary file - %s"),
150*10500SHai-May.Chao@Sun.COM 		    strerror(err));
151*10500SHai-May.Chao@Sun.COM 		(void) fclose(pfile);
152*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
153*10500SHai-May.Chao@Sun.COM 	}
154*10500SHai-May.Chao@Sun.COM 
155*10500SHai-May.Chao@Sun.COM 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
156*10500SHai-May.Chao@Sun.COM 		err = errno;
157*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
158*10500SHai-May.Chao@Sun.COM 		    tmpfile_name, strerror(err));
159*10500SHai-May.Chao@Sun.COM 		(void) fclose(pfile);
160*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
161*10500SHai-May.Chao@Sun.COM 	}
162*10500SHai-May.Chao@Sun.COM 
163*10500SHai-May.Chao@Sun.COM 
164*10500SHai-May.Chao@Sun.COM 	/*
165*10500SHai-May.Chao@Sun.COM 	 * Loop thru the config file. If the provider was reserved within a
166*10500SHai-May.Chao@Sun.COM 	 * package bracket, just uncomment it.  Otherwise, append it at
167*10500SHai-May.Chao@Sun.COM 	 * the end.  The resulting file will be saved in the temp file first.
168*10500SHai-May.Chao@Sun.COM 	 */
169*10500SHai-May.Chao@Sun.COM 	found_count = 0;
170*10500SHai-May.Chao@Sun.COM 	rc = SUCCESS;
171*10500SHai-May.Chao@Sun.COM 
172*10500SHai-May.Chao@Sun.COM 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
173*10500SHai-May.Chao@Sun.COM 		found = B_FALSE;
174*10500SHai-May.Chao@Sun.COM 		if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) {
175*10500SHai-May.Chao@Sun.COM 			if (buffer[0] == '#') {
176*10500SHai-May.Chao@Sun.COM 				ptr = buffer;
177*10500SHai-May.Chao@Sun.COM 				ptr++;
178*10500SHai-May.Chao@Sun.COM 				if (strcmp(entry, ptr) == 0) {
179*10500SHai-May.Chao@Sun.COM 					found = B_TRUE;
180*10500SHai-May.Chao@Sun.COM 					found_count++;
181*10500SHai-May.Chao@Sun.COM 				}
182*10500SHai-May.Chao@Sun.COM 			}
183*10500SHai-May.Chao@Sun.COM 		} else { /* _PATH_KCF_CONF */
184*10500SHai-May.Chao@Sun.COM 			if (buffer[0] == '#') {
185*10500SHai-May.Chao@Sun.COM 				(void) strlcpy(buffer2, buffer, BUFSIZ);
186*10500SHai-May.Chao@Sun.COM 				ptr = buffer2;
187*10500SHai-May.Chao@Sun.COM 				ptr++; /* skip # */
188*10500SHai-May.Chao@Sun.COM 				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
189*10500SHai-May.Chao@Sun.COM 					rc = FAILURE;
190*10500SHai-May.Chao@Sun.COM 					break;
191*10500SHai-May.Chao@Sun.COM 				} else if (strcmp(FIPS_KEYWORD, name) == 0) {
192*10500SHai-May.Chao@Sun.COM 					found = B_TRUE;
193*10500SHai-May.Chao@Sun.COM 					found_count++;
194*10500SHai-May.Chao@Sun.COM 				}
195*10500SHai-May.Chao@Sun.COM 			} else {
196*10500SHai-May.Chao@Sun.COM 				(void) strlcpy(buffer2, buffer, BUFSIZ);
197*10500SHai-May.Chao@Sun.COM 				ptr = buffer2;
198*10500SHai-May.Chao@Sun.COM 				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
199*10500SHai-May.Chao@Sun.COM 					rc = FAILURE;
200*10500SHai-May.Chao@Sun.COM 					break;
201*10500SHai-May.Chao@Sun.COM 				} else if (strcmp(FIPS_KEYWORD, name) == 0) {
202*10500SHai-May.Chao@Sun.COM 					found = B_TRUE;
203*10500SHai-May.Chao@Sun.COM 					found_count++;
204*10500SHai-May.Chao@Sun.COM 				}
205*10500SHai-May.Chao@Sun.COM 			}
206*10500SHai-May.Chao@Sun.COM 		}
207*10500SHai-May.Chao@Sun.COM 
208*10500SHai-May.Chao@Sun.COM 		if (found == B_FALSE) {
209*10500SHai-May.Chao@Sun.COM 			if (fputs(buffer, pfile_tmp) == EOF) {
210*10500SHai-May.Chao@Sun.COM 				rc = FAILURE;
211*10500SHai-May.Chao@Sun.COM 			}
212*10500SHai-May.Chao@Sun.COM 		} else {
213*10500SHai-May.Chao@Sun.COM 			if (found_count == 1) {
214*10500SHai-May.Chao@Sun.COM 				if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) {
215*10500SHai-May.Chao@Sun.COM 					if (fputs(ptr, pfile_tmp) == EOF) {
216*10500SHai-May.Chao@Sun.COM 						rc = FAILURE;
217*10500SHai-May.Chao@Sun.COM 					}
218*10500SHai-May.Chao@Sun.COM 				} else {
219*10500SHai-May.Chao@Sun.COM 					if (fputs(entry, pfile_tmp) == EOF) {
220*10500SHai-May.Chao@Sun.COM 						rc = FAILURE;
221*10500SHai-May.Chao@Sun.COM 					}
222*10500SHai-May.Chao@Sun.COM 				}
223*10500SHai-May.Chao@Sun.COM 			} else {
224*10500SHai-May.Chao@Sun.COM 				/*
225*10500SHai-May.Chao@Sun.COM 				 * Found a second entry with same tag name.
226*10500SHai-May.Chao@Sun.COM 				 * Should not happen. The config file
227*10500SHai-May.Chao@Sun.COM 				 * is corrupted. Give a warning and skip
228*10500SHai-May.Chao@Sun.COM 				 * this entry.
229*10500SHai-May.Chao@Sun.COM 				 */
230*10500SHai-May.Chao@Sun.COM 				cryptoerror(LOG_STDERR, gettext(
231*10500SHai-May.Chao@Sun.COM 				    "(Warning) Found an additional reserved "
232*10500SHai-May.Chao@Sun.COM 				    "entry for %s."), entry);
233*10500SHai-May.Chao@Sun.COM 			}
234*10500SHai-May.Chao@Sun.COM 		}
235*10500SHai-May.Chao@Sun.COM 
236*10500SHai-May.Chao@Sun.COM 		if (rc == FAILURE) {
237*10500SHai-May.Chao@Sun.COM 			break;
238*10500SHai-May.Chao@Sun.COM 		}
239*10500SHai-May.Chao@Sun.COM 	}
240*10500SHai-May.Chao@Sun.COM 
241*10500SHai-May.Chao@Sun.COM 	(void) fclose(pfile);
242*10500SHai-May.Chao@Sun.COM 
243*10500SHai-May.Chao@Sun.COM 	if (rc == FAILURE) {
244*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR, gettext("write error."));
245*10500SHai-May.Chao@Sun.COM 		(void) fclose(pfile_tmp);
246*10500SHai-May.Chao@Sun.COM 		if (unlink(tmpfile_name) != 0) {
247*10500SHai-May.Chao@Sun.COM 			err = errno;
248*10500SHai-May.Chao@Sun.COM 			cryptoerror(LOG_STDERR, gettext(
249*10500SHai-May.Chao@Sun.COM 			    "(Warning) failed to remove %s: %s"), tmpfile_name,
250*10500SHai-May.Chao@Sun.COM 			    strerror(err));
251*10500SHai-May.Chao@Sun.COM 		}
252*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
253*10500SHai-May.Chao@Sun.COM 	}
254*10500SHai-May.Chao@Sun.COM 
255*10500SHai-May.Chao@Sun.COM 	if (found_count == 0) {
256*10500SHai-May.Chao@Sun.COM 		/*
257*10500SHai-May.Chao@Sun.COM 		 * The entry was not in config file before, append it to the
258*10500SHai-May.Chao@Sun.COM 		 * end of the temp file.
259*10500SHai-May.Chao@Sun.COM 		 */
260*10500SHai-May.Chao@Sun.COM 		if (fputs(entry, pfile_tmp) == EOF) {
261*10500SHai-May.Chao@Sun.COM 			cryptoerror(LOG_STDERR, gettext(
262*10500SHai-May.Chao@Sun.COM 			    "failed to write to %s: %s"), tmpfile_name,
263*10500SHai-May.Chao@Sun.COM 			    strerror(errno));
264*10500SHai-May.Chao@Sun.COM 			(void) fclose(pfile_tmp);
265*10500SHai-May.Chao@Sun.COM 			if (unlink(tmpfile_name) != 0) {
266*10500SHai-May.Chao@Sun.COM 				err = errno;
267*10500SHai-May.Chao@Sun.COM 				cryptoerror(LOG_STDERR, gettext(
268*10500SHai-May.Chao@Sun.COM 				    "(Warning) failed to remove %s: %s"),
269*10500SHai-May.Chao@Sun.COM 				    tmpfile_name, strerror(err));
270*10500SHai-May.Chao@Sun.COM 			}
271*10500SHai-May.Chao@Sun.COM 			return (FAILURE);
272*10500SHai-May.Chao@Sun.COM 		}
273*10500SHai-May.Chao@Sun.COM 	}
274*10500SHai-May.Chao@Sun.COM 
275*10500SHai-May.Chao@Sun.COM 	if (fclose(pfile_tmp) != 0) {
276*10500SHai-May.Chao@Sun.COM 		err = errno;
277*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR,
278*10500SHai-May.Chao@Sun.COM 		    gettext("failed to close %s: %s"), tmpfile_name,
279*10500SHai-May.Chao@Sun.COM 		    strerror(err));
280*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
281*10500SHai-May.Chao@Sun.COM 	}
282*10500SHai-May.Chao@Sun.COM 
283*10500SHai-May.Chao@Sun.COM 	if (rename(tmpfile_name, conf_file) == -1) {
284*10500SHai-May.Chao@Sun.COM 		err = errno;
285*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR,
286*10500SHai-May.Chao@Sun.COM 		    gettext("failed to update the configuration - %s"),
287*10500SHai-May.Chao@Sun.COM 		    strerror(err));
288*10500SHai-May.Chao@Sun.COM 		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
289*10500SHai-May.Chao@Sun.COM 		    conf_file, strerror(err));
290*10500SHai-May.Chao@Sun.COM 		rc = FAILURE;
291*10500SHai-May.Chao@Sun.COM 	} else if (chmod(conf_file,
292*10500SHai-May.Chao@Sun.COM 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
293*10500SHai-May.Chao@Sun.COM 		err = errno;
294*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_STDERR,
295*10500SHai-May.Chao@Sun.COM 		    gettext("failed to update the configuration - %s"),
296*10500SHai-May.Chao@Sun.COM 		    strerror(err));
297*10500SHai-May.Chao@Sun.COM 		cryptodebug("failed to chmod to %s: %s", conf_file,
298*10500SHai-May.Chao@Sun.COM 		    strerror(err));
299*10500SHai-May.Chao@Sun.COM 		rc = FAILURE;
300*10500SHai-May.Chao@Sun.COM 	} else {
301*10500SHai-May.Chao@Sun.COM 		rc = SUCCESS;
302*10500SHai-May.Chao@Sun.COM 	}
303*10500SHai-May.Chao@Sun.COM 
304*10500SHai-May.Chao@Sun.COM 	if (rc == FAILURE) {
305*10500SHai-May.Chao@Sun.COM 		if (unlink(tmpfile_name) != 0) {
306*10500SHai-May.Chao@Sun.COM 			err = errno;
307*10500SHai-May.Chao@Sun.COM 			cryptoerror(LOG_STDERR, gettext(
308*10500SHai-May.Chao@Sun.COM 			    "(Warning) failed to remove %s: %s"),
309*10500SHai-May.Chao@Sun.COM 			    tmpfile_name, strerror(err));
310*10500SHai-May.Chao@Sun.COM 		}
311*10500SHai-May.Chao@Sun.COM 	}
312*10500SHai-May.Chao@Sun.COM 
313*10500SHai-May.Chao@Sun.COM 	return (rc);
314*10500SHai-May.Chao@Sun.COM 
315*10500SHai-May.Chao@Sun.COM }
316