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