NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
privilege-helper.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
25 #include "privilege-helper.hpp"
26 #include "core/logger.hpp"
27 
28 #include <pwd.h>
29 #include <grp.h>
30 
31 namespace nfd {
32 
33 NFD_LOG_INIT("PrivilegeHelper");
34 
35 uid_t PrivilegeHelper::s_normalUid = ::geteuid();
36 gid_t PrivilegeHelper::s_normalGid = ::getegid();
37 
38 uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
39 gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
40 
41 void
42 PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
43 {
44  static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16kB
45  static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
46 
47  static const size_t FALLBACK_GROUP_BUFFER_SIZE = 1024;
48  static const size_t FALLBACK_PASSWD_BUFFER_SIZE = 1024;
49 
50  NFD_LOG_TRACE("initializing privilege helper with user \"" << userName << "\""
51  << " group \"" << groupName << "\"");
52 
53  // workflow from man getpwnam_r
54 
55  if (!groupName.empty())
56  {
57  static int groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
58 
59  if (groupSize == -1)
60  {
61  groupSize = FALLBACK_GROUP_BUFFER_SIZE;
62  }
63 
64  std::vector<char> groupBuffer(groupSize);
65  struct group group;
66  struct group* groupResult = 0;
67 
68  int errorCode = getgrnam_r(groupName.c_str(), &group,
69  &groupBuffer[0], groupSize, &groupResult);
70 
71  while (errorCode == ERANGE)
72  {
73  if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
74  {
75  throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct group");
76  }
77 
78  groupBuffer.resize(groupBuffer.size() * 2);
79 
80  errorCode = getgrnam_r(groupName.c_str(), &group,
81  &groupBuffer[0], groupBuffer.size(), &groupResult);
82  }
83 
84  if (errorCode != 0 || !groupResult)
85  {
86  throw PrivilegeHelper::Error("Failed to get gid for \"" + groupName + "\"");
87  }
88 
89  s_normalGid = group.gr_gid;
90  }
91 
92  if (!userName.empty())
93  {
94  static int passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
95 
96  if (passwdSize == -1)
97  {
98  passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
99  }
100 
101  std::vector<char> passwdBuffer(passwdSize);
102  struct passwd passwd;
103  struct passwd* passwdResult = 0;
104 
105  int errorCode =
106  getpwnam_r(userName.c_str(), &passwd,
107  &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
108 
109  while (errorCode == ERANGE)
110  {
111  if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
112  {
113  throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct passwd");
114  }
115 
116  passwdBuffer.resize(passwdBuffer.size() * 2);
117 
118  errorCode = getpwnam_r(userName.c_str(), &passwd,
119  &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
120  }
121 
122  if (errorCode != 0 || !passwdResult)
123  {
124  throw PrivilegeHelper::Error("Failed to get uid for \"" + userName + "\"");
125  }
126 
127  s_normalUid = passwd.pw_uid;
128  }
129 }
130 
131 void
133 {
134  NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
135  if (::setegid(s_normalGid) != 0)
136  {
137  std::stringstream error;
138  error << "Failed to drop to effective gid=" << s_normalGid;
139 
140  throw PrivilegeHelper::Error(error.str());
141  }
142 
143  NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
144  if (::seteuid(s_normalUid) != 0)
145  {
146  std::stringstream error;
147  error << "Failed to drop to effective uid=" << s_normalUid;
148 
149  throw PrivilegeHelper::Error(error.str());
150  }
151 
152  NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
153 }
154 
155 void
156 PrivilegeHelper::raise()
157 {
158  NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
159  if (::seteuid(s_privilegedUid) != 0)
160  {
161  std::stringstream error;
162  error << "Failed to elevate to effective uid=" << s_privilegedUid;
163 
164  throw PrivilegeHelper::Error(error.str());
165  }
166 
167  NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
168  if (::setegid(s_privilegedGid) != 0)
169  {
170  std::stringstream error;
171  error << "Failed to elevate to effective gid=" << s_privilegedGid;
172 
173  throw PrivilegeHelper::Error(error.str());
174  }
175  NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
176 }
177 
178 void
179 PrivilegeHelper::runElevated(function<void()> f)
180 {
181  raise();
182 
183  try
184  {
185  f();
186  }
187  catch (...)
188  {
189  drop();
190  throw;
191  }
192  drop();
193 }
194 
195 } // namespace nfd
static void runElevated(function< void()> f)
PrivilegeHelper::Error represents a serious seteuid/gid failure and should only be caught by main in ...
#define NFD_LOG_INFO(expression)
Definition: logger.hpp:37
static void initialize(const std::string &userName, const std::string &groupName)
#define NFD_LOG_INIT(name)
Definition: logger.hpp:33
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:35