Commit message: None
CVE: CVE-2018-14036
CWE: CWE-22
Vulnerability description: Directory Traversal with ../ sequences occurs in AccountsService before 0.6.50 because of an insufficient path check in user_change_icon_file_authorized_cb() in user.c.

Project: accountsservice

save_extra_data (User *user)
{
        g_autofree gchar *data = NULL;
        g_autofree gchar *filename = NULL;
        g_autoptr(GError) error = NULL;

        user_save_to_keyfile (user, user->keyfile);

        data = g_key_file_to_data (user->keyfile, NULL, &error);
        if (data == NULL) {
                g_warning ("Saving data for user %s failed: %s",
                           accounts_user_get_user_name (ACCOUNTS_USER (user)), error->message);
                return;
        }

        filename = g_build_filename (USERDIR,
                                     accounts_user_get_user_name (ACCOUNTS_USER (user)),
                                     NULL);
        g_file_set_contents (filename, data, -1, &error);
}

Project: accountsservice

user_change_real_name_authorized_cb (Daemon                *daemon,
                                     User                  *user,
                                     GDBusMethodInvocation *context,
                                     gpointer               data)

{
        gchar *name = data;
        g_autoptr(GError) error = NULL;
        const gchar *argv[6];

        if (g_strcmp0 (accounts_user_get_real_name (ACCOUNTS_USER (user)), name) != 0) {
                sys_log (context,
                         "change real name of user '%s' (%d) to '%s'",
                         accounts_user_get_user_name (ACCOUNTS_USER (user)),
                         accounts_user_get_uid (ACCOUNTS_USER (user)),
                         name);

                argv[0] = "/usr/sbin/usermod";
                argv[1] = "-c";
                argv[2] = name;
                argv[3] = "--";
                argv[4] = accounts_user_get_user_name (ACCOUNTS_USER (user));
                argv[5] = NULL;

                if (!spawn_with_login_uid (context, argv, &error)) {
                        throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
                        return;
                }

                accounts_user_set_real_name (ACCOUNTS_USER (user), name);
        }

        accounts_user_complete_set_real_name (ACCOUNTS_USER (user), context);
}

Project: accountsservice

user_extension_authentication_done (Daemon                *daemon,
                                    User                  *user,
                                    GDBusMethodInvocation *invocation,
                                    gpointer               user_data)
{
        GDBusInterfaceInfo *interface = user_data;
        const gchar *method_name;

        method_name = g_dbus_method_invocation_get_method_name (invocation);

        if (g_str_equal (method_name, "Get"))
                user_extension_get_property (user, daemon, interface, invocation);
        else if (g_str_equal (method_name, "GetAll"))
                user_extension_get_all_properties (user, daemon, interface, invocation);
        else if (g_str_equal (method_name, "Set"))
                user_extension_set_property (user, daemon, interface, invocation);
        else
                g_assert_not_reached ();
}

Project: accountsservice

user_extension_get_all_properties (User                  *user,
                                   Daemon                *daemon,
                                   GDBusInterfaceInfo    *interface,
                                   GDBusMethodInvocation *invocation)
{
        GVariantBuilder builder;
        gint i;

        g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
        for (i = 0; interface->properties && interface->properties[i]; i++) {
                GDBusPropertyInfo *property = interface->properties[i];
                g_autoptr(GVariant) value = NULL;

                value = user_extension_get_value (user, interface, property);

                if (value)
                        g_variant_builder_add (&builder, "{sv}", property->name, value);
        }

        g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{sv})", &builder));
}

Project: accountsservice

user_unregister (User *user)
{
        g_signal_handlers_disconnect_by_func (G_OBJECT (user), G_CALLBACK (on_user_property_notify), NULL);

        g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (user));

        if (user->extension_ids) {
                guint i;

                for (i = 0; i < user->n_extension_ids; i++) {
                        /* In theory, if an error happened during registration, we could have 0 here. */
                        if (user->extension_ids[i] == 0)
                                continue;

                        g_dbus_connection_unregister_object (user->system_bus_connection, user->extension_ids[i]);
                }

                g_clear_pointer (&user->extension_ids, g_free);
                user->n_extension_ids = 0;
        }
}