chiark / gitweb /
Classify processes from sessions into cgroups
[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 /// elogind does not support systemd slices
559 #if 0
560         return cg_path_get_owner_uid(shifted, uid);
561 #else
562         *uid = c->uid;
563         return 0;
564 #endif // 0
565 }
566
567 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
568         assert_return(c, -EINVAL);
569
570         if (!(c->mask & SD_BUS_CREDS_CMDLINE))
571                 return -ENODATA;
572
573         if (!c->cmdline)
574                 return -ENXIO;
575
576         if (!c->cmdline_array) {
577                 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
578                 if (!c->cmdline_array)
579                         return -ENOMEM;
580         }
581
582         *cmdline = c->cmdline_array;
583         return 0;
584 }
585
586 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
587         assert_return(c, -EINVAL);
588         assert_return(sessionid, -EINVAL);
589
590         if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
591                 return -ENODATA;
592
593         if (c->audit_session_id == AUDIT_SESSION_INVALID)
594                 return -ENXIO;
595
596         *sessionid = c->audit_session_id;
597         return 0;
598 }
599
600 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
601         assert_return(c, -EINVAL);
602         assert_return(uid, -EINVAL);
603
604         if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
605                 return -ENODATA;
606
607         if (c->audit_login_uid == UID_INVALID)
608                 return -ENXIO;
609
610         *uid = c->audit_login_uid;
611         return 0;
612 }
613
614 _public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) {
615         assert_return(c, -EINVAL);
616         assert_return(ret, -EINVAL);
617
618         if (!(c->mask & SD_BUS_CREDS_TTY))
619                 return -ENODATA;
620
621         if (!c->tty)
622                 return -ENXIO;
623
624         *ret = c->tty;
625         return 0;
626 }
627
628 /// UNNEEDED by elogind
629 #if 0
630 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
631         assert_return(c, -EINVAL);
632         assert_return(unique_name, -EINVAL);
633
634         if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
635                 return -ENODATA;
636
637         *unique_name = c->unique_name;
638         return 0;
639 }
640
641 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
642         assert_return(c, -EINVAL);
643         assert_return(well_known_names, -EINVAL);
644
645         if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
646                 return -ENODATA;
647
648         /* As a special hack we return the bus driver as well-known
649          * names list when this is requested. */
650         if (c->well_known_names_driver) {
651                 static const char* const wkn[] = {
652                         "org.freedesktop.DBus",
653                         NULL
654                 };
655
656                 *well_known_names = (char**) wkn;
657                 return 0;
658         }
659
660         if (c->well_known_names_local) {
661                 static const char* const wkn[] = {
662                         "org.freedesktop.DBus.Local",
663                         NULL
664                 };
665
666                 *well_known_names = (char**) wkn;
667                 return 0;
668         }
669
670         *well_known_names = c->well_known_names;
671         return 0;
672 }
673
674 _public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
675         assert_return(c, -EINVAL);
676         assert_return(ret, -EINVAL);
677
678         if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
679                 return -ENODATA;
680
681         assert(c->description);
682
683         if (!c->unescaped_description) {
684                 c->unescaped_description = bus_label_unescape(c->description);
685                 if (!c->unescaped_description)
686                         return -ENOMEM;
687         }
688
689         *ret = c->unescaped_description;
690         return 0;
691 }
692 #endif // 0
693
694 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
695         size_t sz;
696
697         assert(c);
698         assert(capability >= 0);
699         assert(c->capability);
700
701         if ((unsigned) capability > cap_last_cap())
702                 return 0;
703
704         sz = DIV_ROUND_UP(cap_last_cap(), 32U);
705
706         return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
707 }
708
709 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
710         assert_return(c, -EINVAL);
711         assert_return(capability >= 0, -EINVAL);
712
713         if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
714                 return -ENODATA;
715
716         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
717 }
718
719 /// UNNEEDED by elogind
720 #if 0
721 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
722         assert_return(c, -EINVAL);
723         assert_return(capability >= 0, -EINVAL);
724
725         if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
726                 return -ENODATA;
727
728         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
729 }
730
731 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
732         assert_return(c, -EINVAL);
733         assert_return(capability >= 0, -EINVAL);
734
735         if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
736                 return -ENODATA;
737
738         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
739 }
740
741 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
742         assert_return(c, -EINVAL);
743         assert_return(capability >= 0, -EINVAL);
744
745         if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
746                 return -ENODATA;
747
748         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
749 }
750 #endif // 0
751
752 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
753         size_t sz, max;
754         unsigned i, j;
755
756         assert(c);
757         assert(p);
758
759         max = DIV_ROUND_UP(cap_last_cap(), 32U);
760         p += strspn(p, WHITESPACE);
761
762         sz = strlen(p);
763         if (sz % 8 != 0)
764                 return -EINVAL;
765
766         sz /= 8;
767         if (sz > max)
768                 return -EINVAL;
769
770         if (!c->capability) {
771                 c->capability = new0(uint32_t, max * 4);
772                 if (!c->capability)
773                         return -ENOMEM;
774         }
775
776         for (i = 0; i < sz; i ++) {
777                 uint32_t v = 0;
778
779                 for (j = 0; j < 8; ++j) {
780                         int t;
781
782                         t = unhexchar(*p++);
783                         if (t < 0)
784                                 return -EINVAL;
785
786                         v = (v << 4) | t;
787                 }
788
789                 c->capability[offset * max + (sz - i - 1)] = v;
790         }
791
792         return 0;
793 }
794
795 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
796         uint64_t missing;
797         int r;
798
799         assert(c);
800         assert(c->allocated);
801
802         if (!(mask & SD_BUS_CREDS_AUGMENT))
803                 return 0;
804
805         /* Try to retrieve PID from creds if it wasn't passed to us */
806         if (pid > 0) {
807                 c->pid = pid;
808                 c->mask |= SD_BUS_CREDS_PID;
809         } else if (c->mask & SD_BUS_CREDS_PID)
810                 pid = c->pid;
811         else
812                 /* Without pid we cannot do much... */
813                 return 0;
814
815         /* Try to retrieve TID from creds if it wasn't passed to us */
816         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
817                 tid = c->tid;
818
819         /* Calculate what we shall and can add */
820         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);
821         if (missing == 0)
822                 return 0;
823
824         if (tid > 0) {
825                 c->tid = tid;
826                 c->mask |= SD_BUS_CREDS_TID;
827         }
828
829         if (missing & (SD_BUS_CREDS_PPID |
830                        SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
831                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
832                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
833                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
834                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
835
836                 _cleanup_fclose_ FILE *f = NULL;
837                 const char *p;
838
839                 p = procfs_file_alloca(pid, "status");
840
841                 f = fopen(p, "re");
842                 if (!f) {
843                         if (errno == ENOENT)
844                                 return -ESRCH;
845                         else if (errno != EPERM && errno != EACCES)
846                                 return -errno;
847                 } else {
848                         char line[LINE_MAX];
849
850                         FOREACH_LINE(line, f, return -errno) {
851                                 truncate_nl(line);
852
853                                 if (missing & SD_BUS_CREDS_PPID) {
854                                         p = startswith(line, "PPid:");
855                                         if (p) {
856                                                 p += strspn(p, WHITESPACE);
857
858                                                 /* Explicitly check for PPID 0 (which is the case for PID 1) */
859                                                 if (!streq(p, "0")) {
860                                                         r = parse_pid(p, &c->ppid);
861                                                         if (r < 0)
862                                                                 return r;
863
864                                                 } else
865                                                         c->ppid = 0;
866
867                                                 c->mask |= SD_BUS_CREDS_PPID;
868                                                 continue;
869                                         }
870                                 }
871
872                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
873                                         p = startswith(line, "Uid:");
874                                         if (p) {
875                                                 unsigned long uid, euid, suid, fsuid;
876
877                                                 p += strspn(p, WHITESPACE);
878                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
879                                                         return -EIO;
880
881                                                 if (missing & SD_BUS_CREDS_UID)
882                                                         c->uid = (uid_t) uid;
883                                                 if (missing & SD_BUS_CREDS_EUID)
884                                                         c->euid = (uid_t) euid;
885                                                 if (missing & SD_BUS_CREDS_SUID)
886                                                         c->suid = (uid_t) suid;
887                                                 if (missing & SD_BUS_CREDS_FSUID)
888                                                         c->fsuid = (uid_t) fsuid;
889
890                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
891                                                 continue;
892                                         }
893                                 }
894
895                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
896                                         p = startswith(line, "Gid:");
897                                         if (p) {
898                                                 unsigned long gid, egid, sgid, fsgid;
899
900                                                 p += strspn(p, WHITESPACE);
901                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
902                                                         return -EIO;
903
904                                                 if (missing & SD_BUS_CREDS_GID)
905                                                         c->gid = (gid_t) gid;
906                                                 if (missing & SD_BUS_CREDS_EGID)
907                                                         c->egid = (gid_t) egid;
908                                                 if (missing & SD_BUS_CREDS_SGID)
909                                                         c->sgid = (gid_t) sgid;
910                                                 if (missing & SD_BUS_CREDS_FSGID)
911                                                         c->fsgid = (gid_t) fsgid;
912
913                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
914                                                 continue;
915                                         }
916                                 }
917
918                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
919                                         p = startswith(line, "Groups:");
920                                         if (p) {
921                                                 size_t allocated = 0;
922
923                                                 for (;;) {
924                                                         unsigned long g;
925                                                         int n = 0;
926
927                                                         p += strspn(p, WHITESPACE);
928                                                         if (*p == 0)
929                                                                 break;
930
931                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
932                                                                 return -EIO;
933
934                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
935                                                                 return -ENOMEM;
936
937                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
938                                                         p += n;
939                                                 }
940
941                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
942                                                 continue;
943                                         }
944                                 }
945
946                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
947                                         p = startswith(line, "CapEff:");
948                                         if (p) {
949                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
950                                                 if (r < 0)
951                                                         return r;
952
953                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
954                                                 continue;
955                                         }
956                                 }
957
958                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
959                                         p = startswith(line, "CapPrm:");
960                                         if (p) {
961                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
962                                                 if (r < 0)
963                                                         return r;
964
965                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
966                                                 continue;
967                                         }
968                                 }
969
970                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
971                                         p = startswith(line, "CapInh:");
972                                         if (p) {
973                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
974                                                 if (r < 0)
975                                                         return r;
976
977                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
978                                                 continue;
979                                         }
980                                 }
981
982                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
983                                         p = startswith(line, "CapBnd:");
984                                         if (p) {
985                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
986                                                 if (r < 0)
987                                                         return r;
988
989                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
990                                                 continue;
991                                         }
992                                 }
993                         }
994                 }
995         }
996
997         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
998                 const char *p;
999
1000                 p = procfs_file_alloca(pid, "attr/current");
1001                 r = read_one_line_file(p, &c->label);
1002                 if (r < 0) {
1003                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
1004                                 return r;
1005                 } else
1006                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1007         }
1008
1009         if (missing & SD_BUS_CREDS_COMM) {
1010                 r = get_process_comm(pid, &c->comm);
1011                 if (r < 0) {
1012                         if (r != -EPERM && r != -EACCES)
1013                                 return r;
1014                 } else
1015                         c->mask |= SD_BUS_CREDS_COMM;
1016         }
1017
1018         if (missing & SD_BUS_CREDS_EXE) {
1019                 r = get_process_exe(pid, &c->exe);
1020                 if (r == -ESRCH) {
1021                         /* Unfortunately we cannot really distinguish
1022                          * the case here where the process does not
1023                          * exist, and /proc/$PID/exe being unreadable
1024                          * because $PID is a kernel thread. Hence,
1025                          * assume it is a kernel thread, and rely on
1026                          * that this case is caught with a later
1027                          * call. */
1028                         c->exe = NULL;
1029                         c->mask |= SD_BUS_CREDS_EXE;
1030                 } else if (r < 0) {
1031                         if (r != -EPERM && r != -EACCES)
1032                                 return r;
1033                 } else
1034                         c->mask |= SD_BUS_CREDS_EXE;
1035         }
1036
1037         if (missing & SD_BUS_CREDS_CMDLINE) {
1038                 const char *p;
1039
1040                 p = procfs_file_alloca(pid, "cmdline");
1041                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
1042                 if (r == -ENOENT)
1043                         return -ESRCH;
1044                 if (r < 0) {
1045                         if (r != -EPERM && r != -EACCES)
1046                                 return r;
1047                 } else {
1048                         if (c->cmdline_size == 0) {
1049                                 free(c->cmdline);
1050                                 c->cmdline = NULL;
1051                         }
1052
1053                         c->mask |= SD_BUS_CREDS_CMDLINE;
1054                 }
1055         }
1056
1057         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
1058                 _cleanup_free_ char *p = NULL;
1059
1060                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
1061                         return -ENOMEM;
1062
1063                 r = read_one_line_file(p, &c->tid_comm);
1064                 if (r == -ENOENT)
1065                         return -ESRCH;
1066                 if (r < 0) {
1067                         if (r != -EPERM && r != -EACCES)
1068                                 return r;
1069                 } else
1070                         c->mask |= SD_BUS_CREDS_TID_COMM;
1071         }
1072
1073         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)) {
1074
1075                 if (!c->cgroup) {
1076                         r = cg_pid_get_path(NULL, pid, &c->cgroup);
1077                         if (r < 0) {
1078                                 if (r != -EPERM && r != -EACCES)
1079                                         return r;
1080                         }
1081                 }
1082
1083                 if (!c->cgroup_root) {
1084                         r = cg_get_root_path(&c->cgroup_root);
1085                         if (r < 0)
1086                                 return r;
1087                 }
1088
1089                 if (c->cgroup)
1090                         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);
1091         }
1092
1093         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1094                 r = audit_session_from_pid(pid, &c->audit_session_id);
1095                 if (r == -ENODATA) {
1096                         /* ENODATA means: no audit session id assigned */
1097                         c->audit_session_id = AUDIT_SESSION_INVALID;
1098                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1099                 } else if (r < 0) {
1100                         if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
1101                                 return r;
1102                 } else
1103                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1104         }
1105
1106         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1107                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
1108                 if (r == -ENODATA) {
1109                         /* ENODATA means: no audit login uid assigned */
1110                         c->audit_login_uid = UID_INVALID;
1111                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1112                 } else if (r < 0) {
1113                         if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
1114                                 return r;
1115                 } else
1116                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1117         }
1118
1119         if (missing & SD_BUS_CREDS_TTY) {
1120                 r = get_ctty(pid, NULL, &c->tty);
1121                 if (r == -ENXIO) {
1122                         /* ENXIO means: process has no controlling TTY */
1123                         c->tty = NULL;
1124                         c->mask |= SD_BUS_CREDS_TTY;
1125                 } else if (r < 0) {
1126                         if (r != -EPERM && r != -EACCES && r != -ENOENT)
1127                                 return r;
1128                 } else
1129                         c->mask |= SD_BUS_CREDS_TTY;
1130         }
1131
1132         /* In case only the exe path was to be read we cannot
1133          * distinguish the case where the exe path was unreadable
1134          * because the process was a kernel thread, or when the
1135          * process didn't exist at all. Hence, let's do a final check,
1136          * to be sure. */
1137         if (!pid_is_alive(pid))
1138                 return -ESRCH;
1139
1140         if (tid > 0 && tid != pid && !pid_is_unwaited(tid))
1141                 return -ESRCH;
1142
1143         c->augmented = missing & c->mask;
1144
1145         return 0;
1146 }
1147
1148 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
1149         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
1150         int r;
1151
1152         assert(c);
1153         assert(ret);
1154
1155         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
1156                 /* There's already all data we need, or augmentation
1157                  * wasn't turned on. */
1158
1159                 *ret = sd_bus_creds_ref(c);
1160                 return 0;
1161         }
1162
1163         n = bus_creds_new();
1164         if (!n)
1165                 return -ENOMEM;
1166
1167         /* Copy the original data over */
1168
1169         if (c->mask & mask & SD_BUS_CREDS_PID) {
1170                 n->pid = c->pid;
1171                 n->mask |= SD_BUS_CREDS_PID;
1172         }
1173
1174         if (c->mask & mask & SD_BUS_CREDS_TID) {
1175                 n->tid = c->tid;
1176                 n->mask |= SD_BUS_CREDS_TID;
1177         }
1178
1179         if (c->mask & mask & SD_BUS_CREDS_PPID) {
1180                 n->ppid = c->ppid;
1181                 n->mask |= SD_BUS_CREDS_PPID;
1182         }
1183
1184         if (c->mask & mask & SD_BUS_CREDS_UID) {
1185                 n->uid = c->uid;
1186                 n->mask |= SD_BUS_CREDS_UID;
1187         }
1188
1189         if (c->mask & mask & SD_BUS_CREDS_EUID) {
1190                 n->euid = c->euid;
1191                 n->mask |= SD_BUS_CREDS_EUID;
1192         }
1193
1194         if (c->mask & mask & SD_BUS_CREDS_SUID) {
1195                 n->suid = c->suid;
1196                 n->mask |= SD_BUS_CREDS_SUID;
1197         }
1198
1199         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
1200                 n->fsuid = c->fsuid;
1201                 n->mask |= SD_BUS_CREDS_FSUID;
1202         }
1203
1204         if (c->mask & mask & SD_BUS_CREDS_GID) {
1205                 n->gid = c->gid;
1206                 n->mask |= SD_BUS_CREDS_GID;
1207         }
1208
1209         if (c->mask & mask & SD_BUS_CREDS_EGID) {
1210                 n->egid = c->egid;
1211                 n->mask |= SD_BUS_CREDS_EGID;
1212         }
1213
1214         if (c->mask & mask & SD_BUS_CREDS_SGID) {
1215                 n->sgid = c->sgid;
1216                 n->mask |= SD_BUS_CREDS_SGID;
1217         }
1218
1219         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
1220                 n->fsgid = c->fsgid;
1221                 n->mask |= SD_BUS_CREDS_FSGID;
1222         }
1223
1224         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
1225                 if (c->supplementary_gids) {
1226                         n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
1227                         if (!n->supplementary_gids)
1228                                 return -ENOMEM;
1229                         n->n_supplementary_gids = c->n_supplementary_gids;
1230                 } else {
1231                         n->supplementary_gids = NULL;
1232                         n->n_supplementary_gids = 0;
1233                 }
1234
1235                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
1236         }
1237
1238         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1239                 assert(c->comm);
1240
1241                 n->comm = strdup(c->comm);
1242                 if (!n->comm)
1243                         return -ENOMEM;
1244
1245                 n->mask |= SD_BUS_CREDS_COMM;
1246         }
1247
1248         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1249                 assert(c->tid_comm);
1250
1251                 n->tid_comm = strdup(c->tid_comm);
1252                 if (!n->tid_comm)
1253                         return -ENOMEM;
1254
1255                 n->mask |= SD_BUS_CREDS_TID_COMM;
1256         }
1257
1258         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1259                 if (c->exe) {
1260                         n->exe = strdup(c->exe);
1261                         if (!n->exe)
1262                                 return -ENOMEM;
1263                 } else
1264                         n->exe = NULL;
1265
1266                 n->mask |= SD_BUS_CREDS_EXE;
1267         }
1268
1269         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1270                 if (c->cmdline) {
1271                         n->cmdline = memdup(c->cmdline, c->cmdline_size);
1272                         if (!n->cmdline)
1273                                 return -ENOMEM;
1274
1275                         n->cmdline_size = c->cmdline_size;
1276                 } else {
1277                         n->cmdline = NULL;
1278                         n->cmdline_size = 0;
1279                 }
1280
1281                 n->mask |= SD_BUS_CREDS_CMDLINE;
1282         }
1283
1284         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)) {
1285                 assert(c->cgroup);
1286
1287                 n->cgroup = strdup(c->cgroup);
1288                 if (!n->cgroup)
1289                         return -ENOMEM;
1290
1291                 n->cgroup_root = strdup(c->cgroup_root);
1292                 if (!n->cgroup_root)
1293                         return -ENOMEM;
1294
1295                 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);
1296         }
1297
1298         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1299                 assert(c->capability);
1300
1301                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1302                 if (!n->capability)
1303                         return -ENOMEM;
1304
1305                 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);
1306         }
1307
1308         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1309                 assert(c->label);
1310
1311                 n->label = strdup(c->label);
1312                 if (!n->label)
1313                         return -ENOMEM;
1314                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1315         }
1316
1317         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1318                 n->audit_session_id = c->audit_session_id;
1319                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1320         }
1321         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1322                 n->audit_login_uid = c->audit_login_uid;
1323                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1324         }
1325
1326         if (c->mask & mask & SD_BUS_CREDS_TTY) {
1327                 if (c->tty) {
1328                         n->tty = strdup(c->tty);
1329                         if (!n->tty)
1330                                 return -ENOMEM;
1331                 } else
1332                         n->tty = NULL;
1333                 n->mask |= SD_BUS_CREDS_TTY;
1334         }
1335
1336         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1337                 assert(c->unique_name);
1338
1339                 n->unique_name = strdup(c->unique_name);
1340                 if (!n->unique_name)
1341                         return -ENOMEM;
1342                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1343         }
1344
1345         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1346                 if (strv_isempty(c->well_known_names))
1347                         n->well_known_names = NULL;
1348                 else {
1349                         n->well_known_names = strv_copy(c->well_known_names);
1350                         if (!n->well_known_names)
1351                                 return -ENOMEM;
1352                 }
1353                 n->well_known_names_driver = c->well_known_names_driver;
1354                 n->well_known_names_local = c->well_known_names_local;
1355                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1356         }
1357
1358         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1359                 assert(c->description);
1360                 n->description = strdup(c->description);
1361                 if (!n->description)
1362                         return -ENOMEM;
1363                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1364         }
1365
1366         n->augmented = c->augmented & n->mask;
1367
1368         /* Get more data */
1369
1370         r = bus_creds_add_more(n, mask, 0, 0);
1371         if (r < 0)
1372                 return r;
1373
1374         *ret = n;
1375         n = NULL;
1376         return 0;
1377 }