]>
Commit | Line | Data |
---|---|---|
52661efd LP |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
f23c09b0 | 6 | Copyright 2010 Lennart Poettering |
52661efd LP |
7 | |
8 | systemd is free software; you can redistribute it and/or modify it | |
5430f7f2 LP |
9 | under the terms of the GNU Lesser General Public License as published by |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
52661efd LP |
11 | (at your option) any later version. |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
5430f7f2 | 16 | Lesser General Public License for more details. |
52661efd | 17 | |
5430f7f2 | 18 | You should have received a copy of the GNU Lesser General Public License |
52661efd LP |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | |
21 | ||
22 | #include <stdlib.h> | |
23 | #include <errno.h> | |
24 | #include <string.h> | |
25 | #include <unistd.h> | |
62590f23 | 26 | #include <sys/capability.h> |
d0516109 | 27 | #include <sys/statvfs.h> |
c0d6e764 | 28 | #include <fnmatch.h> |
52661efd | 29 | |
c0d6e764 | 30 | #include <systemd/sd-id128.h> |
52661efd LP |
31 | #include "util.h" |
32 | #include "condition.h" | |
8095200d | 33 | #include "virt.h" |
9eb977db | 34 | #include "path-util.h" |
a5c32cff | 35 | #include "fileio.h" |
4b744dfa | 36 | #include "unit.h" |
d682b3a7 LP |
37 | #include "smack-util.h" |
38 | #include "apparmor-util.h" | |
39 | #include "ima-util.h" | |
40 | #include "selinux-util.h" | |
52661efd | 41 | |
afc50ea8 TG |
42 | static bool condition_test_security(Condition *c) { |
43 | assert(c); | |
44 | assert(c->parameter); | |
45 | assert(c->type == CONDITION_SECURITY); | |
46 | ||
47 | if (streq(c->parameter, "selinux")) | |
48 | return use_selinux() == !c->negate; | |
49 | if (streq(c->parameter, "apparmor")) | |
50 | return use_apparmor() == !c->negate; | |
51 | if (streq(c->parameter, "ima")) | |
52 | return use_ima() == !c->negate; | |
53 | if (streq(c->parameter, "smack")) | |
54 | return use_smack() == !c->negate; | |
55 | return c->negate; | |
07e833bc MS |
56 | } |
57 | ||
afc50ea8 | 58 | static bool condition_test_capability(Condition *c) { |
62590f23 LP |
59 | cap_value_t value; |
60 | FILE *f; | |
61 | char line[LINE_MAX]; | |
62 | unsigned long long capabilities = (unsigned long long) -1; | |
63 | ||
afc50ea8 TG |
64 | assert(c); |
65 | assert(c->parameter); | |
66 | assert(c->type == CONDITION_CAPABILITY); | |
67 | ||
62590f23 LP |
68 | /* If it's an invalid capability, we don't have it */ |
69 | ||
afc50ea8 TG |
70 | if (cap_from_name(c->parameter, &value) < 0) |
71 | return c->negate; | |
62590f23 LP |
72 | |
73 | /* If it's a valid capability we default to assume | |
74 | * that we have it */ | |
75 | ||
76 | f = fopen("/proc/self/status", "re"); | |
77 | if (!f) | |
afc50ea8 | 78 | return !c->negate; |
62590f23 LP |
79 | |
80 | while (fgets(line, sizeof(line), f)) { | |
81 | truncate_nl(line); | |
82 | ||
83 | if (startswith(line, "CapBnd:")) { | |
84 | (void) sscanf(line+7, "%llx", &capabilities); | |
85 | break; | |
86 | } | |
87 | } | |
88 | ||
7670e5a2 TJ |
89 | fclose(f); |
90 | ||
afc50ea8 | 91 | return !!(capabilities & (1ULL << value)) == !c->negate; |
62590f23 LP |
92 | } |
93 | ||
52990c2e | 94 | static bool condition_test(Condition *c) { |
52661efd LP |
95 | assert(c); |
96 | ||
97 | switch(c->type) { | |
98 | ||
99 | case CONDITION_PATH_EXISTS: | |
100 | return (access(c->parameter, F_OK) >= 0) == !c->negate; | |
101 | ||
8092a428 LP |
102 | case CONDITION_PATH_EXISTS_GLOB: |
103 | return (glob_exists(c->parameter) > 0) == !c->negate; | |
104 | ||
2b583ce6 KS |
105 | case CONDITION_PATH_IS_DIRECTORY: { |
106 | struct stat st; | |
107 | ||
8571962c | 108 | if (stat(c->parameter, &st) < 0) |
1f8fef5a | 109 | return c->negate; |
2b583ce6 KS |
110 | return S_ISDIR(st.st_mode) == !c->negate; |
111 | } | |
112 | ||
0d60602c MS |
113 | case CONDITION_PATH_IS_SYMBOLIC_LINK: { |
114 | struct stat st; | |
115 | ||
116 | if (lstat(c->parameter, &st) < 0) | |
1f8fef5a | 117 | return c->negate; |
0d60602c MS |
118 | return S_ISLNK(st.st_mode) == !c->negate; |
119 | } | |
120 | ||
ab7f148f LP |
121 | case CONDITION_PATH_IS_MOUNT_POINT: |
122 | return (path_is_mount_point(c->parameter, true) > 0) == !c->negate; | |
123 | ||
3d9a4122 LP |
124 | case CONDITION_PATH_IS_READ_WRITE: |
125 | return (path_is_read_only_fs(c->parameter) > 0) == c->negate; | |
d0516109 | 126 | |
36af55d9 LP |
127 | case CONDITION_DIRECTORY_NOT_EMPTY: { |
128 | int k; | |
129 | ||
130 | k = dir_is_empty(c->parameter); | |
131 | return !(k == -ENOENT || k > 0) == !c->negate; | |
132 | } | |
133 | ||
742a862b LP |
134 | case CONDITION_FILE_NOT_EMPTY: { |
135 | struct stat st; | |
136 | ||
137 | if (stat(c->parameter, &st) < 0) | |
138 | return c->negate; | |
139 | ||
140 | return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate; | |
141 | } | |
142 | ||
82e487c5 LP |
143 | case CONDITION_FILE_IS_EXECUTABLE: { |
144 | struct stat st; | |
145 | ||
34a2dc4b | 146 | if (stat(c->parameter, &st) < 0) |
1f8fef5a | 147 | return c->negate; |
82e487c5 LP |
148 | |
149 | return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate; | |
150 | } | |
151 | ||
52661efd | 152 | case CONDITION_KERNEL_COMMAND_LINE: |
afc50ea8 | 153 | return condition_test_kernel_command_line(c); |
52661efd | 154 | |
039655a4 | 155 | case CONDITION_VIRTUALIZATION: |
afc50ea8 | 156 | return condition_test_virtualization(c); |
039655a4 | 157 | |
07e833bc | 158 | case CONDITION_SECURITY: |
afc50ea8 | 159 | return condition_test_security(c); |
07e833bc | 160 | |
62590f23 | 161 | case CONDITION_CAPABILITY: |
afc50ea8 | 162 | return condition_test_capability(c); |
62590f23 | 163 | |
c0d6e764 | 164 | case CONDITION_HOST: |
afc50ea8 | 165 | return condition_test_host(c); |
c0d6e764 | 166 | |
240dbaa4 | 167 | case CONDITION_AC_POWER: |
afc50ea8 | 168 | return condition_test_ac_power(c); |
240dbaa4 | 169 | |
099524d7 LP |
170 | case CONDITION_ARCHITECTURE: |
171 | return condition_test_architecture(c); | |
172 | ||
d257ddef LP |
173 | case CONDITION_NULL: |
174 | return !c->negate; | |
175 | ||
52661efd LP |
176 | default: |
177 | assert_not_reached("Invalid condition type."); | |
178 | } | |
179 | } | |
180 | ||
4b744dfa | 181 | bool condition_test_list(const char *unit, Condition *first) { |
52661efd | 182 | Condition *c; |
267632f0 | 183 | int triggered = -1; |
52661efd LP |
184 | |
185 | /* If the condition list is empty, then it is true */ | |
186 | if (!first) | |
187 | return true; | |
188 | ||
267632f0 LP |
189 | /* Otherwise, if all of the non-trigger conditions apply and |
190 | * if any of the trigger conditions apply (unless there are | |
191 | * none) we return true */ | |
192 | LIST_FOREACH(conditions, c, first) { | |
193 | bool b; | |
194 | ||
195 | b = condition_test(c); | |
4b744dfa ZJS |
196 | if (unit) |
197 | log_debug_unit(unit, | |
198 | "%s=%s%s%s %s for %s.", | |
199 | condition_type_to_string(c->type), | |
200 | c->trigger ? "|" : "", | |
201 | c->negate ? "!" : "", | |
202 | c->parameter, | |
203 | b ? "succeeded" : "failed", | |
204 | unit); | |
52990c2e | 205 | c->state = b ? 1 : -1; |
267632f0 LP |
206 | |
207 | if (!c->trigger && !b) | |
208 | return false; | |
209 | ||
210 | if (c->trigger && triggered <= 0) | |
211 | triggered = b; | |
212 | } | |
52661efd | 213 | |
267632f0 | 214 | return triggered != 0; |
52661efd | 215 | } |