]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nss-systemd/nss-systemd.c
nss: add new "nss-systemd" NSS module for mapping dynamic users
[thirdparty/systemd.git] / src / nss-systemd / nss-systemd.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2016 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <nss.h>
21
22 #include "sd-bus.h"
23
24 #include "bus-common-errors.h"
25 #include "env-util.h"
26 #include "macro.h"
27 #include "nss-util.h"
28 #include "signal-util.h"
29 #include "user-util.h"
30 #include "util.h"
31
32 NSS_GETPW_PROTOTYPES(systemd);
33 NSS_GETGR_PROTOTYPES(systemd);
34
35 enum nss_status _nss_systemd_getpwnam_r(
36 const char *name,
37 struct passwd *pwd,
38 char *buffer, size_t buflen,
39 int *errnop) {
40
41 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
42 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
43 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
44 uint32_t translated;
45 size_t l;
46 int r;
47
48 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
49
50 assert(name);
51 assert(pwd);
52
53 /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
54 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
55 goto not_found;
56
57 r = sd_bus_open_system(&bus);
58 if (r < 0)
59 goto fail;
60
61 r = sd_bus_call_method(bus,
62 "org.freedesktop.systemd1",
63 "/org/freedesktop/systemd1",
64 "org.freedesktop.systemd1.Manager",
65 "LookupDynamicUserByName",
66 &error,
67 &reply,
68 "s",
69 name);
70 if (r < 0) {
71 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
72 goto not_found;
73
74 goto fail;
75 }
76
77 r = sd_bus_message_read(reply, "u", &translated);
78 if (r < 0)
79 goto fail;
80
81 l = strlen(name);
82 if (buflen < l+1) {
83 *errnop = ENOMEM;
84 return NSS_STATUS_TRYAGAIN;
85 }
86
87 memcpy(buffer, name, l+1);
88
89 pwd->pw_name = buffer;
90 pwd->pw_uid = (uid_t) translated;
91 pwd->pw_gid = (uid_t) translated;
92 pwd->pw_gecos = (char*) "Dynamic User";
93 pwd->pw_passwd = (char*) "*"; /* locked */
94 pwd->pw_dir = (char*) "/";
95 pwd->pw_shell = (char*) "/sbin/nologin";
96
97 *errnop = 0;
98 return NSS_STATUS_SUCCESS;
99
100 not_found:
101 *errnop = 0;
102 return NSS_STATUS_NOTFOUND;
103
104 fail:
105 *errnop = -r;
106 return NSS_STATUS_UNAVAIL;
107 }
108
109 enum nss_status _nss_systemd_getpwuid_r(
110 uid_t uid,
111 struct passwd *pwd,
112 char *buffer, size_t buflen,
113 int *errnop) {
114
115 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
116 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
117 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
118 const char *translated;
119 size_t l;
120 int r;
121
122 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
123
124 if (!uid_is_valid(uid)) {
125 r = -EINVAL;
126 goto fail;
127 }
128
129 if (uid <= SYSTEM_UID_MAX)
130 goto not_found;
131
132 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
133 goto not_found;
134
135 r = sd_bus_open_system(&bus);
136 if (r < 0)
137 goto fail;
138
139 r = sd_bus_call_method(bus,
140 "org.freedesktop.systemd1",
141 "/org/freedesktop/systemd1",
142 "org.freedesktop.systemd1.Manager",
143 "LookupDynamicUserByUID",
144 &error,
145 &reply,
146 "u",
147 (uint32_t) uid);
148 if (r < 0) {
149 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
150 goto not_found;
151
152 goto fail;
153 }
154
155 r = sd_bus_message_read(reply, "s", &translated);
156 if (r < 0)
157 goto fail;
158
159 l = strlen(translated) + 1;
160 if (buflen < l) {
161 *errnop = ENOMEM;
162 return NSS_STATUS_TRYAGAIN;
163 }
164
165 memcpy(buffer, translated, l);
166
167 pwd->pw_name = buffer;
168 pwd->pw_uid = uid;
169 pwd->pw_gid = uid;
170 pwd->pw_gecos = (char*) "Dynamic User";
171 pwd->pw_passwd = (char*) "*"; /* locked */
172 pwd->pw_dir = (char*) "/";
173 pwd->pw_shell = (char*) "/sbin/nologin";
174
175 *errnop = 0;
176 return NSS_STATUS_SUCCESS;
177
178 not_found:
179 *errnop = 0;
180 return NSS_STATUS_NOTFOUND;
181
182 fail:
183 *errnop = -r;
184 return NSS_STATUS_UNAVAIL;
185 }
186
187 enum nss_status _nss_systemd_getgrnam_r(
188 const char *name,
189 struct group *gr,
190 char *buffer, size_t buflen,
191 int *errnop) {
192
193 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
194 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
195 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
196 uint32_t translated;
197 size_t l;
198 int r;
199
200 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
201
202 assert(name);
203 assert(gr);
204
205 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
206 goto not_found;
207
208 r = sd_bus_open_system(&bus);
209 if (r < 0)
210 goto fail;
211
212 r = sd_bus_call_method(bus,
213 "org.freedesktop.systemd1",
214 "/org/freedesktop/systemd1",
215 "org.freedesktop.systemd1.Manager",
216 "LookupDynamicUserByName",
217 &error,
218 &reply,
219 "s",
220 name);
221 if (r < 0) {
222 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
223 goto not_found;
224
225 goto fail;
226 }
227
228 r = sd_bus_message_read(reply, "u", &translated);
229 if (r < 0)
230 goto fail;
231
232 l = sizeof(char*) + strlen(name) + 1;
233 if (buflen < l) {
234 *errnop = ENOMEM;
235 return NSS_STATUS_TRYAGAIN;
236 }
237
238 memzero(buffer, sizeof(char*));
239 strcpy(buffer + sizeof(char*), name);
240
241 gr->gr_name = buffer + sizeof(char*);
242 gr->gr_gid = (gid_t) translated;
243 gr->gr_passwd = (char*) "*"; /* locked */
244 gr->gr_mem = (char**) buffer;
245
246 *errnop = 0;
247 return NSS_STATUS_SUCCESS;
248
249 not_found:
250 *errnop = 0;
251 return NSS_STATUS_NOTFOUND;
252
253 fail:
254 *errnop = -r;
255 return NSS_STATUS_UNAVAIL;
256 }
257
258 enum nss_status _nss_systemd_getgrgid_r(
259 gid_t gid,
260 struct group *gr,
261 char *buffer, size_t buflen,
262 int *errnop) {
263
264 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
265 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
266 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
267 const char *translated;
268 size_t l;
269 int r;
270
271 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
272
273 if (!gid_is_valid(gid)) {
274 r = -EINVAL;
275 goto fail;
276 }
277
278 if (gid <= SYSTEM_GID_MAX)
279 goto not_found;
280
281 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
282 goto not_found;
283
284 r = sd_bus_open_system(&bus);
285 if (r < 0)
286 goto fail;
287
288 r = sd_bus_call_method(bus,
289 "org.freedesktop.systemd1",
290 "/org/freedesktop/systemd1",
291 "org.freedesktop.systemd1.Manager",
292 "LookupDynamicUserByUID",
293 &error,
294 &reply,
295 "u",
296 (uint32_t) gid);
297 if (r < 0) {
298 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
299 goto not_found;
300
301 goto fail;
302 }
303
304 r = sd_bus_message_read(reply, "s", &translated);
305 if (r < 0)
306 goto fail;
307
308 l = sizeof(char*) + strlen(translated) + 1;
309 if (buflen < l) {
310 *errnop = ENOMEM;
311 return NSS_STATUS_TRYAGAIN;
312 }
313
314 memzero(buffer, sizeof(char*));
315 strcpy(buffer + sizeof(char*), translated);
316
317 gr->gr_name = buffer + sizeof(char*);
318 gr->gr_gid = gid;
319 gr->gr_passwd = (char*) "*"; /* locked */
320 gr->gr_mem = (char**) buffer;
321
322 *errnop = 0;
323 return NSS_STATUS_SUCCESS;
324
325 not_found:
326 *errnop = 0;
327 return NSS_STATUS_NOTFOUND;
328
329 fail:
330 *errnop = -r;
331 return NSS_STATUS_UNAVAIL;
332 }