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