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