PolicyKit/polkitd Makefile.am, NONE, 1.1 debug-polkitd.sh, NONE, 1.1 main.c, NONE, 1.1 policy.c, NONE, 1.1 policy.h, NONE, 1.1 polkit-manager.c, NONE, 1.1 polkit-manager.h, NONE, 1.1 polkit-marshal.list, NONE, 1.1 polkit-session.c, NONE, 1.1 polkit-session.h, NONE, 1.1 polkitd-test.c, NONE, 1.1 run-polkitd.sh, NONE, 1.1 valgrind-polkitd.sh, NONE, 1.1

David Zeuthen david at kemper.freedesktop.org
Mon Mar 13 22:14:35 PST 2006


Update of /cvs/hal/PolicyKit/polkitd
In directory kemper:/tmp/cvs-serv13970/polkitd

Added Files:
	Makefile.am debug-polkitd.sh main.c policy.c policy.h 
	polkit-manager.c polkit-manager.h polkit-marshal.list 
	polkit-session.c polkit-session.h polkitd-test.c 
	run-polkitd.sh valgrind-polkitd.sh 
Log Message:
2006-03-14  David Zeuthen  <davidz at redhat.com>

	Add a bunch of code; basically a full rewrite moving all queries
	to the daemon.

	* COPYING:
	* Makefile.am:
	* configure.in:
	* libpolkit/Makefile.am:
	* libpolkit/libpolkit-test.c:
	* libpolkit/libpolkit.c: (libpolkit_new_context),
	(libpolkit_free_context),
	(libpolkit_get_allowed_resources_for_privilege_for_uid),
	(libpolkit_is_uid_allowed_for_privilege),
	(libpolkit_get_privilege_list):
	* libpolkit/libpolkit.h:
	* policy-kit.in:
	* polkit-interface-manager.xml:
	* polkit-interface-session.xml:
	* polkit.pc.in:
	* polkitd/Makefile.am:
	* polkitd/debug-polkitd.sh:
	* polkitd/main.c: (usage), (delete_pid), (main):
	* polkitd/policy.c: (policy_util_set_policy_directory),
	(policy_element_new), (policy_element_free),
	(policy_element_free_list), (policy_element_dump),
	(txt_backend_read_policy), (policy_get_whitelist),
	(policy_get_blacklist), (policy_get_policies), (afp_process_elem),
	(policy_get_allowed_resources_for_policy_for_uid_gid),
	(policy_is_uid_gid_allowed_for_policy), (policy_util_uid_to_name),
	(policy_util_gid_to_name), (policy_util_name_to_uid),
	(policy_util_name_to_gid),
	(policy_get_allowed_resources_for_policy_for_uid),
	(policy_is_uid_allowed_for_policy), (getgrouplist):
	* polkitd/policy.h:
	* polkitd/polkit-manager.c: (caller_info_delete),
	(polkit_manager_init), (polkit_manager_finalize),
	(polkit_manager_class_init), (polkit_manager_error_quark),
	(polkit_manager_error_get_type), (bus_name_owner_changed),
	(session_remover), (session_finalized), (polkit_manager_new),
	(uid_from_username), (safe_strcmp),
	(polkit_manager_get_caller_info),
	(polkit_manager_initiate_privilege_grant),
	(polkit_manager_is_user_privileged),
	(polkit_manager_get_allowed_resources_for_privilege),
	(polkit_manager_list_privileges),
	(polkit_manager_add_temporary_privilege),
	(polkit_manager_remove_temporary_privilege):
	* polkitd/polkit-manager.h:
	* polkitd/polkit-marshal.list:
	* polkitd/polkit-session.c: (polkit_session_init),
	(polkit_session_finalize), (polkit_session_class_init),
	(polkit_session_error_quark), (polkit_session_error_get_type),
	(polkit_session_check_caller), (polkit_session_is_authenticated),
	(polkit_session_get_auth_denied_reason), (safe_memset),
	(my_conversation), (write_back_to_parent), (do_pam_auth),
	(data_from_pam), (polkit_session_get_auth_details),
	(polkit_session_initiate_auth), (polkit_session_get_questions),
	(polkit_session_provide_answers), (polkit_session_close),
	(polkit_session_grant_privilege_temporarily), (polkit_session_new),
	(polkit_session_initiator_disconnected):
	* polkitd/polkit-session.h:
	* polkitd/polkitd-test.c: (my_exit), (do_check),
	(write_test_policy), (do_read_tests), (main):
	* polkitd/run-polkitd.sh:
	* polkitd/valgrind-polkitd.sh:
	* privileges/Makefile.am:
	* privileges/desktop-console.privilege:
	* tools/Makefile.am:
	* tools/Makefile.in:
	* tools/polkit-grant-privilege.c: (have_questions_handler),
	(auth_done_handler), (do_grant_privilege), (usage), (main):
	* tools/polkit-is-privileged.c: (usage), (main):
	* tools/polkit-list-privileges.c: (usage), (main):



--- NEW FILE: Makefile.am ---

INCLUDES = \
	-DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \
	-DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
	-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
	-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
	-I$(top_srcdir) \
	@GLIB_CFLAGS@ \
	@DBUS_GLIB_CFLAGS@

# polkitd
#

sbin_PROGRAMS = polkitd

polkitd_SOURCES =                  					\
	polkit-marshal.c                polkit-marshal.h                \
	polkit-session.c 		polkit-session.h		\
	polkit-manager.c 		polkit-manager.h		\
					polkit-interface-manager-glue.h \
					polkit-interface-session-glue.h \
	policy.c                        policy.h                        \
	main.c

polkitd_CFLAGS = -fno-strict-aliasing
polkitd_LDADD = @GLIB_LIBS@ @DBUS_GLIB_LIBS@ @AUTH_LIBS@

#### Init scripts fun
SCRIPT_IN_FILES=PolicyKit.in

## Red Hat start
if OS_TYPE_RED_HAT

initddir=$(sysconfdir)/rc.d/init.d

initd_SCRIPTS= 	\
	PolicyKit

endif
## Red Hat end

# D-BUS configuration file
#

dbusdir = $(sysconfdir)/dbus-1/system.d
dist_dbus_DATA = PolicyKit.conf

# D-BUS glue
#

polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am
	dbus-binding-tool --prefix=polkit_manager --mode=glib-server --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml

polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am
	dbus-binding-tool --prefix=polkit_session --mode=glib-server --output=polkit-interface-session-glue.h ../polkit-interface-session.xml

BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h

# Marshallers
#

polkit-marshal.c: Makefile polkit-marshal.list
	glib-genmarshal --prefix=polkit_marshal $(srcdir)/polkit-marshal.list --header --body > $@.tmp && mv $@.tmp $@

polkit-marshal.h: Makefile polkit-marshal.list
	glib-genmarshal --prefix=polkit_marshal $(srcdir)/polkit-marshal.list --header > $@.tmp && mv $@.tmp $@

BUILT_SOURCES += polkit-marshal.c polkit-marshal.h


# Test harness 
#

check_PROGRAMS = polkitd-test

polkitd_test_SOURCES =                             \
	policy.c		policy.h	   \
	polkitd-test.c

polkitd_test_LDADD = @GLIB_LIBS@

TESTS = polkitd-test



EXTRA_DIST = polkit-marshal.list

# Clean
#

clean-local:
	rm -f *~ $(BUILT_SOURCES) PolicyKit.conf

--- NEW FILE: debug-polkitd.sh ---
#!/bin/sh

echo ========================================
echo Just type \'run\' to start debugging polkitd
echo ========================================
gdb run --args ./polkitd --no-daemon --verbose




--- NEW FILE: main.c ---
/***************************************************************************
 * CVSID: $Id: main.c,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * main.c : Main for polkitd
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <dbus/dbus-glib.h>

#include "polkit-session.h"
#include "polkit-manager.h"

#include "polkit-interface-session-glue.h"
#include "polkit-interface-manager-glue.h"

/** Print out program usage.
 *
 */
static void
usage (int argc, char *argv[])
{
	fprintf (stderr, "\n" "usage : polkitd [--no-daemon] [--verbose]\n");
	fprintf (stderr,
		 "\n"
		 "        -n, --no-daemon      Do not daemonize\n"
		 "        -v, --verbose        Print out debug\n"
		 "        -h, --help           Show this information and exit\n"
		 "        -V, --version        Output version information and exit"
		 "\n"
		 "The PolicyKit daemon maintains a list of privileges and\n"
		 "provides interfaces for changing it.\n"
		 "\n"
		 "For more information visit http://freedesktop.org/Software/hal\n"
		 "\n");
}

static void 
delete_pid (void)
{
	unlink (POLKITD_PID_FILE);
}

