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