1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "bus-polkit.h"
4 #include "bus-util.h"
5 #include "dbus-util.h"
6 #include "escape.h"
7 #include "parse-util.h"
8 #include "path-util.h"
9 #include "unit-printf.h"
10 #include "user-util.h"
11 #include "unit.h"
12 
bus_property_get_triggered_unit(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)13 int bus_property_get_triggered_unit(
14                 sd_bus *bus,
15                 const char *path,
16                 const char *interface,
17                 const char *property,
18                 sd_bus_message *reply,
19                 void *userdata,
20                 sd_bus_error *error) {
21 
22         Unit *u = userdata, *trigger;
23 
24         assert(bus);
25         assert(reply);
26         assert(u);
27 
28         trigger = UNIT_TRIGGER(u);
29 
30         return sd_bus_message_append(reply, "s", trigger ? trigger->id : NULL);
31 }
32 
33 BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
34 BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
35 
valid_user_group_name_or_id_relaxed(const char * u)36 static inline bool valid_user_group_name_or_id_relaxed(const char *u) {
37         return valid_user_group_name(u, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX);
38 }
39 
40 BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed);
41 BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
42 
bus_set_transient_string(Unit * u,const char * name,char ** p,sd_bus_message * message,UnitWriteFlags flags,sd_bus_error * error)43 int bus_set_transient_string(
44                 Unit *u,
45                 const char *name,
46                 char **p,
47                 sd_bus_message *message,
48                 UnitWriteFlags flags,
49                 sd_bus_error *error) {
50 
51         const char *v;
52         int r;
53 
54         assert(p);
55 
56         r = sd_bus_message_read(message, "s", &v);
57         if (r < 0)
58                 return r;
59 
60         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
61                 r = free_and_strdup(p, empty_to_null(v));
62                 if (r < 0)
63                         return r;
64 
65                 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
66                                     "%s=%s", name, strempty(v));
67         }
68 
69         return 1;
70 }
71 
bus_set_transient_bool(Unit * u,const char * name,bool * p,sd_bus_message * message,UnitWriteFlags flags,sd_bus_error * error)72 int bus_set_transient_bool(
73                 Unit *u,
74                 const char *name,
75                 bool *p,
76                 sd_bus_message *message,
77                 UnitWriteFlags flags,
78                 sd_bus_error *error) {
79 
80         int v, r;
81 
82         assert(p);
83 
84         r = sd_bus_message_read(message, "b", &v);
85         if (r < 0)
86                 return r;
87 
88         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
89                 *p = v;
90                 unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(v));
91         }
92 
93         return 1;
94 }
95 
bus_set_transient_usec_internal(Unit * u,const char * name,usec_t * p,bool fix_0,sd_bus_message * message,UnitWriteFlags flags,sd_bus_error * error)96 int bus_set_transient_usec_internal(
97                 Unit *u,
98                 const char *name,
99                 usec_t *p,
100                 bool fix_0,
101                 sd_bus_message *message,
102                 UnitWriteFlags flags,
103                 sd_bus_error *error) {
104 
105         uint64_t v;
106         int r;
107 
108         assert(p);
109 
110         r = sd_bus_message_read(message, "t", &v);
111         if (r < 0)
112                 return r;
113 
114         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
115                 if (fix_0)
116                         *p = v != 0 ? v: USEC_INFINITY;
117                 else
118                         *p = v;
119 
120                 char *n = strndupa_safe(name, strlen(name) - 4);
121                 unit_write_settingf(u, flags, name, "%sSec=%s", n, FORMAT_TIMESPAN(v, USEC_PER_MSEC));
122         }
123 
124         return 1;
125 }
126 
bus_verify_manage_units_async_full(Unit * u,const char * verb,int capability,const char * polkit_message,bool interactive,sd_bus_message * call,sd_bus_error * error)127 int bus_verify_manage_units_async_full(
128                 Unit *u,
129                 const char *verb,
130                 int capability,
131                 const char *polkit_message,
132                 bool interactive,
133                 sd_bus_message *call,
134                 sd_bus_error *error) {
135 
136         const char *details[9] = {
137                 "unit", u->id,
138                 "verb", verb,
139         };
140 
141         if (polkit_message) {
142                 details[4] = "polkit.message";
143                 details[5] = polkit_message;
144                 details[6] = "polkit.gettext_domain";
145                 details[7] = GETTEXT_PACKAGE;
146         }
147 
148         return bus_verify_polkit_async(
149                         call,
150                         capability,
151                         "org.freedesktop.systemd1.manage-units",
152                         details,
153                         interactive,
154                         UID_INVALID,
155                         &u->manager->polkit_registry,
156                         error);
157 }
158 
159 /* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */
bus_read_mount_options(sd_bus_message * message,sd_bus_error * error,MountOptions ** ret_options,char ** ret_format_str,const char * separator)160 int bus_read_mount_options(
161                 sd_bus_message *message,
162                 sd_bus_error *error,
163                 MountOptions **ret_options,
164                 char **ret_format_str,
165                 const char *separator) {
166 
167         _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
168         _cleanup_free_ char *format_str = NULL;
169         const char *mount_options, *partition;
170         int r;
171 
172         assert(message);
173         assert(ret_options);
174         assert(separator);
175 
176         r = sd_bus_message_enter_container(message, 'a', "(ss)");
177         if (r < 0)
178                 return r;
179 
180         while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
181                 _cleanup_free_ char *escaped = NULL;
182                 _cleanup_free_ MountOptions *o = NULL;
183                 PartitionDesignator partition_designator;
184 
185                 if (chars_intersect(mount_options, WHITESPACE))
186                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
187                                                 "Invalid mount options string, contains whitespace character(s): %s", mount_options);
188 
189                 partition_designator = partition_designator_from_string(partition);
190                 if (partition_designator < 0)
191                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
192 
193                 /* Need to store the options with the escapes, so that they can be parsed again */
194                 escaped = shell_escape(mount_options, ":");
195                 if (!escaped)
196                         return -ENOMEM;
197 
198                 if (!strextend_with_separator(&format_str, separator, partition, ":", escaped))
199                         return -ENOMEM;
200 
201                 o = new(MountOptions, 1);
202                 if (!o)
203                         return -ENOMEM;
204                 *o = (MountOptions) {
205                         .partition_designator = partition_designator,
206                         .options = strdup(mount_options),
207                 };
208                 if (!o->options)
209                         return -ENOMEM;
210                 LIST_APPEND(mount_options, options, TAKE_PTR(o));
211         }
212         if (r < 0)
213                 return r;
214 
215         r = sd_bus_message_exit_container(message);
216         if (r < 0)
217                 return r;
218 
219         if (!LIST_IS_EMPTY(options)) {
220                 if (ret_format_str) {
221                         char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str);
222                         if (!final)
223                                 return -ENOMEM;
224                         free_and_replace(*ret_format_str, final);
225                 }
226                 LIST_JOIN(mount_options, *ret_options, options);
227         }
228 
229         return 0;
230 }
231