1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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;
}
|