OpenVPN 3 Core Library
Loading...
Searching...
No Matches
usergroup.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#ifndef OPENVPN_COMMON_USERGROUP_H
13#define OPENVPN_COMMON_USERGROUP_H
14
15#include <pwd.h>
16#include <grp.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <errno.h>
20
21#include <string>
22
24
25#ifdef OPENVPN_PLATFORM_LINUX
26#include <sys/prctl.h>
27#endif
28
33
34namespace openvpn {
35// NOTE: -- SetUserGroup object does not own passwd and group
36// objects, therefore *pw and *gr can change under us.
38{
39 public:
40 OPENVPN_EXCEPTION(user_group_err);
41
42 SetUserGroup(const std::string &user, const std::string &group, const bool strict)
43 : SetUserGroup(user.empty() ? nullptr : user.c_str(),
44 group.empty() ? nullptr : group.c_str(),
45 strict)
46 {
47 }
48
49 SetUserGroup(const char *user, const char *group, const bool strict)
50 : pw(nullptr),
51 gr(nullptr)
52 {
53 if (user)
54 {
55 pw = ::getpwnam(user);
56 if (!pw && strict)
57 OPENVPN_THROW(user_group_err, "user lookup failed for '" << user << '\'');
59 }
60 if (group)
61 {
62 gr = ::getgrnam(group);
63 if (!gr && strict)
64 OPENVPN_THROW(user_group_err, "group lookup failed for '" << group << '\'');
66 }
67 }
68
69 virtual ~SetUserGroup() = default;
70
71 const std::string &user() const
72 {
73 return user_name;
74 }
75
76 const std::string &group() const
77 {
78 return group_name;
79 }
80
81 virtual void pre_thread() const
82 {
83 }
84
85 virtual void post_thread() const
86 {
87 }
88
89 virtual void activate() const
90 {
92 do_setuid();
94 }
95
96 void chown(const std::string &fn) const
97 {
98 if (pw && gr)
99 {
100 const int status = ::chown(fn.c_str(), uid(), gid());
101 if (status < 0)
102 {
103 const int eno = errno;
104 OPENVPN_THROW(user_group_err, "chown " << user_name << '.' << group_name << ' ' << fn << " : " << strerror_str(eno));
105 }
106 }
107 }
108
109 void chown(const int fd, const std::string &title) const
110 {
111 if (pw && gr)
112 {
113 const int status = ::fchown(fd, uid(), gid());
114 if (status < 0)
115 {
116 const int eno = errno;
117 OPENVPN_THROW(user_group_err, "chown " << user_name << '.' << group_name << ' ' << title << " : " << strerror_str(eno));
118 }
119 }
120 }
121
123 {
124 pw = nullptr;
125 gr = nullptr;
126 }
127
128 uid_t uid() const
129 {
130 if (pw)
131 return pw->pw_uid;
132 else
133 return -1;
134 }
135
136 gid_t gid() const
137 {
138 if (gr)
139 return gr->gr_gid;
140 else
141 return -1;
142 }
143
144 bool uid_defined() const
145 {
146 return bool(pw);
147 }
148
149 bool gid_defined() const
150 {
151 return bool(gr);
152 }
153
154 bool defined() const
155 {
156 return uid_defined() && gid_defined();
157 }
158
159 protected:
161 {
162 if (gr)
163 {
164 if (::setgid(gr->gr_gid))
165 {
166 const int eno = errno;
167 OPENVPN_THROW(user_group_err, "setgid failed for group '" << group_name << "': " << strerror_str(eno));
168 }
169 gid_t gr_list[1];
170 gr_list[0] = gr->gr_gid;
171 if (::setgroups(1, gr_list))
172 {
173 const int eno = errno;
174 OPENVPN_THROW(user_group_err, "setgroups failed for group '" << group_name << "': " << strerror_str(eno));
175 }
176 OPENVPN_LOG("GID set to '" << group_name << '\'');
177 }
178 }
179
180 void do_setuid() const
181 {
182 if (pw)
183 {
184 if (::setuid(pw->pw_uid))
185 {
186 const int eno = errno;
187 OPENVPN_THROW(user_group_err, "setuid failed for user '" << user_name << "': " << strerror_str(eno));
188 }
189 OPENVPN_LOG("UID set to '" << user_name << '\'');
190 }
191 }
192
193 void retain_core_dumps() const
194 {
195#ifdef OPENVPN_PLATFORM_LINUX
196 // retain core dumpability after setgid/setuid
197 if (gr || pw)
198 {
199 if (::prctl(PR_SET_DUMPABLE, 1))
200 {
201 const int eno = errno;
202 OPENVPN_THROW(user_group_err, "SetUserGroup prctl PR_SET_DUMPABLE fail: " << strerror_str(eno));
203 }
204 }
205#endif
206 }
207
208 std::string user_name;
209 std::string group_name;
210
211 struct passwd *pw;
212 struct group *gr;
213};
214} // namespace openvpn
215
216#endif
virtual void post_thread() const
Definition usergroup.hpp:85
void chown(const int fd, const std::string &title) const
struct group * gr
bool gid_defined() const
SetUserGroup(const char *user, const char *group, const bool strict)
Definition usergroup.hpp:49
virtual void pre_thread() const
Definition usergroup.hpp:81
void do_setuid() const
void chown(const std::string &fn) const
Definition usergroup.hpp:96
void do_setgid_setgroups() const
const std::string & user() const
Definition usergroup.hpp:71
bool uid_defined() const
virtual ~SetUserGroup()=default
SetUserGroup(const std::string &user, const std::string &group, const bool strict)
Definition usergroup.hpp:42
OPENVPN_EXCEPTION(user_group_err)
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