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