libi2ncommon: (tomj) unit tests for normalize_path() corner cases
[libi2ncommon] / src / daemonfunc.cpp
CommitLineData
0a654ec0
TJ
1/***************************************************************************
2 * Copyright (C) 2008 by Intra2net AG - Thomas Jarosch *
3 * thomas.jarosch@intra2net.com *
4 * http://www.intra2net.com *
5 ***************************************************************************/
6#include <sys/types.h>
7#include <unistd.h>
5efd35b1 8#include <stdlib.h>
0a654ec0
TJ
9#include <pwd.h>
10#include <grp.h>
11
12#include <string>
13#include <stdexcept>
1eb904be 14#include "daemonfunc.hpp"
6a93d84a
TJ
15#include "stringfunc.hxx"
16#include "filefunc.hxx"
17
a287a306
TJ
18
19namespace I2n
6a93d84a 20{
1eb904be 21namespace Daemon
6a93d84a 22{
0a654ec0
TJ
23
24using namespace std;
25
26/**
27 * Fork into the background.
28 */
6a93d84a 29void daemonize()
0a654ec0 30{
90246b4a
TJ
31 int pid=fork();
32
33 if (pid < 0)
34 {
35 throw runtime_error("fork() failed");
36 }
37 if (pid > 0)
38 {
39 // parent process
40 exit (0);
41 }
42 // pid==0 -> child process: continue
0a654ec0
TJ
43}
44
45/**
09684efc 46 * Drop root privileges
0a654ec0
TJ
47 * @param username User to become. Don't change user if empty
48 * @param group Group to become. Don't change group if empty
90246b4a
TJ
49 * @param get_group_from_user Get group GID from user information if group is empty.
50 * @return true if all is fine, false otherwise
0a654ec0 51 */
90246b4a
TJ
52bool drop_root_privileges(const std::string &username,
53 const std::string &group, bool get_group_from_user)
0a654ec0 54{
90246b4a
TJ
55 if (!group.empty())
56 {
57 Group my_group(group);
58 if (!my_group.is_valid())
59 return false;
60
61 if (setgid((my_group.Gid)))
62 return false;
63 }
64
65 if (!username.empty())
66 {
67 User my_user(username);
68 if (!my_user.is_valid())
69 return false;
70
71 if (get_group_from_user && group.empty())
72 {
73 if (setgid((my_user.Gid)))
74 return false;
75 }
76
77 if (setuid(my_user.Uid))
78 return false;
79 }
6a93d84a
TJ
80}
81
82/**
83 * @brief determine the pids for a given program
84 * @param[in] name name (or full path) of the binary
85 * @param[out] result the pids associated with the name.
86 * @return @a true if the function performed without errors.
87 *
88 * Walk though the /proc/\<pid\>'s and search for the name.
89 *
90 * @note Since this function uses /proc, it's system specific. Currently:
91 * Linux only!
92 *
93 * @todo check cmdline and stat in /proc/\<pid\> dir for the searched name.
94 */
95bool pid_of(const std::string& name, std::vector< pid_t >& result)
96{
90246b4a
TJ
97 std::vector< std::string > entries;
98 std::vector< pid_t > fuzz1_result;
99 std::vector< pid_t > fuzz2_result;
100 result.clear();
101 if (!get_dir("/proc", entries)) return false;
102 for (std::vector< std::string >::const_iterator it= entries.begin();
103 it != entries.end();
104 ++it)
105 {
106 pid_t pid;
107 if (! string_to<pid_t>(*it, pid)) continue;
108 std::string base_path= std::string("/proc/") + *it;
109 std::string exe_path= base_path + "/exe";
110 I2n::Stat stat(exe_path, false);
111 if (not stat or not stat.is_link()) continue;
112 std::string real_exe= read_link(exe_path);
113 if (real_exe == name)
114 {
115 result.push_back( pid );
116 continue;
117 }
118
119 std::string proc_stat= read_file( base_path + "/stat");
120 if (proc_stat.empty()) continue; // process vanished
121
122 //TODO some more fuzz tests here?! (cmdline, stat(us))
123
124 if (basename(real_exe) == name)
125 {
126 fuzz2_result.push_back(pid);
127 continue;
128 }
129 }
130 if (result.empty())
131 {
132 result.swap(fuzz1_result);
133 }
134 if (result.empty())
135 {
136 result.swap(fuzz2_result);
137 }
138 return true;
6a93d84a
TJ
139} // eo pidOf(const std::string&,std::vector< pid_t >&)
140
141}
0a654ec0 142}