NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
privilege-helper.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "privilege-helper.hpp"
27 #include "core/logger.hpp"
28 
29 #include <pwd.h>
30 #include <grp.h>
31 
32 namespace nfd {
33 
34 NFD_LOG_INIT("PrivilegeHelper");
35 
36 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
37 uid_t PrivilegeHelper::s_normalUid = ::geteuid();
38 gid_t PrivilegeHelper::s_normalGid = ::getegid();
39 
40 uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
41 gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
42 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
43 
44 void
45 PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
46 {
47 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
48  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 
57  // 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  }
133 #else
134  if (!userName.empty() || !groupName.empty()) {
135  throw Error("Dropping and raising privileges is not supported on this platform");
136  }
137 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
138 }
139 
140 void
142 {
143 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
144  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());
163 #else
164  NFD_LOG_WARN("Dropping privileges is not supported on this platform");
165 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
166 }
167 
168 void
169 PrivilegeHelper::raise()
170 {
171 #ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
172  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());
190 #else
191  NFD_LOG_WARN("Elevating privileges is not supported on this platform");
192 #endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
193 }
194 
195 void
196 PrivilegeHelper::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
static void runElevated(function< void()> f)
represents a serious seteuid/gid failure
#define NFD_LOG_WARN(expression)
Definition: logger.hpp:58
#define NFD_LOG_INFO(expression)
Definition: logger.hpp:56
static void initialize(const std::string &userName, const std::string &groupName)
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54