xref: /illumos-gate/usr/src/lib/libgss/g_utils.c (revision 4c87aefe8930bd07275b8dd2e96ea5f24d93a52e)
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