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