int
main (int argc, char *argv[])
{
	DBusGConnection *bus;
	DBusGProxy *bus_proxy;
	GError *error = NULL;
	PolicyKitManager *manager;
	GMainLoop *mainloop;
	guint request_name_result;
	int ret;
	gboolean no_daemon = FALSE;
	gboolean is_verbose = FALSE;
	static const struct option long_options[] = {
		{"help", no_argument, NULL, 'h'},
		{"no-daemon", no_argument, NULL, 'n'},
		{"verbose", no_argument, NULL, 'v'},
		{"version", no_argument, NULL, 'V'},
		{NULL, 0, NULL, 0}
	};


	ret = 1;

	g_type_init ();

	while (TRUE) {
		int c;
		
		c = getopt_long (argc, argv, "nhVv", long_options, NULL);

		if (c == -1)
			break;
		
		switch (c) {
		case 'n':
			no_daemon = TRUE;
			break;

		case 'v':
			is_verbose = TRUE;
			break;

		case 'h':
			usage (argc, argv);
			ret = 0;
			goto out;

		case 'V':
			printf (PACKAGE_NAME " version " PACKAGE_VERSION "\n");
			ret = 0;
			goto out;
			
		default:
			usage (argc, argv);
			goto out;
		}
	}


	if (!no_daemon) {
		int child_pid;
		int dev_null_fd;
		int pf;
		ssize_t written;
		char pid[9];
		

		if (chdir ("/") < 0) {
			g_warning ("Could not chdir to /: %s", strerror (errno));
			goto out;
		}

		child_pid = fork ();
		switch (child_pid) {
		case -1:
			g_warning ("Cannot fork(): %s", strerror (errno));
			goto out;

		case 0:
			/* child */
			dev_null_fd = open ("/dev/null", O_RDWR);
			/* ignore if we can't open /dev/null */
			if (dev_null_fd >= 0) {
				/* attach /dev/null to stdout, stdin, stderr */
				dup2 (dev_null_fd, 0);
				dup2 (dev_null_fd, 1);
				dup2 (dev_null_fd, 2);
				close (dev_null_fd);
			}

			umask (022);
			break;

		default:
			/* parent exits */
			exit (0);
			break;
		}

		/* create session */
		setsid ();

		/* remove old pid file */
		unlink (POLKITD_PID_FILE);

		/* make a new pid file */
		if ((pf = open (POLKITD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
			snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
			written = write (pf, pid, strlen(pid));
			close (pf);
			g_atexit (delete_pid);
		}
	} else {
		g_debug (("not becoming a daemon"));
	}

	g_type_init ();

	dbus_g_object_type_install_info (POLKIT_TYPE_MANAGER, &dbus_glib_polkit_manager_object_info);
	dbus_g_object_type_install_info (POLKIT_TYPE_SESSION, &dbus_glib_polkit_session_object_info);
	dbus_g_error_domain_register (POLKIT_MANAGER_ERROR, NULL, POLKIT_MANAGER_TYPE_ERROR);
	dbus_g_error_domain_register (POLKIT_SESSION_ERROR, NULL, POLKIT_SESSION_TYPE_ERROR);

	mainloop = g_main_loop_new (NULL, FALSE);

	bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
	if (bus == NULL) {
		g_warning ("Couldn't connect to system bus: %s", error->message);
		g_error_free (error);
		goto out;
	}

	bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus",
					       "/org/freedesktop/DBus",
					       "org.freedesktop.DBus");
	if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
				G_TYPE_STRING, "org.freedesktop.PolicyKit",
				G_TYPE_UINT, 0,
				G_TYPE_INVALID,
				G_TYPE_UINT, &request_name_result,
				G_TYPE_INVALID)) {
		g_warning ("Failed to acquire org.freedesktop.PolicyKit: %s", error->message);
		g_error_free (error);
		goto out;
	}
	


	manager = polkit_manager_new (bus, bus_proxy);

	g_debug ("service running");

	g_main_loop_run (mainloop);

	ret = 0;
out:
	return ret;
}

--- NEW FILE: policy.c ---
/***************************************************************************
 * CVSID: $Id: policy.c,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * policy.c : Wraps policy
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <errno.h>

#include <glib.h>

#include "policy.h"

#ifdef __SUNPRO_C
#define __FUNCTION__ __func__
#endif

static char *policy_directory = PACKAGE_SYSCONF_DIR "/PolicyKit/privilege.d";

void
policy_util_set_policy_directory (const char *directory)
{
	policy_directory = g_strdup (directory);
}


typedef enum {
	POLICY_ELEMENT_TYPE_UID,
	POLICY_ELEMENT_TYPE_GID
} PolicyElementType;


struct PolicyElement_s
{
	PolicyElementType type;
	union {
		uid_t uid;
		gid_t gid;
	} id;
	gboolean include_all;
	gboolean exclude_all;
	char *resource;
};

typedef struct PolicyElement_s PolicyElement;

static PolicyElement *
policy_element_new (void)
{
	PolicyElement *elem;

	elem = g_new0 (PolicyElement, 1);
	return elem;
}

static void
policy_element_free (PolicyElement *elem)
{
	g_free (elem->resource);
	g_free (elem);
}

static void 
policy_element_free_list (GList *policy_element_list)
{
	GList *l;

	for (l = policy_element_list; l != NULL; l = g_list_next (l)) {
		PolicyElement *elem = (PolicyElement *) l->data;
		policy_element_free (elem);
	}

	g_list_free (policy_element_list);
}

#if 0
static void
policy_element_dump (PolicyElement *elem, FILE* fp)
{
	char *t;

	if (elem->type == POLICY_ELEMENT_TYPE_UID)
		t = "uid";
	else if (elem->type == POLICY_ELEMENT_TYPE_GID)
		t = "gid";
	else
		t = "(Unknown)";

	fprintf (fp, "type:     %s\n", t);
	if (elem->type == POLICY_ELEMENT_TYPE_UID) {
		if (elem->include_all) {
			fprintf (fp, "uid:      all\n");
		} else if (elem->exclude_all) {
			fprintf (fp, "uid:      none\n");
		} else {
			fprintf (fp, "uid:      %d\n", (int) elem->id.uid);
		}
	} else if (elem->type == POLICY_ELEMENT_TYPE_GID) {
		if (elem->include_all) {
			fprintf (fp, "gid:      all\n");
		} else if (elem->exclude_all) {
			fprintf (fp, "gid:      none\n");
		} else {
			fprintf (fp, "gid:      %d\n", (int) elem->id.gid);
		}
	}
	fprintf (fp, "resource: %s\n", elem->resource != NULL ? elem->resource : "(None)");
}
#endif


static PolicyResult
txt_backend_read_policy (const char             *policy,
			 const char             *key,
			 GList                 **result)
{
	int i;
	GKeyFile *keyfile;
	GError *error;
	PolicyResult rc;
	char *path;
	char *value = NULL;
	char **tokens = NULL;
	char *ttype = NULL;
	char *tvalue = NULL;
	char *tresource = NULL;
	PolicyElement *elem = NULL;
	GList *res;
	GList *l;
	char *token;

	error = NULL;
	rc = POLICY_RESULT_ERROR;
	res = NULL;
	*result = NULL;

	keyfile = g_key_file_new ();
	path = g_strdup_printf ("%s/%s.privilege", policy_directory, policy);
	/*g_message ("Loading %s", path);*/
	if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error)) {
		g_warning ("Couldn't open key-file '%s': %s", path, error->message);
		g_error_free (error);
		rc = POLICY_RESULT_NO_SUCH_POLICY;
		goto out;
	}

	value = g_key_file_get_string (keyfile, "Policy", key, &error);
	if (value == NULL) {
		g_warning ("Cannot get key '%s' in group 'Policy' in file '%s': %s", key, path, error->message);
		g_error_free (error);
		rc = POLICY_RESULT_ERROR;
		goto out;
	}

	/*g_message ("value = '%s'", value);*/
	tokens = g_strsplit (value, " ", 0);
	for (i = 0; tokens[i] != NULL; i++) {
		char **components;
		int num_components;

		token = tokens[i];
		/*g_message ("  token = '%s'", token);*/

		ttype = NULL;
		tvalue = NULL;
		tresource = NULL;

		elem = policy_element_new ();

		components = g_strsplit (token, ":", 3);
		num_components = g_strv_length (components);
		if (num_components == 2) {
			ttype = g_strdup (components[0]);
			tvalue = g_strdup (components[1]);
			tresource = NULL;
		} else if (num_components == 3) {
			ttype = g_strdup (components[0]);
			tvalue = g_strdup (components[1]);
			tresource = g_strdup (components[2]);
		} else {
			g_strfreev (components);
			goto malformed_token;
		}
		g_strfreev (components);

		/*g_message ("  type='%s' value='%s' resource='%s'", ttype, tvalue, tresource != NULL ? tresource : "None");*/

		if (strcmp (ttype, "uid") == 0) {
			elem->type = POLICY_ELEMENT_TYPE_UID;
			if (strcmp (tvalue, "__all__") == 0) {
				elem->include_all = TRUE;
			} else if (strcmp (tvalue, "__none__") == 0) {
				elem->exclude_all = TRUE;
			} else {
				uid_t uid;
				char *endp;
				uid = (uid_t) g_ascii_strtoull (tvalue, &endp, 0);
				if (endp[0] != '\0') {
					uid = policy_util_name_to_uid (tvalue, NULL);
					if (uid == (uid_t) -1) {
						g_warning ("User '%s' does not exist", tvalue);
						goto malformed_token;
					}
				}
				elem->id.uid = uid;
			}
		} else if (strcmp (ttype, "gid") == 0) {
			elem->type = POLICY_ELEMENT_TYPE_GID;
			if (strcmp (tvalue, "__all__") == 0) {
				elem->include_all = TRUE;
			} else if (strcmp (tvalue, "__none__") == 0) {
				elem->exclude_all = TRUE;
			} else {
				gid_t gid;
				char *endp;
				gid = (gid_t) g_ascii_strtoull (tvalue, &endp, 0);
				if (endp[0] != '\0') {
					gid = policy_util_name_to_gid (tvalue);
					if (gid == (gid_t) -1) {
						g_warning ("Group '%s' does not exist", tvalue);
						goto malformed_token;
					}
				}
				elem->id.gid = gid;
			}
		} else {
			g_warning ("Token '%s' in key '%s' in group 'Policy' in file '%s' malformed",
				   token, key, path);
			goto malformed_token;
		}

		if (tresource != NULL) {
			elem->resource = g_strdup (tresource);
		}

		g_free (ttype);
		g_free (tvalue);
		g_free (tresource);

		res = g_list_append (res, elem);
		/*policy_element_dump (elem, stderr);*/

	}

	*result = res;
	rc = POLICY_RESULT_OK;
	goto out;

