blob: b0ca116d5e866acd40a0515ba2787104e92502dc [file] [log] [blame]
Steve DiBenedetto24b9a642014-04-07 15:45:39 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa997d292017-08-24 20:16:59 -04002/*
3 * Copyright (c) 2014-2017, Regents of the University of California,
Alexander Afanasyev7c10b3b2015-01-20 12:24:27 -08004 * 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
Davide Pesaventoa997d292017-08-24 20:16:59 -040032#include <sstream>
33
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060034namespace nfd {
35
36NFD_LOG_INIT("PrivilegeHelper");
37
Alexander Afanasyev49343f62015-01-26 21:58:07 -080038#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Alexander Afanasyevff489a22014-04-22 23:50:39 -070039uid_t PrivilegeHelper::s_normalUid = ::geteuid();
40gid_t PrivilegeHelper::s_normalGid = ::getegid();
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060041
Alexander Afanasyevff489a22014-04-22 23:50:39 -070042uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
43gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
Alexander Afanasyev49343f62015-01-26 21:58:07 -080044#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060045
46void
47PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
48{
Alexander Afanasyev49343f62015-01-26 21:58:07 -080049#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060050 static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16kB
51 static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
52
53 static const size_t FALLBACK_GROUP_BUFFER_SIZE = 1024;
54 static const size_t FALLBACK_PASSWD_BUFFER_SIZE = 1024;
55
56 NFD_LOG_TRACE("initializing privilege helper with user \"" << userName << "\""
57 << " group \"" << groupName << "\"");
58
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060059 // workflow from man getpwnam_r
60
61 if (!groupName.empty())
62 {
63 static int groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
64
65 if (groupSize == -1)
66 {
67 groupSize = FALLBACK_GROUP_BUFFER_SIZE;
68 }
69
70 std::vector<char> groupBuffer(groupSize);
71 struct group group;
72 struct group* groupResult = 0;
73
74 int errorCode = getgrnam_r(groupName.c_str(), &group,
75 &groupBuffer[0], groupSize, &groupResult);
76
77 while (errorCode == ERANGE)
78 {
79 if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
80 {
81 throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct group");
82 }
83
84 groupBuffer.resize(groupBuffer.size() * 2);
85
86 errorCode = getgrnam_r(groupName.c_str(), &group,
87 &groupBuffer[0], groupBuffer.size(), &groupResult);
88 }
89
90 if (errorCode != 0 || !groupResult)
91 {
92 throw PrivilegeHelper::Error("Failed to get gid for \"" + groupName + "\"");
93 }
94
95 s_normalGid = group.gr_gid;
96 }
97
98 if (!userName.empty())
99 {
100 static int passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
101
102 if (passwdSize == -1)
103 {
104 passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
105 }
106
107 std::vector<char> passwdBuffer(passwdSize);
108 struct passwd passwd;
109 struct passwd* passwdResult = 0;
110
111 int errorCode =
112 getpwnam_r(userName.c_str(), &passwd,
113 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
114
115 while (errorCode == ERANGE)
116 {
117 if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
118 {
119 throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct passwd");
120 }
121
122 passwdBuffer.resize(passwdBuffer.size() * 2);
123
124 errorCode = getpwnam_r(userName.c_str(), &passwd,
125 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
126 }
127
128 if (errorCode != 0 || !passwdResult)
129 {
130 throw PrivilegeHelper::Error("Failed to get uid for \"" + userName + "\"");
131 }
132
133 s_normalUid = passwd.pw_uid;
134 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800135#else
Alexander Afanasyev9cfeeca2015-02-12 16:44:24 -0800136 if (!userName.empty() || !groupName.empty()) {
137 throw Error("Dropping and raising privileges is not supported on this platform");
138 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800139#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600140}
141
142void
143PrivilegeHelper::drop()
144{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800145#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600146 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
147 if (::setegid(s_normalGid) != 0)
148 {
149 std::stringstream error;
150 error << "Failed to drop to effective gid=" << s_normalGid;
151
152 throw PrivilegeHelper::Error(error.str());
153 }
154
155 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
156 if (::seteuid(s_normalUid) != 0)
157 {
158 std::stringstream error;
159 error << "Failed to drop to effective uid=" << s_normalUid;
160
161 throw PrivilegeHelper::Error(error.str());
162 }
163
164 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800165#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800166 NFD_LOG_WARN("Dropping privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800167#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600168}
169
170void
171PrivilegeHelper::raise()
172{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800173#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600174 NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
175 if (::seteuid(s_privilegedUid) != 0)
176 {
177 std::stringstream error;
178 error << "Failed to elevate to effective uid=" << s_privilegedUid;
179
180 throw PrivilegeHelper::Error(error.str());
181 }
182
183 NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
184 if (::setegid(s_privilegedGid) != 0)
185 {
186 std::stringstream error;
187 error << "Failed to elevate to effective gid=" << s_privilegedGid;
188
189 throw PrivilegeHelper::Error(error.str());
190 }
191 NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800192#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800193 NFD_LOG_WARN("Elevating privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800194#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600195}
196
197void
198PrivilegeHelper::runElevated(function<void()> f)
199{
200 raise();
201
202 try
203 {
204 f();
205 }
206 catch (...)
207 {
208 drop();
209 throw;
210 }
211 drop();
212}
213
214} // namespace nfd