Compare commits
30 Commits
d3e0662c7d
...
95b29f3267
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 95b29f3267 | |
Zbigniew Jędrzejewski-Szmek | b8ff0663e8 | |
Yu Watanabe | 43bf28741f | |
Yu Watanabe | 93b0b88c3a | |
Yu Watanabe | 6906794dd1 | |
Yu Watanabe | 5d976f5f64 | |
Yu Watanabe | 0c816fcc7b | |
Yu Watanabe | 659ad3a0af | |
Yu Watanabe | d98c546dac | |
Yu Watanabe | 01c344bdd4 | |
Yu Watanabe | 571f953934 | |
Yu Watanabe | 39373cb984 | |
Yu Watanabe | c5fcd8a70a | |
Yu Watanabe | 491b79aeac | |
Yu Watanabe | eb01a2dfb1 | |
Yu Watanabe | a4623f84ed | |
Yu Watanabe | feb596b5c3 | |
Yu Watanabe | 2a877f4560 | |
Lennart Poettering | ee5c1311ee | |
Zbigniew Jędrzejewski-Szmek | a996ead6a2 | |
Filipe Brandenburger | 26698337f3 | |
Zbigniew Jędrzejewski-Szmek | b56a877ef8 | |
Zbigniew Jędrzejewski-Szmek | a318a5659a | |
Lennart Poettering | dad2062f40 | |
Lennart Poettering | 38ccb55731 | |
Lennart Poettering | 4c2cf15751 | |
Lennart Poettering | 4751364e76 | |
Lennart Poettering | 74d1b7d2ad | |
Lennart Poettering | a07f18cd30 | |
Lennart Poettering | 56870d324b |
22
README
22
README
|
@ -262,19 +262,19 @@ USERS AND GROUPS:
|
|||
NSS:
|
||||
systemd ships with four glibc NSS modules:
|
||||
|
||||
nss-myhostname resolves the local hostname to locally
|
||||
configured IP addresses, as well as "localhost" to
|
||||
127.0.0.1/::1.
|
||||
nss-myhostname resolves the local hostname to locally configured IP
|
||||
addresses, as well as "localhost" to 127.0.0.1/::1.
|
||||
|
||||
nss-resolve enables DNS resolution via the systemd-resolved
|
||||
DNS/LLMNR caching stub resolver "systemd-resolved".
|
||||
nss-resolve enables DNS resolution via the systemd-resolved DNS/LLMNR
|
||||
caching stub resolver "systemd-resolved".
|
||||
|
||||
nss-mymachines enables resolution of all local containers registered
|
||||
with machined to their respective IP addresses. It also maps UID/GIDs
|
||||
ranges used by containers to useful names.
|
||||
with machined to their respective IP addresses.
|
||||
|
||||
nss-systemd enables resolution of all dynamically allocated service
|
||||
users. (See the DynamicUser= setting in unit files.)
|
||||
nss-systemd enables resolution of users/group registered via the
|
||||
User/Group Record Lookup API (https://systemd.io/USER_GROUP_API/),
|
||||
including all dynamically allocated service users. (See the
|
||||
DynamicUser= setting in unit files.)
|
||||
|
||||
To make use of these NSS modules, please add them to the "hosts:",
|
||||
"passwd:" and "group:" lines in /etc/nsswitch.conf. The "resolve"
|
||||
|
@ -283,8 +283,8 @@ NSS:
|
|||
|
||||
The four modules should be used in the following order:
|
||||
|
||||
passwd: compat mymachines systemd
|
||||
group: compat mymachines systemd
|
||||
passwd: compat systemd
|
||||
group: compat systemd
|
||||
hosts: files mymachines resolve [!UNAVAIL=return] dns myhostname
|
||||
|
||||
SYSV INIT.D SCRIPTS:
|
||||
|
|
1
TODO
1
TODO
|
@ -336,7 +336,6 @@ Features:
|
|||
|
||||
* homed:
|
||||
- when user tries to log into record signed by unrecognized key, automatically add key to our chain after polkit auth
|
||||
- hook up machined/nspawn users with a varlink user query interface
|
||||
- rollback when resize fails mid-operation
|
||||
- GNOME's side for forget key on suspend (requires rework so that lock screen runs outside of uid)
|
||||
- resize on login?
|
||||
|
|
|
@ -132,7 +132,7 @@ but downstreams are strongly advised against doing that.)
|
|||
range is above the 16bit boundary. Moreover it's below the 31bit boundary,
|
||||
as some broken code (specifically: the kernel's `devpts` file system)
|
||||
erroneously considers UIDs signed integers, and hence can't deal with values
|
||||
above 2^31. The `nss-mymachines` glibc NSS module will synthesize user
|
||||
above 2^31. The `systemd-machined.service` service will synthesize user
|
||||
database records for all UIDs assigned to a running container from this
|
||||
range.
|
||||
|
||||
|
@ -240,14 +240,14 @@ the artifacts the container manager persistently leaves in the system.
|
|||
| 5 | `tty` group | `systemd` | `/etc/passwd` |
|
||||
| 6…999 | System users | Distributions | `/etc/passwd` |
|
||||
| 1000…60000 | Regular users | Distributions | `/etc/passwd` + LDAP/NIS/… |
|
||||
| 60001…60513 | Human Users (homed) | `systemd` | `nss-systemd`
|
||||
| 60001…60513 | Human Users (homed) | `systemd` | `nss-systemd` |
|
||||
| 60514…61183 | Unused | | |
|
||||
| 61184…65519 | Dynamic service users | `systemd` | `nss-systemd` |
|
||||
| 65520…65533 | Unused | | |
|
||||
| 65534 | `nobody` user | Linux | `/etc/passwd` + `nss-systemd` |
|
||||
| 65535 | 16bit `(uid_t) -1` | Linux | |
|
||||
| 65536…524287 | Unused | | |
|
||||
| 524288…1879048191 | Container UID ranges | `systemd` | `nss-mymachines` |
|
||||
| 524288…1879048191 | Container UID ranges | `systemd` | `nss-systemd` |
|
||||
| 1879048192…2147483647 | Unused | | |
|
||||
| 2147483648…4294967294 | HIC SVNT LEONES | | |
|
||||
| 4294967295 | 32bit `(uid_t) -1` | Linux | |
|
||||
|
|
|
@ -108,7 +108,7 @@ example, introspection is not available, and the resolver logic is not used.
|
|||
|
||||
## Other Services
|
||||
|
||||
The `systemd` project provides two other services implementing this
|
||||
The `systemd` project provides three other services implementing this
|
||||
interface. Specifically:
|
||||
|
||||
1. `io.systemd.DynamicUser` → This service is implemented by the service
|
||||
|
@ -119,6 +119,10 @@ interface. Specifically:
|
|||
and provides records for the users and groups defined by the home
|
||||
directories it manages.
|
||||
|
||||
3. `io.systemd.Machine` → This service is implemented by
|
||||
`systemd-machined.service` and provides records for the users and groups used
|
||||
by local containers that use user namespacing.
|
||||
|
||||
Other projects are invited to implement these services too. For example it
|
||||
would make sense for LDAP/ActiveDirectory projects to implement these
|
||||
interfaces, which would provide them a way to do per-user resource management
|
||||
|
@ -185,6 +189,7 @@ error NoRecordFound()
|
|||
error BadService()
|
||||
error ServiceNotAvailable()
|
||||
error ConflictingRecordFound()
|
||||
error EnumerationNotSupported()
|
||||
```
|
||||
|
||||
The `GetUserRecord` method looks up or enumerates a user record. If the `uid`
|
||||
|
@ -264,4 +269,11 @@ services. Result of this is that it can be one service that defines a user A,
|
|||
and another service that defines a group B, and a third service that declares
|
||||
that A is a member of B.
|
||||
|
||||
Looking up explicit users/groups by their name or UID/GID, or querying
|
||||
user/group memberships must be supported by all services implementing these
|
||||
interfaces. However, supporting enumeration (i.e. user/group lookups that may
|
||||
result in more than one reply, because neither UID/GID nor name is specified)
|
||||
is optional. Services which are asked for enumeration may return the
|
||||
`EnumerationNotSupported` error in this case.
|
||||
|
||||
And that's really all there is to it.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# This file is part of systemd.
|
||||
|
||||
passwd: compat mymachines systemd
|
||||
group: compat [SUCCESS=merge] mymachines [SUCCESS=merge] systemd
|
||||
passwd: compat systemd
|
||||
group: compat [SUCCESS=merge] systemd
|
||||
shadow: compat
|
||||
|
||||
hosts: files mymachines resolve [!UNAVAIL=return] dns myhostname
|
||||
|
|
|
@ -82,8 +82,8 @@
|
|||
<command>nss-myhostname</command> correctly:</para>
|
||||
|
||||
<!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf -->
|
||||
<programlisting>passwd: compat mymachines systemd
|
||||
group: compat mymachines systemd
|
||||
<programlisting>passwd: compat systemd
|
||||
group: compat systemd
|
||||
shadow: compat
|
||||
|
||||
# Either (untrusted network):
|
||||
|
|
|
@ -39,22 +39,13 @@
|
|||
Note that the name that is resolved is the one registered with <command>systemd-machined</command>, which
|
||||
may be different than the hostname configured inside of the container.</para>
|
||||
|
||||
<para>The module also provides name resolution for user and group identifiers mapped to containers. All names from
|
||||
the range allocated to a given container <replaceable>container</replaceable> are exposed on the host as
|
||||
<literal>vu-<replaceable>container</replaceable>-<replaceable>uid</replaceable></literal> and
|
||||
<literal>vg-<replaceable>container</replaceable>-<replaceable>gid</replaceable></literal> (see example below). This
|
||||
functionality only applies to containers using user namespacing (see the description of
|
||||
<option>--private-users</option> in
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
|
||||
|
||||
<para>To activate the NSS module, add <literal>mymachines</literal> to the lines starting with
|
||||
<literal>hosts:</literal>, <literal>passwd:</literal> and <literal>group:</literal> in
|
||||
<filename>/etc/nsswitch.conf</filename>.</para>
|
||||
<para>To activate the NSS module, add <literal>mymachines</literal> to the line starting with
|
||||
<literal>hosts:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
|
||||
|
||||
<para>It is recommended to place <literal>mymachines</literal> after the <literal>files</literal> or
|
||||
<literal>compat</literal> entry of the <filename>/etc/nsswitch.conf</filename> lines to make sure that its mappings
|
||||
are preferred over other resolvers such as DNS, but so that <filename>/etc/hosts</filename>,
|
||||
<filename>/etc/passwd</filename> and <filename>/etc/group</filename> based mappings take precedence.</para>
|
||||
<literal>compat</literal> entry of the <filename>/etc/nsswitch.conf</filename> line to make sure that its
|
||||
mappings are preferred over other resolvers such as DNS, but so that <filename>/etc/hosts</filename>
|
||||
based mappings take precedence.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -64,8 +55,8 @@
|
|||
<command>nss-mymachines</command> correctly:</para>
|
||||
|
||||
<!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf -->
|
||||
<programlisting>passwd: compat <command>mymachines</command> systemd
|
||||
group: compat <command>mymachines</command> systemd
|
||||
<programlisting>passwd: compat systemd
|
||||
group: compat systemd
|
||||
shadow: compat
|
||||
|
||||
hosts: <command>mymachines</command> resolve [!UNAVAIL=return] myhostname files dns
|
||||
|
@ -81,7 +72,7 @@ netgroup: nis</programlisting>
|
|||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Mappings provided by <filename>nss-mymachines</filename></title>
|
||||
<title>Example: Mappings provided by <filename>nss-mymachines</filename></title>
|
||||
|
||||
<para>The container <literal>rawhide</literal> is spawned using
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>:
|
||||
|
@ -96,29 +87,6 @@ $ machinectl --max-addresses=3
|
|||
MACHINE CLASS SERVICE OS VERSION ADDRESSES
|
||||
rawhide container systemd-nspawn fedora 30 169.254.40.164 fe80::94aa:3aff:fe7b:d4b9
|
||||
|
||||
$ getent passwd vu-rawhide-0 vu-rawhide-81
|
||||
vu-rawhide-0:*:20119552:65534:vu-rawhide-0:/:/usr/sbin/nologin
|
||||
vu-rawhide-81:*:20119633:65534:vu-rawhide-81:/:/usr/sbin/nologin
|
||||
|
||||
$ getent group vg-rawhide-0 vg-rawhide-81
|
||||
vg-rawhide-0:*:20119552:
|
||||
vg-rawhide-81:*:20119633:
|
||||
|
||||
$ ps -o user:15,pid,tty,command -e|grep '^vu-rawhide'
|
||||
vu-rawhide-0 692 ? /usr/lib/systemd/systemd
|
||||
vu-rawhide-0 731 ? /usr/lib/systemd/systemd-journald
|
||||
vu-rawhide-192 734 ? /usr/lib/systemd/systemd-networkd
|
||||
vu-rawhide-193 738 ? /usr/lib/systemd/systemd-resolved
|
||||
vu-rawhide-0 742 ? /usr/lib/systemd/systemd-logind
|
||||
vu-rawhide-81 744 ? /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
|
||||
vu-rawhide-0 746 ? /usr/sbin/sshd -D ...
|
||||
vu-rawhide-0 752 ? /usr/lib/systemd/systemd --user
|
||||
vu-rawhide-0 753 ? (sd-pam)
|
||||
vu-rawhide-0 1628 ? login -- zbyszek
|
||||
vu-rawhide-1000 1630 ? /usr/lib/systemd/systemd --user
|
||||
vu-rawhide-1000 1631 ? (sd-pam)
|
||||
vu-rawhide-1000 1637 pts/8 -zsh
|
||||
|
||||
$ ping -c1 rawhide
|
||||
PING rawhide(fe80::94aa:3aff:fe7b:d4b9%ve-rawhide (fe80::94aa:3aff:fe7b:d4b9%ve-rawhide)) 56 data bytes
|
||||
64 bytes from fe80::94aa:3aff:fe7b:d4b9%ve-rawhide (fe80::94aa:3aff:fe7b:d4b9%ve-rawhide): icmp_seq=1 ttl=64 time=0.045 ms
|
||||
|
|
|
@ -63,8 +63,8 @@
|
|||
correctly:</para>
|
||||
|
||||
<!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf -->
|
||||
<programlisting>passwd: compat mymachines systemd
|
||||
group: compat mymachines systemd
|
||||
<programlisting>passwd: compat systemd
|
||||
group: compat systemd
|
||||
shadow: compat
|
||||
|
||||
hosts: mymachines <command>resolve [!UNAVAIL=return]</command> myhostname files dns
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> (for its
|
||||
<varname>DynamicUser=</varname> feature, see
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details) or
|
||||
<citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
details),
|
||||
<citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, or <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>This module also ensures that the root and nobody users and groups (i.e. the users/groups with the UIDs/GIDs
|
||||
0 and 65534) remain resolvable at all times, even if they aren't listed in <filename>/etc/passwd</filename> or
|
||||
|
@ -55,14 +55,14 @@
|
|||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<title>Configuration in <filename>/etc/nsswitch.conf</filename></title>
|
||||
|
||||
<para>Here is an example <filename>/etc/nsswitch.conf</filename> file that enables
|
||||
<command>nss-systemd</command> correctly:</para>
|
||||
|
||||
<!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf -->
|
||||
<programlisting>passwd: compat mymachines <command>systemd</command>
|
||||
group: compat [SUCCESS=merge] mymachines [SUCCESS=merge] <command>systemd</command>
|
||||
<programlisting>passwd: compat <command>systemd</command>
|
||||
group: compat [SUCCESS=merge] <command>systemd</command>
|
||||
shadow: compat
|
||||
|
||||
hosts: mymachines resolve [!UNAVAIL=return] myhostname files dns
|
||||
|
@ -77,6 +77,47 @@ netgroup: nis</programlisting>
|
|||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example: Mappings provided by <filename>systemd-machined.service</filename></title>
|
||||
|
||||
<para>The container <literal>rawhide</literal> is spawned using
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>:
|
||||
</para>
|
||||
|
||||
<programlisting># systemd-nspawn -M rawhide --boot --network-veth --private-users=pick
|
||||
Spawning container rawhide on /var/lib/machines/rawhide.
|
||||
Selected user namespace base 20119552 and range 65536.
|
||||
...
|
||||
|
||||
$ machinectl --max-addresses=3
|
||||
MACHINE CLASS SERVICE OS VERSION ADDRESSES
|
||||
rawhide container systemd-nspawn fedora 30 169.254.40.164 fe80::94aa:3aff:fe7b:d4b9
|
||||
|
||||
$ getent passwd vu-rawhide-0 vu-rawhide-81
|
||||
vu-rawhide-0:*:20119552:65534:vu-rawhide-0:/:/usr/sbin/nologin
|
||||
vu-rawhide-81:*:20119633:65534:vu-rawhide-81:/:/usr/sbin/nologin
|
||||
|
||||
$ getent group vg-rawhide-0 vg-rawhide-81
|
||||
vg-rawhide-0:*:20119552:
|
||||
vg-rawhide-81:*:20119633:
|
||||
|
||||
$ ps -o user:15,pid,tty,command -e|grep '^vu-rawhide'
|
||||
vu-rawhide-0 692 ? /usr/lib/systemd/systemd
|
||||
vu-rawhide-0 731 ? /usr/lib/systemd/systemd-journald
|
||||
vu-rawhide-192 734 ? /usr/lib/systemd/systemd-networkd
|
||||
vu-rawhide-193 738 ? /usr/lib/systemd/systemd-resolved
|
||||
vu-rawhide-0 742 ? /usr/lib/systemd/systemd-logind
|
||||
vu-rawhide-81 744 ? /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
|
||||
vu-rawhide-0 746 ? /usr/sbin/sshd -D ...
|
||||
vu-rawhide-0 752 ? /usr/lib/systemd/systemd --user
|
||||
vu-rawhide-0 753 ? (sd-pam)
|
||||
vu-rawhide-0 1628 ? login -- zbyszek
|
||||
vu-rawhide-1000 1630 ? /usr/lib/systemd/systemd --user
|
||||
vu-rawhide-1000 1631 ? (sd-pam)
|
||||
vu-rawhide-1000 1637 pts/8 -zsh
|
||||
</programlisting>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
|
@ -85,6 +126,9 @@ netgroup: nis</programlisting>
|
|||
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>nss-mymachines</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-userdbd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>nsswitch.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>getent</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
|
|
|
@ -167,6 +167,7 @@
|
|||
<varlistentry>
|
||||
<term><keycap>h</keycap></term>
|
||||
<term><keycap>?</keycap></term>
|
||||
<term><keycap>F1</keycap></term>
|
||||
<listitem><para>Show a help screen</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
|
|
@ -116,6 +116,13 @@
|
|||
<citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
is also available, which implements importing, exporting, and downloading of container and VM images.
|
||||
</para>
|
||||
|
||||
<para>For each container registered with <filename>systemd-machined.service</filename> that employs user
|
||||
namespacing, users/groups are synthesized for the used UIDs/GIDs. These are made available to the system
|
||||
using the <ulink url="https://systemd.io/USER_GROUP_API">User/Group Record Lookup API via
|
||||
Varlink</ulink>, and thus may be resolved with
|
||||
<citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> or the
|
||||
usual glibc NSS calls.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
|
|
@ -186,6 +186,15 @@
|
|||
available to the system.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>io.systemd.Machine</constant></term>
|
||||
|
||||
<listitem><para>This service is provided by
|
||||
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
and synthesizes records for all users/groups used by a container that employs user
|
||||
namespacing.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>io.systemd.Multiplexer</constant></term>
|
||||
|
||||
|
|
|
@ -20,14 +20,16 @@
|
|||
#define procfs_file_alloca(pid, field) \
|
||||
({ \
|
||||
pid_t _pid_ = (pid); \
|
||||
const char *_r_; \
|
||||
const char *_field_ = (field); \
|
||||
char *_r_; \
|
||||
if (_pid_ == 0) { \
|
||||
_r_ = ("/proc/self/" field); \
|
||||
_r_ = newa(char, STRLEN("/proc/self/") + strlen(_field_) + 1); \
|
||||
strcpy(stpcpy(_r_, "/proc/self/"), _field_); \
|
||||
} else { \
|
||||
_r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
|
||||
sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
|
||||
_r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + strlen(_field_) + 1); \
|
||||
sprintf(_r_, "/proc/" PID_FMT "/%s", _pid_, _field_); \
|
||||
} \
|
||||
_r_; \
|
||||
(const char*) _r_; \
|
||||
})
|
||||
|
||||
typedef enum ProcessCmdlineFlags {
|
||||
|
|
|
@ -346,6 +346,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
|
|||
bool found_monotonic = false, found_realtime = false;
|
||||
bool leave_around = false;
|
||||
triple_timestamp ts;
|
||||
dual_timestamp dts;
|
||||
TimerValue *v;
|
||||
Unit *trigger;
|
||||
int r;
|
||||
|
@ -389,10 +390,10 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
|
|||
|
||||
/* To make the delay due to RandomizedDelaySec= work even at boot,
|
||||
* if the scheduled time has already passed, set the time when systemd
|
||||
* first started as the scheduled time.
|
||||
* Also, we don't have to check t->persistent since the logic implicitly express true. */
|
||||
if (v->next_elapse < UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime)
|
||||
v->next_elapse = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime;
|
||||
* first started as the scheduled time. */
|
||||
dual_timestamp_from_monotonic(&dts, UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic);
|
||||
if (v->next_elapse < dts.realtime)
|
||||
v->next_elapse = dts.realtime;
|
||||
|
||||
if (!found_realtime)
|
||||
t->next_elapse_realtime = v->next_elapse;
|
||||
|
|
|
@ -746,6 +746,143 @@ int machine_get_uid_shift(Machine *m, uid_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int machine_owns_uid_internal(
|
||||
Machine *machine,
|
||||
const char *map_file, /* "uid_map" or "gid_map" */
|
||||
uid_t uid,
|
||||
uid_t *ret_internal_uid) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
const char *p;
|
||||
|
||||
/* This is a generic implementation for both uids and gids, under the assumptions they have the same types and semantics. */
|
||||
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
||||
|
||||
assert(machine);
|
||||
|
||||
/* Checks if the specified host UID is owned by the machine, and returns the UID it maps to
|
||||
* internally in the machine */
|
||||
|
||||
if (machine->class != MACHINE_CONTAINER)
|
||||
goto negative;
|
||||
|
||||
p = procfs_file_alloca(machine->leader, map_file);
|
||||
f = fopen(p, "re");
|
||||
if (!f) {
|
||||
log_debug_errno(errno, "Failed to open %s, ignoring.", p);
|
||||
goto negative;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
uid_t uid_base, uid_shift, uid_range, converted;
|
||||
int k;
|
||||
|
||||
errno = 0;
|
||||
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
|
||||
if (k < 0 && feof(f))
|
||||
break;
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* The private user namespace is disabled, ignoring. */
|
||||
if (uid_shift == 0)
|
||||
continue;
|
||||
|
||||
if (uid < uid_shift || uid >= uid_shift + uid_range)
|
||||
continue;
|
||||
|
||||
converted = (uid - uid_shift + uid_base);
|
||||
if (!uid_is_valid(converted))
|
||||
return -EINVAL;
|
||||
|
||||
if (ret_internal_uid)
|
||||
*ret_internal_uid = converted;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
negative:
|
||||
if (ret_internal_uid)
|
||||
*ret_internal_uid = UID_INVALID;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int machine_owns_uid(Machine *machine, uid_t uid, uid_t *ret_internal_uid) {
|
||||
return machine_owns_uid_internal(machine, "uid_map", uid, ret_internal_uid);
|
||||
}
|
||||
|
||||
int machine_owns_gid(Machine *machine, gid_t gid, gid_t *ret_internal_gid) {
|
||||
return machine_owns_uid_internal(machine, "gid_map", (uid_t) gid, (uid_t*) ret_internal_gid);
|
||||
}
|
||||
|
||||
static int machine_translate_uid_internal(
|
||||
Machine *machine,
|
||||
const char *map_file, /* "uid_map" or "gid_map" */
|
||||
uid_t uid,
|
||||
uid_t *ret_host_uid) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
const char *p;
|
||||
|
||||
/* This is a generic implementation for both uids and gids, under the assumptions they have the same types and semantics. */
|
||||
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
||||
|
||||
assert(machine);
|
||||
assert(uid_is_valid(uid));
|
||||
|
||||
if (machine->class != MACHINE_CONTAINER)
|
||||
return -ESRCH;
|
||||
|
||||
/* Translates a machine UID into a host UID */
|
||||
|
||||
p = procfs_file_alloca(machine->leader, map_file);
|
||||
f = fopen(p, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
uid_t uid_base, uid_shift, uid_range, converted;
|
||||
int k;
|
||||
|
||||
errno = 0;
|
||||
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
|
||||
if (k < 0 && feof(f))
|
||||
break;
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (uid < uid_base || uid >= uid_base + uid_range)
|
||||
continue;
|
||||
|
||||
converted = uid - uid_base + uid_shift;
|
||||
if (!uid_is_valid(converted))
|
||||
return -EINVAL;
|
||||
|
||||
if (ret_host_uid)
|
||||
*ret_host_uid = converted;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
int machine_translate_uid(Machine *machine, gid_t uid, gid_t *ret_host_uid) {
|
||||
return machine_translate_uid_internal(machine, "uid_map", uid, ret_host_uid);
|
||||
}
|
||||
|
||||
int machine_translate_gid(Machine *machine, gid_t gid, gid_t *ret_host_gid) {
|
||||
return machine_translate_uid_internal(machine, "gid_map", (uid_t) gid, (uid_t*) ret_host_gid);
|
||||
}
|
||||
|
||||
static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
|
||||
[MACHINE_CONTAINER] = "container",
|
||||
[MACHINE_VM] = "vm",
|
||||
|
|
|
@ -94,3 +94,9 @@ int machine_openpt(Machine *m, int flags, char **ret_slave);
|
|||
int machine_open_terminal(Machine *m, const char *path, int mode);
|
||||
|
||||
int machine_get_uid_shift(Machine *m, uid_t *ret);
|
||||
|
||||
int machine_owns_uid(Machine *m, uid_t host_uid, uid_t *ret_internal_uid);
|
||||
int machine_owns_gid(Machine *m, gid_t host_gid, gid_t *ret_internal_gid);
|
||||
|
||||
int machine_translate_uid(Machine *m, uid_t internal_uid, uid_t *ret_host_uid);
|
||||
int machine_translate_gid(Machine *m, gid_t internal_gid, gid_t *ret_host_gid);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "machined.h"
|
||||
#include "nscd-flush.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
|
||||
static int on_nscd_cache_flush_event(sd_event_source *s, void *userdata) {
|
||||
/* Let's ask glibc's nscd daemon to flush its caches. We request this for the three database machines may show
|
||||
|
@ -34,3 +35,72 @@ int manager_enqueue_nscd_cache_flush(Manager *m) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_find_machine_for_uid(Manager *m, uid_t uid, Machine **ret_machine, uid_t *ret_internal_uid) {
|
||||
Machine *machine;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(uid_is_valid(uid));
|
||||
|
||||
/* Finds the machine for the specified host UID and returns it along with the UID translated into the
|
||||
* internal UID inside the machine */
|
||||
|
||||
HASHMAP_FOREACH(machine, m->machines, i) {
|
||||
uid_t converted;
|
||||
|
||||
r = machine_owns_uid(machine, uid, &converted);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r) {
|
||||
if (ret_machine)
|
||||
*ret_machine = machine;
|
||||
|
||||
if (ret_internal_uid)
|
||||
*ret_internal_uid = converted;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_machine)
|
||||
*ret_machine = NULL;
|
||||
if (ret_internal_uid)
|
||||
*ret_internal_uid = UID_INVALID;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int manager_find_machine_for_gid(Manager *m, gid_t gid, Machine **ret_machine, gid_t *ret_internal_gid) {
|
||||
Machine *machine;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(gid_is_valid(gid));
|
||||
|
||||
HASHMAP_FOREACH(machine, m->machines, i) {
|
||||
gid_t converted;
|
||||
|
||||
r = machine_owns_gid(machine, gid, &converted);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r) {
|
||||
if (ret_machine)
|
||||
*ret_machine = machine;
|
||||
|
||||
if (ret_internal_gid)
|
||||
*ret_internal_gid = converted;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_machine)
|
||||
*ret_machine = NULL;
|
||||
if (ret_internal_gid)
|
||||
*ret_internal_gid = GID_INVALID;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -883,11 +883,11 @@ static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bu
|
|||
}
|
||||
|
||||
static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
Manager *m = userdata;
|
||||
const char *name, *p;
|
||||
const char *name;
|
||||
Machine *machine;
|
||||
uint32_t uid;
|
||||
uid_t converted;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(message, "su", &name, &uid);
|
||||
|
@ -904,44 +904,20 @@ static int method_map_from_machine_user(sd_bus_message *message, void *userdata,
|
|||
if (machine->class != MACHINE_CONTAINER)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
|
||||
|
||||
p = procfs_file_alloca(machine->leader, "uid_map");
|
||||
f = fopen(p, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
uid_t uid_base, uid_shift, uid_range, converted;
|
||||
int k;
|
||||
|
||||
errno = 0;
|
||||
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
|
||||
if (k < 0 && feof(f))
|
||||
break;
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (uid < uid_base || uid >= uid_base + uid_range)
|
||||
continue;
|
||||
|
||||
converted = uid - uid_base + uid_shift;
|
||||
if (!uid_is_valid(converted))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
|
||||
r = machine_translate_uid(machine, uid, &converted);
|
||||
if (r == -ESRCH)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
|
||||
}
|
||||
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
|
||||
}
|
||||
|
||||
static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *o = NULL;
|
||||
Manager *m = userdata;
|
||||
Machine *machine;
|
||||
uid_t uid;
|
||||
Iterator i;
|
||||
uid_t uid, converted;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(message, "u", &uid);
|
||||
|
@ -952,46 +928,11 @@ static int method_map_to_machine_user(sd_bus_message *message, void *userdata, s
|
|||
if (uid < 0x10000)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
|
||||
|
||||
HASHMAP_FOREACH(machine, m->machines, i) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char p[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
|
||||
|
||||
if (machine->class != MACHINE_CONTAINER)
|
||||
continue;
|
||||
|
||||
xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
|
||||
f = fopen(p, "re");
|
||||
if (!f) {
|
||||
log_warning_errno(errno, "Failed to open %s, ignoring,", p);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *o = NULL;
|
||||
uid_t uid_base, uid_shift, uid_range, converted;
|
||||
int k;
|
||||
|
||||
errno = 0;
|
||||
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
|
||||
if (k < 0 && feof(f))
|
||||
break;
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* The private user namespace is disabled, ignoring. */
|
||||
if (uid_shift == 0)
|
||||
continue;
|
||||
|
||||
if (uid < uid_shift || uid >= uid_shift + uid_range)
|
||||
continue;
|
||||
|
||||
converted = (uid - uid_shift + uid_base);
|
||||
if (!uid_is_valid(converted))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
|
||||
r = manager_find_machine_for_uid(m, uid, &machine, &converted);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!r)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
|
||||
|
||||
o = machine_bus_path(machine);
|
||||
if (!o)
|
||||
|
@ -999,16 +940,12 @@ static int method_map_to_machine_user(sd_bus_message *message, void *userdata, s
|
|||
|
||||
return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
|
||||
}
|
||||
}
|
||||
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
|
||||
}
|
||||
|
||||
static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
Manager *m = groupdata;
|
||||
const char *name, *p;
|
||||
static int method_map_from_machine_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
const char *name;
|
||||
Machine *machine;
|
||||
gid_t converted;
|
||||
uint32_t gid;
|
||||
int r;
|
||||
|
||||
|
@ -1026,44 +963,20 @@ static int method_map_from_machine_group(sd_bus_message *message, void *groupdat
|
|||
if (machine->class != MACHINE_CONTAINER)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
|
||||
|
||||
p = procfs_file_alloca(machine->leader, "gid_map");
|
||||
f = fopen(p, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
gid_t gid_base, gid_shift, gid_range, converted;
|
||||
int k;
|
||||
|
||||
errno = 0;
|
||||
k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
|
||||
if (k < 0 && feof(f))
|
||||
break;
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (gid < gid_base || gid >= gid_base + gid_range)
|
||||
continue;
|
||||
|
||||
converted = gid - gid_base + gid_shift;
|
||||
if (!gid_is_valid(converted))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
|
||||
r = machine_translate_gid(machine, gid, &converted);
|
||||
if (r == -ESRCH)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching group mappings.", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
|
||||
}
|
||||
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
|
||||
}
|
||||
|
||||
static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
|
||||
Manager *m = groupdata;
|
||||
static int method_map_to_machine_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *o = NULL;
|
||||
Manager *m = userdata;
|
||||
Machine *machine;
|
||||
gid_t gid;
|
||||
Iterator i;
|
||||
gid_t gid, converted;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(message, "u", &gid);
|
||||
|
@ -1074,46 +987,11 @@ static int method_map_to_machine_group(sd_bus_message *message, void *groupdata,
|
|||
if (gid < 0x10000)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
|
||||
|
||||
HASHMAP_FOREACH(machine, m->machines, i) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char p[STRLEN("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
|
||||
|
||||
if (machine->class != MACHINE_CONTAINER)
|
||||
continue;
|
||||
|
||||
xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
|
||||
f = fopen(p, "re");
|
||||
if (!f) {
|
||||
log_warning_errno(errno, "Failed to open %s, ignoring,", p);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *o = NULL;
|
||||
gid_t gid_base, gid_shift, gid_range, converted;
|
||||
int k;
|
||||
|
||||
errno = 0;
|
||||
k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
|
||||
if (k < 0 && feof(f))
|
||||
break;
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* The private user namespace is disabled, ignoring. */
|
||||
if (gid_shift == 0)
|
||||
continue;
|
||||
|
||||
if (gid < gid_shift || gid >= gid_shift + gid_range)
|
||||
continue;
|
||||
|
||||
converted = (gid - gid_shift + gid_base);
|
||||
if (!gid_is_valid(converted))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
|
||||
r = manager_find_machine_for_gid(m, gid, &machine, &converted);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!r)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
|
||||
|
||||
o = machine_bus_path(machine);
|
||||
if (!o)
|
||||
|
@ -1121,10 +999,6 @@ static int method_map_to_machine_group(sd_bus_message *message, void *groupdata,
|
|||
|
||||
return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
|
||||
}
|
||||
}
|
||||
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
|
||||
}
|
||||
|
||||
const sd_bus_vtable manager_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
|
|
|
@ -0,0 +1,404 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "format-util.h"
|
||||
#include "machined-varlink.h"
|
||||
#include "mkdir.h"
|
||||
#include "user-util.h"
|
||||
#include "varlink.h"
|
||||
|
||||
typedef struct LookupParameters {
|
||||
const char *user_name;
|
||||
const char *group_name;
|
||||
union {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
const char *service;
|
||||
} LookupParameters;
|
||||
|
||||
static int build_user_json(const char *user_name, uid_t uid, const char *real_name, JsonVariant **ret) {
|
||||
assert(user_name);
|
||||
assert(uid_is_valid(uid));
|
||||
assert(ret);
|
||||
|
||||
return json_build(ret, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("record", JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(user_name)),
|
||||
JSON_BUILD_PAIR("uid", JSON_BUILD_UNSIGNED(uid)),
|
||||
JSON_BUILD_PAIR("gid", JSON_BUILD_UNSIGNED(GID_NOBODY)),
|
||||
JSON_BUILD_PAIR_CONDITION(!isempty(real_name), "realName", JSON_BUILD_STRING(real_name)),
|
||||
JSON_BUILD_PAIR("homeDirectory", JSON_BUILD_STRING("/")),
|
||||
JSON_BUILD_PAIR("shell", JSON_BUILD_STRING(NOLOGIN)),
|
||||
JSON_BUILD_PAIR("locked", JSON_BUILD_BOOLEAN(true)),
|
||||
JSON_BUILD_PAIR("service", JSON_BUILD_STRING("io.systemd.Machine")),
|
||||
JSON_BUILD_PAIR("disposition", JSON_BUILD_STRING("container"))))));
|
||||
}
|
||||
|
||||
static bool user_match_lookup_parameters(LookupParameters *p, const char *name, uid_t uid) {
|
||||
assert(p);
|
||||
|
||||
if (p->user_name && !streq(name, p->user_name))
|
||||
return false;
|
||||
|
||||
if (uid_is_valid(p->uid) && uid != p->uid)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int user_lookup_uid(Manager *m, uid_t uid, char **ret_name, char **ret_real_name) {
|
||||
_cleanup_free_ char *n = NULL, *rn = NULL;
|
||||
uid_t converted_uid;
|
||||
Machine *machine;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(uid_is_valid(uid));
|
||||
assert(ret_name);
|
||||
assert(ret_real_name);
|
||||
|
||||
if (uid < 0x10000) /* Host UID range */
|
||||
return -ESRCH;
|
||||
|
||||
r = manager_find_machine_for_uid(m, uid, &machine, &converted_uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!r)
|
||||
return -ESRCH;
|
||||
|
||||
if (asprintf(&n, "vu-%s-" UID_FMT, machine->name, converted_uid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Don't synthesize invalid user/group names (too long...) */
|
||||
if (!valid_user_group_name(n, 0))
|
||||
return -ESRCH;
|
||||
|
||||
if (asprintf(&rn, "UID " UID_FMT " of Container %s", converted_uid, machine->name) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Don't synthesize invalid real names either, but since this field doesn't matter much, simply invalidate things */
|
||||
if (!valid_gecos(rn))
|
||||
rn = mfree(rn);
|
||||
|
||||
*ret_name = TAKE_PTR(n);
|
||||
*ret_real_name = TAKE_PTR(rn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int user_lookup_name(Manager *m, const char *name, uid_t *ret_uid, char **ret_real_name) {
|
||||
_cleanup_free_ char *mn = NULL, *rn = NULL;
|
||||
uid_t uid, converted_uid;
|
||||
Machine *machine;
|
||||
const char *e, *d;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (!valid_user_group_name(name, 0))
|
||||
return -ESRCH;
|
||||
|
||||
e = startswith(name, "vu-");
|
||||
if (!e)
|
||||
return -ESRCH;
|
||||
|
||||
d = strrchr(e, '-');
|
||||
if (!d)
|
||||
return -ESRCH;
|
||||
|
||||
if (parse_uid(d + 1, &uid) < 0)
|
||||
return -ESRCH;
|
||||
|
||||
mn = strndup(e, d - e);
|
||||
if (!mn)
|
||||
return -ENOMEM;
|
||||
|
||||
machine = hashmap_get(m->machines, mn);
|
||||
if (!machine)
|
||||
return -ESRCH;
|
||||
|
||||
if (machine->class != MACHINE_CONTAINER)
|
||||
return -ESRCH;
|
||||
|
||||
r = machine_translate_uid(machine, uid, &converted_uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (asprintf(&rn, "UID " UID_FMT " of Container %s", uid, machine->name) < 0)
|
||||
return -ENOMEM;
|
||||
if (!valid_gecos(rn))
|
||||
rn = mfree(rn);
|
||||
|
||||
*ret_uid = converted_uid;
|
||||
*ret_real_name = TAKE_PTR(rn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(LookupParameters, uid), 0 },
|
||||
{ "userName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, user_name), JSON_SAFE },
|
||||
{ "service", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, service), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
LookupParameters p = {
|
||||
.uid = UID_INVALID,
|
||||
};
|
||||
_cleanup_free_ char *found_name = NULL, *found_real_name = NULL;
|
||||
uid_t found_uid = UID_INVALID, uid;
|
||||
Manager *m = userdata;
|
||||
const char *un;
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
assert(m);
|
||||
|
||||
r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!streq_ptr(p.service, "io.systemd.Machine"))
|
||||
return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
|
||||
|
||||
if (uid_is_valid(p.uid))
|
||||
r = user_lookup_uid(m, p.uid, &found_name, &found_real_name);
|
||||
else if (p.user_name)
|
||||
r = user_lookup_name(m, p.user_name, &found_uid, &found_real_name);
|
||||
else
|
||||
return varlink_error(link, "io.systemd.UserDatabase.EnumerationNotSupported", NULL);
|
||||
if (r == -ESRCH)
|
||||
return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uid = uid_is_valid(found_uid) ? found_uid : p.uid;
|
||||
un = found_name ?: p.user_name;
|
||||
|
||||
if (!user_match_lookup_parameters(&p, un, uid))
|
||||
return varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
|
||||
|
||||
r = build_user_json(un, uid, found_real_name, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return varlink_reply(link, v);
|
||||
}
|
||||
|
||||
static int build_group_json(const char *group_name, gid_t gid, JsonVariant **ret) {
|
||||
assert(group_name);
|
||||
assert(gid_is_valid(gid));
|
||||
assert(ret);
|
||||
|
||||
return json_build(ret, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("record", JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(group_name)),
|
||||
JSON_BUILD_PAIR("gid", JSON_BUILD_UNSIGNED(gid)),
|
||||
JSON_BUILD_PAIR("service", JSON_BUILD_STRING("io.systemd.Machine")),
|
||||
JSON_BUILD_PAIR("disposition", JSON_BUILD_STRING("container"))))));
|
||||
}
|
||||
|
||||
static bool group_match_lookup_parameters(LookupParameters *p, const char *name, gid_t gid) {
|
||||
assert(p);
|
||||
|
||||
if (p->group_name && !streq(name, p->group_name))
|
||||
return false;
|
||||
|
||||
if (gid_is_valid(p->gid) && gid != p->gid)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int group_lookup_gid(Manager *m, gid_t gid, char **ret_name) {
|
||||
_cleanup_free_ char *n = NULL;
|
||||
gid_t converted_gid;
|
||||
Machine *machine;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(gid_is_valid(gid));
|
||||
assert(ret_name);
|
||||
|
||||
if (gid < 0x10000) /* Host GID range */
|
||||
return -ESRCH;
|
||||
|
||||
r = manager_find_machine_for_gid(m, gid, &machine, &converted_gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!r)
|
||||
return -ESRCH;
|
||||
|
||||
if (asprintf(&n, "vg-%s-" GID_FMT, machine->name, converted_gid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!valid_user_group_name(n, 0))
|
||||
return -ESRCH;
|
||||
|
||||
*ret_name = TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int group_lookup_name(Manager *m, const char *name, gid_t *ret_gid) {
|
||||
_cleanup_free_ char *mn = NULL;
|
||||
gid_t gid, converted_gid;
|
||||
Machine *machine;
|
||||
const char *e, *d;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (!valid_user_group_name(name, 0))
|
||||
return -ESRCH;
|
||||
|
||||
e = startswith(name, "vg-");
|
||||
if (!e)
|
||||
return -ESRCH;
|
||||
|
||||
d = strrchr(e, '-');
|
||||
if (!d)
|
||||
return -ESRCH;
|
||||
|
||||
if (parse_gid(d + 1, &gid) < 0)
|
||||
return -ESRCH;
|
||||
|
||||
mn = strndup(e, d - e);
|
||||
if (!mn)
|
||||
return -ENOMEM;
|
||||
|
||||
machine = hashmap_get(m->machines, mn);
|
||||
if (!mn)
|
||||
return -ESRCH;
|
||||
|
||||
if (machine->class != MACHINE_CONTAINER)
|
||||
return -ESRCH;
|
||||
|
||||
r = machine_translate_gid(machine, gid, &converted_gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_gid = converted_gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(LookupParameters, gid), 0 },
|
||||
{ "groupName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, group_name), JSON_SAFE },
|
||||
{ "service", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, service), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
LookupParameters p = {
|
||||
.gid = GID_INVALID,
|
||||
};
|
||||
_cleanup_free_ char *found_name = NULL;
|
||||
uid_t found_gid = GID_INVALID, gid;
|
||||
Manager *m = userdata;
|
||||
const char *gn;
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
assert(m);
|
||||
|
||||
r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!streq_ptr(p.service, "io.systemd.Machine"))
|
||||
return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
|
||||
|
||||
if (gid_is_valid(p.gid))
|
||||
r = group_lookup_gid(m, p.gid, &found_name);
|
||||
else if (p.group_name)
|
||||
r = group_lookup_name(m, p.group_name, (uid_t*) &found_gid);
|
||||
else
|
||||
return varlink_error(link, "io.systemd.UserDatabase.EnumerationNotSupported", NULL);
|
||||
if (r == -ESRCH)
|
||||
return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
gid = gid_is_valid(found_gid) ? found_gid : p.gid;
|
||||
gn = found_name ?: p.group_name;
|
||||
|
||||
if (!group_match_lookup_parameters(&p, gn, gid))
|
||||
return varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
|
||||
|
||||
r = build_group_json(gn, gid, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return varlink_reply(link, v);
|
||||
}
|
||||
|
||||
static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "userName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, user_name), JSON_SAFE },
|
||||
{ "groupName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, group_name), JSON_SAFE },
|
||||
{ "service", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, service), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
LookupParameters p = {};
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!streq_ptr(p.service, "io.systemd.Machine"))
|
||||
return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL);
|
||||
|
||||
/* We don't support auxiliary groups for machines. */
|
||||
return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
|
||||
}
|
||||
|
||||
int manager_varlink_init(Manager *m) {
|
||||
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->varlink_server)
|
||||
return 0;
|
||||
|
||||
r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate varlink server object: %m");
|
||||
|
||||
varlink_server_set_userdata(s, m);
|
||||
|
||||
r = varlink_server_bind_method_many(
|
||||
s,
|
||||
"io.systemd.UserDatabase.GetUserRecord", vl_method_get_user_record,
|
||||
"io.systemd.UserDatabase.GetGroupRecord", vl_method_get_group_record,
|
||||
"io.systemd.UserDatabase.GetMemberships", vl_method_get_memberships);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
(void) mkdir_p("/run/systemd/userdb", 0755);
|
||||
|
||||
r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.Machine", 0666);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind to varlink socket: %m");
|
||||
|
||||
r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
|
||||
|
||||
m->varlink_server = TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_varlink_done(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
m->varlink_server = varlink_server_unref(m->varlink_server);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "machined.h"
|
||||
|
||||
int manager_varlink_init(Manager *m);
|
||||
void manager_varlink_done(Manager *m);
|
|
@ -20,6 +20,7 @@
|
|||
#include "hostname-util.h"
|
||||
#include "label.h"
|
||||
#include "machine-image.h"
|
||||
#include "machined-varlink.h"
|
||||
#include "machined.h"
|
||||
#include "main-func.h"
|
||||
#include "process-util.h"
|
||||
|
@ -86,6 +87,8 @@ static Manager* manager_unref(Manager *m) {
|
|||
|
||||
bus_verify_polkit_async_registry_free(m->polkit_registry);
|
||||
|
||||
manager_varlink_done(m);
|
||||
|
||||
sd_bus_flush_close_unref(m->bus);
|
||||
sd_event_unref(m->event);
|
||||
|
||||
|
@ -272,6 +275,11 @@ static int manager_startup(Manager *m) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Set up Varlink service */
|
||||
r = manager_varlink_init(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Deserialize state */
|
||||
manager_enumerate_machines(m);
|
||||
|
||||
|
@ -291,6 +299,9 @@ static bool check_idle(void *userdata) {
|
|||
if (m->operations)
|
||||
return false;
|
||||
|
||||
if (varlink_server_current_connections(m->varlink_server) > 0)
|
||||
return false;
|
||||
|
||||
manager_gc(m, true);
|
||||
|
||||
return hashmap_isempty(m->machines);
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
#include "sd-bus.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "image-dbus.h"
|
||||
#include "list.h"
|
||||
#include "machine-dbus.h"
|
||||
#include "machine.h"
|
||||
#include "operation.h"
|
||||
#include "varlink.h"
|
||||
|
||||
struct Manager {
|
||||
sd_event *event;
|
||||
|
@ -37,6 +37,8 @@ struct Manager {
|
|||
unsigned n_operations;
|
||||
|
||||
sd_event_source *nscd_cache_flush_event;
|
||||
|
||||
VarlinkServer *varlink_server;
|
||||
};
|
||||
|
||||
int manager_add_machine(Manager *m, const char *name, Machine **_machine);
|
||||
|
@ -56,3 +58,6 @@ int manager_unit_is_active(Manager *manager, const char *unit);
|
|||
int manager_job_is_active(Manager *manager, const char *path);
|
||||
|
||||
int manager_enqueue_nscd_cache_flush(Manager *m);
|
||||
|
||||
int manager_find_machine_for_uid(Manager *m, uid_t host_uid, Machine **ret_machine, uid_t *ret_internal_uid);
|
||||
int manager_find_machine_for_gid(Manager *m, gid_t host_gid, Machine **ret_machine, gid_t *ret_internal_gid);
|
||||
|
|
|
@ -6,14 +6,16 @@ systemd_machined_sources = files('''
|
|||
'''.split())
|
||||
|
||||
libmachine_core_sources = files('''
|
||||
machine.c
|
||||
machine.h
|
||||
machined-dbus.c
|
||||
machined-core.c
|
||||
machine-dbus.c
|
||||
machine-dbus.h
|
||||
image-dbus.c
|
||||
image-dbus.h
|
||||
machine-dbus.c
|
||||
machine-dbus.h
|
||||
machine.c
|
||||
machine.h
|
||||
machined-core.c
|
||||
machined-dbus.c
|
||||
machined-varlink.c
|
||||
machined-varlink.h
|
||||
operation.c
|
||||
operation.h
|
||||
'''.split())
|
||||
|
|
|
@ -444,6 +444,8 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL)
|
||||
log_link_message_warning_errno(link, m, r, "Could not drop address");
|
||||
else
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
#include "sysctl-util.h"
|
||||
#include "web-util.h"
|
||||
|
||||
static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
|
||||
static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
|
||||
static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
|
||||
static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback);
|
||||
static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback);
|
||||
static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback);
|
||||
static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, link_netlink_message_handler_t callback);
|
||||
static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link);
|
||||
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link);
|
||||
static int dhcp4_update_address(Link *link, bool announce);
|
||||
static int dhcp4_remove_all(Link *link);
|
||||
|
||||
void dhcp4_release_old_lease(Link *link) {
|
||||
struct in_addr address = {}, address_old = {};
|
||||
|
@ -40,9 +40,9 @@ void dhcp4_release_old_lease(Link *link) {
|
|||
(void) sd_dhcp_lease_get_address(link->dhcp_lease_old, &address_old);
|
||||
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
|
||||
(void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false);
|
||||
(void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false);
|
||||
(void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false);
|
||||
(void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false, NULL);
|
||||
(void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false, NULL);
|
||||
(void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false, NULL);
|
||||
|
||||
if (!in4_addr_equal(&address_old, &address))
|
||||
(void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old, NULL);
|
||||
|
@ -88,17 +88,12 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
|
|||
|
||||
if (link->dhcp4_messages == 0) {
|
||||
if (link->dhcp4_route_failed) {
|
||||
struct in_addr address = {};
|
||||
|
||||
link->dhcp4_route_failed = false;
|
||||
link->dhcp4_route_retrying = true;
|
||||
|
||||
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
(void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
|
||||
(void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
|
||||
(void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
|
||||
(void) dhcp_remove_address(link, link->dhcp_lease, &address, dhcp_remove_address_handler);
|
||||
|
||||
r = dhcp4_remove_all(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
if (!link->network->dhcp_send_decline)
|
||||
|
@ -401,7 +396,26 @@ static int link_set_dhcp_routes(Link *link) {
|
|||
return link_set_dns_routes(link, &address);
|
||||
}
|
||||
|
||||
static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
|
||||
static int dhcp_route_remove(Route *route, Link *link, link_netlink_message_handler_t callback) {
|
||||
int r;
|
||||
|
||||
r = route_remove(route, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (callback)
|
||||
link->dhcp4_remove_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_remove_routes(
|
||||
Link *link,
|
||||
sd_dhcp_lease *lease,
|
||||
const struct in_addr *address,
|
||||
bool remove_all,
|
||||
link_netlink_message_handler_t callback) {
|
||||
|
||||
_cleanup_free_ sd_dhcp_route **routes = NULL;
|
||||
uint32_t table;
|
||||
int n, i, r;
|
||||
|
@ -440,13 +454,21 @@ static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_
|
|||
if (!remove_all && set_contains(link->dhcp_routes, route))
|
||||
continue;
|
||||
|
||||
(void) route_remove(route, link, NULL);
|
||||
r = dhcp_route_remove(route, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
|
||||
static int dhcp_remove_router(
|
||||
Link *link,
|
||||
sd_dhcp_lease *lease,
|
||||
const struct in_addr *address,
|
||||
bool remove_all,
|
||||
link_netlink_message_handler_t callback) {
|
||||
|
||||
_cleanup_(route_freep) Route *route_gw = NULL, *route = NULL;
|
||||
const struct in_addr *router;
|
||||
uint32_t table;
|
||||
|
@ -484,8 +506,11 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_
|
|||
route_gw->priority = link->network->dhcp_route_metric;
|
||||
route_gw->table = table;
|
||||
|
||||
if (remove_all || !set_contains(link->dhcp_routes, route_gw))
|
||||
(void) route_remove(route_gw, link, NULL);
|
||||
if (remove_all || !set_contains(link->dhcp_routes, route_gw)) {
|
||||
r = dhcp_route_remove(route_gw, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
|
@ -498,8 +523,11 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_
|
|||
route->priority = link->network->dhcp_route_metric;
|
||||
route->table = table;
|
||||
|
||||
if (remove_all || !set_contains(link->dhcp_routes, route))
|
||||
(void) route_remove(route, link, NULL);
|
||||
if (remove_all || !set_contains(link->dhcp_routes, route)) {
|
||||
r = dhcp_route_remove(route, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
Route *rt;
|
||||
LIST_FOREACH(routes, rt, link->network->static_routes) {
|
||||
|
@ -512,13 +540,21 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_
|
|||
if (!remove_all && in4_addr_equal(router, &rt->gw.in))
|
||||
continue;
|
||||
|
||||
(void) route_remove(rt, link, NULL);
|
||||
r = dhcp_route_remove(rt, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
|
||||
static int dhcp_remove_dns_routes(
|
||||
Link *link,
|
||||
sd_dhcp_lease *lease,
|
||||
const struct in_addr *address,
|
||||
bool remove_all,
|
||||
link_netlink_message_handler_t callback) {
|
||||
|
||||
const struct in_addr *dns;
|
||||
uint32_t table;
|
||||
int i, n, r;
|
||||
|
@ -558,7 +594,9 @@ static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct
|
|||
if (!remove_all && set_contains(link->dhcp_routes, route))
|
||||
continue;
|
||||
|
||||
(void) route_remove(route, link, NULL);
|
||||
r = dhcp_route_remove(route, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!link_prefixroute(link)) {
|
||||
|
@ -566,36 +604,18 @@ static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct
|
|||
|
||||
r = dhcp_prefix_route_from_lease(lease, table, address, &prefix_route);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not delete prefix route: %m");
|
||||
return log_link_warning_errno(link, r, "Could not create prefix route: %m");
|
||||
|
||||
if (remove_all || !set_contains(link->dhcp_routes, prefix_route))
|
||||
(void) route_remove(prefix_route, link, NULL);
|
||||
if (remove_all || !set_contains(link->dhcp_routes, prefix_route)) {
|
||||
r = dhcp_route_remove(prefix_route, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
/* This is only used when retrying to assign the address received from DHCPv4 server.
|
||||
* See dhcp4_route_handler(). */
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
|
||||
else
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
(void) dhcp_lease_renew(link->dhcp_client, link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dhcp_remove_address(
|
||||
Link *link, sd_dhcp_lease *lease,
|
||||
const struct in_addr *address,
|
||||
|
@ -621,7 +641,12 @@ static int dhcp_remove_address(
|
|||
if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0)
|
||||
a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
|
||||
|
||||
(void) address_remove(a, link, callback);
|
||||
r = address_remove(a, link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (callback)
|
||||
link->dhcp4_remove_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -676,8 +701,90 @@ static int dhcp_reset_hostname(Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp4_remove_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->dhcp4_remove_messages > 0);
|
||||
|
||||
link->dhcp4_remove_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -ESRCH)
|
||||
log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 route, ignoring");
|
||||
|
||||
if (link->dhcp4_remove_messages == 0) {
|
||||
r = dhcp4_update_address(link, false);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dhcp4_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->dhcp4_remove_messages > 0);
|
||||
|
||||
link->dhcp4_remove_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL)
|
||||
log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
|
||||
else
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
if (link->dhcp4_remove_messages == 0) {
|
||||
r = dhcp4_update_address(link, false);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dhcp4_remove_all(Link *link) {
|
||||
struct in_addr address;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp_lease);
|
||||
|
||||
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get DHCPv4 address: %m");
|
||||
|
||||
r = dhcp_remove_routes(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_remove_router(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_remove_address(link, link->dhcp_lease, &address, dhcp4_remove_address_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_lease_lost(Link *link) {
|
||||
struct in_addr address = {};
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp_lease);
|
||||
|
@ -686,13 +793,17 @@ static int dhcp_lease_lost(Link *link) {
|
|||
|
||||
link->dhcp4_configured = false;
|
||||
|
||||
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
(void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
|
||||
(void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
|
||||
(void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
|
||||
(void) dhcp_remove_address(link, link->dhcp_lease, &address, NULL);
|
||||
(void) dhcp_reset_mtu(link);
|
||||
(void) dhcp_reset_hostname(link);
|
||||
r = dhcp4_remove_all(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_reset_mtu(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_reset_hostname(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
|
||||
link_dirty(link);
|
||||
|
@ -830,66 +941,33 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int dhcp4_update_address(Link *link,
|
||||
struct in_addr *address,
|
||||
struct in_addr *netmask,
|
||||
uint32_t lifetime) {
|
||||
static int dhcp4_update_address(Link *link, bool announce) {
|
||||
_cleanup_(address_freep) Address *addr = NULL;
|
||||
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
|
||||
struct in_addr address, netmask;
|
||||
unsigned prefixlen;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
assert(netmask);
|
||||
assert(lifetime);
|
||||
|
||||
prefixlen = in4_addr_netmask_to_prefixlen(netmask);
|
||||
|
||||
r = address_new(&addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
addr->family = AF_INET;
|
||||
addr->in_addr.in.s_addr = address->s_addr;
|
||||
addr->cinfo.ifa_prefered = lifetime;
|
||||
addr->cinfo.ifa_valid = lifetime;
|
||||
addr->prefixlen = prefixlen;
|
||||
addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
|
||||
addr->prefix_route = link_prefixroute(link);
|
||||
|
||||
/* allow reusing an existing address and simply update its lifetime
|
||||
* in case it already exists */
|
||||
r = address_configure(addr, link, dhcp4_address_handler, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
|
||||
sd_dhcp_lease *lease;
|
||||
struct in_addr address;
|
||||
struct in_addr netmask;
|
||||
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(client);
|
||||
assert(link->network);
|
||||
|
||||
r = sd_dhcp_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
|
||||
if (!link->dhcp_lease)
|
||||
return 0;
|
||||
|
||||
sd_dhcp_lease_unref(link->dhcp_lease);
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
link->dhcp4_configured = false;
|
||||
link->dhcp_lease = sd_dhcp_lease_ref(lease);
|
||||
link_dirty(link);
|
||||
|
||||
r = sd_dhcp_lease_get_address(lease, &address);
|
||||
/* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they
|
||||
* are called, the related flags must be cleared. Otherwise, the link becomes configured state
|
||||
* before routes are configured. */
|
||||
link->static_routes_configured = false;
|
||||
link->static_nexthops_configured = false;
|
||||
|
||||
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP error: no address: %m");
|
||||
|
||||
r = sd_dhcp_lease_get_netmask(lease, &netmask);
|
||||
r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
|
||||
|
||||
|
@ -899,48 +977,12 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
|
|||
return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
|
||||
}
|
||||
|
||||
r = dhcp4_update_address(link, &address, &netmask, lifetime);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not update IP address: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
|
||||
const struct in_addr *router;
|
||||
sd_dhcp_lease *lease;
|
||||
struct in_addr address;
|
||||
struct in_addr netmask;
|
||||
unsigned prefixlen;
|
||||
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(link);
|
||||
|
||||
link->dhcp4_configured = false;
|
||||
|
||||
r = sd_dhcp_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP error: No lease: %m");
|
||||
|
||||
r = sd_dhcp_lease_get_address(lease, &address);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP error: No address: %m");
|
||||
|
||||
r = sd_dhcp_lease_get_netmask(lease, &netmask);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
|
||||
|
||||
prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
|
||||
|
||||
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
|
||||
r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
|
||||
}
|
||||
if (announce) {
|
||||
const struct in_addr *router;
|
||||
|
||||
r = sd_dhcp_lease_get_router(lease, &router);
|
||||
r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
|
||||
|
||||
|
@ -962,7 +1004,59 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
|
|||
prefixlen),
|
||||
"ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
|
||||
"PREFIXLEN=%u", prefixlen);
|
||||
}
|
||||
|
||||
r = address_new(&addr);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
addr->family = AF_INET;
|
||||
addr->in_addr.in.s_addr = address.s_addr;
|
||||
addr->cinfo.ifa_prefered = lifetime;
|
||||
addr->cinfo.ifa_valid = lifetime;
|
||||
addr->prefixlen = prefixlen;
|
||||
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
|
||||
addr->prefix_route = link_prefixroute(link);
|
||||
|
||||
/* allow reusing an existing address and simply update its lifetime
|
||||
* in case it already exists */
|
||||
r = address_configure(addr, link, dhcp4_address_handler, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
|
||||
sd_dhcp_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(client);
|
||||
|
||||
r = sd_dhcp_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
|
||||
|
||||
sd_dhcp_lease_unref(link->dhcp_lease);
|
||||
link->dhcp_lease = sd_dhcp_lease_ref(lease);
|
||||
link_dirty(link);
|
||||
|
||||
return dhcp4_update_address(link, false);
|
||||
}
|
||||
|
||||
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
|
||||
sd_dhcp_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(link);
|
||||
|
||||
r = sd_dhcp_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP error: No lease: %m");
|
||||
|
||||
sd_dhcp_lease_unref(link->dhcp_lease);
|
||||
link->dhcp_lease = sd_dhcp_lease_ref(lease);
|
||||
link_dirty(link);
|
||||
|
||||
|
@ -1013,9 +1107,14 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
|
|||
}
|
||||
}
|
||||
|
||||
r = dhcp4_update_address(link, &address, &netmask, lifetime);
|
||||
if (link->dhcp4_remove_messages == 0) {
|
||||
r = dhcp4_update_address(link, true);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not update IP address: %m");
|
||||
return r;
|
||||
} else
|
||||
log_link_debug(link,
|
||||
"The link has previously assigned DHCPv4 address or routes. "
|
||||
"The newly assigned address and routes will set up after old ones are removed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "radv-internal.h"
|
||||
#include "web-util.h"
|
||||
|
||||
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
|
||||
static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
|
||||
static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link);
|
||||
static int dhcp6_prefix_remove_all(Manager *m, Link *link);
|
||||
|
@ -33,7 +32,7 @@ static int dhcp6_assign_delegated_prefix(Link *link, const struct in6_addr *pref
|
|||
uint32_t lifetime_preferred,
|
||||
uint32_t lifetime_valid);
|
||||
|
||||
static bool dhcp6_get_prefix_delegation(Link *link) {
|
||||
bool dhcp6_get_prefix_delegation(Link *link) {
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
|
@ -125,7 +124,7 @@ static int dhcp6_get_preferred_delegated_prefix(
|
|||
|
||||
r = in_addr_prefix_next(AF_INET6, &prefix, 64);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Can't allocate another prefix. Out of address space?");
|
||||
return log_link_error_errno(link, r, "Can't allocate another prefix. Out of address space?: %m");
|
||||
}
|
||||
|
||||
return log_link_warning_errno(link, SYNTHETIC_ERRNO(ERANGE), "Couldn't find a suitable prefix. Ran out of address space.");
|
||||
|
@ -172,11 +171,9 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (link->network->dhcp6_pd_assign_prefix) {
|
||||
r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -324,13 +321,25 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link
|
|||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp6_route_messages > 0);
|
||||
|
||||
link->dhcp6_route_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_message_warning_errno(link, m, r, "Received error when adding unreachable route for DHCPv6 delegated subnet");
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_message_warning_errno(link, m, r, "Failed to add unreachable route for DHCPv6 delegated subnet");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (link->dhcp6_route_messages == 0) {
|
||||
log_link_debug(link, "Unreachable routes for DHCPv6 delegated subnets set");
|
||||
link->dhcp6_route_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -342,6 +351,8 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
|||
uint8_t pd_prefix_len;
|
||||
int r;
|
||||
|
||||
link->dhcp6_route_configured = false;
|
||||
|
||||
r = sd_dhcp6_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -386,6 +397,8 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
|||
pd_prefix_len);
|
||||
continue;
|
||||
}
|
||||
if (r > 0)
|
||||
link->dhcp6_route_messages++;
|
||||
|
||||
log_link_debug(link, "Configuring unreachable route for %s/%u",
|
||||
strnull(buf), pd_prefix_len);
|
||||
|
@ -435,6 +448,14 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
|||
* fulfill those with the next available pd delegated prefix. */
|
||||
}
|
||||
|
||||
if (link->dhcp6_route_messages == 0) {
|
||||
link->dhcp6_route_configured = true;
|
||||
link_check_ready(link);
|
||||
} else {
|
||||
log_link_debug(link, "Setting unreachable routes for DHCPv6 delegated subnets");
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -461,14 +482,14 @@ int dhcp6_request_prefix_delegation(Link *link) {
|
|||
|
||||
r = sd_dhcp6_client_get_prefix_delegation(l->dhcp6_client, &enabled);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link");
|
||||
log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enabled == 0) {
|
||||
r = sd_dhcp6_client_set_prefix_delegation(l->dhcp6_client, 1);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link");
|
||||
log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link: 5m");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -486,13 +507,13 @@ int dhcp6_request_prefix_delegation(Link *link) {
|
|||
|
||||
r = sd_dhcp6_client_stop(l->dhcp6_client);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link");
|
||||
log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_start(l->dhcp6_client);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link");
|
||||
log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -506,6 +527,9 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp6_address_messages > 0);
|
||||
|
||||
link->dhcp6_address_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
@ -518,11 +542,15 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||
} else if (r >= 0)
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
if (link->dhcp6_address_messages == 0) {
|
||||
log_link_debug(link, "DHCPv6 addresses set");
|
||||
link->dhcp6_address_configured = true;
|
||||
r = link_request_set_routes(link);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -556,6 +584,8 @@ static int dhcp6_address_change(
|
|||
r = address_configure(addr, link, dhcp6_address_handler, true);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
|
||||
if (r > 0)
|
||||
link->dhcp6_address_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -566,12 +596,13 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
|
|||
struct in6_addr ip6_addr;
|
||||
uint32_t lifetime_preferred, lifetime_valid;
|
||||
|
||||
link->dhcp6_address_configured = false;
|
||||
|
||||
r = sd_dhcp6_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sd_dhcp6_lease_reset_address_iter(lease);
|
||||
|
||||
while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
|
||||
&lifetime_preferred,
|
||||
&lifetime_valid) >= 0) {
|
||||
|
@ -581,6 +612,19 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (link->dhcp6_address_messages == 0) {
|
||||
link->dhcp6_address_configured = true;
|
||||
return link_request_set_routes(link);
|
||||
} else {
|
||||
log_link_debug(link, "Setting DHCPv6 addresses");
|
||||
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
|
||||
* Before they are called, the related flags must be cleared. Otherwise, the link
|
||||
* becomes configured state before routes are configured. */
|
||||
link->static_routes_configured = false;
|
||||
link->static_nexthops_configured = false;
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -605,7 +649,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
|||
(void) dhcp6_prefix_remove_all(link->manager, link);
|
||||
|
||||
link_dirty(link);
|
||||
link->dhcp6_configured = false;
|
||||
break;
|
||||
|
||||
case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
|
||||
|
@ -617,7 +660,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
|||
|
||||
r = dhcp6_lease_pd_prefix_acquired(client, link);
|
||||
if (r < 0)
|
||||
log_link_debug(link, "DHCPv6 did not receive prefixes to delegate");
|
||||
log_link_debug_errno(link, r, "DHCPv6 did not receive prefixes to delegate: %m");
|
||||
|
||||
_fallthrough_;
|
||||
case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
|
||||
|
@ -628,7 +671,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
|||
}
|
||||
|
||||
link_dirty(link);
|
||||
link->dhcp6_configured = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -812,7 +854,6 @@ int dhcp6_configure(Link *link) {
|
|||
log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||
}
|
||||
|
@ -865,21 +906,30 @@ static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
|
|||
return hashmap_get(m->dhcp6_prefixes, addr);
|
||||
}
|
||||
|
||||
static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
|
||||
static int dhcp6_pd_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp6_pd_route_messages > 0);
|
||||
|
||||
link->dhcp6_pd_route_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_message_warning_errno(link, m, r, "Received error adding DHCPv6 Prefix Delegation route");
|
||||
log_link_message_warning_errno(link, m, r, "Failed to add DHCPv6 Prefix Delegation route");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (link->dhcp6_pd_route_messages == 0) {
|
||||
log_link_debug(link, "DHCPv6 prefix delegation routes set");
|
||||
link->dhcp6_pd_route_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -901,9 +951,14 @@ static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
|||
route->dst.in6 = *addr;
|
||||
route->dst_prefixlen = 64;
|
||||
|
||||
r = route_configure(route, link, dhcp6_route_add_handler);
|
||||
link->dhcp6_pd_route_configured = false;
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
|
||||
r = route_configure(route, link, dhcp6_pd_route_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
link->dhcp6_pd_route_messages++;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
|
||||
log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
|
||||
|
@ -998,10 +1053,13 @@ static int dhcp6_prefix_remove_all(Manager *m, Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp6_assign_delegeted_prefix_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp6_pd_address_messages > 0);
|
||||
|
||||
link->dhcp6_pd_address_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
@ -1014,11 +1072,15 @@ static int dhcp6_assign_delegeted_prefix_address_handler(sd_netlink *rtnl, sd_ne
|
|||
} else if (r >= 0)
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
if (link->dhcp6_pd_address_messages == 0) {
|
||||
log_link_debug(link, "DHCPv6 delegated prefix addresses set");
|
||||
link->dhcp6_pd_address_configured = true;
|
||||
r = link_request_set_routes(link);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1036,8 +1098,10 @@ static int dhcp6_assign_delegated_prefix(Link *link,
|
|||
assert(link->network);
|
||||
assert(prefix);
|
||||
|
||||
if (!link->network->dhcp6_pd_assign_prefix)
|
||||
if (!link->network->dhcp6_pd_assign_prefix) {
|
||||
link->dhcp6_pd_address_configured = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
|
@ -1058,11 +1122,19 @@ static int dhcp6_assign_delegated_prefix(Link *link,
|
|||
address->cinfo.ifa_prefered = lifetime_preferred;
|
||||
address->cinfo.ifa_valid = lifetime_valid;
|
||||
|
||||
/* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they
|
||||
* are called, the related flags must be cleared. Otherwise, the link becomes configured state
|
||||
* before routes are configured. */
|
||||
link->static_routes_configured = false;
|
||||
link->static_nexthops_configured = false;
|
||||
link->dhcp6_pd_address_configured = false;
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
|
||||
r = address_configure(address, link, dhcp6_assign_delegeted_prefix_address_handler, true);
|
||||
r = address_configure(address, link, dhcp6_pd_address_handler, true);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to set acquired DHCPv6 delegated prefix address: %m");
|
||||
if (r > 0)
|
||||
link->dhcp6_pd_address_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ typedef enum DHCP6ClientStartMode {
|
|||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
|
||||
bool dhcp6_get_prefix_delegation(Link *link);
|
||||
int dhcp6_request_prefix_delegation(Link *link);
|
||||
int dhcp6_configure(Link *link);
|
||||
int dhcp6_request_address(Link *link, int ir);
|
||||
|
|
|
@ -932,10 +932,9 @@ static int link_request_set_routing_policy_rule(Link *link) {
|
|||
}
|
||||
|
||||
routing_policy_rule_purge(link->manager, link);
|
||||
if (link->routing_policy_rule_messages == 0) {
|
||||
if (link->routing_policy_rule_messages == 0)
|
||||
link->routing_policy_rules_configured = true;
|
||||
link_check_ready(link);
|
||||
} else {
|
||||
else {
|
||||
log_link_debug(link, "Setting routing policy rules");
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
}
|
||||
|
@ -972,10 +971,12 @@ static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int link_request_set_nexthop(Link *link) {
|
||||
static int link_request_set_nexthop(Link *link) {
|
||||
NextHop *nh;
|
||||
int r;
|
||||
|
||||
link->static_nexthops_configured = false;
|
||||
|
||||
LIST_FOREACH(nexthops, nh, link->network->static_nexthops) {
|
||||
r = nexthop_configure(nh, link, nexthop_handler);
|
||||
if (r < 0)
|
||||
|
@ -1018,7 +1019,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|||
if (link->route_messages == 0) {
|
||||
log_link_debug(link, "Routes set");
|
||||
link->static_routes_configured = true;
|
||||
link_check_ready(link);
|
||||
link_request_set_nexthop(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -1040,7 +1041,6 @@ int link_request_set_routes(Link *link) {
|
|||
assert(link->state != _LINK_STATE_INVALID);
|
||||
|
||||
link->static_routes_configured = false;
|
||||
link->static_routes_ready = false;
|
||||
|
||||
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
|
||||
/* During configuring addresses, the link lost its carrier. As networkd is dropping
|
||||
|
@ -1069,7 +1069,7 @@ int link_request_set_routes(Link *link) {
|
|||
|
||||
if (link->route_messages == 0) {
|
||||
link->static_routes_configured = true;
|
||||
link_check_ready(link);
|
||||
link_request_set_nexthop(link);
|
||||
} else {
|
||||
log_link_debug(link, "Setting routes");
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
|
@ -1085,72 +1085,109 @@ void link_check_ready(Link *link) {
|
|||
|
||||
assert(link);
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
|
||||
log_link_debug(link, "%s(): link is in failed or linger state.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->network)
|
||||
return;
|
||||
|
||||
if (!link->addresses_configured)
|
||||
if (!link->addresses_configured) {
|
||||
log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->neighbors_configured)
|
||||
if (!link->neighbors_configured) {
|
||||
log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FOREACH(a, link->addresses, i)
|
||||
if (!address_is_ready(a))
|
||||
if (!address_is_ready(a)) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
|
||||
(void) in_addr_to_string(a->family, &a->in_addr, &str);
|
||||
log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->addresses_ready) {
|
||||
link->addresses_ready = true;
|
||||
r = link_request_set_routes(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
log_link_debug(link, "%s(): static addresses are configured. Configuring static routes.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->static_routes_configured)
|
||||
return;
|
||||
|
||||
if (!link->static_routes_ready) {
|
||||
link->static_routes_ready = true;
|
||||
r = link_request_set_nexthop(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
if (!link->static_routes_configured) {
|
||||
log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->static_nexthops_configured)
|
||||
if (!link->static_nexthops_configured) {
|
||||
log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->routing_policy_rules_configured)
|
||||
if (!link->routing_policy_rules_configured) {
|
||||
log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->tc_configured)
|
||||
if (!link->tc_configured) {
|
||||
log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->sr_iov_configured)
|
||||
if (!link->sr_iov_configured) {
|
||||
log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
|
||||
|
||||
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address)
|
||||
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address) {
|
||||
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_ipv6ll_enabled(link) &&
|
||||
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address))
|
||||
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
|
||||
log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link)) &&
|
||||
!link->dhcp4_configured &&
|
||||
!link->dhcp6_configured &&
|
||||
!link->ndisc_configured &&
|
||||
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address))
|
||||
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && set_isempty(link->addresses)) {
|
||||
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no address is assigned yet.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || dhcp6_get_prefix_delegation(link) || link_ipv6_accept_ra_enabled(link)) {
|
||||
if (!link->dhcp4_configured &&
|
||||
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
|
||||
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
|
||||
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
|
||||
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address)) {
|
||||
/* When DHCP or RA is enabled, at least one protocol must provide an address, or
|
||||
* an IPv4ll fallback address must be configured. */
|
||||
log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
|
||||
__func__,
|
||||
yes_no(link->dhcp4_configured),
|
||||
yes_no(link->dhcp6_address_configured),
|
||||
yes_no(link->dhcp6_route_configured),
|
||||
yes_no(link->dhcp6_pd_address_configured),
|
||||
yes_no(link->dhcp6_pd_route_configured),
|
||||
yes_no(link->ndisc_addresses_configured),
|
||||
yes_no(link->ndisc_routes_configured));
|
||||
}
|
||||
}
|
||||
|
||||
if (link->state != LINK_STATE_CONFIGURED)
|
||||
link_enter_configured(link);
|
||||
|
||||
|
@ -1245,7 +1282,6 @@ static int link_request_set_addresses(Link *link) {
|
|||
link->addresses_ready = false;
|
||||
link->neighbors_configured = false;
|
||||
link->static_routes_configured = false;
|
||||
link->static_routes_ready = false;
|
||||
link->static_nexthops_configured = false;
|
||||
link->routing_policy_rules_configured = false;
|
||||
|
||||
|
|
|
@ -100,13 +100,23 @@ typedef struct Link {
|
|||
char *lease_file;
|
||||
uint32_t original_mtu;
|
||||
unsigned dhcp4_messages;
|
||||
unsigned dhcp4_remove_messages;
|
||||
unsigned dhcp6_address_messages;
|
||||
unsigned dhcp6_route_messages;
|
||||
unsigned dhcp6_pd_address_messages;
|
||||
unsigned dhcp6_pd_route_messages;
|
||||
bool dhcp4_route_failed:1;
|
||||
bool dhcp4_route_retrying:1;
|
||||
bool dhcp4_configured:1;
|
||||
bool dhcp6_configured:1;
|
||||
bool dhcp6_address_configured:1;
|
||||
bool dhcp6_route_configured:1;
|
||||
bool dhcp6_pd_address_configured:1;
|
||||
bool dhcp6_pd_route_configured:1;
|
||||
|
||||
unsigned ndisc_messages;
|
||||
bool ndisc_configured;
|
||||
unsigned ndisc_addresses_messages;
|
||||
unsigned ndisc_routes_messages;
|
||||
bool ndisc_addresses_configured:1;
|
||||
bool ndisc_routes_configured:1;
|
||||
|
||||
sd_ipv4ll *ipv4ll;
|
||||
bool ipv4ll_address:1;
|
||||
|
@ -115,7 +125,6 @@ typedef struct Link {
|
|||
bool addresses_ready:1;
|
||||
bool neighbors_configured:1;
|
||||
bool static_routes_configured:1;
|
||||
bool static_routes_ready:1;
|
||||
bool static_nexthops_configured:1;
|
||||
bool routing_policy_rules_configured:1;
|
||||
bool tc_configured:1;
|
||||
|
@ -217,7 +226,6 @@ uint32_t link_get_vrf_table(Link *link);
|
|||
uint32_t link_get_dhcp_route_table(Link *link);
|
||||
uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
|
||||
int link_request_set_routes(Link *link);
|
||||
int link_request_set_nexthop(Link *link);
|
||||
|
||||
int link_reconfigure(Link *link, bool force);
|
||||
|
||||
|
|
|
@ -82,64 +82,60 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->ndisc_messages > 0);
|
||||
assert(link->ndisc_routes_messages > 0);
|
||||
|
||||
link->ndisc_messages--;
|
||||
link->ndisc_routes_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_message_error_errno(link, m, r, "Could not set NDisc route or address");
|
||||
log_link_message_error_errno(link, m, r, "Could not set NDisc route");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (link->ndisc_messages == 0) {
|
||||
link->ndisc_configured = true;
|
||||
r = link_request_set_routes(link);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
if (link->ndisc_routes_messages == 0) {
|
||||
log_link_debug(link, "NDisc routes set.");
|
||||
link->ndisc_routes_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndisc_netlink_address_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->ndisc_messages > 0);
|
||||
assert(link->ndisc_addresses_messages > 0);
|
||||
|
||||
link->ndisc_messages--;
|
||||
link->ndisc_addresses_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_message_error_errno(link, m, r, "Could not set NDisc route or address");
|
||||
log_link_message_error_errno(link, m, r, "Could not set NDisc address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
if (link->ndisc_messages == 0) {
|
||||
link->ndisc_configured = true;
|
||||
if (link->ndisc_addresses_messages == 0) {
|
||||
log_link_debug(link, "NDisc SLAAC addresses set.");
|
||||
link->ndisc_addresses_configured = true;
|
||||
r = link_request_set_routes(link);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -223,14 +219,14 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
|||
route->lifetime = time_now + lifetime * USEC_PER_SEC;
|
||||
route->mtu = mtu;
|
||||
|
||||
r = route_configure(route, link, ndisc_netlink_route_message_handler);
|
||||
r = route_configure(route, link, ndisc_route_handler);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set default route: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
if (r > 0)
|
||||
link->ndisc_messages++;
|
||||
link->ndisc_routes_messages++;
|
||||
|
||||
Route *route_gw;
|
||||
LIST_FOREACH(routes, route_gw, link->network->static_routes) {
|
||||
|
@ -242,14 +238,14 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
|||
|
||||
route_gw->gw = gateway;
|
||||
|
||||
r = route_configure(route_gw, link, ndisc_netlink_route_message_handler);
|
||||
r = route_configure(route_gw, link, ndisc_route_handler);
|
||||
if (r < 0) {
|
||||
log_link_error_errno(link, r, "Could not set gateway: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
if (r > 0)
|
||||
link->ndisc_messages++;
|
||||
link->ndisc_routes_messages++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -404,20 +400,19 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
|||
} else if (lifetime_valid > 0)
|
||||
a->cinfo.ifa_valid = lifetime_valid;
|
||||
else
|
||||
return 0; /* see RFC4862 section 5.5.3.d */
|
||||
continue; /* see RFC4862 section 5.5.3.d */
|
||||
|
||||
if (a->cinfo.ifa_valid == 0)
|
||||
continue;
|
||||
|
||||
r = address_configure(a, link, ndisc_netlink_address_message_handler, true);
|
||||
r = address_configure(a, link, ndisc_address_handler, true);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r > 0)
|
||||
link->ndisc_messages++;
|
||||
link->ndisc_addresses_messages++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -461,14 +456,14 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
|
|||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||
|
||||
r = route_configure(route, link, ndisc_netlink_route_message_handler);
|
||||
r = route_configure(route, link, ndisc_route_handler);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set prefix route: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
if (r > 0)
|
||||
link->ndisc_messages++;
|
||||
link->ndisc_routes_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -523,14 +518,14 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
|
|||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get route address: %m");
|
||||
|
||||
r = route_configure(route, link, ndisc_netlink_route_message_handler);
|
||||
r = route_configure(route, link, ndisc_route_handler);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set additional route: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
if (r > 0)
|
||||
link->ndisc_messages++;
|
||||
link->ndisc_routes_messages++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -816,11 +811,38 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r
|
|||
switch (event) {
|
||||
|
||||
case SD_NDISC_EVENT_ROUTER:
|
||||
link->ndisc_addresses_configured = false;
|
||||
link->ndisc_routes_configured = false;
|
||||
|
||||
(void) ndisc_router_handler(link, rt);
|
||||
|
||||
if (link->ndisc_addresses_messages == 0)
|
||||
link->ndisc_addresses_configured = true;
|
||||
else {
|
||||
log_link_debug(link, "Setting SLAAC addresses.");
|
||||
|
||||
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
|
||||
* Before they are called, the related flags must be cleared. Otherwise, the link
|
||||
* becomes configured state before routes are configured. */
|
||||
link->static_routes_configured = false;
|
||||
link->static_nexthops_configured = false;
|
||||
}
|
||||
|
||||
if (link->ndisc_routes_messages == 0)
|
||||
link->ndisc_routes_configured = true;
|
||||
else
|
||||
log_link_debug(link, "Setting NDisc routes.");
|
||||
|
||||
if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
|
||||
link_check_ready(link);
|
||||
else
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
break;
|
||||
|
||||
case SD_NDISC_EVENT_TIMEOUT:
|
||||
link->ndisc_configured = true;
|
||||
log_link_debug(link, "NDISC handler get timeout event");
|
||||
link->ndisc_addresses_configured = true;
|
||||
link->ndisc_routes_configured = true;
|
||||
link_check_ready(link);
|
||||
|
||||
break;
|
||||
|
|
|
@ -4636,7 +4636,7 @@ static int run_container(
|
|||
if (!barrier_place_and_sync(&barrier)) /* #5 */
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early.");
|
||||
|
||||
/* At this point we have made use of the UID we picked, and thus nss-mymachines
|
||||
/* At this point we have made use of the UID we picked, and thus nss-systemd/systemd-machined.service
|
||||
* will make them appear in getpwuid(), thus we can release the /etc/passwd lock. */
|
||||
etc_passwd_lock = safe_close(etc_passwd_lock);
|
||||
|
||||
|
|
|
@ -19,15 +19,11 @@
|
|||
#include "nss-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
|
||||
NSS_GETPW_PROTOTYPES(mymachines);
|
||||
NSS_GETGR_PROTOTYPES(mymachines);
|
||||
|
||||
#define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
|
||||
#define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
|
||||
|
||||
static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
|
||||
unsigned c = 0;
|
||||
int r;
|
||||
|
@ -402,94 +398,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
|
|||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
const char *p, *e, *machine;
|
||||
uint32_t mapped;
|
||||
uid_t uid;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
||||
assert(name);
|
||||
assert(pwd);
|
||||
|
||||
p = startswith(name, "vu-");
|
||||
if (!p)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
e = strrchr(p, '-');
|
||||
if (!e || e == p)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
r = parse_uid(e + 1, &uid);
|
||||
if (r < 0)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
machine = strndupa(p, e - p);
|
||||
if (!machine_name_is_valid(machine))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
|
||||
/* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
|
||||
* these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
|
||||
* running on the host. */
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_call_method(bus, bus_machine_mgr, "MapFromMachineUser", &error, &reply, "su", machine, (uint32_t) uid);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &mapped);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
|
||||
if (mapped < HOST_UID_LIMIT || mapped == uid)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
l = strlen(name);
|
||||
if (buflen < l+1) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
memcpy(buffer, name, l+1);
|
||||
|
||||
pwd->pw_name = buffer;
|
||||
pwd->pw_uid = mapped;
|
||||
pwd->pw_gid = GID_NOBODY;
|
||||
pwd->pw_gecos = buffer;
|
||||
pwd->pw_passwd = (char*) "*"; /* locked */
|
||||
pwd->pw_dir = (char*) "/";
|
||||
pwd->pw_shell = (char*) NOLOGIN;
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
enum nss_status _nss_mymachines_getpwuid_r(
|
||||
|
@ -498,162 +407,16 @@ enum nss_status _nss_mymachines_getpwuid_r(
|
|||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
const char *machine;
|
||||
uint32_t mapped;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
||||
if (!uid_is_valid(uid))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* We consider all uids < 65536 host uids */
|
||||
if (uid < HOST_UID_LIMIT)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_call_method(bus, bus_machine_mgr, "MapToMachineUser", &error, &reply, "u", (uint32_t) uid);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (mapped == uid)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
pwd->pw_name = buffer;
|
||||
pwd->pw_uid = uid;
|
||||
pwd->pw_gid = GID_NOBODY;
|
||||
pwd->pw_gecos = buffer;
|
||||
pwd->pw_passwd = (char*) "*"; /* locked */
|
||||
pwd->pw_dir = (char*) "/";
|
||||
pwd->pw_shell = (char*) NOLOGIN;
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
|
||||
|
||||
enum nss_status _nss_mymachines_getgrnam_r(
|
||||
const char *name,
|
||||
struct group *gr,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
const char *p, *e, *machine;
|
||||
uint32_t mapped;
|
||||
uid_t gid;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
||||
assert(name);
|
||||
assert(gr);
|
||||
|
||||
p = startswith(name, "vg-");
|
||||
if (!p)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
e = strrchr(p, '-');
|
||||
if (!e || e == p)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
r = parse_gid(e + 1, &gid);
|
||||
if (r < 0)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
machine = strndupa(p, e - p);
|
||||
if (!machine_name_is_valid(machine))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_call_method(bus, bus_machine_mgr, "MapFromMachineGroup", &error, &reply, "su", machine, (uint32_t) gid);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &mapped);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (mapped < HOST_GID_LIMIT || mapped == gid)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
l = sizeof(char*) + strlen(name) + 1;
|
||||
if (buflen < l) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
memzero(buffer, sizeof(char*));
|
||||
strcpy(buffer + sizeof(char*), name);
|
||||
|
||||
gr->gr_name = buffer + sizeof(char*);
|
||||
gr->gr_gid = mapped;
|
||||
gr->gr_passwd = (char*) "*"; /* locked */
|
||||
gr->gr_mem = (char**) buffer;
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
enum nss_status _nss_mymachines_getgrgid_r(
|
||||
|
@ -662,72 +425,5 @@ enum nss_status _nss_mymachines_getgrgid_r(
|
|||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
const char *machine;
|
||||
uint32_t mapped;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
||||
if (!gid_is_valid(gid))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* We consider all gids < 65536 host gids */
|
||||
if (gid < HOST_GID_LIMIT)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_call_method(bus, bus_machine_mgr, "MapToMachineGroup", &error, &reply, "u", (uint32_t) gid);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (mapped == gid)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (buflen < sizeof(char*) + 1) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
memzero(buffer, sizeof(char*));
|
||||
if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
gr->gr_name = buffer + sizeof(char*);
|
||||
gr->gr_gid = gid;
|
||||
gr->gr_passwd = (char*) "*"; /* locked */
|
||||
gr->gr_mem = (char**) buffer;
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
|
||||
static int print_catalog(FILE *f, sd_journal *j) {
|
||||
_cleanup_free_ char *t = NULL, *z = NULL;
|
||||
const char *newline, *prefix;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
@ -60,12 +61,30 @@ static int print_catalog(FILE *f, sd_journal *j) {
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find catalog entry: %m");
|
||||
|
||||
z = strreplace(strstrip(t), "\n", "\n-- ");
|
||||
if (is_locale_utf8())
|
||||
prefix = strjoina(special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), special_glyph(SPECIAL_GLYPH_LIGHT_SHADE));
|
||||
else
|
||||
prefix = "--";
|
||||
|
||||
if (colors_enabled())
|
||||
newline = strjoina(ANSI_NORMAL "\n" ANSI_GREY, prefix, ANSI_NORMAL " " ANSI_GREEN);
|
||||
else
|
||||
newline = strjoina("\n", prefix, " ");
|
||||
|
||||
z = strreplace(strstrip(t), "\n", newline);
|
||||
if (!z)
|
||||
return log_oom();
|
||||
|
||||
fputs("-- ", f);
|
||||
if (colors_enabled())
|
||||
fprintf(f, ANSI_GREY "%s" ANSI_NORMAL " " ANSI_GREEN, prefix);
|
||||
else
|
||||
fprintf(f, "%s ", prefix);
|
||||
|
||||
fputs(z, f);
|
||||
|
||||
if (colors_enabled())
|
||||
fputs(ANSI_NORMAL "\n", f);
|
||||
else
|
||||
fputc('\n', f);
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -156,6 +156,8 @@ static int userdb_on_query_reply(
|
|||
r = -ESRCH;
|
||||
else if (streq(error_id, "io.systemd.UserDatabase.ServiceNotAvailable"))
|
||||
r = -EHOSTDOWN;
|
||||
else if (streq(error_id, "io.systemd.UserDatabase.EnumerationNotSupported"))
|
||||
r = -EOPNOTSUPP;
|
||||
else if (streq(error_id, VARLINK_ERROR_TIMEOUT))
|
||||
r = -ETIMEDOUT;
|
||||
else
|
||||
|
|
|
@ -858,7 +858,7 @@ static void test_path_is_encrypted_one(const char *p, int expect) {
|
|||
return;
|
||||
assert_se(r >= 0);
|
||||
|
||||
printf("%s encrypted: %s\n", p, yes_no(r));
|
||||
log_info("%s encrypted: %s", p, yes_no(r));
|
||||
|
||||
assert_se(expect < 0 || ((r > 0) == (expect > 0)));
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../TEST-01-BASIC/Makefile
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
TEST_DESCRIPTION="test timer units when initial clock is ahead"
|
||||
TEST_NO_NSPAWN=1
|
||||
|
||||
future_date=$(date -u +%Y-%m-%dT%H:%M:%S -d '+3 days')
|
||||
QEMU_OPTIONS="-rtc base=${future_date}"
|
||||
. $TEST_BASE_DIR/test-functions
|
||||
|
||||
do_test "$@" 53
|
|
@ -376,7 +376,7 @@ DHCP={}
|
|||
# IPv6, but we want to wait for both
|
||||
for _ in range(10):
|
||||
out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.iface])
|
||||
if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out:
|
||||
if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out and b'tentative' not in out:
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
[Match]
|
||||
Name=bond199
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=veth-peer
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
EmitLLDP=yes
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
KeepConfiguration=static
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=veth99
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
LLDP=yes
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=192.168.42.100/24
|
||||
DNS=192.168.42.1
|
||||
Domains= one two three four five six seven eight nine ten
|
||||
|
|
|
@ -3,3 +3,6 @@ Name=dummy98
|
|||
|
||||
[Link]
|
||||
MACAddress=00:01:02:aa:bb:cc
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
# these lines are ignored
|
||||
Address=hogehoge
|
||||
Address=foofoo
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[RoutingPolicyRule]
|
||||
TypeOfService=0x08
|
||||
Table=7
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[RoutingPolicyRule]
|
||||
TypeOfService=0x08
|
||||
Table=7
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[RoutingPolicyRule]
|
||||
TypeOfService=0x08
|
||||
Table=7
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=149.10.124.58/28
|
||||
Gateway=149.10.124.60
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Address=149.10.124.58/28
|
||||
Gateway=149.10.124.59
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[IPv6AddressLabel]
|
||||
Label=4444
|
||||
Prefix=2004:da8:1:0::/64
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
VRF=vrf99
|
||||
Address=192.168.100.2/24
|
||||
Gateway=192.168.100.1
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
[Match]
|
||||
Name=vrf99
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=sittun99
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=erspan99
|
||||
Tunnel=erspan98
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=gretap99
|
||||
Tunnel=gretap98
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=gretun99
|
||||
Tunnel=gretun98
|
||||
Tunnel=gretun97
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=ip6gretap99
|
||||
Tunnel=ip6gretap98
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=ip6gretun99
|
||||
Tunnel=ip6gretun98
|
||||
Tunnel=ip6gretun97
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=ip6tnl99
|
||||
Tunnel=ip6tnl98
|
||||
Tunnel=ip6tnl97
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=ipiptun99
|
||||
Tunnel=ipiptun98
|
||||
Tunnel=ipiptun97
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
IPVLAN=ipvlan99
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
IPVTAP=ipvtap99
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=isataptun99
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
MACVLAN=macvlan99
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
MACVTAP=macvtap99
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[RoutingPolicyRule]
|
||||
TypeOfService=0x08
|
||||
Table=8
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[RoutingPolicyRule]
|
||||
TypeOfService=0x08
|
||||
Table=7
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=sittun99
|
||||
Tunnel=sittun98
|
||||
Tunnel=sittun97
|
||||
|
|
|
@ -5,6 +5,7 @@ Name=dummy98
|
|||
RequiredForOnline=routable
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
DNS=10.10.10.10 10.10.10.11
|
||||
NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org
|
||||
Domains=hogehoge ~foofoo
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=vtitun99
|
||||
Tunnel=vtitun98
|
||||
Tunnel=vtitun97
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
Tunnel=vti6tun99
|
||||
Tunnel=vti6tun98
|
||||
Tunnel=vti6tun97
|
||||
|
|
|
@ -557,7 +557,7 @@ class Utilities():
|
|||
if i > 0:
|
||||
time.sleep(1)
|
||||
output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
|
||||
if re.search(address_regex, output):
|
||||
if re.search(address_regex, output) and 'tentative' not in output:
|
||||
break
|
||||
else:
|
||||
self.assertRegex(output, address_regex)
|
||||
|
@ -3168,6 +3168,12 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||
self.assertRegex(output, '2600::')
|
||||
self.assertNotRegex(output, '192.168.5')
|
||||
|
||||
output = check_output('ip addr show dev veth99')
|
||||
print(output)
|
||||
self.assertRegex(output, '2600::')
|
||||
self.assertNotRegex(output, '192.168.5')
|
||||
self.assertNotRegex(output, 'tentative')
|
||||
|
||||
# Confirm that ipv6 token is not set in the kernel
|
||||
output = check_output('ip token show dev veth99')
|
||||
print(output)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=TEST-53-ISSUE-16347
|
||||
|
||||
[Service]
|
||||
ExecStartPre=rm -f /failed /testok
|
||||
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
|
||||
Type=oneshot
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
>/failed
|
||||
|
||||
# Reset host date to current time, 3 days in the past.
|
||||
date -s "-3 days"
|
||||
|
||||
# Run a timer for every 15 minutes.
|
||||
systemd-run --unit test-timer --on-calendar "*:0/15:0" true
|
||||
|
||||
next_elapsed=$(systemctl show test-timer.timer -p NextElapseUSecRealtime --value)
|
||||
next_elapsed=$(date -d "${next_elapsed}" +%s)
|
||||
now=$(date +%s)
|
||||
time_delta=$((next_elapsed - now))
|
||||
|
||||
# Check that the timer will elapse in less than 20 minutes.
|
||||
((0 < time_delta && time_delta < 1200)) || {
|
||||
echo 'Timer elapse outside of the expected 20 minute window.'
|
||||
echo " next_elapsed=${next_elapsed}"
|
||||
echo " now=${now}"
|
||||
echo " time_delta=${time_delta}"
|
||||
echo ''
|
||||
} >>/failed
|
||||
|
||||
if test ! -s /failed ; then
|
||||
rm -f /failed
|
||||
touch /testok
|
||||
fi
|
Loading…
Reference in New Issue