chiark / gitweb /
exec: Add SELinuxContext configuration item
[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 #include "env-util.h"
34
35 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
36
37 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
38
39 static int property_get_environment_files(
40                 sd_bus *bus,
41                 const char *path,
42                 const char *interface,
43                 const char *property,
44                 sd_bus_message *reply,
45                 void *userdata,
46                 sd_bus_error *error) {
47
48         ExecContext *c = userdata;
49         char **j;
50         int r;
51
52         assert(bus);
53         assert(reply);
54         assert(c);
55
56         r = sd_bus_message_open_container(reply, 'a', "(sb)");
57         if (r < 0)
58                 return r;
59
60         STRV_FOREACH(j, c->environment_files) {
61                 const char *fn = *j;
62
63                 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
64                 if (r < 0)
65                         return r;
66         }
67
68         return sd_bus_message_close_container(reply);
69 }
70
71 static int property_get_rlimit(
72                 sd_bus *bus,
73                 const char *path,
74                 const char *interface,
75                 const char *property,
76                 sd_bus_message *reply,
77                 void *userdata,
78                 sd_bus_error *error) {
79
80         struct rlimit *rl;
81         uint64_t u;
82
83         assert(bus);
84         assert(reply);
85         assert(userdata);
86
87         rl = *(struct rlimit**) userdata;
88         if (rl)
89                 u = (uint64_t) rl->rlim_max;
90         else {
91                 struct rlimit buf = {};
92                 int z;
93
94                 z = rlimit_from_string(property);
95                 assert(z >= 0);
96
97                 getrlimit(z, &buf);
98
99                 u = (uint64_t) buf.rlim_max;
100         }
101
102         return sd_bus_message_append(reply, "t", u);
103 }
104
105 static int property_get_oom_score_adjust(
106                 sd_bus *bus,
107                 const char *path,
108                 const char *interface,
109                 const char *property,
110                 sd_bus_message *reply,
111                 void *userdata,
112                 sd_bus_error *error) {
113
114
115         ExecContext *c = userdata;
116         int32_t n;
117
118         assert(bus);
119         assert(reply);
120         assert(c);
121
122         if (c->oom_score_adjust_set)
123                 n = c->oom_score_adjust;
124         else {
125                 _cleanup_free_ char *t = NULL;
126
127                 n = 0;
128                 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
129                         safe_atoi(t, &n);
130         }
131
132         return sd_bus_message_append(reply, "i", n);
133 }
134
135 static int property_get_nice(
136                 sd_bus *bus,
137                 const char *path,
138                 const char *interface,
139                 const char *property,
140                 sd_bus_message *reply,
141                 void *userdata,
142                 sd_bus_error *error) {
143
144
145         ExecContext *c = userdata;
146         int32_t n;
147
148         assert(bus);
149         assert(reply);
150         assert(c);
151
152         if (c->nice_set)
153                 n = c->nice;
154         else {
155                 errno = 0;
156                 n = getpriority(PRIO_PROCESS, 0);
157                 if (errno != 0)
158                         n = 0;
159         }
160
161         return sd_bus_message_append(reply, "i", n);
162 }
163
164 static int property_get_ioprio(
165                 sd_bus *bus,
166                 const char *path,
167                 const char *interface,
168                 const char *property,
169                 sd_bus_message *reply,
170                 void *userdata,
171                 sd_bus_error *error) {
172
173
174         ExecContext *c = userdata;
175         int32_t n;
176
177         assert(bus);
178         assert(reply);
179         assert(c);
180
181         if (c->ioprio_set)
182                 n = c->ioprio;
183         else {
184                 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
185                 if (n < 0)
186                         n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
187         }
188
189         return sd_bus_message_append(reply, "i", n);
190 }
191
192 static int property_get_cpu_sched_policy(
193                 sd_bus *bus,
194                 const char *path,
195                 const char *interface,
196                 const char *property,
197                 sd_bus_message *reply,
198                 void *userdata,
199                 sd_bus_error *error) {
200
201         ExecContext *c = userdata;
202         int32_t n;
203
204         assert(bus);
205         assert(reply);
206         assert(c);
207
208         if (c->cpu_sched_set)
209                 n = c->cpu_sched_policy;
210         else {
211                 n = sched_getscheduler(0);
212                 if (n < 0)
213                         n = SCHED_OTHER;
214         }
215
216         return sd_bus_message_append(reply, "i", n);
217 }
218
219 static int property_get_cpu_sched_priority(
220                 sd_bus *bus,
221                 const char *path,
222                 const char *interface,
223                 const char *property,
224                 sd_bus_message *reply,
225                 void *userdata,
226                 sd_bus_error *error) {
227
228         ExecContext *c = userdata;
229         int32_t n;
230
231         assert(bus);
232         assert(reply);
233         assert(c);
234
235         if (c->cpu_sched_set)
236                 n = c->cpu_sched_priority;
237         else {
238                 struct sched_param p = {};
239
240                 if (sched_getparam(0, &p) >= 0)
241                         n = p.sched_priority;
242                 else
243                         n = 0;
244         }
245
246         return sd_bus_message_append(reply, "i", n);
247 }
248
249 static int property_get_cpu_affinity(
250                 sd_bus *bus,
251                 const char *path,
252                 const char *interface,
253                 const char *property,
254                 sd_bus_message *reply,
255                 void *userdata,
256                 sd_bus_error *error) {
257
258         ExecContext *c = userdata;
259
260         assert(bus);
261         assert(reply);
262         assert(c);
263
264         if (c->cpuset)
265                 return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
266         else
267                 return sd_bus_message_append_array(reply, 'y', NULL, 0);
268 }
269
270 static int property_get_timer_slack_nsec(
271                 sd_bus *bus,
272                 const char *path,
273                 const char *interface,
274                 const char *property,
275                 sd_bus_message *reply,
276                 void *userdata,
277                 sd_bus_error *error) {
278
279         ExecContext *c = userdata;
280         uint64_t u;
281
282         assert(bus);
283         assert(reply);
284         assert(c);
285
286         if (c->timer_slack_nsec != (nsec_t) -1)
287                 u = (uint64_t) c->timer_slack_nsec;
288         else
289                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
290
291         return sd_bus_message_append(reply, "t", u);
292 }
293
294 static int property_get_capability_bounding_set(
295                 sd_bus *bus,
296                 const char *path,
297                 const char *interface,
298                 const char *property,
299                 sd_bus_message *reply,
300                 void *userdata,
301                 sd_bus_error *error) {
302
303         ExecContext *c = userdata;
304
305         assert(bus);
306         assert(reply);
307         assert(c);
308
309         /* We store this negated internally, to match the kernel, but
310          * we expose it normalized. */
311         return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
312 }
313
314 static int property_get_capabilities(
315                 sd_bus *bus,
316                 const char *path,
317                 const char *interface,
318                 const char *property,
319                 sd_bus_message *reply,
320                 void *userdata,
321                 sd_bus_error *error) {
322
323         ExecContext *c = userdata;
324         _cleanup_cap_free_charp_ char *t = NULL;
325         const char *s;
326
327         assert(bus);
328         assert(reply);
329         assert(c);
330
331         if (c->capabilities)
332                 s = t = cap_to_text(c->capabilities, NULL);
333         else
334                 s = "";
335
336         if (!s)
337                 return -ENOMEM;
338
339         return sd_bus_message_append(reply, "s", s);
340 }
341
342 static int property_get_syscall_filter(
343                 sd_bus *bus,
344                 const char *path,
345                 const char *interface,
346                 const char *property,
347                 sd_bus_message *reply,
348                 void *userdata,
349                 sd_bus_error *error) {
350
351         ExecContext *c = userdata;
352
353         assert(bus);
354         assert(reply);
355         assert(c);
356
357         if (c->syscall_filter)
358                 return sd_bus_message_append_array(reply, 'u', c->syscall_filter, (syscall_max() + 31) >> 4);
359         else
360                 return sd_bus_message_append_array(reply, 'u', NULL, 0);
361 }
362
363 const sd_bus_vtable bus_exec_vtable[] = {
364         SD_BUS_VTABLE_START(0),
365         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
366         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
367         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
368         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
369         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
370         SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
371         SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
372         SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
373         SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
374         SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
375         SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
376         SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
377         SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
378         SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
379         SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
380         SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
381         SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
382         SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
383         SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
384         SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
385         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
386         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
387         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
388         SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
389         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
390         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
391         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
392         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
393         SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
394         SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
395         SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
396         SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
397         SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
398         SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
399         SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
400         SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
401         SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
402         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
403         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
404         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
405         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
406         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
407         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
408         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
409         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
410         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
411         SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), SD_BUS_VTABLE_PROPERTY_CONST),
412         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
413         SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
414         SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
415         SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
416         SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
417         SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
418         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
419         SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
420         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
421         SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
422         SD_BUS_PROPERTY("SELinuxContext", "s", NULL, offsetof(ExecContext, selinux_context), SD_BUS_VTABLE_PROPERTY_CONST),
423         SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
424         SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
425         SD_BUS_PROPERTY("SystemCallFilter", "au", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
426         SD_BUS_VTABLE_END
427 };
428
429 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
430         int r;
431
432         assert(reply);
433         assert(c);
434
435         if (!c->path)
436                 return 0;
437
438         r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
439         if (r < 0)
440                 return r;
441
442         r = sd_bus_message_append(reply, "s", c->path);
443         if (r < 0)
444                 return r;
445
446         r = sd_bus_message_append_strv(reply, c->argv);
447         if (r < 0)
448                 return r;
449
450         r = sd_bus_message_append(reply, "bttttuii",
451                                   c->ignore,
452                                   c->exec_status.start_timestamp.realtime,
453                                   c->exec_status.start_timestamp.monotonic,
454                                   c->exec_status.exit_timestamp.realtime,
455                                   c->exec_status.exit_timestamp.monotonic,
456                                   (uint32_t) c->exec_status.pid,
457                                   (int32_t) c->exec_status.code,
458                                   (int32_t) c->exec_status.status);
459         if (r < 0)
460                 return r;
461
462         return sd_bus_message_close_container(reply);
463 }
464
465 int bus_property_get_exec_command(
466                 sd_bus *bus,
467                 const char *path,
468                 const char *interface,
469                 const char *property,
470                 sd_bus_message *reply,
471                 void *userdata,
472                 sd_bus_error *ret_error) {
473
474         ExecCommand *c = (ExecCommand*) userdata;
475         int r;
476
477         assert(bus);
478         assert(reply);
479
480         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
481         if (r < 0)
482                 return r;
483
484         r = append_exec_command(reply, c);
485         if (r < 0)
486                 return r;
487
488         return sd_bus_message_close_container(reply);
489 }
490
491 int bus_property_get_exec_command_list(
492                 sd_bus *bus,
493                 const char *path,
494                 const char *interface,
495                 const char *property,
496                 sd_bus_message *reply,
497                 void *userdata,
498                 sd_bus_error *ret_error) {
499
500         ExecCommand *c = *(ExecCommand**) userdata;
501         int r;
502
503         assert(bus);
504         assert(reply);
505
506         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
507         if (r < 0)
508                 return r;
509
510         LIST_FOREACH(command, c, c) {
511                 r = append_exec_command(reply, c);
512                 if (r < 0)
513                         return r;
514         }
515
516         return sd_bus_message_close_container(reply);
517 }
518
519 int bus_exec_context_set_transient_property(
520                 Unit *u,
521                 ExecContext *c,
522                 const char *name,
523                 sd_bus_message *message,
524                 UnitSetPropertiesMode mode,
525                 sd_bus_error *error) {
526
527         int r;
528
529         assert(u);
530         assert(c);
531         assert(name);
532         assert(message);
533
534         if (streq(name, "User")) {
535                 const char *uu;
536
537                 r = sd_bus_message_read(message, "s", &uu);
538                 if (r < 0)
539                         return r;
540
541                 if (mode != UNIT_CHECK) {
542
543                         if (isempty(uu)) {
544                                 free(c->user);
545                                 c->user = NULL;
546                         } else {
547                                 char *t;
548
549                                 t = strdup(uu);
550                                 if (!t)
551                                         return -ENOMEM;
552
553                                 free(c->user);
554                                 c->user = t;
555                         }
556
557                         unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
558                 }
559
560                 return 1;
561
562         } else if (streq(name, "Group")) {
563                 const char *gg;
564
565                 r = sd_bus_message_read(message, "s", &gg);
566                 if (r < 0)
567                         return r;
568
569                 if (mode != UNIT_CHECK) {
570
571                         if (isempty(gg)) {
572                                 free(c->group);
573                                 c->group = NULL;
574                         } else {
575                                 char *t;
576
577                                 t = strdup(gg);
578                                 if (!t)
579                                         return -ENOMEM;
580
581                                 free(c->group);
582                                 c->group = t;
583                         }
584
585                         unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
586                 }
587
588                 return 1;
589
590         } else if (streq(name, "Nice")) {
591                 int n;
592
593                 r = sd_bus_message_read(message, "i", &n);
594                 if (r < 0)
595                         return r;
596
597                 if (n < PRIO_MIN || n >= PRIO_MAX)
598                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
599
600                 if (mode != UNIT_CHECK) {
601                         c->nice = n;
602                         unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
603                 }
604
605                 return 1;
606
607         } else if (streq(name, "Environment")) {
608
609                 _cleanup_strv_free_ char **l = NULL;
610
611                 r = sd_bus_message_read_strv(message, &l);
612                 if (r < 0)
613                         return r;
614
615                 if (!strv_env_is_valid(l))
616                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
617
618                 if (mode != UNIT_CHECK) {
619                         _cleanup_free_ char *joined = NULL;
620                         char **e;
621
622                         e = strv_env_merge(2, c->environment, l);
623                         if (!e)
624                                 return -ENOMEM;
625
626                         strv_free(c->environment);
627                         c->environment = e;
628
629                         joined = strv_join(c->environment, " ");
630                         if (!joined)
631                                 return -ENOMEM;
632
633                         unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
634                 }
635
636                 return 1;
637         }
638
639         return 0;
640 }