/* PureAdmin
 * Copyright (C) 2003 Isak Savo
 *
 *  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 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.
 *
 *  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.
 */

/*
 * Functions related to run a program as root
 *
 * Copyright (C) 2003-2004 Isak Savo
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <gtk/gtk.h>
#ifdef HAVE_LIBDL
#include <dlfcn.h>
#endif

#include <sys/wait.h>
#include <errno.h>

#include "globals.h"
#include "binreloc.h"

//#ifndef SELFPATH
//# define SELFPATH BINDIR G_DIR_SEPARATOR_S "pureadmin"
//#endif
static void startup_notify_complete (void)
{
#ifdef HAVE_LIBDL
	void *gdk;
	gdk = dlopen (NULL, RTLD_LAZY);
	if (gdk) {
		void (*gdk_notify_startup_complete)() = dlsym (gdk, "gdk_notify_startup_complete");
		if (gdk_notify_startup_complete) 
			gdk_notify_startup_complete ();
	
		dlclose (gdk);
	}
	else
		pur_log_wrn ("Couldn't dlopen() myself: %s", g_strerror (errno));
#endif
}

gpointer gnomesu_dl = NULL;
gboolean alternative_run_as_root (gchar **argv)
{
	gboolean rv = FALSE;
	GError *err = NULL;
	gchar *icon = g_build_filename (pixmapdir, "pureadmin-48x48.png", NULL);
	
	/* No gnomesu available, try gksu as last resort
	   (available on sudo distros, such as ubuntu) */
	if (g_find_program_in_path ("gksudo"))
	{
		GString *pa_cmdline;
		gchar *cmd;
		gint exitstatus;
		pa_cmdline = g_string_new ("");
		argv++;
		while (*argv){
			gchar *tmp = g_shell_quote (*argv);
			g_string_append (pa_cmdline, tmp);
			g_string_append_c (pa_cmdline, ' ');
			argv++;
		}
		cmd = g_strdup_printf ("gksudo --icon \"%s\" \"%s %s\"",
				       icon, selfname, pa_cmdline->str);
		startup_notify_complete ();
		g_spawn_command_line_sync (cmd, NULL, NULL, &exitstatus, &err);
		g_string_free (pa_cmdline, TRUE);
		g_free (cmd);
		/* We should actually check the return value, but gksudo seems
		 * to return anything *BUT* the documented values. */
		if (err) {
			pur_log_err ("Error running gksudo: %s", err->message);
			g_error_free (err);
			rv = FALSE;
		} else 	if (!WIFEXITED(exitstatus)) {
			/* Terminated abnormally */
			rv = FALSE;
		}
		else
			/* Exited alright and returned 0 */
			rv = TRUE;
	}
	g_free (icon);
	return rv;
}

#ifndef HAVE_LIBDL
gboolean init_suexec (void){
	return TRUE;
}

gboolean run_as_root (gchar **argv)
{
	return alternative_run_as_root (argv);
}

void suexec_shutdown (void) {
	return;
}
#else 

/* init_suexec: Tries to dlopen() libgnomesu, enabling easy switch-user
 * functions.
 */
gboolean init_suexec (void)
{

	if (gnomesu_dl == NULL)
	{
		gnomesu_dl = dlopen ("libgnomesu.so", RTLD_LAZY);
		if (!gnomesu_dl)
			gnomesu_dl = dlopen ("libgnomesu.so.0", RTLD_LAZY); /* One more try */
		if (!gnomesu_dl)
			return FALSE;
	}
	return TRUE;
}

/* suexec_shutdown: Closes the handle to libgnomesu */
void suexec_shutdown (void)
{
	if (!gnomesu_dl)
		return;
	if (dlclose(gnomesu_dl) != 0)
		pur_log_wrn ("Unable to close gnomesu dl-handle: %s", dlerror());
}

/* run_as_root: Wrapper around gnomesu_spawn_async() that executes pureadmin
 *		as root. It does some sanity checks first, and makes sure that
 *		the program executed is an absolute path.
 *
 * Arguments: argv	The argument vector from main()
 */
gboolean run_as_root (gchar **argv)
{
	static gboolean (*spawn_command) (gchar *,gchar**, gint*) = NULL;
	gchar *prgm, *tmp;
	gint pid = 0;
        
	if (!init_suexec())
		return alternative_run_as_root (argv);

	dlerror();

	if (spawn_command == NULL)
	{
		spawn_command = dlsym (gnomesu_dl, "gnomesu_spawn_async");
		if ((tmp = dlerror()) != NULL) {
			pur_log_wrn ("Unable to retreive gnomesu function: %s", tmp);
			return FALSE;
		}
	}
	/* Ensure we have full path to pureadmin! */
	if (!g_path_is_absolute (selfname)) {
		pur_log_wrn ("Cannot run %s: not an absolute path", selfname);
		return FALSE;
	}
    
	prgm = g_strdup (selfname);
	tmp = argv[0];
	argv[0] = prgm;

	if (!spawn_command ("root", argv ,&pid))
		pur_log_wrn ("Unable to run pureadmin as root");

	argv[0] = tmp;
	g_free(prgm);
	return TRUE;
}

#endif /* HAVE_LIBDL */


syntax highlighted by Code2HTML, v. 0.9.1