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