blob: edc8336eca914370ecd4299e43bc3343c2d62ce1 [file] [log] [blame]
Steve DiBenedetto24b9a642014-04-07 15:45:39 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa997d292017-08-24 20:16:59 -04002/*
Davide Pesaventoacd00872018-02-15 18:24:06 -05003 * Copyright (c) 2014-2018, Regents of the University of California,
Alexander Afanasyev7c10b3b2015-01-20 12:24:27 -08004 * 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.
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060010 *
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/>.
Alexander Afanasyev7c10b3b2015-01-20 12:24:27 -080024 */
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060025
26#include "privilege-helper.hpp"
27#include "core/logger.hpp"
28
29#include <pwd.h>
30#include <grp.h>
31
32namespace nfd {
33
34NFD_LOG_INIT("PrivilegeHelper");
35
Alexander Afanasyev49343f62015-01-26 21:58:07 -080036#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Alexander Afanasyevff489a22014-04-22 23:50:39 -070037uid_t PrivilegeHelper::s_normalUid = ::geteuid();
38gid_t PrivilegeHelper::s_normalGid = ::getegid();
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060039
Alexander Afanasyevff489a22014-04-22 23:50:39 -070040uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
41gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
Alexander Afanasyev49343f62015-01-26 21:58:07 -080042#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060043
44void
45PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
46{
Alexander Afanasyev49343f62015-01-26 21:58:07 -080047#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060048 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
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060057 // workflow from man getpwnam_r
58
Davide Pesaventoacd00872018-02-15 18:24:06 -050059 if (!groupName.empty()) {
60 static long groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060061
Davide Pesaventoacd00872018-02-15 18:24:06 -050062 if (groupSize == -1)
63 groupSize = FALLBACK_GROUP_BUFFER_SIZE;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060064
Davide Pesaventoacd00872018-02-15 18:24:06 -050065 std::vector<char> groupBuffer(groupSize);
66 struct group group;
67 struct group* groupResult = nullptr;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060068
Davide Pesaventoacd00872018-02-15 18:24:06 -050069 int errorCode = getgrnam_r(groupName.data(), &group,
70 &groupBuffer[0], groupBuffer.size(), &groupResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060071
Davide Pesaventoacd00872018-02-15 18:24:06 -050072 while (errorCode == ERANGE) {
73 if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
74 throw Error("Cannot allocate large enough buffer for struct group");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060075
Davide Pesaventoacd00872018-02-15 18:24:06 -050076 groupBuffer.resize(groupBuffer.size() * 2);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060077
Davide Pesaventoacd00872018-02-15 18:24:06 -050078 errorCode = getgrnam_r(groupName.data(), &group,
79 &groupBuffer[0], groupBuffer.size(), &groupResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060080 }
81
Davide Pesaventoacd00872018-02-15 18:24:06 -050082 if (errorCode != 0 || !groupResult)
83 throw Error("Failed to get gid for \"" + groupName + "\"");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060084
Davide Pesaventoacd00872018-02-15 18:24:06 -050085 s_normalGid = group.gr_gid;
86 }
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060087
Davide Pesaventoacd00872018-02-15 18:24:06 -050088 if (!userName.empty()) {
89 static long passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060090
Davide Pesaventoacd00872018-02-15 18:24:06 -050091 if (passwdSize == -1)
92 passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060093
Davide Pesaventoacd00872018-02-15 18:24:06 -050094 std::vector<char> passwdBuffer(passwdSize);
95 struct passwd passwd;
96 struct passwd* passwdResult = nullptr;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060097
Davide Pesaventoacd00872018-02-15 18:24:06 -050098 int errorCode = getpwnam_r(userName.data(), &passwd,
99 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600100
Davide Pesaventoacd00872018-02-15 18:24:06 -0500101 while (errorCode == ERANGE) {
102 if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
103 throw Error("Cannot allocate large enough buffer for struct passwd");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600104
Davide Pesaventoacd00872018-02-15 18:24:06 -0500105 passwdBuffer.resize(passwdBuffer.size() * 2);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600106
Davide Pesaventoacd00872018-02-15 18:24:06 -0500107 errorCode = getpwnam_r(userName.data(), &passwd,
108 &passwdBuffer[0], passwdBuffer.size(), &passwdResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600109 }
Davide Pesaventoacd00872018-02-15 18:24:06 -0500110
111 if (errorCode != 0 || !passwdResult)
112 throw Error("Failed to get uid for \"" + userName + "\"");
113
114 s_normalUid = passwd.pw_uid;
115 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800116#else
Alexander Afanasyev9cfeeca2015-02-12 16:44:24 -0800117 if (!userName.empty() || !groupName.empty()) {
118 throw Error("Dropping and raising privileges is not supported on this platform");
119 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800120#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600121}
122
123void
124PrivilegeHelper::drop()
125{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800126#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600127 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
128 if (::setegid(s_normalGid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500129 throw Error("Failed to drop to effective gid=" + to_string(s_normalGid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600130
131 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
132 if (::seteuid(s_normalUid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500133 throw Error("Failed to drop to effective uid=" + to_string(s_normalUid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600134
135 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800136#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800137 NFD_LOG_WARN("Dropping privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800138#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600139}
140
141void
142PrivilegeHelper::raise()
143{
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800144#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600145 NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
146 if (::seteuid(s_privilegedUid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500147 throw Error("Failed to elevate to effective uid=" + to_string(s_privilegedUid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600148
149 NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
150 if (::setegid(s_privilegedGid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500151 throw Error("Failed to elevate to effective gid=" + to_string(s_privilegedGid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600152
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600153 NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800154#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800155 NFD_LOG_WARN("Elevating privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800156#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600157}
158
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600159} // namespace nfd