#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);
static OM_uint32
__gss_read_qop_file(void)
{
char buf[BUFLEN];
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;
}
qop_num_pair_cnt = 0;
while (!feof(fp)) {
line = fgets(buf, BUFLEN, fp);
if (line == NULL)
break;
if ((*line == '#') || (*line == '\n'))
continue;
next = strchr(line, '#');
if (next)
*next = '\0';
name = &(buf[0]);
while (isspace(*name))
name++;
if (*name == '\0')
continue;
qopname = name;
while (!isspace(*qopname))
qopname++;
if (*qopname == '\0') {
continue;
}
next = qopname+1;
*qopname = '\0';
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') {
free(qop_num_pairs[qop_num_pair_cnt].qop);
continue;
}
num_str = name;
while (!isspace(*num_str))
num_str++;
next = num_str+1;
*num_str++ = '\0';
qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
name = next;
while (isspace(*name))
name++;
if (*name == '\0') {
free(qop_num_pairs[qop_num_pair_cnt].qop);
continue;
}
num_str = name;
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);
}
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);
}
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);
}