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