10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*1914Scasper * Common Development and Distribution License (the "License").
6*1914Scasper * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*1914Scasper * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/stat.h>
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <strings.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <gssapi/gssapi.h>
360Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
370Sstevel@tonic-gate #include <synch.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate #define Q_DEFAULT "default"
400Sstevel@tonic-gate #define BUFLEN 256
410Sstevel@tonic-gate
420Sstevel@tonic-gate static int qop_num_pair_cnt;
430Sstevel@tonic-gate static const char QOP_NUM_FILE[] = "/etc/gss/qop";
440Sstevel@tonic-gate static qop_num qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
450Sstevel@tonic-gate static mutex_t qopfile_lock = DEFAULTMUTEX;
460Sstevel@tonic-gate
470Sstevel@tonic-gate static OM_uint32 __gss_read_qop_file(void);
480Sstevel@tonic-gate
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate * This routine fetches qop and num from "/etc/gss/qop".
510Sstevel@tonic-gate * There is a memory leak associated with rereading this file,
520Sstevel@tonic-gate * because we can't free the qop_num_pairs array when we reread
530Sstevel@tonic-gate * the file (some callers may have been given these pointers).
540Sstevel@tonic-gate * In general, this memory leak should be a small one, because
550Sstevel@tonic-gate * we don't expect the qop file to be changed and reread often.
560Sstevel@tonic-gate */
570Sstevel@tonic-gate static OM_uint32
__gss_read_qop_file(void)580Sstevel@tonic-gate __gss_read_qop_file(void)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate char buf[BUFLEN]; /* one line from the file */
610Sstevel@tonic-gate char *name, *next;
620Sstevel@tonic-gate char *qopname, *num_str;
630Sstevel@tonic-gate char *line;
640Sstevel@tonic-gate FILE *fp;
650Sstevel@tonic-gate static int last = 0;
660Sstevel@tonic-gate struct stat stbuf;
670Sstevel@tonic-gate OM_uint32 major = GSS_S_COMPLETE;
680Sstevel@tonic-gate
690Sstevel@tonic-gate (void) mutex_lock(&qopfile_lock);
700Sstevel@tonic-gate if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
710Sstevel@tonic-gate if (!qop_num_pairs[0].qop) {
720Sstevel@tonic-gate major = GSS_S_FAILURE;
730Sstevel@tonic-gate }
740Sstevel@tonic-gate goto done;
750Sstevel@tonic-gate }
760Sstevel@tonic-gate last = stbuf.st_mtime;
770Sstevel@tonic-gate
78*1914Scasper fp = fopen(QOP_NUM_FILE, "rF");
790Sstevel@tonic-gate if (fp == (FILE *)0) {
800Sstevel@tonic-gate major = GSS_S_FAILURE;
810Sstevel@tonic-gate goto done;
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * For each line in the file parse it appropriately.
860Sstevel@tonic-gate * File format : qopname num(int)
870Sstevel@tonic-gate * Note that we silently ignore corrupt entries.
880Sstevel@tonic-gate */
890Sstevel@tonic-gate qop_num_pair_cnt = 0;
900Sstevel@tonic-gate while (!feof(fp)) {
910Sstevel@tonic-gate line = fgets(buf, BUFLEN, fp);
920Sstevel@tonic-gate if (line == NULL)
930Sstevel@tonic-gate break;
940Sstevel@tonic-gate
950Sstevel@tonic-gate /* Skip comments and blank lines */
960Sstevel@tonic-gate if ((*line == '#') || (*line == '\n'))
970Sstevel@tonic-gate continue;
980Sstevel@tonic-gate
990Sstevel@tonic-gate /* Skip trailing comments */
1000Sstevel@tonic-gate next = strchr(line, '#');
1010Sstevel@tonic-gate if (next)
1020Sstevel@tonic-gate *next = '\0';
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate name = &(buf[0]);
1050Sstevel@tonic-gate while (isspace(*name))
1060Sstevel@tonic-gate name++;
1070Sstevel@tonic-gate if (*name == '\0') /* blank line */
1080Sstevel@tonic-gate continue;
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate qopname = name; /* will contain qop name */
1110Sstevel@tonic-gate while (!isspace(*qopname))
1120Sstevel@tonic-gate qopname++;
1130Sstevel@tonic-gate if (*qopname == '\0') {
1140Sstevel@tonic-gate continue;
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate next = qopname+1;
1170Sstevel@tonic-gate *qopname = '\0'; /* null terminate qopname */
1180Sstevel@tonic-gate qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
1190Sstevel@tonic-gate if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
1200Sstevel@tonic-gate continue;
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate name = next;
1230Sstevel@tonic-gate while (isspace(*name))
1240Sstevel@tonic-gate name++;
1250Sstevel@tonic-gate if (*name == '\0') { /* end of line, no num */
1260Sstevel@tonic-gate free(qop_num_pairs[qop_num_pair_cnt].qop);
1270Sstevel@tonic-gate continue;
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate num_str = name; /* will contain num (n) */
1300Sstevel@tonic-gate while (!isspace(*num_str))
1310Sstevel@tonic-gate num_str++;
1320Sstevel@tonic-gate next = num_str+1;
1330Sstevel@tonic-gate *num_str++ = '\0'; /* null terminate num_str */
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
1360Sstevel@tonic-gate name = next;
1370Sstevel@tonic-gate while (isspace(*name))
1380Sstevel@tonic-gate name++;
1390Sstevel@tonic-gate if (*name == '\0') { /* end of line, no mechanism */
1400Sstevel@tonic-gate free(qop_num_pairs[qop_num_pair_cnt].qop);
1410Sstevel@tonic-gate continue;
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate num_str = name; /* will contain mech */
1440Sstevel@tonic-gate while (!isspace(*num_str))
1450Sstevel@tonic-gate num_str++;
1460Sstevel@tonic-gate *num_str = '\0';
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
1490Sstevel@tonic-gate if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
1500Sstevel@tonic-gate free(qop_num_pairs[qop_num_pair_cnt].qop);
1510Sstevel@tonic-gate continue;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
1550Sstevel@tonic-gate break;
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate (void) fclose(fp);
1580Sstevel@tonic-gate done:
1590Sstevel@tonic-gate (void) mutex_unlock(&qopfile_lock);
1600Sstevel@tonic-gate return (major);
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate OM_uint32
__gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)1640Sstevel@tonic-gate __gss_qop_to_num(
1650Sstevel@tonic-gate char *qop,
1660Sstevel@tonic-gate char *mech,
1670Sstevel@tonic-gate OM_uint32 *num
1680Sstevel@tonic-gate )
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate int i;
1710Sstevel@tonic-gate OM_uint32 major = GSS_S_FAILURE;
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate if (!num)
1740Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_WRITE);
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate if (qop == NULL || strlen(qop) == 0 ||
1770Sstevel@tonic-gate strcasecmp(qop, Q_DEFAULT) == 0) {
1780Sstevel@tonic-gate *num = GSS_C_QOP_DEFAULT;
1790Sstevel@tonic-gate return (GSS_S_COMPLETE);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
1830Sstevel@tonic-gate return (major);
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate for (i = 0; i < qop_num_pair_cnt; i++) {
1860Sstevel@tonic-gate if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
1870Sstevel@tonic-gate (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
1880Sstevel@tonic-gate *num = qop_num_pairs[i].num;
1890Sstevel@tonic-gate return (GSS_S_COMPLETE);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate return (GSS_S_FAILURE);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate OM_uint32
__gss_num_to_qop(char * mech,OM_uint32 num,char ** qop)1970Sstevel@tonic-gate __gss_num_to_qop(
1980Sstevel@tonic-gate char *mech,
1990Sstevel@tonic-gate OM_uint32 num,
2000Sstevel@tonic-gate char **qop
2010Sstevel@tonic-gate )
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate int i;
2040Sstevel@tonic-gate OM_uint32 major;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate if (!qop)
2070Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_WRITE);
2080Sstevel@tonic-gate *qop = NULL;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate if (num == GSS_C_QOP_DEFAULT) {
2110Sstevel@tonic-gate *qop = Q_DEFAULT;
2120Sstevel@tonic-gate return (GSS_S_COMPLETE);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate if (mech == NULL)
2160Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_READ);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
2190Sstevel@tonic-gate return (major);
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate for (i = 0; i < qop_num_pair_cnt; i++) {
2220Sstevel@tonic-gate if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
2230Sstevel@tonic-gate (num == qop_num_pairs[i].num)) {
2240Sstevel@tonic-gate *qop = qop_num_pairs[i].qop;
2250Sstevel@tonic-gate return (GSS_S_COMPLETE);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate return (GSS_S_FAILURE);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate * For a given mechanism pass back qop information about it in a buffer
2330Sstevel@tonic-gate * of size MAX_QOPS_PER_MECH+1.
2340Sstevel@tonic-gate */
2350Sstevel@tonic-gate OM_uint32
__gss_get_mech_info(char * mech,char ** qops)2360Sstevel@tonic-gate __gss_get_mech_info(
2370Sstevel@tonic-gate char *mech,
2380Sstevel@tonic-gate char **qops
2390Sstevel@tonic-gate )
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate int i, cnt = 0;
2420Sstevel@tonic-gate OM_uint32 major = GSS_S_COMPLETE;
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate if (!qops)
2450Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_WRITE);
2460Sstevel@tonic-gate *qops = NULL;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate if (!mech)
2490Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_READ);
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
2520Sstevel@tonic-gate return (major);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate for (i = 0; i < qop_num_pair_cnt; i++) {
2550Sstevel@tonic-gate if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
2560Sstevel@tonic-gate if (cnt >= MAX_QOPS_PER_MECH) {
2570Sstevel@tonic-gate return (GSS_S_FAILURE);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate qops[cnt++] = qop_num_pairs[i].qop;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate qops[cnt] = NULL;
2630Sstevel@tonic-gate return (GSS_S_COMPLETE);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * Copy the qop values and names for the mechanism back in a qop_num
2680Sstevel@tonic-gate * buffer of size MAX_QOPS_PER_MECH provided by the caller.
2690Sstevel@tonic-gate */
2700Sstevel@tonic-gate OM_uint32
__gss_mech_qops(char * mech,qop_num * mechqops,int * numqop)2710Sstevel@tonic-gate __gss_mech_qops(
2720Sstevel@tonic-gate char *mech,
2730Sstevel@tonic-gate qop_num *mechqops,
2740Sstevel@tonic-gate int *numqop
2750Sstevel@tonic-gate )
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate int i;
2780Sstevel@tonic-gate OM_uint32 major;
2790Sstevel@tonic-gate int cnt = 0;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate if (!mechqops || !numqop)
2820Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_WRITE);
2830Sstevel@tonic-gate *numqop = 0;
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate if (!mech)
2860Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_READ);
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
2890Sstevel@tonic-gate return (major);
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate for (i = 0; i < qop_num_pair_cnt; i++) {
2920Sstevel@tonic-gate if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
2930Sstevel@tonic-gate if (cnt >= MAX_QOPS_PER_MECH) {
2940Sstevel@tonic-gate return (GSS_S_FAILURE);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate mechqops[cnt++] = qop_num_pairs[i];
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate *numqop = cnt;
3000Sstevel@tonic-gate return (GSS_S_COMPLETE);
3010Sstevel@tonic-gate }
302