From: Lennart Poettering Date: Thu, 25 Apr 2024 08:56:00 +0000 (+0200) Subject: varlink: add helper that adds a connection via stdio to a varlink server X-Git-Tag: v257-rc1~1037^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4120151f7b9c7eedcdf7ee0c06cd0a9f8c4cd7d5;p=thirdparty%2Fsystemd.git varlink: add helper that adds a connection via stdio to a varlink server This adds varlink_server_add_connection_stdio() as wrapper around varlink_server_add_connection_pair(), that steals stdin/stdout fds and turns them into a varlink connection. To be safe it replaces stdin/stdout with /dev/null fds. --- diff --git a/src/shared/varlink.c b/src/shared/varlink.c index 563e81472a4..6826e3eb9bd 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -3703,6 +3703,66 @@ int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t return 0; } +int varlink_server_add_connection_stdio(VarlinkServer *s, Varlink **ret) { + _cleanup_close_ int input_fd = -EBADF, output_fd = -EBADF; + int r; + + assert_return(s, -EINVAL); + + input_fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 3); + if (input_fd < 0) + return -errno; + + output_fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 3); + if (output_fd < 0) + return -errno; + + r = rearrange_stdio(-EBADF, -EBADF, STDERR_FILENO); + if (r < 0) + return r; + + r = fd_nonblock(input_fd, true); + if (r < 0) + return r; + + r = fd_nonblock(output_fd, true); + if (r < 0) + return r; + + struct stat input_st; + if (fstat(input_fd, &input_st) < 0) + return -errno; + + struct stat output_st; + if (fstat(output_fd, &output_st) < 0) + return -errno; + + /* If stdin/stdout are both pipes and have the same owning uid/gid then let's synthesize a "struct + * ucred" from the owning UID/GID, since we got them passed in with such ownership. We'll not fill in + * the PID however, since there's no way to know which process created a pipe. */ + struct ucred ucred, *pucred; + if (S_ISFIFO(input_st.st_mode) && + S_ISFIFO(output_st.st_mode) && + input_st.st_uid == output_st.st_uid && + input_st.st_gid == output_st.st_gid) { + ucred = (struct ucred) { + .uid = input_st.st_uid, + .gid = input_st.st_gid, + }; + pucred = &ucred; + } else + pucred = NULL; + + r = varlink_server_add_connection_pair(s, input_fd, output_fd, pucred, ret); + if (r < 0) + return r; + + TAKE_FD(input_fd); + TAKE_FD(output_fd); + + return 0; +} + int varlink_server_listen_auto(VarlinkServer *s) { _cleanup_strv_free_ char **names = NULL; int r, n = 0; diff --git a/src/shared/varlink.h b/src/shared/varlink.h index 2585c45efd6..47eed171deb 100644 --- a/src/shared/varlink.h +++ b/src/shared/varlink.h @@ -222,6 +222,7 @@ int varlink_server_listen_fd(VarlinkServer *s, int fd); int varlink_server_listen_auto(VarlinkServer *s); int varlink_server_add_connection(VarlinkServer *s, int fd, Varlink **ret); int varlink_server_add_connection_pair(VarlinkServer *s, int input_fd, int output_fd, const struct ucred *ucred_override, Varlink **ret); +int varlink_server_add_connection_stdio(VarlinkServer *s, Varlink **ret); /* Bind callbacks */ int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMethod callback);