#ifdef WITH_SELINUX
# include <selinux/selinux.h>
-# include <sys/mount.h>
#endif
#ifdef __i386__
# endif
#endif
-#ifdef USE_PAM
-# include <security/pam_appl.h>
-# include <security/pam_misc.h>
-#endif
-
#include "init.h"
#include "initreq.h"
#include "paths.h"
/* Set a signal handler. */
#define SETSIG(sa, sig, fun, flags) \
do { \
+ memset(&sa, 0, sizeof(sa)); \
sa.sa_handler = fun; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
}
static
-char *istrdup(char *s)
+char *istrdup(const char *s)
{
char *m;
int l;
tty.c_cc[VEOF] = CEOF;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
+#ifdef VSWTC /* not defined on FreeBSD */
tty.c_cc[VSWTC] = _POSIX_VDISABLE;
+#endif /* VSWTC */
tty.c_cc[VSTART] = CSTART;
tty.c_cc[VSTOP] = CSTOP;
tty.c_cc[VSUSP] = CSUSP;
/*
* Set pre and post processing
*/
- tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
-#ifdef IUTF8 /* Not defined on FreeBSD */
- tty.c_iflag |= IUTF8;
+ tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY
+#ifdef IUTF8 /* Not defined on FreeBSD */
+ | (tty.c_iflag & IUTF8)
#endif /* IUTF8 */
+ ;
tty.c_oflag = OPOST|ONLCR;
tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
(void) close(fd);
}
+static ssize_t
+safe_write(int fd, const char *buffer, size_t count)
+{
+ ssize_t offset = 0;
+
+ while (count > 0) {
+ ssize_t block = write(fd, &buffer[offset], count);
+
+ if (block < 0 && errno == EINTR)
+ continue;
+ if (block <= 0)
+ return offset ? offset : block;
+ offset += block;
+ count -= block;
+ }
+ return offset;
+}
+
/*
* Print to the system console
*/
int fd;
if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
- write(fd, s, strlen(s));
+ safe_write(fd, s, strlen(s));
close(fd);
}
}
}
}
-
-#ifdef USE_PAM
-static pam_handle_t *pamh = NULL;
-# ifdef __GNUC__
-static int
-init_conv(int num_msg, const struct pam_message **msgm,
- struct pam_response **response __attribute__((unused)),
- void *appdata_ptr __attribute__((unused)))
-# else
-static int
-init_conv(int num_msg, const struct pam_message **msgm,
- struct pam_response **response, void *appdata_ptr)
-# endif
+/*
+ * Add or replace specific environment value
+ */
+int addnewenv(const char *new, char **curr, int n)
{
+ size_t nlen = strcspn(new, "=");
int i;
- for (i = 0; i < num_msg; i++) {
- const struct pam_message *msg = msgm[i];
- if (msg == (const struct pam_message*)0)
- continue;
- if (msg->msg == (char*)0)
+ for (i = 0; i < n; i++) {
+ if (nlen != strcspn(curr[i], "="))
continue;
- switch (msg->msg_style) {
- case PAM_ERROR_MSG:
- case PAM_TEXT_INFO:
- initlog(L_VB, "pam_message %s", msg->msg);
- default:
+ if (strncmp (new, curr[i], nlen) == 0)
break;
- }
}
- return 0;
-}
-static const struct pam_conv conv = { init_conv, NULL };
-# define PAM_FAIL_CHECK(func, args...) \
- { \
- if ((pam_ret = (func)(args)) != PAM_SUCCESS) { \
- initlog(L_VB, "%s", pam_strerror(pamh, pam_ret)); \
- goto pam_error; \
- } \
+ if (i >= n)
+ curr[n++] = istrdup(new);
+ else {
+ free(curr[i]);
+ curr[i] = istrdup(new);
}
-#endif /* USE_PAM */
-
+ return n;
+}
/*
* Build a new environment for execve().
{
char i_lvl[] = "RUNLEVEL=x";
char i_prev[] = "PREVLEVEL=x";
- char i_cons[32];
+ char i_cons[128];
char i_shell[] = "SHELL=" SHELL;
char **e;
-#ifdef USE_PAM
- char **pamenv = (char**)0;
-#endif
int n, i;
for (n = 0; environ[n]; n++)
;
- n += NR_EXTRA_ENV;
- if (child) {
-#ifdef USE_PAM
- pamenv = pam_getenvlist(pamh);
- for (i = 0; pamenv[i]; i++)
- ;
- n += i;
-#endif
+ n += NR_EXTRA_ENV + 1; /* Also room for last NULL */
+ if (child)
n += 8;
+
+ while ((e = (char**)calloc(n, sizeof(char *))) == NULL) {
+ initlog(L_VB, "out of memory");
+ do_sleep(5);
}
- e = calloc(n, sizeof(char *));
for (n = 0; environ[n]; n++)
e[n] = istrdup(environ[n]);
for (i = 0; i < NR_EXTRA_ENV; i++) {
- if (extra_env[i])
- e[n++] = istrdup(extra_env[i]);
+ if (extra_env[i] == NULL || *extra_env[i] == '\0')
+ continue;
+ n = addnewenv(extra_env[i], e, n);
}
if (child) {
-#ifdef USE_PAM
- for (i = 0; pamenv[i]; i++)
- e[n++] = istrdup(pamenv[i]);
-#endif
snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
i_lvl[9] = thislevel;
i_prev[10] = prevlevel;
- e[n++] = istrdup(i_shell);
- e[n++] = istrdup(i_lvl);
- e[n++] = istrdup(i_prev);
- e[n++] = istrdup(i_cons);
- e[n++] = istrdup(E_VERSION);
+ n = addnewenv(i_shell, e, n);
+ n = addnewenv(i_lvl, e, n);
+ n = addnewenv(i_prev, e, n);
+ n = addnewenv(i_cons, e, n);
+ n = addnewenv(E_VERSION, e, n);
}
e[n++] = NULL;
sigprocmask(SIG_BLOCK, &nmask, &omask);
if ((pid = fork()) == 0) {
-#ifdef USE_PAM
- int pam_ret;
-#endif
+
close(0);
close(1);
close(2);
dup(f);
}
-#ifdef USE_PAM
- PAM_FAIL_CHECK(pam_start, "init", "root" , &conv, &pamh);
- PAM_FAIL_CHECK(pam_set_item, pamh, PAM_TTY, console_dev);
- PAM_FAIL_CHECK(pam_acct_mgmt, pamh, PAM_SILENT);
- PAM_FAIL_CHECK(pam_open_session, pamh, PAM_SILENT);
- PAM_FAIL_CHECK(pam_setcred, pamh, PAM_ESTABLISH_CRED|PAM_SILENT);
-#endif
/*
* Update utmp/wtmp file prior to starting
* any child. This MUST be done right here in
if (ch->process[0] != '+')
write_utmp_wtmp("", ch->id, getpid(), DEAD_PROCESS, NULL);
-#ifdef USE_PAM
- (void)pam_setcred(pamh, PAM_DELETE_CRED|PAM_SILENT);
- pam_ret = pam_close_session(pamh, PAM_SILENT);
- pam_error:
- pam_end(pamh, pam_ret);
-#endif
exit(1);
}
*res = pid;
#endif
/*
- * Open INITTAB and real line by line.
+ * Open INITTAB and read line by line.
*/
if ((fp = fopen(INITTAB, "r")) == NULL)
initlog(L_VB, "No inittab file found");
case 0: /* Send TERM signal */
if (talk)
initlog(L_CO,
- "Sending processes the TERM signal");
+ "Sending processes configured via /etc/inittab the TERM signal");
kill(-(ch->pid), SIGTERM);
foundOne = 1;
break;
case 1: /* Send KILL signal and collect status */
if (talk)
initlog(L_CO,
- "Sending processes the KILL signal");
+ "Sending processes configured via /etc/inittab the KILL signal");
kill(-(ch->pid), SIGKILL);
break;
}
if (fd < 0) return('S');
while(!strchr("0123456789S", lvl)) {
- write(fd, prompt, sizeof(prompt) - 1);
- buf[0] = 0;
- read(fd, buf, sizeof(buf));
+ safe_write(fd, prompt, sizeof(prompt) - 1);
+ if (read(fd, buf, sizeof(buf)) <= 0)
+ buf[0] = 0;
if (buf[0] != 0 && (buf[1] == '\r' || buf[1] == '\n'))
lvl = buf[0];
if (islower(lvl)) lvl = toupper(lvl);
{
int fds[2];
- pipe(fds);
+ if (pipe(fds)) {
+ initlog(L_VB, "pipe: %m");
+ return -1;
+ }
dup2(fds[0], fd);
close(fds[0]);
fcntl(fds[1], F_SETFD, 1);
fcntl(fd, F_SETFD, 0);
- write(fds[1], Signature, 8);
+ safe_write(fds[1], Signature, 8);
return fds[1];
}
/*
* construct a pipe fd --> STATE_PIPE and write a signature
*/
- fd = make_pipe(STATE_PIPE);
+ if ((fd = make_pipe(STATE_PIPE)) < 0) {
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ initlog(L_CO, "Attempt to re-exec failed");
+ }
/*
* It's a backup day today, so I'm pissed off. Being a BOFH, however,
* We shouldn't be here, something failed.
* Bitch, close the state pipe, unblock signals and return.
*/
+ init_freeenv(env);
close(fd);
close(STATE_PIPE);
sigprocmask(SIG_SETMASK, &oldset, NULL);
- init_freeenv(env);
initlog(L_CO, "Attempt to re-exec failed");
}
static
void initcmd_setenv(char *data, int size)
{
- char *env, *p, *e, *eq;
- int i, sz;
+ char *env, *p, *e;
+ size_t sz;
+ int i, eq;
e = data + size;
while (*data && data < e) {
- eq = NULL;
for (p = data; *p && p < e; p++)
- if (*p == '=') eq = p;
+ ;
if (*p) break;
env = data;
data = ++p;
- sz = eq ? (eq - env) : (p - env);
-
- /*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/
-
/*
* We only allow INIT_* to be set.
*/
if (strncmp(env, "INIT_", 5) != 0)
continue;
+ sz = strcspn(env, "=");
+ eq = (env[sz] == '=');
+
+ /*initlog(L_SY, "init_setenv: %s, %d, %d", env, eq, sz);*/
+
/* Free existing vars. */
for (i = 0; i < NR_EXTRA_ENV; i++) {
- if (extra_env[i] == NULL) continue;
- if (!strncmp(extra_env[i], env, sz) &&
- extra_env[i][sz] == '=') {
+ if (extra_env[i] == NULL)
+ continue;
+ if (sz != strcspn(extra_env[i], "="))
+ continue;
+ if (strncmp(extra_env[i], env, sz) == 0) {
free(extra_env[i]);
extra_env[i] = NULL;
}
}
+ if (eq == 0)
+ continue;
+
/* Set new vars if needed. */
- if (eq == NULL) continue;
for (i = 0; i < NR_EXTRA_ENV; i++) {
if (extra_env[i] == NULL) {
extra_env[i] = istrdup(env);
/* See _what_ kind of SIGPWR this is. */
pwrstat = 0;
if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {
- c = 0;
- read(fd, &c, 1);
+ if (read(fd, &c, 1) != 1)
+ c = 0;
pwrstat = c;
close(fd);
unlink(PWRSTAT);
- }
+ } else if ((fd = open(PWRSTAT_OLD, O_RDONLY)) >= 0) {
+ /* Path changed 2010-03-20. Look for the old path for a while. */
+ initlog(L_VB, "warning: found obsolete path %s, use %s instead",
+ PWRSTAT_OLD, PWRSTAT);
+ if (read(fd, &c, 1) != 1)
+ c = 0;
+ pwrstat = c;
+ close(fd);
+ unlink(PWRSTAT_OLD);
+ }
do_power_fail(pwrstat);
DELSET(got_signals, SIGPWR);
}
while((rc = wait(&st)) != f)
if (rc < 0 && errno == ECHILD)
break;
- write(1, killmsg, sizeof(killmsg) - 1);
+ safe_write(1, killmsg, sizeof(killmsg) - 1);
while(1) pause();
}
#endif
p = argv[0];
/* Common umask */
- umask(022);
+ umask(umask(077) | 022);
/* Quick check */
if (geteuid() != 0) {
#ifdef WITH_SELINUX
if (getenv("SELINUX_INIT") == NULL) {
- const int rc = mount("proc", "/proc", "proc", 0, 0);
- if (is_selinux_enabled() > 0) {
- putenv("SELINUX_INIT=YES");
- if (rc == 0) umount2("/proc", MNT_DETACH);
+ if (is_selinux_enabled() != 1) {
if (selinux_init_load_policy(&enforce) == 0) {
+ putenv("SELINUX_INIT=YES");
execv(myname, argv);
} else {
if (enforce > 0) {
}
}
}
- if (rc == 0) umount2("/proc", MNT_DETACH);
}
#endif
/* Start booting. */