Switch license from Intranator license to GPLv2 + linking exception (ACKed by Steffen)
[libi2ncommon] / src / daemonfunc.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
0a654ec0
TJ
20/***************************************************************************
21 * Copyright (C) 2008 by Intra2net AG - Thomas Jarosch *
0a654ec0
TJ
22 ***************************************************************************/
23#include <sys/types.h>
24#include <unistd.h>
5efd35b1 25#include <stdlib.h>
0a654ec0
TJ
26#include <pwd.h>
27#include <grp.h>
28
29#include <string>
30#include <stdexcept>
1eb904be 31#include "daemonfunc.hpp"
6a93d84a
TJ
32#include "stringfunc.hxx"
33#include "filefunc.hxx"
34
a287a306
TJ
35
36namespace I2n
6a93d84a 37{
1eb904be 38namespace Daemon
6a93d84a 39{
0a654ec0
TJ
40
41using namespace std;
42
43/**
44 * Fork into the background.
45 */
6a93d84a 46void daemonize()
0a654ec0 47{
90246b4a
TJ
48 int pid=fork();
49
50 if (pid < 0)
51 {
52 throw runtime_error("fork() failed");
53 }
54 if (pid > 0)
55 {
56 // parent process
57 exit (0);
58 }
59 // pid==0 -> child process: continue
0a654ec0
TJ
60}
61
62/**
09684efc 63 * Drop root privileges
0a654ec0
TJ
64 * @param username User to become. Don't change user if empty
65 * @param group Group to become. Don't change group if empty
90246b4a
TJ
66 * @param get_group_from_user Get group GID from user information if group is empty.
67 * @return true if all is fine, false otherwise
0a654ec0 68 */
90246b4a
TJ
69bool drop_root_privileges(const std::string &username,
70 const std::string &group, bool get_group_from_user)
0a654ec0 71{
90246b4a
TJ
72 if (!group.empty())
73 {
74 Group my_group(group);
75 if (!my_group.is_valid())
76 return false;
77
78 if (setgid((my_group.Gid)))
79 return false;
80 }
81
82 if (!username.empty())
83 {
84 User my_user(username);
85 if (!my_user.is_valid())
86 return false;
87
88 if (get_group_from_user && group.empty())
89 {
90 if (setgid((my_user.Gid)))
91 return false;
92 }
93
94 if (setuid(my_user.Uid))
95 return false;
96 }
e43beb91
TJ
97
98 return true;
6a93d84a
TJ
99}
100
101/**
102 * @brief determine the pids for a given program
103 * @param[in] name name (or full path) of the binary
104 * @param[out] result the pids associated with the name.
105 * @return @a true if the function performed without errors.
106 *
107 * Walk though the /proc/\<pid\>'s and search for the name.
108 *
109 * @note Since this function uses /proc, it's system specific. Currently:
110 * Linux only!
111 *
112 * @todo check cmdline and stat in /proc/\<pid\> dir for the searched name.
113 */
114bool pid_of(const std::string& name, std::vector< pid_t >& result)
115{
90246b4a
TJ
116 std::vector< std::string > entries;
117 std::vector< pid_t > fuzz1_result;
118 std::vector< pid_t > fuzz2_result;
119 result.clear();
120 if (!get_dir("/proc", entries)) return false;
121 for (std::vector< std::string >::const_iterator it= entries.begin();
122 it != entries.end();
123 ++it)
124 {
125 pid_t pid;
126 if (! string_to<pid_t>(*it, pid)) continue;
127 std::string base_path= std::string("/proc/") + *it;
128 std::string exe_path= base_path + "/exe";
129 I2n::Stat stat(exe_path, false);
130 if (not stat or not stat.is_link()) continue;
131 std::string real_exe= read_link(exe_path);
132 if (real_exe == name)
133 {
134 result.push_back( pid );
135 continue;
136 }
137
138 std::string proc_stat= read_file( base_path + "/stat");
139 if (proc_stat.empty()) continue; // process vanished
140
141 //TODO some more fuzz tests here?! (cmdline, stat(us))
142
143 if (basename(real_exe) == name)
144 {
145 fuzz2_result.push_back(pid);
146 continue;
147 }
148 }
149 if (result.empty())
150 {
151 result.swap(fuzz1_result);
152 }
153 if (result.empty())
154 {
155 result.swap(fuzz2_result);
156 }
157 return true;
6a93d84a
TJ
158} // eo pidOf(const std::string&,std::vector< pid_t >&)
159
160}
0a654ec0 161}