OpenSolaris_b135/lib/libgss/g_utils.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 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_ext.h>
#include <synch.h>

#define	Q_DEFAULT		"default"
#define	BUFLEN			256

static int qop_num_pair_cnt;
static const char    QOP_NUM_FILE[] = "/etc/gss/qop";
static qop_num	qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
static mutex_t qopfile_lock = DEFAULTMUTEX;

static OM_uint32 __gss_read_qop_file(void);

/*
 * This routine fetches qop and num from "/etc/gss/qop".
 * There is a memory leak associated with rereading this file,
 * because we can't free the qop_num_pairs array when we reread
 * the file (some callers may have been given these pointers).
 * In general, this memory leak should be a small one, because
 * we don't expect the qop file to be changed and reread often.
 */
static OM_uint32
__gss_read_qop_file(void)
{
	char 	buf[BUFLEN];	/* one line from the file */
	char	*name, *next;
	char	*qopname, *num_str;
	char 	*line;
	FILE 	*fp;
	static int last = 0;
	struct stat stbuf;
	OM_uint32 major = GSS_S_COMPLETE;

	(void) mutex_lock(&qopfile_lock);
	if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
		if (!qop_num_pairs[0].qop) {
			major = GSS_S_FAILURE;
		}
		goto done;
	}
	last = stbuf.st_mtime;

	fp = fopen(QOP_NUM_FILE, "rF");
	if (fp == (FILE *)0) {
		major = GSS_S_FAILURE;
		goto done;
	}

	/*
	 * For each line in the file parse it appropriately.
	 * File format : qopname	num(int)
	 * Note that we silently ignore corrupt entries.
	 */
	qop_num_pair_cnt = 0;
	while (!feof(fp)) {
		line = fgets(buf, BUFLEN, fp);
		if (line == NULL)
			break;

		/* Skip comments and blank lines */
		if ((*line == '#') || (*line == '\n'))
			continue;

		/* Skip trailing comments */
		next = strchr(line, '#');
		if (next)
			*next = '\0';

		name = &(buf[0]);
		while (isspace(*name))
			name++;
		if (*name == '\0')	/* blank line */
			continue;

		qopname = name;	/* will contain qop name */
		while (!isspace(*qopname))
			qopname++;
		if (*qopname == '\0') {
			continue;
		}
		next = qopname+1;
		*qopname = '\0';	/* null terminate qopname */
		qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
		if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
			continue;

		name = next;
		while (isspace(*name))
			name++;
		if (*name == '\0') { 	/* end of line, no num */
			free(qop_num_pairs[qop_num_pair_cnt].qop);
			continue;
		}
		num_str = name;	/* will contain num (n) */
		while (!isspace(*num_str))
			num_str++;
		next = num_str+1;
		*num_str++ = '\0';	/* null terminate num_str */

		qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
		name = next;
		while (isspace(*name))
			name++;
		if (*name == '\0') { 	/* end of line, no mechanism */
			free(qop_num_pairs[qop_num_pair_cnt].qop);
			continue;
		}
		num_str = name;	/* will contain mech */
		while (!isspace(*num_str))
			num_str++;
		*num_str = '\0';

		qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
		if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
			free(qop_num_pairs[qop_num_pair_cnt].qop);
			continue;
		}

		if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
			break;
	}
	(void) fclose(fp);
done:
	(void) mutex_unlock(&qopfile_lock);
	return (major);
}

OM_uint32
__gss_qop_to_num(
	char		*qop,
	char		*mech,
	OM_uint32	*num
)
{
	int i;
	OM_uint32 major = GSS_S_FAILURE;

	if (!num)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	if (qop == NULL || strlen(qop) == 0 ||
			strcasecmp(qop, Q_DEFAULT) == 0) {
		*num = GSS_C_QOP_DEFAULT;
		return (GSS_S_COMPLETE);
	}

	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
		return (major);

	for (i = 0; i < qop_num_pair_cnt; i++) {
		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
		    (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
			*num = qop_num_pairs[i].num;
			return (GSS_S_COMPLETE);
		}
	}

	return (GSS_S_FAILURE);
}

OM_uint32
__gss_num_to_qop(
	char		*mech,
	OM_uint32	num,
	char		**qop
)
{
	int i;
	OM_uint32 major;

	if (!qop)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);
	*qop = NULL;

	if (num == GSS_C_QOP_DEFAULT) {
		*qop = Q_DEFAULT;
		return (GSS_S_COMPLETE);
	}

	if (mech == NULL)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
		return (major);

	for (i = 0; i < qop_num_pair_cnt; i++) {
		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
		    (num == qop_num_pairs[i].num)) {
			*qop = qop_num_pairs[i].qop;
			return (GSS_S_COMPLETE);
		}
	}
	return (GSS_S_FAILURE);
}

/*
 * For a given mechanism pass back qop information about it in a buffer
 * of size MAX_QOPS_PER_MECH+1.
 */
OM_uint32
__gss_get_mech_info(
	char		*mech,
	char		**qops
)
{
	int i, cnt = 0;
	OM_uint32 major = GSS_S_COMPLETE;

	if (!qops)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);
	*qops = NULL;

	if (!mech)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
		return (major);

	for (i = 0; i < qop_num_pair_cnt; i++) {
		if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
		    if (cnt >= MAX_QOPS_PER_MECH) {
			return (GSS_S_FAILURE);
		    }
		    qops[cnt++] = qop_num_pairs[i].qop;
		}
	}
	qops[cnt] = NULL;
	return (GSS_S_COMPLETE);
}

/*
 * Copy the qop values and names for the mechanism back in a qop_num
 * buffer of size MAX_QOPS_PER_MECH provided by the caller.
 */
OM_uint32
__gss_mech_qops(
	char *mech,
	qop_num *mechqops,
	int *numqop
)
{
	int i;
	OM_uint32 major;
	int cnt = 0;

	if (!mechqops || !numqop)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);
	*numqop = 0;

	if (!mech)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
		return (major);

	for (i = 0; i < qop_num_pair_cnt; i++) {
	    if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
		if (cnt >= MAX_QOPS_PER_MECH) {
			return (GSS_S_FAILURE);
		}
		mechqops[cnt++] = qop_num_pairs[i];
	    }
	}
	*numqop = cnt;
	return (GSS_S_COMPLETE);
}