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