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