Skip to content

genesis_tool/GenesisCeremonyPlatformPosix.cpp

Namespaces

Name
sgns
sgns::trustedpeer
sgns::trustedpeer::genesis_ceremony_platform

Functions

Name
outcome::result< GenesisCeremony::KeyFileStatus > InspectKeyFile(const std::string & path)
outcome::result< std::string > ReadKeyFile(const std::string & path)
int RestrictKeyFileToCurrentUser(const std::string & path)
int RemoveKeyFile(const std::string & path)
ProtectedInputResult ReadProtectedLine(std::istream & input, std::ostream & output, std::string & line)

Functions Documentation

function InspectKeyFile

outcome::result< GenesisCeremony::KeyFileStatus > InspectKeyFile(
    const std::string & path
)

function ReadKeyFile

outcome::result< std::string > ReadKeyFile(
    const std::string & path
)

function RestrictKeyFileToCurrentUser

int RestrictKeyFileToCurrentUser(
    const std::string & path
)

function RemoveKeyFile

int RemoveKeyFile(
    const std::string & path
)

function ReadProtectedLine

ProtectedInputResult ReadProtectedLine(
    std::istream & input,
    std::ostream & output,
    std::string & line
)

Source code

#include "trustedpeer/genesis_tool/GenesisCeremonyPlatform.hpp"

#include <cerrno>
#include <fcntl.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>

namespace sgns::trustedpeer::genesis_ceremony_platform
{
    namespace
    {
        constexpr size_t MAX_KEY_FILE_BYTES = 256;

    } // namespace

    outcome::result<GenesisCeremony::KeyFileStatus> InspectKeyFile( const std::string &path )
    {
        struct stat metadata
        {
        };
        if ( ::lstat( path.c_str(), &metadata ) != 0 )
            return outcome::failure( GenesisCeremony::Error::KEY_FILE_IO );
        return GenesisCeremony::KeyFileStatus{ true,
                                               S_ISREG( metadata.st_mode ) != 0,
                                               S_ISLNK( metadata.st_mode ) != 0,
                                               metadata.st_uid == ::geteuid(),
                                               static_cast<uint32_t>( metadata.st_mode & 0777 ) };
    }

    outcome::result<std::string> ReadKeyFile( const std::string &path )
    {
        const int descriptor = ::open( path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW );
        if ( descriptor < 0 )
            return outcome::failure( errno == ELOOP ? GenesisCeremony::Error::KEY_FILE_SYMLINK
                                                    : GenesisCeremony::Error::KEY_FILE_IO );

        struct stat metadata
        {
        };
        if ( ::fstat( descriptor, &metadata ) != 0 )
        {
            ::close( descriptor );
            return outcome::failure( GenesisCeremony::Error::KEY_FILE_IO );
        }
        if ( !S_ISREG( metadata.st_mode ) )
        {
            ::close( descriptor );
            return outcome::failure( GenesisCeremony::Error::KEY_FILE_NOT_REGULAR );
        }
        if ( metadata.st_uid != ::geteuid() )
        {
            ::close( descriptor );
            return outcome::failure( GenesisCeremony::Error::KEY_FILE_OWNER );
        }
        if ( ( metadata.st_mode & 0777 ) != 0600 )
        {
            ::close( descriptor );
            return outcome::failure( GenesisCeremony::Error::KEY_FILE_MODE );
        }

        std::string value( MAX_KEY_FILE_BYTES + 1, '\0' );
        const auto bytes_read = ::read( descriptor, value.data(), value.size() );
        const int close_result = ::close( descriptor );
        if ( bytes_read < 0 || close_result != 0 || static_cast<size_t>( bytes_read ) > MAX_KEY_FILE_BYTES )
            return outcome::failure( GenesisCeremony::Error::KEY_FILE_IO );
        value.resize( static_cast<size_t>( bytes_read ) );
        TrimLineEnding( value );
        return value;
    }

    int RestrictKeyFileToCurrentUser( const std::string &path )
    {
        return ::chmod( path.c_str(), 0600 );
    }

    int RemoveKeyFile( const std::string &path )
    {
        return ::unlink( path.c_str() );
    }

    ProtectedInputResult ReadProtectedLine( std::istream &input, std::ostream &output, std::string &line )
    {
        if ( &input != &std::cin )
            return std::getline( input, line ) ? ProtectedInputResult::SUCCESS : ProtectedInputResult::READ_FAILED;
        if ( ::isatty( STDIN_FILENO ) == 0 ) return ProtectedInputResult::NOT_A_TERMINAL;

        struct termios original
        {
        };
        if ( ::tcgetattr( STDIN_FILENO, &original ) != 0 ) return ProtectedInputResult::NOT_A_TERMINAL;
        auto protected_mode = original;
        protected_mode.c_lflag &= static_cast<tcflag_t>( ~ECHO );
        if ( ::tcsetattr( STDIN_FILENO, TCSAFLUSH, &protected_mode ) != 0 )
            return ProtectedInputResult::NOT_A_TERMINAL;
        const bool read = static_cast<bool>( std::getline( input, line ) );
        ::tcsetattr( STDIN_FILENO, TCSAFLUSH, &original );
        output << '\n';
        return read ? ProtectedInputResult::SUCCESS : ProtectedInputResult::READ_FAILED;
    }
} // namespace sgns::trustedpeer::genesis_ceremony_platform

Updated on 2026-09-25 at 15:46:12 +0000