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
,
122 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
127 /* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
128 * generate EINVAL here, because it isn't really out business to complain about invalid user names. */
129 if (!valid_user_group_name(name
))
132 /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
133 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
134 if (streq(name
, root_passwd
.pw_name
)) {
137 return NSS_STATUS_SUCCESS
;
139 if (synthesize_nobody() &&
140 streq(name
, nobody_passwd
.pw_name
)) {
141 *pwd
= nobody_passwd
;
143 return NSS_STATUS_SUCCESS
;
147 /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
148 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
151 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
153 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
154 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
155 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
157 r
= sd_bus_open_system(&bus
);
163 r
= sd_bus_call_method(bus
,
164 "org.freedesktop.systemd1",
165 "/org/freedesktop/systemd1",
166 "org.freedesktop.systemd1.Manager",
167 "LookupDynamicUserByName",
173 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
179 r
= sd_bus_message_read(reply
, "u", &translated
);
186 /* Access the dynamic UID allocation directly if we are called from dbus-daemon, see above. */
187 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
197 return NSS_STATUS_TRYAGAIN
;
200 memcpy(buffer
, name
, l
+1);
202 pwd
->pw_name
= buffer
;
203 pwd
->pw_uid
= (uid_t
) translated
;
204 pwd
->pw_gid
= (uid_t
) translated
;
205 pwd
->pw_gecos
= (char*) "Dynamic User";
206 pwd
->pw_passwd
= (char*) "*"; /* locked */
207 pwd
->pw_dir
= (char*) "/";
208 pwd
->pw_shell
= (char*) "/sbin/nologin";
211 return NSS_STATUS_SUCCESS
;
215 return NSS_STATUS_NOTFOUND
;
219 return NSS_STATUS_UNAVAIL
;
222 enum nss_status
_nss_systemd_getpwuid_r(
225 char *buffer
, size_t buflen
,
228 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
229 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
230 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
231 _cleanup_free_
char *direct
= NULL
;
232 const char *translated
;
236 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
238 if (!uid_is_valid(uid
))
241 /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
242 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
243 if (uid
== root_passwd
.pw_uid
) {
246 return NSS_STATUS_SUCCESS
;
248 if (synthesize_nobody() &&
249 uid
== nobody_passwd
.pw_uid
) {
250 *pwd
= nobody_passwd
;
252 return NSS_STATUS_SUCCESS
;
256 if (!uid_is_dynamic(uid
))
259 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
262 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
264 r
= sd_bus_open_system(&bus
);
270 r
= sd_bus_call_method(bus
,
271 "org.freedesktop.systemd1",
272 "/org/freedesktop/systemd1",
273 "org.freedesktop.systemd1.Manager",
274 "LookupDynamicUserByUID",
280 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
286 r
= sd_bus_message_read(reply
, "s", &translated
);
293 r
= direct_lookup_uid(uid
, &direct
);
303 l
= strlen(translated
) + 1;
306 return NSS_STATUS_TRYAGAIN
;
309 memcpy(buffer
, translated
, l
);
311 pwd
->pw_name
= buffer
;
314 pwd
->pw_gecos
= (char*) "Dynamic User";
315 pwd
->pw_passwd
= (char*) "*"; /* locked */
316 pwd
->pw_dir
= (char*) "/";
317 pwd
->pw_shell
= (char*) "/sbin/nologin";
320 return NSS_STATUS_SUCCESS
;
324 return NSS_STATUS_NOTFOUND
;
328 return NSS_STATUS_UNAVAIL
;
331 enum nss_status
_nss_systemd_getgrnam_r(
334 char *buffer
, size_t buflen
,
341 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
346 if (!valid_user_group_name(name
))
349 /* Synthesize records for root and nobody, in case they are missing form /etc/group */
350 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
351 if (streq(name
, root_group
.gr_name
)) {
354 return NSS_STATUS_SUCCESS
;
356 if (synthesize_nobody() &&
357 streq(name
, nobody_group
.gr_name
)) {
360 return NSS_STATUS_SUCCESS
;
364 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
367 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
369 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
370 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
371 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
373 r
= sd_bus_open_system(&bus
);
379 r
= sd_bus_call_method(bus
,
380 "org.freedesktop.systemd1",
381 "/org/freedesktop/systemd1",
382 "org.freedesktop.systemd1.Manager",
383 "LookupDynamicUserByName",
389 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
395 r
= sd_bus_message_read(reply
, "u", &translated
);
402 /* Access the dynamic GID allocation directly if we are called from dbus-daemon, see above. */
403 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
410 l
= sizeof(char*) + strlen(name
) + 1;
413 return NSS_STATUS_TRYAGAIN
;
416 memzero(buffer
, sizeof(char*));
417 strcpy(buffer
+ sizeof(char*), name
);
419 gr
->gr_name
= buffer
+ sizeof(char*);
420 gr
->gr_gid
= (gid_t
) translated
;
421 gr
->gr_passwd
= (char*) "*"; /* locked */
422 gr
->gr_mem
= (char**) buffer
;
425 return NSS_STATUS_SUCCESS
;
429 return NSS_STATUS_NOTFOUND
;
433 return NSS_STATUS_UNAVAIL
;
436 enum nss_status
_nss_systemd_getgrgid_r(
439 char *buffer
, size_t buflen
,
442 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
443 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
444 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
445 _cleanup_free_
char *direct
= NULL
;
446 const char *translated
;
450 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
452 if (!gid_is_valid(gid
))
455 /* Synthesize records for root and nobody, in case they are missing from /etc/group */
456 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
457 if (gid
== root_group
.gr_gid
) {
460 return NSS_STATUS_SUCCESS
;
462 if (synthesize_nobody() &&
463 gid
== nobody_group
.gr_gid
) {
466 return NSS_STATUS_SUCCESS
;
470 if (!gid_is_dynamic(gid
))
473 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
476 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
478 r
= sd_bus_open_system(&bus
);
484 r
= sd_bus_call_method(bus
,
485 "org.freedesktop.systemd1",
486 "/org/freedesktop/systemd1",
487 "org.freedesktop.systemd1.Manager",
488 "LookupDynamicUserByUID",
494 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
500 r
= sd_bus_message_read(reply
, "s", &translated
);
507 r
= direct_lookup_uid(gid
, &direct
);
516 l
= sizeof(char*) + strlen(translated
) + 1;
519 return NSS_STATUS_TRYAGAIN
;
522 memzero(buffer
, sizeof(char*));
523 strcpy(buffer
+ sizeof(char*), translated
);
525 gr
->gr_name
= buffer
+ sizeof(char*);
527 gr
->gr_passwd
= (char*) "*"; /* locked */
528 gr
->gr_mem
= (char**) buffer
;
531 return NSS_STATUS_SUCCESS
;
535 return NSS_STATUS_NOTFOUND
;
539 return NSS_STATUS_UNAVAIL
;