mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 09:20:04 +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 "nm-std-utils.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <net/if.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:
|
* _nm_strerror_r:
|
||||||
* @errsv: the errno passed to 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);
|
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__ */
|
#endif /* __NM_STD_UTILS_H__ */
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ components.
|
||||||
nm-daemon-helper
|
nm-daemon-helper
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
A internal helper application that is spawned by NetworkManager
|
A internal helper application that is spawned by NetworkManager to
|
||||||
to perform certain actions.
|
perform certain actions which can't be done in the daemon.
|
||||||
|
|
||||||
Currently all it does is doing a reverse DNS lookup, which
|
Currently it's used to do a reverse DNS lookup after reconfiguring the
|
||||||
cannot be done by NetworkManager because the operation requires
|
libc resolver (which is a process-wide operation), and to read files
|
||||||
to reconfigure the libc resolver (which is a process-wide operation).
|
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.
|
This is not directly useful to the user.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,37 @@ cmd_resolve_address(void)
|
||||||
return RETURN_ERROR;
|
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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
@ -150,6 +181,8 @@ main(int argc, char **argv)
|
||||||
return cmd_version();
|
return cmd_version();
|
||||||
if (nm_streq(cmd, "resolve-address"))
|
if (nm_streq(cmd, "resolve-address"))
|
||||||
return 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;
|
return RETURN_INVALID_CMD;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue