diff options
Diffstat (limited to 'src/nm-helpers/nm-daemon-helper.c')
| -rw-r--r-- | src/nm-helpers/nm-daemon-helper.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/nm-helpers/nm-daemon-helper.c b/src/nm-helpers/nm-daemon-helper.c new file mode 100644 index 00000000..759993a4 --- /dev/null +++ b/src/nm-helpers/nm-daemon-helper.c @@ -0,0 +1,188 @@ +/* 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; +} |