mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-03-19 13:30:48 +01:00
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.
188 lines
4.5 KiB
C
188 lines
4.5 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
/* Copyright (C) 2021 Red Hat, Inc. */
|
|
|
|
#include "libnm-std-aux/nm-default-std.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#if defined(__GLIBC__)
|
|
#include <nss.h>
|
|
#endif
|
|
#include <stdarg.h>
|
|
|
|
enum {
|
|
RETURN_SUCCESS = 0,
|
|
RETURN_INVALID_CMD = 1,
|
|
RETURN_INVALID_ARGS = 2,
|
|
RETURN_ERROR = 3,
|
|
};
|
|
|
|
static char *
|
|
read_arg(void)
|
|
{
|
|
nm_auto_free char *arg = NULL;
|
|
size_t len = 0;
|
|
|
|
if (getdelim(&arg, &len, '\0', stdin) < 0)
|
|
return NULL;
|
|
|
|
return nm_steal_pointer(&arg);
|
|
}
|
|
|
|
static int
|
|
more_args(void)
|
|
{
|
|
nm_auto_free char *arg = NULL;
|
|
|
|
arg = read_arg();
|
|
|
|
return !!arg;
|
|
}
|
|
|
|
static int
|
|
cmd_version(void)
|
|
{
|
|
if (more_args())
|
|
return RETURN_INVALID_ARGS;
|
|
|
|
printf("1");
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
cmd_resolve_address(void)
|
|
{
|
|
nm_auto_free char *address = NULL;
|
|
nm_auto_free char *services = NULL;
|
|
union {
|
|
struct sockaddr_in in;
|
|
struct sockaddr_in6 in6;
|
|
} sockaddr;
|
|
socklen_t sockaddr_size;
|
|
char name[NI_MAXHOST];
|
|
char *saveptr = NULL;
|
|
char *service;
|
|
char *str;
|
|
int ret;
|
|
|
|
address = read_arg();
|
|
if (!address)
|
|
return RETURN_INVALID_ARGS;
|
|
|
|
services = read_arg();
|
|
if (!services) {
|
|
/* Called by an old NM version which doesn't support the 'services'
|
|
* argument. Use both services. */
|
|
services = strdup("dns,files");
|
|
}
|
|
|
|
memset(&sockaddr, 0, sizeof(sockaddr));
|
|
|
|
if (inet_pton(AF_INET, address, &sockaddr.in.sin_addr) == 1) {
|
|
sockaddr.in.sin_family = AF_INET;
|
|
sockaddr_size = sizeof(struct sockaddr_in);
|
|
} else if (inet_pton(AF_INET6, address, &sockaddr.in6.sin6_addr) == 1) {
|
|
sockaddr.in6.sin6_family = AF_INET6;
|
|
sockaddr_size = sizeof(struct sockaddr_in6);
|
|
} else
|
|
return RETURN_INVALID_ARGS;
|
|
|
|
for (str = services; (service = strtok_r(str, ",", &saveptr)); str = NULL) {
|
|
if (!NM_IN_STRSET(service, "dns", "files")) {
|
|
fprintf(stderr, "Unsupported resolver service '%s'\n", service);
|
|
continue;
|
|
}
|
|
|
|
#if defined(__GLIBC__)
|
|
__nss_configure_lookup("hosts", service);
|
|
#endif
|
|
|
|
ret = getnameinfo((struct sockaddr *) &sockaddr,
|
|
sockaddr_size,
|
|
name,
|
|
sizeof(name),
|
|
NULL,
|
|
0,
|
|
NI_NAMEREQD);
|
|
|
|
if (ret == 0) {
|
|
printf("%s", name);
|
|
return RETURN_SUCCESS;
|
|
} else if (ret == EAI_SYSTEM) {
|
|
char buf[1024];
|
|
int errsv = errno;
|
|
|
|
fprintf(stderr,
|
|
"getnameinfo() via service '%s' failed: %d (%s), system error: %d (%s)\n",
|
|
service,
|
|
ret,
|
|
gai_strerror(ret),
|
|
errsv,
|
|
_nm_strerror_r(errsv, buf, sizeof(buf)));
|
|
} else {
|
|
fprintf(stderr,
|
|
"getnameinfo() via service '%s' failed: %d (%s)\n",
|
|
service,
|
|
ret,
|
|
gai_strerror(ret));
|
|
}
|
|
#if !defined(__GLIBC__)
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
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)
|
|
{
|
|
nm_auto_free char *cmd = NULL;
|
|
|
|
cmd = read_arg();
|
|
if (!cmd)
|
|
return RETURN_INVALID_CMD;
|
|
|
|
if (nm_streq(cmd, "version"))
|
|
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;
|
|
}
|