mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 05:50:06 +01:00
daemon-helper: add read-file-as-user
Add a new command to read the content of a file after switching to the given user. This command can be used to enforce Unix filesystem permissions when accessing a file on behalf of a user.
This commit is contained in:
parent
6c1e04fc61
commit
41e28b900f
4 changed files with 156 additions and 6 deletions
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
#include "nm-std-utils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <net/if.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -95,6 +99,114 @@ out_huge:
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
bool
|
||||
nm_utils_set_effective_user(const char *user, char *errbuf, size_t errbuf_len)
|
||||
{
|
||||
struct passwd *pwentry;
|
||||
int errsv;
|
||||
char error[1024];
|
||||
|
||||
errno = 0;
|
||||
pwentry = getpwnam(user);
|
||||
if (!pwentry) {
|
||||
errsv = errno;
|
||||
if (errsv == 0) {
|
||||
snprintf(errbuf, errbuf_len, "user not found");
|
||||
} else {
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"error getting user entry: %d (%s)\n",
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setgid(pwentry->pw_gid) != 0) {
|
||||
errsv = errno;
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"failed to change group to %u: %d (%s)\n",
|
||||
pwentry->pw_gid,
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (initgroups(user, pwentry->pw_gid) != 0) {
|
||||
errsv = errno;
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"failed to reset supplementary group list to %u: %d (%s)\n",
|
||||
pwentry->pw_gid,
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setuid(pwentry->pw_uid) != 0) {
|
||||
errsv = errno;
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"failed to change user to %u: %d (%s)\n",
|
||||
pwentry->pw_uid,
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
bool
|
||||
nm_utils_read_file_to_stdout(const char *filename, char *errbuf, size_t errbuf_len)
|
||||
{
|
||||
nm_auto_close int fd = -1;
|
||||
char buffer[4096];
|
||||
char error[1024];
|
||||
ssize_t bytes_read;
|
||||
int errsv;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
errsv = errno;
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"error opening the file: %d (%s)",
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
if (fwrite(buffer, 1, bytes_read, stdout) != (size_t) bytes_read) {
|
||||
errsv = errno;
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"error writing to stdout: %d (%s)",
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_read < 0) {
|
||||
errsv = errno;
|
||||
snprintf(errbuf,
|
||||
errbuf_len,
|
||||
"error reading the file: %d (%s)",
|
||||
errsv,
|
||||
strerror_r(errsv, error, sizeof(error)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* _nm_strerror_r:
|
||||
* @errsv: the errno passed to strerror_r()
|
||||
|
|
|
|||
|
|
@ -37,4 +37,8 @@ size_t nm_utils_get_next_realloc_size(bool true_realloc, size_t requested);
|
|||
|
||||
const char *_nm_strerror_r(int errsv, char *buf, size_t buf_size);
|
||||
|
||||
bool nm_utils_set_effective_user(const char *user, char *errbuf, size_t errbuf_size);
|
||||
|
||||
bool nm_utils_read_file_to_stdout(const char *filename, char *errbuf, size_t errbuf_len);
|
||||
|
||||
#endif /* __NM_STD_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ components.
|
|||
nm-daemon-helper
|
||||
----------------
|
||||
|
||||
A internal helper application that is spawned by NetworkManager
|
||||
to perform certain actions.
|
||||
A internal helper application that is spawned by NetworkManager to
|
||||
perform certain actions which can't be done in the daemon.
|
||||
|
||||
Currently all it does is doing a reverse DNS lookup, which
|
||||
cannot be done by NetworkManager because the operation requires
|
||||
to reconfigure the libc resolver (which is a process-wide operation).
|
||||
Currently it's used to do a reverse DNS lookup after reconfiguring the
|
||||
libc resolver (which is a process-wide operation), and to read files
|
||||
on behalf of unprivileged users (which requires a seteuid that affects
|
||||
all the threads of the process).
|
||||
|
||||
This is not directly useful to the user.
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,37 @@ cmd_resolve_address(void)
|
|||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_read_file_as_user(void)
|
||||
{
|
||||
nm_auto_free char *user = NULL;
|
||||
nm_auto_free char *filename = NULL;
|
||||
char error[1024];
|
||||
|
||||
user = read_arg();
|
||||
if (!user)
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
filename = read_arg();
|
||||
if (!filename)
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
if (more_args())
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
if (!nm_utils_set_effective_user(user, error, sizeof(error))) {
|
||||
fprintf(stderr, "Failed to set effective user '%s': %s", user, error);
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
if (!nm_utils_read_file_to_stdout(filename, error, sizeof(error))) {
|
||||
fprintf(stderr, "Failed to read file '%s' as user '%s': %s", filename, user, error);
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
|
@ -150,6 +181,8 @@ main(int argc, char **argv)
|
|||
return cmd_version();
|
||||
if (nm_streq(cmd, "resolve-address"))
|
||||
return cmd_resolve_address();
|
||||
if (nm_streq(cmd, "read-file-as-user"))
|
||||
return cmd_read_file_as_user();
|
||||
|
||||
return RETURN_INVALID_CMD;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue