blob: 865234787abb55e6ad92472e1707296b0dcb1db9 [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/*
Alexander Afanasyev99a7ce12018-07-05 15:32:12 -04003 * Copyright (c) 2014-2019, 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
Davide Pesaventoa3148082018-04-12 18:21:54 -040034NFD_LOG_INIT(PrivilegeHelper);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060035
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
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 Pesaventoacd00872018-02-15 18:24:06 -050066 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,
Davide Pesavento70156942018-09-15 18:40:21 -040070 groupBuffer.data(), 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);
Davide Pesaventoacd00872018-02-15 18:24:06 -050077 errorCode = getgrnam_r(groupName.data(), &group,
Davide Pesavento70156942018-09-15 18:40:21 -040078 groupBuffer.data(), groupBuffer.size(), &groupResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060079 }
80
Davide Pesaventoacd00872018-02-15 18:24:06 -050081 if (errorCode != 0 || !groupResult)
82 throw Error("Failed to get gid for \"" + groupName + "\"");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060083
Davide Pesaventoacd00872018-02-15 18:24:06 -050084 s_normalGid = group.gr_gid;
85 }
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060086
Davide Pesaventoacd00872018-02-15 18:24:06 -050087 if (!userName.empty()) {
88 static long passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060089
Davide Pesaventoacd00872018-02-15 18:24:06 -050090 if (passwdSize == -1)
91 passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060092
Davide Pesavento70156942018-09-15 18:40:21 -040093 std::vector<char> passwdBuffer(static_cast<size_t>(passwdSize));
Davide Pesaventoacd00872018-02-15 18:24:06 -050094 struct passwd passwd;
95 struct passwd* passwdResult = nullptr;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060096
Davide Pesaventoacd00872018-02-15 18:24:06 -050097 int errorCode = getpwnam_r(userName.data(), &passwd,
Davide Pesavento70156942018-09-15 18:40:21 -040098 passwdBuffer.data(), passwdBuffer.size(), &passwdResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060099
Davide Pesaventoacd00872018-02-15 18:24:06 -0500100 while (errorCode == ERANGE) {
101 if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
102 throw Error("Cannot allocate large enough buffer for struct passwd");
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600103
Davide Pesaventoacd00872018-02-15 18:24:06 -0500104 passwdBuffer.resize(passwdBuffer.size() * 2);
Davide Pesaventoacd00872018-02-15 18:24:06 -0500105 errorCode = getpwnam_r(userName.data(), &passwd,
Davide Pesavento70156942018-09-15 18:40:21 -0400106 passwdBuffer.data(), passwdBuffer.size(), &passwdResult);
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600107 }
Davide Pesaventoacd00872018-02-15 18:24:06 -0500108
109 if (errorCode != 0 || !passwdResult)
110 throw Error("Failed to get uid for \"" + userName + "\"");
111
112 s_normalUid = passwd.pw_uid;
113 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800114#else
Alexander Afanasyev9cfeeca2015-02-12 16:44:24 -0800115 if (!userName.empty() || !groupName.empty()) {
116 throw Error("Dropping and raising privileges is not supported on this platform");
117 }
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800118#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600119}
120
121void
122PrivilegeHelper::drop()
123{
Alexander Afanasyev99a7ce12018-07-05 15:32:12 -0400124#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Davide Pesaventoa3148082018-04-12 18:21:54 -0400125 if (::geteuid() == s_normalUid && ::getegid() == s_normalGid)
126 return;
127
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600128 NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
129 if (::setegid(s_normalGid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500130 throw Error("Failed to drop to effective gid=" + to_string(s_normalGid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600131
132 NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
133 if (::seteuid(s_normalUid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500134 throw Error("Failed to drop to effective uid=" + to_string(s_normalUid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600135
136 NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800137#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800138 NFD_LOG_WARN("Dropping privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800139#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600140}
141
142void
143PrivilegeHelper::raise()
144{
Alexander Afanasyev99a7ce12018-07-05 15:32:12 -0400145#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
Davide Pesaventoa3148082018-04-12 18:21:54 -0400146 if (::geteuid() == s_privilegedUid && ::getegid() == s_privilegedGid)
147 return;
148
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600149 NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
150 if (::seteuid(s_privilegedUid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500151 throw Error("Failed to elevate to effective uid=" + to_string(s_privilegedUid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600152
153 NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
154 if (::setegid(s_privilegedGid) != 0)
Davide Pesaventoacd00872018-02-15 18:24:06 -0500155 throw Error("Failed to elevate to effective gid=" + to_string(s_privilegedGid));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600156
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600157 NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800158#else
Alexander Afanasyev6f570de2015-02-11 16:15:25 -0800159 NFD_LOG_WARN("Elevating privileges is not supported on this platform");
Alexander Afanasyev49343f62015-01-26 21:58:07 -0800160#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600161}
162
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600163} // namespace nfd