components/krb5/Solaris/g_utils.c
author Will Fiveash <will.fiveash@oracle.com>
Wed, 24 Feb 2016 10:43:57 -0600
changeset 5490 9bf0bc57423a
permissions -rw-r--r--
PSARC/2015/144 Kerberos 1.13 Delivery to Userland 19153034 Add MIT Kerberos to the Userland Consolidation

/*
 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
 */

#include "mglueP.h"
#include "gssapiP_krb5.h"

#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
gssint_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
gssint_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
gssint_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);
}