reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ServerProcess.cxx
Go to the documentation of this file.
1
2#if defined(HAVE_CONFIG_H)
3 #include "config.h"
4#endif
5
6#ifndef WIN32
7#include <grp.h>
8#include <pwd.h>
9#include <sys/types.h>
10#include <unistd.h>
11#endif
12
13#include <iostream>
14#include <fstream>
15#include <signal.h>
16#include <stdexcept>
17
19#include "rutil/Log.hxx"
20#include "rutil/Logger.hxx"
21#include "rutil/Time.hxx"
22
23#define RESIPROCATE_SUBSYSTEM resip::Subsystem::SIP
24
25using namespace resip;
26using namespace std;
27
28static ServerProcess* _instance = NULL;
29
30static void
31signalHandler(int signo)
32{
34 _instance->onSignal(signo);
35}
36
37ServerProcess::ServerProcess(std::chrono::milliseconds waitPeriod)
38 : mWaitPeriod(waitPeriod),
39 mPidFile(""),
40 mFinished(false),
41 mReceivedHUP(false)
42{
44 _instance = this;
45}
46
51
52void
54{
55#ifndef _WIN32
56 if(signo == SIGHUP)
57 {
58 InfoLog(<<"Received HUP signal, logger reset");
59 Log::reset();
60 mReceivedHUP = true;
61 return;
62 }
63#endif
64 std::cerr << "Shutting down" << endl;
65 mFinished = true;
66}
67
68bool
70{
71#ifdef WIN32
72 WarningLog(<<dependentSettings<<" not supported on Windows, the setting will be ignored");
73 return false;
74#else
75 return true;
76#endif
77}
78
79void
81{
82 // Install signal handlers
83#ifndef _WIN32
84 if ( signal( SIGPIPE, SIG_IGN) == SIG_ERR)
85 {
86 cerr << "Couldn't install signal handler for SIGPIPE" << endl;
87 exit(-1);
88 }
89 if ( signal( SIGHUP, signalHandler ) == SIG_ERR )
90 {
91 cerr << "Couldn't install signal handler for SIGHUP" << endl;
92 exit( -1 );
93 }
94#endif
95
96 if ( signal( SIGINT, signalHandler ) == SIG_ERR )
97 {
98 cerr << "Couldn't install signal handler for SIGINT" << endl;
99 exit( -1 );
100 }
101
102 if ( signal( SIGTERM, signalHandler ) == SIG_ERR )
103 {
104 cerr << "Couldn't install signal handler for SIGTERM" << endl;
105 exit( -1 );
106 }
107}
108
109void
110ServerProcess::dropPrivileges(const Data& runAsUser, const Data& runAsGroup)
111{
112#ifdef WIN32
113 // setuid is not supported on Windows. Callers are expected to check
114 // checkPosixProcessControl() first and skip this entirely; warn through the
115 // same helper and return rather than throwing, so that a caller which
116 // forgets does not abort the process over a setting with no meaning here.
117 checkPosixProcessControl("RunAsUser/RunAsGroup");
118#else
119 int rval;
120 uid_t cur_uid;
121 gid_t cur_gid;
122 uid_t new_uid;
123 gid_t new_gid;
124 const char *username;
125 struct passwd *pw;
126 struct group *gr;
127
128 if(runAsUser.empty())
129 {
130 ErrLog(<<"Unable to drop privileges, username not specified");
131 throw std::runtime_error("Unable to drop privileges, username not specified");
132 }
133 username = runAsUser.c_str();
134 pw = getpwnam(username);
135 if (pw == NULL)
136 {
137 ErrLog(<<"Unable to drop privileges, user not found");
138 throw std::runtime_error("Unable to drop privileges, user not found");
139 }
140 new_uid = pw->pw_uid;
141
142 if(!runAsGroup.empty())
143 {
144 gr = getgrnam(runAsGroup.c_str());
145 if (gr == NULL)
146 {
147 ErrLog(<<"Unable to drop privileges, group not found");
148 throw std::runtime_error("Unable to drop privileges, group not found");
149 }
150 new_gid = gr->gr_gid;
151 }
152 else
153 {
154 // Use default group for the specified user
155 new_gid = pw->pw_gid;
156 }
157
158 cur_gid = getgid();
159 if (cur_gid != new_gid)
160 {
161 if (cur_gid != 0)
162 {
163 ErrLog(<<"Unable to drop privileges, not root!");
164 throw std::runtime_error("Unable to drop privileges, not root!");
165 }
166
167 rval = setgid(new_gid);
168 if (rval < 0)
169 {
170 ErrLog(<<"Unable to drop privileges, operation failed (setgid)");
171 throw std::runtime_error("Unable to drop privileges, operation failed");
172 }
173 }
174
175 if(initgroups(username, new_gid) < 0)
176 {
177 ErrLog(<<"Unable to drop privileges, operation failed (initgroups)");
178 throw std::runtime_error("Unable to drop privileges, operation failed");
179 }
180
181 cur_uid = getuid();
182 if (cur_uid != new_uid)
183 {
184 if (cur_uid != 0)
185 {
186 ErrLog(<<"Unable to drop privileges, not root!");
187 throw std::runtime_error("Unable to drop privileges, not root!");
188 }
189
190 // If logging to file, the file ownership may be root and needs to
191 // be changed
192 Log::droppingPrivileges(new_uid, new_gid);
193 if(mPidFile.size() > 0)
194 {
195 if(chown(mPidFile.c_str(), new_uid, new_gid) < 0)
196 {
197 ErrLog(<<"Failed to change ownership of PID file");
198 }
199 }
200
201 rval = setuid(new_uid);
202 if (rval < 0)
203 {
204 ErrLog(<<"Unable to drop privileges, operation failed (setuid)");
205 throw std::runtime_error("Unable to drop privileges, operation failed");
206 }
207 }
208#endif
209}
210
211bool
213{
214#ifndef __linux__
215 //WarningLog(<<"can't check if process already running on this platform (not implemented yet)");
216 return false;
217#else
218 if(mPidFile.size() == 0)
219 {
220 // if no PID file specified, we do not make any check
221 return false;
222 }
223
224 pid_t running_pid;
225 std::ifstream _pid(mPidFile.c_str(), std::ios_base::in);
226 if(!_pid.good())
227 {
228 // if the file doesn't exist or can't be opened, just ignore
229 return false;
230 }
231 _pid >> running_pid;
232 _pid.close();
233
234 StackLog(<< mPidFile << " contains PID " << running_pid);
235
236 Data ourProc = Data("/proc/self/exe");
237 Data otherProc = Data("/proc/") + Data(running_pid) + Data("/exe");
238 char our_exe[513], other_exe[513];
239 int buf_size;
240
241 buf_size = readlink(ourProc.c_str(), our_exe, 512);
242 if(buf_size < 0 || buf_size == 512)
243 {
244 // if readlink fails, just ignore
245 return false;
246 }
247 our_exe[buf_size] = 0;
248
249 buf_size = readlink(otherProc.c_str(), other_exe, 512);
250 if(buf_size < 0 || buf_size == 512)
251 {
252 // if readlink fails, just ignore
253 return false;
254 }
255 other_exe[buf_size] = 0;
256
257 if(strcmp(our_exe, other_exe) == 0)
258 {
259 ErrLog(<<"already running PID: " << running_pid);
260 return true;
261 }
262 return false;
263#endif
264}
265
266void
268{
269#ifdef WIN32
270 // fork() is not possible on Windows. Callers are expected to check
271 // checkPosixProcessControl() first and skip this entirely; warn through the
272 // same helper and return rather than throwing, so that a caller which
273 // forgets keeps running in the foreground instead of aborting.
274 checkPosixProcessControl("Daemonize");
275#else
276 pid_t pid;
277 if ((pid = fork()) < 0)
278 {
279 // fork() failed
280 ErrLog(<<"fork() failed: "<<strError(errno));
281 throw std::runtime_error(strError(errno));
282 }
283 else if (pid != 0)
284 {
285 // parent process done
286 exit(0);
287 }
288 if(chdir("/") < 0)
289 {
290 ErrLog(<<"chdir() failed: "<<strError(errno));
291 throw std::runtime_error(strError(errno));
292 }
293 // Nothing should be writing to stdout/stderr after this
294 close(STDIN_FILENO);
295 close(STDOUT_FILENO);
296 close(STDERR_FILENO);
297
298 if(mPidFile.size() > 0)
299 {
300 std::ofstream _pid(mPidFile.c_str(), std::ios_base::out | std::ios_base::trunc);
301 _pid << getpid();
302 _pid.close();
303 }
304#endif
305}
306
307void
309{
310 mPidFile = pidFile;
311}
312
313void
315{
316 // Main program thread, just waits here for a signal to shutdown
317 while (!mFinished)
318 {
319 doWait();
320 if(mReceivedHUP)
321 {
322 onReload();
323 mReceivedHUP = false;
324 }
325 onLoop();
326 }
327}
328
329void
331{
332 sleepMs((unsigned int)mWaitPeriod.count());
333}
334
335void
339
340void
344
345/* ====================================================================
346 *
347 * Copyright (c) 2026, SIP Spectrum, Inc. https://www.sipspectrum.com
348 * Copyright (c) 2012 Daniel Pocock. All rights reserved.
349 *
350 * Redistribution and use in source and binary forms, with or without
351 * modification, are permitted provided that the following conditions
352 * are met:
353 *
354 * 1. Redistributions of source code must retain the above copyright
355 * notice, this list of conditions and the following disclaimer.
356 *
357 * 2. Redistributions in binary form must reproduce the above copyright
358 * notice, this list of conditions and the following disclaimer in
359 * the documentation and/or other materials provided with the
360 * distribution.
361 *
362 * 3. Neither the name of the author(s) nor the names of any contributors
363 * may be used to endorse or promote products derived from this software
364 * without specific prior written permission.
365 *
366 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
367 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
368 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
369 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
370 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
371 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
372 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
373 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
374 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
375 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
376 * SUCH DAMAGE.
377 *
378 * ====================================================================
379 *
380 */
381/*
382 * vi: set shiftwidth=3 expandtab:
383 */
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
static ServerProcess * _instance
static void signalHandler(int signo)
#define sleepMs(t)
Definition Server.hxx:16
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
static void reset()
Frees logger stream.
Definition Log.cxx:957
static void droppingPrivileges(uid_t uid, pid_t pid)
Definition Log.cxx:964
void dropPrivileges(const Data &runAsUser, const Data &runAsGroup)
ServerProcess(std::chrono::milliseconds waitPeriod=std::chrono::milliseconds(50))
virtual void onReload()
void onSignal(int signo)
void setPidFile(const Data &pidFile)
bool checkPosixProcessControl(const Data &dependentSettings)
dcm! – add UnusedChecking(_enum) below;
std::string strError(int err)
Definition compat.hxx:274