malformed_token:
	g_warning ("Token '%s' in key '%s' in group 'Policy' in file '%s' malformed", token, key, path);

	for (l = res; l != NULL; l = g_list_next (l)) {
		policy_element_free ((PolicyElement *) l->data);
	}
	g_list_free (res);
	policy_element_free (elem);
	g_free (ttype);
	g_free (tvalue);
	g_free (tresource);

out:
	g_strfreev (tokens);
	g_free (value);

	g_key_file_free (keyfile);
	g_free (path);

	return rc;
}

static PolicyResult
policy_get_whitelist (const char           *policy,
		      GList               **result)
{
	return txt_backend_read_policy (policy, "Allow", result);
}

static PolicyResult
policy_get_blacklist (const char           *policy,
		      GList               **result)
{
	return txt_backend_read_policy (policy, "Deny", result);
}

/** Return all elements in the white-list for a policy
 *
 *  @param  result              On success set to a list of dynamically allocated strings. 
 *                              Must be freed by the caller.
 *  @return                     Whether the operation succeeded
 */
PolicyResult
policy_get_policies (GList              **result)
{
	GDir *dir;
	GError *error;
	const char *f;

	error = NULL;
	*result = NULL;

	if ((dir = g_dir_open (policy_directory, 0, &error)) == NULL) {
		g_critical ("Unable to open %s: %s", policy_directory, error->message);
		g_error_free (error);
		goto error;
	}
	while ((f = g_dir_read_name (dir)) != NULL) {
		if (g_str_has_suffix (f, ".privilege")) {
			char *s;
			int pos;
			
			s = g_strdup (f);
			pos = strlen (s) - 10; /* .privilege - 10 chars */
			if (pos > 0)
				s[pos] = '\0';

			*result = g_list_append (*result, s);
		}
	}
	
	g_dir_close (dir);

	return POLICY_RESULT_OK;

error:
	return POLICY_RESULT_ERROR;
}


static void
afp_process_elem(PolicyElement *elem, gboolean *flag, uid_t uid, guint num_gids, gid_t *gid_list)
{
	/*policy_element_dump (elem, stderr);*/

	switch (elem->type) {
	case POLICY_ELEMENT_TYPE_UID:
		if (elem->include_all) {
			*flag = TRUE;
		} else if (elem->exclude_all) {
			*flag = FALSE;
		}else {
			if (elem->id.uid == uid)
				*flag = TRUE;
		}
		break;
		
	case POLICY_ELEMENT_TYPE_GID:
		if (elem->include_all) {
			*flag = TRUE;
		} else if (elem->exclude_all) {
			*flag = FALSE;
		}else {
			guint i;
			for (i = 0; i < num_gids; i++) {
				if (elem->id.gid == gid_list[i])
					*flag = TRUE;
			}
		}
		break;
	}
}

PolicyResult
policy_get_allowed_resources_for_policy_for_uid_gid  (uid_t                  uid, 
						      guint                  num_gids,
						      gid_t                 *gid_list,
						      const char            *policy, 
						      GList                **result)
{
	GList *l;
	GList *whitelist;
	GList *blacklist;
	gboolean is_in_whitelist;
	gboolean is_in_blacklist;
	PolicyResult res;

	whitelist = NULL;
	blacklist = NULL;
	*result = NULL;
	res = POLICY_RESULT_ERROR;

	res = policy_get_whitelist (policy, &whitelist);
	if (res != POLICY_RESULT_OK)
		goto out;

	res = policy_get_blacklist (policy, &blacklist);
	if (res != POLICY_RESULT_OK)
		goto out;

	is_in_whitelist = FALSE;
	is_in_blacklist = FALSE;

	/*  Algorithm: check each resource in whitelist; 
	 *               if allowed, check against blacklist.. 
	 *                 if not in blacklist, push to results  
	 */

	for (l = whitelist; l != NULL; l = g_list_next (l)) {
		PolicyElement *elem;
		gboolean in_whitelist;
		elem = (PolicyElement *) l->data;

		if (elem->resource != NULL) {
			/* check if we're allowed for this resource */
			afp_process_elem (elem, &in_whitelist, uid, num_gids, gid_list);
			if (in_whitelist) {
				GList *j;
				gboolean in_blacklist;

				/* in whitelist.. yes.. now check if this resource is in the black list*/

				in_blacklist = FALSE;

				for (j = blacklist; j != NULL; j = g_list_next (j)) {
					PolicyElement *elem2;
					elem2 = (PolicyElement *) j->data;

					if (elem2->resource != NULL && 
					    strcmp (elem->resource, elem2->resource) == 0) {
						afp_process_elem (elem2, &in_blacklist, uid, num_gids, gid_list);
						if (in_blacklist)
							break;
					}
				}

				if (in_whitelist && !in_blacklist)
					*result = g_list_append (*result, g_strdup (elem->resource));
			}
		}
	}


	res = POLICY_RESULT_OK;

out:
	if (whitelist != NULL)
		policy_element_free_list (whitelist);
	if (blacklist != NULL)
		policy_element_free_list (blacklist);

	return res;	
}

PolicyResult 
policy_is_uid_gid_allowed_for_policy (uid_t                 uid, 
				      guint                 num_gids,
				      gid_t                *gid_list,
				      const char           *policy, 
				      const char           *resource,
				      gboolean             *result)
{
	gboolean is_in_whitelist;
	gboolean is_in_blacklist;
	GList *l;
	GList *whitelist;
	GList *blacklist;
	PolicyResult res;

	whitelist = NULL;
	blacklist = NULL;
	res = POLICY_RESULT_ERROR;

	res = policy_get_whitelist (policy, &whitelist);
	if (res != POLICY_RESULT_OK)
		goto out;

	res = policy_get_blacklist (policy, &blacklist);
	if (res != POLICY_RESULT_OK)
		goto out;

	is_in_whitelist = FALSE;
	is_in_blacklist = FALSE;

	/*  Algorithm: To succeed.. we must be in the whitelist.. and not in the blacklist */

	for (l = whitelist; l != NULL; l = g_list_next (l)) {
		PolicyElement *elem;
		elem = (PolicyElement *) l->data;
		if ((elem->resource == NULL) ||
		    ((resource != NULL) && (strcmp (elem->resource, resource) == 0))) {
			afp_process_elem (elem, &is_in_whitelist, uid, num_gids, gid_list);
		}
	}

	for (l = blacklist; l != NULL; l = g_list_next (l)) {
		PolicyElement *elem;
		elem = (PolicyElement *) l->data;
		if ((elem->resource == NULL) ||
		    ((resource != NULL) && (strcmp (elem->resource, resource) == 0))) {
			afp_process_elem (elem, &is_in_blacklist, uid, num_gids, gid_list);
		}
	}

	*result =  is_in_whitelist && (!is_in_blacklist);

	res = POLICY_RESULT_OK;

out:
	if (whitelist != NULL)
		policy_element_free_list (whitelist);
	if (blacklist != NULL)
		policy_element_free_list (blacklist);

	return res;	
}

