author | Michael Krelin <hacker@klever.net> | 2004-07-15 04:13:35 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2004-07-15 04:13:35 (UTC) |
commit | 5e437102c59f4544e3803598eabcb643d403272d (patch) (unidiff) | |
tree | 7703657f2dac2fd9fb2b2a1f453ca2f30227efa1 /src/process.cc | |
parent | 4f8a6f291a231410a03c438bc9d63a7beb861e7b (diff) | |
download | dudki-5e437102c59f4544e3803598eabcb643d403272d.zip dudki-5e437102c59f4544e3803598eabcb643d403272d.tar.gz dudki-5e437102c59f4544e3803598eabcb643d403272d.tar.bz2 |
initgroups() call added when changing uid
-rw-r--r-- | src/process.cc | 17 |
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> |
13 | using namespace std; | 13 | using namespace std; |
14 | #include "process.h" | 14 | #include "process.h" |
15 | #include "configuration.h" | 15 | #include "configuration.h" |
16 | 16 | ||
17 | void process::check(const string& id,configuration& config) { | 17 | void 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 | ||
60 | void process::launch(const string& id,configuration& config) { | 60 | void 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 | ||
119 | void process::do_notify(const string& id,const string& event,const string& description,configuration& config) { | 122 | void 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 | ||
142 | void process::notify_mailto(const string& email,const string& id,const string& event,const string& description,configuration& config) { | 145 | void 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 | } |