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