1/* $Id$ */
2
3/***
4  This file is part of avahi.
5
6  avahi is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Lesser General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  avahi is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14  Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with avahi; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  USA.
20***/
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <sys/types.h>
27#include <assert.h>
28#include <errno.h>
29#include <string.h>
30#include <sys/capability.h>
31#include <sys/prctl.h>
32
33#include <avahi-core/log.h>
34
35#include "caps.h"
36
37int avahi_caps_reduce(void) {
38    int ret = 0;
39    cap_t caps;
40    static cap_value_t cap_values[] = { CAP_SYS_CHROOT, CAP_SETUID, CAP_SETGID };
41
42    /* Let's reduce our caps to the minimum set and tell Linux to keep
43     * them across setuid(). This is called before we drop
44     * privileges. */
45
46    caps = cap_init();
47    assert(caps);
48    cap_clear(caps);
49
50    cap_set_flag(caps, CAP_EFFECTIVE, 3, cap_values, CAP_SET);
51    cap_set_flag(caps, CAP_PERMITTED, 3, cap_values, CAP_SET);
52
53    if (cap_set_proc(caps) < 0) {
54        avahi_log_error("cap_set_proc() failed: %s", strerror(errno));
55        ret = -1;
56    }
57    cap_free(caps);
58
59    /* Retain capabilities across setuid() */
60    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
61        avahi_log_error("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno));
62        ret = -1;
63    }
64
65    return ret;
66}
67
68int avahi_caps_reduce2(void) {
69    int ret = 0;
70    cap_t caps;
71    static cap_value_t cap_values[] = { CAP_SYS_CHROOT };
72
73    /* Reduce our caps to the bare minimum and tell Linux not to keep
74     * them across setuid(). This is called after we drop
75     * privileges. */
76
77    /* No longer retain caps across setuid() */
78    if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
79        avahi_log_error("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno));
80        ret = -1;
81    }
82
83    caps = cap_init();
84    assert(caps);
85    cap_clear(caps);
86
87    /* setuid() zeroed our effective caps, let's get them back */
88    cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_values, CAP_SET);
89    cap_set_flag(caps, CAP_PERMITTED, 1, cap_values, CAP_SET);
90
91    if (cap_set_proc(caps) < 0) {
92        avahi_log_error("cap_set_proc() failed: %s", strerror(errno));
93        ret = -1;
94    }
95    cap_free(caps);
96
97    return ret;
98}
99
100int avahi_caps_drop_all(void) {
101    cap_t caps;
102    int ret = 0;
103
104    /* Drop all capabilities and turn ourselves into a normal user process */
105
106    caps = cap_init();
107    assert(caps);
108    cap_clear(caps);
109
110    if (cap_set_proc(caps) < 0) {
111        avahi_log_error("cap_set_proc() failed: %s", strerror(errno));
112        ret = -1;
113    }
114    cap_free(caps);
115
116    return ret;
117}
118