chiark / gitweb /
sd-bus: optimize how we generate the well-known-names lists in messages from kdbus
[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         free(c->well_known_names); /* note that this is an strv, but
55                                     * we only free the array, not the
56                                     * strings the array points to. The
57                                     * full strv we only free if
58                                     * c->allocated is set, see
59                                     * below. */
60
61         strv_free(c->cmdline_array);
62 }
63
64 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
65         assert_return(c, NULL);
66
67         if (c->allocated) {
68                 assert(c->n_ref > 0);
69                 c->n_ref++;
70         } else {
71                 sd_bus_message *m;
72
73                 /* If this is an embedded creds structure, then
74                  * forward ref counting to the message */
75                 m = container_of(c, sd_bus_message, creds);
76                 sd_bus_message_ref(m);
77         }
78
79         return c;
80 }
81
82 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
83
84         if (!c)
85                 return NULL;
86
87         if (c->allocated) {
88                 assert(c->n_ref > 0);
89                 c->n_ref--;
90
91                 if (c->n_ref == 0) {
92                         free(c->comm);
93                         free(c->tid_comm);
94                         free(c->exe);
95                         free(c->cmdline);
96                         free(c->cgroup);
97                         free(c->capability);
98                         free(c->label);
99                         free(c->unique_name);
100                         free(c->cgroup_root);
101                         free(c->description);
102                         free(c->supplementary_gids);
103
104                         strv_free(c->well_known_names);
105                         c->well_known_names = NULL;
106
107                         bus_creds_done(c);
108
109                         free(c);
110                 }
111         } else {
112                 sd_bus_message *m;
113
114                 m = container_of(c, sd_bus_message, creds);
115                 sd_bus_message_unref(m);
116         }
117
118
119         return NULL;
120 }
121
122 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
123         assert_return(c, 0);
124
125         return c->mask;
126 }
127
128 sd_bus_creds* bus_creds_new(void) {
129         sd_bus_creds *c;
130
131         c = new0(sd_bus_creds, 1);
132         if (!c)
133                 return NULL;
134
135         c->allocated = true;
136         c->n_ref = 1;
137         return c;
138 }
139
140 _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
141         sd_bus_creds *c;
142         int r;
143
144         assert_return(pid >= 0, -EINVAL);
145         assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
146         assert_return(ret, -EINVAL);
147
148         if (pid == 0)
149                 pid = getpid();
150
151         c = bus_creds_new();
152         if (!c)
153                 return -ENOMEM;
154
155         r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
156         if (r < 0) {
157                 sd_bus_creds_unref(c);
158                 return r;
159         }
160
161         /* Check if the process existed at all, in case we haven't
162          * figured that out already */
163         if (!pid_is_alive(pid)) {
164                 sd_bus_creds_unref(c);
165                 return -ESRCH;
166         }
167
168         *ret = c;
169         return 0;
170 }
171
172 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
173         assert_return(c, -EINVAL);
174         assert_return(uid, -EINVAL);
175
176         if (!(c->mask & SD_BUS_CREDS_UID))
177                 return -ENODATA;
178
179         *uid = c->uid;
180         return 0;
181 }
182
183 _public_ int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) {
184         assert_return(c, -EINVAL);
185         assert_return(euid, -EINVAL);
186
187         if (!(c->mask & SD_BUS_CREDS_EUID))
188                 return -ENODATA;
189
190         *euid = c->euid;
191         return 0;
192 }
193
194 _public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
195         assert_return(c, -EINVAL);
196         assert_return(suid, -EINVAL);
197
198         if (!(c->mask & SD_BUS_CREDS_SUID))
199                 return -ENODATA;
200
201         *suid = c->suid;
202         return 0;
203 }
204
205
206 _public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
207         assert_return(c, -EINVAL);
208         assert_return(fsuid, -EINVAL);
209
210         if (!(c->mask & SD_BUS_CREDS_FSUID))
211                 return -ENODATA;
212
213         *fsuid = c->fsuid;
214         return 0;
215 }
216
217 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
218         assert_return(c, -EINVAL);
219         assert_return(gid, -EINVAL);
220
221         if (!(c->mask & SD_BUS_CREDS_UID))
222                 return -ENODATA;
223
224         *gid = c->gid;
225         return 0;
226 }
227
228
229 _public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
230         assert_return(c, -EINVAL);
231         assert_return(egid, -EINVAL);
232
233         if (!(c->mask & SD_BUS_CREDS_EGID))
234                 return -ENODATA;
235
236         *egid = c->egid;
237         return 0;
238 }
239
240 _public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
241         assert_return(c, -EINVAL);
242         assert_return(sgid, -EINVAL);
243
244         if (!(c->mask & SD_BUS_CREDS_SGID))
245                 return -ENODATA;
246
247         *sgid = c->sgid;
248         return 0;
249 }
250
251 _public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
252         assert_return(c, -EINVAL);
253         assert_return(fsgid, -EINVAL);
254
255         if (!(c->mask & SD_BUS_CREDS_FSGID))
256                 return -ENODATA;
257
258         *fsgid = c->fsgid;
259         return 0;
260 }
261
262 _public_ int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) {
263         assert_return(c, -EINVAL);
264         assert_return(gids, -EINVAL);
265
266         if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
267                 return -ENODATA;
268
269         *gids = c->supplementary_gids;
270         return (int) c->n_supplementary_gids;
271 }
272
273 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
274         assert_return(c, -EINVAL);
275         assert_return(pid, -EINVAL);
276
277         if (!(c->mask & SD_BUS_CREDS_PID))
278                 return -ENODATA;
279
280         assert(c->pid > 0);
281         *pid = c->pid;
282         return 0;
283 }
284
285 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
286         assert_return(c, -EINVAL);
287         assert_return(tid, -EINVAL);
288
289         if (!(c->mask & SD_BUS_CREDS_TID))
290                 return -ENODATA;
291
292         assert(c->tid > 0);
293         *tid = c->tid;
294         return 0;
295 }
296
297 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
298         assert_return(c, -EINVAL);
299         assert_return(usec, -EINVAL);
300
301         if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
302                 return -ENODATA;
303
304         assert(c->pid_starttime > 0);
305         *usec = c->pid_starttime;
306         return 0;
307 }
308
309 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
310         assert_return(c, -EINVAL);
311
312         if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
313                 return -ENODATA;
314
315         assert(c->label);
316         *ret = c->label;
317         return 0;
318 }
319
320 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
321         assert_return(c, -EINVAL);
322         assert_return(ret, -EINVAL);
323
324         if (!(c->mask & SD_BUS_CREDS_COMM))
325                 return -ENODATA;
326
327         assert(c->comm);
328         *ret = c->comm;
329         return 0;
330 }
331
332 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
333         assert_return(c, -EINVAL);
334         assert_return(ret, -EINVAL);
335
336         if (!(c->mask & SD_BUS_CREDS_TID_COMM))
337                 return -ENODATA;
338
339         assert(c->tid_comm);
340         *ret = c->tid_comm;
341         return 0;
342 }
343
344 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
345         assert_return(c, -EINVAL);
346         assert_return(ret, -EINVAL);
347
348         if (!(c->mask & SD_BUS_CREDS_EXE))
349                 return -ENODATA;
350
351         assert(c->exe);
352         *ret = c->exe;
353         return 0;
354 }
355
356 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
357         assert_return(c, -EINVAL);
358         assert_return(ret, -EINVAL);
359
360         if (!(c->mask & SD_BUS_CREDS_CGROUP))
361                 return -ENODATA;
362
363         assert(c->cgroup);
364         *ret = c->cgroup;
365         return 0;
366 }
367
368 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
369         int r;
370
371         assert_return(c, -EINVAL);
372         assert_return(ret, -EINVAL);
373
374         if (!(c->mask & SD_BUS_CREDS_UNIT))
375                 return -ENODATA;
376
377         assert(c->cgroup);
378
379         if (!c->unit) {
380                 const char *shifted;
381
382                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
383                 if (r < 0)
384                         return r;
385
386                 r = cg_path_get_unit(shifted, (char**) &c->unit);
387                 if (r < 0)
388                         return r;
389         }
390
391         *ret = c->unit;
392         return 0;
393 }
394
395 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
396         int r;
397
398         assert_return(c, -EINVAL);
399         assert_return(ret, -EINVAL);
400
401         if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
402                 return -ENODATA;
403
404         assert(c->cgroup);
405
406         if (!c->user_unit) {
407                 const char *shifted;
408
409                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
410                 if (r < 0)
411                         return r;
412
413                 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
414                 if (r < 0)
415                         return r;
416         }
417
418         *ret = c->user_unit;
419         return 0;
420 }
421
422 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
423         int r;
424
425         assert_return(c, -EINVAL);
426         assert_return(ret, -EINVAL);
427
428         if (!(c->mask & SD_BUS_CREDS_SLICE))
429                 return -ENODATA;
430
431         assert(c->cgroup);
432
433         if (!c->slice) {
434                 const char *shifted;
435
436                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
437                 if (r < 0)
438                         return r;
439
440                 r = cg_path_get_slice(shifted, (char**) &c->slice);
441                 if (r < 0)
442                         return r;
443         }
444
445         *ret = c->slice;
446         return 0;
447 }
448
449 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
450         int r;
451
452         assert_return(c, -EINVAL);
453         assert_return(ret, -EINVAL);
454
455         if (!(c->mask & SD_BUS_CREDS_SESSION))
456                 return -ENODATA;
457
458         assert(c->cgroup);
459
460         if (!c->session) {
461                 const char *shifted;
462
463                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
464                 if (r < 0)
465                         return r;
466
467                 r = cg_path_get_session(shifted, (char**) &c->session);
468                 if (r < 0)
469                         return r;
470         }
471
472         *ret = c->session;
473         return 0;
474 }
475
476 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
477         const char *shifted;
478         int r;
479
480         assert_return(c, -EINVAL);
481         assert_return(uid, -EINVAL);
482
483         if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
484                 return -ENODATA;
485
486         assert(c->cgroup);
487
488         r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
489         if (r < 0)
490                 return r;
491
492         return cg_path_get_owner_uid(shifted, uid);
493 }
494
495 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
496         assert_return(c, -EINVAL);
497
498         if (!(c->mask & SD_BUS_CREDS_CMDLINE))
499                 return -ENODATA;
500
501         assert_return(c->cmdline, -ESRCH);
502         assert(c->cmdline);
503
504         if (!c->cmdline_array) {
505                 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
506                 if (!c->cmdline_array)
507                         return -ENOMEM;
508         }
509
510         *cmdline = c->cmdline_array;
511         return 0;
512 }
513
514 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
515         assert_return(c, -EINVAL);
516         assert_return(sessionid, -EINVAL);
517
518         if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
519                 return -ENODATA;
520
521         *sessionid = c->audit_session_id;
522         return 0;
523 }
524
525 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
526         assert_return(c, -EINVAL);
527         assert_return(uid, -EINVAL);
528
529         if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
530                 return -ENODATA;
531
532         *uid = c->audit_login_uid;
533         return 0;
534 }
535
536 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
537         assert_return(c, -EINVAL);
538         assert_return(unique_name, -EINVAL);
539
540         if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
541                 return -ENODATA;
542
543         *unique_name = c->unique_name;
544         return 0;
545 }
546
547 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
548         assert_return(c, -EINVAL);
549         assert_return(well_known_names, -EINVAL);
550
551         if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
552                 return -ENODATA;
553
554         *well_known_names = c->well_known_names;
555         return 0;
556 }
557
558 _public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
559         assert_return(c, -EINVAL);
560         assert_return(ret, -EINVAL);
561
562         if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
563                 return -ENODATA;
564
565         assert(c->description);
566
567         if (!c->unescaped_description) {
568                 c->unescaped_description = bus_label_unescape(c->description);
569                 if (!c->unescaped_description)
570                         return -ENOMEM;
571         }
572
573         *ret = c->unescaped_description;
574         return 0;
575 }
576
577 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
578         size_t sz;
579
580         assert(c);
581         assert(c->capability);
582
583         sz = c->capability_size / 4;
584         if ((size_t) capability >= sz*8)
585                 return 0;
586
587         return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
588 }
589
590 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
591         assert_return(c, -EINVAL);
592         assert_return(capability >= 0, -EINVAL);
593
594         if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
595                 return -ENODATA;
596
597         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
598 }
599
600 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
601         assert_return(c, -EINVAL);
602         assert_return(capability >= 0, -EINVAL);
603
604         if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
605                 return -ENODATA;
606
607         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
608 }
609
610 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
611         assert_return(c, -EINVAL);
612         assert_return(capability >= 0, -EINVAL);
613
614         if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
615                 return -ENODATA;
616
617         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
618 }
619
620 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
621         assert_return(c, -EINVAL);
622         assert_return(capability >= 0, -EINVAL);
623
624         if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
625                 return -ENODATA;
626
627         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
628 }
629
630 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
631         size_t sz;
632         unsigned i;
633
634         assert(c);
635         assert(p);
636
637         p += strspn(p, WHITESPACE);
638
639         sz = strlen(p);
640         if (sz % 2 != 0)
641                 return -EINVAL;
642
643         sz /= 2;
644         if (!c->capability) {
645                 c->capability = new0(uint8_t, sz * 4);
646                 if (!c->capability)
647                         return -ENOMEM;
648
649                 c->capability_size = sz * 4;
650         }
651
652         for (i = 0; i < sz; i ++) {
653                 int x, y;
654
655                 x = unhexchar(p[i*2]);
656                 y = unhexchar(p[i*2+1]);
657
658                 if (x < 0 || y < 0)
659                         return -EINVAL;
660
661                 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
662         }
663
664         return 0;
665 }
666
667 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
668         uint64_t missing;
669         int r;
670
671         assert(c);
672         assert(c->allocated);
673
674         if (!(mask & SD_BUS_CREDS_AUGMENT))
675                 return 0;
676
677         missing = mask & ~c->mask;
678         if (missing == 0)
679                 return 0;
680
681         /* Try to retrieve PID from creds if it wasn't passed to us */
682         if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
683                 pid = c->pid;
684
685         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
686                 tid = c->pid;
687
688         /* Without pid we cannot do much... */
689         if (pid <= 0)
690                 return 0;
691
692         if (pid > 0) {
693                 c->pid = pid;
694                 c->mask |= SD_BUS_CREDS_PID;
695         }
696
697         if (tid > 0) {
698                 c->tid = tid;
699                 c->mask |= SD_BUS_CREDS_TID;
700         }
701
702         if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
703                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
704                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
705                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
706                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
707
708                 _cleanup_fclose_ FILE *f = NULL;
709                 const char *p;
710
711                 p = procfs_file_alloca(pid, "status");
712
713                 f = fopen(p, "re");
714                 if (!f) {
715                         if (errno == ENOENT)
716                                 return -ESRCH;
717                         else if (errno != EPERM && errno != EACCES)
718                                 return -errno;
719                 } else {
720                         char line[LINE_MAX];
721
722                         FOREACH_LINE(line, f, return -errno) {
723                                 truncate_nl(line);
724
725                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
726                                         p = startswith(line, "Uid:");
727                                         if (p) {
728                                                 unsigned long uid, euid, suid, fsuid;
729
730                                                 p += strspn(p, WHITESPACE);
731                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
732                                                         return -EIO;
733
734                                                 c->uid = (uid_t) uid;
735                                                 c->euid = (uid_t) euid;
736                                                 c->suid = (uid_t) suid;
737                                                 c->fsuid = (uid_t) fsuid;
738                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
739                                                 continue;
740                                         }
741                                 }
742
743                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
744                                         p = startswith(line, "Gid:");
745                                         if (p) {
746                                                 unsigned long gid, egid, sgid, fsgid;
747
748                                                 p += strspn(p, WHITESPACE);
749                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
750                                                         return -EIO;
751
752                                                 c->gid = (gid_t) gid;
753                                                 c->egid = (gid_t) egid;
754                                                 c->sgid = (gid_t) sgid;
755                                                 c->fsgid = (gid_t) fsgid;
756                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
757                                                 continue;
758                                         }
759                                 }
760
761                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
762                                         p = startswith(line, "Groups:");
763                                         if (p) {
764                                                 size_t allocated = 0;
765
766                                                 for (;;) {
767                                                         unsigned long g;
768                                                         int n = 0;
769
770                                                         p += strspn(p, WHITESPACE);
771                                                         if (*p == 0)
772                                                                 break;
773
774                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
775                                                                 return -EIO;
776
777                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
778                                                                 return -ENOMEM;
779
780                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
781                                                         p += n;
782                                                 }
783
784                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
785                                                 continue;
786                                         }
787                                 }
788
789                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
790                                         p = startswith(line, "CapEff:");
791                                         if (p) {
792                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
793                                                 if (r < 0)
794                                                         return r;
795
796                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
797                                                 continue;
798                                         }
799                                 }
800
801                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
802                                         p = startswith(line, "CapPrm:");
803                                         if (p) {
804                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
805                                                 if (r < 0)
806                                                         return r;
807
808                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
809                                                 continue;
810                                         }
811                                 }
812
813                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
814                                         p = startswith(line, "CapInh:");
815                                         if (p) {
816                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
817                                                 if (r < 0)
818                                                         return r;
819
820                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
821                                                 continue;
822                                         }
823                                 }
824
825                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
826                                         p = startswith(line, "CapBnd:");
827                                         if (p) {
828                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
829                                                 if (r < 0)
830                                                         return r;
831
832                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
833                                                 continue;
834                                         }
835                                 }
836                         }
837                 }
838         }
839
840         if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
841                 unsigned long long st;
842
843                 r = get_starttime_of_pid(pid, &st);
844                 if (r < 0) {
845                         if (r != -EPERM && r != -EACCES)
846                                 return r;
847                 } else {
848                         c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
849                         c->mask |= SD_BUS_CREDS_PID_STARTTIME;
850                 }
851         }
852
853         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
854                 const char *p;
855
856                 p = procfs_file_alloca(pid, "attr/current");
857                 r = read_one_line_file(p, &c->label);
858                 if (r < 0) {
859                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
860                                 return r;
861                 } else
862                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
863         }
864
865         if (missing & SD_BUS_CREDS_COMM) {
866                 r = get_process_comm(pid, &c->comm);
867                 if (r < 0) {
868                         if (r != -EPERM && r != -EACCES)
869                                 return r;
870                 } else
871                         c->mask |= SD_BUS_CREDS_COMM;
872         }
873
874         if (missing & SD_BUS_CREDS_EXE) {
875                 r = get_process_exe(pid, &c->exe);
876                 if (r < 0) {
877                         if (r != -EPERM && r != -EACCES)
878                                 return r;
879                 } else
880                         c->mask |= SD_BUS_CREDS_EXE;
881         }
882
883         if (missing & SD_BUS_CREDS_CMDLINE) {
884                 const char *p;
885
886                 p = procfs_file_alloca(pid, "cmdline");
887                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
888                 if (r < 0) {
889                         if (r == -ENOENT)
890                                 return -ESRCH;
891                         if (r != -EPERM && r != -EACCES)
892                                 return r;
893                 } else {
894                         if (c->cmdline_size == 0) {
895                                 free(c->cmdline);
896                                 c->cmdline = NULL;
897                         } else
898                                 c->mask |= SD_BUS_CREDS_CMDLINE;
899                 }
900         }
901
902         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
903                 _cleanup_free_ char *p = NULL;
904
905                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
906                         return -ENOMEM;
907
908                 r = read_one_line_file(p, &c->tid_comm);
909                 if (r < 0) {
910                         if (r == -ENOENT)
911                                 return -ESRCH;
912                         if (r != -EPERM && r != -EACCES)
913                                 return r;
914                 } else
915                         c->mask |= SD_BUS_CREDS_TID_COMM;
916         }
917
918         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)) {
919
920                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
921                 if (r < 0) {
922                         if (r != -EPERM && r != -EACCES)
923                                 return r;
924                 } else {
925                         r = cg_get_root_path(&c->cgroup_root);
926                         if (r < 0)
927                                 return r;
928
929                         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);
930                 }
931         }
932
933         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
934                 r = audit_session_from_pid(pid, &c->audit_session_id);
935                 if (r < 0) {
936                         if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
937                                 return r;
938                 } else
939                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
940         }
941
942         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
943                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
944                 if (r < 0) {
945                         if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
946                                 return r;
947                 } else
948                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
949         }
950
951         return 0;
952 }
953
954 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
955         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
956         int r;
957
958         assert(c);
959         assert(ret);
960
961         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
962                 /* There's already all data we need, or augmentation
963                  * wasn't turned on. */
964
965                 *ret = sd_bus_creds_ref(c);
966                 return 0;
967         }
968
969         n = bus_creds_new();
970         if (!n)
971                 return -ENOMEM;
972
973         /* Copy the original data over */
974
975         if (c->mask & mask & SD_BUS_CREDS_UID) {
976                 n->uid = c->uid;
977                 n->mask |= SD_BUS_CREDS_UID;
978         }
979
980         if (c->mask & mask & SD_BUS_CREDS_EUID) {
981                 n->euid = c->euid;
982                 n->mask |= SD_BUS_CREDS_EUID;
983         }
984
985         if (c->mask & mask & SD_BUS_CREDS_SUID) {
986                 n->suid = c->suid;
987                 n->mask |= SD_BUS_CREDS_SUID;
988         }
989
990         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
991                 n->fsuid = c->fsuid;
992                 n->mask |= SD_BUS_CREDS_FSUID;
993         }
994
995         if (c->mask & mask & SD_BUS_CREDS_GID) {
996                 n->gid = c->gid;
997                 n->mask |= SD_BUS_CREDS_GID;
998         }
999
1000         if (c->mask & mask & SD_BUS_CREDS_EGID) {
1001                 n->egid = c->egid;
1002                 n->mask |= SD_BUS_CREDS_EGID;
1003         }
1004
1005         if (c->mask & mask & SD_BUS_CREDS_SGID) {
1006                 n->sgid = c->sgid;
1007                 n->mask |= SD_BUS_CREDS_SGID;
1008         }
1009
1010         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
1011                 n->fsgid = c->fsgid;
1012                 n->mask |= SD_BUS_CREDS_FSGID;
1013         }
1014
1015         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
1016                 n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
1017                 if (!n->supplementary_gids)
1018                         return -ENOMEM;
1019                 n->n_supplementary_gids = c->n_supplementary_gids;
1020                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
1021         }
1022
1023         if (c->mask & mask & SD_BUS_CREDS_PID) {
1024                 n->pid = c->pid;
1025                 n->mask |= SD_BUS_CREDS_PID;
1026         }
1027
1028         if (c->mask & mask & SD_BUS_CREDS_TID) {
1029                 n->tid = c->tid;
1030                 n->mask |= SD_BUS_CREDS_TID;
1031         }
1032
1033         if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
1034                 n->pid_starttime = c->pid_starttime;
1035                 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
1036         }
1037
1038         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1039                 n->comm = strdup(c->comm);
1040                 if (!n->comm)
1041                         return -ENOMEM;
1042
1043                 n->mask |= SD_BUS_CREDS_COMM;
1044         }
1045
1046         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1047                 n->tid_comm = strdup(c->tid_comm);
1048                 if (!n->tid_comm)
1049                         return -ENOMEM;
1050
1051                 n->mask |= SD_BUS_CREDS_TID_COMM;
1052         }
1053
1054         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1055                 n->exe = strdup(c->exe);
1056                 if (!n->exe)
1057                         return -ENOMEM;
1058
1059                 n->mask |= SD_BUS_CREDS_EXE;
1060         }
1061
1062         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1063                 n->cmdline = memdup(c->cmdline, c->cmdline_size);
1064                 if (!n->cmdline)
1065                         return -ENOMEM;
1066
1067                 n->cmdline_size = c->cmdline_size;
1068                 n->mask |= SD_BUS_CREDS_CMDLINE;
1069         }
1070
1071         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)) {
1072                 n->cgroup = strdup(c->cgroup);
1073                 if (!n->cgroup)
1074                         return -ENOMEM;
1075
1076                 n->cgroup_root = strdup(c->cgroup_root);
1077                 if (!n->cgroup_root)
1078                         return -ENOMEM;
1079
1080                 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);
1081         }
1082
1083         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1084                 n->capability = memdup(c->capability, c->capability_size);
1085                 if (!n->capability)
1086                         return -ENOMEM;
1087
1088                 n->capability_size = c->capability_size;
1089                 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);
1090         }
1091
1092         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1093                 n->label = strdup(c->label);
1094                 if (!n->label)
1095                         return -ENOMEM;
1096                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1097         }
1098
1099         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1100                 n->audit_session_id = c->audit_session_id;
1101                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1102         }
1103         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1104                 n->audit_login_uid = c->audit_login_uid;
1105                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1106         }
1107
1108         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1109                 n->unique_name = strdup(c->unique_name);
1110                 if (!n->unique_name)
1111                         return -ENOMEM;
1112                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1113         }
1114
1115         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1116                 n->well_known_names = strv_copy(c->well_known_names);
1117                 if (!n->well_known_names)
1118                         return -ENOMEM;
1119                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1120         }
1121
1122         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1123                 n->description = strdup(c->description);
1124                 if (!n->description)
1125                         return -ENOMEM;
1126                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1127         }
1128
1129         /* Get more data */
1130
1131         r = bus_creds_add_more(n, mask,
1132                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
1133                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
1134         if (r < 0)
1135                 return r;
1136
1137         *ret = n;
1138         n = NULL;
1139         return 0;
1140 }