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