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
57693SVallish.Vaidyeshwara@Sun.COM * Common Development and Distribution License (the "License").
67693SVallish.Vaidyeshwara@Sun.COM * 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 /* LINTLIBRARY */
220Sstevel@tonic-gate
230Sstevel@tonic-gate /*
24*8650SVallish.Vaidyeshwara@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
250Sstevel@tonic-gate * Use is subject to license terms.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * nfs security related library routines.
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * Some of the routines in this file are adopted from
320Sstevel@tonic-gate * lib/libnsl/netselect/netselect.c and are modified to be
330Sstevel@tonic-gate * used for accessing /etc/nfssec.conf.
340Sstevel@tonic-gate */
350Sstevel@tonic-gate
360Sstevel@tonic-gate /* SVr4.0 1.18 */
370Sstevel@tonic-gate
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <ctype.h>
410Sstevel@tonic-gate #include <stdlib.h>
420Sstevel@tonic-gate #include <syslog.h>
430Sstevel@tonic-gate #include <synch.h>
440Sstevel@tonic-gate #include <rpc/rpc.h>
450Sstevel@tonic-gate #include <nfs/nfs_sec.h>
460Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
470Sstevel@tonic-gate #ifdef WNFS_SEC_NEGO
480Sstevel@tonic-gate #include "webnfs.h"
490Sstevel@tonic-gate #endif
500Sstevel@tonic-gate
510Sstevel@tonic-gate #define GETBYNAME 1
520Sstevel@tonic-gate #define GETBYNUM 2
530Sstevel@tonic-gate
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate * mapping for /etc/nfssec.conf
560Sstevel@tonic-gate */
570Sstevel@tonic-gate struct sc_data {
580Sstevel@tonic-gate char *string;
590Sstevel@tonic-gate int value;
600Sstevel@tonic-gate };
610Sstevel@tonic-gate
620Sstevel@tonic-gate static struct sc_data sc_service[] = {
630Sstevel@tonic-gate "default", rpc_gss_svc_default,
640Sstevel@tonic-gate "-", rpc_gss_svc_none,
650Sstevel@tonic-gate "none", rpc_gss_svc_none,
660Sstevel@tonic-gate "integrity", rpc_gss_svc_integrity,
670Sstevel@tonic-gate "privacy", rpc_gss_svc_privacy,
680Sstevel@tonic-gate NULL, SC_FAILURE
690Sstevel@tonic-gate };
700Sstevel@tonic-gate
710Sstevel@tonic-gate static char *gettoken(char *, int);
720Sstevel@tonic-gate extern int atoi(const char *str);
730Sstevel@tonic-gate
740Sstevel@tonic-gate extern bool_t rpc_gss_get_principal_name(rpc_gss_principal_t *, char *,
750Sstevel@tonic-gate char *, char *, char *);
760Sstevel@tonic-gate
770Sstevel@tonic-gate extern bool_t rpc_gss_mech_to_oid(char *, rpc_gss_OID *);
780Sstevel@tonic-gate extern bool_t rpc_gss_qop_to_num(char *, char *, uint_t *);
790Sstevel@tonic-gate
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * blank() returns true if the line is a blank line, 0 otherwise
820Sstevel@tonic-gate */
830Sstevel@tonic-gate static int
blank(cp)840Sstevel@tonic-gate blank(cp)
850Sstevel@tonic-gate char *cp;
860Sstevel@tonic-gate {
870Sstevel@tonic-gate while (*cp && isspace(*cp)) {
880Sstevel@tonic-gate cp++;
890Sstevel@tonic-gate }
900Sstevel@tonic-gate return (*cp == '\0');
910Sstevel@tonic-gate }
920Sstevel@tonic-gate
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate * comment() returns true if the line is a comment, 0 otherwise.
950Sstevel@tonic-gate */
960Sstevel@tonic-gate static int
comment(cp)970Sstevel@tonic-gate comment(cp)
980Sstevel@tonic-gate char *cp;
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate while (*cp && isspace(*cp)) {
1010Sstevel@tonic-gate cp++;
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate return (*cp == '#');
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate * getvalue() searches for the given string in the given array,
1090Sstevel@tonic-gate * and returns the integer value associated with the string.
1100Sstevel@tonic-gate */
1110Sstevel@tonic-gate static unsigned long
getvalue(cp,sc_data)1120Sstevel@tonic-gate getvalue(cp, sc_data)
1130Sstevel@tonic-gate char *cp;
1140Sstevel@tonic-gate struct sc_data sc_data[];
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate int i; /* used to index through the given struct sc_data array */
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate for (i = 0; sc_data[i].string; i++) {
1190Sstevel@tonic-gate if (strcmp(sc_data[i].string, cp) == 0) {
1200Sstevel@tonic-gate break;
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate return (sc_data[i].value);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate * shift1left() moves all characters in the string over 1 to
1280Sstevel@tonic-gate * the left.
1290Sstevel@tonic-gate */
1300Sstevel@tonic-gate static void
shift1left(p)1310Sstevel@tonic-gate shift1left(p)
1320Sstevel@tonic-gate char *p;
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate for (; *p; p++)
1350Sstevel@tonic-gate *p = *(p + 1);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate * gettoken() behaves much like strtok(), except that
1410Sstevel@tonic-gate * it knows about escaped space characters (i.e., space characters
1420Sstevel@tonic-gate * preceeded by a '\' are taken literally).
1430Sstevel@tonic-gate *
1440Sstevel@tonic-gate * XXX We should make this MT-hot by making it more like strtok_r().
1450Sstevel@tonic-gate */
1460Sstevel@tonic-gate static char *
gettoken(cp,skip)1470Sstevel@tonic-gate gettoken(cp, skip)
1480Sstevel@tonic-gate char *cp;
1490Sstevel@tonic-gate int skip;
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate static char *savep; /* the place where we left off */
1520Sstevel@tonic-gate register char *p; /* the beginning of the new token */
1530Sstevel@tonic-gate register char *retp; /* the token to be returned */
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /* Determine if first or subsequent call */
1570Sstevel@tonic-gate p = (cp == NULL)? savep: cp;
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate /* Return if no tokens remain. */
1600Sstevel@tonic-gate if (p == 0) {
1610Sstevel@tonic-gate return (NULL);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate while (isspace(*p))
1650Sstevel@tonic-gate p++;
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate if (*p == '\0') {
1680Sstevel@tonic-gate return (NULL);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate * Save the location of the token and then skip past it
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate retp = p;
1760Sstevel@tonic-gate while (*p) {
1770Sstevel@tonic-gate if (isspace(*p))
1780Sstevel@tonic-gate if (skip == TRUE) {
1790Sstevel@tonic-gate shift1left(p);
1800Sstevel@tonic-gate continue;
1810Sstevel@tonic-gate } else
1820Sstevel@tonic-gate break;
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * Only process the escape of the space separator;
1850Sstevel@tonic-gate * since the token may contain other separators,
1860Sstevel@tonic-gate * let the other routines handle the escape of
1870Sstevel@tonic-gate * specific characters in the token.
1880Sstevel@tonic-gate */
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) {
1910Sstevel@tonic-gate shift1left(p);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate p++;
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate if (*p == '\0') {
1960Sstevel@tonic-gate savep = 0; /* indicate this is last token */
1970Sstevel@tonic-gate } else {
1980Sstevel@tonic-gate *p = '\0';
1990Sstevel@tonic-gate savep = ++p;
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate return (retp);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate /*
2050Sstevel@tonic-gate * matchname() parses a line of the /etc/nfssec.conf file
2060Sstevel@tonic-gate * and match the sc_name with the given name.
2070Sstevel@tonic-gate * If there is a match, it fills the information into the given
2080Sstevel@tonic-gate * pointer of the seconfig_t structure.
2090Sstevel@tonic-gate *
2100Sstevel@tonic-gate * Returns TRUE if a match is found.
2110Sstevel@tonic-gate */
2120Sstevel@tonic-gate static bool_t
matchname(char * line,char * name,seconfig_t * secp)2130Sstevel@tonic-gate matchname(char *line, char *name, seconfig_t *secp)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate char *tok1, *tok2; /* holds a token from the line */
2160Sstevel@tonic-gate char *secname, *gss_mech, *gss_qop; /* pointer to a secmode name */
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate if ((secname = gettoken(line, FALSE)) == NULL) {
2190Sstevel@tonic-gate /* bad line */
2200Sstevel@tonic-gate return (FALSE);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate if (strcmp(secname, name) != 0) {
2240Sstevel@tonic-gate return (FALSE);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate tok1 = tok2 = NULL;
2280Sstevel@tonic-gate if (((tok1 = gettoken(NULL, FALSE)) == NULL) ||
2297693SVallish.Vaidyeshwara@Sun.COM ((gss_mech = gettoken(NULL, FALSE)) == NULL) ||
2307693SVallish.Vaidyeshwara@Sun.COM ((gss_qop = gettoken(NULL, FALSE)) == NULL) ||
2317693SVallish.Vaidyeshwara@Sun.COM ((tok2 = gettoken(NULL, FALSE)) == NULL) ||
2327693SVallish.Vaidyeshwara@Sun.COM ((secp->sc_service = getvalue(tok2, sc_service))
2337693SVallish.Vaidyeshwara@Sun.COM == SC_FAILURE)) {
2340Sstevel@tonic-gate return (FALSE);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate secp->sc_nfsnum = atoi(tok1);
2370Sstevel@tonic-gate (void) strcpy(secp->sc_name, secname);
2380Sstevel@tonic-gate (void) strcpy(secp->sc_gss_mech, gss_mech);
2390Sstevel@tonic-gate secp->sc_gss_mech_type = NULL;
2400Sstevel@tonic-gate if (secp->sc_gss_mech[0] != '-') {
2417693SVallish.Vaidyeshwara@Sun.COM if (!rpc_gss_mech_to_oid(gss_mech, &secp->sc_gss_mech_type) ||
2427693SVallish.Vaidyeshwara@Sun.COM !rpc_gss_qop_to_num(gss_qop, gss_mech, &secp->sc_qop)) {
2437693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
2447693SVallish.Vaidyeshwara@Sun.COM }
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate return (TRUE);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate * matchnum() parses a line of the /etc/nfssec.conf file
2520Sstevel@tonic-gate * and match the sc_nfsnum with the given number.
2530Sstevel@tonic-gate * If it is a match, it fills the information in the given pointer
2540Sstevel@tonic-gate * of the seconfig_t structure.
2550Sstevel@tonic-gate *
2560Sstevel@tonic-gate * Returns TRUE if a match is found.
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate static bool_t
matchnum(char * line,int num,seconfig_t * secp)2590Sstevel@tonic-gate matchnum(char *line, int num, seconfig_t *secp)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate char *tok1, *tok2; /* holds a token from the line */
2620Sstevel@tonic-gate char *secname, *gss_mech, *gss_qop; /* pointer to a secmode name */
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if ((secname = gettoken(line, FALSE)) == NULL) {
2650Sstevel@tonic-gate /* bad line */
2660Sstevel@tonic-gate return (FALSE);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate tok1 = tok2 = NULL;
2700Sstevel@tonic-gate if ((tok1 = gettoken(NULL, FALSE)) == NULL) {
2710Sstevel@tonic-gate /* bad line */
2720Sstevel@tonic-gate return (FALSE);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate if ((secp->sc_nfsnum = atoi(tok1)) != num) {
2760Sstevel@tonic-gate return (FALSE);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate if (((gss_mech = gettoken(NULL, FALSE)) == NULL) ||
2807693SVallish.Vaidyeshwara@Sun.COM ((gss_qop = gettoken(NULL, FALSE)) == NULL) ||
2817693SVallish.Vaidyeshwara@Sun.COM ((tok2 = gettoken(NULL, FALSE)) == NULL) ||
2827693SVallish.Vaidyeshwara@Sun.COM ((secp->sc_service = getvalue(tok2, sc_service))
2837693SVallish.Vaidyeshwara@Sun.COM == SC_FAILURE)) {
2840Sstevel@tonic-gate return (FALSE);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate (void) strcpy(secp->sc_name, secname);
2880Sstevel@tonic-gate (void) strcpy(secp->sc_gss_mech, gss_mech);
2890Sstevel@tonic-gate if (secp->sc_gss_mech[0] != '-') {
2907693SVallish.Vaidyeshwara@Sun.COM if (!rpc_gss_mech_to_oid(gss_mech, &secp->sc_gss_mech_type) ||
2917693SVallish.Vaidyeshwara@Sun.COM !rpc_gss_qop_to_num(gss_qop, gss_mech, &secp->sc_qop)) {
2927693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
2937693SVallish.Vaidyeshwara@Sun.COM }
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate return (TRUE);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate /*
3000Sstevel@tonic-gate * Fill in the RPC Protocol security flavor number
3010Sstevel@tonic-gate * into the sc_rpcnum of seconfig_t structure.
3020Sstevel@tonic-gate *
3030Sstevel@tonic-gate * Mainly to map NFS secmod number to RPCSEC_GSS if
3040Sstevel@tonic-gate * a mechanism name is specified.
3050Sstevel@tonic-gate */
3060Sstevel@tonic-gate static void
get_rpcnum(seconfig_t * secp)3070Sstevel@tonic-gate get_rpcnum(seconfig_t *secp)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate if (secp->sc_gss_mech[0] != '-') {
3100Sstevel@tonic-gate secp->sc_rpcnum = RPCSEC_GSS;
3110Sstevel@tonic-gate } else {
3120Sstevel@tonic-gate secp->sc_rpcnum = secp->sc_nfsnum;
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * Parse a given hostname (nodename[.domain@realm]) to
3180Sstevel@tonic-gate * instant name (nodename[.domain]) and realm.
3190Sstevel@tonic-gate *
3200Sstevel@tonic-gate * Assuming user has allocated the space for inst and realm.
3210Sstevel@tonic-gate */
3220Sstevel@tonic-gate static int
parsehostname(char * hostname,char * inst,char * realm)3230Sstevel@tonic-gate parsehostname(char *hostname, char *inst, char *realm)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate char *h, *r;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate if (!hostname)
3280Sstevel@tonic-gate return (0);
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate h = (char *)strdup(hostname);
3310Sstevel@tonic-gate if (!h) {
3320Sstevel@tonic-gate syslog(LOG_ERR, "parsehostname: no memory\n");
3330Sstevel@tonic-gate return (0);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate r = (char *)strchr(h, '@');
3370Sstevel@tonic-gate if (!r) {
3380Sstevel@tonic-gate (void) strcpy(inst, h);
3390Sstevel@tonic-gate (void) strcpy(realm, "");
3400Sstevel@tonic-gate } else {
3410Sstevel@tonic-gate *r++ = '\0';
3420Sstevel@tonic-gate (void) strcpy(inst, h);
3430Sstevel@tonic-gate (void) strcpy(realm, r);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate free(h);
3460Sstevel@tonic-gate return (1);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate * Get the name corresponding to a qop num.
3510Sstevel@tonic-gate */
3520Sstevel@tonic-gate char *
nfs_get_qop_name(seconfig_t * entryp)3530Sstevel@tonic-gate nfs_get_qop_name(seconfig_t *entryp)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate char *tok; /* holds a token from the line */
3560Sstevel@tonic-gate char *secname, *gss_qop = NULL; /* pointer to a secmode name */
3570Sstevel@tonic-gate static mutex_t matching_lock = DEFAULTMUTEX;
3580Sstevel@tonic-gate char line[BUFSIZ]; /* holds each line of NFSSEC_CONF */
3590Sstevel@tonic-gate FILE *fp; /* file stream for NFSSEC_CONF */
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) {
3627693SVallish.Vaidyeshwara@Sun.COM return (NULL);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate (void) mutex_lock(&matching_lock);
3660Sstevel@tonic-gate while (fgets(line, BUFSIZ, fp)) {
3677693SVallish.Vaidyeshwara@Sun.COM if (!(blank(line) || comment(line))) {
3687693SVallish.Vaidyeshwara@Sun.COM if ((secname = gettoken(line, FALSE)) == NULL) {
3697693SVallish.Vaidyeshwara@Sun.COM /* bad line */
3707693SVallish.Vaidyeshwara@Sun.COM continue;
3717693SVallish.Vaidyeshwara@Sun.COM }
3727693SVallish.Vaidyeshwara@Sun.COM if (strcmp(secname, entryp->sc_name) == 0) {
3737693SVallish.Vaidyeshwara@Sun.COM tok = NULL;
3747693SVallish.Vaidyeshwara@Sun.COM if ((tok = gettoken(NULL, FALSE)) == NULL) {
3757693SVallish.Vaidyeshwara@Sun.COM /* bad line */
3767693SVallish.Vaidyeshwara@Sun.COM goto err;
3777693SVallish.Vaidyeshwara@Sun.COM }
3787693SVallish.Vaidyeshwara@Sun.COM
3797693SVallish.Vaidyeshwara@Sun.COM if (atoi(tok) != entryp->sc_nfsnum)
3807693SVallish.Vaidyeshwara@Sun.COM goto err;
3817693SVallish.Vaidyeshwara@Sun.COM
3827693SVallish.Vaidyeshwara@Sun.COM if ((gettoken(NULL, FALSE) == NULL) ||
3837693SVallish.Vaidyeshwara@Sun.COM ((gss_qop = gettoken(NULL, FALSE))
3847693SVallish.Vaidyeshwara@Sun.COM == NULL)) {
3857693SVallish.Vaidyeshwara@Sun.COM goto err;
3867693SVallish.Vaidyeshwara@Sun.COM }
3877693SVallish.Vaidyeshwara@Sun.COM break;
3887693SVallish.Vaidyeshwara@Sun.COM }
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate err:
3920Sstevel@tonic-gate (void) mutex_unlock(&matching_lock);
3930Sstevel@tonic-gate (void) fclose(fp);
3940Sstevel@tonic-gate return (gss_qop);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * This routine creates an auth handle assocaited with the
3990Sstevel@tonic-gate * negotiated security flavor contained in nfs_sec. The auth
4000Sstevel@tonic-gate * handle will be used in the next LOOKUP request to fetch
4010Sstevel@tonic-gate * the filehandle.
4020Sstevel@tonic-gate */
4030Sstevel@tonic-gate AUTH *
nfs_create_ah(CLIENT * cl,char * hostname,seconfig_t * nfs_sec)4040Sstevel@tonic-gate nfs_create_ah(CLIENT *cl, char *hostname, seconfig_t *nfs_sec)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate char netname[MAXNETNAMELEN+1];
4070Sstevel@tonic-gate char svc_name[MAXNETNAMELEN+1];
4080Sstevel@tonic-gate char *gss_qop;
4090Sstevel@tonic-gate static int window = 60;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate if (nfs_sec == NULL)
4127693SVallish.Vaidyeshwara@Sun.COM goto err;
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate switch (nfs_sec->sc_rpcnum) {
4157693SVallish.Vaidyeshwara@Sun.COM case AUTH_UNIX:
4167693SVallish.Vaidyeshwara@Sun.COM case AUTH_NONE:
4177693SVallish.Vaidyeshwara@Sun.COM return (NULL);
4180Sstevel@tonic-gate
4197693SVallish.Vaidyeshwara@Sun.COM case AUTH_DES:
4207693SVallish.Vaidyeshwara@Sun.COM if (!host2netname(netname, hostname, NULL))
4217693SVallish.Vaidyeshwara@Sun.COM goto err;
4220Sstevel@tonic-gate
4237693SVallish.Vaidyeshwara@Sun.COM return (authdes_seccreate(netname, window, hostname,
4247693SVallish.Vaidyeshwara@Sun.COM NULL));
4250Sstevel@tonic-gate
4267693SVallish.Vaidyeshwara@Sun.COM case RPCSEC_GSS:
4277693SVallish.Vaidyeshwara@Sun.COM if (cl == NULL)
4287693SVallish.Vaidyeshwara@Sun.COM goto err;
4290Sstevel@tonic-gate
4307693SVallish.Vaidyeshwara@Sun.COM if (nfs_sec->sc_gss_mech_type == NULL) {
4317693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
4327693SVallish.Vaidyeshwara@Sun.COM "nfs_create_ah: need mechanism information\n");
4337693SVallish.Vaidyeshwara@Sun.COM goto err;
4347693SVallish.Vaidyeshwara@Sun.COM }
4350Sstevel@tonic-gate
4367693SVallish.Vaidyeshwara@Sun.COM /*
4377693SVallish.Vaidyeshwara@Sun.COM * RPCSEC_GSS service names are of the form svc@host.dom
4387693SVallish.Vaidyeshwara@Sun.COM */
4397693SVallish.Vaidyeshwara@Sun.COM (void) sprintf(svc_name, "nfs@%s", hostname);
4400Sstevel@tonic-gate
4417693SVallish.Vaidyeshwara@Sun.COM gss_qop = nfs_get_qop_name(nfs_sec);
4427693SVallish.Vaidyeshwara@Sun.COM if (gss_qop == NULL)
4437693SVallish.Vaidyeshwara@Sun.COM goto err;
4440Sstevel@tonic-gate
4457693SVallish.Vaidyeshwara@Sun.COM return (rpc_gss_seccreate(cl, svc_name,
4467693SVallish.Vaidyeshwara@Sun.COM nfs_sec->sc_gss_mech, nfs_sec->sc_service, gss_qop,
4477693SVallish.Vaidyeshwara@Sun.COM NULL, NULL));
4480Sstevel@tonic-gate
4497693SVallish.Vaidyeshwara@Sun.COM default:
4507693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR, "nfs_create_ah: unknown flavor\n");
4517693SVallish.Vaidyeshwara@Sun.COM return (NULL);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate err:
4540Sstevel@tonic-gate syslog(LOG_ERR, "nfs_create_ah: failed to make auth handle\n");
4550Sstevel@tonic-gate return (NULL);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate #ifdef WNFS_SEC_NEGO
4590Sstevel@tonic-gate /*
4600Sstevel@tonic-gate * This routine negotiates sec flavors with server and returns:
4610Sstevel@tonic-gate * SNEGO_SUCCESS: successful; sec flavors are
4620Sstevel@tonic-gate * returned in snego,
4630Sstevel@tonic-gate * SNEGO_DEF_VALID: default sec flavor valid; no need
4640Sstevel@tonic-gate * to negotiate flavors,
4650Sstevel@tonic-gate * SNEGO_ARRAY_TOO_SMALL: array too small,
4660Sstevel@tonic-gate * SNEGO_FAILURE: failure
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate * The following depicts how sec flavors are placed in an
4700Sstevel@tonic-gate * overloaded V2 fhandle:
4710Sstevel@tonic-gate *
4720Sstevel@tonic-gate * Note that the first four octets contain the length octet,
4730Sstevel@tonic-gate * the status octet, and two padded octets to make them XDR
4740Sstevel@tonic-gate * four-octet aligned.
4750Sstevel@tonic-gate *
4760Sstevel@tonic-gate * 1 2 3 4 32
4770Sstevel@tonic-gate * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
4780Sstevel@tonic-gate * | l | s | | | sec_1 |...| sec_n |...| |
4790Sstevel@tonic-gate * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
4800Sstevel@tonic-gate *
4810Sstevel@tonic-gate * where
4820Sstevel@tonic-gate *
4830Sstevel@tonic-gate * the status octet s indicates whether there are more security
4840Sstevel@tonic-gate * flavors(1 means yes, 0 means no) that require the client to
4850Sstevel@tonic-gate * perform another 0x81 LOOKUP to get them,
4860Sstevel@tonic-gate *
4870Sstevel@tonic-gate * the length octet l is the length describing the number of
4880Sstevel@tonic-gate * valid octets that follow. (l = 4 * n, where n is the number
4890Sstevel@tonic-gate *
4900Sstevel@tonic-gate * The following depicts how sec flavors are placed in an
4910Sstevel@tonic-gate * overloaded V3 fhandle:
4920Sstevel@tonic-gate *
4930Sstevel@tonic-gate * 1 4
4940Sstevel@tonic-gate * +--+--+--+--+
4950Sstevel@tonic-gate * | len |
4960Sstevel@tonic-gate * +--+--+--+--+
4970Sstevel@tonic-gate * up to 64
4980Sstevel@tonic-gate * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
4990Sstevel@tonic-gate * |s | | | | sec_1 | sec_2 | ... | sec_n |
5000Sstevel@tonic-gate * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
5010Sstevel@tonic-gate *
5020Sstevel@tonic-gate * len = 4 * (n+1), where n is the number of security flavors
5030Sstevel@tonic-gate * sent in the current overloaded filehandle.
5040Sstevel@tonic-gate *
5050Sstevel@tonic-gate * the status octet s indicates whether there are more security
5060Sstevel@tonic-gate * mechanisms(1 means yes, 0 means no) that require the client
5070Sstevel@tonic-gate * to perform another 0x81 LOOKUP to get them.
5080Sstevel@tonic-gate *
5090Sstevel@tonic-gate * Three octets are padded after the status octet.
5100Sstevel@tonic-gate */
5110Sstevel@tonic-gate enum snego_stat
nfs_sec_nego(rpcprog_t vers,CLIENT * clnt,char * fspath,struct snego_t * snego)5120Sstevel@tonic-gate nfs_sec_nego(rpcprog_t vers, CLIENT *clnt, char *fspath, struct snego_t *snego)
5130Sstevel@tonic-gate {
5140Sstevel@tonic-gate enum clnt_stat rpc_stat;
5150Sstevel@tonic-gate static int MAX_V2_CNT = (WNL_FHSIZE/sizeof (int)) - 1;
5160Sstevel@tonic-gate static int MAX_V3_CNT = (WNL3_FHSIZE/sizeof (int)) - 1;
5170Sstevel@tonic-gate static struct timeval TIMEOUT = { 25, 0 };
5180Sstevel@tonic-gate int status;
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate if (clnt == NULL || fspath == NULL || snego == NULL)
5210Sstevel@tonic-gate return (SNEGO_FAILURE);
5220Sstevel@tonic-gate
5237693SVallish.Vaidyeshwara@Sun.COM if (vers == WNL_V2) {
5247693SVallish.Vaidyeshwara@Sun.COM wnl_diropargs arg;
5257693SVallish.Vaidyeshwara@Sun.COM wnl_diropres clnt_res;
5260Sstevel@tonic-gate
5277693SVallish.Vaidyeshwara@Sun.COM memset((char *)&arg.dir, 0, sizeof (wnl_fh));
5287693SVallish.Vaidyeshwara@Sun.COM arg.name = fspath;
5297693SVallish.Vaidyeshwara@Sun.COM memset((char *)&clnt_res, 0, sizeof (clnt_res));
5307693SVallish.Vaidyeshwara@Sun.COM rpc_stat = clnt_call(clnt, WNLPROC_LOOKUP,
5317693SVallish.Vaidyeshwara@Sun.COM (xdrproc_t)xdr_wnl_diropargs, (caddr_t)&arg,
5327693SVallish.Vaidyeshwara@Sun.COM (xdrproc_t)xdr_wnl_diropres, (caddr_t)&clnt_res,
5337693SVallish.Vaidyeshwara@Sun.COM TIMEOUT);
5347693SVallish.Vaidyeshwara@Sun.COM if (rpc_stat == RPC_SUCCESS && clnt_res.status == WNL_OK)
5357693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_DEF_VALID);
5367693SVallish.Vaidyeshwara@Sun.COM if (rpc_stat != RPC_AUTHERROR)
5370Sstevel@tonic-gate return (SNEGO_FAILURE);
5387693SVallish.Vaidyeshwara@Sun.COM
5397693SVallish.Vaidyeshwara@Sun.COM {
5407693SVallish.Vaidyeshwara@Sun.COM struct rpc_err e;
5417693SVallish.Vaidyeshwara@Sun.COM wnl_diropres res;
5427693SVallish.Vaidyeshwara@Sun.COM char *p;
5437693SVallish.Vaidyeshwara@Sun.COM int tot = 0;
5440Sstevel@tonic-gate
5457693SVallish.Vaidyeshwara@Sun.COM CLNT_GETERR(clnt, &e);
5467693SVallish.Vaidyeshwara@Sun.COM if (e.re_why != AUTH_TOOWEAK)
5477693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
5487693SVallish.Vaidyeshwara@Sun.COM
5497693SVallish.Vaidyeshwara@Sun.COM if ((p = malloc(strlen(fspath)+3)) == NULL) {
5507693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR, "no memory\n");
5517693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
5527693SVallish.Vaidyeshwara@Sun.COM }
5530Sstevel@tonic-gate /*
5547693SVallish.Vaidyeshwara@Sun.COM * Do an x81 LOOKUP
5550Sstevel@tonic-gate */
5567693SVallish.Vaidyeshwara@Sun.COM p[0] = (char)WNL_SEC_NEGO;
5577693SVallish.Vaidyeshwara@Sun.COM strcpy(&p[2], fspath);
5587693SVallish.Vaidyeshwara@Sun.COM do {
5597693SVallish.Vaidyeshwara@Sun.COM p[1] = (char)(1+snego->cnt); /* sec index */
5607693SVallish.Vaidyeshwara@Sun.COM arg.name = p;
5617693SVallish.Vaidyeshwara@Sun.COM memset((char *)&res, 0, sizeof (wnl_diropres));
5627693SVallish.Vaidyeshwara@Sun.COM if (wnlproc_lookup_2(&arg, &res, clnt) !=
5637693SVallish.Vaidyeshwara@Sun.COM RPC_SUCCESS || res.status != WNL_OK) {
5647693SVallish.Vaidyeshwara@Sun.COM free(p);
5657693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
5667693SVallish.Vaidyeshwara@Sun.COM }
5670Sstevel@tonic-gate
5687693SVallish.Vaidyeshwara@Sun.COM /*
5697693SVallish.Vaidyeshwara@Sun.COM * retrieve flavors from filehandle:
5707693SVallish.Vaidyeshwara@Sun.COM * 1st byte: length
5717693SVallish.Vaidyeshwara@Sun.COM * 2nd byte: status
5727693SVallish.Vaidyeshwara@Sun.COM * 3rd & 4th: pad
5737693SVallish.Vaidyeshwara@Sun.COM * 5th and after: sec flavors.
5747693SVallish.Vaidyeshwara@Sun.COM */
5757693SVallish.Vaidyeshwara@Sun.COM {
5767693SVallish.Vaidyeshwara@Sun.COM char *c = (char *)&res.wnl_diropres_u.
5777693SVallish.Vaidyeshwara@Sun.COM wnl_diropres.file;
5787693SVallish.Vaidyeshwara@Sun.COM int ii;
5797693SVallish.Vaidyeshwara@Sun.COM int cnt = ((int)*c)/sizeof (uint_t);
5807693SVallish.Vaidyeshwara@Sun.COM /* LINTED pointer alignment */
5817693SVallish.Vaidyeshwara@Sun.COM int *ip = (int *)(c+sizeof (int));
5820Sstevel@tonic-gate
5837693SVallish.Vaidyeshwara@Sun.COM tot += cnt;
5847693SVallish.Vaidyeshwara@Sun.COM if (tot >= MAX_FLAVORS) {
5857693SVallish.Vaidyeshwara@Sun.COM free(p);
5867693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_ARRAY_TOO_SMALL);
5877693SVallish.Vaidyeshwara@Sun.COM }
5887693SVallish.Vaidyeshwara@Sun.COM status = (int)*(c+1);
5897693SVallish.Vaidyeshwara@Sun.COM if (cnt > MAX_V2_CNT || cnt < 0) {
5907693SVallish.Vaidyeshwara@Sun.COM free(p);
5917693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
5927693SVallish.Vaidyeshwara@Sun.COM }
5937693SVallish.Vaidyeshwara@Sun.COM for (ii = 0; ii < cnt; ii++)
5947693SVallish.Vaidyeshwara@Sun.COM snego->array[snego->cnt+ii] =
5957693SVallish.Vaidyeshwara@Sun.COM ntohl(*(ip+ii));
5967693SVallish.Vaidyeshwara@Sun.COM snego->cnt += cnt;
5977693SVallish.Vaidyeshwara@Sun.COM }
5987693SVallish.Vaidyeshwara@Sun.COM } while (status);
5997693SVallish.Vaidyeshwara@Sun.COM free(p);
6007693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_SUCCESS);
6017693SVallish.Vaidyeshwara@Sun.COM }
6027693SVallish.Vaidyeshwara@Sun.COM } else if (vers == WNL_V3) {
6037693SVallish.Vaidyeshwara@Sun.COM WNL_LOOKUP3args arg;
6047693SVallish.Vaidyeshwara@Sun.COM WNL_LOOKUP3res clnt_res;
6050Sstevel@tonic-gate
6067693SVallish.Vaidyeshwara@Sun.COM memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
6077693SVallish.Vaidyeshwara@Sun.COM arg.what.name = fspath;
6087693SVallish.Vaidyeshwara@Sun.COM arg.what.dir.data.data_len = 0;
6097693SVallish.Vaidyeshwara@Sun.COM arg.what.dir.data.data_val = 0;
6107693SVallish.Vaidyeshwara@Sun.COM memset((char *)&clnt_res, 0, sizeof (clnt_res));
6117693SVallish.Vaidyeshwara@Sun.COM rpc_stat = clnt_call(clnt, WNLPROC3_LOOKUP,
6127693SVallish.Vaidyeshwara@Sun.COM (xdrproc_t)xdr_WNL_LOOKUP3args, (caddr_t)&arg,
6137693SVallish.Vaidyeshwara@Sun.COM (xdrproc_t)xdr_WNL_LOOKUP3res, (caddr_t)&clnt_res,
6147693SVallish.Vaidyeshwara@Sun.COM TIMEOUT);
6157693SVallish.Vaidyeshwara@Sun.COM if (rpc_stat == RPC_SUCCESS && clnt_res.status == WNL3_OK)
6167693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_DEF_VALID);
6177693SVallish.Vaidyeshwara@Sun.COM if (rpc_stat != RPC_AUTHERROR)
6180Sstevel@tonic-gate return (SNEGO_FAILURE);
6197693SVallish.Vaidyeshwara@Sun.COM
6207693SVallish.Vaidyeshwara@Sun.COM {
6217693SVallish.Vaidyeshwara@Sun.COM struct rpc_err e;
6227693SVallish.Vaidyeshwara@Sun.COM WNL_LOOKUP3res res;
6237693SVallish.Vaidyeshwara@Sun.COM char *p;
6247693SVallish.Vaidyeshwara@Sun.COM int tot = 0;
6250Sstevel@tonic-gate
6267693SVallish.Vaidyeshwara@Sun.COM CLNT_GETERR(clnt, &e);
6277693SVallish.Vaidyeshwara@Sun.COM if (e.re_why != AUTH_TOOWEAK)
6287693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
6297693SVallish.Vaidyeshwara@Sun.COM
6307693SVallish.Vaidyeshwara@Sun.COM if ((p = malloc(strlen(fspath)+3)) == NULL) {
6317693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR, "no memory\n");
6327693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
6337693SVallish.Vaidyeshwara@Sun.COM }
6340Sstevel@tonic-gate /*
6357693SVallish.Vaidyeshwara@Sun.COM * Do an x81 LOOKUP
6360Sstevel@tonic-gate */
6377693SVallish.Vaidyeshwara@Sun.COM p[0] = (char)WNL_SEC_NEGO;
6387693SVallish.Vaidyeshwara@Sun.COM strcpy(&p[2], fspath);
6397693SVallish.Vaidyeshwara@Sun.COM do {
6407693SVallish.Vaidyeshwara@Sun.COM p[1] = (char)(1+snego->cnt); /* sec index */
6417693SVallish.Vaidyeshwara@Sun.COM arg.what.name = p;
6427693SVallish.Vaidyeshwara@Sun.COM memset((char *)&res, 0,
6437693SVallish.Vaidyeshwara@Sun.COM sizeof (WNL_LOOKUP3res));
6447693SVallish.Vaidyeshwara@Sun.COM if (wnlproc3_lookup_3(&arg, &res, clnt) !=
6457693SVallish.Vaidyeshwara@Sun.COM RPC_SUCCESS || res.status != WNL3_OK) {
6467693SVallish.Vaidyeshwara@Sun.COM free(p);
6477693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
6487693SVallish.Vaidyeshwara@Sun.COM }
6490Sstevel@tonic-gate
6507693SVallish.Vaidyeshwara@Sun.COM /*
6517693SVallish.Vaidyeshwara@Sun.COM * retrieve flavors from filehandle:
6527693SVallish.Vaidyeshwara@Sun.COM *
6537693SVallish.Vaidyeshwara@Sun.COM * 1st byte: status
6547693SVallish.Vaidyeshwara@Sun.COM * 2nd thru 4th: pad
6557693SVallish.Vaidyeshwara@Sun.COM * 5th and after: sec flavors.
6567693SVallish.Vaidyeshwara@Sun.COM */
6577693SVallish.Vaidyeshwara@Sun.COM {
658*8650SVallish.Vaidyeshwara@Sun.COM char *c = res.WNL_LOOKUP3res_u.
6597693SVallish.Vaidyeshwara@Sun.COM res_ok.object.data.data_val;
6607693SVallish.Vaidyeshwara@Sun.COM int ii;
6617693SVallish.Vaidyeshwara@Sun.COM int len = res.WNL_LOOKUP3res_u.res_ok.
6627693SVallish.Vaidyeshwara@Sun.COM object.data.data_len;
6637693SVallish.Vaidyeshwara@Sun.COM int cnt;
6647693SVallish.Vaidyeshwara@Sun.COM /* LINTED pointer alignment */
6657693SVallish.Vaidyeshwara@Sun.COM int *ip = (int *)(c+sizeof (int));
6660Sstevel@tonic-gate
6677693SVallish.Vaidyeshwara@Sun.COM cnt = len/sizeof (uint_t) - 1;
6687693SVallish.Vaidyeshwara@Sun.COM tot += cnt;
6697693SVallish.Vaidyeshwara@Sun.COM if (tot >= MAX_FLAVORS) {
6707693SVallish.Vaidyeshwara@Sun.COM free(p);
6717693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_ARRAY_TOO_SMALL);
6727693SVallish.Vaidyeshwara@Sun.COM }
6737693SVallish.Vaidyeshwara@Sun.COM status = (int)(*c);
6747693SVallish.Vaidyeshwara@Sun.COM if (cnt > MAX_V3_CNT || cnt < 0) {
6757693SVallish.Vaidyeshwara@Sun.COM free(p);
6767693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_FAILURE);
6777693SVallish.Vaidyeshwara@Sun.COM }
6787693SVallish.Vaidyeshwara@Sun.COM for (ii = 0; ii < cnt; ii++)
6797693SVallish.Vaidyeshwara@Sun.COM snego->array[snego->cnt+ii] =
6807693SVallish.Vaidyeshwara@Sun.COM ntohl(*(ip+ii));
6817693SVallish.Vaidyeshwara@Sun.COM snego->cnt += cnt;
6827693SVallish.Vaidyeshwara@Sun.COM }
6837693SVallish.Vaidyeshwara@Sun.COM } while (status);
6847693SVallish.Vaidyeshwara@Sun.COM free(p);
6857693SVallish.Vaidyeshwara@Sun.COM return (SNEGO_SUCCESS);
6867693SVallish.Vaidyeshwara@Sun.COM }
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate return (SNEGO_FAILURE);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate #endif
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate /*
6930Sstevel@tonic-gate * Get seconfig from /etc/nfssec.conf by name or by number or
6940Sstevel@tonic-gate * by descriptior.
6950Sstevel@tonic-gate */
6960Sstevel@tonic-gate /* ARGSUSED */
6970Sstevel@tonic-gate static int
get_seconfig(int whichway,char * name,int num,rpc_gss_service_t service,seconfig_t * entryp)6980Sstevel@tonic-gate get_seconfig(int whichway, char *name, int num,
6990Sstevel@tonic-gate rpc_gss_service_t service, seconfig_t *entryp)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate static mutex_t matching_lock = DEFAULTMUTEX;
7020Sstevel@tonic-gate char line[BUFSIZ]; /* holds each line of NFSSEC_CONF */
7030Sstevel@tonic-gate FILE *fp; /* file stream for NFSSEC_CONF */
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate if ((whichway == GETBYNAME) && (name == NULL))
7060Sstevel@tonic-gate return (SC_NOTFOUND);
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) {
7090Sstevel@tonic-gate return (SC_OPENFAIL);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate (void) mutex_lock(&matching_lock);
7130Sstevel@tonic-gate while (fgets(line, BUFSIZ, fp)) {
7147693SVallish.Vaidyeshwara@Sun.COM if (!(blank(line) || comment(line))) {
7157693SVallish.Vaidyeshwara@Sun.COM switch (whichway) {
7167693SVallish.Vaidyeshwara@Sun.COM case GETBYNAME:
7177693SVallish.Vaidyeshwara@Sun.COM if (matchname(line, name, entryp)) {
7187693SVallish.Vaidyeshwara@Sun.COM goto found;
7197693SVallish.Vaidyeshwara@Sun.COM }
7207693SVallish.Vaidyeshwara@Sun.COM break;
7210Sstevel@tonic-gate
7227693SVallish.Vaidyeshwara@Sun.COM case GETBYNUM:
7237693SVallish.Vaidyeshwara@Sun.COM if (matchnum(line, num, entryp)) {
7247693SVallish.Vaidyeshwara@Sun.COM goto found;
7257693SVallish.Vaidyeshwara@Sun.COM }
7267693SVallish.Vaidyeshwara@Sun.COM break;
7277693SVallish.Vaidyeshwara@Sun.COM
7287693SVallish.Vaidyeshwara@Sun.COM default:
7297693SVallish.Vaidyeshwara@Sun.COM break;
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate (void) mutex_unlock(&matching_lock);
7340Sstevel@tonic-gate (void) fclose(fp);
7350Sstevel@tonic-gate return (SC_NOTFOUND);
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate found:
7380Sstevel@tonic-gate (void) mutex_unlock(&matching_lock);
7390Sstevel@tonic-gate (void) fclose(fp);
7400Sstevel@tonic-gate (void) get_rpcnum(entryp);
7410Sstevel@tonic-gate return (SC_NOERROR);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate /*
7460Sstevel@tonic-gate * NFS project private API.
7470Sstevel@tonic-gate * Get a seconfig entry from /etc/nfssec.conf by nfs specific sec name,
7480Sstevel@tonic-gate * e.g. des, krb5p, etc.
7490Sstevel@tonic-gate */
7500Sstevel@tonic-gate int
nfs_getseconfig_byname(char * secmode_name,seconfig_t * entryp)7510Sstevel@tonic-gate nfs_getseconfig_byname(char *secmode_name, seconfig_t *entryp)
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate if (!entryp)
7540Sstevel@tonic-gate return (SC_NOMEM);
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate return (get_seconfig(GETBYNAME, secmode_name, 0, rpc_gss_svc_none,
7577693SVallish.Vaidyeshwara@Sun.COM entryp));
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate /*
7610Sstevel@tonic-gate * NFS project private API.
7620Sstevel@tonic-gate *
7630Sstevel@tonic-gate * Get a seconfig entry from /etc/nfssec.conf by nfs specific sec number,
7640Sstevel@tonic-gate * e.g. AUTH_DES, AUTH_KRB5_P, etc.
7650Sstevel@tonic-gate */
7660Sstevel@tonic-gate int
nfs_getseconfig_bynumber(int nfs_secnum,seconfig_t * entryp)7670Sstevel@tonic-gate nfs_getseconfig_bynumber(int nfs_secnum, seconfig_t *entryp)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate if (!entryp)
7700Sstevel@tonic-gate return (SC_NOMEM);
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate return (get_seconfig(GETBYNUM, NULL, nfs_secnum, rpc_gss_svc_none,
7737693SVallish.Vaidyeshwara@Sun.COM entryp));
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate /*
7770Sstevel@tonic-gate * NFS project private API.
7780Sstevel@tonic-gate *
7790Sstevel@tonic-gate * Get a seconfig_t entry used as the default for NFS operations.
7800Sstevel@tonic-gate * The default flavor entry is defined in /etc/nfssec.conf.
7810Sstevel@tonic-gate *
7820Sstevel@tonic-gate * Assume user has allocate spaces for secp.
7830Sstevel@tonic-gate */
7840Sstevel@tonic-gate int
nfs_getseconfig_default(seconfig_t * secp)7850Sstevel@tonic-gate nfs_getseconfig_default(seconfig_t *secp)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate if (secp == NULL)
7880Sstevel@tonic-gate return (SC_NOMEM);
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate return (nfs_getseconfig_byname("default", secp));
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate
7940Sstevel@tonic-gate /*
7950Sstevel@tonic-gate * NFS project private API.
7960Sstevel@tonic-gate *
7970Sstevel@tonic-gate * Free an sec_data structure.
7980Sstevel@tonic-gate * Free the parts that nfs_clnt_secdata allocates.
7990Sstevel@tonic-gate */
8000Sstevel@tonic-gate void
nfs_free_secdata(sec_data_t * secdata)8010Sstevel@tonic-gate nfs_free_secdata(sec_data_t *secdata)
8020Sstevel@tonic-gate {
8030Sstevel@tonic-gate dh_k4_clntdata_t *dkdata;
8040Sstevel@tonic-gate gss_clntdata_t *gdata;
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate if (!secdata)
8070Sstevel@tonic-gate return;
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate switch (secdata->rpcflavor) {
8107693SVallish.Vaidyeshwara@Sun.COM case AUTH_UNIX:
8117693SVallish.Vaidyeshwara@Sun.COM case AUTH_NONE:
8127693SVallish.Vaidyeshwara@Sun.COM break;
8130Sstevel@tonic-gate
8147693SVallish.Vaidyeshwara@Sun.COM case AUTH_DES:
8157693SVallish.Vaidyeshwara@Sun.COM /* LINTED pointer alignment */
8167693SVallish.Vaidyeshwara@Sun.COM dkdata = (dh_k4_clntdata_t *)secdata->data;
8177693SVallish.Vaidyeshwara@Sun.COM if (dkdata) {
8187693SVallish.Vaidyeshwara@Sun.COM if (dkdata->netname)
8197693SVallish.Vaidyeshwara@Sun.COM free(dkdata->netname);
8207693SVallish.Vaidyeshwara@Sun.COM if (dkdata->syncaddr.buf)
8217693SVallish.Vaidyeshwara@Sun.COM free(dkdata->syncaddr.buf);
8227693SVallish.Vaidyeshwara@Sun.COM free(dkdata);
8237693SVallish.Vaidyeshwara@Sun.COM }
8247693SVallish.Vaidyeshwara@Sun.COM break;
8250Sstevel@tonic-gate
8267693SVallish.Vaidyeshwara@Sun.COM case RPCSEC_GSS:
8277693SVallish.Vaidyeshwara@Sun.COM /* LINTED pointer alignment */
8287693SVallish.Vaidyeshwara@Sun.COM gdata = (gss_clntdata_t *)secdata->data;
8297693SVallish.Vaidyeshwara@Sun.COM if (gdata) {
8307693SVallish.Vaidyeshwara@Sun.COM if (gdata->mechanism.elements)
8317693SVallish.Vaidyeshwara@Sun.COM free(gdata->mechanism.elements);
8327693SVallish.Vaidyeshwara@Sun.COM free(gdata);
8337693SVallish.Vaidyeshwara@Sun.COM }
8347693SVallish.Vaidyeshwara@Sun.COM break;
8350Sstevel@tonic-gate
8367693SVallish.Vaidyeshwara@Sun.COM default:
8377693SVallish.Vaidyeshwara@Sun.COM break;
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate free(secdata);
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate /*
8440Sstevel@tonic-gate * Make an client side sec_data structure and fill in appropriate value
8450Sstevel@tonic-gate * based on its rpc security flavor.
8460Sstevel@tonic-gate *
8470Sstevel@tonic-gate * It is caller's responsibility to allocate space for seconfig_t,
8480Sstevel@tonic-gate * and this routine will allocate space for the sec_data structure
8490Sstevel@tonic-gate * and related data field.
8500Sstevel@tonic-gate *
8510Sstevel@tonic-gate * Return the sec_data_t on success.
8520Sstevel@tonic-gate * If fail, return NULL pointer.
8530Sstevel@tonic-gate */
8540Sstevel@tonic-gate sec_data_t *
nfs_clnt_secdata(seconfig_t * secp,char * hostname,struct knetconfig * knconf,struct netbuf * syncaddr,int flags)8550Sstevel@tonic-gate nfs_clnt_secdata(seconfig_t *secp, char *hostname, struct knetconfig *knconf,
8560Sstevel@tonic-gate struct netbuf *syncaddr, int flags)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate char netname[MAXNETNAMELEN+1];
8590Sstevel@tonic-gate sec_data_t *secdata;
8600Sstevel@tonic-gate dh_k4_clntdata_t *dkdata;
8610Sstevel@tonic-gate gss_clntdata_t *gdata;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate secdata = malloc(sizeof (sec_data_t));
8640Sstevel@tonic-gate if (!secdata) {
8650Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
8660Sstevel@tonic-gate return (NULL);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate (void) memset(secdata, 0, sizeof (sec_data_t));
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate secdata->secmod = secp->sc_nfsnum;
8710Sstevel@tonic-gate secdata->rpcflavor = secp->sc_rpcnum;
8720Sstevel@tonic-gate secdata->uid = secp->sc_uid;
8730Sstevel@tonic-gate secdata->flags = flags;
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate /*
8760Sstevel@tonic-gate * Now, fill in the information for client side secdata :
8770Sstevel@tonic-gate *
8780Sstevel@tonic-gate * For AUTH_UNIX, AUTH_DES
8790Sstevel@tonic-gate * hostname can be in the form of
8800Sstevel@tonic-gate * nodename or
8810Sstevel@tonic-gate * nodename.domain
8820Sstevel@tonic-gate *
8830Sstevel@tonic-gate * For RPCSEC_GSS security flavor
8840Sstevel@tonic-gate * hostname can be in the form of
8850Sstevel@tonic-gate * nodename or
8860Sstevel@tonic-gate * nodename.domain or
8870Sstevel@tonic-gate * nodename@realm (realm can be the same as the domain) or
8880Sstevel@tonic-gate * nodename.domain@realm
8890Sstevel@tonic-gate */
8900Sstevel@tonic-gate switch (secp->sc_rpcnum) {
8917693SVallish.Vaidyeshwara@Sun.COM case AUTH_UNIX:
8927693SVallish.Vaidyeshwara@Sun.COM case AUTH_NONE:
8937693SVallish.Vaidyeshwara@Sun.COM secdata->data = NULL;
8947693SVallish.Vaidyeshwara@Sun.COM break;
8950Sstevel@tonic-gate
8967693SVallish.Vaidyeshwara@Sun.COM case AUTH_DES:
8977693SVallish.Vaidyeshwara@Sun.COM /*
8987693SVallish.Vaidyeshwara@Sun.COM * If hostname is in the format of host.nisdomain
8997693SVallish.Vaidyeshwara@Sun.COM * the netname will be constructed with
9007693SVallish.Vaidyeshwara@Sun.COM * this nisdomain name rather than the default
9017693SVallish.Vaidyeshwara@Sun.COM * domain of the machine.
9027693SVallish.Vaidyeshwara@Sun.COM */
9037693SVallish.Vaidyeshwara@Sun.COM if (!host2netname(netname, hostname, NULL)) {
9047693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR, "host2netname: %s: unknown\n",
9057693SVallish.Vaidyeshwara@Sun.COM hostname);
9067693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9077693SVallish.Vaidyeshwara@Sun.COM }
9087693SVallish.Vaidyeshwara@Sun.COM dkdata = malloc(sizeof (dh_k4_clntdata_t));
9097693SVallish.Vaidyeshwara@Sun.COM if (!dkdata) {
9107693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9117693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: no memory\n");
9127693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9137693SVallish.Vaidyeshwara@Sun.COM }
9147693SVallish.Vaidyeshwara@Sun.COM (void) memset((char *)dkdata, 0,
9157693SVallish.Vaidyeshwara@Sun.COM sizeof (dh_k4_clntdata_t));
9167693SVallish.Vaidyeshwara@Sun.COM if ((dkdata->netname = strdup(netname)) == NULL) {
9177693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9187693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: no memory\n");
9197693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9207693SVallish.Vaidyeshwara@Sun.COM }
9217693SVallish.Vaidyeshwara@Sun.COM dkdata->netnamelen = strlen(netname);
9227693SVallish.Vaidyeshwara@Sun.COM dkdata->knconf = knconf;
9237693SVallish.Vaidyeshwara@Sun.COM dkdata->syncaddr = *syncaddr;
9247693SVallish.Vaidyeshwara@Sun.COM dkdata->syncaddr.buf = malloc(syncaddr->len);
9257693SVallish.Vaidyeshwara@Sun.COM if (dkdata->syncaddr.buf == NULL) {
9267693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9277693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: no memory\n");
9287693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9297693SVallish.Vaidyeshwara@Sun.COM }
9307693SVallish.Vaidyeshwara@Sun.COM (void) memcpy(dkdata->syncaddr.buf, syncaddr->buf,
9317693SVallish.Vaidyeshwara@Sun.COM syncaddr->len);
9327693SVallish.Vaidyeshwara@Sun.COM secdata->data = (caddr_t)dkdata;
9337693SVallish.Vaidyeshwara@Sun.COM break;
9340Sstevel@tonic-gate
9357693SVallish.Vaidyeshwara@Sun.COM case RPCSEC_GSS:
9367693SVallish.Vaidyeshwara@Sun.COM if (secp->sc_gss_mech_type == NULL) {
9377693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9387693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: need mechanism information\n");
9397693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9407693SVallish.Vaidyeshwara@Sun.COM }
9417693SVallish.Vaidyeshwara@Sun.COM
9427693SVallish.Vaidyeshwara@Sun.COM gdata = malloc(sizeof (gss_clntdata_t));
9437693SVallish.Vaidyeshwara@Sun.COM if (!gdata) {
9447693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9457693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: no memory\n");
9467693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9477693SVallish.Vaidyeshwara@Sun.COM }
9480Sstevel@tonic-gate
9497693SVallish.Vaidyeshwara@Sun.COM (void) strcpy(gdata->uname, "nfs");
9507693SVallish.Vaidyeshwara@Sun.COM if (!parsehostname(hostname, gdata->inst,
9517693SVallish.Vaidyeshwara@Sun.COM gdata->realm)) {
9527693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9537693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: bad host name\n");
9547693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9557693SVallish.Vaidyeshwara@Sun.COM }
9560Sstevel@tonic-gate
9577693SVallish.Vaidyeshwara@Sun.COM gdata->mechanism.length =
9587693SVallish.Vaidyeshwara@Sun.COM secp->sc_gss_mech_type->length;
9597693SVallish.Vaidyeshwara@Sun.COM if (!(gdata->mechanism.elements =
9607693SVallish.Vaidyeshwara@Sun.COM malloc(secp->sc_gss_mech_type->length))) {
9617693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
9627693SVallish.Vaidyeshwara@Sun.COM "nfs_clnt_secdata: no memory\n");
9637693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9647693SVallish.Vaidyeshwara@Sun.COM }
9657693SVallish.Vaidyeshwara@Sun.COM (void) memcpy(gdata->mechanism.elements,
9667693SVallish.Vaidyeshwara@Sun.COM secp->sc_gss_mech_type->elements,
9677693SVallish.Vaidyeshwara@Sun.COM secp->sc_gss_mech_type->length);
9687693SVallish.Vaidyeshwara@Sun.COM
9697693SVallish.Vaidyeshwara@Sun.COM gdata->qop = secp->sc_qop;
9707693SVallish.Vaidyeshwara@Sun.COM gdata->service = secp->sc_service;
9717693SVallish.Vaidyeshwara@Sun.COM secdata->data = (caddr_t)gdata;
9727693SVallish.Vaidyeshwara@Sun.COM break;
9737693SVallish.Vaidyeshwara@Sun.COM
9747693SVallish.Vaidyeshwara@Sun.COM default:
9757693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR, "nfs_clnt_secdata: unknown flavor\n");
9767693SVallish.Vaidyeshwara@Sun.COM goto err_out;
9770Sstevel@tonic-gate }
9780Sstevel@tonic-gate
9790Sstevel@tonic-gate return (secdata);
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate err_out:
9820Sstevel@tonic-gate free(secdata);
9830Sstevel@tonic-gate return (NULL);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate * nfs_get_root_principal() maps a host name to its principal name
9880Sstevel@tonic-gate * based on the given security information.
9890Sstevel@tonic-gate *
9900Sstevel@tonic-gate * input : seconfig - security configuration information
9910Sstevel@tonic-gate * host - the host name which could be in the following forms:
9920Sstevel@tonic-gate * node
9930Sstevel@tonic-gate * node.namedomain
9940Sstevel@tonic-gate * node@secdomain (e.g. kerberos realm is a secdomain)
9950Sstevel@tonic-gate * node.namedomain@secdomain
9960Sstevel@tonic-gate * output : rootname_p - address of the principal name for the host
9970Sstevel@tonic-gate *
9980Sstevel@tonic-gate * Currently, this routine is only used by share program.
9990Sstevel@tonic-gate *
10000Sstevel@tonic-gate */
10010Sstevel@tonic-gate bool_t
nfs_get_root_principal(seconfig_t * seconfig,char * host,caddr_t * rootname_p)10020Sstevel@tonic-gate nfs_get_root_principal(seconfig_t *seconfig, char *host, caddr_t *rootname_p)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate char netname[MAXNETNAMELEN+1], node[MAX_NAME_LEN];
10050Sstevel@tonic-gate char secdomain[MAX_NAME_LEN];
10060Sstevel@tonic-gate rpc_gss_principal_t gssname;
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate switch (seconfig->sc_rpcnum) {
10090Sstevel@tonic-gate case AUTH_DES:
10107693SVallish.Vaidyeshwara@Sun.COM if (!host2netname(netname, host, NULL)) {
10117693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
10120Sstevel@tonic-gate "nfs_get_root_principal: unknown host: %s\n", host);
10137693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
10147693SVallish.Vaidyeshwara@Sun.COM }
10157693SVallish.Vaidyeshwara@Sun.COM *rootname_p = strdup(netname);
10167693SVallish.Vaidyeshwara@Sun.COM if (!*rootname_p) {
10177693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
10187693SVallish.Vaidyeshwara@Sun.COM "nfs_get_root_principal: no memory\n");
10197693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
10207693SVallish.Vaidyeshwara@Sun.COM }
10217693SVallish.Vaidyeshwara@Sun.COM break;
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate case RPCSEC_GSS:
10247693SVallish.Vaidyeshwara@Sun.COM if (!parsehostname(host, node, secdomain)) {
10257693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
10267693SVallish.Vaidyeshwara@Sun.COM "nfs_get_root_principal: bad host name\n");
10277693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
10287693SVallish.Vaidyeshwara@Sun.COM }
10297693SVallish.Vaidyeshwara@Sun.COM if (!rpc_gss_get_principal_name(&gssname,
10307693SVallish.Vaidyeshwara@Sun.COM seconfig->sc_gss_mech, "root", node, secdomain)) {
10317693SVallish.Vaidyeshwara@Sun.COM syslog(LOG_ERR,
10320Sstevel@tonic-gate "nfs_get_root_principal: can not get principal name : %s\n", host);
10337693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
10347693SVallish.Vaidyeshwara@Sun.COM }
10350Sstevel@tonic-gate
10367693SVallish.Vaidyeshwara@Sun.COM *rootname_p = (caddr_t)gssname;
10377693SVallish.Vaidyeshwara@Sun.COM break;
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate default:
10407693SVallish.Vaidyeshwara@Sun.COM return (FALSE);
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate return (TRUE);
10430Sstevel@tonic-gate }
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate * SYSLOG SC_* errors.
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate int
nfs_syslog_scerr(int scerror,char msg[])10500Sstevel@tonic-gate nfs_syslog_scerr(int scerror, char msg[])
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate switch (scerror) {
10530Sstevel@tonic-gate case SC_NOMEM :
10540Sstevel@tonic-gate sprintf(msg, "%s : no memory", NFSSEC_CONF);
10550Sstevel@tonic-gate return (0);
10560Sstevel@tonic-gate case SC_OPENFAIL :
10570Sstevel@tonic-gate sprintf(msg, "can not open %s", NFSSEC_CONF);
10580Sstevel@tonic-gate return (0);
10590Sstevel@tonic-gate case SC_NOTFOUND :
10600Sstevel@tonic-gate sprintf(msg, "has no entry in %s", NFSSEC_CONF);
10610Sstevel@tonic-gate return (0);
10620Sstevel@tonic-gate case SC_BADENTRIES :
10630Sstevel@tonic-gate sprintf(msg, "bad entry in %s", NFSSEC_CONF);
10640Sstevel@tonic-gate return (0);
10650Sstevel@tonic-gate default:
10660Sstevel@tonic-gate msg[0] = '\0';
10670Sstevel@tonic-gate return (-1);
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate }
1070