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