1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
26 #include "bus-common-errors.h"
31 #include "signal-util.h"
32 #include "stdio-util.h"
33 #include "string-util.h"
34 #include "user-util.h"
37 static const struct passwd root_passwd
= {
38 .pw_name
= (char*) "root",
39 .pw_passwd
= (char*) "x", /* see shadow file */
42 .pw_gecos
= (char*) "Super User",
43 .pw_dir
= (char*) "/root",
44 .pw_shell
= (char*) "/bin/sh",
47 static const struct passwd nobody_passwd
= {
48 .pw_name
= (char*) NOBODY_USER_NAME
,
49 .pw_passwd
= (char*) "*", /* locked */
52 .pw_gecos
= (char*) "User Nobody",
53 .pw_dir
= (char*) "/",
54 .pw_shell
= (char*) "/sbin/nologin",
57 static const struct group root_group
= {
58 .gr_name
= (char*) "root",
60 .gr_passwd
= (char*) "x", /* see shadow file */
61 .gr_mem
= (char*[]) { NULL
},
64 static const struct group nobody_group
= {
65 .gr_name
= (char*) NOBODY_GROUP_NAME
,
67 .gr_passwd
= (char*) "*", /* locked */
68 .gr_mem
= (char*[]) { NULL
},
71 NSS_GETPW_PROTOTYPES(systemd
);
72 NSS_GETGR_PROTOTYPES(systemd
);
74 static int direct_lookup_name(const char *name
, uid_t
*ret
) {
75 _cleanup_free_
char *s
= NULL
;
81 /* Normally, we go via the bus to resolve names. That has the benefit that it is available from any mount
82 * namespace and subject to proper authentication. However, there's one problem: if our module is called from
83 * dbus-daemon itself we really can't use D-Bus to communicate. In this case, resort to a client-side hack,
84 * and look for the dynamic names directly. This is pretty ugly, but breaks the cyclic dependency. */
86 path
= strjoina("/run/systemd/dynamic-uid/direct:", name
);
87 r
= readlink_malloc(path
, &s
);
91 return parse_uid(s
, ret
);
94 static int direct_lookup_uid(uid_t uid
, char **ret
) {
95 char path
[STRLEN("/run/systemd/dynamic-uid/direct:") + DECIMAL_STR_MAX(uid_t
) + 1], *s
;
98 xsprintf(path
, "/run/systemd/dynamic-uid/direct:" UID_FMT
, uid
);
100 r
= readlink_malloc(path
, &s
);
103 if (!valid_user_group_name(s
)) { /* extra safety check */
112 enum nss_status
_nss_systemd_getpwnam_r(
115 char *buffer
, size_t buflen
,
118 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
119 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
120 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
125 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
130 /* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
131 * generate EINVAL here, because it isn't really out business to complain about invalid user names. */
132 if (!valid_user_group_name(name
))
135 /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
136 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
137 if (streq(name
, root_passwd
.pw_name
)) {
140 return NSS_STATUS_SUCCESS
;
142 if (synthesize_nobody() &&
143 streq(name
, nobody_passwd
.pw_name
)) {
144 *pwd
= nobody_passwd
;
146 return NSS_STATUS_SUCCESS
;
150 /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
151 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
154 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
156 r
= sd_bus_open_system(&bus
);
162 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
168 r
= sd_bus_call_method(bus
,
169 "org.freedesktop.systemd1",
170 "/org/freedesktop/systemd1",
171 "org.freedesktop.systemd1.Manager",
172 "LookupDynamicUserByName",
178 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
184 r
= sd_bus_message_read(reply
, "u", &translated
);
192 return NSS_STATUS_TRYAGAIN
;
195 memcpy(buffer
, name
, l
+1);
197 pwd
->pw_name
= buffer
;
198 pwd
->pw_uid
= (uid_t
) translated
;
199 pwd
->pw_gid
= (uid_t
) translated
;
200 pwd
->pw_gecos
= (char*) "Dynamic User";
201 pwd
->pw_passwd
= (char*) "*"; /* locked */
202 pwd
->pw_dir
= (char*) "/";
203 pwd
->pw_shell
= (char*) "/sbin/nologin";
206 return NSS_STATUS_SUCCESS
;
210 return NSS_STATUS_NOTFOUND
;
214 return NSS_STATUS_UNAVAIL
;
217 enum nss_status
_nss_systemd_getpwuid_r(
220 char *buffer
, size_t buflen
,
223 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
224 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
225 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
226 _cleanup_free_
char *direct
= NULL
;
227 const char *translated
;
231 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
233 if (!uid_is_valid(uid
))
236 /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
237 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
238 if (uid
== root_passwd
.pw_uid
) {
241 return NSS_STATUS_SUCCESS
;
243 if (synthesize_nobody() &&
244 uid
== nobody_passwd
.pw_uid
) {
245 *pwd
= nobody_passwd
;
247 return NSS_STATUS_SUCCESS
;
251 if (!uid_is_dynamic(uid
))
254 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
257 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
259 r
= sd_bus_open_system(&bus
);
265 r
= direct_lookup_uid(uid
, &direct
);
274 r
= sd_bus_call_method(bus
,
275 "org.freedesktop.systemd1",
276 "/org/freedesktop/systemd1",
277 "org.freedesktop.systemd1.Manager",
278 "LookupDynamicUserByUID",
284 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
290 r
= sd_bus_message_read(reply
, "s", &translated
);
295 l
= strlen(translated
) + 1;
298 return NSS_STATUS_TRYAGAIN
;
301 memcpy(buffer
, translated
, l
);
303 pwd
->pw_name
= buffer
;
306 pwd
->pw_gecos
= (char*) "Dynamic User";
307 pwd
->pw_passwd
= (char*) "*"; /* locked */
308 pwd
->pw_dir
= (char*) "/";
309 pwd
->pw_shell
= (char*) "/sbin/nologin";
312 return NSS_STATUS_SUCCESS
;
316 return NSS_STATUS_NOTFOUND
;
320 return NSS_STATUS_UNAVAIL
;
323 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
325 enum nss_status
_nss_systemd_getgrnam_r(
328 char *buffer
, size_t buflen
,
331 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
332 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
333 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
338 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
343 if (!valid_user_group_name(name
))
346 /* Synthesize records for root and nobody, in case they are missing form /etc/group */
347 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
348 if (streq(name
, root_group
.gr_name
)) {
351 return NSS_STATUS_SUCCESS
;
353 if (synthesize_nobody() &&
354 streq(name
, nobody_group
.gr_name
)) {
357 return NSS_STATUS_SUCCESS
;
361 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
364 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
366 r
= sd_bus_open_system(&bus
);
372 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
378 r
= sd_bus_call_method(bus
,
379 "org.freedesktop.systemd1",
380 "/org/freedesktop/systemd1",
381 "org.freedesktop.systemd1.Manager",
382 "LookupDynamicUserByName",
388 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
394 r
= sd_bus_message_read(reply
, "u", &translated
);
399 l
= sizeof(char*) + strlen(name
) + 1;
402 return NSS_STATUS_TRYAGAIN
;
405 memzero(buffer
, sizeof(char*));
406 strcpy(buffer
+ sizeof(char*), name
);
408 gr
->gr_name
= buffer
+ sizeof(char*);
409 gr
->gr_gid
= (gid_t
) translated
;
410 gr
->gr_passwd
= (char*) "*"; /* locked */
411 gr
->gr_mem
= (char**) buffer
;
414 return NSS_STATUS_SUCCESS
;
418 return NSS_STATUS_NOTFOUND
;
422 return NSS_STATUS_UNAVAIL
;
425 enum nss_status
_nss_systemd_getgrgid_r(
428 char *buffer
, size_t buflen
,
431 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
432 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
433 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
434 _cleanup_free_
char *direct
= NULL
;
435 const char *translated
;
439 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
441 if (!gid_is_valid(gid
))
444 /* Synthesize records for root and nobody, in case they are missing from /etc/group */
445 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
446 if (gid
== root_group
.gr_gid
) {
449 return NSS_STATUS_SUCCESS
;
451 if (synthesize_nobody() &&
452 gid
== nobody_group
.gr_gid
) {
455 return NSS_STATUS_SUCCESS
;
459 if (!gid_is_dynamic(gid
))
462 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
465 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
467 r
= sd_bus_open_system(&bus
);
473 r
= direct_lookup_uid(gid
, &direct
);
482 r
= sd_bus_call_method(bus
,
483 "org.freedesktop.systemd1",
484 "/org/freedesktop/systemd1",
485 "org.freedesktop.systemd1.Manager",
486 "LookupDynamicUserByUID",
492 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
498 r
= sd_bus_message_read(reply
, "s", &translated
);
503 l
= sizeof(char*) + strlen(translated
) + 1;
506 return NSS_STATUS_TRYAGAIN
;
509 memzero(buffer
, sizeof(char*));
510 strcpy(buffer
+ sizeof(char*), translated
);
512 gr
->gr_name
= buffer
+ sizeof(char*);
514 gr
->gr_passwd
= (char*) "*"; /* locked */
515 gr
->gr_mem
= (char**) buffer
;
518 return NSS_STATUS_SUCCESS
;
522 return NSS_STATUS_NOTFOUND
;
526 return NSS_STATUS_UNAVAIL
;