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