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