char *
policy_util_uid_to_name (uid_t  uid, 
			 gid_t *default_gid)
{
	int rc;
	char *res;
	char *buf = NULL;
	unsigned int bufsize;
	struct passwd pwd;
	struct passwd *pwdp;

	res = NULL;

	bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
	buf = g_new0 (char, bufsize);

	rc = getpwuid_r (uid, &pwd, buf, bufsize, &pwdp);
	if (rc != 0 || pwdp == NULL) {
		/*g_warning ("getpwuid_r() returned %d", rc);*/
		goto out;
	}

	res = g_strdup (pwdp->pw_name);
	if (default_gid != NULL)
		*default_gid = pwdp->pw_gid;

out:
	g_free (buf);
	return res;
}

char *
policy_util_gid_to_name (gid_t gid)
{
	int rc;
	char *res;
	char *buf = NULL;
	unsigned int bufsize;
	struct group gbuf;
	struct group *gbufp;

	res = NULL;

	bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
	buf = g_new0 (char, bufsize);
		
	rc = getgrgid_r (gid, &gbuf, buf, bufsize, &gbufp);
	if (rc != 0 || gbufp == NULL) {
		/*g_warning ("getgrgid_r() returned %d", rc);*/
		goto out;
	}

	res = g_strdup (gbufp->gr_name);

out:
	g_free (buf);
	return res;
}



uid_t
policy_util_name_to_uid (const char *username, gid_t *default_gid)
{
	int rc;
	uid_t res;
	char *buf = NULL;
	unsigned int bufsize;
	struct passwd pwd;
	struct passwd *pwdp;

	res = (uid_t) -1;

	bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
	buf = g_new0 (char, bufsize);
		
	rc = getpwnam_r (username, &pwd, buf, bufsize, &pwdp);
	if (rc != 0 || pwdp == NULL) {
		/*g_warning ("getpwnam_r() returned %d", rc);*/
		goto out;
	}

	res = pwdp->pw_uid;
	if (default_gid != NULL)
		*default_gid = pwdp->pw_gid;

out:
	g_free (buf);
	return res;
}

gid_t 
policy_util_name_to_gid (const char *groupname)
{
	int rc;
	gid_t res;
	char *buf = NULL;
	unsigned int bufsize;
	struct group gbuf;
	struct group *gbufp;

	res = (gid_t) -1;

	bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
	buf = g_new0 (char, bufsize);
		
	rc = getgrnam_r (groupname, &gbuf, buf, bufsize, &gbufp);
	if (rc != 0 || gbufp == NULL) {
		/*g_warning ("getgrnam_r() returned %d", rc);*/
		goto out;
	}

	res = gbufp->gr_gid;

out:
	g_free (buf);
	return res;
}

PolicyResult 
policy_get_allowed_resources_for_policy_for_uid (uid_t                  uid, 
						 const char            *policy, 
						 GList                **result)
{
	int num_groups = 0;
	gid_t *groups = NULL;
	char *username;
	gid_t default_gid;
	PolicyResult  r;

	r = POLICY_RESULT_ERROR;

	if ((username = policy_util_uid_to_name (uid, &default_gid)) == NULL)
		goto out;

	if (getgrouplist(username, default_gid, NULL, &num_groups) < 0) {
		groups = (gid_t *) g_new0 (gid_t, num_groups);
		if (getgrouplist(username, default_gid, groups, &num_groups) < 0) {
			g_warning ("getgrouplist() failed");
			goto out;
		}
	}

	r = policy_get_allowed_resources_for_policy_for_uid_gid (uid,
								 num_groups,
								 groups,
								 policy,
								 result);

out:
	g_free (username);
	g_free (groups);
	return r;
}

PolicyResult 
policy_is_uid_allowed_for_policy (uid_t                 uid, 
				  const char           *policy, 
				  const char           *resource,
				  gboolean             *result)
{
	int num_groups = 0;
	gid_t *groups = NULL;
	char *username;
	gid_t default_gid;
	PolicyResult  r;

	r = POLICY_RESULT_ERROR;

	if ((username = policy_util_uid_to_name (uid, &default_gid)) == NULL)
		goto out;

	if (getgrouplist(username, default_gid, NULL, &num_groups) < 0) {
		groups = (gid_t *) g_new0 (gid_t, num_groups);
		if (getgrouplist(username, default_gid, groups, &num_groups) < 0) {
			g_warning ("getgrouplist() failed");
			goto out;
		}
	}

	r = policy_is_uid_gid_allowed_for_policy (uid,
						  num_groups,
						  groups,
						  policy,
						  resource,
						  result);

out:
	g_free (username);
	g_free (groups);
	return r;
}


#ifndef HAVE_GETGROUPLIST
/* Get group list for the named user.
 * Return up to ngroups in the groups array.
 * Return actual number of groups in ngroups.
 * Return -1 if more groups found than requested.
 */
int
getgrouplist (const char *name, int baseid, int *groups, int *ngroups)
{
	struct group *g;
	int n = 0;
	int i;
	int ret;

	if (*ngroups <= 0) {
		return (-1);
	}

	*groups++ = baseid;
	n++;

	setgrent ();
	while ((g = getgrent ()) != NULL) {
		for (i = 0; g->gr_mem[i]; i++) {
			if (strcmp (name, g->gr_mem[0]) == 0) {
				*groups++ = g->gr_gid;
				if (++n > *ngroups) {
					break;
				}
			}
		}
	}
	endgrent ();

	ret = (n > *ngroups) ? -1 : n;
	*ngroups = n;
	return (ret);
}
#endif

--- NEW FILE: policy.h ---
/***************************************************************************
 * CVSID: $Id: policy.h,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * policy.h : Wraps policy
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#ifndef POLICY_H
#define POLICY_H

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <glib.h>

typedef enum {
	POLICY_RESULT_OK,
	POLICY_RESULT_ERROR,
	POLICY_RESULT_NO_SUCH_POLICY
} PolicyResult;

PolicyResult policy_get_policies                                  (GList       **result);

PolicyResult policy_is_uid_allowed_for_policy                     (uid_t         uid, 
								   const char   *policy, 
								   const char   *resource,
								   gboolean     *result);

PolicyResult policy_get_allowed_resources_for_policy_for_uid      (uid_t         uid, 
								   const char   *policy, 
								   GList       **result);

PolicyResult policy_get_allowed_resources_for_policy_for_uid_gid  (uid_t         uid, 
								   guint         num_gids,
								   gid_t        *gid_list,
								   const char   *policy, 
								   GList       **result);

PolicyResult policy_is_uid_gid_allowed_for_policy                 (uid_t         uid, 
								   guint         num_gids,
								   gid_t        *gid_list,
								   const char   *policy, 
								   const char   *resource,
								   gboolean     *result);

char        *policy_util_uid_to_name                              (uid_t         uid, 
								   gid_t        *default_gid);

char        *policy_util_gid_to_name                              (gid_t         gid);

uid_t        policy_util_name_to_uid                              (const char   *username, 
								   gid_t        *default_gid);

gid_t        policy_util_name_to_gid                              (const char   *groupname);

void         policy_util_set_policy_directory                     (const char   *directory);

#endif /* POLICY_H */



