OpenSolaris_b135/cmd/cmd-crypto/cryptoadm/adm_util.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <ctype.h>
#include <strings.h>
#include <libintl.h>
#include <stdio.h>
#include <sys/stat.h>
#include "cryptoadm.h"
#include <cryptoutil.h>

/*
 * Create one item of type mechlist_t with the mechanism name.  A null is
 * returned to indicate that the storage space available is insufficient.
 */
mechlist_t *
create_mech(char *name)
{
	mechlist_t *pres = NULL;
	char *first, *last;

	if (name == NULL) {
		return (NULL);
	}

	pres = malloc(sizeof (mechlist_t));
	if (pres == NULL) {
		cryptodebug("out of memory.");
		return (NULL);
	}

	first = name;
	while (isspace(*first)) /* nuke leading whitespace */
		first++;
	(void) strlcpy(pres->name, first, sizeof (pres->name));

	last = strrchr(pres->name, '\0');
	last--;
	while (isspace(*last))  /* nuke trailing whitespace */
		*last-- = '\0';

	pres->next = NULL;

	return (pres);
}



void
free_mechlist(mechlist_t *plist)
{
	mechlist_t *pnext;

	while (plist != NULL) {
		pnext = plist->next;
		free(plist);
		plist = pnext;
	}
}



/*
 * Check if the mechanism is in the mechanism list.
 */
boolean_t
is_in_list(char *mechname, mechlist_t *plist)
{
	boolean_t found = B_FALSE;

	if (mechname == NULL) {
		return (B_FALSE);
	}

	while (plist != NULL) {
		if (strcmp(plist->name, mechname) == 0) {
			found = B_TRUE;
			break;
		}
		plist = plist->next;
	}

	return (found);
}

