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