--- NEW FILE: polkit-manager.c ---
/***************************************************************************
 * CVSID: $Id: polkit-manager.c,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * polkit-manager.c : Manager object
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#include <string.h>
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>

#include "polkit-marshal.h"
#include "polkit-manager.h"
#include "polkit-session.h"

#include "policy.h"

typedef struct
{
	uid_t user;
	char *privilege;
	char *resource;
	pid_t pid_restriction;
} TemporaryPrivilege;

struct PolicyKitManagerPrivate
{
	DBusGConnection *connection;
	DBusGProxy *bus_proxy;

	GList *temporary_privileges;

	GHashTable *connection_name_to_caller_info;

	GHashTable *connection_name_to_session_object;
};

G_DEFINE_TYPE(PolicyKitManager, polkit_manager, G_TYPE_OBJECT)

static GObjectClass *parent_class = NULL;


typedef struct {
	uid_t  uid;
	pid_t  pid;
} CallerInfo;

static void 
caller_info_delete (gpointer data)
{
	CallerInfo *caller_info = (CallerInfo *) data;
	g_free (caller_info);
}

static void
polkit_manager_init (PolicyKitManager *manager)
{
	manager->priv = g_new0 (PolicyKitManagerPrivate, 1);
	manager->priv->connection = NULL;
	manager->priv->temporary_privileges = NULL;

	manager->priv->connection_name_to_caller_info = g_hash_table_new_full (g_str_hash,
									       g_str_equal,
									       g_free,
									       caller_info_delete);

	manager->priv->connection_name_to_session_object = g_hash_table_new_full (g_str_hash,
										  g_str_equal,
										  g_free,
										  NULL);
}

static void
polkit_manager_finalize (PolicyKitManager *manager)
{
	dbus_g_connection_unref (manager->priv->connection);

	g_hash_table_destroy (manager->priv->connection_name_to_caller_info);

	g_free (manager->priv);

	G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (manager));
}

static void
polkit_manager_class_init (PolicyKitManagerClass *klass)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

	gobject_class->finalize = (GObjectFinalizeFunc) polkit_manager_finalize;
	parent_class = g_type_class_peek_parent (klass);
}

GQuark
polkit_manager_error_quark (void)
{
	static GQuark ret = 0;
	if (ret == 0)
		ret = g_quark_from_static_string ("PolkitManagerObjectErrorQuark");
	return ret;
}

#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }

GType
polkit_manager_error_get_type (void)
{
	static GType etype = 0;
	
	if (etype == 0) {
		static const GEnumValue values[] = {
			ENUM_ENTRY (POLKIT_MANAGER_ERROR_NO_SUCH_USER, "NoSuchUser"),
			ENUM_ENTRY (POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE, "NoSuchPrivilege"),
			ENUM_ENTRY (POLKIT_MANAGER_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
			ENUM_ENTRY (POLKIT_MANAGER_ERROR_ERROR, "Error"),
			{ 0, 0, 0 }
		};
		
		g_assert (POLKIT_MANAGER_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
		
		etype = g_enum_register_static ("PolkitManagerError", values);
	}
	
	return etype;
}


static void
bus_name_owner_changed (DBusGProxy  *bus_proxy, 
			const char  *service_name, 
			const char  *old_service_name, 
			const char  *new_service_name, 
			gpointer     user_data)
{
	PolicyKitManager *manager = POLKIT_MANAGER (user_data);

	/* track disconnects of clients */

	if (strlen (new_service_name) == 0) {
		CallerInfo *caller_info;
		PolicyKitSession *session;

		/* evict CallerInfo from cache */
		caller_info = (CallerInfo *) g_hash_table_lookup (manager->priv->connection_name_to_caller_info, 
								  old_service_name);
		if (caller_info != NULL) {
			g_hash_table_remove (manager->priv->connection_name_to_caller_info, old_service_name);
		}

		/* session object */
		session = POLKIT_SESSION (g_hash_table_lookup (manager->priv->connection_name_to_session_object,
							       old_service_name));
		if (session != NULL) {
			/* possibly revoke temporary privileges granted */
			polkit_session_initiator_disconnected (session);

			/* end the session */
			g_object_unref (session);

			g_hash_table_remove (manager->priv->connection_name_to_session_object, old_service_name);
		}
	}

	/*g_message ("NameOwnerChanged: service_name='%s', old_service_name='%s' new_service_name='%s'", 
	  service_name, old_service_name, new_service_name);*/
	
}


static gboolean
session_remover (gpointer key,
		 gpointer value,
		 gpointer user_data)
{
	if (value == user_data) {
		return TRUE;
	}
	return FALSE;
}

static void
session_finalized (gpointer  data,
		   GObject  *where_the_object_was)
{
	PolicyKitManager *manager = POLKIT_MANAGER (data);
	
	g_hash_table_foreach_remove (manager->priv->connection_name_to_session_object, 
				     session_remover,
				     where_the_object_was);
}

PolicyKitManager *
polkit_manager_new (DBusGConnection *connection, DBusGProxy *bus_proxy)
{
	PolicyKitManager *manager;

	manager = g_object_new (POLKIT_TYPE_MANAGER, NULL);
	manager->priv->connection = dbus_g_connection_ref (connection);
	dbus_g_connection_register_g_object (manager->priv->connection, 
					     "/org/freedesktop/PolicyKit/Manager", 
					     G_OBJECT (manager));

	manager->priv->bus_proxy = bus_proxy;

	dbus_g_object_register_marshaller (polkit_marshal_VOID__STRING_STRING_STRING, 
					   G_TYPE_NONE, 
					   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
	dbus_g_proxy_add_signal (bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
	dbus_g_proxy_connect_signal (bus_proxy, "NameOwnerChanged", G_CALLBACK (bus_name_owner_changed),
				     manager, NULL);

	return manager;
}


static uid_t
uid_from_username (const char *user)
{
	uid_t uid;

	if (g_ascii_isdigit (user[0])) {
		char *endp;
		uid = (uid_t) g_ascii_strtoull (user, &endp, 0);
		if (endp[0] != '\0') {
			uid = (uid_t) -1;
		}
	} else {
		uid = policy_util_name_to_uid (user, NULL);
	}

	return uid;
}

/* remote methods */

static int
safe_strcmp (const char *s1, const char *s2)
{
	if (s1 == NULL || s2 == NULL)
		return 0;
	else
		return strcmp (s1, s2);
}

gboolean
polkit_manager_get_caller_info (PolicyKitManager      *manager,
				const char            *sender,
				uid_t                 *calling_uid, 
				pid_t                 *calling_pid)
{
	gboolean res;
	CallerInfo *caller_info;
	GError *error = NULL;

	res = FALSE;

	if (sender == NULL)
		goto out;

	caller_info = g_hash_table_lookup (manager->priv->connection_name_to_caller_info,
					   sender);
	if (caller_info != NULL) {

		res = TRUE;
		*calling_uid = caller_info->uid;
		*calling_pid = caller_info->pid;
		/*g_message ("uid = %d (cached)", *calling_uid);
		  g_message ("pid = %d (cached)", *calling_pid);*/
		goto out;
	}

	if (!dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixUser", &error,
				G_TYPE_STRING, sender,
				G_TYPE_INVALID,
				G_TYPE_UINT, calling_uid,
				G_TYPE_INVALID)) {
		g_warning ("GetConnectionUnixUser() failed: %s", error->message);
		g_error_free (error);
		goto out;
	}

	if (!dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
				G_TYPE_STRING, sender,
				G_TYPE_INVALID,
				G_TYPE_UINT, calling_pid,
				G_TYPE_INVALID)) {
		g_warning ("GetConnectionUnixProcessID() failed: %s", error->message);
		g_error_free (error);
		goto out;
	}

	caller_info = g_new0 (CallerInfo, 1);
	caller_info->uid = *calling_uid;
	caller_info->pid = *calling_pid;

	g_hash_table_insert (manager->priv->connection_name_to_caller_info,
			     g_strdup (sender), 
			     caller_info);

	res = TRUE;

	/*g_message ("uid = %d", *calling_uid);
	  g_message ("pid = %d", *calling_pid);*/

out:
	return res;
}

gboolean
polkit_manager_initiate_privilege_grant (PolicyKitManager       *manager, 
					 char                   *user,
					 char                   *privilege,
					 char                   *resource,
					 DBusGMethodInvocation  *context)
{
	uid_t calling_uid;
	pid_t calling_pid;
	uid_t uid;
	PolicyKitSession *session;
	char *sender;

	/* TODO: need to handle limit number of session to prevent DOS.
	 *       Or is dbus-daemon sufficient for that; I think so..
	 */

	if (!polkit_manager_get_caller_info (manager, 
					     dbus_g_method_get_sender (context), 
					     &calling_uid, 
					     &calling_pid)) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	sender = dbus_g_method_get_sender (context);

	uid = uid_from_username (user);

	if (uid == (uid_t) -1) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NO_SUCH_USER,
							 "There is no user '%s'.",
							 user));
		return FALSE;
	}

	session = polkit_session_new (manager->priv->connection, 
				      manager,
				      calling_uid,
				      calling_pid,
				      sender,
				      uid,
				      privilege,
				      strlen (resource) > 0 ? resource : NULL);

	g_object_weak_ref (G_OBJECT (session),
			   session_finalized,
			   manager);

	g_hash_table_insert (manager->priv->connection_name_to_session_object,
			     sender,
			     session);

	//g_timeout_add (5 * 1000, destroy_session_after_timeout, session);

	dbus_g_method_return (context,
			      g_strdup (((char *) g_object_get_data (G_OBJECT (session), "dbus_glib_object_path"))));
	return TRUE;
}

