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