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
__gss_read_qop_file(void)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
__gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)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
__gss_num_to_qop(char * mech,OM_uint32 num,char ** qop)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
__gss_get_mech_info(char * mech,char ** qops)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
__gss_mech_qops(char * mech,qop_num * mechqops,int * numqop)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