Ejemplo n.º 1
0
static gboolean
begin_write_state (GkmMate2Storage *self, GkmTransaction *transaction)
{
    g_assert (GKM_IS_MATE2_STORAGE (self));
    g_assert (GKM_IS_TRANSACTION (transaction));

    g_return_val_if_fail (!gkm_transaction_get_failed (transaction), FALSE);

    /* Already in write state for this transaction? */
    if (self->transaction != NULL) {
        g_return_val_if_fail (self->transaction == transaction, FALSE);
        return TRUE;
    }

    /* Lock file for the transaction */
    self->read_fd = begin_lock_file (self, transaction);
    if (self->read_fd == -1)
        return FALSE;

    gkm_transaction_add (transaction, self, complete_write_state, NULL);
    self->transaction = g_object_ref (transaction);

    /* Open the new file */
    g_assert (self->write_fd == -1);
    self->write_path = g_strdup_printf ("%s.XXXXXX", self->filename);
    self->write_fd = g_mkstemp (self->write_path);
    if (self->write_fd == -1) {
        g_message ("couldn't open new temporary store file: %s: %s", self->write_path, g_strerror (errno));
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        return FALSE;
    }

    return TRUE;
}
void
gkm_object_destroy (GkmObject *self, GkmTransaction *transaction)
{
	GkmSession *session;
	GkmManager *manager;
	GkmModule *module;

	g_return_if_fail (GKM_IS_OBJECT (self));
	g_return_if_fail (GKM_IS_TRANSACTION (transaction));
	g_return_if_fail (!gkm_transaction_get_failed (transaction));
	g_return_if_fail (self->pv->module);

	g_object_ref (self);

	session = gkm_session_for_session_object (self);
	if (session != NULL) {
		gkm_session_destroy_session_object (session, transaction, self);
	} else {
		manager = gkm_object_get_manager (self);
		module = gkm_object_get_module (self);
		if (manager == gkm_module_get_manager (module))
			gkm_module_remove_token_object (module, transaction, self);
	}

	/* Forcefully dispose of the object once the transaction completes */
	gkm_transaction_add (transaction, NULL, complete_destroy, g_object_ref (self));

	g_object_unref (self);
}
Ejemplo n.º 3
0
static gboolean
complete_modification_state (GkmTransaction *transaction, GObject *object, gpointer unused)
{
    GkmMate2Storage *self = GKM_MATE2_STORAGE (object);
    GkmDataResult res;

    if (!gkm_transaction_get_failed (transaction)) {
        res = gkm_mate2_file_write_fd (self->file, self->write_fd, self->login);
        switch(res) {
        case GKM_DATA_FAILURE:
        case GKM_DATA_UNRECOGNIZED:
            g_warning ("couldn't write to temporary store file: %s", self->write_path);
            return FALSE;
        case GKM_DATA_LOCKED:
            g_warning ("couldn't encrypt temporary store file: %s", self->write_path);
            return FALSE;
        case GKM_DATA_SUCCESS:
            break;
        default:
            g_assert_not_reached ();
        }
    }

    return TRUE;
}
Ejemplo n.º 4
0
static void
gkm_secret_item_real_set_attribute (GkmObject *base, GkmSession *session,
                                    GkmTransaction *transaction, CK_ATTRIBUTE_PTR attr)
{
	GkmSecretItem *self = GKM_SECRET_ITEM (base);
	const gchar *identifier;
	GkmSecretData *sdata;
	GHashTable *fields;
	gchar *schema_name;
	GkmSecret *secret;
	gchar *schema;
	CK_RV rv;

	if (!self->collection) {
		gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
		g_return_if_reached ();
	}

	/* Check that the object is not locked */
	if (!gkm_secret_collection_unlocked_have (self->collection, session)) {
		gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
		return;
	}

	switch (attr->type) {
	case CKA_VALUE:
		sdata = gkm_secret_collection_unlocked_use (self->collection, session);
		g_return_if_fail (sdata);
		identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (self));
		secret = gkm_secret_new (attr->pValue, attr->ulValueLen);
		gkm_secret_data_set_transacted (sdata, transaction, identifier, secret);
		g_object_unref (secret);
		g_object_unref (sdata);
		gkm_secret_object_begin_modified (GKM_SECRET_OBJECT (self), transaction);
		if (!gkm_transaction_get_failed (transaction))
			gkm_transaction_add (transaction, self, complete_set_secret, NULL);
		return;

	case CKA_G_FIELDS:
		rv = gkm_secret_fields_parse (attr, &fields, &schema_name);
		if (rv != CKR_OK) {
			gkm_transaction_fail (transaction, rv);
		} else {
			begin_set_fields (self, transaction, fields);
			if (schema_name)
				begin_set_schema (self, transaction, schema_name);
		}
		return;

	case CKA_G_SCHEMA:
		rv = gkm_attribute_get_string (attr, &schema);
		if (rv != CKR_OK)
			gkm_transaction_fail (transaction, rv);
		else
			begin_set_schema (self, transaction, schema);
		return;
	}

	GKM_OBJECT_CLASS (gkm_secret_item_parent_class)->set_attribute (base, session, transaction, attr);
}
Ejemplo n.º 5
0
void
gkm_mate2_storage_destroy (GkmMate2Storage *self, GkmTransaction *transaction, GkmObject *object)
{
    GkmDataResult res;
    gchar *identifier;
    gchar *path;

    g_return_if_fail (GKM_IS_MATE2_STORAGE (self));
    g_return_if_fail (GKM_IS_TRANSACTION (transaction));
    g_return_if_fail (!gkm_transaction_get_failed (transaction));
    g_return_if_fail (object);

    /* Lookup the object identifier */
    identifier = g_hash_table_lookup (self->object_to_identifier, object);
    g_return_if_fail (identifier);

    if (!begin_modification_state (self, transaction))
        return;

    /* First actually delete the file */
    path = g_build_filename (self->directory, identifier, NULL);
    gkm_transaction_remove_file (transaction, path);
    g_free (path);

    if (gkm_transaction_get_failed (transaction))
        return;

    /* Now delete the entry from our store */
    res = gkm_mate2_file_destroy_entry (self->file, identifier);
    switch(res) {
    case GKM_DATA_FAILURE:
    case GKM_DATA_UNRECOGNIZED:
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        return;
    case GKM_DATA_LOCKED:
        gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
        return;
    case GKM_DATA_SUCCESS:
        break;
    default:
        g_assert_not_reached ();
    }

    /* Actual removal of object happened as a callback above */
    g_return_if_fail (g_hash_table_lookup (self->object_to_identifier, object) == NULL);
}
static gboolean
complete_transient_add (GkmTransaction *transaction, GkmModule *self, GkmObject *object)
{
	if (gkm_transaction_get_failed (transaction))
		remove_transient_object (self, NULL, object);
	g_object_unref (object);
	return TRUE;
}
Ejemplo n.º 7
0
static gboolean
complete_set_secret (GkmTransaction *transaction, GObject *obj, gpointer user_data)
{
	if (!gkm_transaction_get_failed (transaction)) {
		gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_VALUE);
	}

	return TRUE;
}
Ejemplo n.º 8
0
static void
begin_set_fields (GkmSecretItem *self, GkmTransaction *transaction, GHashTable *fields)
{
	g_assert (GKM_IS_SECRET_OBJECT (self));
	g_assert (!gkm_transaction_get_failed (transaction));

	gkm_transaction_add (transaction, self, complete_set_fields, self->fields);
	self->fields = fields;
}
static void
begin_set_label (GkmSecretObject *self, GkmTransaction *transaction, gchar *label)
{
	g_assert (GKM_IS_SECRET_OBJECT (self));
	g_assert (!gkm_transaction_get_failed (transaction));

	gkm_transaction_add (transaction, self, complete_set_label, self->pv->label);
	self->pv->label = label;
}
Ejemplo n.º 10
0
static gboolean
begin_new_file (GkmTransaction *self, const gchar *filename)
{
	g_assert (GKM_IS_TRANSACTION (self));
	g_assert (!gkm_transaction_get_failed (self));
	g_assert (filename);

	gkm_transaction_add (self, NULL, complete_new_file, g_strdup (filename));
	return TRUE;
}
static gboolean
complete_expose (GkmTransaction *transaction, GObject *obj, gpointer user_data)
{
	GkmObject *self = GKM_OBJECT (obj);
	gboolean expose = GPOINTER_TO_UINT (user_data);

	if (gkm_transaction_get_failed (transaction))
		gkm_object_expose (self, !expose);

	return TRUE;
}
Ejemplo n.º 12
0
static void
begin_set_schema (GkmSecretItem *self, GkmTransaction *transaction, gchar *schema)
{
	g_assert (GKM_IS_SECRET_OBJECT (self));
	g_assert (!gkm_transaction_get_failed (transaction));

	if (self->schema != schema) {
		gkm_transaction_add (transaction, self, complete_set_schema, self->schema);
		self->schema = schema;
	}
}
Ejemplo n.º 13
0
static gboolean
complete_set_secret (GkmTransaction *transaction, GObject *obj, gpointer user_data)
{
	GkmSecretItem *self = GKM_SECRET_ITEM (obj);

	if (!gkm_transaction_get_failed (transaction)) {
		gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_VALUE);
		gkm_secret_object_was_modified (GKM_SECRET_OBJECT (self));
	}

	return TRUE;
}
Ejemplo n.º 14
0
static gboolean
complete_add_assertion (GkmTransaction *transaction, GObject *object, gpointer user_data)
{
	GkmAssertion *assertion = GKM_ASSERTION (user_data);
	GkmXdgTrust *self = GKM_XDG_TRUST (object);

	if (gkm_transaction_get_failed (transaction))
		remove_assertion_from_trust (self, assertion, NULL);

	g_object_unref (assertion);
	return TRUE;
}
Ejemplo n.º 15
0
static gint
begin_lock_file (GkmMate2Storage *self, GkmTransaction *transaction)
{
    guint tries = 0;
    gint fd = -1;

    /*
     * In this function we don't actually put the object into a 'write' state,
     * that's the callers job if necessary.
     */

    g_assert (GKM_IS_MATE2_STORAGE (self));
    g_assert (GKM_IS_TRANSACTION (transaction));

    g_return_val_if_fail (!gkm_transaction_get_failed (transaction), -1);

    /* File lock retry loop */
    for (tries = 0; TRUE; ++tries) {
        if (tries > MAX_LOCK_TRIES) {
            g_message ("couldn't write to store file: %s: file is locked", self->filename);
            gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
            return -1;
        }

        fd = open (self->filename, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
        if (fd == -1) {
            g_message ("couldn't open store file: %s: %s", self->filename, g_strerror (errno));
            gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
            return -1;
        }

        if (flock (fd, LOCK_EX | LOCK_NB) < 0) {
            if (errno != EWOULDBLOCK) {
                g_message ("couldn't lock store file: %s: %s", self->filename, g_strerror (errno));
                close (fd);
                gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
                return -1;
            }

            close (fd);
            fd = -1;
            g_usleep (200000);
            continue;
        }

        /* Successfully opened file */;
        gkm_transaction_add (transaction, self, complete_lock_file, GINT_TO_POINTER (fd));
        return fd;
    }

    g_assert_not_reached ();
}
Ejemplo n.º 16
0
static void
gkm_mate2_storage_real_write_value (GkmStore *base, GkmTransaction *transaction, GkmObject *object, CK_ATTRIBUTE_PTR attr)
{
    GkmMate2Storage *self = GKM_MATE2_STORAGE (base);
    const gchar *identifier;
    GkmDataResult res;
    CK_RV rv;

    g_return_if_fail (GKM_IS_MATE2_STORAGE (self));
    g_return_if_fail (GKM_IS_OBJECT (object));
    g_return_if_fail (GKM_IS_TRANSACTION (transaction));
    g_return_if_fail (!gkm_transaction_get_failed (transaction));
    g_return_if_fail (attr);

    identifier = g_hash_table_lookup (self->object_to_identifier, object);
    if (!identifier) {
        gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
        return;
    }

    if (self->last_mtime == 0) {
        rv = gkm_mate2_storage_refresh (self);
        if (rv != CKR_OK) {
            gkm_transaction_fail (transaction, rv);
            return;
        }
    }

    res = gkm_mate2_file_write_value (self->file, identifier, attr->type, attr->pValue, attr->ulValueLen);
    switch (res) {
    case GKM_DATA_FAILURE:
        rv = CKR_FUNCTION_FAILED;
        break;
    case GKM_DATA_UNRECOGNIZED:
        rv = CKR_ATTRIBUTE_READ_ONLY;
        break;
    case GKM_DATA_LOCKED:
        rv = CKR_USER_NOT_LOGGED_IN;
        break;
    case GKM_DATA_SUCCESS:
        rv = CKR_OK;
        break;
    default:
        g_assert_not_reached ();
    }

    if (rv != CKR_OK)
        gkm_transaction_fail (transaction, rv);
}
void
gkm_object_set_attribute (GkmObject *self, GkmSession *session,
                          GkmTransaction *transaction, CK_ATTRIBUTE_PTR attr)
{
	g_return_if_fail (GKM_IS_OBJECT (self));
	g_return_if_fail (GKM_IS_TRANSACTION (transaction));
	g_return_if_fail (!gkm_transaction_get_failed (transaction));
	g_return_if_fail (attr);

	g_assert (GKM_OBJECT_GET_CLASS (self)->set_attribute);

	/* Check that the value will actually change */
	if (!gkm_object_match (self, session, attr))
		GKM_OBJECT_GET_CLASS (self)->set_attribute (self, session, transaction, attr);
}
void
gkm_object_create_attributes (GkmObject *self, GkmSession *session, GkmTransaction *transaction,
                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
	g_return_if_fail (GKM_IS_OBJECT (self));
	g_return_if_fail (GKM_IS_TRANSACTION (transaction));
	g_return_if_fail (!gkm_transaction_get_failed (transaction));
	g_return_if_fail (GKM_IS_SESSION (session));
	g_return_if_fail (attrs);

	g_assert (GKM_OBJECT_GET_CLASS (self)->create_attributes);

	/* Check that the value will actually change */
	GKM_OBJECT_GET_CLASS (self)->create_attributes (self, session, transaction, attrs, n_attrs);
}
void
gkm_object_expose_full (GkmObject *self, GkmTransaction *transaction, gboolean expose)
{
	if (!expose && !self)
		return;

	g_return_if_fail (GKM_IS_OBJECT (self));
	g_return_if_fail (!transaction || !gkm_transaction_get_failed (transaction));

	if (self->pv->exposed != expose) {
		if (transaction)
			gkm_transaction_add (transaction, self, complete_expose, GUINT_TO_POINTER (expose));
		gkm_object_expose (self, expose);
	}
}
Ejemplo n.º 20
0
static gboolean
complete_new_file (GkmTransaction *self, GObject *unused, gpointer user_data)
{
	gchar *path = user_data;
	gboolean ret = TRUE;

	if (gkm_transaction_get_failed (self)) {
		if (g_unlink (path) < 0) {
			g_warning ("couldn't delete aborted file, data may be lost: %s: %s",
			           path, g_strerror (errno));
			ret = FALSE;
		}
	}

	g_free (path);
	return ret;
}
Ejemplo n.º 21
0
static gboolean
complete_set_schema (GkmTransaction *transaction, GObject *obj, gpointer user_data)
{
	GkmSecretItem *self = GKM_SECRET_ITEM (obj);
	gchar *old_schema = user_data;

	if (gkm_transaction_get_failed (transaction)) {
		g_free (self->schema);
		self->schema = old_schema;
	} else {
		gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_G_SCHEMA);
		g_object_notify (G_OBJECT (obj), "schema");
		g_free (old_schema);
	}

	return TRUE;
}
static gboolean
complete_set_label (GkmTransaction *transaction, GObject *obj, gpointer user_data)
{
	GkmSecretObject *self = GKM_SECRET_OBJECT (obj);
	gchar *old_label = user_data;

	if (gkm_transaction_get_failed (transaction)) {
		g_free (self->pv->label);
		self->pv->label = old_label;
	} else {
		gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_LABEL);
		g_object_notify (G_OBJECT (obj), "label");
		gkm_secret_object_was_modified (self);
		g_free (old_label);
	}

	return TRUE;
}
Ejemplo n.º 23
0
static gboolean
complete_set_fields (GkmTransaction *transaction, GObject *obj, gpointer user_data)
{
	GkmSecretItem *self = GKM_SECRET_ITEM (obj);
	GHashTable *old_fields = user_data;

	if (gkm_transaction_get_failed (transaction)) {
		if (self->fields)
			g_hash_table_unref (self->fields);
		self->fields = old_fields;
	} else {
		gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_G_FIELDS);
		g_object_notify (G_OBJECT (obj), "fields");
		if (old_fields)
			g_hash_table_unref (old_fields);
	}

	return TRUE;
}
Ejemplo n.º 24
0
static void
relock_each_object (GkmMate2File *file, const gchar *identifier, gpointer data)
{
    RelockArgs *args = data;
    gchar *path;
    guint section;

    g_assert (GKM_IS_MATE2_STORAGE (args->self));
    if (gkm_transaction_get_failed (args->transaction))
        return;

    if (!gkm_mate2_file_lookup_entry (file, identifier, &section))
        g_return_if_reached ();

    /* Only operate on private files */
    if (section != GKM_MATE2_FILE_SECTION_PRIVATE)
        return;

    path = g_build_filename (args->self->directory, identifier, NULL);
    relock_object (args->self, args->transaction, path, identifier, args->old_login, args->new_login);
    g_free (path);
}
Ejemplo n.º 25
0
static gboolean
complete_link_temporary (GkmTransaction *self, GObject *unused, gpointer user_data)
{
	gchar *path = user_data;
	gboolean ret = TRUE;
	gchar *original;
	gchar *ext;

	/* When failed, rename temporary back */
	if (gkm_transaction_get_failed (self)) {

		/* Figure out the original file name */
		original = g_strdup (path);
		ext = strrchr (original, '.');
		g_return_val_if_fail (ext, FALSE);
		*ext = '\0';

		/* Now rename us back */
		if (g_rename (path, original) == -1) {
			g_warning ("couldn't restore original file, data may be lost: %s: %s",
			           original, g_strerror (errno));
			ret = FALSE;
		}

		g_free (original);

	/* When succeeded, remove temporary */
	} else {
		if (g_unlink (path) == -1) {
			g_warning ("couldn't delete temporary backup file: %s: %s",
			           path, g_strerror (errno));
			ret = TRUE; /* Not actually that bad of a situation */
		}
	}

	g_free (path);
	return ret;
}
Ejemplo n.º 26
0
static gboolean
complete_write_state (GkmTransaction *transaction, GObject *object, gpointer unused)
{
    GkmMate2Storage *self = GKM_MATE2_STORAGE (object);
    gboolean ret = TRUE;
    struct stat sb;

    g_return_val_if_fail (GKM_IS_MATE2_STORAGE (object), FALSE);
    g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), FALSE);
    g_return_val_if_fail (self->transaction == transaction, FALSE);

    /* Transaction succeeded, overwrite the old with the new */
    if (!gkm_transaction_get_failed (transaction)) {

        if (g_rename (self->write_path, self->filename) == -1) {
            g_warning ("couldn't rename temporary store file: %s", self->write_path);
            ret = FALSE;
        } else {
            if (fstat (self->write_fd, &sb) >= 0)
                self->last_mtime = sb.st_mtime;
        }
    }

    /* read_fd is closed by complete_lock_file */

    if (self->write_fd != -1)
        close (self->write_fd);
    self->write_fd = -1;

    g_free (self->write_path);
    self->write_path = NULL;

    g_object_unref (self->transaction);
    self->transaction = NULL;

    return ret;
}
Ejemplo n.º 27
0
void
gkm_mate2_storage_create (GkmMate2Storage *self, GkmTransaction *transaction, GkmObject *object)
{
    gboolean is_private;
    GkmDataResult res;
    gchar *identifier;
    gpointer data;
    gsize n_data;
    gchar *path;

    g_return_if_fail (GKM_IS_MATE2_STORAGE (self));
    g_return_if_fail (GKM_IS_TRANSACTION (transaction));
    g_return_if_fail (!gkm_transaction_get_failed (transaction));
    g_return_if_fail (GKM_IS_OBJECT (object));

    /* Make sure we haven't already stored it */
    identifier = g_hash_table_lookup (self->object_to_identifier, object);
    g_return_if_fail (identifier == NULL);

    /* Double check that the object is in fact serializable */
    if (!GKM_IS_SERIALIZABLE (object)) {
        g_warning ("can't store object of type '%s' on token", G_OBJECT_TYPE_NAME (object));
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        g_return_if_reached ();
    }

    /* Figure out whether this is a private object */
    if (!gkm_object_get_attribute_boolean (object, NULL, CKA_PRIVATE, &is_private))
        is_private = FALSE;

    /* Can't serialize private if we're not unlocked */
    if (is_private && !self->login) {
        gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
        return;
    }

    /* Hook ourselves into the transaction */
    if (!begin_modification_state (self, transaction))
        return;

    /* Create an identifier guaranteed unique by this transaction */
    identifier = identifier_for_object (object);
    if (gkm_mate2_file_unique_entry (self->file, &identifier) != GKM_DATA_SUCCESS) {
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        g_return_if_reached ();
    }

    /* We don't want to get signals about this item being added */
    g_signal_handlers_block_by_func (self->file, data_file_entry_added, self);
    g_signal_handlers_block_by_func (self->file, data_file_entry_changed, self);

    res = gkm_mate2_file_create_entry (self->file, identifier,
                                       is_private ? GKM_MATE2_FILE_SECTION_PRIVATE : GKM_MATE2_FILE_SECTION_PUBLIC);

    g_signal_handlers_unblock_by_func (self->file, data_file_entry_added, self);
    g_signal_handlers_unblock_by_func (self->file, data_file_entry_changed, self);

    switch(res) {
    case GKM_DATA_FAILURE:
    case GKM_DATA_UNRECOGNIZED:
        g_free (identifier);
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        return;
    case GKM_DATA_LOCKED:
        g_free (identifier);
        gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
        return;
    case GKM_DATA_SUCCESS:
        break;
    default:
        g_assert_not_reached ();
    }

    /* Serialize the object in question */
    if (!gkm_serializable_save (GKM_SERIALIZABLE (object), is_private ? self->login : NULL, &data, &n_data)) {
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        g_return_if_reached ();
    }

    path = g_build_filename (self->directory, identifier, NULL);
    gkm_transaction_write_file (transaction, path, data, n_data);

    /* Make sure we write in the object hash */
    if (!gkm_transaction_get_failed (transaction))
        store_object_hash (self, transaction, identifier, data, n_data);

    /* Now we decide to own the object */
    if (!gkm_transaction_get_failed (transaction))
        take_object_ownership (self, identifier, object);

    g_free (identifier);
    g_free (path);
    g_free (data);
}
Ejemplo n.º 28
0
void
gkm_mate2_storage_relock (GkmMate2Storage *self, GkmTransaction *transaction,
                          GkmSecret *old_login, GkmSecret *new_login)
{
    GkmMate2File *file;
    GkmDataResult res;
    RelockArgs args;

    g_return_if_fail (GKM_IS_MATE2_STORAGE (self));
    g_return_if_fail (GKM_IS_TRANSACTION (transaction));

    /* Reload the file with the old password and start transaction */
    if (!begin_write_state (self, transaction))
        return;

    file = gkm_mate2_file_new ();

    /* Read in from the old file */
    res = gkm_mate2_file_read_fd (file, self->read_fd, old_login);
    switch(res) {
    case GKM_DATA_FAILURE:
    case GKM_DATA_UNRECOGNIZED:
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        return;
    case GKM_DATA_LOCKED:
        gkm_transaction_fail (transaction, CKR_PIN_INCORRECT);
        return;
    case GKM_DATA_SUCCESS:
        break;
    default:
        g_assert_not_reached ();
    }

    /* Write out to new path as new file */
    res = gkm_mate2_file_write_fd (file, self->write_fd, new_login);
    switch(res) {
    case GKM_DATA_FAILURE:
    case GKM_DATA_UNRECOGNIZED:
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        return;
    case GKM_DATA_LOCKED:
        gkm_transaction_fail (transaction, CKR_PIN_INCORRECT);
        return;
    case GKM_DATA_SUCCESS:
        break;
    default:
        g_assert_not_reached ();
    }

    /* Now go through all objects in the file, and load and reencode them */
    args.transaction = transaction;
    args.old_login = old_login;
    args.new_login = new_login;
    gkm_mate2_file_foreach_entry (file, relock_each_object, &args);

    if (!gkm_transaction_get_failed (transaction) && self->login) {
        if (new_login)
            g_object_ref (new_login);
        g_object_unref (self->login);
        self->login = new_login;
        g_object_notify (G_OBJECT (self), "login");
    }

    g_object_unref (file);
}
Ejemplo n.º 29
0
static void
relock_object (GkmMate2Storage *self, GkmTransaction *transaction, const gchar *path,
               const gchar *identifier, GkmSecret *old_login, GkmSecret *new_login)
{
    GError *error = NULL;
    GkmObject *object;
    gpointer data;
    gsize n_data;
    GType type;

    g_assert (GKM_IS_MATE2_STORAGE (self));
    g_assert (GKM_IS_TRANSACTION (transaction));
    g_assert (identifier);
    g_assert (path);

    g_assert (!gkm_transaction_get_failed (transaction));

    /* Figure out the type of object */
    type = type_from_identifier (identifier);
    if (type == 0) {
        g_warning ("don't know how to relock file in user store: %s", identifier);
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        return;
    }

    /* Create a dummy object for this identifier */
    object = g_object_new (type, "unique", identifier, "module", self->module, NULL);
    if (!GKM_IS_SERIALIZABLE (object)) {
        g_warning ("cannot relock unserializable object for file in user store: %s", identifier);
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        return;
    }

    /* Read in the data for the object */
    if (!g_file_get_contents (path, (gchar**)&data, &n_data, &error)) {
        g_message ("couldn't load file in user store in order to relock: %s: %s", identifier,
                   egg_error_message (error));
        g_clear_error (&error);
        g_object_unref (object);
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        return;
    }

    /* Make sure the data matches the hash */
    if (!check_object_hash (self, identifier, data, n_data)) {
        g_message ("file in data store doesn't match hash: %s", identifier);
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        return;
    }

    /* Load it into our temporary object */
    if (!gkm_serializable_load (GKM_SERIALIZABLE (object), old_login, data, n_data)) {
        g_message ("unrecognized or invalid user store file: %s", identifier);
        gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
        g_free (data);
        g_object_unref (object);
        return;
    }

    g_free (data);
    data = NULL;

    /* Read it out of our temporary object */
    if (!gkm_serializable_save (GKM_SERIALIZABLE (object), new_login, &data, &n_data)) {
        g_warning ("unable to serialize data with new login: %s", identifier);
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        g_object_unref (object);
        g_free (data);
        return;
    }

    g_object_unref (object);

    /* And write it back out to the file */
    gkm_transaction_write_file (transaction, path, data, n_data);

    /* Create and save the hash here */
    if (!gkm_transaction_get_failed (transaction))
        store_object_hash (self, transaction, identifier, data, n_data);

    g_free (data);

}
Ejemplo n.º 30
0
static gboolean
begin_link_temporary_if_exists (GkmTransaction *self, const gchar *filename, gboolean *exists)
{
	guint i = 0;

	g_assert (GKM_IS_TRANSACTION (self));
	g_assert (!gkm_transaction_get_failed (self));
	g_assert (filename);
	g_assert (exists);

	for (i = 0; i < MAX_TRIES; ++i) {
		struct stat sb;
		unsigned int nlink;
		int stat_failed = 0;

		*exists = TRUE;

		/* Try to link to random temporary file names.  We try
		 * to use a hardlink to create a copy but if that
		 * fails (i.e. not supported by the FS), we copy the
		 * entire file.  The result should be the same except
		 * that the file times will change if we need to
		 * rollback the transaction. */
		if (stat (filename, &sb)) {
			stat_failed = 1;
		} else {
			gchar *result;

			result = g_strdup_printf ("%s.temp-%d", filename,
			                          g_random_int_range (0, G_MAXINT));
			nlink = (unsigned int)sb.st_nlink;
			/* The result code of link(2) is not reliable.
			 * Unless it fails with EEXIST we stat the
			 * file to check for success.  Note that there
			 * is a race here: If another process adds a
			 * link to the source file between link and
			 * stat, the check on the increased link count
			 * will fail.  Fortunately the case for
			 * hardlinks are not working solves it.  */
			if (link (filename, result) && errno == EEXIST) {
				/* This is probably a valid error.
				 * Let us try another temporary file.  */
			} else if (stat (filename, &sb)) {
				stat_failed = 1;
			} else {
				if ((sb.st_nlink == nlink + 1)
				    || !copy_to_temp_file (result, filename)) {
					/* Either the link worked or
					 * the copy succeeded.  */
					gkm_transaction_add (self, NULL,
					                     complete_link_temporary,
					                     result);
					return TRUE;
				}
			}

			g_free (result);
		}

		if (stat_failed && (errno == ENOENT || errno == ENOTDIR)) {
			/* The original file does not exist */
			*exists = FALSE;
			return TRUE;
		}

		/* If exists, try again, otherwise fail */
		if (errno != EEXIST) {
			g_warning ("couldn't create temporary file for: %s: %s",
			           filename, g_strerror (errno));
			gkm_transaction_fail (self, CKR_DEVICE_ERROR);
			return FALSE;
		}
	}

	g_assert_not_reached ();
}