blob: f48c4d0756391829e4bbe4f3add6dde8198f0b54 [file] [log] [blame]
Steve DiBenedetto24b9a642014-04-07 15:45:39 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014 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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
24
25#include "privilege-helper.hpp"
26#include "core/logger.hpp"
27
28#include <pwd.h>
29#include <grp.h>
30
31namespace nfd {
32
33NFD_LOG_INIT("PrivilegeHelper");
34
35uid_t PrivilegeHelper::s_normalUid;
36gid_t PrivilegeHelper::s_normalGid;
37
38uid_t PrivilegeHelper::s_privilegedUid;
39gid_t PrivilegeHelper::s_privilegedGid;
40
41void
42PrivilegeHelper::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 s_privilegedUid = ::geteuid();
54 s_privilegedGid = ::getegid();
55
56 NFD_LOG_TRACE("saving effective uid=" << s_privilegedUid << " gid=" << s_privilegedGid);
57
58 s_normalUid = s_privilegedUid;
59 s_normalGid = s_privilegedGid;
60
61 // workflow from man getpwnam_r
62
63 if (!groupName.empty())
64 {
65 static int groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
66
67 if (groupSize == -1)
68 {
69 groupSize = FALLBACK_GROUP_BUFFER_SIZE;
70 }
71
72 std::vector<char> groupBuffer(groupSize);
73 struct group group;
74 struct group* groupResult = 0;
75
76 int errorCode = getgrnam_r(groupName.c_str(), &group,
77 &groupBuffer[0], groupSize, &groupResult);
78
79 while (errorCode == ERANGE)
80 {
81 if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
82 {
83 throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct group");
84 }
85
86 groupBuffer.resize(groupBuffer.size() * 2);
87
88 errorCode = getgrnam_r(groupName.c_str(), &group,
89 &groupBuffer[0], groupBuffer.size(), &groupResult);
90 }
91
92 if (errorCode != 0 || !groupResult)
93 {
94 throw PrivilegeHelper::Error("Failed to get gid for \"" + groupName + "\"");
95 }
96
97 s_normalGid = group.gr_gid;
98 }
99
100 if (!userName.empty())
101 {
102 static int passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
103
104 if (passwdSize == -1)
105 {
106 passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
107 }
108
109 std::vector<char> passwdBuffer(passwdSize);
110 struct passwd passwd;
111 struct passwd* passwdResult = 0;
112
113 int errorCode =
114 getpwnam_r(userName.c_str(), &passwd,
115 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
116
117 while (errorCode == ERANGE)
118 {
119 if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
120 {
121 throw PrivilegeHelper::Error("Cannot allocate large enough buffer for struct passwd");
122 }
123
124 passwdBuffer.resize(passwdBuffer.size() * 2);
125
126 errorCode = getpwnam_r(userName.c_str(), &passwd,
127 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
128 }
129
130 if (errorCode != 0 || !passwdResult)
131 {
132 throw PrivilegeHelper::Error("Failed to get uid for \"" + userName + "\"");
133 }
134
135 s_normalUid = passwd.pw_uid;
136 }
137}
138
139void
140PrivilegeHelper::drop()
141{
142 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
143 if (::setegid(s_normalGid) != 0)
144 {
145 std::stringstream error;
146 error << "Failed to drop to effective gid=" << s_normalGid;
147
148 throw PrivilegeHelper::Error(error.str());
149 }
150
151 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
152 if (::seteuid(s_normalUid) != 0)
153 {
154 std::stringstream error;
155 error << "Failed to drop to effective uid=" << s_normalUid;
156
157 throw PrivilegeHelper::Error(error.str());
158 }
159
160 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
161}
162
163void
164PrivilegeHelper::raise()
165{
166 NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
167 if (::seteuid(s_privilegedUid) != 0)
168 {
169 std::stringstream error;
170 error << "Failed to elevate to effective uid=" << s_privilegedUid;
171
172 throw PrivilegeHelper::Error(error.str());
173 }
174
175 NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
176 if (::setegid(s_privilegedGid) != 0)
177 {
178 std::stringstream error;
179 error << "Failed to elevate to effective gid=" << s_privilegedGid;
180
181 throw PrivilegeHelper::Error(error.str());
182 }
183 NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
184}
185
186void
187PrivilegeHelper::runElevated(function<void()> f)
188{
189 raise();
190
191 try
192 {
193 f();
194 }
195 catch (...)
196 {
197 drop();
198 throw;
199 }
200 drop();
201}
202
203} // namespace nfd