static void add_signal_handlers(void) { struct sigaction sa; (void) sigemptyset(&sigmask); (void) sigaddset(&sigmask, SIGHUP); (void) sigaddset(&sigmask, SIGCHLD); (void) sigaddset(&sigmask, SIGINT); (void) sigprocmask(SIG_BLOCK, &sigmask, NULL); sa.sa_mask = sigmask; sa.sa_flags = 0; /* Signals to handle */ sa.sa_handler = handle_hup; if (sigaction(SIGHUP, &sa, NULL) < 0) early_error("sigaction HUP"); sa.sa_handler = handle_int; if (sigaction(SIGINT, &sa, NULL) < 0) early_error("sigaction INT"); /* * Signals to ignore. Ignoring SIGCHLD in this way makes the * children exit without ever creating zombies. (No wait(2) * call required.) */ sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) early_error("sigaction PIPE"); sa.sa_flags = SA_NOCLDWAIT; if (sigaction(SIGCHLD, &sa, NULL) < 0) early_error("sigaction CHLD"); }
/* * Open the sppptun driver. */ static void open_tunnel_dev(void) { struct ppptun_peer ptp; tunfd = open(tunnam, O_RDWR); if (tunfd == -1) { early_error(tunnam); } /* * Tell the device driver that I'm a daemon handling inbound * connections, not a PPP session. */ (void) memset(&ptp, '\0', sizeof (ptp)); ptp.ptp_style = PTS_PPPOE; ptp.ptp_flags = PTPF_DAEMON; (void) memcpy(ptp.ptp_address.pta_pppoe.ptma_mac, ether_bcast, sizeof (ptp.ptp_address.pta_pppoe.ptma_mac)); if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 0) { myperror("PPPTUN_SPEER"); exit(1); } }
/* * Try to obtain the CAP_IPC_LOCK Linux capability. * Then, whether or not this is successful, drop root * privileges to run as the invoking user. The application is aborted * if for any reason we are unable to drop privileges. Note: even gettext * is unavailable! */ void gkd_capability_obtain_capability_and_drop_privileges (void) { #ifdef HAVE_LIBCAP cap_t caps; cap_value_t cap_list[1]; caps = cap_get_proc (); if (caps == NULL) { early_error ("capability state cannot be allocated"); goto drop; } cap_list[0] = CAP_IPC_LOCK; if (cap_set_flag (caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) { early_error ("error when manipulating capability sets"); goto drop; } if (cap_set_proc (caps) == -1) { /* Only warn when it's root that's running */ if (getuid () == 0) early_error ("cannot apply capabilities to process"); goto drop; } if (cap_free (caps) == -1) { early_error ("failed to free capability structure"); goto drop; } drop: #endif /* Now finally drop the suid by becoming the invoking user */ if (geteuid () != getuid() || getegid () != getgid ()) drop_privileges (); }
/* * Become a daemon. */ static void daemonize(void) { pid_t cpid; /* * A little bit of magic here. By the first fork+setsid, we * disconnect from our current controlling terminal and become * a session group leader. By forking again without setsid, * we make certain that we're not the session group leader and * can never reacquire a controlling terminal. */ if ((cpid = fork()) == (pid_t)-1) { early_error("fork 1"); } if (cpid != 0) { (void) wait(NULL); _exit(0); } if (setsid() == (pid_t)-1) { early_error("setsid"); } if ((cpid = fork()) == (pid_t)-1) { early_error("fork 2"); } if (cpid != 0) { /* Parent just exits */ (void) printf("%d\n", (int)cpid); (void) fflush(stdout); _exit(0); } (void) chdir("/"); (void) umask(0); (void) fdwalk(fdcloser, NULL); reopen_log(); }
static void drop_privileges (void) { uid_t orig_uid; gid_t orig_gid; orig_uid = getuid (); orig_gid = getgid (); /* This is permanent, you cannot go back to root */ setgid (orig_gid); setuid (orig_uid); /* * Check that the switch was ok * We do not allow programs to run without the drop being * successful as this would possibly run the program * using root-privs, when that is not what we want */ if ((getegid () != orig_gid) || (geteuid () != orig_uid)) { early_error ("failed to drop privileges, aborting"); exit (1); } }