summaryrefslogtreecommitdiffabout
path: root/src/process.cc
authorMichael Krelin <hacker@klever.net>2004-07-15 04:13:35 (UTC)
committer Michael Krelin <hacker@klever.net>2004-07-15 04:13:35 (UTC)
commit5e437102c59f4544e3803598eabcb643d403272d (patch) (unidiff)
tree7703657f2dac2fd9fb2b2a1f453ca2f30227efa1 /src/process.cc
parent4f8a6f291a231410a03c438bc9d63a7beb861e7b (diff)
downloaddudki-5e437102c59f4544e3803598eabcb643d403272d.zip
dudki-5e437102c59f4544e3803598eabcb643d403272d.tar.gz
dudki-5e437102c59f4544e3803598eabcb643d403272d.tar.bz2
initgroups() call added when changing uid
Diffstat (limited to 'src/process.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--src/process.cc17
1 files changed, 10 insertions, 7 deletions
diff --git a/src/process.cc b/src/process.cc
index fda35e8..bfab311 100644
--- a/src/process.cc
+++ b/src/process.cc
@@ -1,184 +1,187 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <unistd.h> 3#include <unistd.h>
4#include <signal.h> 4#include <signal.h>
5#include <pwd.h> 5#include <pwd.h>
6#include <grp.h> 6#include <grp.h>
7#include <sys/wait.h> 7#include <sys/wait.h>
8#include <syslog.h> 8#include <syslog.h>
9#include <errno.h> 9#include <errno.h>
10#include <iostream> 10#include <iostream>
11#include <fstream> 11#include <fstream>
12#include <stdexcept> 12#include <stdexcept>
13using namespace std; 13using namespace std;
14#include "process.h" 14#include "process.h"
15#include "configuration.h" 15#include "configuration.h"
16 16
17void process::check(const string& id,configuration& config) { 17void process::check(const string& id,configuration& config) {
18 bool running = false; 18 bool running = false;
19 ifstream pids(pidfile.c_str(),ios::in); 19 ifstream pids(pidfile.c_str(),ios::in);
20 if(pids) { 20 if(pids) {
21 pid_t pid = 0; 21 pid_t pid = 0;
22 pids >> pid; 22 pids >> pid;
23 pids.close(); 23 pids.close();
24 if(pid) { 24 if(pid) {
25 if(!kill(pid,0)) { 25 if(!kill(pid,0)) {
26 running = true; 26 running = true;
27 } 27 }
28 } 28 }
29 } 29 }
30 if(running){ 30 if(running){
31 patience = 0; 31 patience = 0;
32 }else{ 32 }else{
33 if(patience>60) { // TODO: configurable 33 if(patience>60) { // TODO: configurable
34 patience = 0; 34 patience = 0;
35 }else{ 35 }else{
36 if(patience<10) { // TODO: configurable 36 if(patience<10) { // TODO: configurable
37 syslog(LOG_NOTICE,"The process '%s' is down, trying to launch.",id.c_str()); 37 syslog(LOG_NOTICE,"The process '%s' is down, trying to launch.",id.c_str());
38 do_notify(id,"Starting up", 38 do_notify(id,"Starting up",
39 "The named process seems to be down. Dudki will try\n" 39 "The named process seems to be down. Dudki will try\n"
40 "to revive it by running the specified command.\n", 40 "to revive it by running the specified command.\n",
41 config); 41 config);
42 try { 42 try {
43 launch(id,config); 43 launch(id,config);
44 }catch(exception& e) { 44 }catch(exception& e) {
45 syslog(LOG_ERR,"Error trying to launch process '%s': %s",id.c_str(),e.what()); 45 syslog(LOG_ERR,"Error trying to launch process '%s': %s",id.c_str(),e.what());
46 } 46 }
47 }else if(patience==10){ // TODO: configurable like the above 47 }else if(patience==10){ // TODO: configurable like the above
48 syslog(LOG_NOTICE,"Giving up on process '%s' for a while",id.c_str()); 48 syslog(LOG_NOTICE,"Giving up on process '%s' for a while",id.c_str());
49 do_notify(id,"Giving up", 49 do_notify(id,"Giving up",
50 "After a number of attempts to relaunch the named process\n" 50 "After a number of attempts to relaunch the named process\n"
51 "It still seems to be down. Dudki is giving up attempts\n" 51 "It still seems to be down. Dudki is giving up attempts\n"
52 "to revive the process for a while.\n", 52 "to revive the process for a while.\n",
53 config); 53 config);
54 } 54 }
55 patience++; 55 patience++;
56 } 56 }
57 } 57 }
58} 58}
59 59
60void process::launch(const string& id,configuration& config) { 60void process::launch(const string& id,configuration& config) {
61 uid_t uid = 0; 61 uid_t uid = (uid_t)-1;
62 gid_t gid = (gid_t)-1;
62 if(!user.empty()) { 63 if(!user.empty()) {
63 struct passwd *ptmp = getpwnam(user.c_str()); 64 struct passwd *ptmp = getpwnam(user.c_str());
64 if(ptmp) { 65 if(ptmp) {
65 uid = ptmp->pw_uid; 66 uid = ptmp->pw_uid;
67 gid = ptmp->pw_gid;
66 }else{ 68 }else{
67 errno=0; 69 errno=0;
68 uid = strtol(user.c_str(),NULL,0); 70 uid = strtol(user.c_str(),NULL,0);
69 if(errno) 71 if(errno)
70 throw runtime_error("Failed to resolve User value to uid"); 72 throw runtime_error("Failed to resolve User value to uid");
71 } 73 }
72 } 74 }
73 gid_t gid = 0;
74 if(!group.empty()) { 75 if(!group.empty()) {
75 struct group *gtmp = getgrnam(group.c_str()); 76 struct group *gtmp = getgrnam(group.c_str());
76 if(gtmp) { 77 if(gtmp) {
77 gid = gtmp->gr_gid; 78 gid = gtmp->gr_gid;
78 }else{ 79 }else{
79 errno = 0; 80 errno = 0;
80 gid = strtol(group.c_str(),NULL,0); 81 gid = strtol(group.c_str(),NULL,0);
81 if(errno) 82 if(errno)
82 throw runtime_error("Failed to reslove Group value to gid"); 83 throw runtime_error("Failed to reslove Group value to gid");
83 } 84 }
84 } 85 }
85 pid_t p = fork(); 86 pid_t p = fork();
86 if(p<0) 87 if(p<0)
87 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()"); 88 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to fork()");
88 if(!p) { 89 if(!p) {
89 // child 90 // child
90 try { 91 try {
91 setsid(); 92 setsid();
93 if(user.empty()) {
94 if((getgid()!=gid) && setgid(gid))
95 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to setgid()");
96 }else{
97 if(initgroups(user.c_str(),gid))
98 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to initgroups()");
99 }
92 if(!chroot.empty()) { 100 if(!chroot.empty()) {
93 if(::chroot(chroot.c_str())) 101 if(::chroot(chroot.c_str()))
94 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to chroot()"); 102 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to chroot()");
95 } 103 }
96 if(!group.empty()) {
97 // TODO: initgroups()?
98 if((getgid()!=gid) && setgid(gid))
99 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to setgid()");
100 }
101 if(!user.empty()) { 104 if(!user.empty()) {
102 if((getuid()!=uid) && setuid(uid)) 105 if((getuid()!=uid) && setuid(uid))
103 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to setuid()"); 106 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to setuid()");
104 } 107 }
105 char *argv[] = { "/bin/sh", "-c", (char*)restart_cmd.c_str(), NULL }; 108 char *argv[] = { "/bin/sh", "-c", (char*)restart_cmd.c_str(), NULL };
106 close(0); close(1); close(2); 109 close(0); close(1); close(2);
107 execv("/bin/sh",argv); 110 execv("/bin/sh",argv);
108 }catch(exception& e) { 111 }catch(exception& e) {
109 syslog(LOG_ERR,"Error trying to launch process '%s': %s",id.c_str(),e.what()); 112 syslog(LOG_ERR,"Error trying to launch process '%s': %s",id.c_str(),e.what());
110 } 113 }
111 _exit(-1); 114 _exit(-1);
112 } 115 }
113 // parent 116 // parent
114 int rv; 117 int rv;
115 if(waitpid(p,&rv,0)<0) 118 if(waitpid(p,&rv,0)<0)
116 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to waitpid()"); 119 throw runtime_error(string(__PRETTY_FUNCTION__)+": failed to waitpid()");
117} 120}
118 121
119void process::do_notify(const string& id,const string& event,const string& description,configuration& config) { 122void process::do_notify(const string& id,const string& event,const string& description,configuration& config) {
120 string the_notify; 123 string the_notify;
121 if(!notify.empty()) 124 if(!notify.empty())
122 the_notify=notify; 125 the_notify=notify;
123 else if(!config.notify.empty()) 126 else if(!config.notify.empty())
124 the_notify=config.notify; 127 the_notify=config.notify;
125 else 128 else
126 return; 129 return;
127 try { 130 try {
128 string::size_type colon = the_notify.find(':'); 131 string::size_type colon = the_notify.find(':');
129 if(colon==string::npos) 132 if(colon==string::npos)
130 throw runtime_error("invalid notify action specification"); 133 throw runtime_error("invalid notify action specification");
131 string nschema = the_notify.substr(0,colon); 134 string nschema = the_notify.substr(0,colon);
132 string ntarget = the_notify.substr(colon+1); 135 string ntarget = the_notify.substr(colon+1);
133 if(nschema=="mailto") { 136 if(nschema=="mailto") {
134 notify_mailto(ntarget,id,event,description,config); 137 notify_mailto(ntarget,id,event,description,config);
135 }else 138 }else
136 throw runtime_error("unrecognized notification schema"); 139 throw runtime_error("unrecognized notification schema");
137 }catch(exception& e) { 140 }catch(exception& e) {
138 syslog(LOG_ERR,"Notification error: %s",e.what()); 141 syslog(LOG_ERR,"Notification error: %s",e.what());
139 } 142 }
140} 143}
141 144
142void process::notify_mailto(const string& email,const string& id,const string& event,const string& description,configuration& config) { 145void process::notify_mailto(const string& email,const string& id,const string& event,const string& description,configuration& config) {
143 int files[2]; 146 int files[2];
144 if(pipe(files)) 147 if(pipe(files))
145 throw runtime_error("Failed to pipe()"); 148 throw runtime_error("Failed to pipe()");
146 pid_t pid = vfork(); 149 pid_t pid = vfork();
147 if(pid==-1) { 150 if(pid==-1) {
148 close(files[0]); 151 close(files[0]);
149 close(files[1]); 152 close(files[1]);
150 throw runtime_error("Failed to vfork()"); 153 throw runtime_error("Failed to vfork()");
151 } 154 }
152 if(!pid) { 155 if(!pid) {
153 // child 156 // child
154 if(dup2(files[0],0)!=0) 157 if(dup2(files[0],0)!=0)
155 _exit(-1); 158 _exit(-1);
156 close(1); 159 close(1);
157 close(files[0]); 160 close(files[0]);
158 close(files[1]); 161 close(files[1]);
159 execl("/usr/sbin/sendmail","usr/sbin/sendmail","-i",email.c_str(),NULL); 162 execl("/usr/sbin/sendmail","usr/sbin/sendmail","-i",email.c_str(),NULL);
160 _exit(-1); 163 _exit(-1);
161 } 164 }
162 // parent 165 // parent
163 close(files[0]); 166 close(files[0]);
164 FILE *mta = fdopen(files[1],"w"); 167 FILE *mta = fdopen(files[1],"w");
165 for(headers_t::const_iterator i=mailto_headers.begin();i!=mailto_headers.end();++i) { 168 for(headers_t::const_iterator i=mailto_headers.begin();i!=mailto_headers.end();++i) {
166 fprintf(mta,"%s: %s\n",i->first.c_str(),i->second.c_str()); 169 fprintf(mta,"%s: %s\n",i->first.c_str(),i->second.c_str());
167 } 170 }
168 for(headers_t::const_iterator i=config.mailto_headers.begin();i!=config.mailto_headers.end();++i) { 171 for(headers_t::const_iterator i=config.mailto_headers.begin();i!=config.mailto_headers.end();++i) {
169 if(mailto_headers.find(i->first)!=mailto_headers.end()) 172 if(mailto_headers.find(i->first)!=mailto_headers.end())
170 continue; 173 continue;
171 fprintf(mta,"%s: %s\n",i->first.c_str(),i->second.c_str()); 174 fprintf(mta,"%s: %s\n",i->first.c_str(),i->second.c_str());
172 } 175 }
173 fprintf(mta, 176 fprintf(mta,
174 "Subject: [%s] %s\n\n" 177 "Subject: [%s] %s\n\n"
175 "%s\n" 178 "%s\n"
176 "---\n" 179 "---\n"
177 "This message was sent automatically by the 'dudki' daemon\n", 180 "This message was sent automatically by the 'dudki' daemon\n",
178 id.c_str(), event.c_str(), 181 id.c_str(), event.c_str(),
179 description.c_str() ); 182 description.c_str() );
180 fclose(mta); 183 fclose(mta);
181 int status; 184 int status;
182 waitpid(pid,&status,0); 185 waitpid(pid,&status,0);
183 // TODO: check the return code 186 // TODO: check the return code
184} 187}