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 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
333 enum nss_status
_nss_systemd_getgrnam_r(
336 char *buffer
, size_t buflen
,
343 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
348 if (!valid_user_group_name(name
))
351 /* Synthesize records for root and nobody, in case they are missing form /etc/group */
352 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
353 if (streq(name
, root_group
.gr_name
)) {
356 return NSS_STATUS_SUCCESS
;
358 if (synthesize_nobody() &&
359 streq(name
, nobody_group
.gr_name
)) {
362 return NSS_STATUS_SUCCESS
;
366 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
369 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
371 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
372 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
373 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
375 r
= sd_bus_open_system(&bus
);
381 r
= sd_bus_call_method(bus
,
382 "org.freedesktop.systemd1",
383 "/org/freedesktop/systemd1",
384 "org.freedesktop.systemd1.Manager",
385 "LookupDynamicUserByName",
391 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
397 r
= sd_bus_message_read(reply
, "u", &translated
);
404 /* Access the dynamic GID allocation directly if we are called from dbus-daemon, see above. */
405 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
412 l
= sizeof(char*) + strlen(name
) + 1;
415 return NSS_STATUS_TRYAGAIN
;
418 memzero(buffer
, sizeof(char*));
419 strcpy(buffer
+ sizeof(char*), name
);
421 gr
->gr_name
= buffer
+ sizeof(char*);
422 gr
->gr_gid
= (gid_t
) translated
;
423 gr
->gr_passwd
= (char*) "*"; /* locked */
424 gr
->gr_mem
= (char**) buffer
;
427 return NSS_STATUS_SUCCESS
;
431 return NSS_STATUS_NOTFOUND
;
435 return NSS_STATUS_UNAVAIL
;
438 enum nss_status
_nss_systemd_getgrgid_r(
441 char *buffer
, size_t buflen
,
444 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
445 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
446 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
447 _cleanup_free_
char *direct
= NULL
;
448 const char *translated
;
452 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
454 if (!gid_is_valid(gid
))
457 /* Synthesize records for root and nobody, in case they are missing from /etc/group */
458 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
459 if (gid
== root_group
.gr_gid
) {
462 return NSS_STATUS_SUCCESS
;
464 if (synthesize_nobody() &&
465 gid
== nobody_group
.gr_gid
) {
468 return NSS_STATUS_SUCCESS
;
472 if (!gid_is_dynamic(gid
))
475 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
478 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
480 r
= sd_bus_open_system(&bus
);
486 r
= sd_bus_call_method(bus
,
487 "org.freedesktop.systemd1",
488 "/org/freedesktop/systemd1",
489 "org.freedesktop.systemd1.Manager",
490 "LookupDynamicUserByUID",
496 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
502 r
= sd_bus_message_read(reply
, "s", &translated
);
509 r
= direct_lookup_uid(gid
, &direct
);
518 l
= sizeof(char*) + strlen(translated
) + 1;
521 return NSS_STATUS_TRYAGAIN
;
524 memzero(buffer
, sizeof(char*));
525 strcpy(buffer
+ sizeof(char*), translated
);
527 gr
->gr_name
= buffer
+ sizeof(char*);
529 gr
->gr_passwd
= (char*) "*"; /* locked */
530 gr
->gr_mem
= (char**) buffer
;
533 return NSS_STATUS_SUCCESS
;
537 return NSS_STATUS_NOTFOUND
;
541 return NSS_STATUS_UNAVAIL
;