chiark / gitweb /
shared: add formats-util.h
[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
234 _public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
235         assert_return(c, -EINVAL);
236         assert_return(egid, -EINVAL);
237
238         if (!(c->mask & SD_BUS_CREDS_EGID))
239                 return -ENODATA;
240
241         *egid = c->egid;
242         return 0;
243 }
244
245 _public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
246         assert_return(c, -EINVAL);
247         assert_return(sgid, -EINVAL);
248
249         if (!(c->mask & SD_BUS_CREDS_SGID))
250                 return -ENODATA;
251
252         *sgid = c->sgid;
253         return 0;
254 }
255
256 _public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
257         assert_return(c, -EINVAL);
258         assert_return(fsgid, -EINVAL);
259
260         if (!(c->mask & SD_BUS_CREDS_FSGID))
261                 return -ENODATA;
262
263         *fsgid = c->fsgid;
264         return 0;
265 }
266
267 _public_ int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) {
268         assert_return(c, -EINVAL);
269         assert_return(gids, -EINVAL);
270
271         if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
272                 return -ENODATA;
273
274         *gids = c->supplementary_gids;
275         return (int) c->n_supplementary_gids;
276 }
277
278 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
279         assert_return(c, -EINVAL);
280         assert_return(pid, -EINVAL);
281
282         if (!(c->mask & SD_BUS_CREDS_PID))
283                 return -ENODATA;
284
285         assert(c->pid > 0);
286         *pid = c->pid;
287         return 0;
288 }
289
290 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
291         assert_return(c, -EINVAL);
292         assert_return(tid, -EINVAL);
293
294         if (!(c->mask & SD_BUS_CREDS_TID))
295                 return -ENODATA;
296
297         assert(c->tid > 0);
298         *tid = c->tid;
299         return 0;
300 }
301
302 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
303         assert_return(c, -EINVAL);
304
305         if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
306                 return -ENODATA;
307
308         assert(c->label);
309         *ret = c->label;
310         return 0;
311 }
312
313 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
314         assert_return(c, -EINVAL);
315         assert_return(ret, -EINVAL);
316
317         if (!(c->mask & SD_BUS_CREDS_COMM))
318                 return -ENODATA;
319
320         assert(c->comm);
321         *ret = c->comm;
322         return 0;
323 }
324
325 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
326         assert_return(c, -EINVAL);
327         assert_return(ret, -EINVAL);
328
329         if (!(c->mask & SD_BUS_CREDS_TID_COMM))
330                 return -ENODATA;
331
332         assert(c->tid_comm);
333         *ret = c->tid_comm;
334         return 0;
335 }
336
337 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
338         assert_return(c, -EINVAL);
339         assert_return(ret, -EINVAL);
340
341         if (!(c->mask & SD_BUS_CREDS_EXE))
342                 return -ENODATA;
343
344         assert(c->exe);
345         *ret = c->exe;
346         return 0;
347 }
348
349 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
350         assert_return(c, -EINVAL);
351         assert_return(ret, -EINVAL);
352
353         if (!(c->mask & SD_BUS_CREDS_CGROUP))
354                 return -ENODATA;
355
356         assert(c->cgroup);
357         *ret = c->cgroup;
358         return 0;
359 }
360
361 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
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                 return -ESRCH;
372
373         *ret = c->unit;
374         return 0;
375 }
376
377 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
378         assert_return(c, -EINVAL);
379         assert_return(ret, -EINVAL);
380
381         if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
382                 return -ENODATA;
383
384         assert(c->cgroup);
385
386         if (!c->user_unit)
387                 return -ESRCH;
388
389         *ret = c->user_unit;
390         return 0;
391 }
392
393 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
394         assert_return(c, -EINVAL);
395         assert_return(ret, -EINVAL);
396
397         if (!(c->mask & SD_BUS_CREDS_SLICE))
398                 return -ENODATA;
399
400         assert(c->cgroup);
401
402         if (!c->slice)
403                 return -ESRCH;
404
405         *ret = c->slice;
406         return 0;
407 }
408
409 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
410         int r;
411
412         assert_return(c, -EINVAL);
413         assert_return(ret, -EINVAL);
414
415         if (!(c->mask & SD_BUS_CREDS_SESSION))
416                 return -ENODATA;
417
418         assert(c->cgroup);
419
420         if (!c->session) {
421                 const char *shifted;
422
423                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
424                 if (r < 0)
425                         return r;
426
427                 r = cg_path_get_session(shifted, (char**) &c->session);
428                 if (r < 0)
429                         return r;
430         }
431
432         *ret = c->session;
433         return 0;
434 }
435
436 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
437         const char *shifted;
438         int r;
439
440         assert_return(c, -EINVAL);
441         assert_return(uid, -EINVAL);
442
443         if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
444                 return -ENODATA;
445
446         assert(c->cgroup);
447
448         r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
449         if (r < 0)
450                 return r;
451
452         return -ESRCH;
453 }
454
455 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
456         assert_return(c, -EINVAL);
457
458         if (!(c->mask & SD_BUS_CREDS_CMDLINE))
459                 return -ENODATA;
460
461         assert_return(c->cmdline, -ESRCH);
462         assert(c->cmdline);
463
464         if (!c->cmdline_array) {
465                 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
466                 if (!c->cmdline_array)
467                         return -ENOMEM;
468         }
469
470         *cmdline = c->cmdline_array;
471         return 0;
472 }
473
474 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
475         assert_return(c, -EINVAL);
476         assert_return(sessionid, -EINVAL);
477
478         if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
479                 return -ENODATA;
480
481         *sessionid = c->audit_session_id;
482         return 0;
483 }
484
485 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
486         assert_return(c, -EINVAL);
487         assert_return(uid, -EINVAL);
488
489         if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
490                 return -ENODATA;
491
492         *uid = c->audit_login_uid;
493         return 0;
494 }
495
496 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
497         assert_return(c, -EINVAL);
498         assert_return(unique_name, -EINVAL);
499
500         if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
501                 return -ENODATA;
502
503         *unique_name = c->unique_name;
504         return 0;
505 }
506
507 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
508         assert_return(c, -EINVAL);
509         assert_return(well_known_names, -EINVAL);
510
511         if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
512                 return -ENODATA;
513
514         /* As a special hack we return the bus driver as well-known
515          * names list when this is requested. */
516         if (c->well_known_names_driver) {
517                 static const char* const wkn[] = {
518                         "org.freedesktop.DBus",
519                         NULL
520                 };
521
522                 *well_known_names = (char**) wkn;
523                 return 0;
524         }
525
526         if (c->well_known_names_local) {
527                 static const char* const wkn[] = {
528                         "org.freedesktop.DBus.Local",
529                         NULL
530                 };
531
532                 *well_known_names = (char**) wkn;
533                 return 0;
534         }
535
536         *well_known_names = c->well_known_names;
537         return 0;
538 }
539
540 _public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
541         assert_return(c, -EINVAL);
542         assert_return(ret, -EINVAL);
543
544         if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
545                 return -ENODATA;
546
547         assert(c->description);
548
549         if (!c->unescaped_description) {
550                 c->unescaped_description = bus_label_unescape(c->description);
551                 if (!c->unescaped_description)
552                         return -ENOMEM;
553         }
554
555         *ret = c->unescaped_description;
556         return 0;
557 }
558
559 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
560         size_t sz;
561
562         assert(c);
563         assert(capability >= 0);
564         assert(c->capability);
565
566         sz = DIV_ROUND_UP(cap_last_cap(), 32U);
567         if ((unsigned)capability > cap_last_cap())
568                 return 0;
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                                                 c->uid = (uid_t) uid;
724                                                 c->euid = (uid_t) euid;
725                                                 c->suid = (uid_t) suid;
726                                                 c->fsuid = (uid_t) fsuid;
727                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
728                                                 continue;
729                                         }
730                                 }
731
732                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
733                                         p = startswith(line, "Gid:");
734                                         if (p) {
735                                                 unsigned long gid, egid, sgid, fsgid;
736
737                                                 p += strspn(p, WHITESPACE);
738                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
739                                                         return -EIO;
740
741                                                 c->gid = (gid_t) gid;
742                                                 c->egid = (gid_t) egid;
743                                                 c->sgid = (gid_t) sgid;
744                                                 c->fsgid = (gid_t) fsgid;
745                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
746                                                 continue;
747                                         }
748                                 }
749
750                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
751                                         p = startswith(line, "Groups:");
752                                         if (p) {
753                                                 size_t allocated = 0;
754
755                                                 for (;;) {
756                                                         unsigned long g;
757                                                         int n = 0;
758
759                                                         p += strspn(p, WHITESPACE);
760                                                         if (*p == 0)
761                                                                 break;
762
763                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
764                                                                 return -EIO;
765
766                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
767                                                                 return -ENOMEM;
768
769                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
770                                                         p += n;
771                                                 }
772
773                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
774                                                 continue;
775                                         }
776                                 }
777
778                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
779                                         p = startswith(line, "CapEff:");
780                                         if (p) {
781                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
782                                                 if (r < 0)
783                                                         return r;
784
785                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
786                                                 continue;
787                                         }
788                                 }
789
790                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
791                                         p = startswith(line, "CapPrm:");
792                                         if (p) {
793                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
794                                                 if (r < 0)
795                                                         return r;
796
797                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
798                                                 continue;
799                                         }
800                                 }
801
802                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
803                                         p = startswith(line, "CapInh:");
804                                         if (p) {
805                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
806                                                 if (r < 0)
807                                                         return r;
808
809                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
810                                                 continue;
811                                         }
812                                 }
813
814                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
815                                         p = startswith(line, "CapBnd:");
816                                         if (p) {
817                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
818                                                 if (r < 0)
819                                                         return r;
820
821                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
822                                                 continue;
823                                         }
824                                 }
825                         }
826                 }
827         }
828
829         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
830                 const char *p;
831
832                 p = procfs_file_alloca(pid, "attr/current");
833                 r = read_one_line_file(p, &c->label);
834                 if (r < 0) {
835                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
836                                 return r;
837                 } else
838                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
839         }
840
841         if (missing & SD_BUS_CREDS_COMM) {
842                 r = get_process_comm(pid, &c->comm);
843                 if (r < 0) {
844                         if (r != -EPERM && r != -EACCES)
845                                 return r;
846                 } else
847                         c->mask |= SD_BUS_CREDS_COMM;
848         }
849
850         if (missing & SD_BUS_CREDS_EXE) {
851                 r = get_process_exe(pid, &c->exe);
852                 if (r < 0) {
853                         if (r != -EPERM && r != -EACCES)
854                                 return r;
855                 } else
856                         c->mask |= SD_BUS_CREDS_EXE;
857         }
858
859         if (missing & SD_BUS_CREDS_CMDLINE) {
860                 const char *p;
861
862                 p = procfs_file_alloca(pid, "cmdline");
863                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
864                 if (r < 0) {
865                         if (r == -ENOENT)
866                                 return -ESRCH;
867                         if (r != -EPERM && r != -EACCES)
868                                 return r;
869                 } else {
870                         if (c->cmdline_size == 0) {
871                                 free(c->cmdline);
872                                 c->cmdline = NULL;
873                         } else
874                                 c->mask |= SD_BUS_CREDS_CMDLINE;
875                 }
876         }
877
878         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
879                 _cleanup_free_ char *p = NULL;
880
881                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
882                         return -ENOMEM;
883
884                 r = read_one_line_file(p, &c->tid_comm);
885                 if (r < 0) {
886                         if (r == -ENOENT)
887                                 return -ESRCH;
888                         if (r != -EPERM && r != -EACCES)
889                                 return r;
890                 } else
891                         c->mask |= SD_BUS_CREDS_TID_COMM;
892         }
893
894         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)) {
895
896                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
897                 if (r < 0) {
898                         if (r != -EPERM && r != -EACCES)
899                                 return r;
900                 } else {
901                         r = cg_get_root_path(&c->cgroup_root);
902                         if (r < 0)
903                                 return r;
904
905                         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);
906                 }
907         }
908
909         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
910                 r = audit_session_from_pid(pid, &c->audit_session_id);
911                 if (r < 0) {
912                         if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
913                                 return r;
914                 } else
915                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
916         }
917
918         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
919                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
920                 if (r < 0) {
921                         if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
922                                 return r;
923                 } else
924                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
925         }
926
927         return 0;
928 }
929
930 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
931         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
932         int r;
933
934         assert(c);
935         assert(ret);
936
937         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
938                 /* There's already all data we need, or augmentation
939                  * wasn't turned on. */
940
941                 *ret = sd_bus_creds_ref(c);
942                 return 0;
943         }
944
945         n = bus_creds_new();
946         if (!n)
947                 return -ENOMEM;
948
949         /* Copy the original data over */
950
951         if (c->mask & mask & SD_BUS_CREDS_UID) {
952                 n->uid = c->uid;
953                 n->mask |= SD_BUS_CREDS_UID;
954         }
955
956         if (c->mask & mask & SD_BUS_CREDS_EUID) {
957                 n->euid = c->euid;
958                 n->mask |= SD_BUS_CREDS_EUID;
959         }
960
961         if (c->mask & mask & SD_BUS_CREDS_SUID) {
962                 n->suid = c->suid;
963                 n->mask |= SD_BUS_CREDS_SUID;
964         }
965
966         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
967                 n->fsuid = c->fsuid;
968                 n->mask |= SD_BUS_CREDS_FSUID;
969         }
970
971         if (c->mask & mask & SD_BUS_CREDS_GID) {
972                 n->gid = c->gid;
973                 n->mask |= SD_BUS_CREDS_GID;
974         }
975
976         if (c->mask & mask & SD_BUS_CREDS_EGID) {
977                 n->egid = c->egid;
978                 n->mask |= SD_BUS_CREDS_EGID;
979         }
980
981         if (c->mask & mask & SD_BUS_CREDS_SGID) {
982                 n->sgid = c->sgid;
983                 n->mask |= SD_BUS_CREDS_SGID;
984         }
985
986         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
987                 n->fsgid = c->fsgid;
988                 n->mask |= SD_BUS_CREDS_FSGID;
989         }
990
991         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
992                 n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
993                 if (!n->supplementary_gids)
994                         return -ENOMEM;
995                 n->n_supplementary_gids = c->n_supplementary_gids;
996                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
997         }
998
999         if (c->mask & mask & SD_BUS_CREDS_PID) {
1000                 n->pid = c->pid;
1001                 n->mask |= SD_BUS_CREDS_PID;
1002         }
1003
1004         if (c->mask & mask & SD_BUS_CREDS_TID) {
1005                 n->tid = c->tid;
1006                 n->mask |= SD_BUS_CREDS_TID;
1007         }
1008
1009         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1010                 n->comm = strdup(c->comm);
1011                 if (!n->comm)
1012                         return -ENOMEM;
1013
1014                 n->mask |= SD_BUS_CREDS_COMM;
1015         }
1016
1017         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1018                 n->tid_comm = strdup(c->tid_comm);
1019                 if (!n->tid_comm)
1020                         return -ENOMEM;
1021
1022                 n->mask |= SD_BUS_CREDS_TID_COMM;
1023         }
1024
1025         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1026                 n->exe = strdup(c->exe);
1027                 if (!n->exe)
1028                         return -ENOMEM;
1029
1030                 n->mask |= SD_BUS_CREDS_EXE;
1031         }
1032
1033         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1034                 n->cmdline = memdup(c->cmdline, c->cmdline_size);
1035                 if (!n->cmdline)
1036                         return -ENOMEM;
1037
1038                 n->cmdline_size = c->cmdline_size;
1039                 n->mask |= SD_BUS_CREDS_CMDLINE;
1040         }
1041
1042         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)) {
1043                 n->cgroup = strdup(c->cgroup);
1044                 if (!n->cgroup)
1045                         return -ENOMEM;
1046
1047                 n->cgroup_root = strdup(c->cgroup_root);
1048                 if (!n->cgroup_root)
1049                         return -ENOMEM;
1050
1051                 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);
1052         }
1053
1054         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1055                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1056                 if (!n->capability)
1057                         return -ENOMEM;
1058
1059                 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);
1060         }
1061
1062         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1063                 n->label = strdup(c->label);
1064                 if (!n->label)
1065                         return -ENOMEM;
1066                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1067         }
1068
1069         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1070                 n->audit_session_id = c->audit_session_id;
1071                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1072         }
1073         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1074                 n->audit_login_uid = c->audit_login_uid;
1075                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1076         }
1077
1078         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1079                 n->unique_name = strdup(c->unique_name);
1080                 if (!n->unique_name)
1081                         return -ENOMEM;
1082                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1083         }
1084
1085         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1086                 n->well_known_names = strv_copy(c->well_known_names);
1087                 if (!n->well_known_names)
1088                         return -ENOMEM;
1089                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1090         }
1091
1092         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1093                 n->description = strdup(c->description);
1094                 if (!n->description)
1095                         return -ENOMEM;
1096                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1097         }
1098
1099         /* Get more data */
1100
1101         r = bus_creds_add_more(n, mask,
1102                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
1103                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
1104         if (r < 0)
1105                 return r;
1106
1107         *ret = n;
1108         n = NULL;
1109         return 0;
1110 }