11.25Stron/*	$NetBSD: bindresvport.c,v 1.25 2013/03/11 20:19:28 tron Exp $	*/
21.3Scgd
31.1Scgd/*
41.25Stron * Copyright (c) 2010, Oracle America, Inc.
51.25Stron *
61.25Stron * Redistribution and use in source and binary forms, with or without
71.25Stron * modification, are permitted provided that the following conditions are
81.25Stron * met:
91.25Stron *
101.25Stron *     * Redistributions of source code must retain the above copyright
111.25Stron *       notice, this list of conditions and the following disclaimer.
121.25Stron *     * Redistributions in binary form must reproduce the above
131.25Stron *       copyright notice, this list of conditions and the following
141.25Stron *       disclaimer in the documentation and/or other materials
151.25Stron *       provided with the distribution.
161.25Stron *     * Neither the name of the "Oracle America, Inc." nor the names of its
171.25Stron *       contributors may be used to endorse or promote products derived
181.25Stron *       from this software without specific prior written permission.
191.25Stron *
201.25Stron *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
211.25Stron *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
221.25Stron *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
231.25Stron *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
241.25Stron *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
251.25Stron *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261.25Stron *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
271.25Stron *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
281.25Stron *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
291.25Stron *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
301.25Stron *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
311.25Stron *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
321.1Scgd */
331.1Scgd
341.7Schristos#include <sys/cdefs.h>
351.1Scgd#if defined(LIBC_SCCS) && !defined(lint)
361.7Schristos#if 0
371.7Schristosstatic char *sccsid = "@(#)bindresvport.c 1.8 88/02/08 SMI";
381.7Schristosstatic char *sccsid = "@(#)bindresvport.c	2.2 88/07/29 4.0 RPCSRC";
391.7Schristos#else
401.25Stron__RCSID("$NetBSD: bindresvport.c,v 1.25 2013/03/11 20:19:28 tron Exp $");
411.7Schristos#endif
421.1Scgd#endif
431.1Scgd
441.1Scgd/*
451.1Scgd * Copyright (c) 1987 by Sun Microsystems, Inc.
461.1Scgd */
471.1Scgd
481.8Sjtc#include "namespace.h"
491.12Slukem
501.1Scgd#include <sys/types.h>
511.1Scgd#include <sys/socket.h>
521.12Slukem
531.1Scgd#include <netinet/in.h>
541.12Slukem
551.12Slukem#include <errno.h>
561.12Slukem#include <string.h>
571.12Slukem#include <unistd.h>
581.12Slukem
591.7Schristos#include <rpc/rpc.h>
601.24Schristos#include "svc_fdset.h"
611.8Sjtc
621.8Sjtc#ifdef __weak_alias
631.16Smycroft__weak_alias(bindresvport,_bindresvport)
641.18Sfvdl__weak_alias(bindresvport_sa,_bindresvport_sa)
651.8Sjtc#endif
661.1Scgd
671.1Scgd/*
681.1Scgd * Bind a socket to a privileged IP port
691.1Scgd */
701.6Sjtcint
711.23Smattbindresvport(int sd, struct sockaddr_in *brsin)
721.1Scgd{
731.20Slukem	return bindresvport_sa(sd, (struct sockaddr *)(void *)brsin);
741.17Sitojun}
751.17Sitojun
761.17Sitojun/*
771.17Sitojun * Bind a socket to a privileged IP port
781.17Sitojun */
791.17Sitojunint
801.23Smattbindresvport_sa(int sd, struct sockaddr *sa)
811.17Sitojun{
821.17Sitojun	int error, old;
831.17Sitojun	struct sockaddr_storage myaddr;
841.20Slukem	struct sockaddr_in *brsin;
851.17Sitojun#ifdef INET6
861.20Slukem	struct sockaddr_in6 *brsin6;
871.17Sitojun#endif
881.17Sitojun	int proto, portrange, portlow;
891.17Sitojun	u_int16_t *portp;
901.17Sitojun	socklen_t salen;
911.17Sitojun	int af;
921.17Sitojun
931.17Sitojun	if (sa == NULL) {
941.17Sitojun		salen = sizeof(myaddr);
951.19Schristos		sa = (struct sockaddr *)(void *)&myaddr;
961.17Sitojun
971.17Sitojun		if (getsockname(sd, sa, &salen) == -1)
981.17Sitojun			return -1;	/* errno is correctly set */
991.17Sitojun
1001.17Sitojun		af = sa->sa_family;
1011.17Sitojun		memset(sa, 0, salen);
1021.17Sitojun	} else
1031.17Sitojun		af = sa->sa_family;
1041.17Sitojun
1051.17Sitojun	switch (af) {
1061.17Sitojun	case AF_INET:
1071.17Sitojun		proto = IPPROTO_IP;
1081.17Sitojun		portrange = IP_PORTRANGE;
1091.17Sitojun		portlow = IP_PORTRANGE_LOW;
1101.20Slukem		brsin = (struct sockaddr_in *)(void *)sa;
1111.17Sitojun		salen = sizeof(struct sockaddr_in);
1121.20Slukem		portp = &brsin->sin_port;
1131.17Sitojun		break;
1141.17Sitojun#ifdef INET6
1151.17Sitojun	case AF_INET6:
1161.17Sitojun		proto = IPPROTO_IPV6;
1171.17Sitojun		portrange = IPV6_PORTRANGE;
1181.17Sitojun		portlow = IPV6_PORTRANGE_LOW;
1191.20Slukem		brsin6 = (struct sockaddr_in6 *)(void *)sa;
1201.17Sitojun		salen = sizeof(struct sockaddr_in6);
1211.20Slukem		portp = &brsin6->sin6_port;
1221.17Sitojun		break;
1231.17Sitojun#endif
1241.17Sitojun	default:
1251.1Scgd		errno = EPFNOSUPPORT;
1261.1Scgd		return (-1);
1271.1Scgd	}
1281.17Sitojun	sa->sa_family = af;
1291.17Sitojun	sa->sa_len = salen;
1301.9Slukem
1311.17Sitojun	if (*portp == 0) {
1321.15Schristos		socklen_t oldlen = sizeof(old);
1331.9Slukem
1341.17Sitojun		error = getsockopt(sd, proto, portrange, &old, &oldlen);
1351.17Sitojun		if (error < 0)
1361.17Sitojun			return (error);
1371.17Sitojun		error = setsockopt(sd, proto, portrange, &portlow,
1381.22Schristos		    (socklen_t)sizeof(portlow));
1391.17Sitojun		if (error < 0)
1401.17Sitojun			return (error);
1411.1Scgd	}
1421.9Slukem
1431.17Sitojun	error = bind(sd, sa, salen);
1441.9Slukem
1451.17Sitojun	if (*portp == 0) {
1461.9Slukem		int saved_errno = errno;
1471.9Slukem
1481.17Sitojun		if (error < 0) {
1491.17Sitojun			if (setsockopt(sd, proto, portrange, &old,
1501.22Schristos			    (socklen_t)sizeof(old)) < 0)
1511.9Slukem				errno = saved_errno;
1521.17Sitojun			return (error);
1531.9Slukem		}
1541.9Slukem
1551.19Schristos		if (sa != (struct sockaddr *)(void *)&myaddr) {
1561.17Sitojun			/* What did the kernel assign? */
1571.17Sitojun			if (getsockname(sd, sa, &salen) < 0)
1581.9Slukem				errno = saved_errno;
1591.17Sitojun			return (error);
1601.1Scgd		}
1611.1Scgd	}
1621.17Sitojun	return (error);
1631.1Scgd}
164