xref: /onnv-gate/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /* LINTLIBRARY */
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * nfs security related library routines.
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * Some of the routines in this file are adopted from
33*0Sstevel@tonic-gate  * lib/libnsl/netselect/netselect.c and are modified to be
34*0Sstevel@tonic-gate  * used for accessing /etc/nfssec.conf.
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
38*0Sstevel@tonic-gate /* SVr4.0 1.18	*/
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <stdio.h>
41*0Sstevel@tonic-gate #include <string.h>
42*0Sstevel@tonic-gate #include <ctype.h>
43*0Sstevel@tonic-gate #include <stdlib.h>
44*0Sstevel@tonic-gate #include <syslog.h>
45*0Sstevel@tonic-gate #include <synch.h>
46*0Sstevel@tonic-gate #include <rpc/rpc.h>
47*0Sstevel@tonic-gate #include <nfs/nfs_sec.h>
48*0Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
49*0Sstevel@tonic-gate #ifdef WNFS_SEC_NEGO
50*0Sstevel@tonic-gate #include "webnfs.h"
51*0Sstevel@tonic-gate #endif
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #define	GETBYNAME	1
54*0Sstevel@tonic-gate #define	GETBYNUM	2
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate  * mapping for /etc/nfssec.conf
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate struct sc_data {
60*0Sstevel@tonic-gate 	char	*string;
61*0Sstevel@tonic-gate 	int	value;
62*0Sstevel@tonic-gate };
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate static struct sc_data sc_service[] = {
65*0Sstevel@tonic-gate 	"default",	rpc_gss_svc_default,
66*0Sstevel@tonic-gate 	"-",		rpc_gss_svc_none,
67*0Sstevel@tonic-gate 	"none",		rpc_gss_svc_none,
68*0Sstevel@tonic-gate 	"integrity",	rpc_gss_svc_integrity,
69*0Sstevel@tonic-gate 	"privacy",	rpc_gss_svc_privacy,
70*0Sstevel@tonic-gate 	NULL,		SC_FAILURE
71*0Sstevel@tonic-gate };
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static char *gettoken(char *, int);
74*0Sstevel@tonic-gate extern	int atoi(const char *str);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate extern	bool_t rpc_gss_get_principal_name(rpc_gss_principal_t *, char *,
77*0Sstevel@tonic-gate 			char *, char *, char *);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate extern	bool_t rpc_gss_mech_to_oid(char *, rpc_gss_OID *);
80*0Sstevel@tonic-gate extern	bool_t rpc_gss_qop_to_num(char *, char *, uint_t *);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /*
83*0Sstevel@tonic-gate  *  blank() returns true if the line is a blank line, 0 otherwise
84*0Sstevel@tonic-gate  */
85*0Sstevel@tonic-gate static int
86*0Sstevel@tonic-gate blank(cp)
87*0Sstevel@tonic-gate char *cp;
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate 	while (*cp && isspace(*cp)) {
90*0Sstevel@tonic-gate 		cp++;
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 	return (*cp == '\0');
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  *  comment() returns true if the line is a comment, 0 otherwise.
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate static int
99*0Sstevel@tonic-gate comment(cp)
100*0Sstevel@tonic-gate char *cp;
101*0Sstevel@tonic-gate {
102*0Sstevel@tonic-gate 	while (*cp && isspace(*cp)) {
103*0Sstevel@tonic-gate 		cp++;
104*0Sstevel@tonic-gate 	}
105*0Sstevel@tonic-gate 	return (*cp == '#');
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate /*
110*0Sstevel@tonic-gate  *	getvalue() searches for the given string in the given array,
111*0Sstevel@tonic-gate  *	and returns the integer value associated with the string.
112*0Sstevel@tonic-gate  */
113*0Sstevel@tonic-gate static unsigned long
114*0Sstevel@tonic-gate getvalue(cp, sc_data)
115*0Sstevel@tonic-gate char *cp;
116*0Sstevel@tonic-gate struct sc_data sc_data[];
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	int i;	/* used to index through the given struct sc_data array */
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	for (i = 0; sc_data[i].string; i++) {
121*0Sstevel@tonic-gate 		if (strcmp(sc_data[i].string, cp) == 0) {
122*0Sstevel@tonic-gate 			break;
123*0Sstevel@tonic-gate 		}
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 	return (sc_data[i].value);
126*0Sstevel@tonic-gate }
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate /*
129*0Sstevel@tonic-gate  *	shift1left() moves all characters in the string over 1 to
130*0Sstevel@tonic-gate  *	the left.
131*0Sstevel@tonic-gate  */
132*0Sstevel@tonic-gate static void
133*0Sstevel@tonic-gate shift1left(p)
134*0Sstevel@tonic-gate char *p;
135*0Sstevel@tonic-gate {
136*0Sstevel@tonic-gate 	for (; *p; p++)
137*0Sstevel@tonic-gate 		*p = *(p + 1);
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate /*
142*0Sstevel@tonic-gate  *	gettoken() behaves much like strtok(), except that
143*0Sstevel@tonic-gate  *	it knows about escaped space characters (i.e., space characters
144*0Sstevel@tonic-gate  *	preceeded by a '\' are taken literally).
145*0Sstevel@tonic-gate  *
146*0Sstevel@tonic-gate  *	XXX We should make this MT-hot by making it more like strtok_r().
147*0Sstevel@tonic-gate  */
148*0Sstevel@tonic-gate static char *
149*0Sstevel@tonic-gate gettoken(cp, skip)
150*0Sstevel@tonic-gate char	*cp;
151*0Sstevel@tonic-gate int skip;
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate 	static char	*savep;	/* the place where we left off    */
154*0Sstevel@tonic-gate 	register char	*p;	/* the beginning of the new token */
155*0Sstevel@tonic-gate 	register char	*retp;	/* the token to be returned	  */
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	/* Determine if first or subsequent call  */
159*0Sstevel@tonic-gate 	p = (cp == NULL)? savep: cp;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	/* Return if no tokens remain.  */
162*0Sstevel@tonic-gate 	if (p == 0) {
163*0Sstevel@tonic-gate 		return (NULL);
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	while (isspace(*p))
167*0Sstevel@tonic-gate 		p++;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	if (*p == '\0') {
170*0Sstevel@tonic-gate 		return (NULL);
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	/*
174*0Sstevel@tonic-gate 	 *	Save the location of the token and then skip past it
175*0Sstevel@tonic-gate 	 */
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	retp = p;
178*0Sstevel@tonic-gate 	while (*p) {
179*0Sstevel@tonic-gate 		if (isspace(*p))
180*0Sstevel@tonic-gate 			if (skip == TRUE) {
181*0Sstevel@tonic-gate 				shift1left(p);
182*0Sstevel@tonic-gate 				continue;
183*0Sstevel@tonic-gate 			} else
184*0Sstevel@tonic-gate 				break;
185*0Sstevel@tonic-gate 		/*
186*0Sstevel@tonic-gate 		 *	Only process the escape of the space separator;
187*0Sstevel@tonic-gate 		 *	since the token may contain other separators,
188*0Sstevel@tonic-gate 		 *	let the other routines handle the escape of
189*0Sstevel@tonic-gate 		 *	specific characters in the token.
190*0Sstevel@tonic-gate 		 */
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) {
193*0Sstevel@tonic-gate 			shift1left(p);
194*0Sstevel@tonic-gate 		}
195*0Sstevel@tonic-gate 		p++;
196*0Sstevel@tonic-gate 	}
197*0Sstevel@tonic-gate 	if (*p == '\0') {
198*0Sstevel@tonic-gate 		savep = 0;	/* indicate this is last token */
199*0Sstevel@tonic-gate 	} else {
200*0Sstevel@tonic-gate 		*p = '\0';
201*0Sstevel@tonic-gate 		savep = ++p;
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 	return (retp);
204*0Sstevel@tonic-gate }
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate /*
207*0Sstevel@tonic-gate  *  matchname() parses a line of the /etc/nfssec.conf file
208*0Sstevel@tonic-gate  *  and match the sc_name with the given name.
209*0Sstevel@tonic-gate  *  If there is a match, it fills the information into the given
210*0Sstevel@tonic-gate  *  pointer of the seconfig_t structure.
211*0Sstevel@tonic-gate  *
212*0Sstevel@tonic-gate  *  Returns TRUE if a match is found.
213*0Sstevel@tonic-gate  */
214*0Sstevel@tonic-gate static bool_t
215*0Sstevel@tonic-gate matchname(char *line, char *name, seconfig_t *secp)
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	char	*tok1,	*tok2;	/* holds a token from the line */
218*0Sstevel@tonic-gate 	char	*secname, *gss_mech, *gss_qop; /* pointer to a secmode name */
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	if ((secname = gettoken(line, FALSE)) == NULL) {
221*0Sstevel@tonic-gate 		/* bad line */
222*0Sstevel@tonic-gate 		return (FALSE);
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	if (strcmp(secname, name) != 0) {
226*0Sstevel@tonic-gate 		return (FALSE);
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	tok1 = tok2 = NULL;
230*0Sstevel@tonic-gate 	if (((tok1 = gettoken(NULL, FALSE)) == NULL) ||
231*0Sstevel@tonic-gate 		((gss_mech = gettoken(NULL, FALSE)) == NULL) ||
232*0Sstevel@tonic-gate 		((gss_qop = gettoken(NULL, FALSE)) == NULL) ||
233*0Sstevel@tonic-gate 		((tok2 = gettoken(NULL, FALSE)) == NULL) ||
234*0Sstevel@tonic-gate 		((secp->sc_service = getvalue(tok2, sc_service))
235*0Sstevel@tonic-gate 			== SC_FAILURE)) {
236*0Sstevel@tonic-gate 		return (FALSE);
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate 	secp->sc_nfsnum = atoi(tok1);
239*0Sstevel@tonic-gate 	(void) strcpy(secp->sc_name, secname);
240*0Sstevel@tonic-gate 	(void) strcpy(secp->sc_gss_mech, gss_mech);
241*0Sstevel@tonic-gate 	secp->sc_gss_mech_type = NULL;
242*0Sstevel@tonic-gate 	if (secp->sc_gss_mech[0] != '-') {
243*0Sstevel@tonic-gate 	    if (!rpc_gss_mech_to_oid(gss_mech, &secp->sc_gss_mech_type) ||
244*0Sstevel@tonic-gate 		!rpc_gss_qop_to_num(gss_qop, gss_mech, &secp->sc_qop)) {
245*0Sstevel@tonic-gate 		return (FALSE);
246*0Sstevel@tonic-gate 	    }
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	return (TRUE);
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate /*
253*0Sstevel@tonic-gate  *  matchnum() parses a line of the /etc/nfssec.conf file
254*0Sstevel@tonic-gate  *  and match the sc_nfsnum with the given number.
255*0Sstevel@tonic-gate  *  If it is a match, it fills the information in the given pointer
256*0Sstevel@tonic-gate  *  of the seconfig_t structure.
257*0Sstevel@tonic-gate  *
258*0Sstevel@tonic-gate  *  Returns TRUE if a match is found.
259*0Sstevel@tonic-gate  */
260*0Sstevel@tonic-gate static bool_t
261*0Sstevel@tonic-gate matchnum(char *line, int num, seconfig_t *secp)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate 	char	*tok1,	*tok2;	/* holds a token from the line */
264*0Sstevel@tonic-gate 	char	*secname, *gss_mech, *gss_qop;	/* pointer to a secmode name */
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if ((secname = gettoken(line, FALSE)) == NULL) {
267*0Sstevel@tonic-gate 		/* bad line */
268*0Sstevel@tonic-gate 		return (FALSE);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	tok1 = tok2 = NULL;
272*0Sstevel@tonic-gate 	if ((tok1 = gettoken(NULL, FALSE)) == NULL) {
273*0Sstevel@tonic-gate 		/* bad line */
274*0Sstevel@tonic-gate 		return (FALSE);
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	if ((secp->sc_nfsnum = atoi(tok1)) != num) {
278*0Sstevel@tonic-gate 		return (FALSE);
279*0Sstevel@tonic-gate 	}
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	if (((gss_mech = gettoken(NULL, FALSE)) == NULL) ||
282*0Sstevel@tonic-gate 		((gss_qop = gettoken(NULL, FALSE)) == NULL) ||
283*0Sstevel@tonic-gate 		((tok2 = gettoken(NULL, FALSE)) == NULL) ||
284*0Sstevel@tonic-gate 		((secp->sc_service = getvalue(tok2, sc_service))
285*0Sstevel@tonic-gate 			== SC_FAILURE)) {
286*0Sstevel@tonic-gate 		return (FALSE);
287*0Sstevel@tonic-gate 	}
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	(void) strcpy(secp->sc_name, secname);
290*0Sstevel@tonic-gate 	(void) strcpy(secp->sc_gss_mech, gss_mech);
291*0Sstevel@tonic-gate 	if (secp->sc_gss_mech[0] != '-') {
292*0Sstevel@tonic-gate 	    if (!rpc_gss_mech_to_oid(gss_mech, &secp->sc_gss_mech_type) ||
293*0Sstevel@tonic-gate 		!rpc_gss_qop_to_num(gss_qop, gss_mech, &secp->sc_qop)) {
294*0Sstevel@tonic-gate 		return (FALSE);
295*0Sstevel@tonic-gate 	    }
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	return (TRUE);
299*0Sstevel@tonic-gate }
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate /*
302*0Sstevel@tonic-gate  *  Fill in the RPC Protocol security flavor number
303*0Sstevel@tonic-gate  *  into the sc_rpcnum of seconfig_t structure.
304*0Sstevel@tonic-gate  *
305*0Sstevel@tonic-gate  *  Mainly to map NFS secmod number to RPCSEC_GSS if
306*0Sstevel@tonic-gate  *  a mechanism name is specified.
307*0Sstevel@tonic-gate  */
308*0Sstevel@tonic-gate static void
309*0Sstevel@tonic-gate get_rpcnum(seconfig_t *secp)
310*0Sstevel@tonic-gate {
311*0Sstevel@tonic-gate 	if (secp->sc_gss_mech[0] != '-') {
312*0Sstevel@tonic-gate 		secp->sc_rpcnum = RPCSEC_GSS;
313*0Sstevel@tonic-gate 	} else {
314*0Sstevel@tonic-gate 		secp->sc_rpcnum = secp->sc_nfsnum;
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate /*
319*0Sstevel@tonic-gate  *  Parse a given hostname (nodename[.domain@realm]) to
320*0Sstevel@tonic-gate  *  instant name (nodename[.domain]) and realm.
321*0Sstevel@tonic-gate  *
322*0Sstevel@tonic-gate  *  Assuming user has allocated the space for inst and realm.
323*0Sstevel@tonic-gate  */
324*0Sstevel@tonic-gate static int
325*0Sstevel@tonic-gate parsehostname(char *hostname, char *inst, char *realm)
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	char *h, *r;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	if (!hostname)
330*0Sstevel@tonic-gate 		return (0);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	h = (char *)strdup(hostname);
333*0Sstevel@tonic-gate 	if (!h) {
334*0Sstevel@tonic-gate 		syslog(LOG_ERR, "parsehostname: no memory\n");
335*0Sstevel@tonic-gate 		return (0);
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	r = (char *)strchr(h, '@');
339*0Sstevel@tonic-gate 	if (!r) {
340*0Sstevel@tonic-gate 		(void) strcpy(inst, h);
341*0Sstevel@tonic-gate 		(void) strcpy(realm, "");
342*0Sstevel@tonic-gate 	} else {
343*0Sstevel@tonic-gate 		*r++ = '\0';
344*0Sstevel@tonic-gate 		(void) strcpy(inst, h);
345*0Sstevel@tonic-gate 		(void) strcpy(realm, r);
346*0Sstevel@tonic-gate 	}
347*0Sstevel@tonic-gate 	free(h);
348*0Sstevel@tonic-gate 	return (1);
349*0Sstevel@tonic-gate }
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate /*
352*0Sstevel@tonic-gate  *  Get the name corresponding to a qop num.
353*0Sstevel@tonic-gate  */
354*0Sstevel@tonic-gate char *
355*0Sstevel@tonic-gate nfs_get_qop_name(seconfig_t *entryp)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	char	*tok;	/* holds a token from the line */
358*0Sstevel@tonic-gate 	char	*secname, *gss_qop = NULL; /* pointer to a secmode name */
359*0Sstevel@tonic-gate 	static	mutex_t matching_lock = DEFAULTMUTEX;
360*0Sstevel@tonic-gate 	char	line[BUFSIZ];	/* holds each line of NFSSEC_CONF */
361*0Sstevel@tonic-gate 	FILE	*fp;		/* file stream for NFSSEC_CONF */
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) {
364*0Sstevel@tonic-gate 	    return (NULL);
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	(void) mutex_lock(&matching_lock);
368*0Sstevel@tonic-gate 	while (fgets(line, BUFSIZ, fp)) {
369*0Sstevel@tonic-gate 	    if (!(blank(line) || comment(line))) {
370*0Sstevel@tonic-gate 		if ((secname = gettoken(line, FALSE)) == NULL) {
371*0Sstevel@tonic-gate 		    /* bad line */
372*0Sstevel@tonic-gate 		    continue;
373*0Sstevel@tonic-gate 		}
374*0Sstevel@tonic-gate 		if (strcmp(secname, entryp->sc_name) == 0) {
375*0Sstevel@tonic-gate 		    tok = NULL;
376*0Sstevel@tonic-gate 		    if ((tok = gettoken(NULL, FALSE)) == NULL) {
377*0Sstevel@tonic-gate 			/* bad line */
378*0Sstevel@tonic-gate 			goto err;
379*0Sstevel@tonic-gate 		    }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 		    if (atoi(tok) != entryp->sc_nfsnum)
382*0Sstevel@tonic-gate 			goto err;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 		    if ((gettoken(NULL, FALSE) == NULL) ||
385*0Sstevel@tonic-gate 			((gss_qop = gettoken(NULL, FALSE)) == NULL)) {
386*0Sstevel@tonic-gate 			goto err;
387*0Sstevel@tonic-gate 		    }
388*0Sstevel@tonic-gate 		    break;
389*0Sstevel@tonic-gate 		}
390*0Sstevel@tonic-gate 	    }
391*0Sstevel@tonic-gate 	}
392*0Sstevel@tonic-gate err:
393*0Sstevel@tonic-gate 	(void) mutex_unlock(&matching_lock);
394*0Sstevel@tonic-gate 	(void) fclose(fp);
395*0Sstevel@tonic-gate 	return (gss_qop);
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate /*
399*0Sstevel@tonic-gate  * This routine creates an auth handle assocaited with the
400*0Sstevel@tonic-gate  * negotiated security flavor contained in nfs_sec.  The auth
401*0Sstevel@tonic-gate  * handle will be used in the next LOOKUP request to fetch
402*0Sstevel@tonic-gate  * the filehandle.
403*0Sstevel@tonic-gate  */
404*0Sstevel@tonic-gate AUTH *
405*0Sstevel@tonic-gate nfs_create_ah(CLIENT *cl, char *hostname, seconfig_t *nfs_sec)
406*0Sstevel@tonic-gate {
407*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
408*0Sstevel@tonic-gate 	char svc_name[MAXNETNAMELEN+1];
409*0Sstevel@tonic-gate 	char *gss_qop;
410*0Sstevel@tonic-gate 	static int window = 60;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	if (nfs_sec == NULL)
413*0Sstevel@tonic-gate 	    goto err;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	switch (nfs_sec->sc_rpcnum) {
416*0Sstevel@tonic-gate 	    case AUTH_UNIX:
417*0Sstevel@tonic-gate 	    case AUTH_NONE:
418*0Sstevel@tonic-gate 		return (NULL);
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	    case AUTH_DES:
421*0Sstevel@tonic-gate 		if (!host2netname(netname, hostname, NULL))
422*0Sstevel@tonic-gate 		    goto err;
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 		return (authdes_seccreate(netname, window, hostname, NULL));
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	    case RPCSEC_GSS:
427*0Sstevel@tonic-gate 		if (cl == NULL)
428*0Sstevel@tonic-gate 		    goto err;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 		if (nfs_sec->sc_gss_mech_type == NULL) {
431*0Sstevel@tonic-gate 		    syslog(LOG_ERR,
432*0Sstevel@tonic-gate 			"nfs_create_ah: need mechanism information\n");
433*0Sstevel@tonic-gate 		    goto err;
434*0Sstevel@tonic-gate 		}
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 		/* RPCSEC_GSS service names are of the form svc@host.dom */
437*0Sstevel@tonic-gate 		(void) sprintf(svc_name, "nfs@%s", hostname);
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 		gss_qop = nfs_get_qop_name(nfs_sec);
440*0Sstevel@tonic-gate 		if (gss_qop == NULL)
441*0Sstevel@tonic-gate 		    goto err;
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 		return (rpc_gss_seccreate(cl, svc_name, nfs_sec->sc_gss_mech,
444*0Sstevel@tonic-gate 			nfs_sec->sc_service, gss_qop, NULL, NULL));
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	    default:
447*0Sstevel@tonic-gate 		syslog(LOG_ERR, "nfs_create_ah: unknown flavor\n");
448*0Sstevel@tonic-gate 		return (NULL);
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate err:
451*0Sstevel@tonic-gate 	syslog(LOG_ERR, "nfs_create_ah: failed to make auth handle\n");
452*0Sstevel@tonic-gate 	return (NULL);
453*0Sstevel@tonic-gate }
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate #ifdef WNFS_SEC_NEGO
456*0Sstevel@tonic-gate /*
457*0Sstevel@tonic-gate  * This routine negotiates sec flavors with server and returns:
458*0Sstevel@tonic-gate  *	SNEGO_SUCCESS:		successful; sec flavors are
459*0Sstevel@tonic-gate  *				returned in snego,
460*0Sstevel@tonic-gate  *	SNEGO_DEF_VALID:	default sec flavor valid; no need
461*0Sstevel@tonic-gate  *				to negotiate flavors,
462*0Sstevel@tonic-gate  *	SNEGO_ARRAY_TOO_SMALL:	array too small,
463*0Sstevel@tonic-gate  *	SNEGO_FAILURE:		failure
464*0Sstevel@tonic-gate  */
465*0Sstevel@tonic-gate /*
466*0Sstevel@tonic-gate  * The following depicts how sec flavors are placed in an
467*0Sstevel@tonic-gate  * overloaded V2 fhandle:
468*0Sstevel@tonic-gate  *
469*0Sstevel@tonic-gate  * Note that the first four octets contain the length octet,
470*0Sstevel@tonic-gate  * the status octet, and two padded octets to make them XDR
471*0Sstevel@tonic-gate  * four-octet aligned.
472*0Sstevel@tonic-gate  *
473*0Sstevel@tonic-gate  *   1   2   3   4                                          32
474*0Sstevel@tonic-gate  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
475*0Sstevel@tonic-gate  * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
476*0Sstevel@tonic-gate  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
477*0Sstevel@tonic-gate  *
478*0Sstevel@tonic-gate  * where
479*0Sstevel@tonic-gate  *
480*0Sstevel@tonic-gate  *   the status octet s indicates whether there are more security
481*0Sstevel@tonic-gate  *   flavors(1 means yes, 0 means no) that require the client to
482*0Sstevel@tonic-gate  *   perform another 0x81 LOOKUP to get them,
483*0Sstevel@tonic-gate  *
484*0Sstevel@tonic-gate  *   the length octet l is the length describing the number of
485*0Sstevel@tonic-gate  *   valid octets that follow.  (l = 4 * n, where n is the number
486*0Sstevel@tonic-gate  *
487*0Sstevel@tonic-gate  * The following depicts how sec flavors are placed in an
488*0Sstevel@tonic-gate  * overloaded V3 fhandle:
489*0Sstevel@tonic-gate  *
490*0Sstevel@tonic-gate  *  1        4
491*0Sstevel@tonic-gate  * +--+--+--+--+
492*0Sstevel@tonic-gate  * |    len    |
493*0Sstevel@tonic-gate  * +--+--+--+--+
494*0Sstevel@tonic-gate  *                                               up to 64
495*0Sstevel@tonic-gate  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
496*0Sstevel@tonic-gate  * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
497*0Sstevel@tonic-gate  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
498*0Sstevel@tonic-gate  *
499*0Sstevel@tonic-gate  * len = 4 * (n+1), where n is the number of security flavors
500*0Sstevel@tonic-gate  * sent in the current overloaded filehandle.
501*0Sstevel@tonic-gate  *
502*0Sstevel@tonic-gate  * the status octet s indicates whether there are more security
503*0Sstevel@tonic-gate  * mechanisms(1 means yes, 0 means no) that require the client
504*0Sstevel@tonic-gate  * to perform another 0x81 LOOKUP to get them.
505*0Sstevel@tonic-gate  *
506*0Sstevel@tonic-gate  * Three octets are padded after the status octet.
507*0Sstevel@tonic-gate  */
508*0Sstevel@tonic-gate enum snego_stat
509*0Sstevel@tonic-gate nfs_sec_nego(rpcprog_t vers, CLIENT *clnt, char *fspath, struct snego_t *snego)
510*0Sstevel@tonic-gate {
511*0Sstevel@tonic-gate 	enum clnt_stat rpc_stat;
512*0Sstevel@tonic-gate 	static int MAX_V2_CNT = (WNL_FHSIZE/sizeof (int)) - 1;
513*0Sstevel@tonic-gate 	static int MAX_V3_CNT = (WNL3_FHSIZE/sizeof (int)) - 1;
514*0Sstevel@tonic-gate 	static struct timeval TIMEOUT = { 25, 0 };
515*0Sstevel@tonic-gate 	int status;
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	if (clnt == NULL || fspath == NULL || snego == NULL)
518*0Sstevel@tonic-gate 	    return (SNEGO_FAILURE);
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	if (vers == WNL_V2) {
521*0Sstevel@tonic-gate 	    wnl_diropargs arg;
522*0Sstevel@tonic-gate 	    wnl_diropres clnt_res;
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	    memset((char *)&arg.dir, 0, sizeof (wnl_fh));
525*0Sstevel@tonic-gate 	    arg.name = fspath;
526*0Sstevel@tonic-gate 	    memset((char *)&clnt_res, 0, sizeof (clnt_res));
527*0Sstevel@tonic-gate 	    rpc_stat = clnt_call(clnt, WNLPROC_LOOKUP,
528*0Sstevel@tonic-gate 		    (xdrproc_t)xdr_wnl_diropargs, (caddr_t)&arg,
529*0Sstevel@tonic-gate 		    (xdrproc_t)xdr_wnl_diropres, (caddr_t)&clnt_res,
530*0Sstevel@tonic-gate 			TIMEOUT);
531*0Sstevel@tonic-gate 	    if (rpc_stat == RPC_SUCCESS && clnt_res.status == WNL_OK)
532*0Sstevel@tonic-gate 		return (SNEGO_DEF_VALID);
533*0Sstevel@tonic-gate 	    if (rpc_stat != RPC_AUTHERROR)
534*0Sstevel@tonic-gate 		return (SNEGO_FAILURE);
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 	    {
537*0Sstevel@tonic-gate 		struct rpc_err e;
538*0Sstevel@tonic-gate 		wnl_diropres *res;
539*0Sstevel@tonic-gate 		char *p;
540*0Sstevel@tonic-gate 		int tot = 0;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 		CLNT_GETERR(clnt, &e);
543*0Sstevel@tonic-gate 		if (e.re_why != AUTH_TOOWEAK)
544*0Sstevel@tonic-gate 		    return (SNEGO_FAILURE);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		if ((p = malloc(strlen(fspath)+3)) == NULL) {
547*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "no memory\n");
548*0Sstevel@tonic-gate 		    return (SNEGO_FAILURE);
549*0Sstevel@tonic-gate 		}
550*0Sstevel@tonic-gate 		/*
551*0Sstevel@tonic-gate 		 * Do an x81 LOOKUP
552*0Sstevel@tonic-gate 		 */
553*0Sstevel@tonic-gate 		p[0] = (char)WNL_SEC_NEGO;
554*0Sstevel@tonic-gate 		strcpy(&p[2], fspath);
555*0Sstevel@tonic-gate 		do {
556*0Sstevel@tonic-gate 		    p[1] = (char)(1+snego->cnt); /* sec index */
557*0Sstevel@tonic-gate 		    arg.name = p;
558*0Sstevel@tonic-gate 		    res = wnlproc_lookup_2(&arg, clnt);
559*0Sstevel@tonic-gate 		    if (res == NULL || res->status != WNL_OK) {
560*0Sstevel@tonic-gate 			free(p);
561*0Sstevel@tonic-gate 			return (SNEGO_FAILURE);
562*0Sstevel@tonic-gate 		    }
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 			/*
565*0Sstevel@tonic-gate 			 * retrieve flavors from filehandle:
566*0Sstevel@tonic-gate 			 *	1st byte: length
567*0Sstevel@tonic-gate 			 *	2nd byte: status
568*0Sstevel@tonic-gate 			 *	3rd & 4th: pad
569*0Sstevel@tonic-gate 			 *	5th and after: sec flavors.
570*0Sstevel@tonic-gate 			 */
571*0Sstevel@tonic-gate 		    {
572*0Sstevel@tonic-gate 			char *c = (char *)&res->wnl_diropres_u.
573*0Sstevel@tonic-gate 			    wnl_diropres.file;
574*0Sstevel@tonic-gate 			int ii;
575*0Sstevel@tonic-gate 			int cnt = ((int)*c)/sizeof (uint_t);
576*0Sstevel@tonic-gate 			/* LINTED pointer alignment */
577*0Sstevel@tonic-gate 			int *ip = (int *)(c+sizeof (int));
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 			tot += cnt;
580*0Sstevel@tonic-gate 			if (tot >= MAX_FLAVORS) {
581*0Sstevel@tonic-gate 			    free(p);
582*0Sstevel@tonic-gate 			    return (SNEGO_ARRAY_TOO_SMALL);
583*0Sstevel@tonic-gate 			}
584*0Sstevel@tonic-gate 			status = (int)*(c+1);
585*0Sstevel@tonic-gate 			if (cnt > MAX_V2_CNT || cnt < 0) {
586*0Sstevel@tonic-gate 			    free(p);
587*0Sstevel@tonic-gate 			    return (SNEGO_FAILURE);
588*0Sstevel@tonic-gate 			}
589*0Sstevel@tonic-gate 			for (ii = 0; ii < cnt; ii++)
590*0Sstevel@tonic-gate 			    snego->array[snego->cnt+ii] =
591*0Sstevel@tonic-gate 				ntohl(*(ip+ii));
592*0Sstevel@tonic-gate 			snego->cnt += cnt;
593*0Sstevel@tonic-gate 		    }
594*0Sstevel@tonic-gate 		} while (status);
595*0Sstevel@tonic-gate 		free(p);
596*0Sstevel@tonic-gate 		return (SNEGO_SUCCESS);
597*0Sstevel@tonic-gate 	    }
598*0Sstevel@tonic-gate 	} else if (vers == WNL_V3) {
599*0Sstevel@tonic-gate 	    WNL_LOOKUP3args arg;
600*0Sstevel@tonic-gate 	    WNL_LOOKUP3res clnt_res;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	    memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
603*0Sstevel@tonic-gate 	    arg.what.name = fspath;
604*0Sstevel@tonic-gate 	    arg.what.dir.data.data_len = 0;
605*0Sstevel@tonic-gate 	    arg.what.dir.data.data_val = 0;
606*0Sstevel@tonic-gate 	    memset((char *)&clnt_res, 0, sizeof (clnt_res));
607*0Sstevel@tonic-gate 	    rpc_stat = clnt_call(clnt, WNLPROC3_LOOKUP,
608*0Sstevel@tonic-gate 		(xdrproc_t)xdr_WNL_LOOKUP3args, (caddr_t)&arg,
609*0Sstevel@tonic-gate 		(xdrproc_t)xdr_WNL_LOOKUP3res, (caddr_t)&clnt_res,
610*0Sstevel@tonic-gate 		TIMEOUT);
611*0Sstevel@tonic-gate 	    if (rpc_stat == RPC_SUCCESS && clnt_res.status == WNL3_OK)
612*0Sstevel@tonic-gate 		return (SNEGO_DEF_VALID);
613*0Sstevel@tonic-gate 	    if (rpc_stat != RPC_AUTHERROR)
614*0Sstevel@tonic-gate 		return (SNEGO_FAILURE);
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	    {
617*0Sstevel@tonic-gate 		struct rpc_err e;
618*0Sstevel@tonic-gate 		WNL_LOOKUP3res *res;
619*0Sstevel@tonic-gate 		char *p;
620*0Sstevel@tonic-gate 		int tot = 0;
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 		CLNT_GETERR(clnt, &e);
623*0Sstevel@tonic-gate 		if (e.re_why != AUTH_TOOWEAK)
624*0Sstevel@tonic-gate 		    return (SNEGO_FAILURE);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 		if ((p = malloc(strlen(fspath)+3)) == NULL) {
627*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "no memory\n");
628*0Sstevel@tonic-gate 		    return (SNEGO_FAILURE);
629*0Sstevel@tonic-gate 		}
630*0Sstevel@tonic-gate 		/*
631*0Sstevel@tonic-gate 		 * Do an x81 LOOKUP
632*0Sstevel@tonic-gate 		 */
633*0Sstevel@tonic-gate 		p[0] = (char)WNL_SEC_NEGO;
634*0Sstevel@tonic-gate 		strcpy(&p[2], fspath);
635*0Sstevel@tonic-gate 		do {
636*0Sstevel@tonic-gate 		    p[1] = (char)(1+snego->cnt); /* sec index */
637*0Sstevel@tonic-gate 		    arg.what.name = p;
638*0Sstevel@tonic-gate 		    res = wnlproc3_lookup_3(&arg, clnt);
639*0Sstevel@tonic-gate 		    if (res == NULL || res->status != WNL3_OK) {
640*0Sstevel@tonic-gate 			free(p);
641*0Sstevel@tonic-gate 			return (SNEGO_FAILURE);
642*0Sstevel@tonic-gate 		    }
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 			/*
645*0Sstevel@tonic-gate 			 * retrieve flavors from filehandle:
646*0Sstevel@tonic-gate 			 *
647*0Sstevel@tonic-gate 			 * 1st byte: status
648*0Sstevel@tonic-gate 			 * 2nd thru 4th: pad
649*0Sstevel@tonic-gate 			 * 5th and after: sec flavors.
650*0Sstevel@tonic-gate 			 */
651*0Sstevel@tonic-gate 		    {
652*0Sstevel@tonic-gate 			char *c = res->WNL_LOOKUP3res_u.res_ok.
653*0Sstevel@tonic-gate 			    object.data.data_val;
654*0Sstevel@tonic-gate 			int ii;
655*0Sstevel@tonic-gate 			int len = res->WNL_LOOKUP3res_u.res_ok.
656*0Sstevel@tonic-gate 			    object.data.data_len;
657*0Sstevel@tonic-gate 			int cnt;
658*0Sstevel@tonic-gate 			/* LINTED pointer alignment */
659*0Sstevel@tonic-gate 			int *ip = (int *)(c+sizeof (int));
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 			cnt = len/sizeof (uint_t) - 1;
662*0Sstevel@tonic-gate 			tot += cnt;
663*0Sstevel@tonic-gate 			if (tot >= MAX_FLAVORS) {
664*0Sstevel@tonic-gate 			    free(p);
665*0Sstevel@tonic-gate 			    return (SNEGO_ARRAY_TOO_SMALL);
666*0Sstevel@tonic-gate 			}
667*0Sstevel@tonic-gate 			status = (int)(*c);
668*0Sstevel@tonic-gate 			if (cnt > MAX_V3_CNT || cnt < 0) {
669*0Sstevel@tonic-gate 			    free(p);
670*0Sstevel@tonic-gate 			    return (SNEGO_FAILURE);
671*0Sstevel@tonic-gate 			}
672*0Sstevel@tonic-gate 			for (ii = 0; ii < cnt; ii++)
673*0Sstevel@tonic-gate 			    snego->array[snego->cnt+ii] =
674*0Sstevel@tonic-gate 				ntohl(*(ip+ii));
675*0Sstevel@tonic-gate 			snego->cnt += cnt;
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 			CLNT_FREERES(clnt, xdr_WNL_LOOKUP3res,
678*0Sstevel@tonic-gate 			    (char *)res);
679*0Sstevel@tonic-gate 		    }
680*0Sstevel@tonic-gate 		} while (status);
681*0Sstevel@tonic-gate 		free(p);
682*0Sstevel@tonic-gate 		return (SNEGO_SUCCESS);
683*0Sstevel@tonic-gate 	    }
684*0Sstevel@tonic-gate 	}
685*0Sstevel@tonic-gate 	return (SNEGO_FAILURE);
686*0Sstevel@tonic-gate }
687*0Sstevel@tonic-gate #endif
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate /*
690*0Sstevel@tonic-gate  *  Get seconfig from /etc/nfssec.conf by name or by number or
691*0Sstevel@tonic-gate  *  by descriptior.
692*0Sstevel@tonic-gate  */
693*0Sstevel@tonic-gate /* ARGSUSED */
694*0Sstevel@tonic-gate static int
695*0Sstevel@tonic-gate get_seconfig(int whichway, char *name, int num,
696*0Sstevel@tonic-gate 		rpc_gss_service_t service, seconfig_t *entryp)
697*0Sstevel@tonic-gate {
698*0Sstevel@tonic-gate 	static	mutex_t matching_lock = DEFAULTMUTEX;
699*0Sstevel@tonic-gate 	char	line[BUFSIZ];	/* holds each line of NFSSEC_CONF */
700*0Sstevel@tonic-gate 	FILE	*fp;		/* file stream for NFSSEC_CONF */
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	if ((whichway == GETBYNAME) && (name == NULL))
703*0Sstevel@tonic-gate 		return (SC_NOTFOUND);
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) {
706*0Sstevel@tonic-gate 		return (SC_OPENFAIL);
707*0Sstevel@tonic-gate 	}
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 	(void) mutex_lock(&matching_lock);
710*0Sstevel@tonic-gate 	while (fgets(line, BUFSIZ, fp)) {
711*0Sstevel@tonic-gate 	    if (!(blank(line) || comment(line))) {
712*0Sstevel@tonic-gate 		switch (whichway) {
713*0Sstevel@tonic-gate 		    case GETBYNAME:
714*0Sstevel@tonic-gate 			if (matchname(line, name, entryp)) {
715*0Sstevel@tonic-gate 				goto found;
716*0Sstevel@tonic-gate 			}
717*0Sstevel@tonic-gate 			break;
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 		    case GETBYNUM:
720*0Sstevel@tonic-gate 			if (matchnum(line, num, entryp)) {
721*0Sstevel@tonic-gate 				goto found;
722*0Sstevel@tonic-gate 			}
723*0Sstevel@tonic-gate 			break;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		    default:
726*0Sstevel@tonic-gate 			break;
727*0Sstevel@tonic-gate 		}
728*0Sstevel@tonic-gate 	    }
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 	(void) mutex_unlock(&matching_lock);
731*0Sstevel@tonic-gate 	(void) fclose(fp);
732*0Sstevel@tonic-gate 	return (SC_NOTFOUND);
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate found:
735*0Sstevel@tonic-gate 	(void) mutex_unlock(&matching_lock);
736*0Sstevel@tonic-gate 	(void) fclose(fp);
737*0Sstevel@tonic-gate 	(void) get_rpcnum(entryp);
738*0Sstevel@tonic-gate 	return (SC_NOERROR);
739*0Sstevel@tonic-gate }
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate /*
743*0Sstevel@tonic-gate  *  NFS project private API.
744*0Sstevel@tonic-gate  *  Get a seconfig entry from /etc/nfssec.conf by nfs specific sec name,
745*0Sstevel@tonic-gate  *  e.g. des, krb5p, etc.
746*0Sstevel@tonic-gate  */
747*0Sstevel@tonic-gate int
748*0Sstevel@tonic-gate nfs_getseconfig_byname(char *secmode_name, seconfig_t *entryp)
749*0Sstevel@tonic-gate {
750*0Sstevel@tonic-gate 	if (!entryp)
751*0Sstevel@tonic-gate 		return (SC_NOMEM);
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	return (get_seconfig(GETBYNAME, secmode_name, 0, rpc_gss_svc_none,
754*0Sstevel@tonic-gate 			entryp));
755*0Sstevel@tonic-gate }
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate /*
758*0Sstevel@tonic-gate  *  NFS project private API.
759*0Sstevel@tonic-gate  *
760*0Sstevel@tonic-gate  *  Get a seconfig entry from /etc/nfssec.conf by nfs specific sec number,
761*0Sstevel@tonic-gate  *  e.g. AUTH_DES, AUTH_KRB5_P, etc.
762*0Sstevel@tonic-gate  */
763*0Sstevel@tonic-gate int
764*0Sstevel@tonic-gate nfs_getseconfig_bynumber(int nfs_secnum, seconfig_t *entryp)
765*0Sstevel@tonic-gate {
766*0Sstevel@tonic-gate 	if (!entryp)
767*0Sstevel@tonic-gate 		return (SC_NOMEM);
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 	return (get_seconfig(GETBYNUM, NULL, nfs_secnum, rpc_gss_svc_none,
770*0Sstevel@tonic-gate 				entryp));
771*0Sstevel@tonic-gate }
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate /*
774*0Sstevel@tonic-gate  *  NFS project private API.
775*0Sstevel@tonic-gate  *
776*0Sstevel@tonic-gate  *  Get a seconfig_t entry used as the default for NFS operations.
777*0Sstevel@tonic-gate  *  The default flavor entry is defined in /etc/nfssec.conf.
778*0Sstevel@tonic-gate  *
779*0Sstevel@tonic-gate  *  Assume user has allocate spaces for secp.
780*0Sstevel@tonic-gate  */
781*0Sstevel@tonic-gate int
782*0Sstevel@tonic-gate nfs_getseconfig_default(seconfig_t *secp)
783*0Sstevel@tonic-gate {
784*0Sstevel@tonic-gate 	if (secp == NULL)
785*0Sstevel@tonic-gate 		return (SC_NOMEM);
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	return (nfs_getseconfig_byname("default", secp));
788*0Sstevel@tonic-gate }
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate /*
792*0Sstevel@tonic-gate  *  NFS project private API.
793*0Sstevel@tonic-gate  *
794*0Sstevel@tonic-gate  *  Free an sec_data structure.
795*0Sstevel@tonic-gate  *  Free the parts that nfs_clnt_secdata allocates.
796*0Sstevel@tonic-gate  */
797*0Sstevel@tonic-gate void
798*0Sstevel@tonic-gate nfs_free_secdata(sec_data_t *secdata)
799*0Sstevel@tonic-gate {
800*0Sstevel@tonic-gate 	dh_k4_clntdata_t *dkdata;
801*0Sstevel@tonic-gate 	gss_clntdata_t *gdata;
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	if (!secdata)
804*0Sstevel@tonic-gate 		return;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
807*0Sstevel@tonic-gate 	    case AUTH_UNIX:
808*0Sstevel@tonic-gate 	    case AUTH_NONE:
809*0Sstevel@tonic-gate 		break;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	    case AUTH_DES:
812*0Sstevel@tonic-gate 		/* LINTED pointer alignment */
813*0Sstevel@tonic-gate 		dkdata = (dh_k4_clntdata_t *)secdata->data;
814*0Sstevel@tonic-gate 		if (dkdata) {
815*0Sstevel@tonic-gate 			if (dkdata->netname)
816*0Sstevel@tonic-gate 				free(dkdata->netname);
817*0Sstevel@tonic-gate 			if (dkdata->syncaddr.buf)
818*0Sstevel@tonic-gate 				free(dkdata->syncaddr.buf);
819*0Sstevel@tonic-gate 			free(dkdata);
820*0Sstevel@tonic-gate 		}
821*0Sstevel@tonic-gate 		break;
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	    case RPCSEC_GSS:
824*0Sstevel@tonic-gate 		/* LINTED pointer alignment */
825*0Sstevel@tonic-gate 		gdata = (gss_clntdata_t *)secdata->data;
826*0Sstevel@tonic-gate 		if (gdata) {
827*0Sstevel@tonic-gate 			if (gdata->mechanism.elements)
828*0Sstevel@tonic-gate 				free(gdata->mechanism.elements);
829*0Sstevel@tonic-gate 			free(gdata);
830*0Sstevel@tonic-gate 		}
831*0Sstevel@tonic-gate 		break;
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	    default:
834*0Sstevel@tonic-gate 		break;
835*0Sstevel@tonic-gate 	}
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 	free(secdata);
838*0Sstevel@tonic-gate }
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate /*
841*0Sstevel@tonic-gate  *  Make an client side sec_data structure and fill in appropriate value
842*0Sstevel@tonic-gate  *  based on its rpc security flavor.
843*0Sstevel@tonic-gate  *
844*0Sstevel@tonic-gate  *  It is caller's responsibility to allocate space for seconfig_t,
845*0Sstevel@tonic-gate  *  and this routine will allocate space for the sec_data structure
846*0Sstevel@tonic-gate  *  and related data field.
847*0Sstevel@tonic-gate  *
848*0Sstevel@tonic-gate  *  Return the sec_data_t on success.
849*0Sstevel@tonic-gate  *  If fail, return NULL pointer.
850*0Sstevel@tonic-gate  */
851*0Sstevel@tonic-gate sec_data_t *
852*0Sstevel@tonic-gate nfs_clnt_secdata(seconfig_t *secp, char *hostname, struct knetconfig *knconf,
853*0Sstevel@tonic-gate 		struct netbuf *syncaddr, int flags)
854*0Sstevel@tonic-gate {
855*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
856*0Sstevel@tonic-gate 	sec_data_t *secdata;
857*0Sstevel@tonic-gate 	dh_k4_clntdata_t *dkdata;
858*0Sstevel@tonic-gate 	gss_clntdata_t *gdata;
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	secdata = malloc(sizeof (sec_data_t));
861*0Sstevel@tonic-gate 	if (!secdata) {
862*0Sstevel@tonic-gate 		syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
863*0Sstevel@tonic-gate 		return (NULL);
864*0Sstevel@tonic-gate 	}
865*0Sstevel@tonic-gate 	(void) memset(secdata, 0, sizeof (sec_data_t));
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	secdata->secmod = secp->sc_nfsnum;
868*0Sstevel@tonic-gate 	secdata->rpcflavor = secp->sc_rpcnum;
869*0Sstevel@tonic-gate 	secdata->uid = secp->sc_uid;
870*0Sstevel@tonic-gate 	secdata->flags = flags;
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	/*
873*0Sstevel@tonic-gate 	 *  Now, fill in the information for client side secdata :
874*0Sstevel@tonic-gate 	 *
875*0Sstevel@tonic-gate 	 *  For AUTH_UNIX, AUTH_DES
876*0Sstevel@tonic-gate 	 *  hostname can be in the form of
877*0Sstevel@tonic-gate 	 *    nodename or
878*0Sstevel@tonic-gate 	 *    nodename.domain
879*0Sstevel@tonic-gate 	 *
880*0Sstevel@tonic-gate 	 *  For RPCSEC_GSS security flavor
881*0Sstevel@tonic-gate 	 *  hostname can be in the form of
882*0Sstevel@tonic-gate 	 *    nodename or
883*0Sstevel@tonic-gate 	 *    nodename.domain  or
884*0Sstevel@tonic-gate 	 *    nodename@realm (realm can be the same as the domain) or
885*0Sstevel@tonic-gate 	 *    nodename.domain@realm
886*0Sstevel@tonic-gate 	 */
887*0Sstevel@tonic-gate 	switch (secp->sc_rpcnum) {
888*0Sstevel@tonic-gate 	    case AUTH_UNIX:
889*0Sstevel@tonic-gate 	    case AUTH_NONE:
890*0Sstevel@tonic-gate 		secdata->data = NULL;
891*0Sstevel@tonic-gate 		break;
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	    case AUTH_DES:
894*0Sstevel@tonic-gate 		/*
895*0Sstevel@tonic-gate 		 *  If hostname is in the format of host.nisdomain
896*0Sstevel@tonic-gate 		 *  the netname will be constructed with
897*0Sstevel@tonic-gate 		 *  this nisdomain name rather than the default
898*0Sstevel@tonic-gate 		 *  domain of the machine.
899*0Sstevel@tonic-gate 		 */
900*0Sstevel@tonic-gate 		    if (!host2netname(netname, hostname, NULL)) {
901*0Sstevel@tonic-gate 			syslog(LOG_ERR, "host2netname: %s: unknown\n",
902*0Sstevel@tonic-gate 				hostname);
903*0Sstevel@tonic-gate 			goto err_out;
904*0Sstevel@tonic-gate 		    }
905*0Sstevel@tonic-gate 		dkdata = malloc(sizeof (dh_k4_clntdata_t));
906*0Sstevel@tonic-gate 		if (!dkdata) {
907*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
908*0Sstevel@tonic-gate 		    goto err_out;
909*0Sstevel@tonic-gate 		}
910*0Sstevel@tonic-gate 		(void) memset((char *)dkdata, 0, sizeof (dh_k4_clntdata_t));
911*0Sstevel@tonic-gate 		if ((dkdata->netname = strdup(netname)) == NULL) {
912*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
913*0Sstevel@tonic-gate 		    goto err_out;
914*0Sstevel@tonic-gate 		}
915*0Sstevel@tonic-gate 		dkdata->netnamelen = strlen(netname);
916*0Sstevel@tonic-gate 		dkdata->knconf = knconf;
917*0Sstevel@tonic-gate 		dkdata->syncaddr = *syncaddr;
918*0Sstevel@tonic-gate 		dkdata->syncaddr.buf = malloc(syncaddr->len);
919*0Sstevel@tonic-gate 		if (dkdata->syncaddr.buf == NULL) {
920*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
921*0Sstevel@tonic-gate 		    goto err_out;
922*0Sstevel@tonic-gate 		}
923*0Sstevel@tonic-gate 		(void) memcpy(dkdata->syncaddr.buf, syncaddr->buf,
924*0Sstevel@tonic-gate 						syncaddr->len);
925*0Sstevel@tonic-gate 		secdata->data = (caddr_t)dkdata;
926*0Sstevel@tonic-gate 		break;
927*0Sstevel@tonic-gate 
928*0Sstevel@tonic-gate 	    case RPCSEC_GSS: {
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 		if (secp->sc_gss_mech_type == NULL) {
931*0Sstevel@tonic-gate 		    syslog(LOG_ERR,
932*0Sstevel@tonic-gate 			"nfs_clnt_secdata: need mechanism information\n");
933*0Sstevel@tonic-gate 		    goto err_out;
934*0Sstevel@tonic-gate 		}
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 		gdata = malloc(sizeof (gss_clntdata_t));
937*0Sstevel@tonic-gate 		if (!gdata) {
938*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
939*0Sstevel@tonic-gate 		    goto err_out;
940*0Sstevel@tonic-gate 		}
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 		(void) strcpy(gdata->uname, "nfs");
943*0Sstevel@tonic-gate 		if (!parsehostname(hostname, gdata->inst, gdata->realm)) {
944*0Sstevel@tonic-gate 		    syslog(LOG_ERR, "nfs_clnt_secdata: bad host name\n");
945*0Sstevel@tonic-gate 		    goto err_out;
946*0Sstevel@tonic-gate 		}
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 		gdata->mechanism.length = secp->sc_gss_mech_type->length;
949*0Sstevel@tonic-gate 		if (!(gdata->mechanism.elements =
950*0Sstevel@tonic-gate 			malloc(secp->sc_gss_mech_type->length))) {
951*0Sstevel@tonic-gate 			syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n");
952*0Sstevel@tonic-gate 			goto err_out;
953*0Sstevel@tonic-gate 		}
954*0Sstevel@tonic-gate 		(void) memcpy(gdata->mechanism.elements,
955*0Sstevel@tonic-gate 			secp->sc_gss_mech_type->elements,
956*0Sstevel@tonic-gate 			secp->sc_gss_mech_type->length);
957*0Sstevel@tonic-gate 
958*0Sstevel@tonic-gate 		gdata->qop = secp->sc_qop;
959*0Sstevel@tonic-gate 		gdata->service = secp->sc_service;
960*0Sstevel@tonic-gate 		secdata->data = (caddr_t)gdata;
961*0Sstevel@tonic-gate 	    }
962*0Sstevel@tonic-gate 	    break;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	    default:
965*0Sstevel@tonic-gate 		syslog(LOG_ERR, "nfs_clnt_secdata: unknown flavor\n");
966*0Sstevel@tonic-gate 		goto err_out;
967*0Sstevel@tonic-gate 	}
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	return (secdata);
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate err_out:
972*0Sstevel@tonic-gate 	free(secdata);
973*0Sstevel@tonic-gate 	return (NULL);
974*0Sstevel@tonic-gate }
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate /*
977*0Sstevel@tonic-gate  *  nfs_get_root_principal() maps a host name to its principal name
978*0Sstevel@tonic-gate  *  based on the given security information.
979*0Sstevel@tonic-gate  *
980*0Sstevel@tonic-gate  *  input :  seconfig - security configuration information
981*0Sstevel@tonic-gate  *		host - the host name which could be in the following forms:
982*0Sstevel@tonic-gate  *		node
983*0Sstevel@tonic-gate  *		node.namedomain
984*0Sstevel@tonic-gate  *		node@secdomain (e.g. kerberos realm is a secdomain)
985*0Sstevel@tonic-gate  *		node.namedomain@secdomain
986*0Sstevel@tonic-gate  *  output : rootname_p - address of the principal name for the host
987*0Sstevel@tonic-gate  *
988*0Sstevel@tonic-gate  *  Currently, this routine is only used by share program.
989*0Sstevel@tonic-gate  *
990*0Sstevel@tonic-gate  */
991*0Sstevel@tonic-gate bool_t
992*0Sstevel@tonic-gate nfs_get_root_principal(seconfig_t *seconfig, char *host, caddr_t *rootname_p)
993*0Sstevel@tonic-gate {
994*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1], node[MAX_NAME_LEN];
995*0Sstevel@tonic-gate 	char secdomain[MAX_NAME_LEN];
996*0Sstevel@tonic-gate 	rpc_gss_principal_t gssname;
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	switch (seconfig->sc_rpcnum) {
999*0Sstevel@tonic-gate 		case AUTH_DES:
1000*0Sstevel@tonic-gate 		    if (!host2netname(netname, host, NULL)) {
1001*0Sstevel@tonic-gate 			syslog(LOG_ERR,
1002*0Sstevel@tonic-gate 			    "nfs_get_root_principal: unknown host: %s\n", host);
1003*0Sstevel@tonic-gate 			return (FALSE);
1004*0Sstevel@tonic-gate 		    }
1005*0Sstevel@tonic-gate 		    *rootname_p = strdup(netname);
1006*0Sstevel@tonic-gate 		    if (!*rootname_p) {
1007*0Sstevel@tonic-gate 			syslog(LOG_ERR, "nfs_get_root_principal: no memory\n");
1008*0Sstevel@tonic-gate 			return (FALSE);
1009*0Sstevel@tonic-gate 		    }
1010*0Sstevel@tonic-gate 		    break;
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 		case RPCSEC_GSS:
1013*0Sstevel@tonic-gate 		    if (!parsehostname(host, node, secdomain)) {
1014*0Sstevel@tonic-gate 			syslog(LOG_ERR,
1015*0Sstevel@tonic-gate 			    "nfs_get_root_principal: bad host name\n");
1016*0Sstevel@tonic-gate 			return (FALSE);
1017*0Sstevel@tonic-gate 		    }
1018*0Sstevel@tonic-gate 		    if (!rpc_gss_get_principal_name(&gssname,
1019*0Sstevel@tonic-gate 				seconfig->sc_gss_mech, "root",
1020*0Sstevel@tonic-gate 				node, secdomain)) {
1021*0Sstevel@tonic-gate 			syslog(LOG_ERR,
1022*0Sstevel@tonic-gate 	"nfs_get_root_principal: can not get principal name : %s\n", host);
1023*0Sstevel@tonic-gate 			return (FALSE);
1024*0Sstevel@tonic-gate 		    }
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate 		    *rootname_p = (caddr_t)gssname;
1027*0Sstevel@tonic-gate 		    break;
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 		default:
1030*0Sstevel@tonic-gate 		    return (FALSE);
1031*0Sstevel@tonic-gate 	}
1032*0Sstevel@tonic-gate 	return (TRUE);
1033*0Sstevel@tonic-gate }
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 
1036*0Sstevel@tonic-gate /*
1037*0Sstevel@tonic-gate  *  SYSLOG SC_* errors.
1038*0Sstevel@tonic-gate  */
1039*0Sstevel@tonic-gate int
1040*0Sstevel@tonic-gate nfs_syslog_scerr(int scerror, char msg[])
1041*0Sstevel@tonic-gate {
1042*0Sstevel@tonic-gate 	switch (scerror) {
1043*0Sstevel@tonic-gate 		case SC_NOMEM :
1044*0Sstevel@tonic-gate 			sprintf(msg, "%s : no memory", NFSSEC_CONF);
1045*0Sstevel@tonic-gate 			return (0);
1046*0Sstevel@tonic-gate 		case SC_OPENFAIL :
1047*0Sstevel@tonic-gate 			sprintf(msg, "can not open %s", NFSSEC_CONF);
1048*0Sstevel@tonic-gate 			return (0);
1049*0Sstevel@tonic-gate 		case SC_NOTFOUND :
1050*0Sstevel@tonic-gate 			sprintf(msg, "has no entry in %s", NFSSEC_CONF);
1051*0Sstevel@tonic-gate 			return (0);
1052*0Sstevel@tonic-gate 		case SC_BADENTRIES :
1053*0Sstevel@tonic-gate 			sprintf(msg, "bad entry in %s", NFSSEC_CONF);
1054*0Sstevel@tonic-gate 			return (0);
1055*0Sstevel@tonic-gate 		default:
1056*0Sstevel@tonic-gate 			msg[0] = '\0';
1057*0Sstevel@tonic-gate 			return (-1);
1058*0Sstevel@tonic-gate 	}
1059*0Sstevel@tonic-gate }
1060