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