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