privilege-helper.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2017, 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.
10  *
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/>.
24  */
25 
26 #include "privilege-helper.hpp"
27 #include "core/logger.hpp"
28 
29 #include <pwd.h>
30 #include <grp.h>
31 
32 #include <sstream>
33 
34 namespace nfd {
35 
36 NFD_LOG_INIT("PrivilegeHelper");
37 
38 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
39 uid_t PrivilegeHelper::s_normalUid = ::geteuid();
40 gid_t PrivilegeHelper::s_normalGid = ::getegid();
41 
42 uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
43 gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
44 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
45 
46 void
47 PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
48 {
49 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
50  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 
59  // 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  }
135 #else
136  if (!userName.empty() || !groupName.empty()) {
137  throw Error("Dropping and raising privileges is not supported on this platform");
138  }
139 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
140 }
141 
142 void
144 {
145 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
146  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());
165 #else
166  NFD_LOG_WARN("Dropping privileges is not supported on this platform");
167 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
168 }
169 
170 void
171 PrivilegeHelper::raise()
172 {
173 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
174  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());
192 #else
193  NFD_LOG_WARN("Elevating privileges is not supported on this platform");
194 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
195 }
196 
197 void
198 PrivilegeHelper::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
#define NFD_LOG_WARN(expression)
Definition: logger.hpp:163
#define NFD_LOG_INFO(expression)
Definition: logger.hpp:162
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
static void initialize(const std::string &userName, const std::string &groupName)
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
static void runElevated(function< void()> f)
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:160
represents a serious seteuid/gid failure