| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <strings.h> |
| #include <ctype.h> |
| #include <errno.h> |
| #include <gssapi/gssapi.h> |
| #include <gssapi/gssapi_ext.h> |
| #include <synch.h> |
| |
| #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, "rF"); |
| 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); |
| } |