summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r--sys/netinet6/ip6_output.c119
1 files changed, 75 insertions, 44 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index a79363e..4b6c52e 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -114,12 +114,12 @@ struct ip6_exthdrs {
};
static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **,
- int, int));
+ struct ucred *, int));
static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
struct socket *, struct sockopt *));
static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
-static int ip6_setpktopt __P((int, u_char *, int, struct ip6_pktopts *, int,
- int, int, int));
+static int ip6_setpktopt __P((int, u_char *, int, struct ip6_pktopts *,
+ struct ucred *, int, int, int));
static int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *);
static int ip6_getmoptions(int, struct ip6_moptions *, struct mbuf **);
@@ -1346,7 +1346,7 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
int
ip6_ctloutput(struct socket *so, struct sockopt *sopt)
{
- int privileged, optdatalen, uproto;
+ int optdatalen, uproto;
void *optdata;
struct inpcb *in6p = sotoinpcb(so);
int error, optval;
@@ -1365,7 +1365,6 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
}
error = optval = 0;
- privileged = (td == 0 || suser(td)) ? 0 : 1;
uproto = (int)so->so_proto->pr_protocol;
if (level == IPPROTO_IPV6) {
@@ -1408,9 +1407,11 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
case IPV6_RECVHOPOPTS:
case IPV6_RECVDSTOPTS:
case IPV6_RECVRTHDRDSTOPTS:
- if (!privileged) {
- error = EPERM;
- break;
+ if (td != NULL) {
+ error = priv_check(td,
+ PRIV_NETINET_SETHDROPTS);
+ if (error)
+ break;
}
/* FALLTHROUGH */
case IPV6_UNICAST_HOPS:
@@ -1482,10 +1483,9 @@ do { \
}
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(IPV6_HOPLIMIT,
- (u_char *)&optval,
- sizeof(optval),
- optp,
- privileged, uproto);
+ (u_char *)&optval, sizeof(optval),
+ optp, (td != NULL) ? td->td_ucred :
+ NULL, uproto);
break;
}
@@ -1597,10 +1597,9 @@ do { \
struct ip6_pktopts **optp;
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(optname,
- (u_char *)&optval,
- sizeof(optval),
- optp,
- privileged, uproto);
+ (u_char *)&optval, sizeof(optval),
+ optp, (td != NULL) ? td->td_ucred :
+ NULL, uproto);
break;
}
@@ -1630,13 +1629,21 @@ do { \
* Check super-user privilege.
* See comments for IPV6_RECVHOPOPTS.
*/
- if (!privileged)
- return (EPERM);
+ if (td != NULL) {
+ error = priv_check(td,
+ PRIV_NETINET_SETHDROPTS);
+ if (error)
+ return (error);
+ }
OPTSET2292(IN6P_HOPOPTS);
break;
case IPV6_2292DSTOPTS:
- if (!privileged)
- return (EPERM);
+ if (td != NULL) {
+ error = priv_check(td,
+ PRIV_NETINET_SETHDROPTS);
+ if (error)
+ return (error);
+ }
OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
break;
case IPV6_2292RTHDR:
@@ -1675,9 +1682,9 @@ do { \
optlen = sopt->sopt_valsize;
optbuf = optbuf_storage;
optp = &in6p->in6p_outputopts;
- error = ip6_pcbopt(optname,
- optbuf, optlen,
- optp, privileged, uproto);
+ error = ip6_pcbopt(optname, optbuf, optlen,
+ optp, (td != NULL) ? td->td_ucred : NULL,
+ uproto);
break;
}
#undef OPTSET
@@ -1764,6 +1771,7 @@ do { \
caddr_t req = NULL;
size_t len = 0;
struct mbuf *m;
+ int priv = 0;
if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
break;
@@ -1773,8 +1781,22 @@ do { \
req = mtod(m, caddr_t);
len = m->m_len;
}
+ if (sopt->sopt_td != NULL) {
+ /*
+ * XXXRW/XXX-BZ: Would be more desirable to do
+ * this one layer down so that we only exercise
+ * privilege if it is needed.
+ */
+ error = priv_check(sopt->sopt_td,
+ PRIV_NETINET_IPSEC);
+ if (error)
+ priv = 0;
+ else
+ priv = 1;
+ } else
+ priv = 1;
error = ipsec6_set_policy(in6p, optname, req,
- len, privileged);
+ len, priv);
m_freem(m);
}
break;
@@ -2103,7 +2125,6 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
struct ip6_pktopts *opt = *pktopt;
int error = 0;
struct thread *td = sopt->sopt_td;
- int priv = 0;
/* turn off any old options. */
if (opt) {
@@ -2128,10 +2149,8 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
}
/* set options specified by user. */
- if (td && !suser(td))
- priv = 1;
- if ((error = ip6_setpktopts(m, opt, NULL, priv,
- so->so_proto->pr_protocol)) != 0) {
+ if ((error = ip6_setpktopts(m, opt, NULL, (td != NULL) ?
+ td->td_ucred : NULL, so->so_proto->pr_protocol)) != 0) {
ip6_clearpktopts(opt, -1); /* XXX: discard all options */
free(opt, M_IP6OPT);
return (error);
@@ -2157,7 +2176,7 @@ ip6_initpktopts(struct ip6_pktopts *opt)
static int
ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
- int priv, int uproto)
+ struct ucred *cred, int uproto)
{
struct ip6_pktopts *opt;
@@ -2168,7 +2187,7 @@ ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
}
opt = *pktopt;
- return (ip6_setpktopt(optname, buf, len, opt, priv, 1, 0, uproto));
+ return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto));
}
static int
@@ -2411,7 +2430,6 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
struct ip6_moptions *im6o = *im6op;
struct route_in6 ro;
struct in6_multi_mship *imm;
- struct thread *td = curthread;
if (im6o == NULL) {
/*
@@ -2507,10 +2525,10 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
* all multicast addresses. Only super user is allowed
* to do this.
*/
- if (suser(td)) {
- error = EACCES;
+ /* XXX-BZ might need a better PRIV_NETINET_x for this */
+ error = priv_check(curthread, PRIV_NETINET_MROUTE);
+ if (error)
break;
- }
} else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
error = EINVAL;
break;
@@ -2769,7 +2787,7 @@ ip6_freemoptions(struct ip6_moptions *im6o)
*/
int
ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
- struct ip6_pktopts *stickyopt, int priv, int uproto)
+ struct ip6_pktopts *stickyopt, struct ucred *cred, int uproto)
{
struct cmsghdr *cm = 0;
@@ -2814,7 +2832,7 @@ ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
continue;
error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
- cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto);
+ cm->cmsg_len - CMSG_LEN(0), opt, cred, 0, 1, uproto);
if (error)
return (error);
}
@@ -2833,9 +2851,10 @@ ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
*/
static int
ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
- int priv, int sticky, int cmsg, int uproto)
+ struct ucred *cred, int sticky, int cmsg, int uproto)
{
int minmtupolicy, preftemp;
+ int error;
if (!sticky && !cmsg) {
#ifdef DIAGNOSTIC
@@ -2977,8 +2996,12 @@ ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
case IPV6_2292NEXTHOP:
case IPV6_NEXTHOP:
- if (!priv)
- return (EPERM);
+ if (cred != NULL) {
+ error = priv_check_cred(cred,
+ PRIV_NETINET_SETHDROPTS, 0);
+ if (error)
+ return (error);
+ }
if (len == 0) { /* just remove the option */
ip6_clearpktopts(opt, IPV6_NEXTHOP);
@@ -3032,8 +3055,12 @@ ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
* options, since per-option restriction has too much
* overhead.
*/
- if (!priv)
- return (EPERM);
+ if (cred != NULL) {
+ error = priv_check_cred(cred,
+ PRIV_NETINET_SETHDROPTS, 0);
+ if (error)
+ return (error);
+ }
if (len == 0) {
ip6_clearpktopts(opt, IPV6_HOPOPTS);
@@ -3065,8 +3092,12 @@ ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
struct ip6_dest *dest, **newdest = NULL;
int destlen;
- if (!priv) /* XXX: see the comment for IPV6_HOPOPTS */
- return (EPERM);
+ if (cred != NULL) { /* XXX: see the comment for IPV6_HOPOPTS */
+ error = priv_check_cred(cred,
+ PRIV_NETINET_SETHDROPTS, 0);
+ if (error)
+ return (error);
+ }
if (len == 0) {
ip6_clearpktopts(opt, optname);
OpenPOWER on IntegriCloud