chiark / gitweb /
sd-bus: update to current kernel version, by splitting off the extended KDBUS_ITEM_PI...
[elogind.git] / src / libsystemd / 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
24 #include "util.h"
25 #include "cgroup-util.h"
26 #include "fileio.h"
27 #include "audit.h"
28 #include "bus-message.h"
29 #include "bus-util.h"
30 #include "time-util.h"
31 #include "strv.h"
32 #include "bus-creds.h"
33 #include "bus-label.h"
34
35 enum {
36         CAP_OFFSET_INHERITABLE = 0,
37         CAP_OFFSET_PERMITTED = 1,
38         CAP_OFFSET_EFFECTIVE = 2,
39         CAP_OFFSET_BOUNDING = 3
40 };
41
42 void bus_creds_done(sd_bus_creds *c) {
43         assert(c);
44
45         /* For internal bus cred structures that are allocated by
46          * something else */
47
48         free(c->session);
49         free(c->unit);
50         free(c->user_unit);
51         free(c->slice);
52         free(c->unescaped_description);
53
54         strv_free(c->cmdline_array);
55         strv_free(c->well_known_names);
56 }
57
58 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
59         assert_return(c, NULL);
60
61         if (c->allocated) {
62                 assert(c->n_ref > 0);
63                 c->n_ref++;
64         } else {
65                 sd_bus_message *m;
66
67                 /* If this is an embedded creds structure, then
68                  * forward ref counting to the message */
69                 m = container_of(c, sd_bus_message, creds);
70                 sd_bus_message_ref(m);
71         }
72
73         return c;
74 }
75
76 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
77
78         if (!c)
79                 return NULL;
80
81         if (c->allocated) {
82                 assert(c->n_ref > 0);
83                 c->n_ref--;
84
85                 if (c->n_ref == 0) {
86                         bus_creds_done(c);
87
88                         free(c->comm);
89                         free(c->tid_comm);
90                         free(c->exe);
91                         free(c->cmdline);
92                         free(c->cgroup);
93                         free(c->capability);
94                         free(c->label);
95                         free(c->unique_name);
96                         free(c->cgroup_root);
97                         free(c->description);
98                         free(c);
99                 }
100         } else {
101                 sd_bus_message *m;
102
103                 m = container_of(c, sd_bus_message, creds);
104                 sd_bus_message_unref(m);
105         }
106
107
108         return NULL;
109 }
110
111 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
112         assert_return(c, 0);
113
114         return c->mask;
115 }
116
117 sd_bus_creds* bus_creds_new(void) {
118         sd_bus_creds *c;
119
120         c = new0(sd_bus_creds, 1);
121         if (!c)
122                 return NULL;
123
124         c->allocated = true;
125         c->n_ref = 1;
126         return c;
127 }
128
129 _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
130         sd_bus_creds *c;
131         int r;
132
133         assert_return(pid >= 0, -EINVAL);
134         assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
135         assert_return(ret, -EINVAL);
136
137         if (pid == 0)
138                 pid = getpid();
139
140         c = bus_creds_new();
141         if (!c)
142                 return -ENOMEM;
143
144         r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
145         if (r < 0) {
146                 sd_bus_creds_unref(c);
147                 return r;
148         }
149
150         /* Check if the process existed at all, in case we haven't
151          * figured that out already */
152         if (!pid_is_alive(pid)) {
153                 sd_bus_creds_unref(c);
154                 return -ESRCH;
155         }
156
157         *ret = c;
158         return 0;
159 }
160
161 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
162         assert_return(c, -EINVAL);
163         assert_return(uid, -EINVAL);
164
165         if (!(c->mask & SD_BUS_CREDS_UID))
166                 return -ENODATA;
167
168         *uid = c->uid;
169         return 0;
170 }
171
172 _public_ int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) {
173         assert_return(c, -EINVAL);
174         assert_return(euid, -EINVAL);
175
176         if (!(c->mask & SD_BUS_CREDS_EUID))
177                 return -ENODATA;
178
179         *euid = c->euid;
180         return 0;
181 }
182
183 _public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
184         assert_return(c, -EINVAL);
185         assert_return(suid, -EINVAL);
186
187         if (!(c->mask & SD_BUS_CREDS_SUID))
188                 return -ENODATA;
189
190         *suid = c->suid;
191         return 0;
192 }
193
194
195 _public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
196         assert_return(c, -EINVAL);
197         assert_return(fsuid, -EINVAL);
198
199         if (!(c->mask & SD_BUS_CREDS_FSUID))
200                 return -ENODATA;
201
202         *fsuid = c->fsuid;
203         return 0;
204 }
205
206 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
207         assert_return(c, -EINVAL);
208         assert_return(gid, -EINVAL);
209
210         if (!(c->mask & SD_BUS_CREDS_UID))
211                 return -ENODATA;
212
213         *gid = c->gid;
214         return 0;
215 }
216
217
218 _public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
219         assert_return(c, -EINVAL);
220         assert_return(egid, -EINVAL);
221
222         if (!(c->mask & SD_BUS_CREDS_EGID))
223                 return -ENODATA;
224
225         *egid = c->egid;
226         return 0;
227 }
228
229 _public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
230         assert_return(c, -EINVAL);
231         assert_return(sgid, -EINVAL);
232
233         if (!(c->mask & SD_BUS_CREDS_SGID))
234                 return -ENODATA;
235
236         *sgid = c->sgid;
237         return 0;
238 }
239
240
241 _public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
242         assert_return(c, -EINVAL);
243         assert_return(fsgid, -EINVAL);
244
245         if (!(c->mask & SD_BUS_CREDS_FSGID))
246                 return -ENODATA;
247
248         *fsgid = c->fsgid;
249         return 0;
250 }
251
252 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
253         assert_return(c, -EINVAL);
254         assert_return(pid, -EINVAL);
255
256         if (!(c->mask & SD_BUS_CREDS_PID))
257                 return -ENODATA;
258
259         assert(c->pid > 0);
260         *pid = c->pid;
261         return 0;
262 }
263
264 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
265         assert_return(c, -EINVAL);
266         assert_return(tid, -EINVAL);
267
268         if (!(c->mask & SD_BUS_CREDS_TID))
269                 return -ENODATA;
270
271         assert(c->tid > 0);
272         *tid = c->tid;
273         return 0;
274 }
275
276 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
277         assert_return(c, -EINVAL);
278         assert_return(usec, -EINVAL);
279
280         if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
281                 return -ENODATA;
282
283         assert(c->pid_starttime > 0);
284         *usec = c->pid_starttime;
285         return 0;
286 }
287
288 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
289         assert_return(c, -EINVAL);
290
291         if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
292                 return -ENODATA;
293
294         assert(c->label);
295         *ret = c->label;
296         return 0;
297 }
298
299 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
300         assert_return(c, -EINVAL);
301         assert_return(ret, -EINVAL);
302
303         if (!(c->mask & SD_BUS_CREDS_COMM))
304                 return -ENODATA;
305
306         assert(c->comm);
307         *ret = c->comm;
308         return 0;
309 }
310
311 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
312         assert_return(c, -EINVAL);
313         assert_return(ret, -EINVAL);
314
315         if (!(c->mask & SD_BUS_CREDS_TID_COMM))
316                 return -ENODATA;
317
318         assert(c->tid_comm);
319         *ret = c->tid_comm;
320         return 0;
321 }
322
323 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
324         assert_return(c, -EINVAL);
325         assert_return(ret, -EINVAL);
326
327         if (!(c->mask & SD_BUS_CREDS_EXE))
328                 return -ENODATA;
329
330         assert(c->exe);
331         *ret = c->exe;
332         return 0;
333 }
334
335 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
336         assert_return(c, -EINVAL);
337         assert_return(ret, -EINVAL);
338
339         if (!(c->mask & SD_BUS_CREDS_CGROUP))
340                 return -ENODATA;
341
342         assert(c->cgroup);
343         *ret = c->cgroup;
344         return 0;
345 }
346
347 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
348         int r;
349
350         assert_return(c, -EINVAL);
351         assert_return(ret, -EINVAL);
352
353         if (!(c->mask & SD_BUS_CREDS_UNIT))
354                 return -ENODATA;
355
356         assert(c->cgroup);
357
358         if (!c->unit) {
359                 const char *shifted;
360
361                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
362                 if (r < 0)
363                         return r;
364
365                 r = cg_path_get_unit(shifted, (char**) &c->unit);
366                 if (r < 0)
367                         return r;
368         }
369
370         *ret = c->unit;
371         return 0;
372 }
373
374 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
375         int r;
376
377         assert_return(c, -EINVAL);
378         assert_return(ret, -EINVAL);
379
380         if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
381                 return -ENODATA;
382
383         assert(c->cgroup);
384
385         if (!c->user_unit) {
386                 const char *shifted;
387
388                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
389                 if (r < 0)
390                         return r;
391
392                 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
393                 if (r < 0)
394                         return r;
395         }
396
397         *ret = c->user_unit;
398         return 0;
399 }
400
401 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
402         int r;
403
404         assert_return(c, -EINVAL);
405         assert_return(ret, -EINVAL);
406
407         if (!(c->mask & SD_BUS_CREDS_SLICE))
408                 return -ENODATA;
409
410         assert(c->cgroup);
411
412         if (!c->slice) {
413                 const char *shifted;
414
415                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
416                 if (r < 0)
417                         return r;
418
419                 r = cg_path_get_slice(shifted, (char**) &c->slice);
420                 if (r < 0)
421                         return r;
422         }
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 cg_path_get_owner_uid(shifted, uid);
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_unique_name(sd_bus_creds *c, const char **unique_name) {
516         assert_return(c, -EINVAL);
517         assert_return(unique_name, -EINVAL);
518
519         if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
520                 return -ENODATA;
521
522         *unique_name = c->unique_name;
523         return 0;
524 }
525
526 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
527         assert_return(c, -EINVAL);
528         assert_return(well_known_names, -EINVAL);
529
530         if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
531                 return -ENODATA;
532
533         *well_known_names = c->well_known_names;
534         return 0;
535 }
536
537 _public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
538         assert_return(c, -EINVAL);
539         assert_return(ret, -EINVAL);
540
541         if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
542                 return -ENODATA;
543
544         assert(c->description);
545
546         if (!c->unescaped_description) {
547                 c->unescaped_description = bus_label_unescape(c->description);
548                 if (!c->unescaped_description)
549                         return -ENOMEM;
550         }
551
552         *ret = c->unescaped_description;
553         return 0;
554 }
555
556 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
557         size_t sz;
558
559         assert(c);
560         assert(c->capability);
561
562         sz = c->capability_size / 4;
563         if ((size_t) capability >= sz*8)
564                 return 0;
565
566         return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
567 }
568
569 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
570         assert_return(c, -EINVAL);
571         assert_return(capability >= 0, -EINVAL);
572
573         if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
574                 return -ENODATA;
575
576         return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
577 }
578
579 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
580         assert_return(c, -EINVAL);
581         assert_return(capability >= 0, -EINVAL);
582
583         if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
584                 return -ENODATA;
585
586         return has_cap(c, CAP_OFFSET_PERMITTED, capability);
587 }
588
589 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
590         assert_return(c, -EINVAL);
591         assert_return(capability >= 0, -EINVAL);
592
593         if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
594                 return -ENODATA;
595
596         return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
597 }
598
599 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
600         assert_return(c, -EINVAL);
601         assert_return(capability >= 0, -EINVAL);
602
603         if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
604                 return -ENODATA;
605
606         return has_cap(c, CAP_OFFSET_BOUNDING, capability);
607 }
608
609 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
610         size_t sz;
611         unsigned i;
612
613         assert(c);
614         assert(p);
615
616         p += strspn(p, WHITESPACE);
617
618         sz = strlen(p);
619         if (sz % 2 != 0)
620                 return -EINVAL;
621
622         sz /= 2;
623         if (!c->capability) {
624                 c->capability = new0(uint8_t, sz * 4);
625                 if (!c->capability)
626                         return -ENOMEM;
627
628                 c->capability_size = sz * 4;
629         }
630
631         for (i = 0; i < sz; i ++) {
632                 int x, y;
633
634                 x = unhexchar(p[i*2]);
635                 y = unhexchar(p[i*2+1]);
636
637                 if (x < 0 || y < 0)
638                         return -EINVAL;
639
640                 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
641         }
642
643         return 0;
644 }
645
646 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
647         uint64_t missing;
648         int r;
649
650         assert(c);
651         assert(c->allocated);
652
653         if (!(mask & SD_BUS_CREDS_AUGMENT))
654                 return 0;
655
656         missing = mask & ~c->mask;
657         if (missing == 0)
658                 return 0;
659
660         /* Try to retrieve PID from creds if it wasn't passed to us */
661         if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
662                 pid = c->pid;
663
664         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
665                 tid = c->pid;
666
667         /* Without pid we cannot do much... */
668         if (pid <= 0)
669                 return 0;
670
671         if (pid > 0) {
672                 c->pid = pid;
673                 c->mask |= SD_BUS_CREDS_PID;
674         }
675
676         if (tid > 0) {
677                 c->tid = tid;
678                 c->mask |= SD_BUS_CREDS_TID;
679         }
680
681         if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
682                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
683                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
684                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
685
686                 _cleanup_fclose_ FILE *f = NULL;
687                 const char *p;
688
689                 p = procfs_file_alloca(pid, "status");
690
691                 f = fopen(p, "re");
692                 if (!f) {
693                         if (errno == ENOENT)
694                                 return -ESRCH;
695                         else if (errno != EPERM && errno != EACCES)
696                                 return -errno;
697                 } else {
698                         char line[LINE_MAX];
699
700                         FOREACH_LINE(line, f, return -errno) {
701                                 truncate_nl(line);
702
703                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
704                                         p = startswith(line, "Uid:");
705                                         if (p) {
706                                                 unsigned long uid, euid, suid, fsuid;
707
708                                                 p += strspn(p, WHITESPACE);
709                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
710                                                         return -EIO;
711
712                                                 c->uid = (uid_t) uid;
713                                                 c->euid = (uid_t) euid;
714                                                 c->suid = (uid_t) suid;
715                                                 c->fsuid = (uid_t) fsuid;
716                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
717                                                 continue;
718                                         }
719                                 }
720
721                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
722                                         p = startswith(line, "Gid:");
723                                         if (p) {
724                                                 unsigned long gid, egid, sgid, fsgid;
725
726                                                 p += strspn(p, WHITESPACE);
727                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
728                                                         return -EIO;
729
730                                                 c->gid = (gid_t) gid;
731                                                 c->egid = (gid_t) egid;
732                                                 c->sgid = (gid_t) sgid;
733                                                 c->fsgid = (gid_t) fsgid;
734                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
735                                                 continue;
736                                         }
737                                 }
738
739                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
740                                         p = startswith(line, "CapEff:");
741                                         if (p) {
742                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
743                                                 if (r < 0)
744                                                         return r;
745
746                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
747                                                 continue;
748                                         }
749                                 }
750
751                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
752                                         p = startswith(line, "CapPrm:");
753                                         if (p) {
754                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
755                                                 if (r < 0)
756                                                         return r;
757
758                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
759                                                 continue;
760                                         }
761                                 }
762
763                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
764                                         p = startswith(line, "CapInh:");
765                                         if (p) {
766                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
767                                                 if (r < 0)
768                                                         return r;
769
770                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
771                                                 continue;
772                                         }
773                                 }
774
775                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
776                                         p = startswith(line, "CapBnd:");
777                                         if (p) {
778                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
779                                                 if (r < 0)
780                                                         return r;
781
782                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
783                                                 continue;
784                                         }
785                                 }
786                         }
787                 }
788         }
789
790         if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
791                 unsigned long long st;
792
793                 r = get_starttime_of_pid(pid, &st);
794                 if (r < 0) {
795                         if (r != -EPERM && r != -EACCES)
796                                 return r;
797                 } else {
798                         c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
799                         c->mask |= SD_BUS_CREDS_PID_STARTTIME;
800                 }
801         }
802
803         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
804                 const char *p;
805
806                 p = procfs_file_alloca(pid, "attr/current");
807                 r = read_one_line_file(p, &c->label);
808                 if (r < 0) {
809                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
810                                 return r;
811                 } else
812                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
813         }
814
815         if (missing & SD_BUS_CREDS_COMM) {
816                 r = get_process_comm(pid, &c->comm);
817                 if (r < 0) {
818                         if (r != -EPERM && r != -EACCES)
819                                 return r;
820                 } else
821                         c->mask |= SD_BUS_CREDS_COMM;
822         }
823
824         if (missing & SD_BUS_CREDS_EXE) {
825                 r = get_process_exe(pid, &c->exe);
826                 if (r < 0) {
827                         if (r != -EPERM && r != -EACCES)
828                                 return r;
829                 } else
830                         c->mask |= SD_BUS_CREDS_EXE;
831         }
832
833         if (missing & SD_BUS_CREDS_CMDLINE) {
834                 const char *p;
835
836                 p = procfs_file_alloca(pid, "cmdline");
837                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
838                 if (r < 0) {
839                         if (r == -ENOENT)
840                                 return -ESRCH;
841                         if (r != -EPERM && r != -EACCES)
842                                 return r;
843                 } else {
844                         if (c->cmdline_size == 0) {
845                                 free(c->cmdline);
846                                 c->cmdline = NULL;
847                         } else
848                                 c->mask |= SD_BUS_CREDS_CMDLINE;
849                 }
850         }
851
852         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
853                 _cleanup_free_ char *p = NULL;
854
855                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
856                         return -ENOMEM;
857
858                 r = read_one_line_file(p, &c->tid_comm);
859                 if (r < 0) {
860                         if (r == -ENOENT)
861                                 return -ESRCH;
862                         if (r != -EPERM && r != -EACCES)
863                                 return r;
864                 } else
865                         c->mask |= SD_BUS_CREDS_TID_COMM;
866         }
867
868         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)) {
869
870                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
871                 if (r < 0) {
872                         if (r != -EPERM && r != -EACCES)
873                                 return r;
874                 } else {
875                         r = cg_get_root_path(&c->cgroup_root);
876                         if (r < 0)
877                                 return r;
878
879                         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);
880                 }
881         }
882
883         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
884                 r = audit_session_from_pid(pid, &c->audit_session_id);
885                 if (r < 0) {
886                         if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
887                                 return r;
888                 } else
889                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
890         }
891
892         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
893                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
894                 if (r < 0) {
895                         if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
896                                 return r;
897                 } else
898                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
899         }
900
901         return 0;
902 }
903
904 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
905         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
906         int r;
907
908         assert(c);
909         assert(ret);
910
911         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
912                 /* There's already all data we need, or augmentation
913                  * wasn't turned on. */
914
915                 *ret = sd_bus_creds_ref(c);
916                 return 0;
917         }
918
919         n = bus_creds_new();
920         if (!n)
921                 return -ENOMEM;
922
923         /* Copy the original data over */
924
925         if (c->mask & mask & SD_BUS_CREDS_UID) {
926                 n->uid = c->uid;
927                 n->mask |= SD_BUS_CREDS_UID;
928         }
929
930         if (c->mask & mask & SD_BUS_CREDS_EUID) {
931                 n->euid = c->euid;
932                 n->mask |= SD_BUS_CREDS_EUID;
933         }
934
935         if (c->mask & mask & SD_BUS_CREDS_SUID) {
936                 n->suid = c->suid;
937                 n->mask |= SD_BUS_CREDS_SUID;
938         }
939
940         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
941                 n->fsuid = c->fsuid;
942                 n->mask |= SD_BUS_CREDS_FSUID;
943         }
944
945         if (c->mask & mask & SD_BUS_CREDS_GID) {
946                 n->gid = c->gid;
947                 n->mask |= SD_BUS_CREDS_GID;
948         }
949
950         if (c->mask & mask & SD_BUS_CREDS_EGID) {
951                 n->egid = c->egid;
952                 n->mask |= SD_BUS_CREDS_EGID;
953         }
954
955         if (c->mask & mask & SD_BUS_CREDS_SGID) {
956                 n->sgid = c->sgid;
957                 n->mask |= SD_BUS_CREDS_SGID;
958         }
959
960         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
961                 n->fsgid = c->fsgid;
962                 n->mask |= SD_BUS_CREDS_FSGID;
963         }
964
965         if (c->mask & mask & SD_BUS_CREDS_PID) {
966                 n->pid = c->pid;
967                 n->mask |= SD_BUS_CREDS_PID;
968         }
969
970         if (c->mask & mask & SD_BUS_CREDS_TID) {
971                 n->tid = c->tid;
972                 n->mask |= SD_BUS_CREDS_TID;
973         }
974
975         if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
976                 n->pid_starttime = c->pid_starttime;
977                 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
978         }
979
980         if (c->mask & mask & SD_BUS_CREDS_COMM) {
981                 n->comm = strdup(c->comm);
982                 if (!n->comm)
983                         return -ENOMEM;
984
985                 n->mask |= SD_BUS_CREDS_COMM;
986         }
987
988         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
989                 n->tid_comm = strdup(c->tid_comm);
990                 if (!n->tid_comm)
991                         return -ENOMEM;
992
993                 n->mask |= SD_BUS_CREDS_TID_COMM;
994         }
995
996         if (c->mask & mask & SD_BUS_CREDS_EXE) {
997                 n->exe = strdup(c->exe);
998                 if (!n->exe)
999                         return -ENOMEM;
1000
1001                 n->mask |= SD_BUS_CREDS_EXE;
1002         }
1003
1004         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1005                 n->cmdline = memdup(c->cmdline, c->cmdline_size);
1006                 if (!n->cmdline)
1007                         return -ENOMEM;
1008
1009                 n->cmdline_size = c->cmdline_size;
1010                 n->mask |= SD_BUS_CREDS_CMDLINE;
1011         }
1012
1013         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)) {
1014                 n->cgroup = strdup(c->cgroup);
1015                 if (!n->cgroup)
1016                         return -ENOMEM;
1017
1018                 n->cgroup_root = strdup(c->cgroup_root);
1019                 if (!n->cgroup_root)
1020                         return -ENOMEM;
1021
1022                 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);
1023         }
1024
1025         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1026                 n->capability = memdup(c->capability, c->capability_size);
1027                 if (!n->capability)
1028                         return -ENOMEM;
1029
1030                 n->capability_size = c->capability_size;
1031                 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);
1032         }
1033
1034         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1035                 n->audit_session_id = c->audit_session_id;
1036                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1037         }
1038
1039         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1040                 n->audit_login_uid = c->audit_login_uid;
1041                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1042         }
1043
1044         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1045                 n->unique_name = strdup(c->unique_name);
1046                 if (!n->unique_name)
1047                         return -ENOMEM;
1048         }
1049
1050         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1051                 n->well_known_names = strv_copy(c->well_known_names);
1052                 if (!n->well_known_names)
1053                         return -ENOMEM;
1054         }
1055
1056         /* Get more data */
1057
1058         r = bus_creds_add_more(n, mask,
1059                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
1060                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
1061         if (r < 0)
1062                 return r;
1063
1064         *ret = n;
1065         n = NULL;
1066         return 0;
1067 }