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