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