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