autofs-5.0.3 - don't use proc for is running check
From: Ian Kent <raven@themaw.net>
Using /proc/<pid>/cmdline to check if the daemon is running allows
any user to create a trivial program called "automount" and prevent
the system automounter from running simply by executing it and
leaving it running. This patch makes autofs use a flag file for this
check instead.
---
CHANGELOG | 1
Makefile.conf.in | 3 +
aclocal.m4 | 16 ++++
configure | 35 +++++++++
configure.in | 17 +++++
daemon/Makefile | 5 +
daemon/automount.c | 95 ++++++++------------------
daemon/flag.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 294 insertions(+), 70 deletions(-)
create mode 100644 daemon/flag.c
diff --git a/CHANGELOG b/CHANGELOG
index f40a941..3921552 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,7 @@
- fix incorrect if check in get user info.
- fix couple of memory leaks.
- add command line option to override check for daemon already running.
+- don't use proc file system when checking if the daemon is running.
14/01/2008 autofs-5.0.3
-----------------------
diff --git a/Makefile.conf.in b/Makefile.conf.in
index 09c3129..d88f5ee 100644
--- a/Makefile.conf.in
+++ b/Makefile.conf.in
@@ -74,6 +74,9 @@ autofsmapdir = @mapdir@
# Location for autofs fifos
autofsfifodir = @fifodir@
+# Location for autofs flag file
+autofsflagdir = @flagdir@
+
# Where to install the automount program
sbindir = @sbindir@
diff --git a/aclocal.m4 b/aclocal.m4
index a1105ae..9ef4050 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -136,6 +136,22 @@ AC_DEFUN(AF_FIFO_D,
done
fi])
+dnl --------------------------------------------------------------------------
+dnl AF_FLAG_D
+dnl
+dnl Check the location of the autofs flag file directory
+dnl --------------------------------------------------------------------------
+AC_DEFUN(AF_FLAG_D,
+[if test -z "$flagdir"; then
+ for flag_d in /var/run /tmp; do
+ if test -z "$flagdir"; then
+ if test -d "$flag_d"; then
+ flagdir="$flag_d"
+ fi
+ fi
+ done
+fi])
+
dnl ----------------------------------- ## -*- Autoconf -*-
dnl Check if --with-dmalloc was given. ##
dnl From Franc,ois Pinard ##
diff --git a/configure b/configure
index 0d3268c..9278196 100755
--- a/configure
+++ b/configure
@@ -655,6 +655,7 @@ initdir
confdir
mapdir
fifodir
+flagdir
DMALLOCLIB
MOUNT
HAVE_MOUNT
@@ -1295,6 +1296,7 @@ Optional Packages:
--with-confdir=DIR use DIR for autofs configuration files
--with-mapdir=PATH look in PATH for mount maps used by the automounter
--with-fifodir=PATH use PATH as the directory for fifos used by the automounter
+ --with-flagdir=PATH use PATH as the directory for the flag file used by the automounter
--with-dmalloc use dmalloc, as in
http://www.dmalloc.com/dmalloc.tar.gz
--with-hesiod=DIR enable Hesiod support (libs and includes in DIR)
@@ -1876,6 +1878,36 @@ echo "${ECHO_T}$fifodir" >&6; }
#
+# The user can specify --with-flagdir=PATH to specify where autofs flag file goes
+#
+if test -z "$flagdir"; then
+ for flag_d in /var/run /tmp; do
+ if test -z "$flagdir"; then
+ if test -d "$flag_d"; then
+ flagdir="$flag_d"
+ fi
+ fi
+ done
+fi
+
+# Check whether --with-flagdir was given.
+if test "${with_flagdir+set}" = set; then
+ withval=$with_flagdir; if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no"
+ then
+ :
+ else
+ filagdir="${withval}"
+ fi
+
+fi
+
+{ echo "$as_me:$LINENO: checking for autofs flag file directory" >&5
+echo $ECHO_N "checking for autofs flag file directory... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $flagdir" >&5
+echo "${ECHO_T}$flagdir" >&6; }
+
+
+#
# Optional include dmalloc
#
{ echo "$as_me:$LINENO: checking if malloc debugging is wanted" >&5
@@ -6247,6 +6279,7 @@ initdir!$initdir$ac_delim
confdir!$confdir$ac_delim
mapdir!$mapdir$ac_delim
fifodir!$fifodir$ac_delim
+flagdir!$flagdir$ac_delim
DMALLOCLIB!$DMALLOCLIB$ac_delim
MOUNT!$MOUNT$ac_delim
HAVE_MOUNT!$HAVE_MOUNT$ac_delim
@@ -6297,7 +6330,7 @@ LIBOBJS!$LIBOBJS$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/configure.in b/configure.in
index 27b9bec..5ba3a49 100644
--- a/configure.in
+++ b/configure.in
@@ -96,6 +96,23 @@ AC_MSG_RESULT([$fifodir])
AC_SUBST(fifodir)
#
+# The user can specify --with-flagdir=PATH to specify where autofs flag file goes
+#
+AF_FLAG_D()
+AC_ARG_WITH(flagdir,
+[ --with-flagdir=PATH use PATH as the directory for the flag file used by the automounter],
+ if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no"
+ then
+ :
+ else
+ filagdir="${withval}"
+ fi
+)
+AC_MSG_CHECKING([for autofs flag file directory])
+AC_MSG_RESULT([$flagdir])
+AC_SUBST(flagdir)
+
+#
# Optional include dmalloc
#
AM_WITH_DMALLOC()
diff --git a/daemon/Makefile b/daemon/Makefile
index 528a684..9c2d858 100644
--- a/daemon/Makefile
+++ b/daemon/Makefile
@@ -6,9 +6,9 @@
include ../Makefile.rules
SRCS = automount.c indirect.c direct.c spawn.c module.c mount.c \
- lookup.c state.c
+ lookup.c state.c flag.c
OBJS = automount.o indirect.o direct.o spawn.o module.o mount.o \
- lookup.o state.o
+ lookup.o state.o flag.o
version := $(shell cat ../.version)
@@ -17,6 +17,7 @@ CFLAGS += -DAUTOFS_LIB_DIR=\"$(autofslibdir)\"
CFLAGS += -DAUTOFS_MAP_DIR=\"$(autofsmapdir)\"
CFLAGS += -DAUTOFS_CONF_DIR=\"$(autofsconfdir)\"
CFLAGS += -DAUTOFS_FIFO_DIR=\"$(autofsfifodir)\"
+CFLAGS += -DAUTOFS_FLAG_DIR=\"$(autofsflagdir)\"
CFLAGS += -DVERSION_STRING=\"$(version)\"
LDFLAGS += -rdynamic
LIBS = -ldl
diff --git a/daemon/automount.c b/daemon/automount.c
index 48ac30a..dbf267c 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -81,6 +81,8 @@ pthread_key_t key_thread_stdenv_vars;
#define MAX_OPEN_FILES 10240
+int aquire_flag_file(void);
+void release_flag_file(void);
static int umount_all(struct autofs_point *ap, int force);
extern pthread_mutex_t master_mutex;
@@ -1098,7 +1100,7 @@ static int handle_packet(struct autofs_point *ap)
return -1;
}
-static void become_daemon(unsigned foreground)
+static void become_daemon(unsigned foreground, unsigned daemon_check)
{
FILE *pidfp;
char buf[MAX_ERR_BUF];
@@ -1118,9 +1120,14 @@ static void become_daemon(unsigned foreground)
}
/* Detach from foreground process */
- if (foreground)
+ if (foreground) {
+ if (daemon_check && !aquire_flag_file()) {
+ fprintf(stderr, "%s: program is already running.\n",
+ program);
+ exit(1);
+ }
log_to_stderr();
- else {
+ } else {
pid = fork();
if (pid > 0) {
int r;
@@ -1136,6 +1143,13 @@ static void become_daemon(unsigned foreground)
}
close(start_pipefd[0]);
+ if (daemon_check && !aquire_flag_file()) {
+ fprintf(stderr, "%s: program is already running.\n",
+ program);
+ close(start_pipefd[1]);
+ exit(1);
+ }
+
/*
* Make our own process group for "magic" reason: processes that share
* our pgrp see the raw filesystem behind the magic.
@@ -1143,6 +1157,7 @@ static void become_daemon(unsigned foreground)
if (setsid() == -1) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
fprintf(stderr, "setsid: %s", estr);
+ close(start_pipefd[1]);
exit(1);
}
log_to_syslog();
@@ -1617,64 +1632,6 @@ static void key_thread_stdenv_vars_destroy(void *arg)
return;
}
-static int is_automount_running(void)
-{
- FILE *fp;
- DIR *dir;
- struct dirent entry;
- struct dirent *result;
- char path[PATH_MAX + 1], buf[PATH_MAX];
-
- if ((dir = opendir("/proc")) == NULL) {
- fprintf(stderr, "cannot opendir(/proc)\n");
- exit(1);
- }
-
- while (readdir_r(dir, &entry, &result) == 0) {
- int path_len, pid = 0;
-
- if (!result)
- break;
-
- if (*entry.d_name == '.')
- continue;
-
- if (!strcmp(entry.d_name, "self"))
- continue;
-
- if (!isdigit(*entry.d_name))
- continue;
-
- pid = atoi(entry.d_name);
- if (pid == getpid())
- continue;
-
- path_len = sprintf(path, "/proc/%s/cmdline", entry.d_name);
- if (path_len >= PATH_MAX) {
- fprintf(stderr,
- "buffer to small for /proc path\n");
- return -1;
- }
- path[path_len] = '\0';
-
- fp = fopen(path, "r");
- if (fp) {
- int c, len = 0;
-
- while (len < 127 && (c = fgetc(fp)) != EOF && c)
- buf[len++] = c;
- buf[len] = '\0';
-
- if (strstr(buf, "automount"))
- return pid;
- fclose(fp);
- }
- }
- closedir(dir);
-
- return 0;
-}
-
static void usage(void)
{
fprintf(stderr,
@@ -1973,11 +1930,6 @@ int main(int argc, char *argv[])
exit(exit_code);
}
- if (daemon_check && is_automount_running() > 0) {
- fprintf(stderr, "%s: program is already running.\n",
- program);
- exit(1);
- }
#if 0
if (!load_autofs4_module()) {
fprintf(stderr, "%s: can't load %s filesystem module.\n",
@@ -2009,7 +1961,7 @@ int main(int argc, char *argv[])
"can't increase core file limit - continuing");
#endif
- become_daemon(foreground);
+ become_daemon(foreground, daemon_check);
if (argc == 0)
master_list = master_new(NULL, timeout, ghost);
@@ -2020,6 +1972,7 @@ int main(int argc, char *argv[])
logerr("%s: can't create master map %s",
program, argv[0]);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
@@ -2027,6 +1980,7 @@ int main(int argc, char *argv[])
logerr("%s: failed to init thread attribute struct!",
program);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
@@ -2035,6 +1989,7 @@ int main(int argc, char *argv[])
logerr("%s: failed to set detached thread attribute!",
program);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
@@ -2044,6 +1999,7 @@ int main(int argc, char *argv[])
logerr("%s: failed to set stack size thread attribute!",
program);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
#endif
@@ -2060,6 +2016,7 @@ int main(int argc, char *argv[])
program);
master_kill(master_list);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
@@ -2067,6 +2024,7 @@ int main(int argc, char *argv[])
logerr("%s: failed to create alarm handler thread!", program);
master_kill(master_list);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
@@ -2074,6 +2032,7 @@ int main(int argc, char *argv[])
logerr("%s: failed to create FSM handler thread!", program);
master_kill(master_list);
close(start_pipefd[1]);
+ release_flag_file();
exit(1);
}
@@ -2086,6 +2045,7 @@ int main(int argc, char *argv[])
*pst_stat = 3;
res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
close(start_pipefd[1]);
+ release_flag_file();
exit(3);
}
@@ -2102,6 +2062,7 @@ int main(int argc, char *argv[])
pid_file = NULL;
}
closelog();
+ release_flag_file();
#ifdef LIBXML2_WORKAROUND
if (dh)
diff --git a/daemon/flag.c b/daemon/flag.c
new file mode 100644
index 0000000..d8ca61b
--- /dev/null
+++ b/daemon/flag.c
@@ -0,0 +1,192 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * flag.c - autofs flag file management
+ *
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <alloca.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+#define MAX_PIDSIZE 20
+#define FLAG_FILE AUTOFS_FLAG_DIR "/autofs-running"
+
+/* Flag for already existing flag file. */
+static int we_created_flagfile = 0;
+
+/* file descriptor of flag file */
+static int fd = -1;
+
+static int flag_is_owned(int fd)
+{
+ int pid = 0, tries = 3;
+
+ while (tries--) {
+ char pidbuf[MAX_PIDSIZE + 1];
+ int got;
+
+ lseek(fd, 0, SEEK_SET);
+ got = read(fd, pidbuf, MAX_PIDSIZE);
+ /*
+ * We add a terminator to the pid to verify write complete.
+ * If the write isn't finished in 300 milliseconds then it's
+ * probably a stale lock file.
+ */
+ if (got > 0 && pidbuf[got - 1] == '\n') {
+ sscanf(pidbuf, "%d", &pid);
+ break;
+ } else {
+ struct timespec t = { 0, 100000000 };
+ struct timespec r;
+
+ while (nanosleep(&t, &r) == -1 && errno == EINTR)
+ memcpy(&t, &r, sizeof(struct timespec));
+
+ continue;
+ }
+
+ /* Stale flagfile */
+ if (!tries)
+ return 0;
+ }
+
+
+ if (pid) {
+ int ret;
+
+ ret = kill(pid, 0);
+ /*
+ * If lock file exists but is not owned by a process
+ * we return unowned status so we can get rid of it
+ * and continue.
+ */
+ if (ret == -1 && errno == ESRCH)
+ return 0;
+ } else {
+ /*
+ * Odd, no pid in file - so what should we do?
+ * Assume something bad happened to owner and
+ * return unowned status.
+ */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Remove flag file. */
+void release_flag_file(void)
+{
+ if (fd > 0) {
+ close(fd);
+ fd = -1;
+ }
+
+ if (we_created_flagfile) {
+ unlink(FLAG_FILE);
+ we_created_flagfile = 0;
+ }
+}
+
+/* * Try to create flag file */
+int aquire_flag_file(void)
+{
+ char *linkf;
+ int len;
+
+ len = strlen(FLAG_FILE) + MAX_PIDSIZE;
+ linkf = alloca(len + 1);
+ snprintf(linkf, len, "%s.%d", FLAG_FILE, getpid());
+
+ /*
+ * Repeat until it was us who made the link or we find the
+ * flag file already exists. If an unexpected error occurs
+ * we return 0 claiming the flag file exists which may not
+ * really be the case.
+ */
+ while (!we_created_flagfile) {
+ int errsv, i, j;
+
+ i = open(linkf, O_WRONLY|O_CREAT, 0);
+ if (i < 0) {
+ release_flag_file();
+ return 0;
+ }
+ close(i);
+
+ j = link(linkf, FLAG_FILE);
+ errsv = errno;
+
+ (void) unlink(linkf);
+
+ if (j < 0 && errsv != EEXIST) {
+ release_flag_file();
+ return 0;
+ }
+
+ fd = open(FLAG_FILE, O_RDWR);
+ if (fd < 0) {
+ /* Maybe the file was just deleted? */
+ if (errno == ENOENT)
+ continue;
+ release_flag_file();
+ return 0;
+ }
+
+ if (j == 0) {
+ char pidbuf[MAX_PIDSIZE + 1];
+ int pidlen;
+
+ pidlen = sprintf(pidbuf, "%d\n", getpid());
+ if (write(fd, pidbuf, pidlen) != pidlen) {
+ release_flag_file();
+ return 0;
+ }
+
+ we_created_flagfile = 1;
+ } else {
+ /*
+ * Someone else made the link.
+ * If the flag file is not owned by anyone clean
+ * it up and try again, otherwise return fail.
+ */
+ if (!flag_is_owned(fd)) {
+ close(fd);
+ fd = -1;
+ unlink(FLAG_FILE);
+ continue;
+ }
+
+ release_flag_file();
+ return 0;
+ }
+
+ close(fd);
+ fd = -1;
+ }
+
+ return 1;
+}
+