summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2011-04-11 12:41:00 -0400
committerDavid Zeuthen <davidz@redhat.com>2011-04-11 13:24:07 -0400
commit9a44af8ab67d09a2c08be29428b8fe32da809e99 (patch)
treeafe33d83f127c615015a4d9acac2bd10bb969069
parent83a65f1255fc3eebfb4be1f80a5ab0b5f98eef7c (diff)
downloadpolkit-9a44af8ab67d09a2c08be29428b8fe32da809e99.tar.gz
Make PolkitUnixProcess also record the uid of the process
This is needed to avoid possible TOCTTOU issues since a process can change both its real uid and effective uid. Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--docs/polkit/polkit-1-sections.txt7
-rw-r--r--src/polkit/polkitsubject.c51
-rw-r--r--src/polkit/polkitunixprocess.c350
-rw-r--r--src/polkit/polkitunixprocess.h10
4 files changed, 296 insertions, 122 deletions
diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt
index ac902b6..7f42cd2 100644
--- a/docs/polkit/polkit-1-sections.txt
+++ b/docs/polkit/polkit-1-sections.txt
@@ -148,10 +148,13 @@ POLKIT_UNIX_SESSION_GET_CLASS
PolkitUnixProcess
polkit_unix_process_new
polkit_unix_process_new_full
+polkit_unix_process_new_for_owner
+polkit_unix_process_set_pid
polkit_unix_process_get_pid
+polkit_unix_process_set_start_time
polkit_unix_process_get_start_time
-polkit_unix_process_set_pid
-polkit_unix_process_get_owner
+polkit_unix_process_set_uid
+polkit_unix_process_get_uid
<SUBSECTION Standard>
PolkitUnixProcessClass
POLKIT_UNIX_PROCESS
diff --git a/src/polkit/polkitsubject.c b/src/polkit/polkitsubject.c
index d5039a5..02c707b 100644
--- a/src/polkit/polkitsubject.c
+++ b/src/polkit/polkitsubject.c
@@ -24,6 +24,7 @@
#endif
#include <string.h>
+#include <stdio.h>
#include "polkitsubject.h"
#include "polkitunixprocess.h"
@@ -209,8 +210,6 @@ polkit_subject_from_string (const gchar *str,
GError **error)
{
PolkitSubject *subject;
- guint64 val;
- gchar *endptr;
g_return_val_if_fail (str != NULL, NULL);
@@ -220,12 +219,20 @@ polkit_subject_from_string (const gchar *str,
if (g_str_has_prefix (str, "unix-process:"))
{
- val = g_ascii_strtoull (str + sizeof "unix-process:" - 1,
- &endptr,
- 10);
- if (*endptr == '\0')
+ gint scanned_pid;
+ guint64 scanned_starttime;
+ gint scanned_uid;
+ if (sscanf (str, "unix-process:%d:%" G_GUINT64_FORMAT ":%d", &scanned_pid, &scanned_starttime, &scanned_uid) == 3)
{
- subject = polkit_unix_process_new ((gint) val);
+ subject = polkit_unix_process_new_for_owner (scanned_pid, scanned_starttime, scanned_uid);
+ }
+ else if (sscanf (str, "unix-process:%d:%" G_GUINT64_FORMAT, &scanned_pid, &scanned_starttime) == 2)
+ {
+ subject = polkit_unix_process_new_full (scanned_pid, scanned_starttime);
+ }
+ else if (sscanf (str, "unix-process:%d", &scanned_pid) == 1)
+ {
+ subject = polkit_unix_process_new (scanned_pid);
if (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)) == 0)
{
g_object_unref (subject);
@@ -233,8 +240,8 @@ polkit_subject_from_string (const gchar *str,
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "No process with pid %" G_GUINT64_FORMAT,
- val);
+ "Unable to determine start time for process with pid %d",
+ scanned_pid);
}
}
}
@@ -268,6 +275,7 @@ polkit_subject_new_for_real (_PolkitSubject *real)
EggDBusHashMap *details;
EggDBusVariant *variant;
EggDBusVariant *variant2;
+ EggDBusVariant *variant3;
s = NULL;
@@ -281,10 +289,24 @@ polkit_subject_new_for_real (_PolkitSubject *real)
else if (strcmp (kind, "unix-process") == 0)
{
variant = egg_dbus_hash_map_lookup (details, "pid");
- variant2 = egg_dbus_hash_map_lookup (details, "start-time");
- if (variant != NULL && variant2 != NULL)
- s = polkit_unix_process_new_full (egg_dbus_variant_get_uint (variant),
- egg_dbus_variant_get_uint64 (variant2));
+ if (variant != NULL && egg_dbus_variant_is_uint (variant))
+ {
+ gint pid;
+ guint64 start_time;
+ gint uid;
+ variant2 = egg_dbus_hash_map_lookup (details, "start-time");
+ pid = egg_dbus_variant_get_uint (variant);
+ if (variant2 != NULL && egg_dbus_variant_is_uint64 (variant2))
+ start_time = egg_dbus_variant_get_uint64 (variant2);
+ else
+ start_time = 0;
+ variant3 = egg_dbus_hash_map_lookup (details, "uid");
+ if (variant3 != NULL && egg_dbus_variant_is_int (variant3))
+ uid = egg_dbus_variant_get_int (variant3);
+ else
+ uid = -1;
+ s = polkit_unix_process_new_for_owner (pid, start_time, uid);
+ }
}
else if (strcmp (kind, "unix-session") == 0)
{
@@ -330,6 +352,9 @@ polkit_subject_get_real (PolkitSubject *subject)
egg_dbus_hash_map_insert (details,
"start-time",
egg_dbus_variant_new_for_uint64 (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject))));
+ egg_dbus_hash_map_insert (details,
+ "uid",
+ egg_dbus_variant_new_for_int (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject))));
}
else if (POLKIT_IS_UNIX_SESSION (subject))
{
diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c
index 868e3c5..eb455f6 100644
--- a/src/polkit/polkitunixprocess.c
+++ b/src/polkit/polkitunixprocess.c
@@ -64,6 +64,7 @@ struct _PolkitUnixProcess
gint pid;
guint64 start_time;
+ gint uid;
};
struct _PolkitUnixProcessClass
@@ -76,6 +77,7 @@ enum
PROP_0,
PROP_PID,
PROP_START_TIME,
+ PROP_UID
};
static void subject_iface_init (PolkitSubjectIface *subject_iface);
@@ -83,6 +85,9 @@ static void subject_iface_init (PolkitSubjectIface *subject_iface);
static guint64 get_start_time_for_pid (gint pid,
GError **error);
+static gint _polkit_unix_process_get_owner (PolkitUnixProcess *process,
+ GError **error);
+
#ifdef HAVE_FREEBSD
static gboolean get_kinfo_proc (gint pid, struct kinfo_proc *p);
#endif
@@ -94,6 +99,7 @@ G_DEFINE_TYPE_WITH_CODE (PolkitUnixProcess, polkit_unix_process, G_TYPE_OBJECT,
static void
polkit_unix_process_init (PolkitUnixProcess *unix_process)
{
+ unix_process->uid = -1;
}
static void
@@ -110,6 +116,10 @@ polkit_unix_process_get_property (GObject *object,
g_value_set_int (value, unix_process->pid);
break;
+ case PROP_UID:
+ g_value_set_int (value, unix_process->uid);
+ break;
+
case PROP_START_TIME:
g_value_set_uint64 (value, unix_process->start_time);
break;
@@ -134,6 +144,14 @@ polkit_unix_process_set_property (GObject *object,
polkit_unix_process_set_pid (unix_process, g_value_get_int (value));
break;
+ case PROP_UID:
+ polkit_unix_process_set_uid (unix_process, g_value_get_int (value));
+ break;
+
+ case PROP_START_TIME:
+ polkit_unix_process_set_start_time (unix_process, g_value_get_uint64 (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -141,12 +159,39 @@ polkit_unix_process_set_property (GObject *object,
}
static void
+polkit_unix_process_constructed (GObject *object)
+{
+ PolkitUnixProcess *process = POLKIT_UNIX_PROCESS (object);
+
+ /* sets start_time and uid in case they are unset */
+
+ if (process->start_time == 0)
+ process->start_time = get_start_time_for_pid (process->pid, NULL);
+
+ if (process->uid == -1)
+ {
+ GError *error;
+ error = NULL;
+ process->uid = _polkit_unix_process_get_owner (process, &error);
+ if (error != NULL)
+ {
+ process->uid = -1;
+ g_error_free (error);
+ }
+ }
+
+ if (G_OBJECT_CLASS (polkit_unix_process_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (polkit_unix_process_parent_class)->constructed (object);
+}
+
+static void
polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = polkit_unix_process_get_property;
gobject_class->set_property = polkit_unix_process_set_property;
+ gobject_class->constructed = polkit_unix_process_constructed;
/**
* PolkitUnixProcess:pid:
@@ -158,7 +203,7 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
g_param_spec_int ("pid",
"Process ID",
"The UNIX process ID",
- -1,
+ 0,
G_MAXINT,
0,
G_PARAM_CONSTRUCT |
@@ -168,6 +213,27 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
G_PARAM_STATIC_NICK));
/**
+ * PolkitUnixProcess:uid:
+ *
+ * The UNIX user id of the process or -1 if unknown.
+ *
+ * Note that this is the real user-id, not the effective user-id.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_UID,
+ g_param_spec_int ("uid",
+ "User ID",
+ "The UNIX user ID",
+ -1,
+ G_MAXINT,
+ -1,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
* PolkitUnixProcess:start-time:
*
* The start time of the process.
@@ -180,7 +246,8 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
0,
G_MAXUINT64,
0,
- G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK));
@@ -188,109 +255,50 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
}
/**
- * polkit_unix_process_get_pid:
+ * polkit_unix_process_get_uid:
* @process: A #PolkitUnixProcess.
*
- * Gets the process id for @process.
+ * Gets the user id for @process. Note that this is the real user-id,
+ * not the effective user-id.
*
- * Returns: The process id for @process.
+ * Returns: The user id for @process or -1 if unknown.
*/
gint
-polkit_unix_process_get_pid (PolkitUnixProcess *process)
+polkit_unix_process_get_uid (PolkitUnixProcess *process)
{
- return process->pid;
+ g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), -1);
+ return process->uid;
}
/**
- * polkit_unix_process_get_owner:
+ * polkit_unix_process_set_uid:
* @process: A #PolkitUnixProcess.
- * @error: Return location for error or %NULL.
+ * @uid: The user id to set for @process or -1 to unset it.
*
- * Gets the uid of the owner of @process.
+ * Sets the (real, not effective) user id for @process.
+ */
+void
+polkit_unix_process_set_uid (PolkitUnixProcess *process,
+ gint uid)
+{
+ g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
+ g_return_if_fail (uid >= -1);
+ process->uid = uid;
+}
+
+/**
+ * polkit_unix_process_get_pid:
+ * @process: A #PolkitUnixProcess.
*
- * Note that this returns the real user-id (not the effective user-id) of @process.
+ * Gets the process id for @process.
*
- * Returns: The UNIX user id of the owner for @process or 0 if @error is set.
- **/
+ * Returns: The process id for @process.
+ */
gint
-polkit_unix_process_get_owner (PolkitUnixProcess *process,
- GError **error)
+polkit_unix_process_get_pid (PolkitUnixProcess *process)
{
- gint result;
- gchar *contents;
- gchar **lines;
-#ifdef HAVE_FREEBSD
- struct kinfo_proc p;
-#else
- gchar filename[64];
- guint n;
-#endif
-
- result = 0;
- lines = NULL;
- contents = NULL;
-
-#ifdef HAVE_FREEBSD
- if (get_kinfo_proc (process->pid, &p) == 0)
- {
- g_set_error (error,
- POLKIT_ERROR,
- POLKIT_ERROR_FAILED,
- "get_kinfo_proc() failed for pid %d: %s",
- process->pid,
- g_strerror (errno));
- goto out;
- }
-
- result = p.ki_uid;
-#else
- /* see 'man proc' for layout of the status file
- *
- * Uid, Gid: Real, effective, saved set, and file system UIDs (GIDs).
- */
- g_snprintf (filename, sizeof filename, "/proc/%d/status", process->pid);
- if (!g_file_get_contents (filename,
- &contents,
- NULL,
- error))
- {
- goto out;
- }
- lines = g_strsplit (contents, "\n", -1);
- for (n = 0; lines != NULL && lines[n] != NULL; n++)
- {
- gint real_uid, effective_uid;
- if (!g_str_has_prefix (lines[n], "Uid:"))
- continue;
- if (sscanf (lines[n] + 4, "%d %d", &real_uid, &effective_uid) != 2)
- {
- g_set_error (error,
- POLKIT_ERROR,
- POLKIT_ERROR_FAILED,
- "Unexpected line `%s' in file %s",
- lines[n],
- filename);
- goto out;
- }
- else
- {
- result = real_uid;
- goto out;
- }
- }
-
- g_set_error (error,
- POLKIT_ERROR,
- POLKIT_ERROR_FAILED,
- "Didn't find any line starting with `Uid:' in file %s",
- filename);
-#endif
-
- out:
- g_strfreev (lines);
- g_free (contents);
-
- return result;
+ g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
+ return process->pid;
}
/**
@@ -304,10 +312,26 @@ polkit_unix_process_get_owner (PolkitUnixProcess *process,
guint64
polkit_unix_process_get_start_time (PolkitUnixProcess *process)
{
+ g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
return process->start_time;
}
/**
+ * polkit_unix_process_set_start_time:
+ * @process: A #PolkitUnixProcess.
+ * @start_time: The start time for @pid.
+ *
+ * Set the start time of @process.
+ */
+void
+polkit_unix_process_set_start_time (PolkitUnixProcess *process,
+ guint64 start_time)
+{
+ g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
+ process->start_time = start_time;
+}
+
+/**
* polkit_unix_process_set_pid:
* @process: A #PolkitUnixProcess.
* @pid: A process id.
@@ -318,21 +342,21 @@ void
polkit_unix_process_set_pid (PolkitUnixProcess *process,
gint pid)
{
+ g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
process->pid = pid;
- if (pid != (gint) -1)
- process->start_time = get_start_time_for_pid (pid, NULL);
}
/**
* polkit_unix_process_new:
* @pid: The process id.
*
- * Creates a new #PolkitUnixProcess for @pid. The start time of the
- * process will be looked up in using e.g. the
- * <filename>/proc</filename> filesystem depending on the platform in
- * use.
+ * Creates a new #PolkitUnixProcess for @pid.
*
- * Returns: A #PolkitSubject. Free with g_object_unref().
+ * The uid and start time of the process will be looked up in using
+ * e.g. the <filename>/proc</filename> filesystem depending on the
+ * platform in use.
+ *
+ * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
*/
PolkitSubject *
polkit_unix_process_new (gint pid)
@@ -349,22 +373,42 @@ polkit_unix_process_new (gint pid)
*
* Creates a new #PolkitUnixProcess object for @pid and @start_time.
*
- * Returns: A #PolkitSubject. Free with g_object_unref().
+ * The uid of the process will be looked up in using e.g. the
+ * <filename>/proc</filename> filesystem depending on the platform in
+ * use.
+ *
+ * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
*/
PolkitSubject *
polkit_unix_process_new_full (gint pid,
guint64 start_time)
{
- PolkitUnixProcess *process;
-
- process = POLKIT_UNIX_PROCESS (polkit_unix_process_new ((gint) -1));
- process->pid = pid;
- if (start_time != 0)
- process->start_time = start_time;
- else
- process->start_time = get_start_time_for_pid (pid, NULL);
+ return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_PROCESS,
+ "pid", pid,
+ "start_time", start_time,
+ NULL));
+}
- return POLKIT_SUBJECT (process);
+/**
+ * polkit_unix_process_new_for_owner:
+ * @pid: The process id.
+ * @start_time: The start time for @pid or 0 to look it up in e.g. <filename>/proc</filename>.
+ * @uid: The (real, not effective) uid of the owner of @pid or -1 to look it up in e.g. <filename>/proc</filename>.
+ *
+ * Creates a new #PolkitUnixProcess object for @pid, @start_time and @uid.
+ *
+ * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
+ */
+PolkitSubject *
+polkit_unix_process_new_for_owner (gint pid,
+ guint64 start_time,
+ gint uid)
+{
+ return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_PROCESS,
+ "pid", pid,
+ "start_time", start_time,
+ "uid", uid,
+ NULL));
}
static guint
@@ -612,3 +656,95 @@ out:
return start_time;
}
+
+static gint
+_polkit_unix_process_get_owner (PolkitUnixProcess *process,
+ GError **error)
+{
+ gint result;
+ gchar *contents;
+ gchar **lines;
+#ifdef HAVE_FREEBSD
+ struct kinfo_proc p;
+#else
+ gchar filename[64];
+ guint n;
+#endif
+
+ g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
+ g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+ result = 0;
+ lines = NULL;
+ contents = NULL;
+
+#ifdef HAVE_FREEBSD
+ if (get_kinfo_proc (process->pid, &p) == 0)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "get_kinfo_proc() failed for pid %d: %s",
+ process->pid,
+ g_strerror (errno));
+ goto out;
+ }
+
+ result = p.ki_uid;
+#else
+
+ /* see 'man proc' for layout of the status file
+ *
+ * Uid, Gid: Real, effective, saved set, and file system UIDs (GIDs).
+ */
+ g_snprintf (filename, sizeof filename, "/proc/%d/status", process->pid);
+ if (!g_file_get_contents (filename,
+ &contents,
+ NULL,
+ error))
+ {
+ goto out;
+ }
+ lines = g_strsplit (contents, "\n", -1);
+ for (n = 0; lines != NULL && lines[n] != NULL; n++)
+ {
+ gint real_uid, effective_uid;
+ if (!g_str_has_prefix (lines[n], "Uid:"))
+ continue;
+ if (sscanf (lines[n] + 4, "%d %d", &real_uid, &effective_uid) != 2)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Unexpected line `%s' in file %s",
+ lines[n],
+ filename);
+ goto out;
+ }
+ else
+ {
+ result = real_uid;
+ goto out;
+ }
+ }
+
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Didn't find any line starting with `Uid:' in file %s",
+ filename);
+#endif
+
+out:
+ g_strfreev (lines);
+ g_free (contents);
+ return result;
+}
+
+/* deprecated public method */
+gint
+polkit_unix_process_get_owner (PolkitUnixProcess *process,
+ GError **error)
+{
+ return _polkit_unix_process_get_owner (process, error);
+}
diff --git a/src/polkit/polkitunixprocess.h b/src/polkit/polkitunixprocess.h
index b88cd03..68c7fd7 100644
--- a/src/polkit/polkitunixprocess.h
+++ b/src/polkit/polkitunixprocess.h
@@ -50,11 +50,21 @@ GType polkit_unix_process_get_type (void) G_GNUC_CONST;
PolkitSubject *polkit_unix_process_new (gint pid);
PolkitSubject *polkit_unix_process_new_full (gint pid,
guint64 start_time);
+PolkitSubject *polkit_unix_process_new_for_owner (gint pid,
+ guint64 start_time,
+ gint uid);
gint polkit_unix_process_get_pid (PolkitUnixProcess *process);
+gint polkit_unix_process_get_uid (PolkitUnixProcess *process);
guint64 polkit_unix_process_get_start_time (PolkitUnixProcess *process);
void polkit_unix_process_set_pid (PolkitUnixProcess *process,
gint pid);
+void polkit_unix_process_set_uid (PolkitUnixProcess *process,
+ gint uid);
+void polkit_unix_process_set_start_time (PolkitUnixProcess *process,
+ guint64 start_time);
+
+G_GNUC_DEPRECATED
gint polkit_unix_process_get_owner (PolkitUnixProcess *process,
GError **error);