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