blob: 129633130ad94393e9c9b617f9e063f24af0863b [file] [log] [blame]
Steve DiBenedetto24b9a642014-04-07 15:45:39 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014 Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology
9 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
24
25#include "privilege-helper.hpp"
26#include "core/logger.hpp"
27
28#include <pwd.h>
29#include <grp.h>
30
31namespace nfd {
32
33NFD_LOG_INIT("PrivilegeHelper");
34
Alexander Afanasyev49343f62015-01-26 21:58:07 -080035#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Alexander Afanasyevff489a22014-04-22 23:50:39 -070036uid_t PrivilegeHelper::s_normalUid = ::geteuid();
37gid_t PrivilegeHelper::s_normalGid = ::getegid();
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060038
Alexander Afanasyevff489a22014-04-22 23:50:39 -070039uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
40gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
Alexander Afanasyev49343f62015-01-26 21:58:07 -080041#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060042
43void
44PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
45{
Alexander Afanasyev49343f62015-01-26 21:58:07 -080046#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060047 static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16kB
48 static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
49
50 static const size_t FALLBACK_GROUP_BUFFER_SIZE = 1024;
51 static const size_t FALLBACK_PASSWD_BUFFER_SIZE = 1024;
52
53 NFD_LOG_TRACE("initializing privilege helper with user \"" << userName << "\""
54 << " group \"" << groupName << "\"");
55
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060056 // workflow from man getpwnam_r
57
58 if (!groupName.empty())
59 {
60 static int groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
61
62 if (groupSize == -1)
63 {
64 groupSize = FALLBACK_GROUP_BUFFER_SIZE;
65 }
66
67 std::vector<char> groupBuffer(groupSize);
68 struct group group;
69 struct group* groupResult = 0;
70
71 int errorCode = getgrnam_r(groupName.c_str(), &group,
72 &groupBuffer[0], groupSize, &groupResult);
73
74 while (errorCode == ERANGE)
75 {
76 if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
77 {
78 throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct group");
79 }
80
81 groupBuffer.resize(groupBuffer.size() * 2);
82
83 errorCode = getgrnam_r(groupName.c_str(), &group,
84 &groupBuffer[0], groupBuffer.size(), &groupResult);
85 }
86
87 if (errorCode != 0 || !groupResult)
88 {
89 throw PrivilegeHelper::Error("Failed to get gid for \"" + groupName + "\"");
90 }
91
92 s_normalGid = group.gr_gid;
93 }
94
95 if (!userName.empty())
96 {
97 static int passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
98
99 if (passwdSize == -1)
100 {
101 passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
102 }
103
104 std::vector<char> passwdBuffer(passwdSize);
105 struct passwd passwd;
106 struct passwd* passwdResult = 0;
107
108 int errorCode =
109 getpwnam_r(userName.c_str(), &passwd,
110 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
111
112 while (errorCode == ERANGE)
113 {
114 if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
115 {
116 throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct passwd");
117 }
118
119 passwdBuffer.resize(passwdBuffer.size() * 2);
120
121 errorCode = getpwnam_r(userName.c_str(), &passwd,
122 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
123 }
124
125 if (errorCode != 0 || !passwdResult)
126 {
127 throw PrivilegeHelper::Error("Failed to get uid for \"" + userName + "\"");
128 }
129
130 s_normalUid = passwd.pw_uid;
131 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800132#else
133 throw Error("Dropping and raising privileges is not supported on this platform");
134#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600135}
136
137void
138PrivilegeHelper::drop()
139{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800140#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600141 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
142 if (::setegid(s_normalGid) != 0)
143 {
144 std::stringstream error;
145 error << "Failed to drop to effective gid=" << s_normalGid;
146
147 throw PrivilegeHelper::Error(error.str());
148 }
149
150 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
151 if (::seteuid(s_normalUid) != 0)
152 {
153 std::stringstream error;
154 error << "Failed to drop to effective uid=" << s_normalUid;
155
156 throw PrivilegeHelper::Error(error.str());
157 }
158
159 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800160#else
161 throw Error("Dropping privileges is not supported on this platform");
162#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600163}
164
165void
166PrivilegeHelper::raise()
167{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800168#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600169 NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
170 if (::seteuid(s_privilegedUid) != 0)
171 {
172 std::stringstream error;
173 error << "Failed to elevate to effective uid=" << s_privilegedUid;
174
175 throw PrivilegeHelper::Error(error.str());
176 }
177
178 NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
179 if (::setegid(s_privilegedGid) != 0)
180 {
181 std::stringstream error;
182 error << "Failed to elevate to effective gid=" << s_privilegedGid;
183
184 throw PrivilegeHelper::Error(error.str());
185 }
186 NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800187#else
188 throw Error("Elevating privileges is not supported on this platform");
189#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600190}
191
192void
193PrivilegeHelper::runElevated(function<void()> f)
194{
195 raise();
196
197 try
198 {
199 f();
200 }
201 catch (...)
202 {
203 drop();
204 throw;
205 }
206 drop();
207}
208
209} // namespace nfd