Drop privileges in the parent process before waiting for the signal
from the child process, so that the parent properly responds to
the signal and terminates.
Verify that the log file will be owned by user that the deamon will
run as.
Explicitly set PID file ownership to root when starting the daemon
as root with the PID file enabled.
... | ... |
@@ -90,9 +90,13 @@ int main(int argc, char **argv) |
90 | 90 |
time_t currtime; |
91 | 91 |
mode_t umsk; |
92 | 92 |
pid_t parentPid = getpid(); |
93 |
+#ifndef _WIN32 |
|
94 |
+ int dropPrivRet = 0; |
|
95 |
+#endif /* _WIN32 */ |
|
93 | 96 |
|
94 | 97 |
sigset_t sigset; |
95 | 98 |
struct sigaction act; |
99 |
+ const char * user_name = NULL; |
|
96 | 100 |
|
97 | 101 |
cl_initialize_crypto(); |
98 | 102 |
|
... | ... |
@@ -154,6 +158,10 @@ int main(int argc, char **argv) |
154 | 154 |
} |
155 | 155 |
free(pt); |
156 | 156 |
|
157 |
+ if ((opt = optget(opts, "User"))->enabled){ |
|
158 |
+ user_name = opt->strarg; |
|
159 |
+ } |
|
160 |
+ |
|
157 | 161 |
if ((opt = optget(opts, "Chroot"))->enabled) { |
158 | 162 |
if (chdir(opt->strarg) != 0) { |
159 | 163 |
logg("!Cannot change directory to %s\n", opt->strarg); |
... | ... |
@@ -252,11 +260,11 @@ int main(int argc, char **argv) |
252 | 252 |
} |
253 | 253 |
} |
254 | 254 |
|
255 |
- if ((opt = optget(opts, "User"))->enabled) { |
|
255 |
+ if (NULL != user_name) { |
|
256 | 256 |
struct passwd *user; |
257 |
- if ((user = getpwnam(opt->strarg)) == NULL) { |
|
257 |
+ if ((user = getpwnam(user_name)) == NULL) { |
|
258 | 258 |
logg("ERROR: Can't get information about user %s.\n", |
259 |
- opt->strarg); |
|
259 |
+ user_name); |
|
260 | 260 |
logg_close(); |
261 | 261 |
optfree(opts); |
262 | 262 |
return 1; |
... | ... |
@@ -360,7 +368,7 @@ int main(int argc, char **argv) |
360 | 360 |
|
361 | 361 |
#ifndef _WIN32 |
362 | 362 |
if (!optget(opts, "Foreground")->enabled) { |
363 |
- if (-1 == daemonize_parent_wait()) { |
|
363 |
+ if (-1 == daemonize_parent_wait(user_name, logg_file)) { |
|
364 | 364 |
logg("!daemonize() failed\n"); |
365 | 365 |
localnets_free(); |
366 | 366 |
whitelist_free(); |
... | ... |
@@ -425,6 +433,22 @@ int main(int argc, char **argv) |
425 | 425 |
} |
426 | 426 |
umask(old_umask); |
427 | 427 |
|
428 |
+#ifndef _WIN32 |
|
429 |
+ if (0 == err){ |
|
430 |
+ /*If the file has already been created by a different user, it will just be |
|
431 |
+ * rewritten by us, but not change the ownership, so do that explicitly. |
|
432 |
+ */ |
|
433 |
+ if (0 == geteuid()){ |
|
434 |
+ struct passwd * pw = getpwuid(0); |
|
435 |
+ int ret = lchown(opt->strarg, pw->pw_uid, pw->pw_gid); |
|
436 |
+ if (ret){ |
|
437 |
+ logg("!Can't change ownership of PID file %s '%s'\n", opt->strarg, strerror(errno)); |
|
438 |
+ err = 1; |
|
439 |
+ } |
|
440 |
+ } |
|
441 |
+ } |
|
442 |
+#endif /*_WIN32*/ |
|
443 |
+ |
|
428 | 444 |
if (err){ |
429 | 445 |
localnets_free(); |
430 | 446 |
whitelist_free(); |
... | ... |
@@ -434,42 +458,13 @@ int main(int argc, char **argv) |
434 | 434 |
} |
435 | 435 |
} |
436 | 436 |
|
437 |
- |
|
438 |
- if (geteuid() == 0 && (opt = optget(opts, "User"))->enabled) { |
|
439 |
- struct passwd *user = NULL; |
|
440 |
- if ((user = getpwnam(opt->strarg)) == NULL) { |
|
441 |
- fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg); |
|
442 |
- optfree(opts); |
|
443 |
- return 1; |
|
444 |
- } |
|
445 |
- |
|
446 |
-#ifdef HAVE_INITGROUPS |
|
447 |
- if (initgroups(opt->strarg, user->pw_gid)) { |
|
448 |
- fprintf(stderr, "ERROR: initgroups() failed.\n"); |
|
449 |
- optfree(opts); |
|
450 |
- return 1; |
|
451 |
- } |
|
452 |
-#elif HAVE_SETGROUPS |
|
453 |
- if (setgroups(1, &user->pw_gid)) { |
|
454 |
- fprintf(stderr, "ERROR: setgroups() failed.\n"); |
|
455 |
- optfree(opts); |
|
456 |
- return 1; |
|
457 |
- } |
|
458 |
-#endif |
|
459 |
- if (setgid(user->pw_gid)) { |
|
460 |
- fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int)user->pw_gid); |
|
461 |
- optfree(opts); |
|
462 |
- return 1; |
|
463 |
- } |
|
464 |
- |
|
465 |
- if (setuid(user->pw_uid)) { |
|
466 |
- fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int)user->pw_uid); |
|
467 |
- optfree(opts); |
|
468 |
- return 1; |
|
469 |
- } |
|
437 |
+#ifndef _WIN32 |
|
438 |
+ dropPrivRet = drop_privileges(user_name, logg_file); |
|
439 |
+ if (dropPrivRet){ |
|
440 |
+ optfree(opts); |
|
441 |
+ return dropPrivRet; |
|
470 | 442 |
} |
471 | 443 |
|
472 |
-#ifndef _WIN32 |
|
473 | 444 |
/* We have been daemonized, and initialization is done. Signal |
474 | 445 |
* the parent process so that it can exit cleanly. |
475 | 446 |
*/ |
... | ... |
@@ -126,6 +126,7 @@ int main(int argc, char **argv) |
126 | 126 |
struct passwd *user = NULL; |
127 | 127 |
struct sigaction sa; |
128 | 128 |
struct rlimit rlim; |
129 |
+ int dropPrivRet = 0; |
|
129 | 130 |
#endif |
130 | 131 |
time_t currtime; |
131 | 132 |
const char *dbdir, *cfgfile; |
... | ... |
@@ -144,6 +145,7 @@ int main(int argc, char **argv) |
144 | 144 |
#endif |
145 | 145 |
pid_t mainpid = 0; |
146 | 146 |
mode_t old_umask = 0; |
147 |
+ const char * user_name = NULL; |
|
147 | 148 |
|
148 | 149 |
if (check_flevel()) |
149 | 150 |
exit(1); |
... | ... |
@@ -208,6 +210,10 @@ int main(int argc, char **argv) |
208 | 208 |
} |
209 | 209 |
free(pt); |
210 | 210 |
|
211 |
+ if ((opt = optget(opts, "User"))->enabled){ |
|
212 |
+ user_name = opt->strarg; |
|
213 |
+ } |
|
214 |
+ |
|
211 | 215 |
if (optget(opts, "version")->enabled) { |
212 | 216 |
print_version(optget(opts, "DatabaseDirectory")->strarg); |
213 | 217 |
optfree(opts); |
... | ... |
@@ -267,7 +273,7 @@ int main(int argc, char **argv) |
267 | 267 |
#endif |
268 | 268 |
gengine = engine; |
269 | 269 |
atexit(free_engine); |
270 |
- daemonizeRet = daemonize_parent_wait(); |
|
270 |
+ daemonizeRet = daemonize_parent_wait(user_name, logg_file); |
|
271 | 271 |
if (daemonizeRet < 0){ |
272 | 272 |
logg("!daemonize() failed: %s\n", strerror(errno)); |
273 | 273 |
return 1; |
... | ... |
@@ -306,45 +312,30 @@ int main(int argc, char **argv) |
306 | 306 |
fclose(fd); |
307 | 307 |
} |
308 | 308 |
umask(old_umask); |
309 |
- } |
|
310 | 309 |
|
311 |
- /* drop privileges */ |
|
312 | 310 |
#ifndef _WIN32 |
313 |
- if (geteuid() == 0 && (opt = optget(opts, "User"))->enabled) { |
|
314 |
- if ((user = getpwnam(opt->strarg)) == NULL) { |
|
315 |
- fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg); |
|
316 |
- optfree(opts); |
|
317 |
- return 1; |
|
318 |
- } |
|
319 |
- |
|
320 |
-#ifdef HAVE_INITGROUPS |
|
321 |
- if (initgroups(opt->strarg, user->pw_gid)) { |
|
322 |
- fprintf(stderr, "ERROR: initgroups() failed.\n"); |
|
323 |
- optfree(opts); |
|
324 |
- return 1; |
|
325 |
- } |
|
326 |
-#elif HAVE_SETGROUPS |
|
327 |
- if (setgroups(1, &user->pw_gid)) { |
|
328 |
- fprintf(stderr, "ERROR: setgroups() failed.\n"); |
|
329 |
- optfree(opts); |
|
330 |
- return 1; |
|
331 |
- } |
|
332 |
-#endif |
|
333 |
- |
|
334 |
- if (setgid(user->pw_gid)) { |
|
335 |
- fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int)user->pw_gid); |
|
336 |
- optfree(opts); |
|
337 |
- return 1; |
|
338 |
- } |
|
339 |
- |
|
340 |
- if (setuid(user->pw_uid)) { |
|
341 |
- fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int)user->pw_uid); |
|
342 |
- optfree(opts); |
|
343 |
- return 1; |
|
311 |
+ /*If the file has already been created by a different user, it will just be |
|
312 |
+ * rewritten by us, but not change the ownership, so do that explicitly. |
|
313 |
+ */ |
|
314 |
+ if (0 == geteuid()){ |
|
315 |
+ struct passwd * pw = getpwuid(0); |
|
316 |
+ int ret = lchown(opt->strarg, pw->pw_uid, pw->pw_gid); |
|
317 |
+ if (ret){ |
|
318 |
+ logg("!Can't change ownership of PID file %s '%s'\n", opt->strarg, strerror(errno)); |
|
319 |
+ exit(2); |
|
320 |
+ } |
|
344 | 321 |
} |
322 |
+#endif /* _WIN32 */ |
|
345 | 323 |
} |
346 |
-#endif |
|
347 | 324 |
|
325 |
+ /* drop privileges */ |
|
326 |
+#ifndef _WIN32 |
|
327 |
+ dropPrivRet = drop_privileges(user_name, logg_file); |
|
328 |
+ if (dropPrivRet) { |
|
329 |
+ optfree(opts); |
|
330 |
+ return dropPrivRet; |
|
331 |
+ } |
|
332 |
+#endif /* _WIN32 */ |
|
348 | 333 |
|
349 | 334 |
do { /* logger initialized */ |
350 | 335 |
|
... | ... |
@@ -59,6 +59,9 @@ Example |
59 | 59 |
|
60 | 60 |
# This option allows you to save a process identifier of the listening |
61 | 61 |
# daemon (main thread). |
62 |
+# This file will be owned by root, as long as clamav-milter was started by |
|
63 |
+# root. It is recommended that the directory where this file is stored is |
|
64 |
+# also owned by root to keep other users from tampering with it. |
|
62 | 65 |
# |
63 | 66 |
# Default: disabled |
64 | 67 |
#PidFile /var/run/clamav-milter.pid |
... | ... |
@@ -70,6 +70,9 @@ Example |
70 | 70 |
|
71 | 71 |
# This option allows you to save a process identifier of the listening |
72 | 72 |
# daemon (main thread). |
73 |
+# This file will be owned by root, as long as clamd was started by root. |
|
74 |
+# It is recommended that the directory where this file is stored is |
|
75 |
+# also owned by root to keep other users from tampering with it. |
|
73 | 76 |
# Default: disabled |
74 | 77 |
#PidFile /var/run/clamd.pid |
75 | 78 |
|
... | ... |
@@ -47,6 +47,9 @@ Example |
47 | 47 |
#LogRotate yes |
48 | 48 |
|
49 | 49 |
# This option allows you to save the process identifier of the daemon |
50 |
+# This file will be owned by root, as long as freshclam was started by root. |
|
51 |
+# It is recommended that the directory where this file is stored is |
|
52 |
+# also owned by root to keep other users from tampering with it. |
|
50 | 53 |
# Default: disabled |
51 | 54 |
#PidFile /var/run/freshclam.pid |
52 | 55 |
|
... | ... |
@@ -135,6 +135,21 @@ static int writepid(const char *pidfile) |
135 | 135 |
fclose(fd); |
136 | 136 |
} |
137 | 137 |
umask(old_umask); |
138 |
+ |
|
139 |
+#ifndef _WIN32 |
|
140 |
+ /*If the file has already been created by a different user, it will just be |
|
141 |
+ * rewritten by us, but not change the ownership, so do that explicitly. |
|
142 |
+ */ |
|
143 |
+ if (0 == geteuid()){ |
|
144 |
+ struct passwd * pw = getpwuid(0); |
|
145 |
+ int ret = lchown(pidfile, pw->pw_uid, pw->pw_gid); |
|
146 |
+ if (ret){ |
|
147 |
+ logg("!Can't change ownership of PID file %s '%s'\n", pidfile, strerror(errno)); |
|
148 |
+ return 1; |
|
149 |
+ } |
|
150 |
+ } |
|
151 |
+#endif /*_WIN32 */ |
|
152 |
+ |
|
138 | 153 |
return 0; |
139 | 154 |
} |
140 | 155 |
|
... | ... |
@@ -629,68 +644,6 @@ done: |
629 | 629 |
} |
630 | 630 |
|
631 | 631 |
/** |
632 |
- * @brief Switch users to the DatabaseOwner, if specified. |
|
633 |
- * |
|
634 |
- * @param dbowner A user account that will have write permissions in the database directory. |
|
635 |
- * @return fc_error_t FC_SUCCESS if success. |
|
636 |
- * @return fc_error_t FC_EARG if success. |
|
637 |
- */ |
|
638 |
-static fc_error_t switch_user(const char *dbowner) |
|
639 |
-{ |
|
640 |
- fc_error_t status = FC_EARG; |
|
641 |
- |
|
642 |
-#ifdef HAVE_PWD_H |
|
643 |
- struct passwd *user; |
|
644 |
- |
|
645 |
- if (NULL == dbowner) { |
|
646 |
- logg("*No DatabaseOwner specified. Freshclam will run as the current user.\n"); |
|
647 |
- status = FC_SUCCESS; |
|
648 |
- goto done; |
|
649 |
- } |
|
650 |
- |
|
651 |
- if (!geteuid()) { |
|
652 |
- if ((user = getpwnam(dbowner)) == NULL) { |
|
653 |
- logg("^Can't get information about user %s.\n", dbowner); |
|
654 |
- status = FC_ECONFIG; |
|
655 |
- goto done; |
|
656 |
- } |
|
657 |
- |
|
658 |
-#ifdef HAVE_INITGROUPS |
|
659 |
- if (initgroups(dbowner, user->pw_gid)) { |
|
660 |
- logg("^initgroups() failed.\n"); |
|
661 |
- status = FC_ECONFIG; |
|
662 |
- goto done; |
|
663 |
- } |
|
664 |
-#elif HAVE_SETGROUPS |
|
665 |
- if (setgroups(1, &user->pw_gid)) { |
|
666 |
- logg("^setgroups() failed.\n"); |
|
667 |
- status = FC_ECONFIG; |
|
668 |
- goto done; |
|
669 |
- } |
|
670 |
-#endif |
|
671 |
- |
|
672 |
- if (setgid(user->pw_gid)) { |
|
673 |
- logg("^setgid(%d) failed.\n", (int)user->pw_gid); |
|
674 |
- status = FC_ECONFIG; |
|
675 |
- goto done; |
|
676 |
- } |
|
677 |
- |
|
678 |
- if (setuid(user->pw_uid)) { |
|
679 |
- logg("^setuid(%d) failed.\n", (int)user->pw_uid); |
|
680 |
- status = FC_ECONFIG; |
|
681 |
- goto done; |
|
682 |
- } |
|
683 |
- } |
|
684 |
-#endif /* HAVE_PWD_H */ |
|
685 |
- |
|
686 |
- status = FC_SUCCESS; |
|
687 |
- |
|
688 |
-done: |
|
689 |
- |
|
690 |
- return status; |
|
691 |
-} |
|
692 |
- |
|
693 |
-/** |
|
694 | 632 |
* @brief Get a list of strings for a given repeatable opt argument. |
695 | 633 |
* |
696 | 634 |
* @param opt optstruct of repeatable argument to collect in a list. |
... | ... |
@@ -826,11 +779,12 @@ static fc_error_t initialize(struct optstruct *opts) |
826 | 826 |
/* |
827 | 827 |
* freshclam shouldn't work with root privileges. |
828 | 828 |
* Drop privileges to the DatabaseOwner user, if specified. |
829 |
+ * Pass NULL for the log file name, because it hasn't been created yet. |
|
829 | 830 |
*/ |
830 |
- ret = switch_user(optget(opts, "DatabaseOwner")->strarg); |
|
831 |
- if (FC_SUCCESS != ret) { |
|
831 |
+ ret = drop_privileges(optget(opts, "DatabaseOwner")->strarg, NULL); |
|
832 |
+ if (ret) { |
|
832 | 833 |
logg("!Failed to switch to %s user.\n", optget(opts, "DatabaseOwner")->strarg); |
833 |
- status = ret; |
|
834 |
+ status = FC_ECONFIG; |
|
834 | 835 |
goto done; |
835 | 836 |
} |
836 | 837 |
} |
... | ... |
@@ -1580,6 +1534,11 @@ int main(int argc, char **argv) |
1580 | 1580 |
|
1581 | 1581 |
int bPrune = 1; |
1582 | 1582 |
|
1583 |
+#ifdef HAVE_PWD_H |
|
1584 |
+ const struct optstruct *logFileOpt = NULL; |
|
1585 |
+ const char * logFileName = NULL; |
|
1586 |
+#endif /* HAVE_PWD_H */ |
|
1587 |
+ |
|
1583 | 1588 |
fc_ctx fc_context = {0}; |
1584 | 1589 |
|
1585 | 1590 |
#ifndef _WIN32 |
... | ... |
@@ -1889,7 +1848,7 @@ int main(int argc, char **argv) |
1889 | 1889 |
#ifndef _WIN32 |
1890 | 1890 |
/* fork into background */ |
1891 | 1891 |
if (g_foreground == 0) { |
1892 |
- if (-1 == daemonize_parent_wait()) { |
|
1892 |
+ if (-1 == daemonize_parent_wait(NULL, NULL)) { |
|
1893 | 1893 |
logg("!daemonize() failed\n"); |
1894 | 1894 |
status = FC_EFAILEDUPDATE; |
1895 | 1895 |
goto done; |
... | ... |
@@ -1918,14 +1877,20 @@ int main(int argc, char **argv) |
1918 | 1918 |
#endif |
1919 | 1919 |
|
1920 | 1920 |
#ifdef HAVE_PWD_H |
1921 |
+ /* Get the log file name to pass it into drop_privileges. */ |
|
1922 |
+ logFileOpt = optget(opts, "UpdateLogFile"); |
|
1923 |
+ if (logFileOpt->enabled) { |
|
1924 |
+ logFileName = logFileOpt->strarg; |
|
1925 |
+ } |
|
1926 |
+ |
|
1921 | 1927 |
/* |
1922 | 1928 |
* freshclam shouldn't work with root privileges. |
1923 | 1929 |
* Drop privileges to the DatabaseOwner user, if specified. |
1924 | 1930 |
*/ |
1925 |
- ret = switch_user(optget(opts, "DatabaseOwner")->strarg); |
|
1926 |
- if (FC_SUCCESS != ret) { |
|
1931 |
+ ret = drop_privileges(optget(opts, "DatabaseOwner")->strarg, logFileName); |
|
1932 |
+ if (0 != ret) { |
|
1927 | 1933 |
logg("!Failed to switch to %s user.\n", optget(opts, "DatabaseOwner")->strarg); |
1928 |
- status = ret; |
|
1934 |
+ status = FC_ECONFIG; |
|
1929 | 1935 |
goto done; |
1930 | 1936 |
} |
1931 | 1937 |
#endif /* HAVE_PWD_H */ |
... | ... |
@@ -34,6 +34,9 @@ |
34 | 34 |
#include <sys/stat.h> |
35 | 35 |
#ifndef _WIN32 |
36 | 36 |
#include <sys/socket.h> |
37 |
+#include <pwd.h> |
|
38 |
+#include <grp.h> |
|
39 |
+#include <sys/types.h> |
|
37 | 40 |
#endif |
38 | 41 |
#include <dirent.h> |
39 | 42 |
#include <fcntl.h> |
... | ... |
@@ -325,7 +328,7 @@ static void daemonize_child_initialized_handler(int sig) |
325 | 325 |
exit(0); |
326 | 326 |
} |
327 | 327 |
|
328 |
-int daemonize_parent_wait() |
|
328 |
+int daemonize_parent_wait(const char * const user, const char * const log_file) |
|
329 | 329 |
{ |
330 | 330 |
int daemonizePid = daemonize_all_return(); |
331 | 331 |
if (daemonizePid == -1) { |
... | ... |
@@ -349,6 +352,12 @@ int daemonize_parent_wait() |
349 | 349 |
return -1; |
350 | 350 |
} |
351 | 351 |
|
352 |
+ if (NULL != user){ |
|
353 |
+ if (drop_privileges(user, log_file)){ |
|
354 |
+ return -1; |
|
355 |
+ } |
|
356 |
+ } |
|
357 |
+ |
|
352 | 358 |
int exitStatus; |
353 | 359 |
wait(&exitStatus); |
354 | 360 |
if (WIFEXITED(exitStatus)) { //error |
... | ... |
@@ -364,8 +373,68 @@ void daemonize_signal_parent(pid_t parentPid) |
364 | 364 |
close_std_descriptors(); |
365 | 365 |
kill(parentPid, SIGINT); |
366 | 366 |
} |
367 |
+ |
|
368 |
+int drop_privileges( const char * const user_name, const char * const log_file) { |
|
369 |
+ int ret = 1; |
|
370 |
+ |
|
371 |
+ /*This function is called in a bunch of places, and rather than change the error checking |
|
372 |
+ * in every function, we are just going to return success if there is no work to do. |
|
373 |
+ */ |
|
374 |
+ if ((0 == geteuid()) && (NULL != user_name)){ |
|
375 |
+ struct passwd *user = NULL; |
|
376 |
+ |
|
377 |
+ if ((user = getpwnam(user_name)) == NULL) { |
|
378 |
+ logg("^Can't get information about user %s.\n", user_name); |
|
379 |
+ fprintf(stderr, "ERROR: Can't get information about user %s.\n", user_name); |
|
380 |
+ goto done; |
|
381 |
+ } |
|
382 |
+ |
|
383 |
+#ifdef HAVE_INITGROUPS |
|
384 |
+ if (initgroups(user_name, user->pw_gid)) { |
|
385 |
+ fprintf(stderr, "ERROR: initgroups() failed.\n"); |
|
386 |
+ logg("^initgroups() failed.\n"); |
|
387 |
+ goto done; |
|
388 |
+ } |
|
389 |
+#elif HAVE_SETGROUPS |
|
390 |
+ if (setgroups(1, &user->pw_gid)) { |
|
391 |
+ fprintf(stderr, "ERROR: setgroups() failed.\n"); |
|
392 |
+ logg("^setgroups() failed.\n"); |
|
393 |
+ goto done; |
|
394 |
+ } |
|
367 | 395 |
#endif |
368 | 396 |
|
397 |
+ /*Change ownership of the log file to the user we are going to switch to.*/ |
|
398 |
+ if (NULL != log_file){ |
|
399 |
+ int ret = lchown(log_file, user->pw_uid, user->pw_gid); |
|
400 |
+ if (ret){ |
|
401 |
+ fprintf(stderr, "ERROR: lchown to user '%s' failed on\n", user->pw_name); |
|
402 |
+ fprintf(stderr, "log file '%s'.\n", log_file); |
|
403 |
+ fprintf(stderr, "Error was '%s'\n", strerror(errno)); |
|
404 |
+ logg("^lchown to user '%s' failed on log file '%s'. Error was '%s'\n", |
|
405 |
+ user->pw_name, log_file, strerror(errno)); |
|
406 |
+ goto done; |
|
407 |
+ } |
|
408 |
+ } |
|
409 |
+ |
|
410 |
+ if (setgid(user->pw_gid)) { |
|
411 |
+ fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int)user->pw_gid); |
|
412 |
+ logg("^setgid(%d) failed.\n", (int)user->pw_gid); |
|
413 |
+ goto done; |
|
414 |
+ } |
|
415 |
+ |
|
416 |
+ if (setuid(user->pw_uid)) { |
|
417 |
+ fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int)user->pw_uid); |
|
418 |
+ logg("^setuid(%d) failed.\n", (int)user->pw_uid); |
|
419 |
+ goto done; |
|
420 |
+ } |
|
421 |
+ } |
|
422 |
+ ret = 0; |
|
423 |
+ |
|
424 |
+done: |
|
425 |
+ return ret; |
|
426 |
+} |
|
427 |
+#endif /*_WIN32*/ |
|
428 |
+ |
|
369 | 429 |
int match_regex(const char *filename, const char *pattern) |
370 | 430 |
{ |
371 | 431 |
regex_t reg; |
... | ... |
@@ -26,6 +26,8 @@ |
26 | 26 |
#include <netdb.h> |
27 | 27 |
#include <netinet/in.h> |
28 | 28 |
#endif |
29 |
+#include <stdbool.h> |
|
30 |
+ |
|
29 | 31 |
#include "platform.h" |
30 | 32 |
#include "optparser.h" |
31 | 33 |
/* Maximum filenames under various systems - njh */ |
... | ... |
@@ -77,13 +79,26 @@ int daemonize_all_return(void); |
77 | 77 |
|
78 | 78 |
/*Parent waits for a SIGINT or the child process to exit. If |
79 | 79 |
* it receives a SIGINT, it exits with exit code 0. If the child |
80 |
- * exits (error), it exits with the child process's exit code.*/ |
|
81 |
-int daemonize_parent_wait(); |
|
80 |
+ * exits (error), it exits with the child process's exit code. |
|
81 |
+ * |
|
82 |
+ * @param user If user is supplied and this function is being called |
|
83 |
+ * as root, daemonize_parent_wait will change the parent process |
|
84 |
+ * to user before calling wait so that the child process can signal |
|
85 |
+ * the parent when it is time to exit. The child process will still |
|
86 |
+ * return as root. |
|
87 |
+ * |
|
88 |
+ * @param log_file If user AND log_file are both supplied and this |
|
89 |
+ * function is being called as root, the ownership of log_file will |
|
90 |
+ * be changed to user. |
|
91 |
+ */ |
|
92 |
+int daemonize_parent_wait(const char * const user, const char * const log_file); |
|
82 | 93 |
|
83 | 94 |
/*Sends a SIGINT to the parent process. It also closes stdin, stdout, |
84 | 95 |
* and stderr.*/ |
85 | 96 |
void daemonize_signal_parent(pid_t parentPid); |
86 |
-#endif |
|
97 |
+ |
|
98 |
+int drop_privileges( const char * const user, const char * const log_file); |
|
99 |
+#endif /* _WIN32 */ |
|
87 | 100 |
|
88 | 101 |
const char *get_version(void); |
89 | 102 |
int match_regex(const char *filename, const char *pattern); |