gboolean
polkit_manager_is_user_privileged (PolicyKitManager      *manager, 
				   int                    pid,
				   char                  *user,
				   char                  *privilege,
				   char                  *resource,
				   DBusGMethodInvocation *context)
{
	uid_t calling_uid;
	pid_t calling_pid;
	uid_t uid;
	PolicyResult res;
	gboolean is_privileged;


	if (!polkit_manager_get_caller_info (manager, 
					     dbus_g_method_get_sender (context), 
					     &calling_uid, 
					     &calling_pid)) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	is_privileged = FALSE;

	uid = uid_from_username (user);

	if (uid == (uid_t) -1) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NO_SUCH_USER,
							 "There is no user '%s'.",
							 user));
		return FALSE;
	}

	/* TODO: check if given uid is privileged to ask for this */
	if (FALSE) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NOT_PRIVILEGED,
							 "You are not authorized to know this."));
		return FALSE;
	}

	res = policy_is_uid_allowed_for_policy (uid,
						privilege,
						strlen (resource) > 0 ? resource : NULL,
						&is_privileged);
	switch (res) {
	case POLICY_RESULT_OK:
		break;

	case POLICY_RESULT_NO_SUCH_POLICY:
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE,
							 "There is no such privilege '%s'.",
							 privilege));
		return FALSE;

	default: /* explicit fallthrough */
	case POLICY_RESULT_ERROR:
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	/* check temporary lists */
	if (!is_privileged) {
		GList *i;
		TemporaryPrivilege *p;

		for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
			p = (TemporaryPrivilege *) i->data;
			gboolean res_match;

			if (strlen (resource) == 0)
				res_match = (p->resource == NULL);
			else
				res_match = (safe_strcmp (p->resource, resource) == 0);

			if ((strcmp (p->privilege, privilege) == 0) &&
			    res_match &&
			    (p->user == uid) &&
			    ((p->pid_restriction == -1) || (p->pid_restriction == pid))) {

				is_privileged = TRUE;
				break;
			}
		}
	}

	dbus_g_method_return (context, is_privileged);

	return TRUE;
}


gboolean
polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager      *manager, 
						    char                  *user,
						    char                  *privilege,
						    DBusGMethodInvocation *context)
{
	uid_t calling_uid;
	pid_t calling_pid;
	int n;
	GList *i;
	GList *resources;
	uid_t uid;
	PolicyResult res;
	TemporaryPrivilege *p;
	char **resource_list;

	if (!polkit_manager_get_caller_info (manager, 
					     dbus_g_method_get_sender (context), 
					     &calling_uid, 
					     &calling_pid)) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	uid = uid_from_username (user);

	if (uid == (uid_t) -1) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NO_SUCH_USER,
							 "There is no user '%s'.",
							 user));
		return FALSE;
	}

	/* TODO: check if given uid is privileged to ask for this */
	if (FALSE) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NOT_PRIVILEGED,
							 "You are not authorized to know this."));
		return FALSE;
	}


	res = policy_get_allowed_resources_for_policy_for_uid (uid,
							       privilege,
							       &resources);
	switch (res) {
	case POLICY_RESULT_OK:
		break;

	case POLICY_RESULT_NO_SUCH_POLICY:
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE,
							 "There is no such privilege '%s'.",
							 privilege));
		return FALSE;

	default: /* explicit fallthrough */
	case POLICY_RESULT_ERROR:
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	/* check temporary list */
	for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
		p = (TemporaryPrivilege *) i->data;

		if ((strcmp (p->privilege, privilege) == 0) &&
		    (p->resource != NULL) &&
		    (p->user == uid) &&
		    (p->pid_restriction == -1)) {
			resources = g_list_append (resources, g_strdup (p->resource));
		}
	}

	resource_list = g_new0 (char *, g_list_length (resources) + 1);
	for (i = resources, n = 0; i != NULL; i = g_list_next (i)) {
		char *resource = (char *) i->data;
		resource_list[n++] = g_strdup (resource);
	}
	resource_list[n] = NULL;

	g_list_foreach (resources, (GFunc) g_free, NULL);
	g_list_free (resources);

	dbus_g_method_return (context, resource_list);

	return TRUE;
}

gboolean
polkit_manager_list_privileges (PolicyKitManager      *manager, 
				DBusGMethodInvocation *context)
{
	uid_t calling_uid;
	pid_t calling_pid;
	int n;
	GList *i;
	GList *privileges;
	PolicyResult res;
	char **privilege_list;


	if (!polkit_manager_get_caller_info (manager, 
					     dbus_g_method_get_sender (context), 
					     &calling_uid, 
					     &calling_pid)) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	/* TODO: check if given uid is privileged to ask for this */
	if (FALSE) {
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_NOT_PRIVILEGED,
							 "You are not authorized to know this."));
		return FALSE;
	}

	res = policy_get_policies (&privileges);
	switch (res) {
	case POLICY_RESULT_OK:
		break;
	
	default: /* explicit fallthrough */
	case POLICY_RESULT_ERROR:
		dbus_g_method_return_error (context, 
					    g_error_new (POLKIT_MANAGER_ERROR,
							 POLKIT_MANAGER_ERROR_ERROR,
							 "An error occured."));
		return FALSE;
	}

	privilege_list = g_new0 (char *, g_list_length (privileges) + 1);
	for (i = privileges, n = 0; i != NULL; i = g_list_next (i)) {
		char *privilege = (char *) i->data;
		privilege_list[n++] = g_strdup (privilege);
	}
	privilege_list[n] = NULL;

	g_list_foreach (privileges, (GFunc) g_free, NULL);
	g_list_free (privileges);

	dbus_g_method_return (context, privilege_list);

	return TRUE;
}

/* local methods */


gboolean
polkit_manager_add_temporary_privilege (PolicyKitManager   *manager, 
					uid_t               user,
					const char         *privilege,
					const char         *resource,
					pid_t               pid_restriction)
{
	GList *i;
	TemporaryPrivilege *p;

	for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
		p = (TemporaryPrivilege *) i->data;

		if ((strcmp (p->privilege, privilege) == 0) &&
		    (safe_strcmp (p->resource, resource) == 0) &&
		    (p->user == user) &&
		    (p->pid_restriction == pid_restriction))
			return FALSE;
	}

	p = g_new0 (TemporaryPrivilege, 1);
	p->user = user;
	p->privilege = g_strdup (privilege);
	p->resource = g_strdup (resource);
	p->pid_restriction = pid_restriction;

	manager->priv->temporary_privileges = g_list_append (manager->priv->temporary_privileges, p);

	return TRUE;
}

gboolean
polkit_manager_remove_temporary_privilege (PolicyKitManager   *manager, 
					   uid_t               user,
					   const char         *privilege,
					   const char         *resource,
					   pid_t               pid_restriction)
{
	GList *i;
	TemporaryPrivilege *p;

	for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
		p = (TemporaryPrivilege *) i->data;

		if ((strcmp (p->privilege, privilege) == 0) &&
		    (safe_strcmp (p->resource, resource) == 0) &&
		    (p->user == user) &&
		    (p->pid_restriction == pid_restriction)) {

			g_free (p->privilege);
			g_free (p->resource);
			
			manager->priv->temporary_privileges = g_list_remove (
				manager->priv->temporary_privileges, p);

			return TRUE;
		}
	}

	return FALSE;
}

--- NEW FILE: polkit-manager.h ---
/***************************************************************************
 * CVSID: $Id: polkit-manager.h,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * polkit-manager.h : Manager object
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#ifndef _POLKIT_MANAGER_H
#define _POLKIT_MANAGER_H

#include <unistd.h>
#include <glib.h>
#include <glib-object.h>
#include <dbus/dbus-glib.h>

GQuark polkit_manager_error_quark (void);

#define POLKIT_MANAGER_ERROR (polkit_manager_error_quark ())

typedef enum
{
        POLKIT_MANAGER_ERROR_NO_SUCH_USER = 0,
	POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE = 1,
	POLKIT_MANAGER_ERROR_NOT_PRIVILEGED = 2,
	POLKIT_MANAGER_ERROR_ERROR = 3,
        POLKIT_MANAGER_NUM_ERRORS
} PolkitManagerError;

GType polkit_manager_error_get_type (void);
#define POLKIT_MANAGER_TYPE_ERROR (polkit_manager_error_get_type ())

typedef struct PolicyKitManager PolicyKitManager;
typedef struct PolicyKitManagerClass PolicyKitManagerClass;

GType polkit_manager_get_type (void);

typedef struct PolicyKitManagerPrivate PolicyKitManagerPrivate;

struct PolicyKitManager
{
	GObject parent;

	PolicyKitManagerPrivate *priv;
};

struct PolicyKitManagerClass
{
	GObjectClass parent;
};

#define POLKIT_TYPE_MANAGER              (polkit_manager_get_type ())
#define POLKIT_MANAGER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), POLKIT_TYPE_MANAGER, PolicyKitManager))
#define POLKIT_MANAGER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), POLKIT_TYPE_MANAGER, PolicyKitManagerClass))
#define POLKIT_IS_MANAGER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), POLKIT_TYPE_MANAGER))
#define POLKIT_IS_MANAGER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), POLKIT_TYPE_MANAGER))
#define POLKIT_MANAGER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), POLKIT_TYPE_MANAGER, PolicyKitManagerClass))

PolicyKitManager *polkit_manager_new                                 (DBusGConnection       *connection,
								      DBusGProxy            *bus_proxy);

/* remote methods */

