xref: /onnv-gate/usr/src/lib/libgss/g_utils.c (revision 1914:8a8c5f225b1b)
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*1914Scasper  * Common Development and Distribution License (the "License").
6*1914Scasper  * 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*1914Scasper  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/stat.h>
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <strings.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <gssapi/gssapi.h>
360Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
370Sstevel@tonic-gate #include <synch.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #define	Q_DEFAULT		"default"
400Sstevel@tonic-gate #define	BUFLEN			256
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static int qop_num_pair_cnt;
430Sstevel@tonic-gate static const char    QOP_NUM_FILE[] = "/etc/gss/qop";
440Sstevel@tonic-gate static qop_num	qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
450Sstevel@tonic-gate static mutex_t qopfile_lock = DEFAULTMUTEX;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static OM_uint32 __gss_read_qop_file(void);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * This routine fetches qop and num from "/etc/gss/qop".
510Sstevel@tonic-gate  * There is a memory leak associated with rereading this file,
520Sstevel@tonic-gate  * because we can't free the qop_num_pairs array when we reread
530Sstevel@tonic-gate  * the file (some callers may have been given these pointers).
540Sstevel@tonic-gate  * In general, this memory leak should be a small one, because
550Sstevel@tonic-gate  * we don't expect the qop file to be changed and reread often.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate static OM_uint32
__gss_read_qop_file(void)580Sstevel@tonic-gate __gss_read_qop_file(void)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	char 	buf[BUFLEN];	/* one line from the file */
610Sstevel@tonic-gate 	char	*name, *next;
620Sstevel@tonic-gate 	char	*qopname, *num_str;
630Sstevel@tonic-gate 	char 	*line;
640Sstevel@tonic-gate 	FILE 	*fp;
650Sstevel@tonic-gate 	static int last = 0;
660Sstevel@tonic-gate 	struct stat stbuf;
670Sstevel@tonic-gate 	OM_uint32 major = GSS_S_COMPLETE;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	(void) mutex_lock(&qopfile_lock);
700Sstevel@tonic-gate 	if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
710Sstevel@tonic-gate 		if (!qop_num_pairs[0].qop) {
720Sstevel@tonic-gate 			major = GSS_S_FAILURE;
730Sstevel@tonic-gate 		}
740Sstevel@tonic-gate 		goto done;
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate 	last = stbuf.st_mtime;
770Sstevel@tonic-gate 
78*1914Scasper 	fp = fopen(QOP_NUM_FILE, "rF");
790Sstevel@tonic-gate 	if (fp == (FILE *)0) {
800Sstevel@tonic-gate 		major = GSS_S_FAILURE;
810Sstevel@tonic-gate 		goto done;
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	/*
850Sstevel@tonic-gate 	 * For each line in the file parse it appropriately.
860Sstevel@tonic-gate 	 * File format : qopname	num(int)
870Sstevel@tonic-gate 	 * Note that we silently ignore corrupt entries.
880Sstevel@tonic-gate 	 */
890Sstevel@tonic-gate 	qop_num_pair_cnt = 0;
900Sstevel@tonic-gate 	while (!feof(fp)) {
910Sstevel@tonic-gate 		line = fgets(buf, BUFLEN, fp);
920Sstevel@tonic-gate 		if (line == NULL)
930Sstevel@tonic-gate 			break;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 		/* Skip comments and blank lines */
960Sstevel@tonic-gate 		if ((*line == '#') || (*line == '\n'))
970Sstevel@tonic-gate 			continue;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 		/* Skip trailing comments */
1000Sstevel@tonic-gate 		next = strchr(line, '#');
1010Sstevel@tonic-gate 		if (next)
1020Sstevel@tonic-gate 			*next = '\0';
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		name = &(buf[0]);
1050Sstevel@tonic-gate 		while (isspace(*name))
1060Sstevel@tonic-gate 			name++;
1070Sstevel@tonic-gate 		if (*name == '\0')	/* blank line */
1080Sstevel@tonic-gate 			continue;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 		qopname = name;	/* will contain qop name */
1110Sstevel@tonic-gate 		while (!isspace(*qopname))
1120Sstevel@tonic-gate 			qopname++;
1130Sstevel@tonic-gate 		if (*qopname == '\0') {
1140Sstevel@tonic-gate 			continue;
1150Sstevel@tonic-gate 		}
1160Sstevel@tonic-gate 		next = qopname+1;
1170Sstevel@tonic-gate 		*qopname = '\0';	/* null terminate qopname */
1180Sstevel@tonic-gate 		qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
1190Sstevel@tonic-gate 		if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
1200Sstevel@tonic-gate 			continue;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 		name = next;
1230Sstevel@tonic-gate 		while (isspace(*name))
1240Sstevel@tonic-gate 			name++;
1250Sstevel@tonic-gate 		if (*name == '\0') { 	/* end of line, no num */
1260Sstevel@tonic-gate 			free(qop_num_pairs[qop_num_pair_cnt].qop);
1270Sstevel@tonic-gate 			continue;
1280Sstevel@tonic-gate 		}
1290Sstevel@tonic-gate 		num_str = name;	/* will contain num (n) */
1300Sstevel@tonic-gate 		while (!isspace(*num_str))
1310Sstevel@tonic-gate 			num_str++;
1320Sstevel@tonic-gate 		next = num_str+1;
1330Sstevel@tonic-gate 		*num_str++ = '\0';	/* null terminate num_str */
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 		qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
1360Sstevel@tonic-gate 		name = next;
1370Sstevel@tonic-gate 		while (isspace(*name))
1380Sstevel@tonic-gate 			name++;
1390Sstevel@tonic-gate 		if (*name == '\0') { 	/* end of line, no mechanism */
1400Sstevel@tonic-gate 			free(qop_num_pairs[qop_num_pair_cnt].qop);
1410Sstevel@tonic-gate 			continue;
1420Sstevel@tonic-gate 		}
1430Sstevel@tonic-gate 		num_str = name;	/* will contain mech */
1440Sstevel@tonic-gate 		while (!isspace(*num_str))
1450Sstevel@tonic-gate 			num_str++;
1460Sstevel@tonic-gate 		*num_str = '\0';
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 		qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
1490Sstevel@tonic-gate 		if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
1500Sstevel@tonic-gate 			free(qop_num_pairs[qop_num_pair_cnt].qop);
1510Sstevel@tonic-gate 			continue;
1520Sstevel@tonic-gate 		}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 		if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
1550Sstevel@tonic-gate 			break;
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 	(void) fclose(fp);
1580Sstevel@tonic-gate done:
1590Sstevel@tonic-gate 	(void) mutex_unlock(&qopfile_lock);
1600Sstevel@tonic-gate 	return (major);
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate OM_uint32
__gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)1640Sstevel@tonic-gate __gss_qop_to_num(
1650Sstevel@tonic-gate 	char		*qop,
1660Sstevel@tonic-gate 	char		*mech,
1670Sstevel@tonic-gate 	OM_uint32	*num
1680Sstevel@tonic-gate )
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	int i;
1710Sstevel@tonic-gate 	OM_uint32 major = GSS_S_FAILURE;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if (!num)
1740Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (qop == NULL || strlen(qop) == 0 ||
1770Sstevel@tonic-gate 			strcasecmp(qop, Q_DEFAULT) == 0) {
1780Sstevel@tonic-gate 		*num = GSS_C_QOP_DEFAULT;
1790Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
1830Sstevel@tonic-gate 		return (major);
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	for (i = 0; i < qop_num_pair_cnt; i++) {
1860Sstevel@tonic-gate 		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
1870Sstevel@tonic-gate 		    (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
1880Sstevel@tonic-gate 			*num = qop_num_pairs[i].num;
1890Sstevel@tonic-gate 			return (GSS_S_COMPLETE);
1900Sstevel@tonic-gate 		}
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	return (GSS_S_FAILURE);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate OM_uint32
__gss_num_to_qop(char * mech,OM_uint32 num,char ** qop)1970Sstevel@tonic-gate __gss_num_to_qop(
1980Sstevel@tonic-gate 	char		*mech,
1990Sstevel@tonic-gate 	OM_uint32	num,
2000Sstevel@tonic-gate 	char		**qop
2010Sstevel@tonic-gate )
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 	int i;
2040Sstevel@tonic-gate 	OM_uint32 major;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	if (!qop)
2070Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2080Sstevel@tonic-gate 	*qop = NULL;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if (num == GSS_C_QOP_DEFAULT) {
2110Sstevel@tonic-gate 		*qop = Q_DEFAULT;
2120Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	if (mech == NULL)
2160Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
2190Sstevel@tonic-gate 		return (major);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	for (i = 0; i < qop_num_pair_cnt; i++) {
2220Sstevel@tonic-gate 		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
2230Sstevel@tonic-gate 		    (num == qop_num_pairs[i].num)) {
2240Sstevel@tonic-gate 			*qop = qop_num_pairs[i].qop;
2250Sstevel@tonic-gate 			return (GSS_S_COMPLETE);
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 	return (GSS_S_FAILURE);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  * For a given mechanism pass back qop information about it in a buffer
2330Sstevel@tonic-gate  * of size MAX_QOPS_PER_MECH+1.
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate OM_uint32
__gss_get_mech_info(char * mech,char ** qops)2360Sstevel@tonic-gate __gss_get_mech_info(
2370Sstevel@tonic-gate 	char		*mech,
2380Sstevel@tonic-gate 	char		**qops
2390Sstevel@tonic-gate )
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	int i, cnt = 0;
2420Sstevel@tonic-gate 	OM_uint32 major = GSS_S_COMPLETE;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (!qops)
2450Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2460Sstevel@tonic-gate 	*qops = NULL;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (!mech)
2490Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
2520Sstevel@tonic-gate 		return (major);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	for (i = 0; i < qop_num_pair_cnt; i++) {
2550Sstevel@tonic-gate 		if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
2560Sstevel@tonic-gate 		    if (cnt >= MAX_QOPS_PER_MECH) {
2570Sstevel@tonic-gate 			return (GSS_S_FAILURE);
2580Sstevel@tonic-gate 		    }
2590Sstevel@tonic-gate 		    qops[cnt++] = qop_num_pairs[i].qop;
2600Sstevel@tonic-gate 		}
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 	qops[cnt] = NULL;
2630Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate  * Copy the qop values and names for the mechanism back in a qop_num
2680Sstevel@tonic-gate  * buffer of size MAX_QOPS_PER_MECH provided by the caller.
2690Sstevel@tonic-gate  */
2700Sstevel@tonic-gate OM_uint32
__gss_mech_qops(char * mech,qop_num * mechqops,int * numqop)2710Sstevel@tonic-gate __gss_mech_qops(
2720Sstevel@tonic-gate 	char *mech,
2730Sstevel@tonic-gate 	qop_num *mechqops,
2740Sstevel@tonic-gate 	int *numqop
2750Sstevel@tonic-gate )
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	int i;
2780Sstevel@tonic-gate 	OM_uint32 major;
2790Sstevel@tonic-gate 	int cnt = 0;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if (!mechqops || !numqop)
2820Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2830Sstevel@tonic-gate 	*numqop = 0;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	if (!mech)
2860Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
2890Sstevel@tonic-gate 		return (major);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	for (i = 0; i < qop_num_pair_cnt; i++) {
2920Sstevel@tonic-gate 	    if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
2930Sstevel@tonic-gate 		if (cnt >= MAX_QOPS_PER_MECH) {
2940Sstevel@tonic-gate 			return (GSS_S_FAILURE);
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 		mechqops[cnt++] = qop_num_pairs[i];
2970Sstevel@tonic-gate 	    }
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	*numqop = cnt;
3000Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
3010Sstevel@tonic-gate }
302