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