blob: 6f87f4350921047760652da5d2e72a9ec7fbce5a [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
Alexander Afanasyevff489a22014-04-22 23:50:39 -070035uid_t PrivilegeHelper::s_normalUid = ::geteuid();
36gid_t PrivilegeHelper::s_normalGid = ::getegid();
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060037
Alexander Afanasyevff489a22014-04-22 23:50:39 -070038uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
39gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060040
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
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060053 // 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
131void
132PrivilegeHelper::drop()
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
155void
156PrivilegeHelper::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
178void
179PrivilegeHelper::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