|
1 /*************************************************************************** |
|
2 helper.cpp - description |
|
3 ------------------- |
|
4 begin : Sa M� 5 2005 |
|
5 copyright : (C) 2005 by Christian Hilgers |
|
6 email : christian@hilgers.ag |
|
7 ***************************************************************************/ |
|
8 |
|
9 /*************************************************************************** |
|
10 * * |
|
11 * This program is free software; you can redistribute it and/or modify * |
|
12 * it under the terms of the GNU General Public License as published by * |
|
13 * the Free Software Foundation; either version 2 of the License, or * |
|
14 * (at your option) any later version. * |
|
15 * * |
|
16 ***************************************************************************/ |
|
17 |
|
18 #include "default.h" |
|
19 #include "params.h" |
|
20 #include "logfile.h" |
|
21 |
|
22 #include <sys/types.h> |
|
23 #include <sys/stat.h> |
|
24 #include <sys/wait.h> |
|
25 #include <unistd.h> |
|
26 #include <fcntl.h> |
|
27 #include <pwd.h> |
|
28 #include <grp.h> |
|
29 #include <signal.h> |
|
30 #include <errno.h> |
|
31 #include <iostream> |
|
32 #include <fstream> |
|
33 #include <cstdlib> |
|
34 #include <cstring> |
|
35 |
|
36 extern char TempFileName[MAXSCANTEMPFILELENGTH+1]; |
|
37 extern int fd_tempfile; |
|
38 |
|
39 static void ChildExited( int SignalNo ) |
|
40 { |
|
41 //Handle with waitpid() in havp.cpp |
|
42 } |
|
43 |
|
44 static void ChildChildExited( int SignalNo ) |
|
45 { |
|
46 int status; |
|
47 while (waitpid(-1, &status, WNOHANG) > 0); |
|
48 } |
|
49 |
|
50 static void RereadAll( int SignalNo ) |
|
51 { |
|
52 extern bool rereadall; |
|
53 rereadall = true; |
|
54 } |
|
55 |
|
56 static void RestartChild( int SignalNo ) |
|
57 { |
|
58 extern bool childrestart; |
|
59 childrestart = true; |
|
60 } |
|
61 |
|
62 static void ExitProcess( int SignalNo ) |
|
63 { |
|
64 pid_t pgid = getpgid(0); |
|
65 |
|
66 //PSE: all processes have same pgid! |
|
67 if (getpid() == pgid) |
|
68 { |
|
69 //PSE: only parent, no scan-file to delete!! |
|
70 killpg(pgid,SIGINT); |
|
71 |
|
72 //Delete pidfile |
|
73 while (unlink(Params::GetConfigString("PIDFILE").c_str()) < 0 && (errno == EINTR || errno == EBUSY)); |
|
74 } |
|
75 else |
|
76 { |
|
77 if (fd_tempfile > -1) |
|
78 { |
|
79 //Delete tempfile |
|
80 while (close(fd_tempfile) < 0 && errno == EINTR); |
|
81 while (unlink(TempFileName) < 0 && (errno == EINTR || errno == EBUSY)); |
|
82 } |
|
83 } |
|
84 |
|
85 //End process |
|
86 exit(0); |
|
87 } |
|
88 |
|
89 |
|
90 //Install Signal Handlers for different fork levels |
|
91 int InstallSignal( int level ) |
|
92 { |
|
93 struct sigaction Signal; |
|
94 memset(&Signal, 0, sizeof(Signal)); |
|
95 Signal.sa_flags = 0; |
|
96 |
|
97 //Level 0 = Main Havp Process |
|
98 //Level 1 = ProxyHandler Process |
|
99 //Level 2 = Scanner Process |
|
100 //Signals are inherited from previous level at forking.. |
|
101 |
|
102 if ( level == 0 ) //Main Havp Process |
|
103 { |
|
104 Signal.sa_handler = ExitProcess; |
|
105 if (sigaction(SIGINT, &Signal, NULL) != 0) return -1; |
|
106 if (sigaction(SIGTERM, &Signal, NULL) != 0) return -1; |
|
107 |
|
108 Signal.sa_handler = RereadAll; |
|
109 if (sigaction(SIGHUP, &Signal, NULL) != 0) return -1; |
|
110 //Compatibility for 0.77 and older init-script |
|
111 if (sigaction(SIGUSR2, &Signal, NULL) != 0) return -1; |
|
112 |
|
113 Signal.sa_handler = ChildExited; |
|
114 if (sigaction(SIGCHLD, &Signal, NULL) != 0) return -1; |
|
115 |
|
116 Signal.sa_handler = SIG_IGN; |
|
117 if (sigaction(SIGUSR1, &Signal, NULL) != 0) return -1; |
|
118 if (sigaction(SIGPIPE, &Signal, NULL) != 0) return -1; |
|
119 } |
|
120 else if ( level == 1 ) //ProxyHandler Process |
|
121 { |
|
122 Signal.sa_handler = RestartChild; |
|
123 if (sigaction(SIGUSR1, &Signal, NULL) != 0) return -1; |
|
124 |
|
125 Signal.sa_handler = ChildChildExited; |
|
126 if (sigaction(SIGCHLD, &Signal, NULL) != 0) return -1; |
|
127 |
|
128 Signal.sa_handler = SIG_IGN; |
|
129 if (sigaction(SIGHUP, &Signal, NULL) != 0) return -1; |
|
130 if (sigaction(SIGUSR2, &Signal, NULL) != 0) return -1; |
|
131 } |
|
132 else if ( level == 2 ) //Scanner Process |
|
133 { |
|
134 Signal.sa_handler = SIG_IGN; |
|
135 if (sigaction(SIGUSR1, &Signal, NULL) != 0) return -1; |
|
136 } |
|
137 |
|
138 return 0; |
|
139 } |
|
140 |
|
141 |
|
142 bool MakeDaemon() |
|
143 { |
|
144 pid_t daemon = fork(); |
|
145 |
|
146 if ( daemon < 0 ) |
|
147 { |
|
148 return false; |
|
149 } |
|
150 else if (daemon != 0) |
|
151 { |
|
152 //Exit Parent |
|
153 exit(0); |
|
154 } |
|
155 //Child |
|
156 |
|
157 setsid(); |
|
158 chdir("/tmp/"); |
|
159 umask(077); |
|
160 |
|
161 //Close stdin/stdout/stderr |
|
162 close(0); |
|
163 close(1); |
|
164 close(2); |
|
165 |
|
166 return true; |
|
167 } |
|
168 |
|
169 |
|
170 bool HardLockTest() |
|
171 { |
|
172 memset(&TempFileName, 0, sizeof(TempFileName)); |
|
173 strncpy(TempFileName, Params::GetConfigString("SCANTEMPFILE").c_str(), MAXSCANTEMPFILELENGTH); |
|
174 |
|
175 if ((fd_tempfile = mkstemp(TempFileName)) < 0) |
|
176 { |
|
177 string Error = strerror(errno); |
|
178 cout << "Could not open lock testfile " << TempFileName << ": " << Error << endl; |
|
179 string user = Params::GetConfigString("USER"); |
|
180 string scanpath = Params::GetConfigString("SCANTEMPFILE"); |
|
181 cout << "Maybe you need to: chown " << user << " " << scanpath.substr(0, scanpath.rfind("/")) << endl; |
|
182 return false; |
|
183 } |
|
184 |
|
185 #ifndef NOMAND |
|
186 while (fchmod(fd_tempfile, S_IRUSR|S_IWUSR|S_IRGRP|S_ISGID) < 0) |
|
187 #else |
|
188 while (fchmod(fd_tempfile, S_IRUSR|S_IWUSR|S_IRGRP) < 0) |
|
189 #endif |
|
190 { |
|
191 if (errno == EINTR) continue; |
|
192 |
|
193 string Error = strerror(errno); |
|
194 cout << "Testfile fchmod() failed: " << Error << endl; |
|
195 return false; |
|
196 } |
|
197 |
|
198 char eicardata[] = "a5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*\0"; |
|
199 eicardata[0] = 'X'; |
|
200 |
|
201 while (write(fd_tempfile, eicardata, 68) < 0) |
|
202 { |
|
203 if (errno == EINTR) continue; |
|
204 |
|
205 LogFile::ErrorMessage("Could not write to Scannerfile: %s\n", TempFileName ); |
|
206 return false; |
|
207 } |
|
208 |
|
209 #ifdef NOMAND |
|
210 return true; |
|
211 |
|
212 #else |
|
213 struct flock lock; |
|
214 |
|
215 lock.l_type = F_WRLCK; |
|
216 lock.l_start = 0; |
|
217 lock.l_whence = SEEK_SET; |
|
218 lock.l_len = MAXFILELOCKSIZE; |
|
219 |
|
220 while (fcntl(fd_tempfile, F_SETLK, &lock) < 0) |
|
221 { |
|
222 if (errno == EINTR) continue; |
|
223 |
|
224 string Error = strerror(errno); |
|
225 cout << "Testfile fcntl() failed: " << Error << endl; |
|
226 return false; |
|
227 } |
|
228 |
|
229 if (lseek(fd_tempfile, 0, SEEK_SET) < 0) |
|
230 { |
|
231 string Error = strerror(errno); |
|
232 cout << "Testfile lseek() failed: " << Error << endl; |
|
233 return false; |
|
234 } |
|
235 |
|
236 pid_t testpid = fork(); |
|
237 |
|
238 if (testpid < 0) |
|
239 { |
|
240 string Error = strerror(errno); |
|
241 cout << "Error forking lock test: " << Error << endl; |
|
242 return false; |
|
243 } |
|
244 else if (testpid != 0) |
|
245 { |
|
246 //Parent |
|
247 int status; |
|
248 while ((testpid = wait(&status)) < 0 && errno == EINTR); |
|
249 |
|
250 if (WEXITSTATUS(status) == 1) |
|
251 { |
|
252 return false; |
|
253 } |
|
254 |
|
255 //Descriptor not needed anymore |
|
256 while (close(fd_tempfile) < 0 && errno == EINTR); |
|
257 fd_tempfile = -1; |
|
258 |
|
259 return true; |
|
260 } |
|
261 //Child |
|
262 |
|
263 int fd; |
|
264 |
|
265 if ((fd = open(TempFileName, O_RDONLY)) < 0) |
|
266 { |
|
267 string Error = strerror(errno); |
|
268 cout << "Could not open lock testfile " << TempFileName << ": " << Error << endl; |
|
269 exit(1); |
|
270 } |
|
271 |
|
272 //Set nonblocking |
|
273 while (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
274 { |
|
275 if (errno == EINTR) continue; |
|
276 |
|
277 string Error = strerror(errno); |
|
278 cout << "Testfile fcntl() failed: " << Error << endl; |
|
279 exit(1); |
|
280 } |
|
281 |
|
282 int testread; |
|
283 char tmpread[2]; |
|
284 |
|
285 while ((testread = read(fd, tmpread, 1)) < 0 && errno == EINTR); |
|
286 while (close(fd) < 0 && errno == EINTR); |
|
287 |
|
288 if (testread > 0) |
|
289 { |
|
290 cout << "Filesystem not supporting mandatory locks!" << endl; |
|
291 cout << "On Linux, you need to mount filesystem with \"-o mand\"" << endl; |
|
292 exit(1); |
|
293 } |
|
294 |
|
295 //Success |
|
296 exit(0); |
|
297 #endif |
|
298 } |
|
299 |
|
300 |
|
301 bool ChangeUserAndGroup( string usr, string grp ) |
|
302 { |
|
303 if ( geteuid() != 0 ) return true; |
|
304 |
|
305 if ( usr == "" || grp == "" ) |
|
306 { |
|
307 cout << "You must define User and Group" << endl; |
|
308 return false; |
|
309 } |
|
310 |
|
311 struct passwd *user; |
|
312 struct group *my_group; |
|
313 |
|
314 if ( (user = getpwnam( usr.c_str() )) == NULL ) |
|
315 { |
|
316 cout << "User does not exist: " << usr << endl; |
|
317 cout << "You need to: useradd " << usr << endl; |
|
318 return false; |
|
319 } |
|
320 |
|
321 if ( (my_group = getgrnam( grp.c_str() )) == NULL ) |
|
322 { |
|
323 cout << "Group does not exist: " << grp << endl; |
|
324 cout << "You need to: groupadd " << grp << endl; |
|
325 return false; |
|
326 } |
|
327 |
|
328 #ifdef HAVE_INITGROUPS |
|
329 if ( initgroups( usr.c_str(), user->pw_gid ) ) |
|
330 { |
|
331 cout << "Group initialization failed (initgroups)" << endl; |
|
332 return false; |
|
333 } |
|
334 #else |
|
335 #if HAVE_SETGROUPS |
|
336 if ( setgroups(1, &user->pw_gid) ) |
|
337 { |
|
338 cout << "Group initialization failed (setgroups)" << endl; |
|
339 return false; |
|
340 } |
|
341 #endif |
|
342 #endif |
|
343 |
|
344 if ( setgid( my_group->gr_gid ) < 0 ) |
|
345 { |
|
346 cout << "Could not change group to: " << grp << endl; |
|
347 return false; |
|
348 } |
|
349 |
|
350 if ( setuid( user->pw_uid ) < 0 ) |
|
351 { |
|
352 cout << "Could not change user to: " << usr << endl; |
|
353 return false; |
|
354 } |
|
355 |
|
356 return true; |
|
357 } |
|
358 |
|
359 string GetUser() |
|
360 { |
|
361 struct passwd *user = getpwuid( geteuid() ); |
|
362 if ( user == NULL ) return "<error>"; |
|
363 return (string)user->pw_name; |
|
364 } |
|
365 |
|
366 string GetGroup() |
|
367 { |
|
368 struct group *my_group = getgrgid( getegid() ); |
|
369 if ( my_group == NULL ) return "<error>"; |
|
370 return (string)my_group->gr_name; |
|
371 } |
|
372 |
|
373 bool WritePidFile( pid_t havp_pid ) |
|
374 { |
|
375 ofstream pidf( Params::GetConfigString("PIDFILE").c_str(), ios_base::trunc ); |
|
376 |
|
377 if ( !pidf ) return false; |
|
378 |
|
379 pidf << havp_pid << endl; |
|
380 |
|
381 pidf.close(); |
|
382 |
|
383 return true; |
|
384 } |
|
385 |