]> code.delx.au - pulseaudio/blob - src/daemon/caps.c
Use LGPL 2.1 on all files previously using LGPL 2
[pulseaudio] / src / daemon / caps.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <unistd.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/types.h>
31
32 #include <pulse/i18n.h>
33
34 #include <pulsecore/macro.h>
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/core-util.h>
38
39 #ifdef HAVE_SYS_CAPABILITY_H
40 #include <sys/capability.h>
41 #endif
42 #ifdef HAVE_SYS_PRCTL_H
43 #include <sys/prctl.h>
44 #endif
45
46 #include "caps.h"
47
48 /* Glibc <= 2.2 has broken unistd.h */
49 #if defined(linux) && (__GLIBC__ <= 2 && __GLIBC_MINOR__ <= 2)
50 int setresgid(gid_t r, gid_t e, gid_t s);
51 int setresuid(uid_t r, uid_t e, uid_t s);
52 #endif
53
54 #ifdef HAVE_GETUID
55
56 /* Drop root rights when called SUID root */
57 void pa_drop_root(void) {
58 uid_t uid = getuid();
59
60 if (uid == 0 || geteuid() != 0)
61 return;
62
63 pa_log_info(_("Dropping root privileges."));
64
65 #if defined(HAVE_SETRESUID)
66 pa_assert_se(setresuid(uid, uid, uid) >= 0);
67 #elif defined(HAVE_SETREUID)
68 pa_assert_se(setreuid(uid, uid) >= 0);
69 #else
70 pa_assert_se(setuid(uid) >= 0);
71 pa_assert_se(seteuid(uid) >= 0);
72 #endif
73
74 pa_assert_se(getuid() == uid);
75 pa_assert_se(geteuid() == uid);
76 }
77
78 #else
79
80 void pa_drop_root(void) {
81 }
82
83 #endif
84
85 #if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H)
86
87 /* Limit permitted capabilities set to CAPSYS_NICE */
88 void pa_limit_caps(void) {
89 cap_t caps;
90 cap_value_t nice_cap = CAP_SYS_NICE;
91
92 pa_assert_se(caps = cap_init());
93 pa_assert_se(cap_clear(caps) == 0);
94 pa_assert_se(cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET) == 0);
95 pa_assert_se(cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET) == 0);
96
97 if (cap_set_proc(caps) < 0)
98 /* Hmm, so we couldn't limit our caps, which probably means we
99 * hadn't any in the first place, so let's just make sure of
100 * that */
101 pa_drop_caps();
102 else
103 pa_log_info(_("Limited capabilities successfully to CAP_SYS_NICE."));
104
105 pa_assert_se(cap_free(caps) == 0);
106
107 pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
108 }
109
110 /* Drop all capabilities, effectively becoming a normal user */
111 void pa_drop_caps(void) {
112 cap_t caps;
113
114 #ifndef __OPTIMIZE__
115 /* Valgrind doesn't not know set_caps, so we bypass it here -- but
116 * only in development builds.*/
117
118 if (pa_in_valgrind() && !pa_have_caps())
119 return;
120 #endif
121
122 pa_assert_se(prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == 0);
123
124 pa_assert_se(caps = cap_init());
125 pa_assert_se(cap_clear(caps) == 0);
126 pa_assert_se(cap_set_proc(caps) == 0);
127 pa_assert_se(cap_free(caps) == 0);
128
129 pa_assert_se(!pa_have_caps());
130 }
131
132 pa_bool_t pa_have_caps(void) {
133 cap_t caps;
134 cap_flag_value_t flag = CAP_CLEAR;
135
136 #ifdef __OPTIMIZE__
137 pa_assert_se(caps = cap_get_proc());
138 #else
139 if (!(caps = cap_get_proc()))
140 return FALSE;
141 #endif
142 pa_assert_se(cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0);
143 pa_assert_se(cap_free(caps) == 0);
144
145 return flag == CAP_SET;
146 }
147
148 #else
149
150 /* NOOPs in case capabilities are not available. */
151 void pa_limit_caps(void) {
152 }
153
154 void pa_drop_caps(void) {
155 pa_drop_root();
156 }
157
158 pa_bool_t pa_have_caps(void) {
159 return FALSE;
160 }
161
162 #endif