gboolean          polkit_manager_initiate_privilege_grant            (PolicyKitManager      *manager, 
						                      char                  *user,
						                      char                  *privilege,
						                      char                  *resource,
								      DBusGMethodInvocation *context);

gboolean          polkit_manager_is_user_privileged                  (PolicyKitManager      *manager, 
								      int                    pid,
						                      char                  *user,
						                      char                  *privilege,
						                      char                  *resource,
								      DBusGMethodInvocation *context);

gboolean          polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager      *manager, 
								      char                  *user,
								      char                  *privilege,
								      DBusGMethodInvocation *context);

gboolean          polkit_manager_list_privileges                     (PolicyKitManager      *manager, 
								      DBusGMethodInvocation *context);

/* local methods */

gboolean          polkit_manager_get_caller_info                     (PolicyKitManager      *manager,
								      const char            *sender,
								      uid_t                 *calling_uid, 
								      pid_t                 *calling_pid);


gboolean          polkit_manager_add_temporary_privilege             (PolicyKitManager      *manager, 
								      uid_t                  user,
								      const char            *privilege,
								      const char            *resource,
								      pid_t                  pid_restriction);

gboolean          polkit_manager_remove_temporary_privilege          (PolicyKitManager      *manager, 
								      uid_t                  user,
								      const char            *privilege,
								      const char            *resource,
								      pid_t                  pid_restriction);

#endif /* _POLKIT_MANAGER_H */

--- NEW FILE: polkit-marshal.list ---
VOID:STRING,STRING,STRING

--- NEW FILE: polkit-session.c ---
/***************************************************************************
 * CVSID: $Id: polkit-session.c,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * polkit-session.c : Session object
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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
[...964 lines suppressed...]

void
polkit_session_initiator_disconnected (PolicyKitSession *session)
{
	/*g_debug ("initiator disconnected");*/

	if (session->priv->have_granted_temp_privileges) {
		if (!polkit_manager_remove_temporary_privilege (session->priv->manager,
								session->priv->grant_to_uid,
								session->priv->grant_privilege,
								session->priv->grant_resource,
								session->priv->grant_pid_restriction)) {
			g_warning ("Could not remove tmp priv '%s' to uid %d for resource '%s' on pid %d",
				   session->priv->grant_privilege,
				   session->priv->grant_to_uid,
				   session->priv->grant_resource,
				   session->priv->grant_pid_restriction);
		}
	}
}

--- NEW FILE: polkit-session.h ---
/***************************************************************************
 * CVSID: $Id: polkit-session.h,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * polkit-session.h : Session object
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#ifndef _POLKIT_SESSION_H
#define _POLKIT_SESSION_H

#include <unistd.h>
#include <glib.h>
#include <glib-object.h>
#include <dbus/dbus-glib.h>

#include "polkit-manager.h"

GQuark polkit_session_error_quark (void);

#define POLKIT_SESSION_ERROR (polkit_session_error_quark ())

typedef enum
{
        POLKIT_SESSION_ERROR_AUTHENTICATION_IN_PROGRESS = 0,
        POLKIT_SESSION_ERROR_AUTHENTICATION_ALREADY_INITIATED = 1,
	POLKIT_SESSION_ERROR_NO_QUESTIONS = 2,
	POLKIT_SESSION_ERROR_AUTHENTICATION_WAS_NOT_DENIED = 3,
	POLKIT_SESSION_ERROR_NO_RESOURCES = 4,
        POLKIT_SESSION_ERROR_AUTHENTICATION_NOT_DONE = 5,
        POLKIT_SESSION_ERROR_AUTHENTICATION_FAILED = 6,
        POLKIT_SESSION_ERROR_NOT_INITIATOR = 7,
        POLKIT_SESSION_NUM_ERRORS
} PolkitSessionError;

GType polkit_session_error_get_type (void);
#define POLKIT_SESSION_TYPE_ERROR (polkit_session_error_get_type ())

typedef struct PolicyKitSession PolicyKitSession;
typedef struct PolicyKitSessionClass PolicyKitSessionClass;

GType polkit_session_get_type (void);

typedef struct PolicyKitSessionPrivate PolicyKitSessionPrivate;

struct PolicyKitSession
{
	GObject parent;

	PolicyKitSessionPrivate *priv;
};

struct PolicyKitSessionClass
{
	GObjectClass parent;
};

#define POLKIT_TYPE_SESSION              (polkit_session_get_type ())
#define POLKIT_SESSION(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), POLKIT_TYPE_SESSION, PolicyKitSession))
#define POLKIT_SESSION_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), POLKIT_TYPE_SESSION, PolicyKitSessionClass))
#define POLKIT_IS_SESSION(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), POLKIT_TYPE_SESSION))
#define POLKIT_IS_SESSION_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), POLKIT_TYPE_SESSION))
#define POLKIT_SESSION_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), POLKIT_TYPE_SESSION, PolicyKitSessionClass))

PolicyKitSession *polkit_session_new                         (DBusGConnection    *connection, 
							      PolicyKitManager   *manager,
							      uid_t               calling_uid,
							      pid_t               calling_pid,
							      const char         *calling_dbus_name,
							      uid_t               uid,
							      const char         *privilege,
							      const char         *resource);

/* remote methods */

gboolean          polkit_session_is_authenticated            (PolicyKitSession      *session,
							      DBusGMethodInvocation *context);

gboolean          polkit_session_initiate_auth               (PolicyKitSession      *session, 
							      DBusGMethodInvocation *context);

gboolean          polkit_session_get_questions               (PolicyKitSession      *session, 
							      DBusGMethodInvocation *context);

gboolean          polkit_session_provide_answers             (PolicyKitSession      *session, 
							      char                 **answers, 
							      DBusGMethodInvocation *context);

gboolean          polkit_session_close                       (PolicyKitSession      *session, 
							      gboolean               do_not_revoke_privilege,
							      DBusGMethodInvocation *context);

gboolean          polkit_session_get_auth_details            (PolicyKitSession      *session, 
							      DBusGMethodInvocation *context);

gboolean          polkit_session_get_auth_denied_reason      (PolicyKitSession      *session, 
							      DBusGMethodInvocation *context);

gboolean          polkit_session_grant_privilege_temporarily (PolicyKitSession      *session, 
							      gboolean               restrict_to_callers_pid,
							      DBusGMethodInvocation *context);

/* local methods */

void              polkit_session_initiator_disconnected      (PolicyKitSession      *session);


#endif /* _POLKIT_SESSION_H */

