The first part of check_priv() function, that attempts to obtain creds
from the control message, actually never worked. This means check_priv() didn't work for local dgram sockets. The SCM_CREDS control messages is received only in two cases: 1) If we did setsockopt(LOCAL_CREDS) on our socket, and in this case the message is struct sockcred. 2) If sender did supplied SCM_CREDS control message in his sendmsg() syscall. In this case the message is struct cmsgcred. We can't rely on 2), so we will use 1) for dgram sockets. For stream sockets it is more reliable to obtain accept-time credentials, since SCM_CREDS control message is attached only on first read. Thus: o Do setsockopt(LOCAL_CREDS) on local dgram sockets. o Split check_priv() into check_priv_stream() and check_priv_dgram(), and call them from recv_stream() and recv_dgram() respectively. o Don't provide space for SCM_CREDS control message in recv_stream(). o Provide space for SCM_CREDS control message in recv_dgram(), but there is no need to initialize anything in it. o In recv_dgram() do not blindly expect that first message is SCM_CREDS, instead use correct search cycle through control messages.
This commit is contained in:
parent
d6d3f01e0a
commit
0cf0d912b7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=240234
@ -1026,34 +1026,31 @@ snmp_input_consume(struct port_input *pi)
|
||||
pi->length -= pi->consumed;
|
||||
}
|
||||
|
||||
struct credmsg {
|
||||
struct cmsghdr hdr;
|
||||
struct cmsgcred cred;
|
||||
};
|
||||
static void
|
||||
check_priv_dgram(struct port_input *pi, struct sockcred *cred)
|
||||
{
|
||||
|
||||
/* process explicitly sends credentials */
|
||||
if (cred)
|
||||
pi->priv = (cred->sc_euid == 0);
|
||||
else
|
||||
pi->priv = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
check_priv(struct port_input *pi, struct msghdr *msg)
|
||||
check_priv_stream(struct port_input *pi)
|
||||
{
|
||||
struct credmsg *cmsg;
|
||||
struct xucred ucred;
|
||||
socklen_t ucredlen;
|
||||
|
||||
pi->priv = 0;
|
||||
|
||||
if (msg->msg_controllen == sizeof(*cmsg)) {
|
||||
/* process explicitly sends credentials */
|
||||
|
||||
cmsg = (struct credmsg *)msg->msg_control;
|
||||
pi->priv = (cmsg->cred.cmcred_euid == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ok, obtain the accept time credentials */
|
||||
/* obtain the accept time credentials */
|
||||
ucredlen = sizeof(ucred);
|
||||
|
||||
if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 &&
|
||||
ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION)
|
||||
pi->priv = (ucred.cr_uid == 0);
|
||||
else
|
||||
pi->priv = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1065,7 +1062,6 @@ recv_stream(struct port_input *pi)
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
ssize_t len;
|
||||
struct credmsg cmsg;
|
||||
|
||||
if (pi->buf == NULL) {
|
||||
/* no buffer yet - allocate one */
|
||||
@ -1084,17 +1080,8 @@ recv_stream(struct port_input *pi)
|
||||
msg.msg_namelen = pi->peerlen;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
if (pi->cred) {
|
||||
msg.msg_control = &cmsg;
|
||||
msg.msg_controllen = sizeof(cmsg);
|
||||
|
||||
cmsg.hdr.cmsg_len = sizeof(cmsg);
|
||||
cmsg.hdr.cmsg_level = SOL_SOCKET;
|
||||
cmsg.hdr.cmsg_type = SCM_CREDS;
|
||||
} else {
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
}
|
||||
msg.msg_flags = 0;
|
||||
|
||||
iov[0].iov_base = pi->buf + pi->length;
|
||||
@ -1109,7 +1096,7 @@ recv_stream(struct port_input *pi)
|
||||
pi->length += len;
|
||||
|
||||
if (pi->cred)
|
||||
check_priv(pi, &msg);
|
||||
check_priv_stream(pi);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -1122,10 +1109,12 @@ static int
|
||||
recv_dgram(struct port_input *pi)
|
||||
{
|
||||
u_char embuf[1000];
|
||||
char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX))];
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
ssize_t len;
|
||||
struct credmsg cmsg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct sockcred *cred = NULL;
|
||||
|
||||
if (pi->buf == NULL) {
|
||||
/* no buffer yet - allocate one */
|
||||
@ -1145,17 +1134,9 @@ recv_dgram(struct port_input *pi)
|
||||
msg.msg_namelen = pi->peerlen;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
if (pi->cred) {
|
||||
msg.msg_control = &cmsg;
|
||||
msg.msg_controllen = sizeof(cmsg);
|
||||
|
||||
cmsg.hdr.cmsg_len = sizeof(cmsg);
|
||||
cmsg.hdr.cmsg_level = SOL_SOCKET;
|
||||
cmsg.hdr.cmsg_type = SCM_CREDS;
|
||||
} else {
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
}
|
||||
memset(cbuf, 0, sizeof(cbuf));
|
||||
msg.msg_control = cbuf;
|
||||
msg.msg_controllen = sizeof(cbuf);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
iov[0].iov_base = pi->buf;
|
||||
@ -1176,8 +1157,15 @@ recv_dgram(struct port_input *pi)
|
||||
|
||||
pi->length = (size_t)len;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||
cmsg->cmsg_type == SCM_CREDS)
|
||||
cred = (struct sockcred *)CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
if (pi->cred)
|
||||
check_priv(pi, &msg);
|
||||
check_priv_dgram(pi, cred);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -343,6 +343,7 @@ lsock_init_port(struct tport *tp)
|
||||
}
|
||||
} else {
|
||||
struct lsock_peer *peer;
|
||||
const int on = 1;
|
||||
|
||||
peer = LIST_FIRST(&p->peers);
|
||||
|
||||
@ -351,6 +352,14 @@ lsock_init_port(struct tport *tp)
|
||||
return (SNMP_ERR_RES_UNAVAIL);
|
||||
}
|
||||
|
||||
if (setsockopt(peer->input.fd, 0, LOCAL_CREDS, &on,
|
||||
sizeof(on)) == -1) {
|
||||
syslog(LOG_ERR, "setsockopt(LOCAL_CREDS): %m");
|
||||
close(peer->input.fd);
|
||||
peer->input.fd = -1;
|
||||
return (SNMP_ERR_GENERR);
|
||||
}
|
||||
|
||||
strcpy(sa.sun_path, p->name);
|
||||
sa.sun_family = AF_LOCAL;
|
||||
sa.sun_len = strlen(p->name) +
|
||||
|
Loading…
Reference in New Issue
Block a user