5488N/A/*
5488N/A * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
5488N/A */
5488N/A
5488N/A#include "mglueP.h"
5488N/A#include "gssapiP_krb5.h"
5488N/A
5488N/A#include <sys/types.h>
5488N/A#include <sys/stat.h>
5488N/A#include <stdio.h>
5488N/A#include <stdlib.h>
5488N/A#include <strings.h>
5488N/A#include <ctype.h>
5488N/A#include <errno.h>
5488N/A/*
5488N/A#include <gssapi/gssapi.h>
5488N/A#include <gssapi/gssapi_ext.h>
5488N/A*/
5488N/A#include <synch.h>
5488N/A
5488N/A#define Q_DEFAULT "default"
5488N/A#define BUFLEN 256
5488N/A
5488N/Astatic int qop_num_pair_cnt;
5488N/Astatic const char QOP_NUM_FILE[] = "/etc/gss/qop";
5488N/Astatic qop_num qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
5488N/Astatic mutex_t qopfile_lock = DEFAULTMUTEX;
5488N/A
5488N/Astatic OM_uint32 __gss_read_qop_file(void);
5488N/A
5488N/A/*
5488N/A * This routine fetches qop and num from "/etc/gss/qop".
5488N/A * There is a memory leak associated with rereading this file,
5488N/A * because we can't free the qop_num_pairs array when we reread
5488N/A * the file (some callers may have been given these pointers).
5488N/A * In general, this memory leak should be a small one, because
5488N/A * we don't expect the qop file to be changed and reread often.
5488N/A */
5488N/Astatic OM_uint32
5488N/A__gss_read_qop_file(void)
5488N/A{
5488N/A char buf[BUFLEN]; /* one line from the file */
5488N/A char *name, *next;
5488N/A char *qopname, *num_str;
5488N/A char *line;
5488N/A FILE *fp;
5488N/A static int last = 0;
5488N/A struct stat stbuf;
5488N/A OM_uint32 major = GSS_S_COMPLETE;
5488N/A
5488N/A (void) mutex_lock(&qopfile_lock);
5488N/A if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
5488N/A if (!qop_num_pairs[0].qop) {
5488N/A major = GSS_S_FAILURE;
5488N/A }
5488N/A goto done;
5488N/A }
5488N/A last = stbuf.st_mtime;
5488N/A
5488N/A fp = fopen(QOP_NUM_FILE, "rF");
5488N/A if (fp == (FILE *)0) {
5488N/A major = GSS_S_FAILURE;
5488N/A goto done;
5488N/A }
5488N/A
5488N/A /*
5488N/A * For each line in the file parse it appropriately.
5488N/A * File format : qopname num(int)
5488N/A * Note that we silently ignore corrupt entries.
5488N/A */
5488N/A qop_num_pair_cnt = 0;
5488N/A while (!feof(fp)) {
5488N/A line = fgets(buf, BUFLEN, fp);
5488N/A if (line == NULL)
5488N/A break;
5488N/A
5488N/A /* Skip comments and blank lines */
5488N/A if ((*line == '#') || (*line == '\n'))
5488N/A continue;
5488N/A
5488N/A /* Skip trailing comments */
5488N/A next = strchr(line, '#');
5488N/A if (next)
5488N/A *next = '\0';
5488N/A
5488N/A name = &(buf[0]);
5488N/A while (isspace(*name))
5488N/A name++;
5488N/A if (*name == '\0') /* blank line */
5488N/A continue;
5488N/A
5488N/A qopname = name; /* will contain qop name */
5488N/A while (!isspace(*qopname))
5488N/A qopname++;
5488N/A if (*qopname == '\0') {
5488N/A continue;
5488N/A }
5488N/A next = qopname+1;
5488N/A *qopname = '\0'; /* null terminate qopname */
5488N/A qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
5488N/A if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
5488N/A continue;
5488N/A
5488N/A name = next;
5488N/A while (isspace(*name))
5488N/A name++;
5488N/A if (*name == '\0') { /* end of line, no num */
5488N/A free(qop_num_pairs[qop_num_pair_cnt].qop);
5488N/A continue;
5488N/A }
5488N/A num_str = name; /* will contain num (n) */
5488N/A while (!isspace(*num_str))
5488N/A num_str++;
5488N/A next = num_str+1;
5488N/A *num_str++ = '\0'; /* null terminate num_str */
5488N/A
5488N/A qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
5488N/A name = next;
5488N/A while (isspace(*name))
5488N/A name++;
5488N/A if (*name == '\0') { /* end of line, no mechanism */
5488N/A free(qop_num_pairs[qop_num_pair_cnt].qop);
5488N/A continue;
5488N/A }
5488N/A num_str = name; /* will contain mech */
5488N/A while (!isspace(*num_str))
5488N/A num_str++;
5488N/A *num_str = '\0';
5488N/A
5488N/A qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
5488N/A if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
5488N/A free(qop_num_pairs[qop_num_pair_cnt].qop);
5488N/A continue;
5488N/A }
5488N/A
5488N/A if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
5488N/A break;
5488N/A }
5488N/A (void) fclose(fp);
5488N/Adone:
5488N/A (void) mutex_unlock(&qopfile_lock);
5488N/A return (major);
5488N/A}
5488N/A
5488N/AOM_uint32
5488N/Agssint_qop_to_num(
5488N/A char *qop,
5488N/A char *mech,
5488N/A OM_uint32 *num
5488N/A)
5488N/A{
5488N/A int i;
5488N/A OM_uint32 major = GSS_S_FAILURE;
5488N/A
5488N/A if (!num)
5488N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
5488N/A
5488N/A if (qop == NULL || strlen(qop) == 0 ||
5488N/A strcasecmp(qop, Q_DEFAULT) == 0) {
5488N/A *num = GSS_C_QOP_DEFAULT;
5488N/A return (GSS_S_COMPLETE);
5488N/A }
5488N/A
5488N/A if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
5488N/A return (major);
5488N/A
5488N/A for (i = 0; i < qop_num_pair_cnt; i++) {
5488N/A if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
5488N/A (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
5488N/A *num = qop_num_pairs[i].num;
5488N/A return (GSS_S_COMPLETE);
5488N/A }
5488N/A }
5488N/A
5488N/A return (GSS_S_FAILURE);
5488N/A}
5488N/A
5488N/AOM_uint32
5488N/Agssint_num_to_qop(
5488N/A char *mech,
5488N/A OM_uint32 num,
5488N/A char **qop
5488N/A)
5488N/A{
5488N/A int i;
5488N/A OM_uint32 major;
5488N/A
5488N/A if (!qop)
5488N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
5488N/A *qop = NULL;
5488N/A
5488N/A if (num == GSS_C_QOP_DEFAULT) {
5488N/A *qop = Q_DEFAULT;
5488N/A return (GSS_S_COMPLETE);
5488N/A }
5488N/A
5488N/A if (mech == NULL)
5488N/A return (GSS_S_CALL_INACCESSIBLE_READ);
5488N/A
5488N/A if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
5488N/A return (major);
5488N/A
5488N/A for (i = 0; i < qop_num_pair_cnt; i++) {
5488N/A if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
5488N/A (num == qop_num_pairs[i].num)) {
5488N/A *qop = qop_num_pairs[i].qop;
5488N/A return (GSS_S_COMPLETE);
5488N/A }
5488N/A }
5488N/A return (GSS_S_FAILURE);
5488N/A}
5488N/A
5488N/A/*
5488N/A * For a given mechanism pass back qop information about it in a buffer
5488N/A * of size MAX_QOPS_PER_MECH+1.
5488N/A */
5488N/AOM_uint32
5488N/Agssint_get_mech_info(
5488N/A char *mech,
5488N/A char **qops
5488N/A)
5488N/A{
5488N/A int i, cnt = 0;
5488N/A OM_uint32 major = GSS_S_COMPLETE;
5488N/A
5488N/A if (!qops)
5488N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
5488N/A *qops = NULL;
5488N/A
5488N/A if (!mech)
5488N/A return (GSS_S_CALL_INACCESSIBLE_READ);
5488N/A
5488N/A if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
5488N/A return (major);
5488N/A
5488N/A for (i = 0; i < qop_num_pair_cnt; i++) {
5488N/A if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
5488N/A if (cnt >= MAX_QOPS_PER_MECH) {
5488N/A return (GSS_S_FAILURE);
5488N/A }
5488N/A qops[cnt++] = qop_num_pairs[i].qop;
5488N/A }
5488N/A }
5488N/A qops[cnt] = NULL;
5488N/A return (GSS_S_COMPLETE);
5488N/A}