chiark / gitweb /
Introduce cleanup functions for cap_free
[elogind.git] / src / core / dbus-execute.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
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
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
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/prctl.h>
23
24 #include "bus-util.h"
25 #include "missing.h"
26 #include "ioprio.h"
27 #include "strv.h"
28 #include "syscall-list.h"
29 #include "fileio.h"
30 #include "execute.h"
31 #include "dbus-execute.h"
32 #include "capability.h"
33
34 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
35
36 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
37
38 static int property_get_environment_files(
39                 sd_bus *bus,
40                 const char *path,
41                 const char *interface,
42                 const char *property,
43                 sd_bus_message *reply,
44                 void *userdata,
45                 sd_bus_error *error) {
46
47         ExecContext *c = userdata;
48         char **j;
49         int r;
50
51         assert(bus);
52         assert(reply);
53         assert(c);
54
55         r = sd_bus_message_open_container(reply, 'a', "(sb)");
56         if (r < 0)
57                 return r;
58
59         STRV_FOREACH(j, c->environment_files) {
60                 const char *fn = *j;
61
62                 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
63                 if (r < 0)
64                         return r;
65         }
66
67         return sd_bus_message_close_container(reply);
68 }
69
70 static int property_get_rlimit(
71                 sd_bus *bus,
72                 const char *path,
73                 const char *interface,
74                 const char *property,
75                 sd_bus_message *reply,
76                 void *userdata,
77                 sd_bus_error *error) {
78
79         struct rlimit *rl;
80         uint64_t u;
81
82         assert(bus);
83         assert(reply);
84         assert(userdata);
85
86         rl = *(struct rlimit**) userdata;
87         if (rl)
88                 u = (uint64_t) rl->rlim_max;
89         else {
90                 struct rlimit buf = {};
91                 int z;
92
93                 z = rlimit_from_string(property);
94                 assert(z >= 0);
95
96                 getrlimit(z, &buf);
97
98                 u = (uint64_t) buf.rlim_max;
99         }
100
101         return sd_bus_message_append(reply, "t", u);
102 }
103
104 static int property_get_oom_score_adjust(
105                 sd_bus *bus,
106                 const char *path,
107                 const char *interface,
108                 const char *property,
109                 sd_bus_message *reply,
110                 void *userdata,
111                 sd_bus_error *error) {
112
113
114         ExecContext *c = userdata;
115         int32_t n;
116
117         assert(bus);
118         assert(reply);
119         assert(c);
120
121         if (c->oom_score_adjust_set)
122                 n = c->oom_score_adjust;
123         else {
124                 _cleanup_free_ char *t = NULL;
125
126                 n = 0;
127                 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
128                         safe_atoi(t, &n);
129         }
130
131         return sd_bus_message_append(reply, "i", n);
132 }
133
134 static int property_get_nice(
135                 sd_bus *bus,
136                 const char *path,
137                 const char *interface,
138                 const char *property,
139                 sd_bus_message *reply,
140                 void *userdata,
141                 sd_bus_error *error) {
142
143
144         ExecContext *c = userdata;
145         int32_t n;
146
147         assert(bus);
148         assert(reply);
149         assert(c);
150
151         if (c->nice_set)
152                 n = c->nice;
153         else {
154                 errno = 0;
155                 n = getpriority(PRIO_PROCESS, 0);
156                 if (errno != 0)
157                         n = 0;
158         }
159
160         return sd_bus_message_append(reply, "i", n);
161 }
162
163 static int property_get_ioprio(
164                 sd_bus *bus,
165                 const char *path,
166                 const char *interface,
167                 const char *property,
168                 sd_bus_message *reply,
169                 void *userdata,
170                 sd_bus_error *error) {
171
172
173         ExecContext *c = userdata;
174         int32_t n;
175
176         assert(bus);
177         assert(reply);
178         assert(c);
179
180         if (c->ioprio_set)
181                 n = c->ioprio;
182         else {
183                 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
184                 if (n < 0)
185                         n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
186         }
187
188         return sd_bus_message_append(reply, "i", n);
189 }
190
191 static int property_get_cpu_sched_policy(
192                 sd_bus *bus,
193                 const char *path,
194                 const char *interface,
195                 const char *property,
196                 sd_bus_message *reply,
197                 void *userdata,
198                 sd_bus_error *error) {
199
200         ExecContext *c = userdata;
201         int32_t n;
202
203         assert(bus);
204         assert(reply);
205         assert(c);
206
207         if (c->cpu_sched_set)
208                 n = c->cpu_sched_policy;
209         else {
210                 n = sched_getscheduler(0);
211                 if (n < 0)
212                         n = SCHED_OTHER;
213         }
214
215         return sd_bus_message_append(reply, "i", n);
216 }
217
218 static int property_get_cpu_sched_priority(
219                 sd_bus *bus,
220                 const char *path,
221                 const char *interface,
222                 const char *property,
223                 sd_bus_message *reply,
224                 void *userdata,
225                 sd_bus_error *error) {
226
227         ExecContext *c = userdata;
228         int32_t n;
229
230         assert(bus);
231         assert(reply);
232         assert(c);
233
234         if (c->cpu_sched_set)
235                 n = c->cpu_sched_priority;
236         else {
237                 struct sched_param p = {};
238
239                 if (sched_getparam(0, &p) >= 0)
240                         n = p.sched_priority;
241                 else
242                         n = 0;
243         }
244
245         return sd_bus_message_append(reply, "i", n);
246 }
247
248 static int property_get_cpu_affinity(
249                 sd_bus *bus,
250                 const char *path,
251                 const char *interface,
252                 const char *property,
253                 sd_bus_message *reply,
254                 void *userdata,
255                 sd_bus_error *error) {
256
257         ExecContext *c = userdata;
258
259         assert(bus);
260         assert(reply);
261         assert(c);
262
263         if (c->cpuset)
264                 return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
265         else
266                 return sd_bus_message_append_array(reply, 'y', NULL, 0);
267 }
268
269 static int property_get_timer_slack_nsec(
270                 sd_bus *bus,
271                 const char *path,
272                 const char *interface,
273                 const char *property,
274                 sd_bus_message *reply,
275                 void *userdata,
276                 sd_bus_error *error) {
277
278         ExecContext *c = userdata;
279         uint64_t u;
280
281         assert(bus);
282         assert(reply);
283         assert(c);
284
285         if (c->timer_slack_nsec != (nsec_t) -1)
286                 u = (uint64_t) c->timer_slack_nsec;
287         else
288                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
289
290         return sd_bus_message_append(reply, "t", u);
291 }
292
293 static int property_get_capability_bounding_set(
294                 sd_bus *bus,
295                 const char *path,
296                 const char *interface,
297                 const char *property,
298                 sd_bus_message *reply,
299                 void *userdata,
300                 sd_bus_error *error) {
301
302         ExecContext *c = userdata;
303
304         assert(bus);
305         assert(reply);
306         assert(c);
307
308         /* We store this negated internally, to match the kernel, but
309          * we expose it normalized. */
310         return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
311 }
312
313 static int property_get_capabilities(
314                 sd_bus *bus,
315                 const char *path,
316                 const char *interface,
317                 const char *property,
318                 sd_bus_message *reply,
319                 void *userdata,
320                 sd_bus_error *error) {
321
322         ExecContext *c = userdata;
323         _cleanup_cap_free_charp_ char *t = NULL;
324         const char *s;
325
326         assert(bus);
327         assert(reply);
328         assert(c);
329
330         if (c->capabilities)
331                 s = t = cap_to_text(c->capabilities, NULL);
332         else
333                 s = "";
334
335         if (!s)
336                 return -ENOMEM;
337
338         return sd_bus_message_append(reply, "s", s);
339 }
340
341 static int property_get_syscall_filter(
342                 sd_bus *bus,
343                 const char *path,
344                 const char *interface,
345                 const char *property,
346                 sd_bus_message *reply,
347                 void *userdata,
348                 sd_bus_error *error) {
349
350         ExecContext *c = userdata;
351
352         assert(bus);
353         assert(reply);
354         assert(c);
355
356         if (c->syscall_filter)
357                 return sd_bus_message_append_array(reply, 'u', c->syscall_filter, (syscall_max() + 31) >> 4);
358         else
359                 return sd_bus_message_append_array(reply, 'u', NULL, 0);
360 }
361
362 const sd_bus_vtable bus_exec_vtable[] = {
363         SD_BUS_VTABLE_START(0),
364         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
365         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
366         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
367         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
368         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
369         SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
370         SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
371         SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
372         SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
373         SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
374         SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
375         SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
376         SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
377         SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
378         SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
379         SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
380         SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
381         SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
382         SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
383         SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
384         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
385         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
386         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
387         SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
388         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
389         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
390         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
391         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
392         SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
393         SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
394         SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
395         SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
396         SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
397         SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
398         SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
399         SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
400         SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
401         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
402         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
403         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
404         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
405         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
406         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
407         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
408         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
409         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
410         SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), SD_BUS_VTABLE_PROPERTY_CONST),
411         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
412         SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
413         SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
414         SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
415         SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
416         SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
417         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
418         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
419         SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
420         SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
421         SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
422         SD_BUS_PROPERTY("SystemCallFilter", "au", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
423         SD_BUS_VTABLE_END
424 };
425
426 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
427         int r;
428
429         assert(reply);
430         assert(c);
431
432         if (!c->path)
433                 return 0;
434
435         r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
436         if (r < 0)
437                 return r;
438
439         r = sd_bus_message_append(reply, "s", c->path);
440         if (r < 0)
441                 return r;
442
443         r = sd_bus_message_append_strv(reply, c->argv);
444         if (r < 0)
445                 return r;
446
447         r = sd_bus_message_append(reply, "bttttuii",
448                                   c->ignore,
449                                   c->exec_status.start_timestamp.realtime,
450                                   c->exec_status.start_timestamp.monotonic,
451                                   c->exec_status.exit_timestamp.realtime,
452                                   c->exec_status.exit_timestamp.monotonic,
453                                   (uint32_t) c->exec_status.pid,
454                                   (int32_t) c->exec_status.code,
455                                   (int32_t) c->exec_status.status);
456         if (r < 0)
457                 return r;
458
459         return sd_bus_message_close_container(reply);
460 }
461
462 int bus_property_get_exec_command(
463                 sd_bus *bus,
464                 const char *path,
465                 const char *interface,
466                 const char *property,
467                 sd_bus_message *reply,
468                 void *userdata,
469                 sd_bus_error *ret_error) {
470
471         ExecCommand *c = (ExecCommand*) userdata;
472         int r;
473
474         assert(bus);
475         assert(reply);
476
477         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
478         if (r < 0)
479                 return r;
480
481         r = append_exec_command(reply, c);
482         if (r < 0)
483                 return r;
484
485         return sd_bus_message_close_container(reply);
486 }
487
488 int bus_property_get_exec_command_list(
489                 sd_bus *bus,
490                 const char *path,
491                 const char *interface,
492                 const char *property,
493                 sd_bus_message *reply,
494                 void *userdata,
495                 sd_bus_error *ret_error) {
496
497         ExecCommand *c = *(ExecCommand**) userdata;
498         int r;
499
500         assert(bus);
501         assert(reply);
502
503         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
504         if (r < 0)
505                 return r;
506
507         LIST_FOREACH(command, c, c) {
508                 r = append_exec_command(reply, c);
509                 if (r < 0)
510                         return r;
511         }
512
513         return sd_bus_message_close_container(reply);
514 }