/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #define Q_DEFAULT "default" #define BUFLEN 256 static int qop_num_pair_cnt; static const char QOP_NUM_FILE[] = "/etc/gss/qop"; static qop_num qop_num_pairs[MAX_QOP_NUM_PAIRS+1]; static mutex_t qopfile_lock = DEFAULTMUTEX; static OM_uint32 __gss_read_qop_file(void); /* * This routine fetches qop and num from "/etc/gss/qop". * There is a memory leak associated with rereading this file, * because we can't free the qop_num_pairs array when we reread * the file (some callers may have been given these pointers). * In general, this memory leak should be a small one, because * we don't expect the qop file to be changed and reread often. */ static OM_uint32 __gss_read_qop_file(void) { char buf[BUFLEN]; /* one line from the file */ char *name, *next; char *qopname, *num_str; char *line; FILE *fp; static int last = 0; struct stat stbuf; OM_uint32 major = GSS_S_COMPLETE; (void) mutex_lock(&qopfile_lock); if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) { if (!qop_num_pairs[0].qop) { major = GSS_S_FAILURE; } goto done; } last = stbuf.st_mtime; fp = fopen(QOP_NUM_FILE, "r"); if (fp == (FILE *)0) { major = GSS_S_FAILURE; goto done; } /* * For each line in the file parse it appropriately. * File format : qopname num(int) * Note that we silently ignore corrupt entries. */ qop_num_pair_cnt = 0; while (!feof(fp)) { line = fgets(buf, BUFLEN, fp); if (line == NULL) break; /* Skip comments and blank lines */ if ((*line == '#') || (*line == '\n')) continue; /* Skip trailing comments */ next = strchr(line, '#'); if (next) *next = '\0'; name = &(buf[0]); while (isspace(*name)) name++; if (*name == '\0') /* blank line */ continue; qopname = name; /* will contain qop name */ while (!isspace(*qopname)) qopname++; if (*qopname == '\0') { continue; } next = qopname+1; *qopname = '\0'; /* null terminate qopname */ qop_num_pairs[qop_num_pair_cnt].qop = strdup(name); if (qop_num_pairs[qop_num_pair_cnt].qop == NULL) continue; name = next; while (isspace(*name)) name++; if (*name == '\0') { /* end of line, no num */ free(qop_num_pairs[qop_num_pair_cnt].qop); continue; } num_str = name; /* will contain num (n) */ while (!isspace(*num_str)) num_str++; next = num_str+1; *num_str++ = '\0'; /* null terminate num_str */ qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name); name = next; while (isspace(*name)) name++; if (*name == '\0') { /* end of line, no mechanism */ free(qop_num_pairs[qop_num_pair_cnt].qop); continue; } num_str = name; /* will contain mech */ while (!isspace(*num_str)) num_str++; *num_str = '\0'; qop_num_pairs[qop_num_pair_cnt].mech = strdup(name); if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) { free(qop_num_pairs[qop_num_pair_cnt].qop); continue; } if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS) break; } (void) fclose(fp); done: (void) mutex_unlock(&qopfile_lock); return (major); } OM_uint32 __gss_qop_to_num( char *qop, char *mech, OM_uint32 *num ) { int i; OM_uint32 major = GSS_S_FAILURE; if (!num) return (GSS_S_CALL_INACCESSIBLE_WRITE); if (qop == NULL || strlen(qop) == 0 || strcasecmp(qop, Q_DEFAULT) == 0) { *num = GSS_C_QOP_DEFAULT; return (GSS_S_COMPLETE); } if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) return (major); for (i = 0; i < qop_num_pair_cnt; i++) { if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) && (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) { *num = qop_num_pairs[i].num; return (GSS_S_COMPLETE); } } return (GSS_S_FAILURE); } OM_uint32 __gss_num_to_qop( char *mech, OM_uint32 num, char **qop ) { int i; OM_uint32 major; if (!qop) return (GSS_S_CALL_INACCESSIBLE_WRITE); *qop = NULL; if (num == GSS_C_QOP_DEFAULT) { *qop = Q_DEFAULT; return (GSS_S_COMPLETE); } if (mech == NULL) return (GSS_S_CALL_INACCESSIBLE_READ); if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) return (major); for (i = 0; i < qop_num_pair_cnt; i++) { if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) && (num == qop_num_pairs[i].num)) { *qop = qop_num_pairs[i].qop; return (GSS_S_COMPLETE); } } return (GSS_S_FAILURE); } /* * For a given mechanism pass back qop information about it in a buffer * of size MAX_QOPS_PER_MECH+1. */ OM_uint32 __gss_get_mech_info( char *mech, char **qops ) { int i, cnt = 0; OM_uint32 major = GSS_S_COMPLETE; if (!qops) return (GSS_S_CALL_INACCESSIBLE_WRITE); *qops = NULL; if (!mech) return (GSS_S_CALL_INACCESSIBLE_READ); if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) return (major); for (i = 0; i < qop_num_pair_cnt; i++) { if (strcmp(mech, qop_num_pairs[i].mech) == 0) { if (cnt >= MAX_QOPS_PER_MECH) { return (GSS_S_FAILURE); } qops[cnt++] = qop_num_pairs[i].qop; } } qops[cnt] = NULL; return (GSS_S_COMPLETE); } /* * Copy the qop values and names for the mechanism back in a qop_num * buffer of size MAX_QOPS_PER_MECH provided by the caller. */ OM_uint32 __gss_mech_qops( char *mech, qop_num *mechqops, int *numqop ) { int i; OM_uint32 major; int cnt = 0; if (!mechqops || !numqop) return (GSS_S_CALL_INACCESSIBLE_WRITE); *numqop = 0; if (!mech) return (GSS_S_CALL_INACCESSIBLE_READ); if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE) return (major); for (i = 0; i < qop_num_pair_cnt; i++) { if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) { if (cnt >= MAX_QOPS_PER_MECH) { return (GSS_S_FAILURE); } mechqops[cnt++] = qop_num_pairs[i]; } } *numqop = cnt; return (GSS_S_COMPLETE); }