chiark / gitweb /
55d6fb6b439073c11503aa48b4892923b2b33f4d
[elogind.git] / src / libsystemd / sd-bus / bus-creds.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdlib.h>
23
24 #include "util.h"
25 #include "capability.h"
26 #include "cgroup-util.h"
27 #include "fileio.h"
28 #include "audit.h"
29 #include "bus-message.h"
30 #include "bus-util.h"
31 #include "time-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_UID))
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) * 4;
596         if ((unsigned)capability > cap_last_cap())
597                 return 0;
598
599         return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
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;
645
646         assert(c);
647         assert(p);
648
649         max = DIV_ROUND_UP(cap_last_cap(), 32U) * 4;
650         p += strspn(p, WHITESPACE);
651
652         sz = strlen(p);
653         if (sz % 2 != 0)
654                 return -EINVAL;
655
656         sz /= 2;
657         if (sz > max)
658                 return -EINVAL;
659
660         if (!c->capability) {
661                 c->capability = new0(uint8_t, max * 4);
662                 if (!c->capability)
663                         return -ENOMEM;
664         }
665
666         for (i = 0; i < sz; i ++) {
667                 int x, y;
668
669                 x = unhexchar(p[i*2]);
670                 y = unhexchar(p[i*2+1]);
671
672                 if (x < 0 || y < 0)
673                         return -EINVAL;
674
675                 c->capability[offset * max + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
676         }
677
678         return 0;
679 }
680
681 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
682         uint64_t missing;
683         int r;
684
685         assert(c);
686         assert(c->allocated);
687
688         if (!(mask & SD_BUS_CREDS_AUGMENT))
689                 return 0;
690
691         missing = mask & ~c->mask;
692         if (missing == 0)
693                 return 0;
694
695         /* Try to retrieve PID from creds if it wasn't passed to us */
696         if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
697                 pid = c->pid;
698
699         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
700                 tid = c->pid;
701
702         /* Without pid we cannot do much... */
703         if (pid <= 0)
704                 return 0;
705
706         if (pid > 0) {
707                 c->pid = pid;
708                 c->mask |= SD_BUS_CREDS_PID;
709         }
710
711         if (tid > 0) {
712                 c->tid = tid;
713                 c->mask |= SD_BUS_CREDS_TID;
714         }
715
716         if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
717                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
718                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
719                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
720                        SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
721
722                 _cleanup_fclose_ FILE *f = NULL;
723                 const char *p;
724
725                 p = procfs_file_alloca(pid, "status");
726
727                 f = fopen(p, "re");
728                 if (!f) {
729                         if (errno == ENOENT)
730                                 return -ESRCH;
731                         else if (errno != EPERM && errno != EACCES)
732                                 return -errno;
733                 } else {
734                         char line[LINE_MAX];
735
736                         FOREACH_LINE(line, f, return -errno) {
737                                 truncate_nl(line);
738
739                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
740                                         p = startswith(line, "Uid:");
741                                         if (p) {
742                                                 unsigned long uid, euid, suid, fsuid;
743
744                                                 p += strspn(p, WHITESPACE);
745                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
746                                                         return -EIO;
747
748                                                 c->uid = (uid_t) uid;
749                                                 c->euid = (uid_t) euid;
750                                                 c->suid = (uid_t) suid;
751                                                 c->fsuid = (uid_t) fsuid;
752                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
753                                                 continue;
754                                         }
755                                 }
756
757                                 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
758                                         p = startswith(line, "Gid:");
759                                         if (p) {
760                                                 unsigned long gid, egid, sgid, fsgid;
761
762                                                 p += strspn(p, WHITESPACE);
763                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
764                                                         return -EIO;
765
766                                                 c->gid = (gid_t) gid;
767                                                 c->egid = (gid_t) egid;
768                                                 c->sgid = (gid_t) sgid;
769                                                 c->fsgid = (gid_t) fsgid;
770                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
771                                                 continue;
772                                         }
773                                 }
774
775                                 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
776                                         p = startswith(line, "Groups:");
777                                         if (p) {
778                                                 size_t allocated = 0;
779
780                                                 for (;;) {
781                                                         unsigned long g;
782                                                         int n = 0;
783
784                                                         p += strspn(p, WHITESPACE);
785                                                         if (*p == 0)
786                                                                 break;
787
788                                                         if (sscanf(p, "%lu%n", &g, &n) != 1)
789                                                                 return -EIO;
790
791                                                         if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
792                                                                 return -ENOMEM;
793
794                                                         c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
795                                                         p += n;
796                                                 }
797
798                                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
799                                                 continue;
800                                         }
801                                 }
802
803                                 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
804                                         p = startswith(line, "CapEff:");
805                                         if (p) {
806                                                 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
807                                                 if (r < 0)
808                                                         return r;
809
810                                                 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
811                                                 continue;
812                                         }
813                                 }
814
815                                 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
816                                         p = startswith(line, "CapPrm:");
817                                         if (p) {
818                                                 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
819                                                 if (r < 0)
820                                                         return r;
821
822                                                 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
823                                                 continue;
824                                         }
825                                 }
826
827                                 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
828                                         p = startswith(line, "CapInh:");
829                                         if (p) {
830                                                 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
831                                                 if (r < 0)
832                                                         return r;
833
834                                                 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
835                                                 continue;
836                                         }
837                                 }
838
839                                 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
840                                         p = startswith(line, "CapBnd:");
841                                         if (p) {
842                                                 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
843                                                 if (r < 0)
844                                                         return r;
845
846                                                 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
847                                                 continue;
848                                         }
849                                 }
850                         }
851                 }
852         }
853
854         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
855                 const char *p;
856
857                 p = procfs_file_alloca(pid, "attr/current");
858                 r = read_one_line_file(p, &c->label);
859                 if (r < 0) {
860                         if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
861                                 return r;
862                 } else
863                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
864         }
865
866         if (missing & SD_BUS_CREDS_COMM) {
867                 r = get_process_comm(pid, &c->comm);
868                 if (r < 0) {
869                         if (r != -EPERM && r != -EACCES)
870                                 return r;
871                 } else
872                         c->mask |= SD_BUS_CREDS_COMM;
873         }
874
875         if (missing & SD_BUS_CREDS_EXE) {
876                 r = get_process_exe(pid, &c->exe);
877                 if (r < 0) {
878                         if (r != -EPERM && r != -EACCES)
879                                 return r;
880                 } else
881                         c->mask |= SD_BUS_CREDS_EXE;
882         }
883
884         if (missing & SD_BUS_CREDS_CMDLINE) {
885                 const char *p;
886
887                 p = procfs_file_alloca(pid, "cmdline");
888                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
889                 if (r < 0) {
890                         if (r == -ENOENT)
891                                 return -ESRCH;
892                         if (r != -EPERM && r != -EACCES)
893                                 return r;
894                 } else {
895                         if (c->cmdline_size == 0) {
896                                 free(c->cmdline);
897                                 c->cmdline = NULL;
898                         } else
899                                 c->mask |= SD_BUS_CREDS_CMDLINE;
900                 }
901         }
902
903         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
904                 _cleanup_free_ char *p = NULL;
905
906                 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
907                         return -ENOMEM;
908
909                 r = read_one_line_file(p, &c->tid_comm);
910                 if (r < 0) {
911                         if (r == -ENOENT)
912                                 return -ESRCH;
913                         if (r != -EPERM && r != -EACCES)
914                                 return r;
915                 } else
916                         c->mask |= SD_BUS_CREDS_TID_COMM;
917         }
918
919         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)) {
920
921                 r = cg_pid_get_path(NULL, pid, &c->cgroup);
922                 if (r < 0) {
923                         if (r != -EPERM && r != -EACCES)
924                                 return r;
925                 } else {
926                         r = cg_get_root_path(&c->cgroup_root);
927                         if (r < 0)
928                                 return r;
929
930                         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);
931                 }
932         }
933
934         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
935                 r = audit_session_from_pid(pid, &c->audit_session_id);
936                 if (r < 0) {
937                         if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
938                                 return r;
939                 } else
940                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
941         }
942
943         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
944                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
945                 if (r < 0) {
946                         if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
947                                 return r;
948                 } else
949                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
950         }
951
952         return 0;
953 }
954
955 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
956         _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
957         int r;
958
959         assert(c);
960         assert(ret);
961
962         if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
963                 /* There's already all data we need, or augmentation
964                  * wasn't turned on. */
965
966                 *ret = sd_bus_creds_ref(c);
967                 return 0;
968         }
969
970         n = bus_creds_new();
971         if (!n)
972                 return -ENOMEM;
973
974         /* Copy the original data over */
975
976         if (c->mask & mask & SD_BUS_CREDS_UID) {
977                 n->uid = c->uid;
978                 n->mask |= SD_BUS_CREDS_UID;
979         }
980
981         if (c->mask & mask & SD_BUS_CREDS_EUID) {
982                 n->euid = c->euid;
983                 n->mask |= SD_BUS_CREDS_EUID;
984         }
985
986         if (c->mask & mask & SD_BUS_CREDS_SUID) {
987                 n->suid = c->suid;
988                 n->mask |= SD_BUS_CREDS_SUID;
989         }
990
991         if (c->mask & mask & SD_BUS_CREDS_FSUID) {
992                 n->fsuid = c->fsuid;
993                 n->mask |= SD_BUS_CREDS_FSUID;
994         }
995
996         if (c->mask & mask & SD_BUS_CREDS_GID) {
997                 n->gid = c->gid;
998                 n->mask |= SD_BUS_CREDS_GID;
999         }
1000
1001         if (c->mask & mask & SD_BUS_CREDS_EGID) {
1002                 n->egid = c->egid;
1003                 n->mask |= SD_BUS_CREDS_EGID;
1004         }
1005
1006         if (c->mask & mask & SD_BUS_CREDS_SGID) {
1007                 n->sgid = c->sgid;
1008                 n->mask |= SD_BUS_CREDS_SGID;
1009         }
1010
1011         if (c->mask & mask & SD_BUS_CREDS_FSGID) {
1012                 n->fsgid = c->fsgid;
1013                 n->mask |= SD_BUS_CREDS_FSGID;
1014         }
1015
1016         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
1017                 n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
1018                 if (!n->supplementary_gids)
1019                         return -ENOMEM;
1020                 n->n_supplementary_gids = c->n_supplementary_gids;
1021                 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
1022         }
1023
1024         if (c->mask & mask & SD_BUS_CREDS_PID) {
1025                 n->pid = c->pid;
1026                 n->mask |= SD_BUS_CREDS_PID;
1027         }
1028
1029         if (c->mask & mask & SD_BUS_CREDS_TID) {
1030                 n->tid = c->tid;
1031                 n->mask |= SD_BUS_CREDS_TID;
1032         }
1033
1034         if (c->mask & mask & SD_BUS_CREDS_COMM) {
1035                 n->comm = strdup(c->comm);
1036                 if (!n->comm)
1037                         return -ENOMEM;
1038
1039                 n->mask |= SD_BUS_CREDS_COMM;
1040         }
1041
1042         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1043                 n->tid_comm = strdup(c->tid_comm);
1044                 if (!n->tid_comm)
1045                         return -ENOMEM;
1046
1047                 n->mask |= SD_BUS_CREDS_TID_COMM;
1048         }
1049
1050         if (c->mask & mask & SD_BUS_CREDS_EXE) {
1051                 n->exe = strdup(c->exe);
1052                 if (!n->exe)
1053                         return -ENOMEM;
1054
1055                 n->mask |= SD_BUS_CREDS_EXE;
1056         }
1057
1058         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
1059                 n->cmdline = memdup(c->cmdline, c->cmdline_size);
1060                 if (!n->cmdline)
1061                         return -ENOMEM;
1062
1063                 n->cmdline_size = c->cmdline_size;
1064                 n->mask |= SD_BUS_CREDS_CMDLINE;
1065         }
1066
1067         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)) {
1068                 n->cgroup = strdup(c->cgroup);
1069                 if (!n->cgroup)
1070                         return -ENOMEM;
1071
1072                 n->cgroup_root = strdup(c->cgroup_root);
1073                 if (!n->cgroup_root)
1074                         return -ENOMEM;
1075
1076                 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);
1077         }
1078
1079         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
1080                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1081                 if (!n->capability)
1082                         return -ENOMEM;
1083
1084                 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);
1085         }
1086
1087         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1088                 n->label = strdup(c->label);
1089                 if (!n->label)
1090                         return -ENOMEM;
1091                 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1092         }
1093
1094         if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1095                 n->audit_session_id = c->audit_session_id;
1096                 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1097         }
1098         if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1099                 n->audit_login_uid = c->audit_login_uid;
1100                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1101         }
1102
1103         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1104                 n->unique_name = strdup(c->unique_name);
1105                 if (!n->unique_name)
1106                         return -ENOMEM;
1107                 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
1108         }
1109
1110         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
1111                 n->well_known_names = strv_copy(c->well_known_names);
1112                 if (!n->well_known_names)
1113                         return -ENOMEM;
1114                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1115         }
1116
1117         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1118                 n->description = strdup(c->description);
1119                 if (!n->description)
1120                         return -ENOMEM;
1121                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
1122         }
1123
1124         /* Get more data */
1125
1126         r = bus_creds_add_more(n, mask,
1127                                c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
1128                                c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
1129         if (r < 0)
1130                 return r;
1131
1132         *ret = n;
1133         n = NULL;
1134         return 0;
1135 }