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