- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gprocess_unix.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // gprocess_unix.cpp
19 //
20
21 #include "gdef.h"
22 #include "glimits.h"
23 #include "gprocess.h"
24 #include "gidentity.h"
25 #include "gassert.h"
26 #include "gfs.h"
27 #include "glog.h"
28 #include <iostream>
29 #include <cstring> // std::strerror()
30 #include <fcntl.h>
31 #include <errno.h>
32
33 namespace
34 {
35 void noCloseOnExec( int fd )
36 {
37 ::fcntl( fd , F_SETFD , 0 ) ;
38 }
39 }
40
44 class G::Process::IdImp
45 {
46 public:
47 pid_t m_pid ;
48 } ;
49
50 // ===
51
52 void G::Process::cd( const Path & dir )
53 {
54 if( ! cd(dir,NoThrow()) )
55 throw CannotChangeDirectory( dir.str() ) ;
56 }
57
58 bool G::Process::cd( const Path & dir , NoThrow )
59 {
60 return 0 == ::chdir( dir.str().c_str() ) ;
61 }
62
63 void G::Process::closeStderr()
64 {
65 ::close( STDERR_FILENO ) ;
66 ::open( G::FileSystem::nullDevice() , O_WRONLY ) ;
67 noCloseOnExec( STDERR_FILENO ) ;
68 }
69
70 void G::Process::closeFiles( bool keep_stderr )
71 {
72 closeFiles( keep_stderr ? STDERR_FILENO : -1 ) ;
73 }
74
75 void G::Process::closeFiles( int keep )
76 {
77 G_ASSERT( keep == -1 || keep >= STDERR_FILENO ) ;
78 std::cout << std::flush ;
79 std::cerr << std::flush ;
80
81 int n = 256U ;
82 long rc = ::sysconf( _SC_OPEN_MAX ) ;
83 if( rc > 0L )
84 n = static_cast<int>( rc ) ;
85
86 for( int fd = 0 ; fd < n ; fd++ )
87 {
88 if( fd != keep )
89 ::close( fd ) ;
90 }
91
92 // reopen standard fds to prevent accidental use
93 // of arbitrary files or sockets as standard
94 // streams
95 //
96 ::open( G::FileSystem::nullDevice() , O_RDONLY ) ;
97 ::open( G::FileSystem::nullDevice() , O_WRONLY ) ;
98 if( keep != STDERR_FILENO )
99 {
100 ::open( G::FileSystem::nullDevice() , O_WRONLY ) ;
101 }
102 noCloseOnExec( STDIN_FILENO ) ;
103 noCloseOnExec( STDOUT_FILENO ) ;
104 noCloseOnExec( STDERR_FILENO ) ;
105 }
106
107 int G::Process::errno_()
108 {
109 return errno ; // not ::errno or std::errno for gcc2.95
110 }
111
112 int G::Process::errno_( int e )
113 {
114 int old = errno ;
115 errno = e ;
116 return old ;
117 }
118
119 std::string G::Process::strerror( int errno_ )
120 {
121 char * p = std::strerror( errno_ ) ;
122 return std::string( p ? p : "" ) ;
123 }
124
125 void G::Process::revokeExtraGroups()
126 {
127 if( Identity::real().isRoot() || Identity::effective() != Identity::real() )
128 {
129 gid_t dummy ;
130 G_IGNORE_RETURN(int) ::setgroups( 0U , &dummy ) ; // (only works for root, so ignore the return code)
131 }
132 }
133
134 G::Identity G::Process::beSpecial( Identity special_identity , bool change_group )
135 {
136 change_group = Identity::real().isRoot() ? change_group : true ;
137 Identity old_identity( Identity::effective() ) ;
138 setEffectiveUserTo( special_identity ) ;
139 if( change_group )
140 setEffectiveGroupTo( special_identity ) ;
141 return old_identity ;
142 }
143
144 G::Identity G::Process::beSpecial( SignalSafe safe , Identity special_identity , bool change_group )
145 {
146 change_group = Identity::real().isRoot() ? change_group : true ;
147 Identity old_identity( Identity::effective() ) ;
148 setEffectiveUserTo( safe , special_identity ) ;
149 if( change_group )
150 setEffectiveGroupTo( safe , special_identity ) ;
151 return old_identity ;
152 }
153
154 G::Identity G::Process::beOrdinary( Identity nobody , bool change_group )
155 {
156 Identity special_identity( Identity::effective() ) ;
157 if( Identity::real().isRoot() )
158 {
159 setEffectiveUserTo( Identity::root() ) ;
160 if( change_group )
161 setEffectiveGroupTo( nobody ) ;
162 setEffectiveUserTo( nobody ) ;
163 }
164 else
165 {
166 setEffectiveUserTo( Identity::real() ) ;
167 if( change_group )
168 setEffectiveGroupTo( Identity::real() ) ;
169 }
170 return special_identity ;
171 }
172
173 G::Identity G::Process::beOrdinary( SignalSafe safe , Identity nobody , bool change_group )
174 {
175 Identity special_identity( Identity::effective() ) ;
176 if( Identity::real().isRoot() )
177 {
178 setEffectiveUserTo( safe , Identity::root() ) ;
179 if( change_group )
180 setEffectiveGroupTo( safe , nobody ) ;
181 setEffectiveUserTo( safe , nobody ) ;
182 }
183 else
184 {
185 setEffectiveUserTo( safe , Identity::real() ) ;
186 if( change_group )
187 setEffectiveGroupTo( safe , Identity::real() ) ;
188 }
189 return special_identity ;
190 }
191
192 void G::Process::beNobody( Identity nobody )
193 {
194 if( Identity::real().isRoot() )
195 {
196 setEffectiveUserTo( Identity::root() ) ;
197 setRealGroupTo( nobody ) ;
198 setRealUserTo( nobody ) ;
199 }
200 }
201
202 // ===
203
204 G::Process::Id::Id()
205 {
206 m_pid = ::getpid() ;
207 }
208
209 G::Process::Id::Id( SignalSafe , const char * path ) :
210 m_pid(0)
211 {
212 // signal-safe, reentrant implementation suitable for a signal handler...
213 int fd = ::open( path ? path : "" , O_RDONLY ) ;
214 if( fd >= 0 )
215 {
216 const size_t buffer_size = 11U ;
217 char buffer[buffer_size] ;
218 buffer[0U] = '\0' ;
219 ssize_t rc = ::read( fd , buffer , buffer_size - 1U ) ;
220 ::close( fd ) ;
221 for( const char * p = buffer ; rc > 0 && *p >= '0' && *p <= '9' ; p++ , rc-- )
222 {
223 m_pid *= 10 ;
224 m_pid += ( *p - '0' ) ;
225 }
226 }
227 }
228
229 G::Process::Id::Id( std::istream & stream )
230 {
231 stream >> m_pid ;
232 if( !stream.good() )
233 throw Process::InvalidId() ;
234 }
235
236 std::string G::Process::Id::str() const
237 {
238 std::ostringstream ss ;
239 ss << m_pid ;
240 return ss.str() ;
241 }
242
243 bool G::Process::Id::operator==( const Id & other ) const
244 {
245 return m_pid == other.m_pid ;
246 }
247
248 // ===
249
250 namespace
251 {
252 mode_t umask_value( G::Process::Umask::Mode mode )
253 {
254 mode_t m = 0 ;
255 if( mode == G::Process::Umask::Tightest ) m = 0177 ; // -rw-------
256 if( mode == G::Process::Umask::Tighter ) m = 0117 ; // -rw-rw----
257 if( mode == G::Process::Umask::Readable ) m = 0133 ; // -rw-r--r--
258 if( mode == G::Process::Umask::GroupOpen ) m = 0113 ;// -rw-rw-r--
259 return m ;
260 }
261 }
262
264 class G::Process::Umask::UmaskImp
265 {
266 public:
267 mode_t m_old_mode ;
268 } ;
269
270 G::Process::Umask::Umask( Mode mode ) :
271 m_imp(new UmaskImp)
272 {
273 m_imp->m_old_mode = ::umask( umask_value(mode) ) ;
274 }
275
276 G::Process::Umask::~Umask()
277 {
278 G_IGNORE_RETURN(mode_t) ::umask( m_imp->m_old_mode ) ;
279 delete m_imp ;
280 }
281
282 void G::Process::Umask::set( Mode mode )
283 {
284 G_IGNORE_RETURN(mode_t) ::umask( umask_value(mode) ) ;
285 }
286
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.cpp:135
G::Process::Umask::Umask
Umask(Mode)
Definition: gprocess_unix.cpp:270
G::Process::Umask::Tightest
Definition: gprocess.h:66
G::Identity::isRoot
bool isRoot() const
Returns true if the userid is zero.
Definition: gidentity_unix.cpp:122
G::Process::Umask::UmaskImp
A private implementation class used by G::Process::Umask.
Definition: gprocess_unix.cpp:264
G::SignalSafe
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:35
G::Identity::root
static Identity root()
Returns the superuser identity.
Definition: gidentity_unix.cpp:107
G::Identity::real
static Identity real()
Returns the calling process's real identity.
Definition: gidentity_unix.cpp:94
glog.h
gidentity.h
G::FileSystem::nullDevice
static const char * nullDevice()
Definition: gfs_unix.cpp:24
G::Process::Id::str
std::string str() const
Definition: gprocess_unix.cpp:236
G::Process::closeStderr
static void closeStderr()
Closes stderr.
Definition: gprocess_unix.cpp:63
G::Identity
A very low-level interface to getpwnam() and the get/set/e/uid/gid functions.
Definition: gidentity.h:41
G::Process::Id::Id
Id()
Definition: gprocess_unix.cpp:204
G::Identity::effective
static Identity effective()
Returns the current effective identity.
Definition: gidentity_unix.cpp:86
G::Process::Umask::Readable
Definition: gprocess.h:66
G::Process::errno_
static int errno_()
Returns the process's current 'errno' value.
Definition: gprocess_unix.cpp:107
gfs.h
glimits.h
G_ASSERT
#define G_ASSERT(test)
Definition: gassert.h:30
G::Process::beOrdinary
static Identity beOrdinary(Identity nobody, bool change_group=true)
Revokes special privileges (root or suid).
Definition: gprocess_unix.cpp:154
gassert.h
G::Process::Umask::~Umask
~Umask()
Definition: gprocess_unix.cpp:276
G::Process::beSpecial
static Identity beSpecial(Identity special, bool change_group=true)
Re-acquires special privileges (either root or suid).
Definition: gprocess_unix.cpp:134
G::Process::Id::operator==
bool operator==(const Id &) const
Definition: gprocess_unix.cpp:243
G::Process::NoThrow
An overload discriminator for Process.
Definition: gprocess.h:76
G::Process::revokeExtraGroups
static void revokeExtraGroups()
Revokes secondary group memberships if really root or if suid.
Definition: gprocess_unix.cpp:125
gprocess.h
G::Process::Umask::GroupOpen
Definition: gprocess.h:66
G::Process::Umask::Mode
Mode
Definition: gprocess.h:66
G::Process::IdImp::m_pid
pid_t m_pid
Definition: gprocess_unix.cpp:47
G::Process::Id
Process-id class.
Definition: gprocess.h:52
G::Process::cd
static void cd(const Path &dir)
Changes directory.
Definition: gprocess_unix.cpp:52
G::Process::closeFiles
static void closeFiles(bool keep_stderr=false)
Closes all open file descriptors.
Definition: gprocess_unix.cpp:70
G::Process::Umask::UmaskImp::m_old_mode
mode_t m_old_mode
Definition: gprocess_unix.cpp:267
G::Process::beNobody
static void beNobody(Identity)
If currently running with a real identity of root then the real identity is set to the nobody identit...
Definition: gprocess_unix.cpp:192
G::Process::IdImp
A private implementation class used by G::Process.
Definition: gprocess_unix.cpp:44
G::Process::Umask::Tighter
Definition: gprocess.h:66
G::Path
A Path object represents a file system path.
Definition: gpath.h:44
G::Process::strerror
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
Definition: gprocess_unix.cpp:119
G::Process::Umask::set
static void set(Mode)
Definition: gprocess_unix.cpp:282