]> git.ipfire.org Git - people/ms/network.git/blame - src/networkd/main.c
networkd: Drop all capabilities except a few we would like to keep
[people/ms/network.git] / src / networkd / main.c
CommitLineData
050f4ece
MT
1/*#############################################################################
2# #
3# IPFire.org - A linux based firewall #
4# Copyright (C) 2023 IPFire Network Development Team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
eb3f6449 21#include <grp.h>
dabf344d 22#include <linux/capability.h>
eb3f6449 23#include <pwd.h>
8a88982f 24#include <stddef.h>
dabf344d 25#include <sys/capability.h>
eb3f6449
MT
26#include <sys/prctl.h>
27#include <sys/types.h>
28#include <unistd.h>
26acbb4e 29
112358f3 30#include "daemon.h"
eb3f6449
MT
31#include "logging.h"
32
dabf344d
MT
33static int cap_acquire_setpcap(void) {
34 cap_flag_value_t value;
35 int r;
36
37 // Fetch current capabilities
38 cap_t caps = cap_get_proc();
39
40 // Check if CAP_SETPCAP is already enabled
41 r = cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &value);
42 if (r) {
43 ERROR("The kernel does not seem to know CAP_SETPCAP: %m\n");
44 goto ERROR;
45 }
46
47 // It CAP_SETPCAP isn't set, we will try to set it
48 if (value != CAP_SET) {
49 const cap_value_t cap = CAP_SETPCAP;
50
51 r = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
52 if (r) {
53 ERROR("Could not set CAP_SETPCAP: %m\n");
54 goto ERROR;
55 }
56
57 // Store capabilities
58 r = cap_set_proc(caps);
59 if (r) {
60 ERROR("Could not acquire effective CAP_SETPCAP capability: %m\n");
61 goto ERROR;
62 }
63 }
64
65ERROR:
66 if (caps)
67 cap_free(caps);
68
69 return r;
70}
71
72static cap_flag_value_t keep_cap(const cap_value_t cap, const cap_value_t* keep_caps) {
73 for (const cap_value_t* c = keep_caps; *c; c++) {
74 if (cap == *c)
75 return CAP_SET;
76 }
77
78 return CAP_CLEAR;
79}
80
81static int drop_capabilities(void) {
82 int r;
83
84 const cap_value_t keep_caps[] = {
85 CAP_NET_ADMIN,
86 CAP_NET_BIND_SERVICE,
87 CAP_NET_BROADCAST,
88 CAP_NET_RAW,
89 0,
90 };
91
92 // Acquire CAP_SETPCAP
93 r = cap_acquire_setpcap();
94 if (r)
95 return r;
96
97 // Fetch the current set of capabilities
98 cap_t caps = cap_get_proc();
99
100 // Drop all capabilities that we do not need
101 for (cap_value_t cap = 1; cap <= CAP_LAST_CAP; cap++) {
102 // Skip any capabilities we would like to skip
103 cap_flag_value_t flag = keep_cap(cap, keep_caps);
104
105 // Drop the capability from the bounding set
106 if (flag == CAP_CLEAR) {
107 r = prctl(PR_CAPBSET_DROP, cap);
108 if (r) {
109 ERROR("Could not drop capability from the bounding set: %m\n");
110 goto ERROR;
111 }
112 }
113
114 r = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
115 if (r) {
116 ERROR("Could not set capability %d: %m\n", (int)cap);
117 goto ERROR;
118 }
119
120 r = cap_set_flag(caps, CAP_PERMITTED, 1, &cap, flag);
121 if (r) {
122 ERROR("Could not set capability %d: %m\n", (int)cap);
123 goto ERROR;
124 }
125
126 r = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
127 if (r) {
128 ERROR("Could not set capability %d: %m\n", (int)cap);
129 goto ERROR;
130 }
131 }
132
133 // Restore capabilities
134 r = cap_set_proc(caps);
135 if (r) {
136 ERROR("Could not restore capabilities: %m\n");
137 goto ERROR;
138 }
139
140ERROR:
141 if (caps)
142 cap_free(caps);
143
144 return r;
145}
146
eb3f6449
MT
147static int drop_privileges(const char* user) {
148 struct passwd* passwd = NULL;
149 int r;
150
151 // Fetch the current user
152 uid_t current_uid = getuid();
153
154 // If we have not been launched by root, we will assume that we have already
155 // been launched with a minimal set of privileges.
156 if (current_uid > 0)
157 return 0;
158
159 DEBUG("Dropping privileges...\n");
160
161 // Fetch information about the desired user
162 passwd = getpwnam(user);
163 if (!passwd) {
164 ERROR("Could not find user %s: %m\n", user);
165 return 1;
166 }
167
168 uid_t uid = passwd->pw_uid;
169 gid_t gid = passwd->pw_gid;
170
171 // Change group
172 r = setresgid(gid, gid, gid);
173 if (r) {
174 ERROR("Could not change group to %d: %m\n", gid);
175 return 1;
176 }
177
178 // Set any supplementary groups
179 r = setgroups(0, NULL);
180 if (r) {
181 ERROR("Could not set supplementary groups: %m\n");
182 return 1;
183 }
184
185 // Do not drop any capabilities when we change to the new user
186 r = prctl(PR_SET_KEEPCAPS, 1);
187 if (r) {
188 ERROR("Could not set PR_SET_KEEPCAPS: %m\n");
189 return 1;
190 }
191
192 // Change to the new user
193 r = setresuid(uid, uid, uid);
194 if (r) {
195 ERROR("Could not change user to %d: %m\n", uid);
196 return 1;
197 }
198
199 // Reset PR_SET_KEEPCAPS
200 r = prctl(PR_SET_KEEPCAPS, 0);
201 if (r) {
202 ERROR("Could not set PR_SET_KEEPCAPS: %m\n");
203 return 1;
204 }
205
dabf344d
MT
206 // Drop capabilities
207 r = drop_capabilities();
208 if (r)
209 return r;
210
eb3f6449
MT
211 return 0;
212}
112358f3 213
050f4ece 214int main(int argc, char** argv) {
112358f3
MT
215 struct nw_daemon* daemon = NULL;
216 int r;
217
eb3f6449
MT
218 // Drop privileges
219 r = drop_privileges("network");
220 if (r)
221 return r;
26acbb4e 222
112358f3
MT
223 // Create the daemon
224 r = nw_daemon_create(&daemon);
225 if (r)
8a88982f 226 return r;
26acbb4e 227
c7e1b5db
MT
228 // Run the daemon
229 r = nw_daemon_run(daemon);
26acbb4e 230
8a88982f 231 // Cleanup
112358f3
MT
232 if (daemon)
233 nw_daemon_unref(daemon);
234
8a88982f 235 return r;
050f4ece 236}