--- NEW FILE: polkitd-test.c ---
/***************************************************************************
 * CVSID: $Id: polkitd-test.c,v 1.1 2006/03/14 06:14:33 david Exp $
 *
 * polkitd-test.c : Test harness for PolicyKit daemon
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * 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
 *
 **************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <glib/gstdio.h>

#include "policy.h"

static char *testdir;

static void 
my_exit (int exit_code)
{
	int rc;
	GDir *dir;
	GError *err;
	const char *f;

	g_print ("Removing tmpdir '%s'\n", testdir);
	
	err = NULL;
	if ((dir = g_dir_open (testdir, 0, &err)) == NULL) {
		g_warning ("Unable to open %s: %s", testdir, err->message);
		g_error_free (err);
		goto error;
	}
	while ((f = g_dir_read_name (dir)) != NULL) {
		char *file;

		file = g_strdup_printf ("%s/%s", testdir, f);
		rc = g_unlink (file);
		if (rc != 0) {
			g_warning ("Unable to unlink %s: %d (%s)", file, errno, strerror (errno));
			goto error;
		}
		g_free (file);
	}

	g_dir_close (dir);
	
	rc = g_rmdir (testdir);
	if (rc != 0) {
		g_warning ("Unable to rmdir %s: %d (%s)", testdir, errno, strerror (errno));
		goto error;
	}

error:	
	exit (exit_code);
}

static void 
do_check (const char *policy,
	  uid_t uid,
	  int num_gids,
	  gid_t *gids,
	  const char *resource,
	  gboolean expected)
{
	int i;
	gboolean allowed;
	char *gidstring;
	GString *str;

	str = g_string_new ("");
	for (i = 0; i < num_gids; i++) {
		if (i != 0)
			g_string_append (str, ", ");
		g_string_append_printf (str, "%d", gids[i]);
	}
	gidstring = g_string_free (str, FALSE);

	if (POLICY_RESULT_OK != policy_is_uid_gid_allowed_for_policy (
		    uid, num_gids, gids, policy, resource, &allowed)) {
		g_warning ("fail: no policy %s", policy);
		my_exit (1);
	}
	
	if (allowed != expected) {
		g_warning ("fail: for uid %d (gids %s) expected %s on privilege '%s' for resource '%s' but got %s", 
			   uid, gidstring, 
			   expected ? "TRUE" : "FALSE", 
			   policy, 
			   (char*) (resource != NULL ? resource : ""), 
			   allowed ? "TRUE" : "FALSE");
		my_exit (1);
	}
	
	g_print ("pass: uid %d (gids %s) got %s on privilege '%s' for resource '%s'\n", 
		 uid, gidstring, 
		 expected ? "TRUE " : "FALSE", 
		 policy, 
		 (char*) (resource != NULL ? resource : ""));

	g_free (gidstring);
}

static void
write_test_policy (const char *policy, const char *allow_rule, const char *deny_rule)
{
	char *file;
	FILE *f;

	file = g_strdup_printf ("%s/%s.privilege", testdir, policy);
	f = fopen (file, "w");
	if (f == NULL) {
		g_warning ("Cannot created test policy '%s'", file);
		my_exit (1);
	}
	fprintf (f, 
		 "[Policy]\n"
		 "Allow=%s\n"
		 "Deny=%s\n", 
		 allow_rule, deny_rule);
	fclose (f);

	g_print ("Created test policy '%s' at '%s'\n"
		 "  Allow '%s'\n"
		 "  Deny  '%s'\n",
		 policy, file, allow_rule, deny_rule);

	g_free (file);
}

static void
do_read_tests (void)
{
	gid_t gid500[1] = {500};
	int gid500_len = sizeof (gid500) / sizeof (gid_t);
	gid_t gid501[1] = {501};
	int gid501_len = sizeof (gid501) / sizeof (gid_t);
	gid_t gid502[1] = {502};
	int gid502_len = sizeof (gid502) / sizeof (gid_t);

	gid_t gid500_1[2] = {500, 1};
	int gid500_1_len = sizeof (gid500_1) / sizeof (gid_t);
	gid_t gid501_1[2] = {501, 1};
	int gid501_1_len = sizeof (gid501_1) / sizeof (gid_t);
	gid_t gid502_1[2] = {502, 1};
	int gid502_1_len = sizeof (gid502_1) / sizeof (gid_t);

	/* feel free to add more tests here */

	write_test_policy ("test0", "uid:__none__ uid:500", "");
	do_check ("test0", 500, gid500_len, gid500, NULL, TRUE);
	do_check ("test0", 501, gid501_len, gid501, NULL, FALSE);
	do_check ("test0", 502, gid502_len, gid502, NULL, FALSE);

	write_test_policy ("test1", "uid:__all__", "uid:500:res0");
	do_check ("test1", 500, gid500_len, gid500, NULL, TRUE);
	do_check ("test1", 501, gid501_len, gid501, NULL, TRUE);
	do_check ("test1", 502, gid502_len, gid502, NULL, TRUE);
	do_check ("test1", 500, gid500_len, gid500, "res0", FALSE);
	do_check ("test1", 501, gid501_len, gid501, "res0", TRUE);
	do_check ("test1", 502, gid502_len, gid502, "res0", TRUE);
	do_check ("test1", 500, gid500_len, gid500, "res1", TRUE);
	do_check ("test1", 501, gid501_len, gid501, "res1", TRUE);
	do_check ("test1", 502, gid502_len, gid502, "res1", TRUE);
	
	write_test_policy ("test2", "gid:1", "uid:501");	
	do_check ("test2", 500, gid500_len, gid500, NULL, FALSE);
	do_check ("test2", 501, gid501_len, gid501, NULL, FALSE);
	do_check ("test2", 502, gid502_len, gid502, NULL, FALSE);
	do_check ("test2", 500, gid500_1_len, gid500_1, NULL, TRUE);
	do_check ("test2", 501, gid501_1_len, gid501_1, NULL, FALSE);
	do_check ("test2", 502, gid502_1_len, gid502_1, NULL, TRUE);
	
	write_test_policy ("test3", "gid:1 uid:502:res1", "uid:501 uid:500:res0");	
	do_check ("test3", 500, gid500_1_len, gid500_1, "res0", FALSE);
	do_check ("test3", 501, gid501_1_len, gid501_1, "res0", FALSE);
	do_check ("test3", 502, gid502_1_len, gid502_1, "res0", TRUE);
	do_check ("test3", 500, gid500_1_len, gid500_1, "res1", TRUE);
	do_check ("test3", 501, gid501_1_len, gid501_1, "res1", FALSE);
	do_check ("test3", 502, gid502_1_len, gid502_1, "res1", TRUE);
	do_check ("test3", 500, gid500_len, gid500, "res1", FALSE);
	do_check ("test3", 501, gid501_len, gid501, "res1", FALSE);
	do_check ("test3", 502, gid502_len, gid502, "res1", TRUE);

	write_test_policy ("test4", "gid:1:res1 uid:500:res2", "gid:502:res2");	
	do_check ("test4", 500, gid500_1_len, gid500_1, "res0", FALSE);
	do_check ("test4", 501, gid501_1_len, gid501_1, "res0", FALSE);
	do_check ("test4", 502, gid502_1_len, gid502_1, "res0", FALSE);
	do_check ("test4", 500, gid500_1_len, gid500_1, "res1", TRUE);
	do_check ("test4", 501, gid501_1_len, gid501_1, "res1", TRUE);
	do_check ("test4", 502, gid502_1_len, gid502_1, "res1", TRUE);
	do_check ("test4", 500, gid500_len, gid500, "res2", TRUE);
	do_check ("test4", 501, gid501_len, gid501, "res2", FALSE);
	do_check ("test4", 502, gid502_len, gid502, "res2", FALSE);

	write_test_policy ("test5", "gid:1", "uid:500:res-has-:colon-in-name");	
	do_check ("test5", 500, gid500_1_len, gid500_1, "res-has-:colon-in-name", FALSE);
	do_check ("test5", 501, gid501_1_len, gid501_1, "res-has-:colon-in-name", TRUE);
	do_check ("test5", 502, gid502_1_len, gid502_1, "res-has-:colon-in-name", TRUE);
	do_check ("test5", 500, gid500_len, gid500, "res-has-:colon-in-name", FALSE);
	do_check ("test5", 501, gid501_len, gid501, "res-has-:colon-in-name", FALSE);
	do_check ("test5", 502, gid502_len, gid502, "res-has-:colon-in-name", FALSE);

}

int 
main (int argc, char *argv[])
{
	int i;
	GList *l;
	GList *policies;

	testdir = g_strdup ("/tmp/policy-test-XXXXXX");
	testdir = mkdtemp (testdir);
	if (testdir == NULL) {
		g_warning ("Cannot create tmpdir, errno %d (%s)", errno, strerror (errno));
		g_free (testdir);
		exit (1);
	}

	g_message ("policy-test started; using tmpdir=%s", testdir);

	policy_util_set_policy_directory (testdir);

	do_read_tests ();

	if (policy_get_policies (&policies) != POLICY_RESULT_OK) {
		g_message ("Cannot get policies");
		goto fail;
	}
	g_print ("Loaded %d policies\n", g_list_length (policies));
	for (l = policies, i = 0; l != NULL; l = g_list_next (l), i++) {
		const char *policy;
		policy = (const char *) l->data;
		g_print (" policy %d: '%s'\n", i, policy);
	}
	g_list_foreach (policies, (GFunc) g_free, NULL);
	g_list_free (policies);

	g_print ("policy-test completed\n");

	my_exit (0);

fail:
	my_exit (1);
	return 1;
}

--- NEW FILE: run-polkitd.sh ---
#!/bin/sh

./polkitd --no-daemon --verbose





--- NEW FILE: valgrind-polkitd.sh ---
#!/bin/sh

valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./polkitd --no-daemon --verbose





More information about the hal-commit mailing list