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