1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1914 casper * Common Development and Distribution License (the "License"). 6 1914 casper * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 1914 casper * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 27 0 stevel 28 0 stevel #include <sys/types.h> 29 0 stevel #include <sys/stat.h> 30 0 stevel #include <stdio.h> 31 0 stevel #include <stdlib.h> 32 0 stevel #include <strings.h> 33 0 stevel #include <ctype.h> 34 0 stevel #include <errno.h> 35 0 stevel #include <gssapi/gssapi.h> 36 0 stevel #include <gssapi/gssapi_ext.h> 37 0 stevel #include <synch.h> 38 0 stevel 39 0 stevel #define Q_DEFAULT "default" 40 0 stevel #define BUFLEN 256 41 0 stevel 42 0 stevel static int qop_num_pair_cnt; 43 0 stevel static const char QOP_NUM_FILE[] = "/etc/gss/qop"; 44 0 stevel static qop_num qop_num_pairs[MAX_QOP_NUM_PAIRS+1]; 45 0 stevel static mutex_t qopfile_lock = DEFAULTMUTEX; 46 0 stevel 47 0 stevel static OM_uint32 __gss_read_qop_file(void); 48 0 stevel 49 0 stevel /* 50 0 stevel * This routine fetches qop and num from "/etc/gss/qop". 51 0 stevel * There is a memory leak associated with rereading this file, 52 0 stevel * because we can't free the qop_num_pairs array when we reread 53 0 stevel * the file (some callers may have been given these pointers). 54 0 stevel * In general, this memory leak should be a small one, because 55 0 stevel * we don't expect the qop file to be changed and reread often. 56 0 stevel */ 57 0 stevel static OM_uint32 58 0 stevel __gss_read_qop_file(void) 59 0 stevel { 60 0 stevel char buf[BUFLEN]; /* one line from the file */ 61 0 stevel char *name, *next; 62 0 stevel char *qopname, *num_str; 63 0 stevel char *line; 64 0 stevel FILE *fp; 65 0 stevel static int last = 0; 66 0 stevel struct stat stbuf; 67 0 stevel OM_uint32 major = GSS_S_COMPLETE; 68 0 stevel 69 0 stevel (void) mutex_lock(&qopfile_lock); 70 0 stevel if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) { 71 0 stevel if (!qop_num_pairs[0].qop) { 72 0 stevel major = GSS_S_FAILURE; 73 0 stevel } 74 0 stevel goto done; 75 0 stevel } 76 0 stevel last = stbuf.st_mtime; 77 0 stevel 78 1914 casper fp = fopen(QOP_NUM_FILE, "rF"); 79 0 stevel if (fp == (FILE *)0) { 80 0 stevel major = GSS_S_FAILURE; 81 0 stevel goto done; 82 0 stevel } 83 0 stevel 84 0 stevel /* 85 0 stevel * For each line in the file parse it appropriately. 86 0 stevel * File format : qopname num(int) 87 0 stevel * Note that we silently ignore corrupt entries. 88 0 stevel */ 89 0 stevel qop_num_pair_cnt = 0; 90 0 stevel while (!feof(fp)) { 91 0 stevel line = fgets(buf, BUFLEN, fp); 92 0 stevel if (line == NULL) 93 0 stevel break; 94 0 stevel 95 0 stevel /* Skip comments and blank lines */ 96 0 stevel if ((*line == '#') || (*line == '\n')) 97 0 stevel continue; 98 0 stevel 99 0 stevel /* Skip trailing comments */ 100 0 stevel next = strchr(line, '#'); 101 0 stevel if (next) 102 0 stevel *next = '\0'; 103 0 stevel 104 0 stevel name = &(buf[0]); 105 0 stevel while (isspace(*name)) 106 0 stevel name++; 107 0 stevel if (*name == '\0') /* blank line */ 108 0 stevel continue; 109 0 stevel 110 0 stevel qopname = name; /* will contain qop name */ 111 0 stevel while (!isspace(*qopname)) 112 0 stevel qopname++; 113 0 stevel if (*qopname == '\0') { 114 0 stevel continue; 115 0 stevel } 116 0 stevel next = qopname+1; 117 0 stevel *qopname = '\0'; /* null terminate qopname */ 118 0 stevel qop_num_pairs[qop_num_pair_cnt].qop = strdup(name); 119 0 stevel if (qop_num_pairs[qop_num_pair_cnt].qop == NULL) 120 0 stevel continue; 121 0 stevel 122 0 stevel name = next; 123 0 stevel while (isspace(*name)) 124 0 stevel name++; 125 0 stevel if (*name == '\0') { /* end of line, no num */ 126 0 stevel free(qop_num_pairs[qop_num_pair_cnt].qop); 127 0 stevel continue; 128 0 stevel } 129 0 stevel num_str = name; /* will contain num (n) */ 130 0 stevel while (!isspace(*num_str)) 131 0 stevel num_str++; 132 0 stevel next = num_str+1; 133 0 stevel *num_str++ = '\0'; /* null terminate num_str */ 134 0 stevel 135 0 stevel qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name); 136 0 stevel name = next; 137 0 stevel while (isspace(*name)) 138 0 stevel name++; 139 0 stevel if (*name == '\0') { /* end of line, no mechanism */ 140 0 stevel free(qop_num_pairs[qop_num_pair_cnt].qop); 141 0 stevel continue; 142 0 stevel } 143 0 stevel num_str = name; /* will contain mech */ 144 0 stevel while (!isspace(*num_str)) 145 0 stevel num_str++; 146 0 stevel *num_str = '\0'; 147 0 stevel 148 0 stevel qop_num_pairs[qop_num_pair_cnt].mech = strdup(name); 149 0 stevel if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) { 150 0 stevel free(qop_num_pairs[qop_num_pair_cnt].qop); 151 0 stevel continue; 152 0 stevel } 153 0 stevel 154 0 stevel if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS) 155 0 stevel break; 156 0 stevel } 157 0 stevel (void) fclose(fp); 158 0 stevel done: 159 0 stevel (void) mutex_unlock(&qopfile_lock); 160 0 stevel return (major); 161 0 stevel } 162 0 stevel 163 0 stevel OM_uint32 164 0 stevel __gss_qop_to_num( 165 0 stevel char *qop, 166 0 stevel char *mech, 167 0 stevel OM_uint32 *num 168 0 stevel ) 169 0 stevel { 170 0 stevel int i; 171 0 stevel OM_uint32 major = GSS_S_FAILURE; 172 0 stevel 173 0 stevel if (!num) 174 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 175 0 stevel 176 0 stevel if (qop == NULL || strlen(qop) == 0 || 177 0 stevel strcasecmp(qop, Q_DEFAULT) == 0) { 178 0 stevel *num = GSS_C_QOP_DEFAULT; 179 0 stevel return (GSS_S_COMPLETE); 180 0 stevel } 181 0 stevel 182 0 stevel if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) 183 0 stevel return (major); 184 0 stevel 185 0 stevel for (i = 0; i < qop_num_pair_cnt; i++) { 186 0 stevel if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) && 187 0 stevel (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) { 188 0 stevel *num = qop_num_pairs[i].num; 189 0 stevel return (GSS_S_COMPLETE); 190 0 stevel } 191 0 stevel } 192 0 stevel 193 0 stevel return (GSS_S_FAILURE); 194 0 stevel } 195 0 stevel 196 0 stevel OM_uint32 197 0 stevel __gss_num_to_qop( 198 0 stevel char *mech, 199 0 stevel OM_uint32 num, 200 0 stevel char **qop 201 0 stevel ) 202 0 stevel { 203 0 stevel int i; 204 0 stevel OM_uint32 major; 205 0 stevel 206 0 stevel if (!qop) 207 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 208 0 stevel *qop = NULL; 209 0 stevel 210 0 stevel if (num == GSS_C_QOP_DEFAULT) { 211 0 stevel *qop = Q_DEFAULT; 212 0 stevel return (GSS_S_COMPLETE); 213 0 stevel } 214 0 stevel 215 0 stevel if (mech == NULL) 216 0 stevel return (GSS_S_CALL_INACCESSIBLE_READ); 217 0 stevel 218 0 stevel if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) 219 0 stevel return (major); 220 0 stevel 221 0 stevel for (i = 0; i < qop_num_pair_cnt; i++) { 222 0 stevel if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) && 223 0 stevel (num == qop_num_pairs[i].num)) { 224 0 stevel *qop = qop_num_pairs[i].qop; 225 0 stevel return (GSS_S_COMPLETE); 226 0 stevel } 227 0 stevel } 228 0 stevel return (GSS_S_FAILURE); 229 0 stevel } 230 0 stevel 231 0 stevel /* 232 0 stevel * For a given mechanism pass back qop information about it in a buffer 233 0 stevel * of size MAX_QOPS_PER_MECH+1. 234 0 stevel */ 235 0 stevel OM_uint32 236 0 stevel __gss_get_mech_info( 237 0 stevel char *mech, 238 0 stevel char **qops 239 0 stevel ) 240 0 stevel { 241 0 stevel int i, cnt = 0; 242 0 stevel OM_uint32 major = GSS_S_COMPLETE; 243 0 stevel 244 0 stevel if (!qops) 245 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 246 0 stevel *qops = NULL; 247 0 stevel 248 0 stevel if (!mech) 249 0 stevel return (GSS_S_CALL_INACCESSIBLE_READ); 250 0 stevel 251 0 stevel if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) 252 0 stevel return (major); 253 0 stevel 254 0 stevel for (i = 0; i < qop_num_pair_cnt; i++) { 255 0 stevel if (strcmp(mech, qop_num_pairs[i].mech) == 0) { 256 0 stevel if (cnt >= MAX_QOPS_PER_MECH) { 257 0 stevel return (GSS_S_FAILURE); 258 0 stevel } 259 0 stevel qops[cnt++] = qop_num_pairs[i].qop; 260 0 stevel } 261 0 stevel } 262 0 stevel qops[cnt] = NULL; 263 0 stevel return (GSS_S_COMPLETE); 264 0 stevel } 265 0 stevel 266 0 stevel /* 267 0 stevel * Copy the qop values and names for the mechanism back in a qop_num 268 0 stevel * buffer of size MAX_QOPS_PER_MECH provided by the caller. 269 0 stevel */ 270 0 stevel OM_uint32 271 0 stevel __gss_mech_qops( 272 0 stevel char *mech, 273 0 stevel qop_num *mechqops, 274 0 stevel int *numqop 275 0 stevel ) 276 0 stevel { 277 0 stevel int i; 278 0 stevel OM_uint32 major; 279 0 stevel int cnt = 0; 280 0 stevel 281 0 stevel if (!mechqops || !numqop) 282 0 stevel return (GSS_S_CALL_INACCESSIBLE_WRITE); 283 0 stevel *numqop = 0; 284 0 stevel 285 0 stevel if (!mech) 286 0 stevel return (GSS_S_CALL_INACCESSIBLE_READ); 287 0 stevel 288 0 stevel if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) 289 0 stevel return (major); 290 0 stevel 291 0 stevel for (i = 0; i < qop_num_pair_cnt; i++) { 292 0 stevel if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) { 293 0 stevel if (cnt >= MAX_QOPS_PER_MECH) { 294 0 stevel return (GSS_S_FAILURE); 295 0 stevel } 296 0 stevel mechqops[cnt++] = qop_num_pairs[i]; 297 0 stevel } 298 0 stevel } 299 0 stevel *numqop = cnt; 300 0 stevel return (GSS_S_COMPLETE); 301 0 stevel } 302