OpenVPN 3 Core Library
Loading...
Searching...
No Matches
usergroup_retain_cap.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Drop root privileges but retain one or more Linux capabilities
13
14#pragma once
15
16#include <sys/capability.h>
17
18#include <string>
19#include <vector>
20#include <utility>
21#include <initializer_list>
22
25
26#ifndef OPENVPN_PLATFORM_LINUX
27#error SetUserGroupRetainCap requires Linux
28#endif
29
30namespace openvpn {
31
33{
34 public:
35 SetUserGroupRetainCap(const std::string &user,
36 const std::string &group,
37 const bool strict,
38 std::initializer_list<cap_value_t> retain_caps_arg)
39 : SetUserGroup(user, group, strict),
40 retain_caps(retain_caps_arg)
41 {
42 grab_root();
43 }
44
46 const char *group,
47 const bool strict,
48 std::initializer_list<cap_value_t> retain_caps_arg)
49 : SetUserGroup(user, group, strict),
50 retain_caps(retain_caps_arg)
51 {
52 grab_root();
53 }
54
55 // call first in all threads before user/group downgrade
56 virtual void pre_thread() const override
57 {
58 if (!pw)
59 return;
60
61 // create a capabilities object
62 Capabilities cap("pre_thread");
63
64 // set retained capabilities + setuid/setgid
66
67 // commit it to kernel
68 cap.set_proc();
69
70 // retain the capabilities across identity change
71 if (::prctl(PR_SET_KEEPCAPS, 1L))
72 {
73 const int eno = errno;
74 OPENVPN_THROW(user_group_err, "SetUserGroupRetainCap prctl PR_SET_KEEPCAPS fail: " << strerror_str(eno));
75 }
76 }
77
78 // call once after pre_thread() called in each thread
79 virtual void activate() const override
80 {
81 if (!pw)
82 {
84 return;
85 }
86
87 // set GID/Groups
89
90 // drop extra privileges (aside from capabilities)
91 if (::setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
92 {
93 const int eno = errno;
94 OPENVPN_THROW(user_group_err, "SetUserGroupRetainCap setresuid user fail: " << strerror_str(eno));
95 }
96
97 // retain core dumps after UID/GID downgrade
99
100 // logging
101 {
102 Capabilities cap("logging");
104 OPENVPN_LOG("UID [" << cap.to_string() << "] set to '" << user_name << '\'');
105 }
106 }
107
108 // call in all threads after activate()
109 virtual void post_thread() const override
110 {
111 if (!pw)
112 return;
113
114 // create a capabilities object
115 Capabilities cap("post_thread");
116
117 // set retained capabilities
119
120 // commit it to kernel
121 cap.set_proc();
122 }
123
124 private:
126 {
127 public:
128 Capabilities(std::string title_arg)
129 : capabilities(::cap_init()),
130 title(std::move(title_arg))
131 {
132 }
133
135 {
136 ::cap_free(capabilities);
137 }
138
139 void set_flag(const std::vector<cap_value_t> &caps)
140 {
141 if (::cap_set_flag(capabilities, CAP_PERMITTED, numeric_cast<int>(caps.size()), caps.data(), CAP_SET)
142 || ::cap_set_flag(capabilities, CAP_EFFECTIVE, numeric_cast<int>(caps.size()), caps.data(), CAP_SET))
143 {
144 const int eno = errno;
145 OPENVPN_THROW(user_group_err, "SetUserGroupRetainCap::Capabilities: cap_set_flag " << title << " fail: " << strerror_str(eno));
146 }
147 }
148
149 void set_flag_with_setuid_setgid(std::vector<cap_value_t> caps)
150 {
151 caps.push_back(CAP_SETUID);
152 caps.push_back(CAP_SETGID);
153 set_flag(caps);
154 }
155
156 void set_proc()
157 {
158 if (::cap_set_proc(capabilities))
159 {
160 const int eno = errno;
161 OPENVPN_THROW(user_group_err, "SetUserGroupRetainCap::Capabilities: cap_set_proc " << title << " fail: " << strerror_str(eno));
162 }
163 }
164
165 std::string to_string() const
166 {
167 char *txt = ::cap_to_text(capabilities, nullptr);
168 std::string ret(txt);
169 ::cap_free(txt);
170 return ret;
171 }
172
173 private:
174 Capabilities(const Capabilities &) = delete;
176
177 const cap_t capabilities;
178 const std::string title;
179 };
180
182 {
183 // get full root privileges
184 if (::setresuid(0, 0, 0))
185 {
186 const int eno = errno;
187 OPENVPN_THROW(user_group_err, "SetUserGroupRetainCap setresuid root fail: " << strerror_str(eno));
188 }
189 }
190
191 const std::vector<cap_value_t> retain_caps;
192};
193
194} // namespace openvpn
void set_flag(const std::vector< cap_value_t > &caps)
Capabilities(const Capabilities &)=delete
void set_flag_with_setuid_setgid(std::vector< cap_value_t > caps)
Capabilities & operator=(const Capabilities &)=delete
virtual void post_thread() const override
SetUserGroupRetainCap(const char *user, const char *group, const bool strict, std::initializer_list< cap_value_t > retain_caps_arg)
SetUserGroupRetainCap(const std::string &user, const std::string &group, const bool strict, std::initializer_list< cap_value_t > retain_caps_arg)
virtual void activate() const override
virtual void pre_thread() const override
const std::vector< cap_value_t > retain_caps
void do_setgid_setgroups() const
const std::string & user() const
Definition usergroup.hpp:71
const std::string & group() const
Definition usergroup.hpp:76
void retain_core_dumps() const
virtual void activate() const
Definition usergroup.hpp:89
struct passwd * pw
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_LOG(args)
std::string strerror_str(const int errnum)
Definition strerror.hpp:21
std::string ret