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 (streq(name
, nobody_passwd
.pw_name
)) {
140 *pwd
= nobody_passwd
;
142 return NSS_STATUS_SUCCESS
;
146 /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
147 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
150 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
152 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
153 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
154 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
156 r
= sd_bus_open_system(&bus
);
162 r
= sd_bus_call_method(bus
,
163 "org.freedesktop.systemd1",
164 "/org/freedesktop/systemd1",
165 "org.freedesktop.systemd1.Manager",
166 "LookupDynamicUserByName",
172 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
178 r
= sd_bus_message_read(reply
, "u", &translated
);
185 /* Access the dynamic UID allocation directly if we are called from dbus-daemon, see above. */
186 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
196 return NSS_STATUS_TRYAGAIN
;
199 memcpy(buffer
, name
, l
+1);
201 pwd
->pw_name
= buffer
;
202 pwd
->pw_uid
= (uid_t
) translated
;
203 pwd
->pw_gid
= (uid_t
) translated
;
204 pwd
->pw_gecos
= (char*) "Dynamic User";
205 pwd
->pw_passwd
= (char*) "*"; /* locked */
206 pwd
->pw_dir
= (char*) "/";
207 pwd
->pw_shell
= (char*) "/sbin/nologin";
210 return NSS_STATUS_SUCCESS
;
214 return NSS_STATUS_NOTFOUND
;
218 return NSS_STATUS_UNAVAIL
;
221 enum nss_status
_nss_systemd_getpwuid_r(
224 char *buffer
, size_t buflen
,
227 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
228 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
229 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
230 _cleanup_free_
char *direct
= NULL
;
231 const char *translated
;
235 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
237 if (!uid_is_valid(uid
))
240 /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
241 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
242 if (uid
== root_passwd
.pw_uid
) {
245 return NSS_STATUS_SUCCESS
;
247 if (uid
== nobody_passwd
.pw_uid
) {
248 *pwd
= nobody_passwd
;
250 return NSS_STATUS_SUCCESS
;
254 if (!uid_is_dynamic(uid
))
257 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
260 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
262 r
= sd_bus_open_system(&bus
);
268 r
= sd_bus_call_method(bus
,
269 "org.freedesktop.systemd1",
270 "/org/freedesktop/systemd1",
271 "org.freedesktop.systemd1.Manager",
272 "LookupDynamicUserByUID",
278 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
284 r
= sd_bus_message_read(reply
, "s", &translated
);
291 r
= direct_lookup_uid(uid
, &direct
);
301 l
= strlen(translated
) + 1;
304 return NSS_STATUS_TRYAGAIN
;
307 memcpy(buffer
, translated
, l
);
309 pwd
->pw_name
= buffer
;
312 pwd
->pw_gecos
= (char*) "Dynamic User";
313 pwd
->pw_passwd
= (char*) "*"; /* locked */
314 pwd
->pw_dir
= (char*) "/";
315 pwd
->pw_shell
= (char*) "/sbin/nologin";
318 return NSS_STATUS_SUCCESS
;
322 return NSS_STATUS_NOTFOUND
;
326 return NSS_STATUS_UNAVAIL
;
329 enum nss_status
_nss_systemd_getgrnam_r(
332 char *buffer
, size_t buflen
,
339 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
344 if (!valid_user_group_name(name
))
347 /* Synthesize records for root and nobody, in case they are missing form /etc/group */
348 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
349 if (streq(name
, root_group
.gr_name
)) {
352 return NSS_STATUS_SUCCESS
;
354 if (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 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
367 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
368 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
370 r
= sd_bus_open_system(&bus
);
376 r
= sd_bus_call_method(bus
,
377 "org.freedesktop.systemd1",
378 "/org/freedesktop/systemd1",
379 "org.freedesktop.systemd1.Manager",
380 "LookupDynamicUserByName",
386 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
392 r
= sd_bus_message_read(reply
, "u", &translated
);
399 /* Access the dynamic GID allocation directly if we are called from dbus-daemon, see above. */
400 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
407 l
= sizeof(char*) + strlen(name
) + 1;
410 return NSS_STATUS_TRYAGAIN
;
413 memzero(buffer
, sizeof(char*));
414 strcpy(buffer
+ sizeof(char*), name
);
416 gr
->gr_name
= buffer
+ sizeof(char*);
417 gr
->gr_gid
= (gid_t
) translated
;
418 gr
->gr_passwd
= (char*) "*"; /* locked */
419 gr
->gr_mem
= (char**) buffer
;
422 return NSS_STATUS_SUCCESS
;
426 return NSS_STATUS_NOTFOUND
;
430 return NSS_STATUS_UNAVAIL
;
433 enum nss_status
_nss_systemd_getgrgid_r(
436 char *buffer
, size_t buflen
,
439 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
440 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
441 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
442 _cleanup_free_
char *direct
= NULL
;
443 const char *translated
;
447 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
449 if (!gid_is_valid(gid
))
452 /* Synthesize records for root and nobody, in case they are missing from /etc/group */
453 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
454 if (gid
== root_group
.gr_gid
) {
457 return NSS_STATUS_SUCCESS
;
459 if (gid
== nobody_group
.gr_gid
) {
462 return NSS_STATUS_SUCCESS
;
466 if (!gid_is_dynamic(gid
))
469 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
472 bypass
= getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
474 r
= sd_bus_open_system(&bus
);
480 r
= sd_bus_call_method(bus
,
481 "org.freedesktop.systemd1",
482 "/org/freedesktop/systemd1",
483 "org.freedesktop.systemd1.Manager",
484 "LookupDynamicUserByUID",
490 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
496 r
= sd_bus_message_read(reply
, "s", &translated
);
503 r
= direct_lookup_uid(gid
, &direct
);
512 l
= sizeof(char*) + strlen(translated
) + 1;
515 return NSS_STATUS_TRYAGAIN
;
518 memzero(buffer
, sizeof(char*));
519 strcpy(buffer
+ sizeof(char*), translated
);
521 gr
->gr_name
= buffer
+ sizeof(char*);
523 gr
->gr_passwd
= (char*) "*"; /* locked */
524 gr
->gr_mem
= (char**) buffer
;
527 return NSS_STATUS_SUCCESS
;
531 return NSS_STATUS_NOTFOUND
;
535 return NSS_STATUS_UNAVAIL
;