blob: eb8e60848741c3edf2f42e5bd0c0d780ec1355ad [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 Pesavento264af772021-02-09 21:48:24 -05003 * Copyright (c) 2014-2021, 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
Davide Pesavento2cae8ca2019-04-18 20:48:05 -040026#include "common/privilege-helper.hpp"
27#include "common/logger.hpp"
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060028
29#include <pwd.h>
30#include <grp.h>
31
32namespace nfd {
33
Davide Pesaventoa3148082018-04-12 18:21:54 -040034NFD_LOG_INIT(PrivilegeHelper);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060035
Davide Pesavento264af772021-02-09 21:48:24 -050036#ifdef NFD_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();
Davide Pesavento264af772021-02-09 21:48:24 -050042#endif // NFD_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{
Davide Pesavento264af772021-02-09 21:48:24 -050047#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
Davide Pesavento70156942018-09-15 18:40:21 -040048 static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16 KiB
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060049 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
Davide Pesavento70156942018-09-15 18:40:21 -040054 NFD_LOG_TRACE("initializing with user \"" << userName << "\""
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060055 << " 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 Pesavento70156942018-09-15 18:40:21 -040065 std::vector<char> groupBuffer(static_cast<size_t>(groupSize));
Davide Pesavento17521592020-05-14 19:01:32 -040066 group gr;
67 group* grResult = nullptr;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060068
Davide Pesavento17521592020-05-14 19:01:32 -040069 int errorCode = getgrnam_r(groupName.data(), &gr, groupBuffer.data(), groupBuffer.size(), &grResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060070
Davide Pesaventoacd00872018-02-15 18:24:06 -050071 while (errorCode == ERANGE) {
72 if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
73 throw Error("Cannot allocate large enough buffer for struct group");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060074
Davide Pesaventoacd00872018-02-15 18:24:06 -050075 groupBuffer.resize(groupBuffer.size() * 2);
Davide Pesavento17521592020-05-14 19:01:32 -040076 errorCode = getgrnam_r(groupName.data(), &gr, groupBuffer.data(), groupBuffer.size(), &grResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060077 }
78
Davide Pesavento17521592020-05-14 19:01:32 -040079 if (errorCode != 0 || !grResult)
Davide Pesaventoacd00872018-02-15 18:24:06 -050080 throw Error("Failed to get gid for \"" + groupName + "\"");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060081
Davide Pesavento17521592020-05-14 19:01:32 -040082 s_normalGid = gr.gr_gid;
Davide Pesaventoacd00872018-02-15 18:24:06 -050083 }
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060084
Davide Pesaventoacd00872018-02-15 18:24:06 -050085 if (!userName.empty()) {
86 static long passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060087
Davide Pesaventoacd00872018-02-15 18:24:06 -050088 if (passwdSize == -1)
89 passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060090
Davide Pesavento70156942018-09-15 18:40:21 -040091 std::vector<char> passwdBuffer(static_cast<size_t>(passwdSize));
Davide Pesavento17521592020-05-14 19:01:32 -040092 passwd pw;
93 passwd* pwResult = nullptr;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060094
Davide Pesavento17521592020-05-14 19:01:32 -040095 int errorCode = getpwnam_r(userName.data(), &pw, passwdBuffer.data(), passwdBuffer.size(), &pwResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060096
Davide Pesaventoacd00872018-02-15 18:24:06 -050097 while (errorCode == ERANGE) {
98 if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
99 throw Error("Cannot allocate large enough buffer for struct passwd");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600100
Davide Pesaventoacd00872018-02-15 18:24:06 -0500101 passwdBuffer.resize(passwdBuffer.size() * 2);
Davide Pesavento17521592020-05-14 19:01:32 -0400102 errorCode = getpwnam_r(userName.data(), &pw, passwdBuffer.data(), passwdBuffer.size(), &pwResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600103 }
Davide Pesaventoacd00872018-02-15 18:24:06 -0500104
Davide Pesavento17521592020-05-14 19:01:32 -0400105 if (errorCode != 0 || !pwResult)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500106 throw Error("Failed to get uid for \"" + userName + "\"");
107
Davide Pesavento17521592020-05-14 19:01:32 -0400108 s_normalUid = pw.pw_uid;
Davide Pesaventoacd00872018-02-15 18:24:06 -0500109 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800110#else
Alexander Afanasyev9cfeeca2015-02-12 16:44:24 -0800111 if (!userName.empty() || !groupName.empty()) {
112 throw Error("Dropping and raising privileges is not supported on this platform");
113 }
Davide Pesavento264af772021-02-09 21:48:24 -0500114#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600115}
116
117void
118PrivilegeHelper::drop()
119{
Davide Pesavento264af772021-02-09 21:48:24 -0500120#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
Davide Pesaventoa3148082018-04-12 18:21:54 -0400121 if (::geteuid() == s_normalUid && ::getegid() == s_normalGid)
122 return;
123
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600124 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
125 if (::setegid(s_normalGid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500126 throw Error("Failed to drop to effective gid=" + to_string(s_normalGid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600127
128 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
129 if (::seteuid(s_normalUid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500130 throw Error("Failed to drop to effective uid=" + to_string(s_normalUid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600131
132 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800133#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800134 NFD_LOG_WARN("Dropping privileges is not supported on this platform");
Davide Pesavento264af772021-02-09 21:48:24 -0500135#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600136}
137
138void
139PrivilegeHelper::raise()
140{
Davide Pesavento264af772021-02-09 21:48:24 -0500141#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
Davide Pesaventoa3148082018-04-12 18:21:54 -0400142 if (::geteuid() == s_privilegedUid && ::getegid() == s_privilegedGid)
143 return;
144
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");
Davide Pesavento264af772021-02-09 21:48:24 -0500156#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600157}
158
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600159} // namespace nfd