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