E-MailRelay
gprocess.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gprocess.h
19///
20
21#ifndef G_PROCESS_H
22#define G_PROCESS_H
23
24#include "gdef.h"
25#include "gexception.h"
26#include "gidentity.h"
27#include "gpath.h"
28#include "gstr.h"
29#include "gstringarray.h"
30#include "gsignalsafe.h"
31#include <memory>
32#include <utility>
33#include <iostream>
34#include <limits>
35#include <type_traits>
36#include <string>
37#include <new>
38
39namespace G
40{
41 class Process ;
42 class NewProcess ;
43}
44
45//| \class G::Process
46/// A static interface for doing things with processes.
47/// \see G::Identity
48///
50{
51public:
52 G_EXCEPTION( CannotChangeDirectory , tx("cannot change directory") )
53 G_EXCEPTION( InvalidId , tx("invalid process-id string") )
54 G_EXCEPTION( UidError , tx("cannot set uid") )
55 G_EXCEPTION( GidError , tx("cannot set gid") )
56 G_EXCEPTION( GetCwdError , tx("cannot get current working directory") )
57 class Id ;
58 class Umask ;
59 class UmaskImp ;
60
61 static void closeFiles( bool keep_stderr = false ) ;
62 ///< Closes all open file descriptors and reopens stdin,
63 ///< stdout and possibly stderr to the null device.
64
65 static void closeStderr() ;
66 ///< Closes stderr and reopens it to the null device.
67
68 static void closeOtherFiles( int fd_keep = -1 ) ;
69 ///< Closes all open file descriptors except the three
70 ///< standard ones and optionally one other.
71
72 static void inheritStandardFiles() ;
73 ///< Makes sure that the standard file descriptors
74 ///< are inherited.
75
76 static void cd( const Path & dir ) ;
77 ///< Changes directory.
78
79 static bool cd( const Path & dir , std::nothrow_t ) ;
80 ///< Changes directory. Returns false on error.
81
82 static int errno_( const SignalSafe & = G::SignalSafe() ) noexcept ;
83 ///< Returns the process's current 'errno' value.
84 ///< (Beware of destructors of c++ temporaries disrupting
85 ///< the global errno value.)
86
87 static void errno_( int e_new ) noexcept ;
88 ///< Sets the process's 'errno' value.
89
90 static int errno_( const SignalSafe & , int e_new ) noexcept ;
91 ///< Sets the process's 'errno' value. Returns the old
92 ///< value. Typically used in signal handlers.
93
94 static std::string strerror( int errno_ ) ;
95 ///< Translates an 'errno' value into a meaningful diagnostic string.
96 ///< The returned string is non-empty, even for a zero errno.
97
98 static std::string errorMessage( DWORD error ) ;
99 ///< Translates a GetLastError() value into a meaningful diagnostic string.
100 ///< The returned string is non-empty, even for a zero error number.
101
102 static std::pair<Identity,Identity> beOrdinaryAtStartup( const std::string & nobody , bool change_group ) ;
103 ///< Revokes special privileges (root or suid) at startup, possibly
104 ///< including extra group membership, making the named user the
105 ///< effective identity. Returns the new effective identity and the
106 ///< original effective identity as a pair.
107 ///<
108 ///< \code
109 ///< auto pair = Process::beOrdinaryAtStartup( "daemon" , chgrp ) ;
110 ///< Process::beSpecial( pair.second , chgrp ) ;
111 ///< doPrivilegedStuff() ;
112 ///< Process::beOrdinary( pair.first , chgrp ) ;
113 ///< \endcode
114
115 static void beOrdinary( Identity ordinary_id , bool change_group ) ;
116 ///< Releases special privileges.
117 ///<
118 ///< If the real-id is root then the effective user-id is changed to
119 ///< whatever is passed in. Otherwise the effective user-id is changed
120 ///< to the real user-id (optionally including the group), and the
121 ///< identity parameter is ignored.
122 ///<
123 ///< Logs an error message and throws on failure, resulting in a call
124 ///< to std::terminate() when called from a destructor (see G::Root).
125 ///<
126 ///< (Note that the identity switch applies to all threads in the
127 ///< calling processes, so some run-time libraries engage in signal
128 ///< shenanigans to synchronise the change across threads, which can
129 ///< lead to surprising interruptions of sleep(), select() etc.)
130 ///<
131 ///< See also class G::Root.
132
133 static void beSpecial( Identity special_id , bool change_group = true ) ;
134 ///< Re-acquires special privileges (either root or suid). The
135 ///< parameter must have come from a previous call to
136 ///< beOrdinaryAtStartup() and use the same change_group value.
137 ///<
138 ///< See also class G::Root.
139
140 static void beSpecialForExit( SignalSafe , Identity special_id ) noexcept ;
141 ///< A signal-safe version of beSpecial() that should only be used
142 ///< just before process exit.
143
144 static void beOrdinaryForExec( Identity run_as_id ) noexcept ;
145 ///< Sets the real and effective user-id and group-ids to those
146 ///< given, on a best-effort basis. Errors are ignored.
147
148 static void setEffectiveUser( Identity ) ;
149 ///< Sets the effective user-id. Throws on error.
150
151 static void setEffectiveGroup( Identity ) ;
152 ///< Sets the effective group-id. Throws on error.
153
154 static Path cwd() ;
155 ///< Returns the current working directory. Throws on error.
156
157 static Path cwd( std::nothrow_t ) ;
158 ///< Returns the current working directory. Returns the
159 ///< empty path on error.
160
161 static Path exe() ;
162 ///< Returns the absolute path of the current executable,
163 ///< independent of the argv array passed to main(). Returns
164 ///< the empty path if unknown.
165
166 class Id /// Process-id class.
167 {
168 public:
169 Id() noexcept ;
170 explicit Id( const char * , const char * end ) noexcept ;
171 explicit Id( int ) noexcept ;
172 explicit Id( std::istream & ) ;
173 static Id invalid() noexcept ;
174 std::string str() const ;
175 bool operator==( const Id & ) const noexcept ;
176 bool operator!=( const Id & ) const noexcept ;
177 template <typename T> T value(
178 typename std::enable_if
179 <std::numeric_limits<T>::max() >= std::numeric_limits<pid_t>::max()>
180 ::type * = 0 ) const noexcept
181 {
182 static_assert( sizeof(T) >= sizeof(pid_t) , "" ) ;
183 return static_cast<T>( m_pid ) ;
184 }
185 template <typename T> T seed() const noexcept
186 {
187 return static_cast<T>( m_pid ) ;
188 }
189
190 private:
191 friend class NewProcess ;
192 friend class Process ;
193 pid_t m_pid{0} ;
194 } ;
195
196 class Umask /// Used to temporarily modify the process umask.
197 {
198 public:
199 enum class Mode
200 {
201 NoChange , // typically 0022
202 TightenOther , // -......---
203 LoosenGroup , // -...rwx...
204 Readable , // 0022 -rw-r--r-- for open(0666) and -rwxr-xr-x for mkdir(0777)
205 Tighter , // 0007 -rw-rw---- for open(0666) and -rwxrwx--- for mkdir(0777)
206 Tightest , // 0077 -rw------- for open(0666) and -rwx------ for mkdir(0777)
207 GroupOpen ,// 0002 -rw-rw-r-- for open(0666) and -rwxrwxr-x for mkdir(0777)
208 Open // 0000 -rw-rw-rw- for open(0666) and -rwxrwxrwx for mkdir(0777)
209 } ;
210 explicit Umask( Mode ) ;
211 ~Umask() ;
212 static void set( Mode ) ;
213 static void tightenOther() ; // deny "other" access, user and group unchanged
214 static void loosenGroup() ; // allow group access, user and "other" unchanged
215 Umask( const Umask & ) = delete ;
216 Umask( Umask && ) = delete ;
217 Umask & operator=( const Umask & ) = delete ;
218 Umask & operator=( Umask && ) = delete ;
219
220 private:
221 std::unique_ptr<UmaskImp> m_imp ;
222 } ;
223
224public:
225 Process() = delete ;
226
227private:
228 static Path cwdImp( bool ) ;
229} ;
230
231inline G::Process::Id::Id( int n ) noexcept :
232 m_pid(static_cast<pid_t>(n))
233{
234}
235
236inline G::Process::Id::Id( std::istream & stream )
237{
238 stream >> m_pid ;
239}
240
241inline G::Process::Id::Id( const char * p , const char * end ) noexcept
242{
243 bool overflow = false ;
244 m_pid = G::Str::toUnsigned<pid_t>( p , end , overflow ) ;
245 if( overflow )
246 m_pid = static_cast<pid_t>(-1) ;
247}
248
249inline G::Process::Id G::Process::Id::invalid() noexcept
250{
251 return Id(-1) ;
252}
253
254namespace G
255{
256 inline
257 std::ostream & operator<<( std::ostream & stream , const G::Process::Id & id )
258 {
259 return stream << id.str() ;
260 }
261}
262
263#endif
A combination of user-id and group-id, with a very low-level interface to the get/set/e/uid/gid funct...
Definition: gidentity.h:45
A class for creating new processes.
Definition: gnewprocess.h:62
A Path object represents a file system path.
Definition: gpath.h:82
Process-id class.
Definition: gprocess.h:167
Used to temporarily modify the process umask.
Definition: gprocess.h:197
A static interface for doing things with processes.
Definition: gprocess.h:50
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 optionally one other.
static Path cwd()
Returns the current working directory. Throws on error.
static std::pair< Identity, Identity > beOrdinaryAtStartup(const std::string &nobody, bool change_group)
Revokes special privileges (root or suid) at startup, possibly including extra group membership,...
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-id and group-ids to those given, on a best-effort basis.
static Path exe()
Returns the absolute path of the current executable, independent of the argv array passed to main().
static void setEffectiveGroup(Identity)
Sets the effective group-id. Throws on error.
static void closeStderr()
Closes stderr and reopens it to the null device.
static void inheritStandardFiles()
Makes sure that the standard file descriptors are inherited.
static void beOrdinary(Identity ordinary_id, bool change_group)
Releases special privileges.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
static void setEffectiveUser(Identity)
Sets the effective user-id. Throws on error.
static void closeFiles(bool keep_stderr=false)
Closes all open file descriptors and reopens stdin, stdout and possibly stderr to the null device.
static void cd(const Path &dir)
Changes directory.
static std::string errorMessage(DWORD error)
Translates a GetLastError() value into a meaningful diagnostic string.
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:37
Low-level classes.
Definition: garg.h:36
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84