1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-31 16:21:26 +03:00

socket-util: add new getpeergroups() call

It's a wrapper around the new SO_PEERGROUPS sockopt, similar in style as
getpeersec() and getpeercred().
This commit is contained in:
Lennart Poettering 2017-12-30 14:02:36 +01:00
parent 5e9f01e8a6
commit 43f2c88df0
4 changed files with 106 additions and 0 deletions

View File

@ -621,6 +621,10 @@ struct btrfs_ioctl_quota_ctl_args {
# define SO_REUSEPORT 15
#endif
#ifndef SO_PEERGROUPS
# define SO_PEERGROUPS 59
#endif
#ifndef EVIOCREVOKE
# define EVIOCREVOKE _IOW('E', 0x91, int)
#endif

View File

@ -1019,6 +1019,39 @@ int getpeersec(int fd, char **ret) {
return 0;
}
int getpeergroups(int fd, gid_t **ret) {
socklen_t n = sizeof(gid_t) * 64;
_cleanup_free_ gid_t *d = NULL;
assert(fd);
assert(ret);
for (;;) {
d = malloc(n);
if (!d)
return -ENOMEM;
if (getsockopt(fd, SOL_SOCKET, SO_PEERGROUPS, d, &n) >= 0)
break;
if (errno != ERANGE)
return -errno;
d = mfree(d);
}
assert_se(n % sizeof(gid_t) == 0);
n /= sizeof(gid_t);
if ((socklen_t) (int) n != n)
return -E2BIG;
*ret = d;
d = NULL;
return (int) n;
}
int send_one_fd_sa(
int transport_fd,
int fd,

View File

@ -138,6 +138,7 @@ bool address_label_valid(const char *p);
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
int getpeergroups(int fd, gid_t **ret);
int send_one_fd_sa(int transport_fd,
int fd,

View File

@ -18,6 +18,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include "alloc-util.h"
#include "async.h"
#include "fd-util.h"
@ -474,6 +478,68 @@ static void test_in_addr_is_multicast(void) {
assert_se(in_addr_is_multicast(f, &b) == 0);
}
static void test_getpeercred_getpeergroups(void) {
int r;
r = safe_fork("(getpeercred)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
assert_se(r >= 0);
if (r == 0) {
static const gid_t gids[] = { 3, 4, 5, 6, 7 };
gid_t *test_gids;
gid_t *peer_groups = NULL;
size_t n_test_gids;
uid_t test_uid;
gid_t test_gid;
struct ucred ucred;
int pair[2];
if (geteuid() == 0) {
test_uid = 1;
test_gid = 2;
test_gids = (gid_t*) gids;
n_test_gids = ELEMENTSOF(gids);
assert_se(setgroups(n_test_gids, test_gids) >= 0);
assert_se(setresgid(test_gid, test_gid, test_gid) >= 0);
assert_se(setresuid(test_uid, test_uid, test_uid) >= 0);
} else {
long ngroups_max;
test_uid = getuid();
test_gid = getgid();
ngroups_max = sysconf(_SC_NGROUPS_MAX);
assert(ngroups_max > 0);
test_gids = newa(gid_t, ngroups_max);
r = getgroups(ngroups_max, test_gids);
assert_se(r >= 0);
n_test_gids = (size_t) r;
}
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) >= 0);
assert_se(getpeercred(pair[0], &ucred) >= 0);
assert_se(ucred.uid == test_uid);
assert_se(ucred.gid == test_gid);
assert_se(ucred.pid == getpid_cached());
r = getpeergroups(pair[0], &peer_groups);
assert_se(r >= 0 || IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT));
if (r >= 0) {
assert_se((size_t) r == n_test_gids);
assert_se(memcmp(peer_groups, test_gids, sizeof(gid_t) * n_test_gids) == 0);
}
safe_close_pair(pair);
}
}
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
@ -502,5 +568,7 @@ int main(int argc, char *argv[]) {
test_in_addr_is_multicast();
test_getpeercred_getpeergroups();
return 0;
}