int
update_conf(char *conf_file, char *entry)
{

	boolean_t	found;
	boolean_t	fips_entry = B_FALSE;
	FILE	*pfile;
	FILE	*pfile_tmp;
	char	tmpfile_name[MAXPATHLEN];
	char	*ptr;
	char	*name;
	char	buffer[BUFSIZ];
	char	buffer2[BUFSIZ];
	int		found_count;
	int		rc = SUCCESS;
	int		err;

	if ((pfile = fopen(conf_file, "r+")) == NULL) {
		err = errno;
		cryptoerror(LOG_STDERR,
		    gettext("failed to update the configuration - %s"),
		    strerror(err));
		cryptodebug("failed to open %s for write.", conf_file);
		return (FAILURE);
	}

	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
		err = errno;
		cryptoerror(LOG_STDERR,
		    gettext("failed to lock the configuration - %s"),
		    strerror(err));
		(void) fclose(pfile);
		return (FAILURE);
	}

	/*
	 * Create a temporary file in the /etc/crypto directory.
	 */
	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
	if (mkstemp(tmpfile_name) == -1) {
		err = errno;
		cryptoerror(LOG_STDERR,
		    gettext("failed to create a temporary file - %s"),
		    strerror(err));
		(void) fclose(pfile);
		return (FAILURE);
	}

	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
		err = errno;
		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
		    tmpfile_name, strerror(err));
		(void) fclose(pfile);
		return (FAILURE);
	}


	/*
	 * Loop thru the config file. If the provider was reserved within a
	 * package bracket, just uncomment it.  Otherwise, append it at
	 * the end.  The resulting file will be saved in the temp file first.
	 */
	found_count = 0;
	rc = SUCCESS;

	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
		found = B_FALSE;
		if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) {
			if (buffer[0] == '#') {
				ptr = buffer;
				ptr++;
				if (strcmp(entry, ptr) == 0) {
					found = B_TRUE;
					found_count++;
				}
			} else {
				(void) strlcpy(buffer2, buffer, BUFSIZ);
				ptr = buffer2;
				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
					rc = FAILURE;
					break;
				} else if (strcmp(FIPS_KEYWORD, name) == 0) {
					found = B_TRUE;
					found_count++;
					fips_entry = B_TRUE;
				}
			}
		} else { /* _PATH_KCF_CONF */
			if (buffer[0] == '#') {
				(void) strlcpy(buffer2, buffer, BUFSIZ);
				ptr = buffer2;
				ptr++; /* skip # */
				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
					rc = FAILURE;
					break;
				}
			} else {
				(void) strlcpy(buffer2, buffer, BUFSIZ);
				ptr = buffer2;
				if ((name = strtok(ptr, SEP_COLON)) == NULL) {
					rc = FAILURE;
					break;
				}
			}
		}

		if (found == B_FALSE) {
			if (fputs(buffer, pfile_tmp) == EOF) {
				rc = FAILURE;
			}
		} else {
			if (found_count == 1) {
				if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) {
					if (fips_entry == B_TRUE) {
						if (fputs(entry, pfile_tmp) ==
						    EOF) {
							rc = FAILURE;
						}
						fips_entry = B_FALSE;
					} else {
						if (fputs(ptr, pfile_tmp) ==
						    EOF) {
							rc = FAILURE;
						}
					}
				} else {
					if (fputs(entry, pfile_tmp) == EOF) {
						rc = FAILURE;
					}
				}
			} else {
				/*
				 * Found a second entry with same tag name.
				 * Should not happen. The config file
				 * is corrupted. Give a warning and skip
				 * this entry.
				 */
				cryptoerror(LOG_STDERR, gettext(
				    "(Warning) Found an additional reserved "
				    "entry for %s."), entry);
			}
		}

		if (rc == FAILURE) {
			break;
		}
	}

	(void) fclose(pfile);

	if (rc == FAILURE) {
		cryptoerror(LOG_STDERR, gettext("write error."));
		(void) fclose(pfile_tmp);
		if (unlink(tmpfile_name) != 0) {
			err = errno;
			cryptoerror(LOG_STDERR, gettext(
			    "(Warning) failed to remove %s: %s"), tmpfile_name,
			    strerror(err));
		}
		return (FAILURE);
	}

	if (found_count == 0) {
		/*
		 * The entry was not in config file before, append it to the
		 * end of the temp file.
		 */
		if (fputs(entry, pfile_tmp) == EOF) {
			cryptoerror(LOG_STDERR, gettext(
			    "failed to write to %s: %s"), tmpfile_name,
			    strerror(errno));
			(void) fclose(pfile_tmp);
			if (unlink(tmpfile_name) != 0) {
				err = errno;
				cryptoerror(LOG_STDERR, gettext(
				    "(Warning) failed to remove %s: %s"),
				    tmpfile_name, strerror(err));
			}
			return (FAILURE);
		}
	}

	if (fclose(pfile_tmp) != 0) {
		err = errno;
		cryptoerror(LOG_STDERR,
		    gettext("failed to close %s: %s"), tmpfile_name,
		    strerror(err));
		return (FAILURE);
	}

	if (rename(tmpfile_name, conf_file) == -1) {
		err = errno;
		cryptoerror(LOG_STDERR,
		    gettext("failed to update the configuration - %s"),
		    strerror(err));
		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
		    conf_file, strerror(err));
		rc = FAILURE;
	} else if (chmod(conf_file,
	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
		err = errno;
		cryptoerror(LOG_STDERR,
		    gettext("failed to update the configuration - %s"),
		    strerror(err));
		cryptodebug("failed to chmod to %s: %s", conf_file,
		    strerror(err));
		rc = FAILURE;
	} else {
		rc = SUCCESS;
	}

	if (rc == FAILURE) {
		if (unlink(tmpfile_name) != 0) {
			err = errno;
			cryptoerror(LOG_STDERR, gettext(
			    "(Warning) failed to remove %s: %s"),
			    tmpfile_name, strerror(err));
		}
	}

	return (rc);

}