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