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