xref: /titanic_53/usr/src/lib/libnsl/rpc/ti_opts.c (revision ae347574c7f17d33bb822cb146d7f67c88ab1f68)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2161961e0fSrobinson 
227c478bd9Sstevel@tonic-gate /*
23e8031f0aSraf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26e8031f0aSraf 
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
317c478bd9Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
327c478bd9Sstevel@tonic-gate  * California.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
367c478bd9Sstevel@tonic-gate 
37e8031f0aSraf #include "mt.h"
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <netinet/in.h>
407c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
417c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
427c478bd9Sstevel@tonic-gate #include <inttypes.h>
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <tiuser.h>
457c478bd9Sstevel@tonic-gate #include <sys/socket.h>
467c478bd9Sstevel@tonic-gate #include <net/if.h>
477c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
487c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
497c478bd9Sstevel@tonic-gate #include <sys/tl.h>
507c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
517c478bd9Sstevel@tonic-gate #include <errno.h>
527c478bd9Sstevel@tonic-gate #include <libintl.h>
5361961e0fSrobinson #include <string.h>
547c478bd9Sstevel@tonic-gate #include <strings.h>
557c478bd9Sstevel@tonic-gate #include <syslog.h>
567c478bd9Sstevel@tonic-gate #include <unistd.h>
577c478bd9Sstevel@tonic-gate #include <ucred.h>
587c478bd9Sstevel@tonic-gate #include <alloca.h>
597c478bd9Sstevel@tonic-gate #include <stdlib.h>
607c478bd9Sstevel@tonic-gate #include <zone.h>
6145916cd2Sjpk #include <tsol/label.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate extern bool_t __svc_get_door_ucred(const SVCXPRT *, ucred_t *);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * This routine is typically called on the server side if the server
677c478bd9Sstevel@tonic-gate  * wants to know the caller ucred.  Called typically by rpcbind.  It
687c478bd9Sstevel@tonic-gate  * depends upon the t_optmgmt call to local transport driver so that
697c478bd9Sstevel@tonic-gate  * return the uid value in options in T_CONN_IND, T_CONN_CON and
707c478bd9Sstevel@tonic-gate  * T_UNITDATA_IND.
717c478bd9Sstevel@tonic-gate  * With the advent of the credential in the mblk, this is simply
727c478bd9Sstevel@tonic-gate  * extended to all transports when the packet travels over the
737c478bd9Sstevel@tonic-gate  * loopback network; for UDP we use a special socket option and for
747c478bd9Sstevel@tonic-gate  * tcp we don't need to do any setup, we just call getpeerucred()
757c478bd9Sstevel@tonic-gate  * later.
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Version for Solaris with new local transport code and ucred.
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate int
__rpc_negotiate_uid(int fd)8261961e0fSrobinson __rpc_negotiate_uid(int fd)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	struct strioctl strioc;
857c478bd9Sstevel@tonic-gate 	unsigned int set = 1;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	/* For tcp we use getpeerucred and it needs no initialization. */
887c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_FIND, "tcp") > 0)
897c478bd9Sstevel@tonic-gate 		return (0);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	strioc.ic_cmd = TL_IOC_UCREDOPT;
927c478bd9Sstevel@tonic-gate 	strioc.ic_timout = -1;
937c478bd9Sstevel@tonic-gate 	strioc.ic_len = (int)sizeof (unsigned int);
947c478bd9Sstevel@tonic-gate 	strioc.ic_dp = (char *)&set;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &strioc) == -1 &&
977c478bd9Sstevel@tonic-gate 	    __rpc_tli_set_options(fd, SOL_SOCKET, SO_RECVUCRED, 1) == -1) {
987c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_negotiate_uid (%s): %m",
997c478bd9Sstevel@tonic-gate 		    "ioctl:I_STR:TL_IOC_UCREDOPT/SO_RECVUCRED");
1007c478bd9Sstevel@tonic-gate 		return (-1);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 	return (0);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate void
svc_fd_negotiate_ucred(int fd)1067c478bd9Sstevel@tonic-gate svc_fd_negotiate_ucred(int fd)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	(void) __rpc_negotiate_uid(fd);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * This returns the ucred of the caller.  It assumes that the optbuf
1147c478bd9Sstevel@tonic-gate  * information is stored at xprt->xp_p2.
1157c478bd9Sstevel@tonic-gate  * There are three distinct cases: the option buffer is headed
1167c478bd9Sstevel@tonic-gate  * with a "struct opthdr" and the credential option is the only
1177c478bd9Sstevel@tonic-gate  * one, or it's a T_opthdr and our option may follow others; or there
1187c478bd9Sstevel@tonic-gate  * are no options and we attempt getpeerucred().
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate static int
find_ucred_opt(const SVCXPRT * trans,ucred_t * uc,bool_t checkzone)1217c478bd9Sstevel@tonic-gate find_ucred_opt(const SVCXPRT *trans, ucred_t *uc, bool_t checkzone)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
1247c478bd9Sstevel@tonic-gate 	struct netbuf *abuf = (struct netbuf *)trans->xp_p2;
1257c478bd9Sstevel@tonic-gate 	char *bufp, *maxbufp;
1267c478bd9Sstevel@tonic-gate 	struct opthdr *opth;
1277c478bd9Sstevel@tonic-gate 	static zoneid_t myzone = MIN_ZONEID - 1;	/* invalid */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if (abuf == NULL || abuf->buf == NULL) {
1307c478bd9Sstevel@tonic-gate 		if (getpeerucred(trans->xp_fd, &uc) == 0)
1317c478bd9Sstevel@tonic-gate 			goto verifyzone;
1327c478bd9Sstevel@tonic-gate 		return (-1);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
1367c478bd9Sstevel@tonic-gate 	syslog(LOG_INFO, "find_ucred_opt %p %x", abuf->buf, abuf->len);
1377c478bd9Sstevel@tonic-gate #endif
13861961e0fSrobinson 	/* LINTED pointer cast */
1397c478bd9Sstevel@tonic-gate 	opth = (struct opthdr *)abuf->buf;
1407c478bd9Sstevel@tonic-gate 	if (opth->level == TL_PROT_LEVEL &&
1417c478bd9Sstevel@tonic-gate 	    opth->name == TL_OPT_PEER_UCRED &&
1427c478bd9Sstevel@tonic-gate 	    opth->len + sizeof (*opth) == abuf->len) {
1437c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
1447c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO, "find_ucred_opt (opthdr): OK!");
1457c478bd9Sstevel@tonic-gate #endif
1467c478bd9Sstevel@tonic-gate 		(void) memcpy(uc, &opth[1], opth->len);
1477c478bd9Sstevel@tonic-gate 		/*
1487c478bd9Sstevel@tonic-gate 		 * Always from inside our zone because zones use a separate name
1497c478bd9Sstevel@tonic-gate 		 * space for loopback; at this time, the kernel may send a
1507c478bd9Sstevel@tonic-gate 		 * packet pretending to be from the global zone when it's
1517c478bd9Sstevel@tonic-gate 		 * really from our zone so we skip the zone check.
1527c478bd9Sstevel@tonic-gate 		 */
1537c478bd9Sstevel@tonic-gate 		return (0);
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	bufp = abuf->buf;
1577c478bd9Sstevel@tonic-gate 	maxbufp = bufp + abuf->len;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	while (bufp + sizeof (struct T_opthdr) < maxbufp) {
16061961e0fSrobinson 		/* LINTED pointer cast */
1617c478bd9Sstevel@tonic-gate 		struct T_opthdr *opt = (struct T_opthdr *)bufp;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
1647c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO, "find_ucred_opt opt: %p %x, %d %d", opt,
1657c478bd9Sstevel@tonic-gate 			opt->len, opt->name, opt->level);
1667c478bd9Sstevel@tonic-gate #endif
16761961e0fSrobinson 		if (opt->len > maxbufp - bufp || (opt->len & 3))
1687c478bd9Sstevel@tonic-gate 			return (-1);
1697c478bd9Sstevel@tonic-gate 		if (opt->level == SOL_SOCKET && opt->name == SCM_UCRED &&
1707c478bd9Sstevel@tonic-gate 		    opt->len - sizeof (struct T_opthdr) <= ucred_size()) {
1717c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
1727c478bd9Sstevel@tonic-gate 			syslog(LOG_INFO, "find_ucred_opt (T_opthdr): OK!");
1737c478bd9Sstevel@tonic-gate #endif
1747c478bd9Sstevel@tonic-gate 			(void) memcpy(uc, &opt[1],
1757c478bd9Sstevel@tonic-gate 			    opt->len - sizeof (struct T_opthdr));
1767c478bd9Sstevel@tonic-gate 			goto verifyzone;
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 		bufp += opt->len;
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 	if (getpeerucred(trans->xp_fd, &uc) != 0)
1817c478bd9Sstevel@tonic-gate 		return (-1);
1827c478bd9Sstevel@tonic-gate verifyzone:
1837c478bd9Sstevel@tonic-gate 	if (!checkzone)
1847c478bd9Sstevel@tonic-gate 		return (0);
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (myzone == MIN_ZONEID - 1)
1877c478bd9Sstevel@tonic-gate 		myzone = getzoneid();
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/* Return 0 only for the local zone */
1907c478bd9Sstevel@tonic-gate 	return (ucred_getzoneid(uc) == myzone ? 0 : -1);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate  * Version for Solaris with new local transport code
1957c478bd9Sstevel@tonic-gate  */
1967c478bd9Sstevel@tonic-gate int
__rpc_get_local_uid(SVCXPRT * trans,uid_t * uid_out)1977c478bd9Sstevel@tonic-gate __rpc_get_local_uid(SVCXPRT *trans, uid_t *uid_out)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	ucred_t *uc = alloca(ucred_size());
2007c478bd9Sstevel@tonic-gate 	int err;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/* LINTED - pointer alignment */
2037c478bd9Sstevel@tonic-gate 	if (svc_type(trans) == SVC_DOOR)
2047c478bd9Sstevel@tonic-gate 		err = __svc_get_door_ucred(trans, uc) == FALSE;
2057c478bd9Sstevel@tonic-gate 	else
2067c478bd9Sstevel@tonic-gate 		err = find_ucred_opt(trans, uc, B_TRUE);
2077c478bd9Sstevel@tonic-gate 
20861961e0fSrobinson 	if (err != 0)
2097c478bd9Sstevel@tonic-gate 		return (-1);
2107c478bd9Sstevel@tonic-gate 	*uid_out = ucred_geteuid(uc);
2117c478bd9Sstevel@tonic-gate 	return (0);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * Return local credentials.
2167c478bd9Sstevel@tonic-gate  */
2177c478bd9Sstevel@tonic-gate bool_t
__rpc_get_local_cred(SVCXPRT * xprt,svc_local_cred_t * lcred)2187c478bd9Sstevel@tonic-gate __rpc_get_local_cred(SVCXPRT *xprt, svc_local_cred_t *lcred)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	ucred_t *uc = alloca(ucred_size());
2217c478bd9Sstevel@tonic-gate 	int err;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/* LINTED - pointer alignment */
2247c478bd9Sstevel@tonic-gate 	if (svc_type(xprt) == SVC_DOOR)
2257c478bd9Sstevel@tonic-gate 		err = __svc_get_door_ucred(xprt, uc) == FALSE;
2267c478bd9Sstevel@tonic-gate 	else
2277c478bd9Sstevel@tonic-gate 		err = find_ucred_opt(xprt, uc, B_TRUE);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (err != 0)
2307c478bd9Sstevel@tonic-gate 		return (FALSE);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	lcred->euid = ucred_geteuid(uc);
2337c478bd9Sstevel@tonic-gate 	lcred->egid = ucred_getegid(uc);
2347c478bd9Sstevel@tonic-gate 	lcred->ruid = ucred_getruid(uc);
2357c478bd9Sstevel@tonic-gate 	lcred->rgid = ucred_getrgid(uc);
2367c478bd9Sstevel@tonic-gate 	lcred->pid = ucred_getpid(uc);
2377c478bd9Sstevel@tonic-gate 	return (TRUE);
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  * Return local ucred.
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate int
svc_getcallerucred(const SVCXPRT * trans,ucred_t ** uc)2447c478bd9Sstevel@tonic-gate svc_getcallerucred(const SVCXPRT *trans, ucred_t **uc)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate 	ucred_t *ucp = *uc;
2477c478bd9Sstevel@tonic-gate 	int err;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (ucp == NULL) {
2507c478bd9Sstevel@tonic-gate 		ucp = malloc(ucred_size());
2517c478bd9Sstevel@tonic-gate 		if (ucp == NULL)
2527c478bd9Sstevel@tonic-gate 			return (-1);
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	/* LINTED - pointer alignment */
2567c478bd9Sstevel@tonic-gate 	if (svc_type(trans) == SVC_DOOR)
2577c478bd9Sstevel@tonic-gate 		err = __svc_get_door_ucred(trans, ucp) == FALSE;
2587c478bd9Sstevel@tonic-gate 	else
2597c478bd9Sstevel@tonic-gate 		err = find_ucred_opt(trans, ucp, B_FALSE);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if (err != 0) {
2627c478bd9Sstevel@tonic-gate 		if (*uc == NULL)
2637c478bd9Sstevel@tonic-gate 			free(ucp);
2647c478bd9Sstevel@tonic-gate 		return (-1);
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	if (*uc == NULL)
2687c478bd9Sstevel@tonic-gate 		*uc = ucp;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	return (0);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * get local ip address
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate int
__rpc_get_ltaddr(struct netbuf * nbufp,struct netbuf * ltaddr)2787c478bd9Sstevel@tonic-gate __rpc_get_ltaddr(struct netbuf *nbufp, struct netbuf *ltaddr)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	unsigned int total_optlen;
2817c478bd9Sstevel@tonic-gate 	struct T_opthdr *opt, *opt_start = NULL, *opt_end;
2827c478bd9Sstevel@tonic-gate 	struct sockaddr_in *ipv4sa;
2837c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *ipv6sa;
2847c478bd9Sstevel@tonic-gate 	int s;
2857c478bd9Sstevel@tonic-gate 	struct sioc_addrreq areq;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	if (nbufp == (struct netbuf *)0 || ltaddr == (struct netbuf *)0) {
2887c478bd9Sstevel@tonic-gate 		t_errno = TBADOPT;
2897c478bd9Sstevel@tonic-gate 		return (-1);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	total_optlen = nbufp->len;
2937c478bd9Sstevel@tonic-gate 	if (total_optlen == 0)
2947c478bd9Sstevel@tonic-gate 		return (1);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
2977c478bd9Sstevel@tonic-gate 	opt_start = (struct T_opthdr *)nbufp->buf;
2987c478bd9Sstevel@tonic-gate 	if (opt_start == NULL) {
2997c478bd9Sstevel@tonic-gate 		t_errno = TBADOPT;
3007c478bd9Sstevel@tonic-gate 		return (-1);
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/* Make sure the start of the buffer is aligned */
3047c478bd9Sstevel@tonic-gate 	if (!(__TPI_TOPT_ISALIGNED(opt_start))) {
3057c478bd9Sstevel@tonic-gate 		t_errno = TBADOPT;
3067c478bd9Sstevel@tonic-gate 		return (-1);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
3107c478bd9Sstevel@tonic-gate 	opt_end = (struct T_opthdr *)((uchar_t *)opt_start + total_optlen);
3117c478bd9Sstevel@tonic-gate 	opt = opt_start;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/*
3147c478bd9Sstevel@tonic-gate 	 * Look for the desired option header
3157c478bd9Sstevel@tonic-gate 	 */
3167c478bd9Sstevel@tonic-gate 	do {
3177c478bd9Sstevel@tonic-gate 		if (((uchar_t *)opt + sizeof (struct T_opthdr)) >
3187c478bd9Sstevel@tonic-gate 		    (uchar_t *)opt_end) {
3197c478bd9Sstevel@tonic-gate 			t_errno = TBADOPT;
3207c478bd9Sstevel@tonic-gate 			return (-1);
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 		if (opt->len < sizeof (struct T_opthdr)) {
3237c478bd9Sstevel@tonic-gate 			t_errno = TBADOPT;
3247c478bd9Sstevel@tonic-gate 			return (-1);
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 		if (((uchar_t *)opt + opt->len) > (uchar_t *)opt_end) {
3277c478bd9Sstevel@tonic-gate 			t_errno = TBADOPT;
3287c478bd9Sstevel@tonic-gate 			return (-1);
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 		switch (opt->level) {
3317c478bd9Sstevel@tonic-gate 		case IPPROTO_IP:
3327c478bd9Sstevel@tonic-gate 			if (opt->name == IP_RECVDSTADDR) {
3337c478bd9Sstevel@tonic-gate 				struct sockaddr_in v4tmp;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 				opt++;
3367c478bd9Sstevel@tonic-gate 				if (((uchar_t *)opt + sizeof (struct in_addr)) >
3377c478bd9Sstevel@tonic-gate 				    (uchar_t *)opt_end) {
3387c478bd9Sstevel@tonic-gate 					t_errno = TBADOPT;
3397c478bd9Sstevel@tonic-gate 					return (-1);
3407c478bd9Sstevel@tonic-gate 				}
3417c478bd9Sstevel@tonic-gate 				bzero(&v4tmp, sizeof (v4tmp));
3427c478bd9Sstevel@tonic-gate 				v4tmp.sin_family = AF_INET;
3437c478bd9Sstevel@tonic-gate 				v4tmp.sin_addr = *(struct in_addr *)opt;
3447c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
3457c478bd9Sstevel@tonic-gate 				{
3467c478bd9Sstevel@tonic-gate 				struct in_addr ia;
3477c478bd9Sstevel@tonic-gate 				char str[INET_ADDRSTRLEN];
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 				ia = *(struct in_addr *)opt;
3507c478bd9Sstevel@tonic-gate 				(void) inet_ntop(AF_INET, &ia,
3517c478bd9Sstevel@tonic-gate 						str, sizeof (str));
3527c478bd9Sstevel@tonic-gate 				syslog(LOG_INFO,
3537c478bd9Sstevel@tonic-gate 				    "__rpc_get_ltaddr for IP_RECVDSTADDR: %s",
3547c478bd9Sstevel@tonic-gate 					str);
3557c478bd9Sstevel@tonic-gate 				}
3567c478bd9Sstevel@tonic-gate #endif
3577c478bd9Sstevel@tonic-gate 				if ((s = open("/dev/udp", O_RDONLY)) < 0) {
3587c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
3597c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR, "__rpc_get_ltaddr: "
3607c478bd9Sstevel@tonic-gate 					    "dev udp open failed");
3617c478bd9Sstevel@tonic-gate #endif
3627c478bd9Sstevel@tonic-gate 					return (1);
3637c478bd9Sstevel@tonic-gate 				}
3647c478bd9Sstevel@tonic-gate 
36561961e0fSrobinson 				(void) memcpy(&areq.sa_addr, &v4tmp,
3667c478bd9Sstevel@tonic-gate 								sizeof (v4tmp));
3677c478bd9Sstevel@tonic-gate 				areq.sa_res = -1;
3687c478bd9Sstevel@tonic-gate 				if (ioctl(s, SIOCTMYADDR, (caddr_t)&areq) < 0) {
3697c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
3707c478bd9Sstevel@tonic-gate 					    "get_ltaddr:ioctl for udp failed");
37161961e0fSrobinson 					(void) close(s);
3727c478bd9Sstevel@tonic-gate 					return (1);
3737c478bd9Sstevel@tonic-gate 				}
37461961e0fSrobinson 				(void) close(s);
3757c478bd9Sstevel@tonic-gate 				if (areq.sa_res == 1) {
37661961e0fSrobinson 				    /* LINTED pointer cast */
3777c478bd9Sstevel@tonic-gate 				    ipv4sa = (struct sockaddr_in *)ltaddr->buf;
3787c478bd9Sstevel@tonic-gate 				    ipv4sa->sin_family = AF_INET;
3797c478bd9Sstevel@tonic-gate 				    ipv4sa->sin_addr = *(struct in_addr *)opt;
3807c478bd9Sstevel@tonic-gate 				    return (0);
3817c478bd9Sstevel@tonic-gate 				} else
3827c478bd9Sstevel@tonic-gate 				    return (1);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 			}
3857c478bd9Sstevel@tonic-gate 			break;
3867c478bd9Sstevel@tonic-gate 		case IPPROTO_IPV6:
3877c478bd9Sstevel@tonic-gate 			if (opt->name == IPV6_PKTINFO) {
3887c478bd9Sstevel@tonic-gate 				struct sockaddr_in6 v6tmp;
3897c478bd9Sstevel@tonic-gate 				opt++;
3907c478bd9Sstevel@tonic-gate 				if (((uchar_t *)opt +
3917c478bd9Sstevel@tonic-gate 				    sizeof (struct in6_pktinfo)) >
3927c478bd9Sstevel@tonic-gate 				    (uchar_t *)opt_end) {
3937c478bd9Sstevel@tonic-gate 					t_errno = TBADOPT;
3947c478bd9Sstevel@tonic-gate 					return (-1);
3957c478bd9Sstevel@tonic-gate 				}
3967c478bd9Sstevel@tonic-gate 				bzero(&v6tmp, sizeof (v6tmp));
3977c478bd9Sstevel@tonic-gate 				v6tmp.sin6_family = AF_INET6;
3987c478bd9Sstevel@tonic-gate 				v6tmp.sin6_addr =
3997c478bd9Sstevel@tonic-gate 					((struct in6_pktinfo *)opt)->ipi6_addr;
4007c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
4017c478bd9Sstevel@tonic-gate 				{
4027c478bd9Sstevel@tonic-gate 				struct in6_pktinfo *in6_pkt;
4037c478bd9Sstevel@tonic-gate 				char str[INET6_ADDRSTRLEN];
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 				in6_pkt = (struct in6_pktinfo *)opt;
4067c478bd9Sstevel@tonic-gate 				(void) inet_ntop(AF_INET6, &in6_pkt->ipi6_addr,
4077c478bd9Sstevel@tonic-gate 						str, sizeof (str));
4087c478bd9Sstevel@tonic-gate 				syslog(LOG_INFO,
4097c478bd9Sstevel@tonic-gate 					"__rpc_get_ltaddr for IPV6_PKTINFO: %s",
4107c478bd9Sstevel@tonic-gate 					str);
4117c478bd9Sstevel@tonic-gate 				}
4127c478bd9Sstevel@tonic-gate #endif
4137c478bd9Sstevel@tonic-gate 				if ((s = open("/dev/udp6", O_RDONLY)) < 0) {
4147c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
4157c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR, "__rpc_get_ltaddr: "
4167c478bd9Sstevel@tonic-gate 					    "dev udp6 open failed");
4177c478bd9Sstevel@tonic-gate #endif
4187c478bd9Sstevel@tonic-gate 					return (1);
4197c478bd9Sstevel@tonic-gate 				}
4207c478bd9Sstevel@tonic-gate 
42161961e0fSrobinson 				(void) memcpy(&areq.sa_addr, &v6tmp,
4227c478bd9Sstevel@tonic-gate 								sizeof (v6tmp));
4237c478bd9Sstevel@tonic-gate 				areq.sa_res = -1;
4247c478bd9Sstevel@tonic-gate 				if (ioctl(s, SIOCTMYADDR, (caddr_t)&areq) < 0) {
4257c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
4267c478bd9Sstevel@tonic-gate 					    "get_ltaddr:ioctl for udp6 failed");
42761961e0fSrobinson 					(void) close(s);
4287c478bd9Sstevel@tonic-gate 					return (1);
4297c478bd9Sstevel@tonic-gate 				}
43061961e0fSrobinson 				(void) close(s);
4317c478bd9Sstevel@tonic-gate 				if (areq.sa_res == 1) {
43261961e0fSrobinson 				    /* LINTED pointer cast */
4337c478bd9Sstevel@tonic-gate 				    ipv6sa = (struct sockaddr_in6 *)ltaddr->buf;
4347c478bd9Sstevel@tonic-gate 				    ipv6sa->sin6_family = AF_INET6;
4357c478bd9Sstevel@tonic-gate 				    ipv6sa->sin6_addr =
4367c478bd9Sstevel@tonic-gate 					((struct in6_pktinfo *)opt)->ipi6_addr;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 				    return (0);
4397c478bd9Sstevel@tonic-gate 				} else
4407c478bd9Sstevel@tonic-gate 				    return (1);
4417c478bd9Sstevel@tonic-gate 			}
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 		default:
4447c478bd9Sstevel@tonic-gate 			break;
4457c478bd9Sstevel@tonic-gate 		}
4467c478bd9Sstevel@tonic-gate 		/* LINTED improper alignment */
4477c478bd9Sstevel@tonic-gate 		opt = (struct T_opthdr *)((uchar_t *)opt +
4487c478bd9Sstevel@tonic-gate 			    __TPI_ALIGN(opt->len));
4497c478bd9Sstevel@tonic-gate 	} while (opt < opt_end);
4507c478bd9Sstevel@tonic-gate 	return (1);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate #define	__TRANSPORT_INDSZ	128
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate int
__rpc_tli_set_options(int fd,int optlevel,int optname,int optval)4567c478bd9Sstevel@tonic-gate __rpc_tli_set_options(int fd, int optlevel, int optname, int optval)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	struct t_optmgmt oreq, ores;
4597c478bd9Sstevel@tonic-gate 	struct opthdr *topt;
4607c478bd9Sstevel@tonic-gate 	int *ip;
4617c478bd9Sstevel@tonic-gate 	int optsz;
4627c478bd9Sstevel@tonic-gate 	char buf[__TRANSPORT_INDSZ];
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	switch (optname) {
4667c478bd9Sstevel@tonic-gate 	case SO_DONTLINGER: {
4677c478bd9Sstevel@tonic-gate 		struct linger *ling;
4687c478bd9Sstevel@tonic-gate 		/* LINTED */
4697c478bd9Sstevel@tonic-gate 		ling = (struct linger *)
4707c478bd9Sstevel@tonic-gate 			(buf + sizeof (struct opthdr));
4717c478bd9Sstevel@tonic-gate 		ling->l_onoff = 0;
4727c478bd9Sstevel@tonic-gate 		optsz = sizeof (struct linger);
4737c478bd9Sstevel@tonic-gate 		break;
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	case SO_LINGER: {
4777c478bd9Sstevel@tonic-gate 		struct linger *ling;
4787c478bd9Sstevel@tonic-gate 		/* LINTED */
4797c478bd9Sstevel@tonic-gate 		ling = (struct linger *)
4807c478bd9Sstevel@tonic-gate 			(buf + sizeof (struct opthdr));
4817c478bd9Sstevel@tonic-gate 		ling->l_onoff = 1;
4827c478bd9Sstevel@tonic-gate 		ling->l_linger = (int)optval;
4837c478bd9Sstevel@tonic-gate 		optsz = sizeof (struct linger);
4847c478bd9Sstevel@tonic-gate 		break;
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 	case IP_RECVDSTADDR:
4877c478bd9Sstevel@tonic-gate 	case IPV6_RECVPKTINFO:
4887c478bd9Sstevel@tonic-gate 	case SO_DEBUG:
4897c478bd9Sstevel@tonic-gate 	case SO_KEEPALIVE:
4907c478bd9Sstevel@tonic-gate 	case SO_DONTROUTE:
4917c478bd9Sstevel@tonic-gate 	case SO_USELOOPBACK:
4927c478bd9Sstevel@tonic-gate 	case SO_REUSEADDR:
4937c478bd9Sstevel@tonic-gate 	case SO_DGRAM_ERRIND:
4947c478bd9Sstevel@tonic-gate 	case SO_RECVUCRED:
49545916cd2Sjpk 	case SO_ANON_MLP:
49645916cd2Sjpk 	case SO_MAC_EXEMPT:
497*ae347574Skcpoon 	case SO_EXCLBIND:
4987c478bd9Sstevel@tonic-gate 	case TCP_EXCLBIND:
4997c478bd9Sstevel@tonic-gate 	case UDP_EXCLBIND:
5007c478bd9Sstevel@tonic-gate 		/* LINTED */
5017c478bd9Sstevel@tonic-gate 		ip = (int *)(buf + sizeof (struct opthdr));
5027c478bd9Sstevel@tonic-gate 		*ip = optval;
5037c478bd9Sstevel@tonic-gate 		optsz = sizeof (int);
5047c478bd9Sstevel@tonic-gate 		break;
5057c478bd9Sstevel@tonic-gate 	default:
5067c478bd9Sstevel@tonic-gate 		return (-1);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/* LINTED */
5107c478bd9Sstevel@tonic-gate 	topt = (struct opthdr *)buf;
5117c478bd9Sstevel@tonic-gate 	topt->level =  optlevel;
5127c478bd9Sstevel@tonic-gate 	topt->name = optname;
5137c478bd9Sstevel@tonic-gate 	topt->len = optsz;
5147c478bd9Sstevel@tonic-gate 	oreq.flags = T_NEGOTIATE;
5157c478bd9Sstevel@tonic-gate 	oreq.opt.len = sizeof (struct opthdr) + optsz;
5167c478bd9Sstevel@tonic-gate 	oreq.opt.buf = buf;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	ores.flags = 0;
5197c478bd9Sstevel@tonic-gate 	ores.opt.buf = buf;
5207c478bd9Sstevel@tonic-gate 	ores.opt.maxlen = __TRANSPORT_INDSZ;
5217c478bd9Sstevel@tonic-gate 	if (t_optmgmt(fd, &oreq, &ores) < 0 ||
5227c478bd9Sstevel@tonic-gate 	    ores.flags != T_SUCCESS) {
5237c478bd9Sstevel@tonic-gate 		return (-1);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 	return (0);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate /*
5297c478bd9Sstevel@tonic-gate  * Format an error message corresponding to the given TLI and system error
5307c478bd9Sstevel@tonic-gate  * codes.
5317c478bd9Sstevel@tonic-gate  */
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate void
__tli_sys_strerror(char * buf,size_t buflen,int tli_err,int sys_err)5347c478bd9Sstevel@tonic-gate __tli_sys_strerror(char *buf, size_t buflen, int tli_err, int sys_err)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	char *errorstr;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	if (tli_err == TSYSERR) {
5397c478bd9Sstevel@tonic-gate 		errorstr = strerror(sys_err);
5407c478bd9Sstevel@tonic-gate 		if (errorstr == NULL)
5417c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, buflen,
5427c478bd9Sstevel@tonic-gate 					dgettext(__nsl_dom,
5437c478bd9Sstevel@tonic-gate 						"Unknown system error %d"),
5447c478bd9Sstevel@tonic-gate 					sys_err);
5457c478bd9Sstevel@tonic-gate 		else
5467c478bd9Sstevel@tonic-gate 			(void) strlcpy(buf, errorstr, buflen);
5477c478bd9Sstevel@tonic-gate 	} else {
5487c478bd9Sstevel@tonic-gate 		errorstr = t_strerror(tli_err);
54961961e0fSrobinson 		(void) strlcpy(buf, errorstr, buflen);
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate }
55245916cd2Sjpk 
55345916cd2Sjpk /*
55445916cd2Sjpk  * Depending on the specified RPC number, attempt to set mac_exempt
55545916cd2Sjpk  * option on the opened socket; these requests need to be able to do MAC
55645916cd2Sjpk  * MAC read-down operations.  Privilege is needed to set this option.
55745916cd2Sjpk  */
55845916cd2Sjpk 
55945916cd2Sjpk void
__rpc_set_mac_options(int fd,const struct netconfig * nconf,rpcprog_t prognum)56045916cd2Sjpk __rpc_set_mac_options(int fd, const struct netconfig *nconf, rpcprog_t prognum)
56145916cd2Sjpk {
56245916cd2Sjpk 	int ret = 0;
56345916cd2Sjpk 
56445916cd2Sjpk 	if (!is_system_labeled())
56545916cd2Sjpk 		return;
56645916cd2Sjpk 
56745916cd2Sjpk 	if (strcmp(nconf->nc_protofmly, NC_INET) != 0 &&
56845916cd2Sjpk 	    strcmp(nconf->nc_protofmly, NC_INET6) != 0)
56945916cd2Sjpk 		return;
57045916cd2Sjpk 
57145916cd2Sjpk 	if (is_multilevel(prognum)) {
57245916cd2Sjpk 		ret = __rpc_tli_set_options(fd, SOL_SOCKET, SO_MAC_EXEMPT, 1);
57345916cd2Sjpk 		if (ret < 0) {
57445916cd2Sjpk 			char errorstr[100];
57545916cd2Sjpk 
57645916cd2Sjpk 			__tli_sys_strerror(errorstr, sizeof (errorstr),
57745916cd2Sjpk 			    t_errno, errno);
57845916cd2Sjpk 			(void) syslog(LOG_ERR, "rpc_set_mac_options: %s",
57945916cd2Sjpk 			    errorstr);
58045916cd2Sjpk 		}
58145916cd2Sjpk 	}
58245916cd2Sjpk }
583