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