chiark / gitweb /
Classify processes from sessions into cgroups
[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 "capability.h"
27 #include "cgroup-util.h"
28 #include "fileio.h"
29 #include "audit.h"
30 #include "bus-message.h"
31 #include "bus-util.h"
32 #include "strv.h"
33 #include "bus-creds.h"
34 #include "bus-label.h"
35
36 enum {
37         CAP_OFFSET_INHERITABLE = 0,
38         CAP_OFFSET_PERMITTED = 1,
39         CAP_OFFSET_EFFECTIVE = 2,
40         CAP_OFFSET_BOUNDING = 3
41 };
42
43 void bus_creds_done(sd_bus_creds *c) {
44         assert(c);
45
46         /* For internal bus cred structures that are allocated by
47          * something else */
48
49         free(c->session);
50         free(c->unit);
51         free(c->user_unit);
52         free(c->slice);
53         free(c->unescaped_description);
54         free(c->supplementary_gids);
55
56         free(c->well_known_names); /* note that this is an strv, but
57                                     * we only free the array, not the
58                                     * strings the array points to. The
59                                     * full strv we only free if
60                                     * c->allocated is set, see
61                                     * below. */
62
63         strv_free(c->cmdline_array);
64 }
65
66 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
67         assert_return(c, NULL);
68
69         if (c->allocated) {
70                 assert(c->n_ref > 0);
71                 c->n_ref++;
72         } else {
73                 sd_bus_message *m;
74
75                 /* If this is an embedded creds structure, then
76                  * forward ref counting to the message */
77                 m = container_of(c, sd_bus_message, creds);
78                 sd_bus_message_ref(m);
79         }
80
81         return c;
82 }
83
84 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
85
86         if (!c)
87                 return NULL;
88
89         if (c->allocated) {
90                 assert(c->n_ref > 0);
91                 c->n_ref--;
92
93                 if (c->n_ref == 0) {
94                         free(c->comm);
95                         free(c->tid_comm);
96                         free(c->exe);
97                         free(c->cmdline);
98                         free(c->cgroup);
99                         free(c->capability);
100                         free(c->label);
101                         free(c->unique_name);
102                         free(c->cgroup_root);
103                         free(c->description);
104
105                         free(c->supplementary_gids);
106                         c->supplementary_gids = NULL;
107
108                         strv_free(c->well_known_names);
109                         c->well_known_names = NULL;
110
111                         bus_creds_done(c);
112
113                         free(c);
114                 }
115         } else {
116                 sd_bus_message *m;
117
118                 m = container_of(c, sd_bus_message, creds);
119                 sd_bus_message_unref(m);
120         }
121
122
123         return NULL;
124 }
125
126 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
127         assert_return(c, 0);
128
129         return c->mask;
130 }
131
132 sd_bus_creds* bus_creds_new(void) {
133         sd_bus_creds *c;
134
135         c = new0(sd_bus_creds, 1);
136         if (!c)
137                 return NULL;
138
139         c->allocated = true;
140         c->n_ref = 1;
141         return c;
142 }
143
144 _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
145         sd_bus_creds *c;
146         int r;
147
148         assert_return(pid >= 0, -EINVAL);
149         assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
150         assert_return(ret, -EINVAL);
151
152         if (pid == 0)
153                 pid = getpid();
154
155         c = bus_creds_new();
156         if (!c)
157                 return -ENOMEM;
158
159         r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
160         if (r < 0) {
161                 sd_bus_creds_unref(c);
162                 return r;
163         }
164
165         /* Check if the process existed at all, in case we haven't
166          * figured that out already */
167         if (!pid_is_alive(pid)) {
168                 sd_bus_creds_unref(c);
169                 return -ESRCH;
170         }
171
172         *ret = c;
173         return 0;
174 }
175
176 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
177         assert_return(c, -EINVAL);
178         assert_return(uid, -EINVAL);
179
180         if (!(c->mask & SD_BUS_CREDS_UID))
181                 return -ENODATA;
182
183         *uid = c->uid;
184         return 0;
185 }
186
187 _public_ int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) {
188         assert_return(c, -EINVAL);
189         assert_return(euid, -EINVAL);
190
191         if (!(c->mask & SD_BUS_CREDS_EUID))
192                 return -ENODATA;
193
194         *euid = c->euid;
195         return 0;
196 }
197
198 _public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
199         assert_return(c, -EINVAL);
200         assert_return(suid, -EINVAL);
201
202         if (!(c->mask & SD_BUS_CREDS_SUID))
203                 return -ENODATA;
204
205         *suid = c->suid;
206         return 0;
207 }
208
209
210 _public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
211         assert_return(c, -EINVAL);
212         assert_return(fsuid, -EINVAL);
213
214         if (!(c->mask & SD_BUS_CREDS_FSUID))
215                 return -ENODATA;
216
217         *fsuid = c->fsuid;
218         return 0;
219 }
220
221 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
222         assert_return(c, -EINVAL);
223         assert_return(gid, -EINVAL);
224
225         if (!(c->mask & SD_BUS_CREDS_GID))
226                 return -ENODATA;
227
228         *gid = c->gid;
229         return 0;
230 }
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         sz = DIV_ROUND_UP(cap_last_cap(), 32U);
566         if ((unsigned)capability > cap_last_cap())
567                 return 0;
568
569         return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
570 }
571
572 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
573         assert_return(c, -EINVAL);
574         assert_return(capability >= 0, -EINVAL);
575
576         if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
577                 return -ENODATA;
578
579         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
580 }
581
582 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
583         assert_return(c, -EINVAL);
584         assert_return(capability >= 0, -EINVAL);
585
586         if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
587                 return -ENODATA;
588
589         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
590 }
591
592 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
593         assert_return(c, -EINVAL);
594         assert_return(capability >= 0, -EINVAL);
595
596         if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
597                 return -ENODATA;
598
599         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
600 }
601
602 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
603         assert_return(c, -EINVAL);
604         assert_return(capability >= 0, -EINVAL);
605
606         if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
607                 return -ENODATA;
608
609         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
610 }
611
612 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
613         size_t sz, max;
614         unsigned i, j;
615
616         assert(c);
617         assert(p);
618
619         max = DIV_ROUND_UP(cap_last_cap(), 32U);
620         p += strspn(p, WHITESPACE);
621
622         sz = strlen(p);
623         if (sz % 8 != 0)
624                 return -EINVAL;
625
626         sz /= 8;
627         if (sz > max)
628                 return -EINVAL;
629
630         if (!c->capability) {
631                 c->capability = new0(uint32_t, max * 4);
632                 if (!c->capability)
633                         return -ENOMEM;
634         }
635
636         for (i = 0; i < sz; i ++) {
637                 uint32_t v = 0;
638
639                 for (j = 0; j < 8; ++j) {
640                         int t;
641
642                         t = unhexchar(*p++);
643                         if (t < 0)
644                                 return -EINVAL;
645
646                         v = (v << 4) | t;
647                 }
648
649                 c->capability[offset * max + (sz - i - 1)] = v;
650         }
651
652         return 0;
653 }
654
655 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
656         uint64_t missing;
657         int r;
658
659         assert(c);
660         assert(c->allocated);
661
662         if (!(mask & SD_BUS_CREDS_AUGMENT))
663                 return 0;
664
665         missing = mask & ~c->mask;
666         if (missing == 0)
667                 return 0;
668
669         /* Try to retrieve PID from creds if it wasn't passed to us */
670         if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
671                 pid = c->pid;
672
673         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
674                 tid = c->pid;
675
676         /* Without pid we cannot do much... */
677         if (pid <= 0)
678                 return 0;
679
680         if (pid > 0) {
681                 c->pid = pid;
682                 c->mask |= SD_BUS_CREDS_PID;
683         }
684
685         if (tid > 0) {
686                 c->tid = tid;
687                 c->mask |= SD_BUS_CREDS_TID;
688         }
689
690         if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
691                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
692                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
693                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
694                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
695
696                 _cleanup_fclose_ FILE *f = NULL;
697                 const char *p;
698
699                 p = procfs_file_alloca(pid, "status");
700
701                 f = fopen(p, "re");
702                 if (!f) {
703                         if (errno == ENOENT)
704                                 return -ESRCH;
705                         else if (errno != EPERM && errno != EACCES)
706                                 return -errno;
707                 } else {
708                         char line[LINE_MAX];
709
710                         FOREACH_LINE(line, f, return -errno) {
711                                 truncate_nl(line);
712
713                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
714                                         p = startswith(line, "Uid:");
715                                         if (p) {
716                                                 unsigned long uid, euid, suid, fsuid;
717
718                                                 p += strspn(p, WHITESPACE);
719                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
720                                                         return -EIO;
721
722                                                 c->uid = (uid_t) uid;
723                                                 c->euid = (uid_t) euid;
724                                                 c->suid = (uid_t) suid;
725                                                 c->fsuid = (uid_t) fsuid;
726                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
727                                                 continue;
728                                         }
729                                 }
730
731                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
732                                         p = startswith(line, "Gid:");
733                                         if (p) {
734                                                 unsigned long gid, egid, sgid, fsgid;
735
736                                                 p += strspn(p, WHITESPACE);
737                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
738                                                         return -EIO;
739
740                                                 c->gid = (gid_t) gid;
741                                                 c->egid = (gid_t) egid;
742                                                 c->sgid = (gid_t) sgid;
743                                                 c->fsgid = (gid_t) fsgid;
744                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
745                                                 continue;
746                                         }
747                                 }
748
749                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
750                                         p = startswith(line, "Groups:");
751                                         if (p) {
752                                                 size_t allocated = 0;
753
754                                                 for (;;) {
755                                                         unsigned long g;
756                                                         int n = 0;
757
758                                                         p += strspn(p, WHITESPACE);
759                                                         if (*p == 0)
760                                                                 break;
761
762                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
763                                                                 return -EIO;
764
765                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
766                                                                 return -ENOMEM;
767
768                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
769                                                         p += n;
770                                                 }
771
772                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
773                                                 continue;
774                                         }
775                                 }
776
777                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
778                                         p = startswith(line, "CapEff:");
779                                         if (p) {
780                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
781                                                 if (r < 0)
782                                                         return r;
783
784                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
785                                                 continue;
786                                         }
787                                 }
788
789                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
790                                         p = startswith(line, "CapPrm:");
791                                         if (p) {
792                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
793                                                 if (r < 0)
794                                                         return r;
795
796                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
797                                                 continue;
798                                         }
799                                 }
800
801                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
802                                         p = startswith(line, "CapInh:");
803                                         if (p) {
804                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
805                                                 if (r < 0)
806                                                         return r;
807
808                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
809                                                 continue;
810                                         }
811                                 }
812
813                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
814                                         p = startswith(line, "CapBnd:");
815                                         if (p) {
816                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
817                                                 if (r < 0)
818                                                         return r;
819
820                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
821                                                 continue;
822                                         }
823                                 }
824                         }
825                 }
826         }
827
828         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
829                 const char *p;
830
831                 p = procfs_file_alloca(pid, "attr/current");
832                 r = read_one_line_file(p, &c->label);
833                 if (r < 0) {
834                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
835                                 return r;
836                 } else
837                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
838         }
839
840         if (missing & SD_BUS_CREDS_COMM) {
841                 r = get_process_comm(pid, &c->comm);
842                 if (r < 0) {
843                         if (r != -EPERM && r != -EACCES)
844                                 return r;
845                 } else
846                         c->mask |= SD_BUS_CREDS_COMM;
847         }
848
849         if (missing & SD_BUS_CREDS_EXE) {
850                 r = get_process_exe(pid, &c->exe);
851                 if (r < 0) {
852                         if (r != -EPERM && r != -EACCES)
853                                 return r;
854                 } else
855                         c->mask |= SD_BUS_CREDS_EXE;
856         }
857
858         if (missing & SD_BUS_CREDS_CMDLINE) {
859                 const char *p;
860
861                 p = procfs_file_alloca(pid, "cmdline");
862                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
863                 if (r < 0) {
864                         if (r == -ENOENT)
865                                 return -ESRCH;
866                         if (r != -EPERM && r != -EACCES)
867                                 return r;
868                 } else {
869                         if (c->cmdline_size == 0) {
870                                 free(c->cmdline);
871                                 c->cmdline = NULL;
872                         } else
873                                 c->mask |= SD_BUS_CREDS_CMDLINE;
874                 }
875         }
876
877         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
878                 _cleanup_free_ char *p = NULL;
879
880                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
881                         return -ENOMEM;
882
883                 r = read_one_line_file(p, &c->tid_comm);
884                 if (r < 0) {
885                         if (r == -ENOENT)
886                                 return -ESRCH;
887                         if (r != -EPERM && r != -EACCES)
888                                 return r;
889                 } else
890                         c->mask |= SD_BUS_CREDS_TID_COMM;
891         }
892
893         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)) {
894
895                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
896                 if (r < 0) {
897                         if (r != -EPERM && r != -EACCES)
898                                 return r;
899                 } else {
900                         r = cg_get_root_path(&c->cgroup_root);
901                         if (r < 0)
902                                 return r;
903
904                         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);
905                 }
906         }
907
908         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
909                 r = audit_session_from_pid(pid, &c->audit_session_id);
910                 if (r < 0) {
911                         if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
912                                 return r;
913                 } else
914                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
915         }
916
917         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
918                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
919                 if (r < 0) {
920                         if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
921                                 return r;
922                 } else
923                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
924         }
925
926         return 0;
927 }
928
929 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
930         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
931         int r;
932
933         assert(c);
934         assert(ret);
935
936         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
937                 /* There's already all data we need, or augmentation
938                  * wasn't turned on. */
939
940                 *ret = sd_bus_creds_ref(c);
941                 return 0;
942         }
943
944         n = bus_creds_new();
945         if (!n)
946                 return -ENOMEM;
947
948         /* Copy the original data over */
949
950         if (c->mask & mask & SD_BUS_CREDS_UID) {
951                 n->uid = c->uid;
952                 n->mask |= SD_BUS_CREDS_UID;
953         }
954
955         if (c->mask & mask & SD_BUS_CREDS_EUID) {
956                 n->euid = c->euid;
957                 n->mask |= SD_BUS_CREDS_EUID;
958         }
959
960         if (c->mask & mask & SD_BUS_CREDS_SUID) {
961                 n->suid = c->suid;
962                 n->mask |= SD_BUS_CREDS_SUID;
963         }
964
965         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
966                 n->fsuid = c->fsuid;
967                 n->mask |= SD_BUS_CREDS_FSUID;
968         }
969
970         if (c->mask & mask & SD_BUS_CREDS_GID) {
971                 n->gid = c->gid;
972                 n->mask |= SD_BUS_CREDS_GID;
973         }
974
975         if (c->mask & mask & SD_BUS_CREDS_EGID) {
976                 n->egid = c->egid;
977                 n->mask |= SD_BUS_CREDS_EGID;
978         }
979
980         if (c->mask & mask & SD_BUS_CREDS_SGID) {
981                 n->sgid = c->sgid;
982                 n->mask |= SD_BUS_CREDS_SGID;
983         }
984
985         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
986                 n->fsgid = c->fsgid;
987                 n->mask |= SD_BUS_CREDS_FSGID;
988         }
989
990         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
991                 n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
992                 if (!n->supplementary_gids)
993                         return -ENOMEM;
994                 n->n_supplementary_gids = c->n_supplementary_gids;
995                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
996         }
997
998         if (c->mask & mask & SD_BUS_CREDS_PID) {
999                 n->pid = c->pid;
1000                 n->mask |= SD_BUS_CREDS_PID;
1001         }
1002
1003         if (c->mask & mask & SD_BUS_CREDS_TID) {
1004                 n->tid = c->tid;
1005                 n->mask |= SD_BUS_CREDS_TID;
1006         }
1007
1008         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1009                 n->comm = strdup(c->comm);
1010                 if (!n->comm)
1011                         return -ENOMEM;
1012
1013                 n->mask |= SD_BUS_CREDS_COMM;
1014         }
1015
1016         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1017                 n->tid_comm = strdup(c->tid_comm);
1018                 if (!n->tid_comm)
1019                         return -ENOMEM;
1020
1021                 n->mask |= SD_BUS_CREDS_TID_COMM;
1022         }
1023
1024         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1025                 n->exe = strdup(c->exe);
1026                 if (!n->exe)
1027                         return -ENOMEM;
1028
1029                 n->mask |= SD_BUS_CREDS_EXE;
1030         }
1031
1032         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1033                 n->cmdline = memdup(c->cmdline, c->cmdline_size);
1034                 if (!n->cmdline)
1035                         return -ENOMEM;
1036
1037                 n->cmdline_size = c->cmdline_size;
1038                 n->mask |= SD_BUS_CREDS_CMDLINE;
1039         }
1040
1041         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)) {
1042                 n->cgroup = strdup(c->cgroup);
1043                 if (!n->cgroup)
1044                         return -ENOMEM;
1045
1046                 n->cgroup_root = strdup(c->cgroup_root);
1047                 if (!n->cgroup_root)
1048                         return -ENOMEM;
1049
1050                 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);
1051         }
1052
1053         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1054                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1055                 if (!n->capability)
1056                         return -ENOMEM;
1057
1058                 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);
1059         }
1060
1061         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1062                 n->label = strdup(c->label);
1063                 if (!n->label)
1064                         return -ENOMEM;
1065                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1066         }
1067
1068         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1069                 n->audit_session_id = c->audit_session_id;
1070                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1071         }
1072         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1073                 n->audit_login_uid = c->audit_login_uid;
1074                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1075         }
1076
1077         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1078                 n->unique_name = strdup(c->unique_name);
1079                 if (!n->unique_name)
1080                         return -ENOMEM;
1081                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1082         }
1083
1084         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1085                 n->well_known_names = strv_copy(c->well_known_names);
1086                 if (!n->well_known_names)
1087                         return -ENOMEM;
1088                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1089         }
1090
1091         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1092                 n->description = strdup(c->description);
1093                 if (!n->description)
1094                         return -ENOMEM;
1095                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1096         }
1097
1098         /* Get more data */
1099
1100         r = bus_creds_add_more(n, mask,
1101                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
1102                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
1103         if (r < 0)
1104                 return r;
1105
1106         *ret = n;
1107         n = NULL;
1108         return 0;
1109 }