chiark / gitweb /
libsystemd-bus: sd_bus_request_name: use kdbus_translate_request_name_flags()
[elogind.git] / src / libsystemd-bus / bus-creds.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 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 <stdlib.h>
23
24 #include "util.h"
25 #include "cgroup-util.h"
26 #include "fileio.h"
27 #include "audit.h"
28 #include "bus-message.h"
29 #include "bus-util.h"
30 #include "time-util.h"
31 #include "bus-creds.h"
32
33 enum {
34         CAP_OFFSET_INHERITABLE = 0,
35         CAP_OFFSET_PERMITTED = 1,
36         CAP_OFFSET_EFFECTIVE = 2,
37         CAP_OFFSET_BOUNDING = 3
38 };
39
40 void bus_creds_done(sd_bus_creds *c) {
41         assert(c);
42
43         /* For internal bus cred structures that are allocated by
44          * something else */
45
46         free(c->session);
47         free(c->unit);
48         free(c->user_unit);
49         free(c->slice);
50
51         free(c->cmdline_array);
52 }
53
54 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
55         assert_return(c, NULL);
56
57         if (c->allocated) {
58                 assert(c->n_ref > 0);
59                 c->n_ref++;
60         } else {
61                 sd_bus_message *m;
62
63                 /* If this is an embedded creds structure, then
64                  * forward ref counting to the message */
65                 m = container_of(c, sd_bus_message, creds);
66                 sd_bus_message_ref(m);
67         }
68
69         return c;
70 }
71
72 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
73         assert_return(c, NULL);
74
75         if (c->allocated) {
76                 assert(c->n_ref > 0);
77                 c->n_ref--;
78
79                 if (c->n_ref == 0) {
80                         bus_creds_done(c);
81
82                         free(c->comm);
83                         free(c->tid_comm);
84                         free(c->exe);
85                         free(c->cmdline);
86                         free(c->cgroup);
87                         free(c->capability);
88                         free(c->label);
89                         free(c);
90                 }
91         } else {
92                 sd_bus_message *m;
93
94                 m = container_of(c, sd_bus_message, creds);
95                 sd_bus_message_unref(m);
96         }
97
98
99         return NULL;
100 }
101
102 _public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
103         assert_return(c, 0);
104
105         return c->mask;
106 }
107
108 sd_bus_creds* bus_creds_new(void) {
109         sd_bus_creds *c;
110
111         c = new0(sd_bus_creds, 1);
112         if (!c)
113                 return NULL;
114
115         c->allocated = true;
116         c->n_ref = 1;
117         return c;
118 }
119
120 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
121         sd_bus_creds *c;
122         int r;
123
124         assert_return(pid >= 0, -EINVAL);
125         assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
126         assert_return(ret, -EINVAL);
127
128         if (pid == 0)
129                 pid = getpid();
130
131         c = bus_creds_new();
132         if (!c)
133                 return -ENOMEM;
134
135         r = bus_creds_add_more(c, mask, pid, 0);
136         if (r < 0) {
137                 free(c);
138                 return r;
139         }
140
141         /* Check if the process existed at all, in case we haven't
142          * figured that out already */
143         if (kill(pid, 0) < 0 && errno == ESRCH) {
144                 sd_bus_creds_unref(c);
145                 return -ESRCH;
146         }
147
148         *ret = c;
149         return 0;
150 }
151
152 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
153         assert_return(c, -EINVAL);
154         assert_return(uid, -EINVAL);
155         assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
156
157         *uid = c->uid;
158         return 0;
159 }
160
161 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
162         assert_return(c, -EINVAL);
163         assert_return(gid, -EINVAL);
164         assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
165
166         *gid = c->gid;
167         return 0;
168 }
169
170 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
171         assert_return(c, -EINVAL);
172         assert_return(pid, -EINVAL);
173         assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA);
174
175         assert(c->pid > 0);
176         *pid = c->pid;
177         return 0;
178 }
179
180 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
181         assert_return(c, -EINVAL);
182         assert_return(tid, -EINVAL);
183         assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA);
184
185         assert(c->tid > 0);
186         *tid = c->tid;
187         return 0;
188 }
189
190 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
191         assert_return(c, -EINVAL);
192         assert_return(usec, -EINVAL);
193         assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA);
194
195         assert(c->pid_starttime > 0);
196         *usec = c->pid_starttime;
197         return 0;
198 }
199
200 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
201         assert_return(c, -EINVAL);
202         assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA);
203
204         assert(c->label);
205         *ret = c->label;
206         return 0;
207 }
208
209 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
210         assert_return(c, -EINVAL);
211         assert_return(ret, -EINVAL);
212         assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA);
213
214         assert(c->comm);
215         *ret = c->comm;
216         return 0;
217 }
218
219 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
220         assert_return(c, -EINVAL);
221         assert_return(ret, -EINVAL);
222         assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA);
223
224         assert(c->tid_comm);
225         *ret = c->tid_comm;
226         return 0;
227 }
228
229 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
230         assert_return(c, -EINVAL);
231         assert_return(ret, -EINVAL);
232         assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA);
233
234         assert(c->exe);
235         *ret = c->exe;
236         return 0;
237 }
238
239 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
240         assert_return(c, -EINVAL);
241         assert_return(ret, -EINVAL);
242         assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA);
243
244         assert(c->cgroup);
245         *ret = c->cgroup;
246         return 0;
247 }
248
249 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
250         int r;
251
252         assert_return(c, -EINVAL);
253         assert_return(ret, -EINVAL);
254         assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA);
255
256         assert(c->cgroup);
257
258         if (!c->unit) {
259                 r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
260                 if (r < 0)
261                         return r;
262         }
263
264         *ret = c->unit;
265         return 0;
266 }
267
268 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
269         int r;
270
271         assert_return(c, -EINVAL);
272         assert_return(ret, -EINVAL);
273         assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA);
274
275         assert(c->cgroup);
276
277         if (!c->user_unit) {
278                 r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
279                 if (r < 0)
280                         return r;
281         }
282
283         *ret = c->user_unit;
284         return 0;
285 }
286
287 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
288         int r;
289
290         assert_return(c, -EINVAL);
291         assert_return(ret, -EINVAL);
292         assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA);
293
294         assert(c->cgroup);
295
296         if (!c->slice) {
297                 r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
298                 if (r < 0)
299                         return r;
300         }
301
302         *ret = c->slice;
303         return 0;
304 }
305
306 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
307         int r;
308
309         assert_return(c, -EINVAL);
310         assert_return(ret, -EINVAL);
311         assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA);
312
313         assert(c->cgroup);
314
315         if (!c->session) {
316                 r = cg_path_get_session(c->cgroup, (char**) &c->session);
317                 if (r < 0)
318                         return r;
319         }
320
321         *ret = c->session;
322         return 0;
323 }
324
325 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
326         assert_return(c, -EINVAL);
327         assert_return(uid, -EINVAL);
328         assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA);
329
330         assert(c->cgroup);
331
332         return cg_path_get_owner_uid(c->cgroup, uid);
333 }
334
335 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
336         size_t n, i;
337         const char *p;
338         bool first;
339
340         assert_return(c, -EINVAL);
341         assert_return(c->cmdline, -ESRCH);
342         assert_return(c->mask & SD_BUS_CREDS_CMDLINE, -ENODATA);
343
344         assert(c->cmdline);
345
346         for (p = c->cmdline, n = 0; p < c->cmdline + c->cmdline_length; p++)
347                 if (*p == 0)
348                         n++;
349
350         *(char***) &c->cmdline_array = new(char*, n + 1);
351         if (!c->cmdline_array)
352                 return -ENOMEM;
353
354         for (p = c->cmdline, i = 0, first = true; p < c->cmdline + c->cmdline_length; p++) {
355                 if (first)
356                         c->cmdline_array[i++] = (char*) p;
357
358                 first = *p == 0;
359         }
360
361         c->cmdline_array[i] = NULL;
362         *cmdline = c->cmdline_array;
363
364         return 0;
365 }
366
367 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
368         assert_return(c, -EINVAL);
369         assert_return(sessionid, -EINVAL);
370         assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA);
371
372         *sessionid = c->audit_session_id;
373         return 0;
374 }
375
376 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
377         assert_return(c, -EINVAL);
378         assert_return(uid, -EINVAL);
379         assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA);
380
381         *uid = c->audit_login_uid;
382         return 0;
383 }
384
385 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
386         size_t sz;
387
388         assert(c);
389         assert(c->capability);
390
391         sz = c->capability_size / 4;
392         if ((size_t) capability >= sz*8)
393                 return 0;
394
395         return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
396 }
397
398 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
399         assert_return(c, -EINVAL);
400         assert_return(capability >= 0, -EINVAL);
401         assert_return(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS, -ENODATA);
402
403         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
404 }
405
406 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
407         assert_return(c, -EINVAL);
408         assert_return(capability >= 0, -EINVAL);
409         assert_return(c->mask & SD_BUS_CREDS_PERMITTED_CAPS, -ENODATA);
410
411         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
412 }
413
414 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
415         assert_return(c, -EINVAL);
416         assert_return(capability >= 0, -EINVAL);
417         assert_return(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS, -ENODATA);
418
419         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
420 }
421
422 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
423         assert_return(c, -EINVAL);
424         assert_return(capability >= 0, -EINVAL);
425         assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA);
426
427         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
428 }
429
430 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
431         size_t sz;
432         unsigned i;
433
434         assert(c);
435         assert(p);
436
437         p += strspn(p, WHITESPACE);
438
439         sz = strlen(p);
440         if (sz % 2 != 0)
441                 return -EINVAL;
442
443         sz /= 2;
444         if (!c->capability) {
445                 c->capability = new0(uint8_t, sz * 4);
446                 if (!c->capability)
447                         return -ENOMEM;
448
449                 c->capability_size = sz * 4;
450         }
451
452         for (i = 0; i < sz; i ++) {
453                 int x, y;
454
455                 x = unhexchar(p[i*2]);
456                 y = unhexchar(p[i*2+1]);
457
458                 if (x < 0 || y < 0)
459                         return -EINVAL;
460
461                 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
462         }
463
464         return 0;
465 }
466
467 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
468         uint64_t missing;
469         int r;
470
471         assert(c);
472         assert(c->allocated);
473
474         missing = mask & ~c->mask;
475         if (missing == 0)
476                 return 0;
477
478         /* Try to retrieve PID from creds if it wasn't passed to us */
479         if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
480                 pid = c->pid;
481
482         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
483                 tid = c->pid;
484
485         /* Without pid we cannot do much... */
486         if (pid <= 0)
487                 return 0;
488
489         if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
490                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
491                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
492
493                 _cleanup_fclose_ FILE *f = NULL;
494                 char line[LINE_MAX];
495                 const char *p;
496
497                 p = procfs_file_alloca(pid, "status");
498
499                 f = fopen(p, "re");
500                 if (!f)
501                         return errno == ENOENT ? -ESRCH : -errno;
502
503                 FOREACH_LINE(line, f, return -errno) {
504                         truncate_nl(line);
505
506                         if (missing & SD_BUS_CREDS_UID) {
507                                 p = startswith(line, "Uid:");
508                                 if (p) {
509                                         unsigned long uid;
510
511                                         p += strspn(p, WHITESPACE);
512                                         if (sscanf(p, "%lu", &uid) != 1)
513                                                 return -EIO;
514
515                                         c->uid = (uid_t) uid;
516                                         c->mask |= SD_BUS_CREDS_UID;
517                                         continue;
518                                 }
519                         }
520
521                         if (missing & SD_BUS_CREDS_GID) {
522                                 p = startswith(line, "Gid:");
523                                 if (p) {
524                                         unsigned long gid;
525
526                                         p += strspn(p, WHITESPACE);
527                                         if (sscanf(p, "%lu", &gid) != 1)
528                                                 return -EIO;
529
530                                         c->gid = (uid_t) gid;
531                                         c->mask |= SD_BUS_CREDS_GID;
532                                         continue;
533                                 }
534                         }
535
536                         if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
537                                 p = startswith(line, "CapEff:");
538                                 if (p) {
539                                         r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
540                                         if (r < 0)
541                                                 return r;
542
543                                         c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
544                                         continue;
545                                 }
546                         }
547
548                         if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
549                                 p = startswith(line, "CapPrm:");
550                                 if (p) {
551                                         r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
552                                         if (r < 0)
553                                                 return r;
554
555                                         c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
556                                         continue;
557                                 }
558                         }
559
560                         if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
561                                 p = startswith(line, "CapInh:");
562                                 if (p) {
563                                         r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
564                                         if (r < 0)
565                                                 return r;
566
567                                         c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
568                                         continue;
569                                 }
570                         }
571
572                         if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
573                                 p = startswith(line, "CapBnd:");
574                                 if (p) {
575                                         r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
576                                         if (r < 0)
577                                                 return r;
578
579                                         c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
580                                         continue;
581                                 }
582                         }
583                 }
584         }
585
586         if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
587                 unsigned long long st;
588
589                 r = get_starttime_of_pid(pid, &st);
590                 if (r < 0)
591                         return r;
592
593                 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
594                 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
595         }
596
597         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
598                 const char *p;
599
600                 p = procfs_file_alloca(pid, "attr/current");
601                 r = read_one_line_file(p, &c->label);
602                 if (r < 0 && r != -ENOENT && r != -EINVAL)
603                         return r;
604                 else if (r >= 0)
605                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
606         }
607
608         if (missing & SD_BUS_CREDS_COMM) {
609                 r = get_process_comm(pid, &c->comm);
610                 if (r < 0 && r != -ESRCH)
611                         return r;
612                 else if (r >= 0)
613                         c->mask |= SD_BUS_CREDS_COMM;
614         }
615
616         if (missing & SD_BUS_CREDS_EXE) {
617                 r = get_process_exe(pid, &c->exe);
618                 if (r < 0)
619                         return r;
620
621                 c->mask |= SD_BUS_CREDS_EXE;
622         }
623
624         if (missing & SD_BUS_CREDS_CMDLINE) {
625                 const char *p;
626
627                 p = procfs_file_alloca(pid, "cmdline");
628                 r = read_full_file(p, &c->cmdline, &c->cmdline_length);
629                 if (r < 0)
630                         return r;
631
632                 if (c->cmdline_length == 0) {
633                         free(c->cmdline);
634                         c->cmdline = NULL;
635                 } else
636                         c->mask |= SD_BUS_CREDS_CMDLINE;
637         }
638
639         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
640                 _cleanup_free_ char *p = NULL;
641
642                 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
643                         return -ENOMEM;
644
645                 r = read_one_line_file(p, &c->tid_comm);
646                 if (r < 0 && r != -ENOENT)
647                         return r == -ENOENT ? -ESRCH : r;
648                 else if (r >= 0)
649                         c->mask |= SD_BUS_CREDS_TID_COMM;
650         }
651
652         if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
653
654                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
655                 if (r < 0 && r != -ESRCH)
656                         return r;
657                 else if (r >= 0)
658                         c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
659         }
660
661         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
662                 r = audit_session_from_pid(pid, &c->audit_session_id);
663                 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
664                         return r;
665                 else if (r >= 0)
666                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
667         }
668
669         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
670                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
671                 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
672                         return r;
673                 else if (r >= 0)
674                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
675         }
676
677         return 0;
678 }
679
680 _public_ int sd_bus_creds_extend(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
681         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
682         int r;
683
684         assert_return(c, -EINVAL);
685         assert_return(ret, -EINVAL);
686
687         if ((mask & ~c->mask) == 0) {
688                 /* There's already all data we need. */
689
690                 *ret = sd_bus_creds_ref(c);
691                 return 0;
692         }
693
694         n = bus_creds_new();
695         if (!n)
696                 return -ENOMEM;
697
698         /* Copy the original data over */
699
700         if (c->mask & mask & SD_BUS_CREDS_UID) {
701                 n->uid = c->uid;
702                 n->mask |= SD_BUS_CREDS_UID;
703         }
704
705         if (c->mask & mask & SD_BUS_CREDS_GID) {
706                 n->gid = c->gid;
707                 n->mask |= SD_BUS_CREDS_GID;
708         }
709
710         if (c->mask & mask & SD_BUS_CREDS_PID) {
711                 n->pid = c->pid;
712                 n->mask |= SD_BUS_CREDS_PID;
713         }
714
715         if (c->mask & mask & SD_BUS_CREDS_TID) {
716                 n->tid = c->tid;
717                 n->mask |= SD_BUS_CREDS_TID;
718         }
719
720         if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
721                 n->pid_starttime = c->pid_starttime;
722                 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
723         }
724
725         if (c->mask & mask & SD_BUS_CREDS_COMM) {
726                 n->comm = strdup(c->comm);
727                 if (!n->comm)
728                         return -ENOMEM;
729
730                 n->mask |= SD_BUS_CREDS_COMM;
731         }
732
733         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
734                 n->tid_comm = strdup(c->tid_comm);
735                 if (!n->tid_comm)
736                         return -ENOMEM;
737
738                 n->mask |= SD_BUS_CREDS_TID_COMM;
739         }
740
741         if (c->mask & mask & SD_BUS_CREDS_EXE) {
742                 n->exe = strdup(c->exe);
743                 if (!n->exe)
744                         return -ENOMEM;
745
746                 n->mask |= SD_BUS_CREDS_EXE;
747         }
748
749         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
750                 n->cmdline = memdup(c->cmdline, c->cmdline_length);
751                 if (!n->cmdline)
752                         return -ENOMEM;
753
754                 n->cmdline_length = c->cmdline_length;
755                 n->mask |= SD_BUS_CREDS_CMDLINE;
756         }
757
758         if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) {
759                 n->cgroup = strdup(c->cgroup);
760                 if (!n->cgroup)
761                         return -ENOMEM;
762
763                 n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID);
764         }
765
766         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
767                 n->capability = memdup(c->capability, c->capability_size);
768                 if (!n->capability)
769                         return -ENOMEM;
770
771                 n->capability_size = c->capability_size;
772                 n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
773         }
774
775         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
776                 n->audit_session_id = c->audit_session_id;
777                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
778         }
779
780         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
781                 n->audit_login_uid = c->audit_login_uid;
782                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
783         }
784
785         /* Get more data */
786
787         r = bus_creds_add_more(n, mask,
788                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
789                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
790         if (r < 0)
791                 return r;
792
793         *ret = n;
794         n = NULL;
795         return 0;
796 }