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