chiark / gitweb /
44adb871e88e515000a6895458f2ca326c30a886
[elogind.git] / src / libelogind / sd-bus / bus-creds.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   Copyright 2013 Lennart Poettering
4 ***/
5
6 #include <linux/capability.h>
7 #include <stdlib.h>
8
9 #include "alloc-util.h"
10 #include "audit-util.h"
11 #include "bus-creds.h"
12 #include "bus-label.h"
13 #include "bus-message.h"
14 #include "bus-util.h"
15 #include "capability-util.h"
16 #include "cgroup-util.h"
17 #include "fd-util.h"
18 #include "fileio.h"
19 #include "format-util.h"
20 #include "hexdecoct.h"
21 #include "parse-util.h"
22 #include "process-util.h"
23 #include "string-util.h"
24 #include "strv.h"
25 #include "terminal-util.h"
26 #include "user-util.h"
27 #include "util.h"
28
29 enum {
30         CAP_OFFSET_INHERITABLE = 0,
31         CAP_OFFSET_PERMITTED = 1,
32         CAP_OFFSET_EFFECTIVE = 2,
33         CAP_OFFSET_BOUNDING = 3
34 };
35
36 void bus_creds_done(sd_bus_creds *c) {
37         assert(c);
38
39         /* For internal bus cred structures that are allocated by
40          * something else */
41
42         free(c->session);
43         free(c->unit);
44         free(c->user_unit);
45         free(c->slice);
46         free(c->user_slice);
47         free(c->unescaped_description);
48         free(c->supplementary_gids);
49         free(c->tty);
50
51         free(c->well_known_names); /* note that this is an strv, but
52                                     * we only free the array, not the
53                                     * strings the array points to. The
54                                     * full strv we only free if
55                                     * c->allocated is set, see
56                                     * below. */
57
58         strv_free(c->cmdline_array);
59 }
60
61 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
62
63         if (!c)
64                 return NULL;
65
66         if (c->allocated) {
67                 assert(c->n_ref > 0);
68                 c->n_ref++;
69         } else {
70                 sd_bus_message *m;
71
72                 /* If this is an embedded creds structure, then
73                  * forward ref counting to the message */
74                 m = container_of(c, sd_bus_message, creds);
75                 sd_bus_message_ref(m);
76         }
77
78         return c;
79 }
80
81 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
82
83         if (!c)
84                 return NULL;
85
86         if (c->allocated) {
87                 assert(c->n_ref > 0);
88                 c->n_ref--;
89
90                 if (c->n_ref == 0) {
91                         free(c->comm);
92                         free(c->tid_comm);
93                         free(c->exe);
94                         free(c->cmdline);
95                         free(c->cgroup);
96                         free(c->capability);
97                         free(c->label);
98                         free(c->unique_name);
99                         free(c->cgroup_root);
100                         free(c->description);
101
102                         c->supplementary_gids = mfree(c->supplementary_gids);
103
104                         c->well_known_names = strv_free(c->well_known_names);
105
106                         bus_creds_done(c);
107
108                         free(c);
109                 }
110         } else {
111                 sd_bus_message *m;
112
113                 m = container_of(c, sd_bus_message, creds);
114                 sd_bus_message_unref(m);
115         }
116
117         return NULL;
118 }
119
120 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
121         assert_return(c, 0);
122
123         return c->mask;
124 }
125
126 _public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
127         assert_return(c, 0);
128
129         return c->augmented;
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_cached();
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 _public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
210         assert_return(c, -EINVAL);
211         assert_return(fsuid, -EINVAL);
212
213         if (!(c->mask & SD_BUS_CREDS_FSUID))
214                 return -ENODATA;
215
216         *fsuid = c->fsuid;
217         return 0;
218 }
219
220 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
221         assert_return(c, -EINVAL);
222         assert_return(gid, -EINVAL);
223
224         if (!(c->mask & SD_BUS_CREDS_GID))
225                 return -ENODATA;
226
227         *gid = c->gid;
228         return 0;
229 }
230
231 _public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
232         assert_return(c, -EINVAL);
233         assert_return(egid, -EINVAL);
234
235         if (!(c->mask & SD_BUS_CREDS_EGID))
236                 return -ENODATA;
237
238         *egid = c->egid;
239         return 0;
240 }
241
242 _public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
243         assert_return(c, -EINVAL);
244         assert_return(sgid, -EINVAL);
245
246         if (!(c->mask & SD_BUS_CREDS_SGID))
247                 return -ENODATA;
248
249         *sgid = c->sgid;
250         return 0;
251 }
252
253 _public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
254         assert_return(c, -EINVAL);
255         assert_return(fsgid, -EINVAL);
256
257         if (!(c->mask & SD_BUS_CREDS_FSGID))
258                 return -ENODATA;
259
260         *fsgid = c->fsgid;
261         return 0;
262 }
263
264 _public_ int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) {
265         assert_return(c, -EINVAL);
266         assert_return(gids, -EINVAL);
267
268         if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
269                 return -ENODATA;
270
271         *gids = c->supplementary_gids;
272         return (int) c->n_supplementary_gids;
273 }
274
275 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
276         assert_return(c, -EINVAL);
277         assert_return(pid, -EINVAL);
278
279         if (!(c->mask & SD_BUS_CREDS_PID))
280                 return -ENODATA;
281
282         assert(c->pid > 0);
283         *pid = c->pid;
284         return 0;
285 }
286
287 _public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
288         assert_return(c, -EINVAL);
289         assert_return(ppid, -EINVAL);
290
291         if (!(c->mask & SD_BUS_CREDS_PPID))
292                 return -ENODATA;
293
294         /* PID 1 has no parent process. Let's distinguish the case of
295          * not knowing and not having a parent process by the returned
296          * error code. */
297         if (c->ppid == 0)
298                 return -ENXIO;
299
300         *ppid = c->ppid;
301         return 0;
302 }
303
304 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
305         assert_return(c, -EINVAL);
306         assert_return(tid, -EINVAL);
307
308         if (!(c->mask & SD_BUS_CREDS_TID))
309                 return -ENODATA;
310
311         assert(c->tid > 0);
312         *tid = c->tid;
313         return 0;
314 }
315
316 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
317         assert_return(c, -EINVAL);
318
319         if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
320                 return -ENODATA;
321
322         assert(c->label);
323         *ret = c->label;
324         return 0;
325 }
326
327 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
328         assert_return(c, -EINVAL);
329         assert_return(ret, -EINVAL);
330
331         if (!(c->mask & SD_BUS_CREDS_COMM))
332                 return -ENODATA;
333
334         assert(c->comm);
335         *ret = c->comm;
336         return 0;
337 }
338
339 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
340         assert_return(c, -EINVAL);
341         assert_return(ret, -EINVAL);
342
343         if (!(c->mask & SD_BUS_CREDS_TID_COMM))
344                 return -ENODATA;
345
346         assert(c->tid_comm);
347         *ret = c->tid_comm;
348         return 0;
349 }
350
351 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
352         assert_return(c, -EINVAL);
353         assert_return(ret, -EINVAL);
354
355         if (!(c->mask & SD_BUS_CREDS_EXE))
356                 return -ENODATA;
357
358         if (!c->exe)
359                 return -ENXIO;
360
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 #if 0 /// UNNEEDED by elogind
378 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
379         int r;
380
381         assert_return(c, -EINVAL);
382         assert_return(ret, -EINVAL);
383
384         if (!(c->mask & SD_BUS_CREDS_UNIT))
385                 return -ENODATA;
386
387         assert(c->cgroup);
388
389         if (!c->unit) {
390                 const char *shifted;
391
392                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
393                 if (r < 0)
394                         return r;
395
396                 r = cg_path_get_unit(shifted, (char**) &c->unit);
397                 if (r < 0)
398                         return r;
399         }
400
401         *ret = c->unit;
402         return 0;
403 }
404
405 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
406         int r;
407
408         assert_return(c, -EINVAL);
409         assert_return(ret, -EINVAL);
410
411         if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
412                 return -ENODATA;
413
414         assert(c->cgroup);
415
416         if (!c->user_unit) {
417                 const char *shifted;
418
419                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
420                 if (r < 0)
421                         return r;
422
423                 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
424                 if (r < 0)
425                         return r;
426         }
427
428         *ret = c->user_unit;
429         return 0;
430 }
431 #endif // 0
432
433 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
434         int r;
435
436         assert_return(c, -EINVAL);
437         assert_return(ret, -EINVAL);
438
439         if (!(c->mask & SD_BUS_CREDS_SLICE))
440                 return -ENODATA;
441
442         assert(c->cgroup);
443
444         if (!c->slice) {
445                 const char *shifted;
446
447                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
448                 if (r < 0)
449                         return r;
450
451                 r = cg_path_get_slice(shifted, (char**) &c->slice);
452                 if (r < 0)
453                         return r;
454         }
455
456         *ret = c->slice;
457         return 0;
458 }
459
460 _public_ int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **ret) {
461         int r;
462
463         assert_return(c, -EINVAL);
464         assert_return(ret, -EINVAL);
465
466         if (!(c->mask & SD_BUS_CREDS_USER_SLICE))
467                 return -ENODATA;
468
469         assert(c->cgroup);
470
471         if (!c->user_slice) {
472                 const char *shifted;
473
474                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
475                 if (r < 0)
476                         return r;
477
478                 r = cg_path_get_user_slice(shifted, (char**) &c->user_slice);
479                 if (r < 0)
480                         return r;
481         }
482
483         *ret = c->user_slice;
484         return 0;
485 }
486
487 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
488         int r;
489
490         assert_return(c, -EINVAL);
491         assert_return(ret, -EINVAL);
492
493         if (!(c->mask & SD_BUS_CREDS_SESSION))
494                 return -ENODATA;
495
496         assert(c->cgroup);
497
498         if (!c->session) {
499                 const char *shifted;
500
501                 log_debug_elogind("Shifting cgroup \"%s\", root \"%s\"",
502                                   c->cgroup, c->cgroup_root ? c->cgroup_root : "NULL");
503                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
504                 if (r < 0)
505                         return r;
506
507                 log_debug_elogind("Shifted: \"%s\"", shifted);
508                 r = cg_path_get_session(shifted, (char**) &c->session);
509                 if (r < 0)
510                         return r;
511         }
512
513         *ret = c->session;
514         return 0;
515 }
516
517 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
518         const char *shifted;
519         int r;
520
521         assert_return(c, -EINVAL);
522         assert_return(uid, -EINVAL);
523
524         if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
525                 return -ENODATA;
526
527         assert(c->cgroup);
528
529         r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
530         log_debug_elogind("Shifted to %s from %s/%s for c->uid %u (result %d)",
531                           shifted, c->cgroup_root, c->cgroup, c->uid, r);
532         if (r < 0)
533                 return r;
534
535         return cg_path_get_owner_uid(shifted, uid);
536 }
537
538 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
539         assert_return(c, -EINVAL);
540
541         if (!(c->mask & SD_BUS_CREDS_CMDLINE))
542                 return -ENODATA;
543
544         if (!c->cmdline)
545                 return -ENXIO;
546
547         if (!c->cmdline_array) {
548                 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
549                 if (!c->cmdline_array)
550                         return -ENOMEM;
551         }
552
553         *cmdline = c->cmdline_array;
554         return 0;
555 }
556
557 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
558         assert_return(c, -EINVAL);
559         assert_return(sessionid, -EINVAL);
560
561         if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
562                 return -ENODATA;
563
564         if (!audit_session_is_valid(c->audit_session_id))
565                 return -ENXIO;
566
567         *sessionid = c->audit_session_id;
568         return 0;
569 }
570
571 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
572         assert_return(c, -EINVAL);
573         assert_return(uid, -EINVAL);
574
575         if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
576                 return -ENODATA;
577
578         if (!uid_is_valid(c->audit_login_uid))
579                 return -ENXIO;
580
581         *uid = c->audit_login_uid;
582         return 0;
583 }
584
585 _public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) {
586         assert_return(c, -EINVAL);
587         assert_return(ret, -EINVAL);
588
589         if (!(c->mask & SD_BUS_CREDS_TTY))
590                 return -ENODATA;
591
592         if (!c->tty)
593                 return -ENXIO;
594
595         *ret = c->tty;
596         return 0;
597 }
598
599 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
600         assert_return(c, -EINVAL);
601         assert_return(unique_name, -EINVAL);
602
603         if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
604                 return -ENODATA;
605
606         *unique_name = c->unique_name;
607         return 0;
608 }
609
610 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
611         assert_return(c, -EINVAL);
612         assert_return(well_known_names, -EINVAL);
613
614         if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
615                 return -ENODATA;
616
617         /* As a special hack we return the bus driver as well-known
618          * names list when this is requested. */
619         if (c->well_known_names_driver) {
620                 static const char* const wkn[] = {
621                         "org.freedesktop.DBus",
622                         NULL
623                 };
624
625                 *well_known_names = (char**) wkn;
626                 return 0;
627         }
628
629         if (c->well_known_names_local) {
630                 static const char* const wkn[] = {
631                         "org.freedesktop.DBus.Local",
632                         NULL
633                 };
634
635                 *well_known_names = (char**) wkn;
636                 return 0;
637         }
638
639         *well_known_names = c->well_known_names;
640         return 0;
641 }
642
643 _public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
644         assert_return(c, -EINVAL);
645         assert_return(ret, -EINVAL);
646
647         if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
648                 return -ENODATA;
649
650         assert(c->description);
651
652         if (!c->unescaped_description) {
653                 c->unescaped_description = bus_label_unescape(c->description);
654                 if (!c->unescaped_description)
655                         return -ENOMEM;
656         }
657
658         *ret = c->unescaped_description;
659         return 0;
660 }
661
662 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
663         size_t sz;
664
665         assert(c);
666         assert(capability >= 0);
667         assert(c->capability);
668
669         if ((unsigned) capability > cap_last_cap())
670                 return 0;
671
672         sz = DIV_ROUND_UP(cap_last_cap(), 32U);
673
674         return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
675 }
676
677 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
678         assert_return(c, -EINVAL);
679         assert_return(capability >= 0, -EINVAL);
680
681         if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
682                 return -ENODATA;
683
684         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
685 }
686
687 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
688         assert_return(c, -EINVAL);
689         assert_return(capability >= 0, -EINVAL);
690
691         if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
692                 return -ENODATA;
693
694         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
695 }
696
697 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
698         assert_return(c, -EINVAL);
699         assert_return(capability >= 0, -EINVAL);
700
701         if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
702                 return -ENODATA;
703
704         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
705 }
706
707 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
708         assert_return(c, -EINVAL);
709         assert_return(capability >= 0, -EINVAL);
710
711         if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
712                 return -ENODATA;
713
714         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
715 }
716
717 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
718         size_t sz, max;
719         unsigned i, j;
720
721         assert(c);
722         assert(p);
723
724         max = DIV_ROUND_UP(cap_last_cap(), 32U);
725         p += strspn(p, WHITESPACE);
726
727         sz = strlen(p);
728         if (sz % 8 != 0)
729                 return -EINVAL;
730
731         sz /= 8;
732         if (sz > max)
733                 return -EINVAL;
734
735         if (!c->capability) {
736                 c->capability = new0(uint32_t, max * 4);
737                 if (!c->capability)
738                         return -ENOMEM;
739         }
740
741         for (i = 0; i < sz; i ++) {
742                 uint32_t v = 0;
743
744                 for (j = 0; j < 8; ++j) {
745                         int t;
746
747                         t = unhexchar(*p++);
748                         if (t < 0)
749                                 return -EINVAL;
750
751                         v = (v << 4) | t;
752                 }
753
754                 c->capability[offset * max + (sz - i - 1)] = v;
755         }
756
757         return 0;
758 }
759
760 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
761         uint64_t missing;
762         int r;
763
764         assert(c);
765         assert(c->allocated);
766
767         if (!(mask & SD_BUS_CREDS_AUGMENT))
768                 return 0;
769
770         /* Try to retrieve PID from creds if it wasn't passed to us */
771         if (pid > 0) {
772                 c->pid = pid;
773                 c->mask |= SD_BUS_CREDS_PID;
774         } else if (c->mask & SD_BUS_CREDS_PID)
775                 pid = c->pid;
776         else
777                 /* Without pid we cannot do much... */
778                 return 0;
779
780         /* Try to retrieve TID from creds if it wasn't passed to us */
781         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
782                 tid = c->tid;
783
784         /* Calculate what we shall and can add */
785         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);
786         if (missing == 0)
787                 return 0;
788
789         if (tid > 0) {
790                 c->tid = tid;
791                 c->mask |= SD_BUS_CREDS_TID;
792         }
793
794         if (missing & (SD_BUS_CREDS_PPID |
795                        SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
796                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
797                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
798                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
799                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
800
801                 _cleanup_fclose_ FILE *f = NULL;
802                 const char *p;
803
804                 p = procfs_file_alloca(pid, "status");
805
806                 f = fopen(p, "re");
807                 if (!f) {
808                         if (errno == ENOENT)
809                                 return -ESRCH;
810                         else if (!IN_SET(errno, EPERM, EACCES))
811                                 return -errno;
812                 } else {
813                         char line[LINE_MAX];
814
815                         FOREACH_LINE(line, f, return -errno) {
816                                 truncate_nl(line);
817
818                                 if (missing & SD_BUS_CREDS_PPID) {
819                                         p = startswith(line, "PPid:");
820                                         if (p) {
821                                                 p += strspn(p, WHITESPACE);
822
823                                                 /* Explicitly check for PPID 0 (which is the case for PID 1) */
824                                                 if (!streq(p, "0")) {
825                                                         r = parse_pid(p, &c->ppid);
826                                                         if (r < 0)
827                                                                 return r;
828
829                                                 } else
830                                                         c->ppid = 0;
831
832                                                 c->mask |= SD_BUS_CREDS_PPID;
833                                                 continue;
834                                         }
835                                 }
836
837                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
838                                         p = startswith(line, "Uid:");
839                                         if (p) {
840                                                 unsigned long uid, euid, suid, fsuid;
841
842                                                 p += strspn(p, WHITESPACE);
843                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
844                                                         return -EIO;
845
846                                                 if (missing & SD_BUS_CREDS_UID)
847                                                         c->uid = (uid_t) uid;
848                                                 if (missing & SD_BUS_CREDS_EUID)
849                                                         c->euid = (uid_t) euid;
850                                                 if (missing & SD_BUS_CREDS_SUID)
851                                                         c->suid = (uid_t) suid;
852                                                 if (missing & SD_BUS_CREDS_FSUID)
853                                                         c->fsuid = (uid_t) fsuid;
854
855                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
856                                                 continue;
857                                         }
858                                 }
859
860                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
861                                         p = startswith(line, "Gid:");
862                                         if (p) {
863                                                 unsigned long gid, egid, sgid, fsgid;
864
865                                                 p += strspn(p, WHITESPACE);
866                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
867                                                         return -EIO;
868
869                                                 if (missing & SD_BUS_CREDS_GID)
870                                                         c->gid = (gid_t) gid;
871                                                 if (missing & SD_BUS_CREDS_EGID)
872                                                         c->egid = (gid_t) egid;
873                                                 if (missing & SD_BUS_CREDS_SGID)
874                                                         c->sgid = (gid_t) sgid;
875                                                 if (missing & SD_BUS_CREDS_FSGID)
876                                                         c->fsgid = (gid_t) fsgid;
877
878                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
879                                                 continue;
880                                         }
881                                 }
882
883                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
884                                         p = startswith(line, "Groups:");
885                                         if (p) {
886                                                 size_t allocated = 0;
887
888                                                 for (;;) {
889                                                         unsigned long g;
890                                                         int n = 0;
891
892                                                         p += strspn(p, WHITESPACE);
893                                                         if (*p == 0)
894                                                                 break;
895
896                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
897                                                                 return -EIO;
898
899                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
900                                                                 return -ENOMEM;
901
902                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
903                                                         p += n;
904                                                 }
905
906                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
907                                                 continue;
908                                         }
909                                 }
910
911                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
912                                         p = startswith(line, "CapEff:");
913                                         if (p) {
914                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
915                                                 if (r < 0)
916                                                         return r;
917
918                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
919                                                 continue;
920                                         }
921                                 }
922
923                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
924                                         p = startswith(line, "CapPrm:");
925                                         if (p) {
926                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
927                                                 if (r < 0)
928                                                         return r;
929
930                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
931                                                 continue;
932                                         }
933                                 }
934
935                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
936                                         p = startswith(line, "CapInh:");
937                                         if (p) {
938                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
939                                                 if (r < 0)
940                                                         return r;
941
942                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
943                                                 continue;
944                                         }
945                                 }
946
947                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
948                                         p = startswith(line, "CapBnd:");
949                                         if (p) {
950                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
951                                                 if (r < 0)
952                                                         return r;
953
954                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
955                                                 continue;
956                                         }
957                                 }
958                         }
959                 }
960         }
961
962         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
963                 const char *p;
964
965                 p = procfs_file_alloca(pid, "attr/current");
966                 r = read_one_line_file(p, &c->label);
967                 if (r < 0) {
968                         if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES))
969                                 return r;
970                 } else
971                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
972         }
973
974         if (missing & SD_BUS_CREDS_COMM) {
975                 r = get_process_comm(pid, &c->comm);
976                 if (r < 0) {
977                         if (!IN_SET(r, -EPERM, -EACCES))
978                                 return r;
979                 } else
980                         c->mask |= SD_BUS_CREDS_COMM;
981         }
982
983         if (missing & SD_BUS_CREDS_EXE) {
984                 r = get_process_exe(pid, &c->exe);
985                 if (r == -ESRCH) {
986                         /* Unfortunately we cannot really distinguish
987                          * the case here where the process does not
988                          * exist, and /proc/$PID/exe being unreadable
989                          * because $PID is a kernel thread. Hence,
990                          * assume it is a kernel thread, and rely on
991                          * that this case is caught with a later
992                          * call. */
993                         c->exe = NULL;
994                         c->mask |= SD_BUS_CREDS_EXE;
995                 } else if (r < 0) {
996                         if (!IN_SET(r, -EPERM, -EACCES))
997                                 return r;
998                 } else
999                         c->mask |= SD_BUS_CREDS_EXE;
1000         }
1001
1002         if (missing & SD_BUS_CREDS_CMDLINE) {
1003                 const char *p;
1004
1005                 p = procfs_file_alloca(pid, "cmdline");
1006                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
1007                 if (r == -ENOENT)
1008                         return -ESRCH;
1009                 if (r < 0) {
1010                         if (!IN_SET(r, -EPERM, -EACCES))
1011                                 return r;
1012                 } else {
1013                         if (c->cmdline_size == 0)
1014                                 c->cmdline = mfree(c->cmdline);
1015
1016                         c->mask |= SD_BUS_CREDS_CMDLINE;
1017                 }
1018         }
1019
1020         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
1021                 _cleanup_free_ char *p = NULL;
1022
1023                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
1024                         return -ENOMEM;
1025
1026                 r = read_one_line_file(p, &c->tid_comm);
1027                 if (r == -ENOENT)
1028                         return -ESRCH;
1029                 if (r < 0) {
1030                         if (!IN_SET(r, -EPERM, -EACCES))
1031                                 return r;
1032                 } else
1033                         c->mask |= SD_BUS_CREDS_TID_COMM;
1034         }
1035
1036         if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
1037
1038                 if (!c->cgroup) {
1039                         r = cg_pid_get_path(NULL, pid, &c->cgroup);
1040                         if (r < 0) {
1041                                 if (!IN_SET(r, -EPERM, -EACCES))
1042                                         return r;
1043                         }
1044                 }
1045
1046                 if (!c->cgroup_root) {
1047                         r = cg_get_root_path(&c->cgroup_root);
1048                         if (r < 0)
1049                                 return r;
1050                 }
1051
1052                 if (c->cgroup)
1053                         c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
1054         }
1055
1056         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1057                 r = audit_session_from_pid(pid, &c->audit_session_id);
1058                 if (r == -ENODATA) {
1059                         /* ENODATA means: no audit session id assigned */
1060                         c->audit_session_id = AUDIT_SESSION_INVALID;
1061                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1062                 } else if (r < 0) {
1063                         if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES))
1064                                 return r;
1065                 } else
1066                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1067         }
1068
1069         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1070                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
1071                 if (r == -ENODATA) {
1072                         /* ENODATA means: no audit login uid assigned */
1073                         c->audit_login_uid = UID_INVALID;
1074                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1075                 } else if (r < 0) {
1076                         if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES))
1077                                 return r;
1078                 } else
1079                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1080         }
1081
1082         if (missing & SD_BUS_CREDS_TTY) {
1083                 r = get_ctty(pid, NULL, &c->tty);
1084                 if (r == -ENXIO) {
1085                         /* ENXIO means: process has no controlling TTY */
1086                         c->tty = NULL;
1087                         c->mask |= SD_BUS_CREDS_TTY;
1088                 } else if (r < 0) {
1089                         if (!IN_SET(r, -EPERM, -EACCES, -ENOENT))
1090                                 return r;
1091                 } else
1092                         c->mask |= SD_BUS_CREDS_TTY;
1093         }
1094
1095         /* In case only the exe path was to be read we cannot
1096          * distinguish the case where the exe path was unreadable
1097          * because the process was a kernel thread, or when the
1098          * process didn't exist at all. Hence, let's do a final check,
1099          * to be sure. */
1100         if (!pid_is_alive(pid))
1101                 return -ESRCH;
1102
1103         if (tid > 0 && tid != pid && !pid_is_unwaited(tid))
1104                 return -ESRCH;
1105
1106         c->augmented = missing & c->mask;
1107
1108         return 0;
1109 }
1110
1111 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
1112         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *n = NULL;
1113         int r;
1114
1115         assert(c);
1116         assert(ret);
1117
1118         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
1119                 /* There's already all data we need, or augmentation
1120                  * wasn't turned on. */
1121
1122                 *ret = sd_bus_creds_ref(c);
1123                 return 0;
1124         }
1125
1126         n = bus_creds_new();
1127         if (!n)
1128                 return -ENOMEM;
1129
1130         /* Copy the original data over */
1131
1132         if (c->mask & mask & SD_BUS_CREDS_PID) {
1133                 n->pid = c->pid;
1134                 n->mask |= SD_BUS_CREDS_PID;
1135         }
1136
1137         if (c->mask & mask & SD_BUS_CREDS_TID) {
1138                 n->tid = c->tid;
1139                 n->mask |= SD_BUS_CREDS_TID;
1140         }
1141
1142         if (c->mask & mask & SD_BUS_CREDS_PPID) {
1143                 n->ppid = c->ppid;
1144                 n->mask |= SD_BUS_CREDS_PPID;
1145         }
1146
1147         if (c->mask & mask & SD_BUS_CREDS_UID) {
1148                 n->uid = c->uid;
1149                 n->mask |= SD_BUS_CREDS_UID;
1150         }
1151
1152         if (c->mask & mask & SD_BUS_CREDS_EUID) {
1153                 n->euid = c->euid;
1154                 n->mask |= SD_BUS_CREDS_EUID;
1155         }
1156
1157         if (c->mask & mask & SD_BUS_CREDS_SUID) {
1158                 n->suid = c->suid;
1159                 n->mask |= SD_BUS_CREDS_SUID;
1160         }
1161
1162         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
1163                 n->fsuid = c->fsuid;
1164                 n->mask |= SD_BUS_CREDS_FSUID;
1165         }
1166
1167         if (c->mask & mask & SD_BUS_CREDS_GID) {
1168                 n->gid = c->gid;
1169                 n->mask |= SD_BUS_CREDS_GID;
1170         }
1171
1172         if (c->mask & mask & SD_BUS_CREDS_EGID) {
1173                 n->egid = c->egid;
1174                 n->mask |= SD_BUS_CREDS_EGID;
1175         }
1176
1177         if (c->mask & mask & SD_BUS_CREDS_SGID) {
1178                 n->sgid = c->sgid;
1179                 n->mask |= SD_BUS_CREDS_SGID;
1180         }
1181
1182         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
1183                 n->fsgid = c->fsgid;
1184                 n->mask |= SD_BUS_CREDS_FSGID;
1185         }
1186
1187         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
1188                 if (c->supplementary_gids) {
1189                         n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
1190                         if (!n->supplementary_gids)
1191                                 return -ENOMEM;
1192                         n->n_supplementary_gids = c->n_supplementary_gids;
1193                 } else {
1194                         n->supplementary_gids = NULL;
1195                         n->n_supplementary_gids = 0;
1196                 }
1197
1198                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
1199         }
1200
1201         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1202                 assert(c->comm);
1203
1204                 n->comm = strdup(c->comm);
1205                 if (!n->comm)
1206                         return -ENOMEM;
1207
1208                 n->mask |= SD_BUS_CREDS_COMM;
1209         }
1210
1211         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1212                 assert(c->tid_comm);
1213
1214                 n->tid_comm = strdup(c->tid_comm);
1215                 if (!n->tid_comm)
1216                         return -ENOMEM;
1217
1218                 n->mask |= SD_BUS_CREDS_TID_COMM;
1219         }
1220
1221         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1222                 if (c->exe) {
1223                         n->exe = strdup(c->exe);
1224                         if (!n->exe)
1225                                 return -ENOMEM;
1226                 } else
1227                         n->exe = NULL;
1228
1229                 n->mask |= SD_BUS_CREDS_EXE;
1230         }
1231
1232         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1233                 if (c->cmdline) {
1234                         n->cmdline = memdup(c->cmdline, c->cmdline_size);
1235                         if (!n->cmdline)
1236                                 return -ENOMEM;
1237
1238                         n->cmdline_size = c->cmdline_size;
1239                 } else {
1240                         n->cmdline = NULL;
1241                         n->cmdline_size = 0;
1242                 }
1243
1244                 n->mask |= SD_BUS_CREDS_CMDLINE;
1245         }
1246
1247         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_USER_SLICE|SD_BUS_CREDS_OWNER_UID)) {
1248                 assert(c->cgroup);
1249
1250                 n->cgroup = strdup(c->cgroup);
1251                 if (!n->cgroup)
1252                         return -ENOMEM;
1253
1254                 n->cgroup_root = strdup(c->cgroup_root);
1255                 if (!n->cgroup_root)
1256                         return -ENOMEM;
1257
1258                 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_USER_SLICE|SD_BUS_CREDS_OWNER_UID);
1259         }
1260
1261         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1262                 assert(c->capability);
1263
1264                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1265                 if (!n->capability)
1266                         return -ENOMEM;
1267
1268                 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);
1269         }
1270
1271         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1272                 assert(c->label);
1273
1274                 n->label = strdup(c->label);
1275                 if (!n->label)
1276                         return -ENOMEM;
1277                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1278         }
1279
1280         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1281                 n->audit_session_id = c->audit_session_id;
1282                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1283         }
1284         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1285                 n->audit_login_uid = c->audit_login_uid;
1286                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1287         }
1288
1289         if (c->mask & mask & SD_BUS_CREDS_TTY) {
1290                 if (c->tty) {
1291                         n->tty = strdup(c->tty);
1292                         if (!n->tty)
1293                                 return -ENOMEM;
1294                 } else
1295                         n->tty = NULL;
1296                 n->mask |= SD_BUS_CREDS_TTY;
1297         }
1298
1299         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1300                 assert(c->unique_name);
1301
1302                 n->unique_name = strdup(c->unique_name);
1303                 if (!n->unique_name)
1304                         return -ENOMEM;
1305                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1306         }
1307
1308         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1309                 if (strv_isempty(c->well_known_names))
1310                         n->well_known_names = NULL;
1311                 else {
1312                         n->well_known_names = strv_copy(c->well_known_names);
1313                         if (!n->well_known_names)
1314                                 return -ENOMEM;
1315                 }
1316                 n->well_known_names_driver = c->well_known_names_driver;
1317                 n->well_known_names_local = c->well_known_names_local;
1318                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1319         }
1320
1321         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1322                 assert(c->description);
1323                 n->description = strdup(c->description);
1324                 if (!n->description)
1325                         return -ENOMEM;
1326                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1327         }
1328
1329         n->augmented = c->augmented & n->mask;
1330
1331         /* Get more data */
1332
1333         r = bus_creds_add_more(n, mask, 0, 0);
1334         if (r < 0)
1335                 return r;
1336
1337         *ret = TAKE_PTR(n);
1338
1339         return 0;
1340 }