chiark / gitweb /
pam_elogind compiling
[elogind.git] / src / libsystemd / sd-bus / bus-creds.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdlib.h>
23 #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         int r;
362
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                 const char *shifted;
373
374                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
375                 if (r < 0)
376                         return r;
377
378                 r = cg_path_get_unit(shifted, (char**) &c->unit);
379                 if (r < 0)
380                         return r;
381         }
382
383         *ret = c->unit;
384         return 0;
385 }
386
387 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
388         int r;
389
390         assert_return(c, -EINVAL);
391         assert_return(ret, -EINVAL);
392
393         if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
394                 return -ENODATA;
395
396         assert(c->cgroup);
397
398         if (!c->user_unit) {
399                 const char *shifted;
400
401                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
402                 if (r < 0)
403                         return r;
404
405                 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
406                 if (r < 0)
407                         return r;
408         }
409
410         *ret = c->user_unit;
411         return 0;
412 }
413
414 _public_ int sd_bus_creds_get_slice(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_SLICE))
421                 return -ENODATA;
422
423         assert(c->cgroup);
424
425         if (!c->slice) {
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_slice(shifted, (char**) &c->slice);
433                 if (r < 0)
434                         return r;
435         }
436
437         *ret = c->slice;
438         return 0;
439 }
440
441 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
442         int r;
443
444         assert_return(c, -EINVAL);
445         assert_return(ret, -EINVAL);
446
447         if (!(c->mask & SD_BUS_CREDS_SESSION))
448                 return -ENODATA;
449
450         assert(c->cgroup);
451
452         if (!c->session) {
453                 const char *shifted;
454
455                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
456                 if (r < 0)
457                         return r;
458
459                 r = cg_path_get_session(shifted, (char**) &c->session);
460                 if (r < 0)
461                         return r;
462         }
463
464         *ret = c->session;
465         return 0;
466 }
467
468 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
469         const char *shifted;
470         int r;
471
472         assert_return(c, -EINVAL);
473         assert_return(uid, -EINVAL);
474
475         if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
476                 return -ENODATA;
477
478         assert(c->cgroup);
479
480         r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
481         if (r < 0)
482                 return r;
483
484         return cg_path_get_owner_uid(shifted, uid);
485 }
486
487 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
488         assert_return(c, -EINVAL);
489
490         if (!(c->mask & SD_BUS_CREDS_CMDLINE))
491                 return -ENODATA;
492
493         assert_return(c->cmdline, -ESRCH);
494         assert(c->cmdline);
495
496         if (!c->cmdline_array) {
497                 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
498                 if (!c->cmdline_array)
499                         return -ENOMEM;
500         }
501
502         *cmdline = c->cmdline_array;
503         return 0;
504 }
505
506 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
507         assert_return(c, -EINVAL);
508         assert_return(sessionid, -EINVAL);
509
510         if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
511                 return -ENODATA;
512
513         *sessionid = c->audit_session_id;
514         return 0;
515 }
516
517 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
518         assert_return(c, -EINVAL);
519         assert_return(uid, -EINVAL);
520
521         if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
522                 return -ENODATA;
523
524         *uid = c->audit_login_uid;
525         return 0;
526 }
527
528 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
529         assert_return(c, -EINVAL);
530         assert_return(unique_name, -EINVAL);
531
532         if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
533                 return -ENODATA;
534
535         *unique_name = c->unique_name;
536         return 0;
537 }
538
539 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
540         assert_return(c, -EINVAL);
541         assert_return(well_known_names, -EINVAL);
542
543         if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
544                 return -ENODATA;
545
546         /* As a special hack we return the bus driver as well-known
547          * names list when this is requested. */
548         if (c->well_known_names_driver) {
549                 static const char* const wkn[] = {
550                         "org.freedesktop.DBus",
551                         NULL
552                 };
553
554                 *well_known_names = (char**) wkn;
555                 return 0;
556         }
557
558         if (c->well_known_names_local) {
559                 static const char* const wkn[] = {
560                         "org.freedesktop.DBus.Local",
561                         NULL
562                 };
563
564                 *well_known_names = (char**) wkn;
565                 return 0;
566         }
567
568         *well_known_names = c->well_known_names;
569         return 0;
570 }
571
572 _public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
573         assert_return(c, -EINVAL);
574         assert_return(ret, -EINVAL);
575
576         if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
577                 return -ENODATA;
578
579         assert(c->description);
580
581         if (!c->unescaped_description) {
582                 c->unescaped_description = bus_label_unescape(c->description);
583                 if (!c->unescaped_description)
584                         return -ENOMEM;
585         }
586
587         *ret = c->unescaped_description;
588         return 0;
589 }
590
591 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
592         size_t sz;
593
594         assert(c);
595         assert(capability >= 0);
596         assert(c->capability);
597
598         sz = DIV_ROUND_UP(cap_last_cap(), 32U);
599         if ((unsigned)capability > cap_last_cap())
600                 return 0;
601
602         return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
603 }
604
605 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
606         assert_return(c, -EINVAL);
607         assert_return(capability >= 0, -EINVAL);
608
609         if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
610                 return -ENODATA;
611
612         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
613 }
614
615 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
616         assert_return(c, -EINVAL);
617         assert_return(capability >= 0, -EINVAL);
618
619         if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
620                 return -ENODATA;
621
622         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
623 }
624
625 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
626         assert_return(c, -EINVAL);
627         assert_return(capability >= 0, -EINVAL);
628
629         if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
630                 return -ENODATA;
631
632         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
633 }
634
635 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
636         assert_return(c, -EINVAL);
637         assert_return(capability >= 0, -EINVAL);
638
639         if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
640                 return -ENODATA;
641
642         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
643 }
644
645 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
646         size_t sz, max;
647         unsigned i, j;
648
649         assert(c);
650         assert(p);
651
652         max = DIV_ROUND_UP(cap_last_cap(), 32U);
653         p += strspn(p, WHITESPACE);
654
655         sz = strlen(p);
656         if (sz % 8 != 0)
657                 return -EINVAL;
658
659         sz /= 8;
660         if (sz > max)
661                 return -EINVAL;
662
663         if (!c->capability) {
664                 c->capability = new0(uint32_t, max * 4);
665                 if (!c->capability)
666                         return -ENOMEM;
667         }
668
669         for (i = 0; i < sz; i ++) {
670                 uint32_t v = 0;
671
672                 for (j = 0; j < 8; ++j) {
673                         int t;
674
675                         t = unhexchar(*p++);
676                         if (t < 0)
677                                 return -EINVAL;
678
679                         v = (v << 4) | t;
680                 }
681
682                 c->capability[offset * max + (sz - i - 1)] = v;
683         }
684
685         return 0;
686 }
687
688 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
689         uint64_t missing;
690         int r;
691
692         assert(c);
693         assert(c->allocated);
694
695         if (!(mask & SD_BUS_CREDS_AUGMENT))
696                 return 0;
697
698         missing = mask & ~c->mask;
699         if (missing == 0)
700                 return 0;
701
702         /* Try to retrieve PID from creds if it wasn't passed to us */
703         if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
704                 pid = c->pid;
705
706         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
707                 tid = c->pid;
708
709         /* Without pid we cannot do much... */
710         if (pid <= 0)
711                 return 0;
712
713         if (pid > 0) {
714                 c->pid = pid;
715                 c->mask |= SD_BUS_CREDS_PID;
716         }
717
718         if (tid > 0) {
719                 c->tid = tid;
720                 c->mask |= SD_BUS_CREDS_TID;
721         }
722
723         if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
724                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
725                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
726                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
727                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
728
729                 _cleanup_fclose_ FILE *f = NULL;
730                 const char *p;
731
732                 p = procfs_file_alloca(pid, "status");
733
734                 f = fopen(p, "re");
735                 if (!f) {
736                         if (errno == ENOENT)
737                                 return -ESRCH;
738                         else if (errno != EPERM && errno != EACCES)
739                                 return -errno;
740                 } else {
741                         char line[LINE_MAX];
742
743                         FOREACH_LINE(line, f, return -errno) {
744                                 truncate_nl(line);
745
746                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
747                                         p = startswith(line, "Uid:");
748                                         if (p) {
749                                                 unsigned long uid, euid, suid, fsuid;
750
751                                                 p += strspn(p, WHITESPACE);
752                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
753                                                         return -EIO;
754
755                                                 c->uid = (uid_t) uid;
756                                                 c->euid = (uid_t) euid;
757                                                 c->suid = (uid_t) suid;
758                                                 c->fsuid = (uid_t) fsuid;
759                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
760                                                 continue;
761                                         }
762                                 }
763
764                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
765                                         p = startswith(line, "Gid:");
766                                         if (p) {
767                                                 unsigned long gid, egid, sgid, fsgid;
768
769                                                 p += strspn(p, WHITESPACE);
770                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
771                                                         return -EIO;
772
773                                                 c->gid = (gid_t) gid;
774                                                 c->egid = (gid_t) egid;
775                                                 c->sgid = (gid_t) sgid;
776                                                 c->fsgid = (gid_t) fsgid;
777                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
778                                                 continue;
779                                         }
780                                 }
781
782                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
783                                         p = startswith(line, "Groups:");
784                                         if (p) {
785                                                 size_t allocated = 0;
786
787                                                 for (;;) {
788                                                         unsigned long g;
789                                                         int n = 0;
790
791                                                         p += strspn(p, WHITESPACE);
792                                                         if (*p == 0)
793                                                                 break;
794
795                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
796                                                                 return -EIO;
797
798                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
799                                                                 return -ENOMEM;
800
801                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
802                                                         p += n;
803                                                 }
804
805                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
806                                                 continue;
807                                         }
808                                 }
809
810                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
811                                         p = startswith(line, "CapEff:");
812                                         if (p) {
813                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
814                                                 if (r < 0)
815                                                         return r;
816
817                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
818                                                 continue;
819                                         }
820                                 }
821
822                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
823                                         p = startswith(line, "CapPrm:");
824                                         if (p) {
825                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
826                                                 if (r < 0)
827                                                         return r;
828
829                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
830                                                 continue;
831                                         }
832                                 }
833
834                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
835                                         p = startswith(line, "CapInh:");
836                                         if (p) {
837                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
838                                                 if (r < 0)
839                                                         return r;
840
841                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
842                                                 continue;
843                                         }
844                                 }
845
846                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
847                                         p = startswith(line, "CapBnd:");
848                                         if (p) {
849                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
850                                                 if (r < 0)
851                                                         return r;
852
853                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
854                                                 continue;
855                                         }
856                                 }
857                         }
858                 }
859         }
860
861         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
862                 const char *p;
863
864                 p = procfs_file_alloca(pid, "attr/current");
865                 r = read_one_line_file(p, &c->label);
866                 if (r < 0) {
867                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
868                                 return r;
869                 } else
870                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
871         }
872
873         if (missing & SD_BUS_CREDS_COMM) {
874                 r = get_process_comm(pid, &c->comm);
875                 if (r < 0) {
876                         if (r != -EPERM && r != -EACCES)
877                                 return r;
878                 } else
879                         c->mask |= SD_BUS_CREDS_COMM;
880         }
881
882         if (missing & SD_BUS_CREDS_EXE) {
883                 r = get_process_exe(pid, &c->exe);
884                 if (r < 0) {
885                         if (r != -EPERM && r != -EACCES)
886                                 return r;
887                 } else
888                         c->mask |= SD_BUS_CREDS_EXE;
889         }
890
891         if (missing & SD_BUS_CREDS_CMDLINE) {
892                 const char *p;
893
894                 p = procfs_file_alloca(pid, "cmdline");
895                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
896                 if (r < 0) {
897                         if (r == -ENOENT)
898                                 return -ESRCH;
899                         if (r != -EPERM && r != -EACCES)
900                                 return r;
901                 } else {
902                         if (c->cmdline_size == 0) {
903                                 free(c->cmdline);
904                                 c->cmdline = NULL;
905                         } else
906                                 c->mask |= SD_BUS_CREDS_CMDLINE;
907                 }
908         }
909
910         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
911                 _cleanup_free_ char *p = NULL;
912
913                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
914                         return -ENOMEM;
915
916                 r = read_one_line_file(p, &c->tid_comm);
917                 if (r < 0) {
918                         if (r == -ENOENT)
919                                 return -ESRCH;
920                         if (r != -EPERM && r != -EACCES)
921                                 return r;
922                 } else
923                         c->mask |= SD_BUS_CREDS_TID_COMM;
924         }
925
926         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)) {
927
928                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
929                 if (r < 0) {
930                         if (r != -EPERM && r != -EACCES)
931                                 return r;
932                 } else {
933                         r = cg_get_root_path(&c->cgroup_root);
934                         if (r < 0)
935                                 return r;
936
937                         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);
938                 }
939         }
940
941         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
942                 r = audit_session_from_pid(pid, &c->audit_session_id);
943                 if (r < 0) {
944                         if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
945                                 return r;
946                 } else
947                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
948         }
949
950         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
951                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
952                 if (r < 0) {
953                         if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
954                                 return r;
955                 } else
956                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
957         }
958
959         return 0;
960 }
961
962 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
963         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
964         int r;
965
966         assert(c);
967         assert(ret);
968
969         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
970                 /* There's already all data we need, or augmentation
971                  * wasn't turned on. */
972
973                 *ret = sd_bus_creds_ref(c);
974                 return 0;
975         }
976
977         n = bus_creds_new();
978         if (!n)
979                 return -ENOMEM;
980
981         /* Copy the original data over */
982
983         if (c->mask & mask & SD_BUS_CREDS_UID) {
984                 n->uid = c->uid;
985                 n->mask |= SD_BUS_CREDS_UID;
986         }
987
988         if (c->mask & mask & SD_BUS_CREDS_EUID) {
989                 n->euid = c->euid;
990                 n->mask |= SD_BUS_CREDS_EUID;
991         }
992
993         if (c->mask & mask & SD_BUS_CREDS_SUID) {
994                 n->suid = c->suid;
995                 n->mask |= SD_BUS_CREDS_SUID;
996         }
997
998         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
999                 n->fsuid = c->fsuid;
1000                 n->mask |= SD_BUS_CREDS_FSUID;
1001         }
1002
1003         if (c->mask & mask & SD_BUS_CREDS_GID) {
1004                 n->gid = c->gid;
1005                 n->mask |= SD_BUS_CREDS_GID;
1006         }
1007
1008         if (c->mask & mask & SD_BUS_CREDS_EGID) {
1009                 n->egid = c->egid;
1010                 n->mask |= SD_BUS_CREDS_EGID;
1011         }
1012
1013         if (c->mask & mask & SD_BUS_CREDS_SGID) {
1014                 n->sgid = c->sgid;
1015                 n->mask |= SD_BUS_CREDS_SGID;
1016         }
1017
1018         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
1019                 n->fsgid = c->fsgid;
1020                 n->mask |= SD_BUS_CREDS_FSGID;
1021         }
1022
1023         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
1024                 n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
1025                 if (!n->supplementary_gids)
1026                         return -ENOMEM;
1027                 n->n_supplementary_gids = c->n_supplementary_gids;
1028                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
1029         }
1030
1031         if (c->mask & mask & SD_BUS_CREDS_PID) {
1032                 n->pid = c->pid;
1033                 n->mask |= SD_BUS_CREDS_PID;
1034         }
1035
1036         if (c->mask & mask & SD_BUS_CREDS_TID) {
1037                 n->tid = c->tid;
1038                 n->mask |= SD_BUS_CREDS_TID;
1039         }
1040
1041         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1042                 n->comm = strdup(c->comm);
1043                 if (!n->comm)
1044                         return -ENOMEM;
1045
1046                 n->mask |= SD_BUS_CREDS_COMM;
1047         }
1048
1049         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1050                 n->tid_comm = strdup(c->tid_comm);
1051                 if (!n->tid_comm)
1052                         return -ENOMEM;
1053
1054                 n->mask |= SD_BUS_CREDS_TID_COMM;
1055         }
1056
1057         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1058                 n->exe = strdup(c->exe);
1059                 if (!n->exe)
1060                         return -ENOMEM;
1061
1062                 n->mask |= SD_BUS_CREDS_EXE;
1063         }
1064
1065         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1066                 n->cmdline = memdup(c->cmdline, c->cmdline_size);
1067                 if (!n->cmdline)
1068                         return -ENOMEM;
1069
1070                 n->cmdline_size = c->cmdline_size;
1071                 n->mask |= SD_BUS_CREDS_CMDLINE;
1072         }
1073
1074         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)) {
1075                 n->cgroup = strdup(c->cgroup);
1076                 if (!n->cgroup)
1077                         return -ENOMEM;
1078
1079                 n->cgroup_root = strdup(c->cgroup_root);
1080                 if (!n->cgroup_root)
1081                         return -ENOMEM;
1082
1083                 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);
1084         }
1085
1086         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1087                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1088                 if (!n->capability)
1089                         return -ENOMEM;
1090
1091                 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);
1092         }
1093
1094         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1095                 n->label = strdup(c->label);
1096                 if (!n->label)
1097                         return -ENOMEM;
1098                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1099         }
1100
1101         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1102                 n->audit_session_id = c->audit_session_id;
1103                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1104         }
1105         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1106                 n->audit_login_uid = c->audit_login_uid;
1107                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1108         }
1109
1110         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1111                 n->unique_name = strdup(c->unique_name);
1112                 if (!n->unique_name)
1113                         return -ENOMEM;
1114                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1115         }
1116
1117         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1118                 n->well_known_names = strv_copy(c->well_known_names);
1119                 if (!n->well_known_names)
1120                         return -ENOMEM;
1121                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1122         }
1123
1124         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1125                 n->description = strdup(c->description);
1126                 if (!n->description)
1127                         return -ENOMEM;
1128                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1129         }
1130
1131         /* Get more data */
1132
1133         r = bus_creds_add_more(n, mask,
1134                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
1135                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
1136         if (r < 0)
1137                 return r;
1138
1139         *ret = n;
1140         n = NULL;
1141         return 0;
1142 }