Home | History | Annotate | Download | only in libgss
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/types.h>
     29 #include <sys/stat.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <strings.h>
     33 #include <ctype.h>
     34 #include <errno.h>
     35 #include <gssapi/gssapi.h>
     36 #include <gssapi/gssapi_ext.h>
     37 #include <synch.h>
     38 
     39 #define	Q_DEFAULT		"default"
     40 #define	BUFLEN			256
     41 
     42 static int qop_num_pair_cnt;
     43 static const char    QOP_NUM_FILE[] = "/etc/gss/qop";
     44 static qop_num	qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
     45 static mutex_t qopfile_lock = DEFAULTMUTEX;
     46 
     47 static OM_uint32 __gss_read_qop_file(void);
     48 
     49 /*
     50  * This routine fetches qop and num from "/etc/gss/qop".
     51  * There is a memory leak associated with rereading this file,
     52  * because we can't free the qop_num_pairs array when we reread
     53  * the file (some callers may have been given these pointers).
     54  * In general, this memory leak should be a small one, because
     55  * we don't expect the qop file to be changed and reread often.
     56  */
     57 static OM_uint32
     58 __gss_read_qop_file(void)
     59 {
     60 	char 	buf[BUFLEN];	/* one line from the file */
     61 	char	*name, *next;
     62 	char	*qopname, *num_str;
     63 	char 	*line;
     64 	FILE 	*fp;
     65 	static int last = 0;
     66 	struct stat stbuf;
     67 	OM_uint32 major = GSS_S_COMPLETE;
     68 
     69 	(void) mutex_lock(&qopfile_lock);
     70 	if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
     71 		if (!qop_num_pairs[0].qop) {
     72 			major = GSS_S_FAILURE;
     73 		}
     74 		goto done;
     75 	}
     76 	last = stbuf.st_mtime;
     77 
     78 	fp = fopen(QOP_NUM_FILE, "rF");
     79 	if (fp == (FILE *)0) {
     80 		major = GSS_S_FAILURE;
     81 		goto done;
     82 	}
     83 
     84 	/*
     85 	 * For each line in the file parse it appropriately.
     86 	 * File format : qopname	num(int)
     87 	 * Note that we silently ignore corrupt entries.
     88 	 */
     89 	qop_num_pair_cnt = 0;
     90 	while (!feof(fp)) {
     91 		line = fgets(buf, BUFLEN, fp);
     92 		if (line == NULL)
     93 			break;
     94 
     95 		/* Skip comments and blank lines */
     96 		if ((*line == '#') || (*line == '\n'))
     97 			continue;
     98 
     99 		/* Skip trailing comments */
    100 		next = strchr(line, '#');
    101 		if (next)
    102 			*next = '\0';
    103 
    104 		name = &(buf[0]);
    105 		while (isspace(*name))
    106 			name++;
    107 		if (*name == '\0')	/* blank line */
    108 			continue;
    109 
    110 		qopname = name;	/* will contain qop name */
    111 		while (!isspace(*qopname))
    112 			qopname++;
    113 		if (*qopname == '\0') {
    114 			continue;
    115 		}
    116 		next = qopname+1;
    117 		*qopname = '\0';	/* null terminate qopname */
    118 		qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
    119 		if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
    120 			continue;
    121 
    122 		name = next;
    123 		while (isspace(*name))
    124 			name++;
    125 		if (*name == '\0') { 	/* end of line, no num */
    126 			free(qop_num_pairs[qop_num_pair_cnt].qop);
    127 			continue;
    128 		}
    129 		num_str = name;	/* will contain num (n) */
    130 		while (!isspace(*num_str))
    131 			num_str++;
    132 		next = num_str+1;
    133 		*num_str++ = '\0';	/* null terminate num_str */
    134 
    135 		qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
    136 		name = next;
    137 		while (isspace(*name))
    138 			name++;
    139 		if (*name == '\0') { 	/* end of line, no mechanism */
    140 			free(qop_num_pairs[qop_num_pair_cnt].qop);
    141 			continue;
    142 		}
    143 		num_str = name;	/* will contain mech */
    144 		while (!isspace(*num_str))
    145 			num_str++;
    146 		*num_str = '\0';
    147 
    148 		qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
    149 		if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
    150 			free(qop_num_pairs[qop_num_pair_cnt].qop);
    151 			continue;
    152 		}
    153 
    154 		if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
    155 			break;
    156 	}
    157 	(void) fclose(fp);
    158 done:
    159 	(void) mutex_unlock(&qopfile_lock);
    160 	return (major);
    161 }
    162 
    163 OM_uint32
    164 __gss_qop_to_num(
    165 	char		*qop,
    166 	char		*mech,
    167 	OM_uint32	*num
    168 )
    169 {
    170 	int i;
    171 	OM_uint32 major = GSS_S_FAILURE;
    172 
    173 	if (!num)
    174 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    175 
    176 	if (qop == NULL || strlen(qop) == 0 ||
    177 			strcasecmp(qop, Q_DEFAULT) == 0) {
    178 		*num = GSS_C_QOP_DEFAULT;
    179 		return (GSS_S_COMPLETE);
    180 	}
    181 
    182 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
    183 		return (major);
    184 
    185 	for (i = 0; i < qop_num_pair_cnt; i++) {
    186 		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
    187 		    (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
    188 			*num = qop_num_pairs[i].num;
    189 			return (GSS_S_COMPLETE);
    190 		}
    191 	}
    192 
    193 	return (GSS_S_FAILURE);
    194 }
    195 
    196 OM_uint32
    197 __gss_num_to_qop(
    198 	char		*mech,
    199 	OM_uint32	num,
    200 	char		**qop
    201 )
    202 {
    203 	int i;
    204 	OM_uint32 major;
    205 
    206 	if (!qop)
    207 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    208 	*qop = NULL;
    209 
    210 	if (num == GSS_C_QOP_DEFAULT) {
    211 		*qop = Q_DEFAULT;
    212 		return (GSS_S_COMPLETE);
    213 	}
    214 
    215 	if (mech == NULL)
    216 		return (GSS_S_CALL_INACCESSIBLE_READ);
    217 
    218 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
    219 		return (major);
    220 
    221 	for (i = 0; i < qop_num_pair_cnt; i++) {
    222 		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
    223 		    (num == qop_num_pairs[i].num)) {
    224 			*qop = qop_num_pairs[i].qop;
    225 			return (GSS_S_COMPLETE);
    226 		}
    227 	}
    228 	return (GSS_S_FAILURE);
    229 }
    230 
    231 /*
    232  * For a given mechanism pass back qop information about it in a buffer
    233  * of size MAX_QOPS_PER_MECH+1.
    234  */
    235 OM_uint32
    236 __gss_get_mech_info(
    237 	char		*mech,
    238 	char		**qops
    239 )
    240 {
    241 	int i, cnt = 0;
    242 	OM_uint32 major = GSS_S_COMPLETE;
    243 
    244 	if (!qops)
    245 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    246 	*qops = NULL;
    247 
    248 	if (!mech)
    249 		return (GSS_S_CALL_INACCESSIBLE_READ);
    250 
    251 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
    252 		return (major);
    253 
    254 	for (i = 0; i < qop_num_pair_cnt; i++) {
    255 		if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
    256 		    if (cnt >= MAX_QOPS_PER_MECH) {
    257 			return (GSS_S_FAILURE);
    258 		    }
    259 		    qops[cnt++] = qop_num_pairs[i].qop;
    260 		}
    261 	}
    262 	qops[cnt] = NULL;
    263 	return (GSS_S_COMPLETE);
    264 }
    265 
    266 /*
    267  * Copy the qop values and names for the mechanism back in a qop_num
    268  * buffer of size MAX_QOPS_PER_MECH provided by the caller.
    269  */
    270 OM_uint32
    271 __gss_mech_qops(
    272 	char *mech,
    273 	qop_num *mechqops,
    274 	int *numqop
    275 )
    276 {
    277 	int i;
    278 	OM_uint32 major;
    279 	int cnt = 0;
    280 
    281 	if (!mechqops || !numqop)
    282 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    283 	*numqop = 0;
    284 
    285 	if (!mech)
    286 		return (GSS_S_CALL_INACCESSIBLE_READ);
    287 
    288 	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
    289 		return (major);
    290 
    291 	for (i = 0; i < qop_num_pair_cnt; i++) {
    292 	    if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
    293 		if (cnt >= MAX_QOPS_PER_MECH) {
    294 			return (GSS_S_FAILURE);
    295 		}
    296 		mechqops[cnt++] = qop_num_pairs[i];
    297 	    }
    298 	}
    299 	*numqop = cnt;
    300 	return (GSS_S_COMPLETE);
    301 }
    302