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 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 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 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 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 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