summaryrefslogtreecommitdiff
path: root/xfce4-session/xfsm-shutdown-helper-sudo.c
diff options
context:
space:
mode:
Diffstat (limited to 'xfce4-session/xfsm-shutdown-helper-sudo.c')
-rw-r--r--xfce4-session/xfsm-shutdown-helper-sudo.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/xfce4-session/xfsm-shutdown-helper-sudo.c b/xfce4-session/xfsm-shutdown-helper-sudo.c
new file mode 100644
index 00000000..89fbf463
--- /dev/null
+++ b/xfce4-session/xfsm-shutdown-helper-sudo.c
@@ -0,0 +1,310 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org>
+ * All rights reserved.
+ *
+ * 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; either version 2, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <libxfce4util/libxfce4util.h>
+
+#include <xfce4-session/xfsm-shutdown-helper.h>
+
+
+struct _XfsmShutdownHelper
+{
+ FILE *infile;
+ FILE *outfile;
+ gboolean need_password;
+};
+
+
+XfsmShutdownHelper*
+xfsm_shutdown_helper_spawn (void)
+{
+#if defined(SUDO_CMD)
+ XfsmShutdownHelper *helper;
+ int parent_pipe[2];
+ int child_pipe[2];
+ struct rlimit rlp;
+ char buf[15];
+ int result;
+ pid_t pid;
+ int n;
+
+ helper = g_new0 (XfsmShutdownHelper, 1);
+
+ result = pipe (parent_pipe);
+ if (result < 0)
+ goto error0;
+
+ result = pipe (child_pipe);
+ if (result < 0)
+ goto error1;
+
+ pid = fork ();
+ if (pid < 0)
+ {
+ goto error2;
+ }
+ else if (pid == 0)
+ {
+ /* setup signals */
+ signal (SIGPIPE, SIG_IGN);
+
+ /* setup environment */
+ xfce_setenv ("LC_ALL", "C", TRUE);
+ xfce_setenv ("LANG", "C", TRUE);
+ xfce_setenv ("LANGUAGE", "C", TRUE);
+
+ /* setup the 3 standard file handles */
+ dup2 (child_pipe[0], STDIN_FILENO);
+ dup2 (parent_pipe[1], STDOUT_FILENO);
+ dup2 (parent_pipe[1], STDERR_FILENO);
+
+ /* Close all other file handles */
+ getrlimit (RLIMIT_NOFILE, &rlp);
+ for (n = 0; n < (int) rlp.rlim_cur; ++n)
+ {
+ if (n != STDIN_FILENO && n != STDOUT_FILENO && n != STDERR_FILENO)
+ close (n);
+ }
+
+ /* execute sudo with the helper */
+ execl (SUDO_CMD, "sudo", "-H", "-S", "-p",
+ "XFSM_SUDO_PASS ", "--", XFSM_SHUTDOWN_HELPER, NULL);
+ _exit (127);
+ }
+
+ close (parent_pipe[1]);
+
+ /* read sudo/helper answer */
+ n = read (parent_pipe[0], buf, 15);
+ if (n < 15)
+ goto error2;
+
+ helper->infile = fdopen (parent_pipe[0], "r");
+ if (helper->infile == NULL)
+ goto error2;
+
+ helper->outfile = fdopen (child_pipe[1], "w");
+ if (helper->outfile == NULL)
+ goto error3;
+
+ if (memcmp (buf, "XFSM_SUDO_PASS ", 15) == 0)
+ {
+ helper->need_password = TRUE;
+ }
+ else if (memcmp (buf, "XFSM_SUDO_DONE ", 15) == 0)
+ {
+ helper->need_password = FALSE;
+ }
+ else
+ goto error3;
+
+ close (parent_pipe[1]);
+ close (child_pipe[0]);
+
+ return helper;
+
+error3:
+ if (helper->infile != NULL)
+ fclose (helper->infile);
+ if (helper->outfile != NULL)
+ fclose (helper->outfile);
+
+error2:
+ close (child_pipe[0]);
+ close (child_pipe[1]);
+
+error1:
+ close (parent_pipe[0]);
+ close (parent_pipe[1]);
+
+error0:
+ g_free (helper);
+ return NULL;
+#else
+ /* won't work without sudo */
+ return NULL;
+#endif
+}
+
+
+gboolean
+xfsm_shutdown_helper_need_password (const XfsmShutdownHelper *helper)
+{
+ return helper->need_password;
+}
+
+
+gboolean
+xfsm_shutdown_helper_send_password (XfsmShutdownHelper *helper,
+ const gchar *password)
+{
+ char buffer[1024];
+ ssize_t result;
+ size_t failed;
+ size_t length;
+ size_t bytes;
+ int fd;
+
+ g_return_val_if_fail (helper != NULL, FALSE);
+ g_return_val_if_fail (password != NULL, FALSE);
+ g_return_val_if_fail (helper->need_password, FALSE);
+
+ g_snprintf (buffer, 1024, "%s\n", password);
+ length = strlen (buffer);
+ bytes = fwrite (buffer, 1, length, helper->outfile);
+ fflush (helper->outfile);
+ bzero (buffer, length);
+
+ if (bytes != length)
+ {
+ fprintf (stderr, "Failed to write password (bytes=%u, length=%u)\n",
+ bytes, length);
+ return FALSE;
+ }
+
+ if (ferror (helper->outfile))
+ {
+ fprintf (stderr, "Pipe error\n");
+ return FALSE;
+ }
+
+ fd = fileno (helper->infile);
+
+ for (failed = length = 0;;)
+ {
+ result = read (fd, buffer + length, 256 - length);
+
+ if (result < 0)
+ {
+ perror ("read");
+ return FALSE;
+ }
+ else if (result == 0)
+ {
+ if (++failed > 20)
+ return FALSE;
+ continue;
+ }
+ else if (result + length >= 1024)
+ {
+ fprintf (stderr, "Too much output from sudo!\n");
+ return FALSE;
+ }
+
+ length += result;
+ buffer[length] = 0;
+
+ if (length >= 15)
+ {
+ if (strncmp (buffer + (length - 15), "XFSM_SUDO_PASS ", 15) == 0)
+ {
+ return FALSE;
+ }
+ else if (strncmp (buffer + (length - 15), "XFSM_SUDO_DONE ", 15) == 0)
+ {
+ helper->need_password = FALSE;
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+gboolean
+xfsm_shutdown_helper_send_command (XfsmShutdownHelper *helper,
+ XfsmShutdownCommand command)
+{
+ static char *command_table[] = { "POWEROFF", "REBOOT" };
+ char response[256];
+
+ g_return_val_if_fail (helper != NULL, FALSE);
+ g_return_val_if_fail (!helper->need_password, FALSE);
+
+ fprintf (helper->outfile, "%s\n", command_table[command]);
+ fflush (helper->outfile);
+
+ if (ferror (helper->outfile))
+ {
+ fprintf (stderr, "Error sending command to helper\n");
+ return FALSE;
+ }
+
+ if (fgets (response, 256, helper->infile) == NULL)
+ {
+ fprintf (stderr, "No response from helper\n");
+ return FALSE;
+ }
+
+ if (strncmp (response, "SUCCEED", 7) != 0)
+ {
+ fprintf (stderr, "Command failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void
+xfsm_shutdown_helper_destroy (XfsmShutdownHelper *helper)
+{
+ g_return_if_fail (helper != NULL);
+
+ if (helper->infile != NULL)
+ fclose (helper->infile);
+ if (helper->outfile != NULL)
+ fclose (helper->outfile);
+ g_free (helper);
+}
+
+