41 void noCloseOnExec(
int fd ) noexcept ;
42 void reopen(
int fd ,
int mode ) ;
43 mode_t umaskValue( G::Process::Umask::Mode mode ) ;
44 bool readlink_(
const char * path , std::string & value ) ;
45 bool setRealUser( Identity
id , std::nothrow_t ) noexcept ;
46 bool setRealGroup( Identity
id , std::nothrow_t ) noexcept ;
47 void setEffectiveUser( Identity
id ) ;
48 bool setEffectiveUser( Identity
id , std::nothrow_t ) noexcept ;
49 void setEffectiveGroup( Identity
id ) ;
50 bool setEffectiveGroup( Identity
id , std::nothrow_t ) noexcept ;
52 void beSpecial( Identity special_identity ,
bool change_group ) ;
53 void beSpecialForExit( SignalSafe , Identity special_identity ) noexcept ;
54 Identity beOrdinaryAtStartup( Identity ,
bool change_group ) ;
55 Identity beOrdinary( Identity ,
bool change_group ) ;
56 void beOrdinaryForExec( Identity run_as_id ) noexcept ;
57 void revokeExtraGroups() ;
71 if( !
cd(dir,std::nothrow) )
72 throw CannotChangeDirectory( dir.
str() ) ;
77 return 0 == ::chdir( dir.
cstr() ) ;
82 ProcessImp::reopen( STDERR_FILENO , O_WRONLY ) ;
87 std::cout << std::flush ;
88 std::cerr << std::flush ;
90 ProcessImp::reopen( STDIN_FILENO , O_RDONLY ) ;
91 ProcessImp::reopen( STDOUT_FILENO , O_WRONLY ) ;
93 ProcessImp::reopen( STDERR_FILENO , O_WRONLY ) ;
101 long rc = ::sysconf( _SC_OPEN_MAX ) ;
103 n =
static_cast<int>( rc ) ;
105 for(
int fd = 0 ; fd < n ; fd++ )
107 if( fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO && fd != fd_keep )
110 ProcessImp::noCloseOnExec( STDIN_FILENO ) ;
111 ProcessImp::noCloseOnExec( STDOUT_FILENO ) ;
112 ProcessImp::noCloseOnExec( STDERR_FILENO ) ;
129 char * p = std::strerror( errno_ ) ;
130 std::string s( p ? p :
"" ) ;
131 if( s.empty() ) s =
"unknown error" ;
137 ProcessImp::beSpecial( special_identity , change_group ) ;
142 ProcessImp::beSpecialForExit(
SignalSafe() , special_identity ) ;
150 if( change_group && !ordinary_id.
isRoot() )
154 ProcessImp::revokeExtraGroups() ;
157 return ProcessImp::beOrdinary( ordinary_id , change_group ) ;
162 ProcessImp::beOrdinary( ordinary_id , change_group ) ;
167 ProcessImp::beOrdinaryForExec( run_as_id ) ;
172 G::ProcessImp::setEffectiveUser(
id ) ;
177 G::ProcessImp::setEffectiveGroup(
id ) ;
183 std::array<std::size_t,2U> sizes = {{ G::limits::path_buffer , PATH_MAX+1U }} ;
184 for( std::size_t n : sizes )
186 std::vector<char> buffer( n ) ;
187 char * p = getcwd( &buffer[0] , buffer.size() ) ;
188 int error = errno_() ;
191 buffer.push_back(
'\0' ) ;
192 result.assign( &buffer[0] ) ;
195 else if( error != ERANGE )
200 if( result.empty() && !no_throw )
201 throw std::runtime_error(
"getcwd() failed" ) ;
210 std::vector<char> buffer( std::max(100,PROC_PIDPATHINFO_MAXSIZE) ) ;
212 int rc = proc_pidpath( getpid() , &buffer[0] , buffer.size() ) ;
215 std::size_t n =
static_cast<std::size_t
>(rc) ;
216 if( n > buffer.size() ) n = buffer.size() ;
217 return std::string( &buffer[0] , n ) ;
221 return std::string() ;
229 ProcessImp::readlink_(
"/proc/self/exe" , result ) ||
230 ProcessImp::readlink_(
"/proc/curproc/file" , result ) ||
231 ProcessImp::readlink_(
"/proc/curproc/exe" , result ) ;
238G::Process::Id::Id() noexcept :
243std::string G::Process::Id::str()
const
245 std::ostringstream ss ;
250bool G::Process::Id::operator==(
const Id & other )
const noexcept
252 return m_pid == other.m_pid ;
255bool G::Process::Id::operator!=(
const Id & other )
const noexcept
257 return m_pid != other.m_pid ;
262G::Process::Umask::Umask( Mode mode ) :
263 m_imp(std::make_unique<UmaskImp>())
265 m_imp->m_old_mode = ::umask( ProcessImp::umaskValue(mode) ) ;
268G::Process::Umask::~Umask()
270 GDEF_IGNORE_RETURN ::umask( m_imp->m_old_mode ) ;
273void G::Process::Umask::set( Mode mode )
275 GDEF_IGNORE_RETURN ::umask( ProcessImp::umaskValue(mode) ) ;
278void G::Process::Umask::tighten()
280 ::umask( ::umask(2) | mode_t(7) ) ;
285void G::ProcessImp::noCloseOnExec(
int fd )
noexcept
287 ::fcntl( fd , F_SETFD , 0 ) ;
290void G::ProcessImp::reopen(
int fd ,
int mode )
293 if( fd_null < 0 )
throw std::runtime_error(
"cannot open /dev/null" ) ;
294 ::dup2( fd_null , fd ) ;
298mode_t G::ProcessImp::umaskValue( Process::Umask::Mode mode )
301 if( mode == Process::Umask::Mode::Tightest ) m = 0177 ;
302 if( mode == Process::Umask::Mode::Tighter ) m = 0117 ;
303 if( mode == Process::Umask::Mode::Readable ) m = 0133 ;
304 if( mode == Process::Umask::Mode::GroupOpen ) m = 0113 ;
305 if( mode == Process::Umask::Mode::Open ) m = 0111 ;
309bool G::ProcessImp::readlink_(
const char * path , std::string & value )
312 if( !target.empty() ) value = target.str() ;
313 return !target.empty() ;
318G::Identity G::ProcessImp::beOrdinary( Identity nobody_id ,
bool change_group )
322 if( real_id.isRoot() )
330 if( !setEffectiveGroup( nobody_id , std::nothrow ) )
332 setEffectiveUser( old_id , std::nothrow ) ;
336 if( !setEffectiveUser( nobody_id , std::nothrow ) )
342 if( !setEffectiveUser( real_id , std::nothrow ) )
345 if( change_group && !setEffectiveGroup( real_id , std::nothrow ) )
347 setEffectiveUser( old_id , std::nothrow ) ;
354void G::ProcessImp::beOrdinaryForExec( Identity run_as_id )
noexcept
359 setRealGroup( run_as_id , std::nothrow ) ;
360 setEffectiveGroup( run_as_id , std::nothrow ) ;
361 setRealUser( run_as_id , std::nothrow ) ;
362 setEffectiveUser( run_as_id , std::nothrow ) ;
366void G::ProcessImp::beSpecial( Identity special_identity ,
bool change_group )
368 setEffectiveUser( special_identity ) ;
370 setEffectiveGroup( special_identity ) ;
373void G::ProcessImp::beSpecialForExit( SignalSafe , Identity special_identity )
noexcept
376 setEffectiveUser( special_identity , std::nothrow ) ;
377 setEffectiveGroup( special_identity , std::nothrow ) ;
380void G::ProcessImp::revokeExtraGroups()
386 GDEF_IGNORE_RETURN ::setgroups( 0U , &dummy ) ;
390bool G::ProcessImp::setRealUser( Identity
id , std::nothrow_t )
noexcept
392 return 0 == ::setuid(
id.userid() ) ;
395void G::ProcessImp::setEffectiveUser( Identity
id )
397 if( ::seteuid(
id.userid()) )
404bool G::ProcessImp::setEffectiveUser( Identity
id , std::nothrow_t )
noexcept
406 return 0 == ::seteuid(
id.userid() ) ;
409bool G::ProcessImp::setRealGroup( Identity
id , std::nothrow_t )
noexcept
411 return 0 == ::setgid(
id.groupid() ) ;
414void G::ProcessImp::setEffectiveGroup( Identity
id )
416 if( ::setegid(
id.groupid()) )
423bool G::ProcessImp::setEffectiveGroup( Identity
id , std::nothrow_t )
noexcept
425 return 0 == ::setegid(
id.groupid() ) ;
428void G::ProcessImp::throwError()
431 G_ERROR(
"G::ProcessImp::throwError: failed to give up process privileges" ) ;
432 throw G::Exception(
"cannot give up process privileges" ) ;
A general-purpose exception class derived from std::exception and containing an error message.
static G::Path readlink(const Path &link)
Reads a symlink. Throws on error.
A combination of user-id and group-id, with a very low-level interface to the get/set/e/uid/gid funct...
bool isRoot() const noexcept
Returns true if the userid is zero.
static Identity invalid() noexcept
Returns an invalid identity.
static Identity root() noexcept
Returns the superuser identity.
static Identity effective() noexcept
Returns the current effective identity.
static Identity real(bool with_cache=true) noexcept
Returns the calling process's real identity.
A Path object represents a file system path.
const char * cstr() const noexcept
Returns the path string.
static Path nullDevice()
Returns the path of the "/dev/null" special file, or equivalent.
std::string str() const
Returns the path string.
A private implemetation class for G::Process::Umask that hides mode_t.
static void beSpecialForExit(SignalSafe, Identity special_id) noexcept
A signal-safe version of beSpecial() that should only be used just before process exit.
static void closeOtherFiles(int fd_keep=-1)
Closes all open file descriptors except the three standard ones and possibly one other.
static void beSpecial(Identity special_id, bool change_group=true)
Re-acquires special privileges (either root or suid).
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static void beOrdinaryForExec(Identity run_as_id) noexcept
Sets the real and effective user and group ids to those given, on a best-effort basis.
static void setEffectiveGroup(Identity)
Sets the effective group. Throws on error.
static std::string cwd(bool no_throw=false)
Returns the current working directory.
static void closeStderr()
Closes stderr and reopens it to the null device.
static void beOrdinary(Identity ordinary_id, bool change_group)
Releases special privileges.
static std::string exe()
Returns the absolute path of the current executable, independent of the argv array passed to main().
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
static void setEffectiveUser(Identity)
Sets the effective user. Throws on error.
static void closeFiles(bool keep_stderr=false)
Closes all open file descriptors and reopen stdin, stdout and possibly stderr to the null device.
static void cd(const Path &dir)
Changes directory.
static Identity beOrdinaryAtStartup(Identity ordinary_id, bool change_group)
Revokes special privileges (root or suid), possibly including extra group membership.
An empty structure that is used to indicate a signal-safe, reentrant implementation.
static bool isPrintableAscii(const std::string &s)
Returns true if every character is a 7-bit, non-control character (ie.
static std::string lower(const std::string &s)
Returns a copy of 's' in which all Latin-1 upper-case characters have been replaced by lower-case cha...