[pkg-fso-commits] [SCM] Automatic Display Manager branch, pamhelper, updated. debian/0.1-38-g8ab57e9
Enrico Zini
enrico at enricozini.org
Fri Feb 20 17:48:48 UTC 2009
The following commit has been merged in the pamhelper branch:
commit 8ab57e98e3b2763708af1ac3a96f1cb5ee5d57d8
Author: Enrico Zini <enrico at enricozini.org>
Date: Fri Feb 20 17:48:11 2009 +0000
Complete redesign
- Back to NODM_XINIT, NODM_XSESSION, NODM_X_OPTIONS.
- Virtually split nodm in two: one that starts, monitors and restarts
xinit, one that runs the X session and does the pam / login work
This allows to start X as root (otherwise it will refuse to start) and
then run the proper session inside X.
diff --git a/Makefile b/Makefile
index e25eb4c..f85232b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,10 @@
+all: nodm nodm-session
+
nodm: nodm.c
gcc -o $@ $< -lpam -lpam_misc -Wall
+nodm-session: nodm
+ ln -fs nodm nodm-session
+
clean:
rm -f nodm
diff --git a/debian/nodm.config b/debian/nodm.config
index 999560a..cb746a8 100644
--- a/debian/nodm.config
+++ b/debian/nodm.config
@@ -13,12 +13,18 @@ if [ -s /etc/default/nodm ] ; then
if [ -n "$NODM_USER" ] ; then
db_set nodm/user "$NODM_USER"
fi
- if [ -n "$NODM_COMMAND" ] ; then
- db_set nodm/command "$NODM_COMMAND"
+ if [ -n "$NODM_X_OPTIONS" ] ; then
+ db_set nodm/x_options "$NODM_X_OPTIONS"
fi
if [ -n "$NODM_MIN_SESSION_TIME" ]; then
db_set nodm/min_session_time "$NODM_MIN_SESSION_TIME"
fi
+ if [ -n "$NODM_XINIT" ]; then
+ db_set nodm/xinit "$NODM_XINIT"
+ fi
+ if [ -n "$NODM_XSESSION" ]; then
+ db_set nodm/xsession "$NODM_XSESSION"
+ fi
fi
db_input medium nodm/enabled || true
@@ -31,10 +37,16 @@ if [ "x$START" = "xtrue" ] ; then
db_input medium nodm/user || true
db_go
- db_input low nodm/command || true
+ db_input low nodm/x_options || true
db_go
db_input low nodm/min_session_time || true
db_go
+
+ db_input low nodm/xinit || true
+ db_go
+
+ db_input low nodm/xsession || true
+ db_go
fi
diff --git a/debian/nodm.init b/debian/nodm.init
index 2d53d21..d1f928c 100644
--- a/debian/nodm.init
+++ b/debian/nodm.init
@@ -19,8 +19,10 @@ PIDDIR=/var/run/
PIDFILE=${PIDDIR}/${NAME}.pid
NODM_ENABLED=no
+NODM_XINIT=/usr/bin/xinit
+NODM_XSESSION=/etc/X11/Xsession
+NODM_X_OPTIONS="vt7 -nolisten tcp"
NODM_USER=root
-NODM_COMMAND='/usr/bin/xinit /etc/X11/Xsession -- vt7 -nolisten tcp'
NODM_MIN_SESSION_TIME=60
if [ -f /etc/default/$NAME ]
@@ -28,13 +30,14 @@ then
. /etc/default/$NAME
fi
-export NODM_USER NODM_COMMAND NODM_MIN_SESSION_TIME
+export NODM_XINIT NODM_XSESSION NODM_X_OPTIONS NODM_USER NODM_MIN_SESSION_TIME
# If you change the user to a non-root user, make sure you
# set allowed_users=anybody in /etc/X11/Xwrapper.config
# Gracefully exit if the package or its dependencies have been removed (but not purged).
-[ -x /usr/sbin/nodm ] || exit 0
+[ -x /usr/sbin/nodm -a -x "$NODM_XSESSION" -a -x "$NODM_XINIT" ] || exit 0
+
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
diff --git a/debian/nodm.install b/debian/nodm.install
index 2cdcc73..cd8d39b 100644
--- a/debian/nodm.install
+++ b/debian/nodm.install
@@ -1 +1,2 @@
nodm /usr/sbin/
+nodm-session /usr/sbin/
diff --git a/debian/nodm.postinst b/debian/nodm.postinst
index cee468b..88e4c30 100644
--- a/debian/nodm.postinst
+++ b/debian/nodm.postinst
@@ -11,16 +11,22 @@ if [ "$1" = "configure" ] ; then
NODM_ENABLED="$RET"
db_get nodm/user
NODM_USER="$RET"
- db_get nodm/command
- NODM_COMMAND="$RET"
+ db_get nodm/x_options
+ NODM_X_OPTIONS="$RET"
db_get nodm/min_session_time
NODM_MIN_SESSION_TIME="$RET"
+ db_get nodm/xinit
+ NODM_XINIT="$RET"
+ db_get nodm/xsession
+ NODM_XSESSION="$RET"
if [ -s /etc/default/nodm ] ; then
sed -i -r -e "s,^NODM_ENABLED=.*,NODM_ENABLED=$NODM_ENABLED," \
-e "s,^NODM_USER=.*,NODM_USER=$NODM_USER," \
- -e "s,^NODM_COMMAND=.*,NODM_COMMAND='$NODM_COMMAND'," \
+ -e "s,^NODM_X_OPTIONS=.*,NODM_X_OPTIONS='$NODM_X_OPTIONS'," \
-e "s,^NODM_MIN_SESSION_TIME=.*,NODM_MIN_SESSION_TIME=$NODM_MIN_SESSION_TIME," \
+ -e "s,^NODM_XINIT=.*,NODM_XINIT=$NODM_XINIT," \
+ -e "s,^NODM_XSESSION=.*,NODM_XSESSION=$NODM_XSESSION," \
/etc/default/nodm
else
cat <<EOF > /etc/default/nodm
@@ -33,7 +39,13 @@ NODM_ENABLED=$NODM_ENABLED
NODM_USER=$NODM_USER
# xinit program
-NODM_COMMAND='$NODM_COMMAND'
+NODM_XINIT=$NODM_XINIT
+
+# X session
+NODM_XSESSION=$NODM_XSESSION
+
+# Options for the X server
+NODM_X_OPTIONS='$NODM_X_OPTIONS'
# If an X session will run for less than this time in seconds, nodm will wait an
# increasing bit of time before restarting the session.
diff --git a/debian/nodm.templates b/debian/nodm.templates
index cb94d58..68a0f10 100644
--- a/debian/nodm.templates
+++ b/debian/nodm.templates
@@ -15,14 +15,11 @@ _Description: User to start a session for:
nodm starts an X session for a user without asking for authentication. What
user should be used for the session?
-Template: nodm/command
+Template: nodm/x_options
Type: string
-Default: /usr/bin/xinit /etc/X11/Xsession -- vt7 -nolisten tcp
-_Description: Command to use to run the X session
- This command is passed to the shell to start the X session.
- .
- Please do not use single quotes, as they are used as delimiters in
- /etc/default/nodm
+Default: vt7 -nolisten tcp
+_Description: Options for the X server:
+ Options to pass to the X server when starting the session.
Template: nodm/min_session_time
Type: string
@@ -31,3 +28,22 @@ _Description: Minimum time (in seconds) for a session to be considered ok
If an X session will run for less than this time in seconds, nodm will wait an
amount of time before restarting the session. The waiting time will grow
until a session lasts longer than this amount.
+
+Template: nodm/xinit
+Type: string
+Default: /usr/bin/xinit
+_Description: xinit program to use
+ You can change this to use a different xinit program.
+ .
+ nodm will start the X session with the command:
+ $NODM_XINIT $NODM_XSESSION -- $NODM_X_OPTIONS
+
+Template: nodm/xsession
+Type: string
+Default: /etc/X11/Xsession
+_Description: X session to use
+ You can change this to use a different X session script.
+ .
+ nodm will start the X session with the command:
+ $NODM_XINIT $NODM_XSESSION -- $NODM_X_OPTIONS
+
diff --git a/nodm.c b/nodm.c
index 81c85f0..acc388a 100644
--- a/nodm.c
+++ b/nodm.c
@@ -47,6 +47,9 @@
#define NAME "nodm"
+#define SESSION_CMD "/usr/sbin/nodm-session"
+/* #define DEBUG_NODM */
+
#include <getopt.h>
#include <grp.h>
@@ -101,11 +104,9 @@ static struct pam_conv conv = {
#define E_CMD_NOEXEC 126 /* can't run command/shell */
#define E_CMD_NOTFOUND 127 /* can't find command/shell to run */
-/* #define DEBUG_NODM */
-
#ifdef DEBUG_NODM
/* Turn syslog into fprintf, for debugging */
-#define syslog(prio, str, ...) do { fprintf(stderr, str, __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
+#define syslog(prio, ...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
#endif
/*
@@ -117,9 +118,6 @@ static struct pam_conv conv = {
/* User we are changing to */
static char name[BUFSIZ];
-/* Command that we are running */
-static char command[BUFSIZ];
-
static pam_handle_t *pamh = NULL;
static int caught = 0;
@@ -202,20 +200,11 @@ static void catch_signals (int sig)
* have been applied. Some work was needed to get it integrated into
* su.c from shadow.
*/
-static int run_shell (const char* command, int* status)
+static int run_shell (const char** args, int* status)
{
int child;
sigset_t ourset;
struct sigaction action;
- const char* args[5];
-
- args[0] = "/bin/sh";
- args[1] = "-l";
- args[2] = "-c";
- args[3] = command;
- args[4] = NULL;
-
- syslog (LOG_INFO, "Running %s %s %s '%s'", args[0], args[1], args[2], args[3]);
child = fork ();
if (child == 0) { /* child shell */
@@ -307,20 +296,45 @@ killed:
return -1;
}
-void run_session(const char* command)
+/*
+ * Run the X session
+ *
+ * @param xinit
+ * The path to xinit
+ * @param xsession
+ * The path to the X session
+ * @param xoptions
+ * The path to the X options (can be NULL if no options are to be passed)
+ * @param mst
+ * The minimum time (in seconds) that a session should last to be considered
+ * successful
+ */
+void run_and_restart(const char* xinit, const char* xsession, const char* xoptions, int mst)
{
static int retry_times[] = { 0, 0, 30, 30, 60, 60, -1 };
int restart_count = 0;
- char* s_mst = getenv("NODM_MIN_SESSION_TIME");
- int mst = s_mst ? atoi(s_mst) : 60;
+ char command[BUFSIZ];
+ const char* args[4];
+
+ if (xoptions != NULL)
+ snprintf(command, BUFSIZ, "%s %s -- %s", xinit, xsession, xoptions);
+ else
+ snprintf(command, BUFSIZ, "%s %s", xinit, xsession);
+ command[BUFSIZ-1] = 0;
+
+ args[0] = "/bin/sh";
+ args[1] = "-c";
+ args[2] = command;
+ args[3] = 0;
while (1)
{
- /* Run the shell */
+ /* Run the X server */
time_t begin = time(NULL);
time_t end;
int status;
- if (run_shell(command, &status))
+ syslog (LOG_INFO, "Running %s %s '%s'", args[0], args[1], args[2]);
+ if (run_shell(args, &status))
return;
end = time(NULL);
@@ -341,45 +355,102 @@ void run_session(const char* command)
}
/*
- * su - switch user id
+ * Copy from the environment the value of $name into dest.
*
- * su changes the user's ids to the values for the specified user. if
- * no new user name is specified, "root" is used by default.
+ * If $name is not in the environment, use def.
*
- * Any additional arguments are passed to the user's shell. In
- * particular, the argument "-c" will cause the next argument to be
- * interpreted as a command by the common shell programs.
+ * @param destination buffer, should be at least BUFSIZ long
+ * @param name name of the environment variable to look up
+ * @param def default value to use if $name is not found
*/
-int main (int argc, char **argv)
+static void string_from_env(char* dest, const char* name, const char* def)
{
- char *cp;
- const char *tty = 0; /* Name of tty SU is run from */
- uid_t my_uid;
- struct passwd *pw = 0;
- char **envcp;
- int ret;
+ char* cp = getenv(name);
+ if (cp != NULL)
+ strncpy(dest, cp, BUFSIZ-1);
+ else
+ strncpy(dest, def, BUFSIZ-1);
+ dest[BUFSIZ-1] = 0;
+}
- /*
- * Get the program name. The program name is used as a prefix to
- * most error messages.
- */
- Prog = Basename (argv[0]);
+static void monitor_cmdline_help(int argc, char** argv, FILE* out)
+{
+ fprintf(out, "Usage: %s [options]\n\n", argv[0]);
+ fprintf(out, "Options:\n");
+ fprintf(out, " --help print this help message\n");
+ fprintf(out, " --session=cmd run cmd instead of %s\n", SESSION_CMD);
+ fprintf(out, " (use for testing)\n");
+}
- openlog(NAME, LOG_PID, LOG_AUTHPRIV);
+/*
+ * Start the monitor, that will continue to rerun xinit with appropriate delays
+ */
+static int nodm_monitor(int argc, char **argv)
+{
+ static int opt_help = 0;
+ static struct option options[] =
+ {
+ /* These options set a flag. */
+ {"help", no_argument, &opt_help, 1},
+ {"session", required_argument, 0, 's'},
+ {0, 0, 0, 0}
+ };
+ const char* opt_session = SESSION_CMD;
+ char xinit[BUFSIZ];
+ char xoptions[BUFSIZ];
+ char* cp;
+ int mst;
+
+ /* Parse command line options */
+ while (1)
+ {
+ int option_index = 0;
+ int c = getopt_long(argc, argv, "s:", options, &option_index);
+ if (c == -1) break;
+ switch (c)
+ {
+ case 0: break;
+ case 's': opt_session = optarg; break;
+ default:
+ fprintf(stderr, "Invalid command line option\n");
+ monitor_cmdline_help(argc, argv, stderr);
+ return 1;
+ }
+ }
+ if (opt_help)
+ {
+ monitor_cmdline_help(argc, argv, stdout);
+ return 0;
+ }
- /*
- * Process the command line arguments.
- */
+ syslog(LOG_INFO, "Starting nodm monitor");
- // TODO command line processing
+ /* Read the configuration from the environment */
+ cp = getenv("NODM_MIN_SESSION_TIME");
+ mst = cp ? atoi(cp) : 60;
+ string_from_env(xinit, "NODM_XINIT", "/usr/bin/xinit");
+ string_from_env(xoptions, "NODM_X_OPTIONS", "");
- /* We only run if we are root */
- my_uid = getuid ();
- if (my_uid != 0)
- {
- fprintf (stderr, _("%s: can only be run by root\n"), Prog);
- return E_NOPERM;
- }
+ run_and_restart(xinit, opt_session, xoptions[0] == 0 ? NULL : xoptions, mst);
+
+ return 0;
+}
+
+/*
+ * Start the session, with proper autologin and pam handling
+ */
+static int nodm_session(int argc, char **argv)
+{
+ int ret;
+ char *cp;
+ char **envcp;
+ const char *tty = 0; /* Name of tty SU is run from */
+ struct passwd *pw = 0;
+ int status;
+ char xsession[BUFSIZ];
+ const char* args[5];
+
+ string_from_env(xsession, "NODM_XSESSION", "/etc/X11/Xsession");
/*
* Get the tty name. Entries will be logged indicating that the user
@@ -400,12 +471,6 @@ int main (int argc, char **argv)
else
STRFCPY(name, getenv("NODM_USER"));
- /* Get the command that we should run */
- if (getenv("NODM_COMMAND") == NULL)
- strcpy(command, "/usr/bin/xinit /etc/X11/Xsession -- vt7 -nolisten tcp");
- else
- STRFCPY(command, getenv("NODM_COMMAND"));
-
ret = pam_start (NAME, name, &conv, &pamh);
if (ret != PAM_SUCCESS) {
syslog (LOG_ERR, "pam_start: error %d", ret);
@@ -508,9 +573,23 @@ int main (int argc, char **argv)
setenv ("HOME", pwent.pw_dir, 1);
setenv ("USER", pwent.pw_name, 1);
setenv ("LOGNAME", pwent.pw_name, 1);
+
+ /* Clear the NODM_* environment variables */
+ unsetenv("NODM_USER");
+ unsetenv("NODM_XINIT");
+ unsetenv("NODM_XSESSION");
+ unsetenv("NODM_X_OPTIONS");
+ unsetenv("NODM_MIN_SESSION_TIME");
+
chdir (pwent.pw_dir);
- run_session(command);
+ args[0] = "/bin/sh";
+ args[1] = "-l";
+ args[2] = "-c";
+ args[3] = xsession;
+ args[4] = NULL;
+
+ run_shell(args, &status);
ret = pam_close_session (pamh, 0);
if (ret != PAM_SUCCESS) {
@@ -523,6 +602,60 @@ int main (int argc, char **argv)
ret = pam_end (pamh, PAM_SUCCESS);
+ return status;
+}
+
+/* Return true if string ends with substring */
+static int ends_with(const char* string, const char* substring)
+{
+ int len_string = strlen(string);
+ int len_substring = strlen(substring);
+ if (len_string < len_substring)
+ return 0;
+ return strcmp(string + (len_string - len_substring), substring) == 0;
+}
+
+/*
+ * nodm - start X with autologin to a given user
+ *
+ * First, X is started as root, and nodm itself is used as the session.
+ *
+ * When run as the session, nodm performs a proper login to a given user and
+ * starts the X session.
+ */
+int main (int argc, char **argv)
+{
+ int ret;
+
+ /*
+ * Get the program name. The program name is used as a prefix to
+ * most error messages.
+ */
+ Prog = Basename (argv[0]);
+
+ openlog(NAME, LOG_PID, LOG_AUTHPRIV);
+
+ /*
+ * Process the command line arguments.
+ */
+
+ // TODO command line processing
+
+ /* We only run if we are root */
+ if (getuid() != 0)
+ {
+ fprintf (stderr, _("%s: can only be run by root\n"), Prog);
+ return E_NOPERM;
+ }
+
+ if (ends_with(argv[0], "-session"))
+ {
+ syslog(LOG_INFO, "Starting nodm X session");
+ ret = nodm_session(argc, argv);
+ } else {
+ ret = nodm_monitor(argc, argv);
+ }
+
closelog ();
- return 0;
+ return ret;
}
diff --git a/test_nodm b/test_nodm
index 633b9dc..1c1d86f 100755
--- a/test_nodm
+++ b/test_nodm
@@ -1,26 +1,27 @@
#!/bin/sh
-if [ -z "$1" ]
-then
- echo "Use: $0 username" >&2
- exit 1
-fi
-
-if [ "$1" != runtest ]
-then
- export NODM_USER=$1
- export NODM_COMMAND="`pwd`/$0 runtest -- a b c"
- export NODM_MIN_SESSION_TIME=60
- exec ./nodm
-else
- test "$2" != "--" && echo "\$2 is '$2' instead of '--'"
- test "$3" != "a" && echo "\$3 is '$3' instead of 'a'"
- test "$4" != "b" && echo "\$4 is '$4' instead of 'b'"
- test "$5" != "c" && echo "\$5 is '$5' instead of 'c'"
- echo "PATH is: $PATH"
- echo "USER is: $USER"
- echo "HOME is: $HOME"
- echo "pwd: `pwd`"
- echo "id: `id`"
- exit 0
-fi
+case "$1" in
+ '')
+# test "$2" != "a" && echo "\$3 is '$2' instead of 'a'"
+# test "$3" != "b" && echo "\$4 is '$3' instead of 'b'"
+# test "$4" != "c" && echo "\$5 is '$4' instead of 'c'"
+ echo "PATH is: $PATH"
+ echo "USER is: $USER"
+ echo "HOME is: $HOME"
+ echo "pwd: `pwd`"
+ echo "id: `id`"
+ exit 0
+ ;;
+ *)
+ export NODM_USER=$1
+ export NODM_XINIT=exec
+ export NODM_XSESSION="`pwd`/$0"
+# export NODM_X_OPTIONS="runtest a b c"
+ export NODM_MIN_SESSION_TIME=60
+ exec ./nodm --session `pwd`/nodm-session
+ ;;
+# '')
+# echo "Use: $0 username" >&2
+# exit 1
+# ;;
+esac
--
Automatic Display Manager
More information about the pkg-fso-commits
mailing list