blob: ba3da78dda9244cc60b53c762011da87255614b9 [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
Alexander Afanasyev9cfeeca2015-02-12 16:44:24 -0800134 if (!userName.empty() || !groupName.empty()) {
135 throw Error("Dropping and raising privileges is not supported on this platform");
136 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800137#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600138}
139
140void
141PrivilegeHelper::drop()
142{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800143#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600144 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
145 if (::setegid(s_normalGid) != 0)
146 {
147 std::stringstream error;
148 error << "Failed to drop to effective gid=" << s_normalGid;
149
150 throw PrivilegeHelper::Error(error.str());
151 }
152
153 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
154 if (::seteuid(s_normalUid) != 0)
155 {
156 std::stringstream error;
157 error << "Failed to drop to effective uid=" << s_normalUid;
158
159 throw PrivilegeHelper::Error(error.str());
160 }
161
162 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800163#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800164 NFD_LOG_WARN("Dropping privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800165#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600166}
167
168void
169PrivilegeHelper::raise()
170{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800171#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600172 NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
173 if (::seteuid(s_privilegedUid) != 0)
174 {
175 std::stringstream error;
176 error << "Failed to elevate to effective uid=" << s_privilegedUid;
177
178 throw PrivilegeHelper::Error(error.str());
179 }
180
181 NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
182 if (::setegid(s_privilegedGid) != 0)
183 {
184 std::stringstream error;
185 error << "Failed to elevate to effective gid=" << s_privilegedGid;
186
187 throw PrivilegeHelper::Error(error.str());
188 }
189 NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800190#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800191 NFD_LOG_WARN("Elevating privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800192#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600193}
194
195void
196PrivilegeHelper::runElevated(function<void()> f)
197{
198 raise();
199
200 try
201 {
202 f();
203 }
204 catch (...)
205 {
206 drop();
207 throw;
208 }
209 drop();
210}
211
212} // namespace nfd