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