2 This file is part of systemd.
4 Copyright 2016 Lennart Poettering
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.
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.
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/>.
24 #include "alloc-util.h"
25 #include "bus-common-errors.h"
30 #include "signal-util.h"
31 #include "stdio-util.h"
32 #include "string-util.h"
33 #include "user-util.h"
36 static const struct passwd root_passwd
= {
37 .pw_name
= (char*) "root",
38 .pw_passwd
= (char*) "x", /* see shadow file */
41 .pw_gecos
= (char*) "Super User",
42 .pw_dir
= (char*) "/root",
43 .pw_shell
= (char*) "/bin/sh",
46 static const struct passwd nobody_passwd
= {
47 .pw_name
= (char*) NOBODY_USER_NAME
,
48 .pw_passwd
= (char*) "*", /* locked */
51 .pw_gecos
= (char*) "User Nobody",
52 .pw_dir
= (char*) "/",
53 .pw_shell
= (char*) "/sbin/nologin",
56 static const struct group root_group
= {
57 .gr_name
= (char*) "root",
59 .gr_passwd
= (char*) "x", /* see shadow file */
60 .gr_mem
= (char*[]) { NULL
},
63 static const struct group nobody_group
= {
64 .gr_name
= (char*) NOBODY_GROUP_NAME
,
66 .gr_passwd
= (char*) "*", /* locked */
67 .gr_mem
= (char*[]) { NULL
},
70 NSS_GETPW_PROTOTYPES(systemd
);
71 NSS_GETGR_PROTOTYPES(systemd
);
73 static int direct_lookup_name(const char *name
, uid_t
*ret
) {
74 _cleanup_free_
char *s
= NULL
;
80 /* Normally, we go via the bus to resolve names. That has the benefit that it is available from any mount
81 * namespace and subject to proper authentication. However, there's one problem: if our module is called from
82 * dbus-daemon itself we really can't use D-Bus to communicate. In this case, resort to a client-side hack,
83 * and look for the dynamic names directly. This is pretty ugly, but breaks the cyclic dependency. */
85 path
= strjoina("/run/systemd/dynamic-uid/direct:", name
);
86 r
= readlink_malloc(path
, &s
);
90 return parse_uid(s
, ret
);
93 static int direct_lookup_uid(uid_t uid
, char **ret
) {
94 char path
[strlen("/run/systemd/dynamic-uid/direct:") + DECIMAL_STR_MAX(uid_t
) + 1], *s
;
97 xsprintf(path
, "/run/systemd/dynamic-uid/direct:" UID_FMT
, uid
);
99 r
= readlink_malloc(path
, &s
);
102 if (!valid_user_group_name(s
)) { /* extra safety check */
111 enum nss_status
_nss_systemd_getpwnam_r(
114 char *buffer
, size_t buflen
,
121 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
126 /* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
127 * generate EINVAL here, because it isn't really out business to complain about invalid user names. */
128 if (!valid_user_group_name(name
))
131 /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
132 if (streq(name
, root_passwd
.pw_name
)) {
135 return NSS_STATUS_SUCCESS
;
137 if (streq(name
, nobody_passwd
.pw_name
)) {
138 *pwd
= nobody_passwd
;
140 return NSS_STATUS_SUCCESS
;
143 /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
144 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
147 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
149 /* Access the dynamic UID allocation directly if we are called from dbus-daemon, see above. */
150 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
157 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
158 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
159 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
161 r
= sd_bus_open_system(&bus
);
165 r
= sd_bus_call_method(bus
,
166 "org.freedesktop.systemd1",
167 "/org/freedesktop/systemd1",
168 "org.freedesktop.systemd1.Manager",
169 "LookupDynamicUserByName",
175 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
181 r
= sd_bus_message_read(reply
, "u", &translated
);
189 return NSS_STATUS_TRYAGAIN
;
192 memcpy(buffer
, name
, l
+1);
194 pwd
->pw_name
= buffer
;
195 pwd
->pw_uid
= (uid_t
) translated
;
196 pwd
->pw_gid
= (uid_t
) translated
;
197 pwd
->pw_gecos
= (char*) "Dynamic User";
198 pwd
->pw_passwd
= (char*) "*"; /* locked */
199 pwd
->pw_dir
= (char*) "/";
200 pwd
->pw_shell
= (char*) "/sbin/nologin";
203 return NSS_STATUS_SUCCESS
;
207 return NSS_STATUS_NOTFOUND
;
211 return NSS_STATUS_UNAVAIL
;
214 enum nss_status
_nss_systemd_getpwuid_r(
217 char *buffer
, size_t buflen
,
220 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
221 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
222 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
223 _cleanup_free_
char *direct
= NULL
;
224 const char *translated
;
228 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
230 if (!uid_is_valid(uid
))
233 /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
234 if (uid
== root_passwd
.pw_uid
) {
237 return NSS_STATUS_SUCCESS
;
239 if (uid
== nobody_passwd
.pw_uid
) {
240 *pwd
= nobody_passwd
;
242 return NSS_STATUS_SUCCESS
;
245 if (uid
<= SYSTEM_UID_MAX
)
248 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
251 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
253 r
= direct_lookup_uid(uid
, &direct
);
262 r
= sd_bus_open_system(&bus
);
266 r
= sd_bus_call_method(bus
,
267 "org.freedesktop.systemd1",
268 "/org/freedesktop/systemd1",
269 "org.freedesktop.systemd1.Manager",
270 "LookupDynamicUserByUID",
276 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
282 r
= sd_bus_message_read(reply
, "s", &translated
);
287 l
= strlen(translated
) + 1;
290 return NSS_STATUS_TRYAGAIN
;
293 memcpy(buffer
, translated
, l
);
295 pwd
->pw_name
= buffer
;
298 pwd
->pw_gecos
= (char*) "Dynamic User";
299 pwd
->pw_passwd
= (char*) "*"; /* locked */
300 pwd
->pw_dir
= (char*) "/";
301 pwd
->pw_shell
= (char*) "/sbin/nologin";
304 return NSS_STATUS_SUCCESS
;
308 return NSS_STATUS_NOTFOUND
;
312 return NSS_STATUS_UNAVAIL
;
315 enum nss_status
_nss_systemd_getgrnam_r(
318 char *buffer
, size_t buflen
,
325 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
330 if (!valid_user_group_name(name
))
333 /* Synthesize records for root and nobody, in case they are missing form /etc/group */
334 if (streq(name
, root_group
.gr_name
)) {
337 return NSS_STATUS_SUCCESS
;
339 if (streq(name
, nobody_group
.gr_name
)) {
342 return NSS_STATUS_SUCCESS
;
345 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
348 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
350 /* Access the dynamic GID allocation directly if we are called from dbus-daemon, see above. */
351 r
= direct_lookup_name(name
, (uid_t
*) &translated
);
358 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
359 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
360 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
362 r
= sd_bus_open_system(&bus
);
366 r
= sd_bus_call_method(bus
,
367 "org.freedesktop.systemd1",
368 "/org/freedesktop/systemd1",
369 "org.freedesktop.systemd1.Manager",
370 "LookupDynamicUserByName",
376 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
382 r
= sd_bus_message_read(reply
, "u", &translated
);
387 l
= sizeof(char*) + strlen(name
) + 1;
390 return NSS_STATUS_TRYAGAIN
;
393 memzero(buffer
, sizeof(char*));
394 strcpy(buffer
+ sizeof(char*), name
);
396 gr
->gr_name
= buffer
+ sizeof(char*);
397 gr
->gr_gid
= (gid_t
) translated
;
398 gr
->gr_passwd
= (char*) "*"; /* locked */
399 gr
->gr_mem
= (char**) buffer
;
402 return NSS_STATUS_SUCCESS
;
406 return NSS_STATUS_NOTFOUND
;
410 return NSS_STATUS_UNAVAIL
;
413 enum nss_status
_nss_systemd_getgrgid_r(
416 char *buffer
, size_t buflen
,
419 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
420 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
421 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
422 _cleanup_free_
char *direct
= NULL
;
423 const char *translated
;
427 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
429 if (!gid_is_valid(gid
))
432 /* Synthesize records for root and nobody, in case they are missing from /etc/group */
433 if (gid
== root_group
.gr_gid
) {
436 return NSS_STATUS_SUCCESS
;
438 if (gid
== nobody_group
.gr_gid
) {
441 return NSS_STATUS_SUCCESS
;
444 if (gid
<= SYSTEM_GID_MAX
)
447 if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
450 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
452 r
= direct_lookup_uid(gid
, &direct
);
460 r
= sd_bus_open_system(&bus
);
464 r
= sd_bus_call_method(bus
,
465 "org.freedesktop.systemd1",
466 "/org/freedesktop/systemd1",
467 "org.freedesktop.systemd1.Manager",
468 "LookupDynamicUserByUID",
474 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_DYNAMIC_USER
))
480 r
= sd_bus_message_read(reply
, "s", &translated
);
485 l
= sizeof(char*) + strlen(translated
) + 1;
488 return NSS_STATUS_TRYAGAIN
;
491 memzero(buffer
, sizeof(char*));
492 strcpy(buffer
+ sizeof(char*), translated
);
494 gr
->gr_name
= buffer
+ sizeof(char*);
496 gr
->gr_passwd
= (char*) "*"; /* locked */
497 gr
->gr_mem
= (char**) buffer
;
500 return NSS_STATUS_SUCCESS
;
504 return NSS_STATUS_NOTFOUND
;
508 return NSS_STATUS_UNAVAIL
;