コード例 #1
0
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);
}
コード例 #2
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;
}
コード例 #3
0
static GkmObject*
factory_create_item (GkmSession *session, GkmTransaction *transaction,
                     CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
	GkmSecretCollection *collection = NULL;
	GkmSecretItem *item;
	GkmManager *m_manager;
	GkmManager *s_manager;
	CK_ATTRIBUTE *attr;
	gboolean is_token;
	gchar *identifier;

	g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
	g_return_val_if_fail (attrs || !n_attrs, NULL);

	/* See if a collection attribute was specified */
	attr = gkm_attributes_find (attrs, n_attrs, CKA_G_COLLECTION);
	if (attr == NULL) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
		return NULL;
	}

	m_manager = gkm_module_get_manager (gkm_session_get_module (session));
	s_manager = gkm_session_get_manager (session);

	gkm_attribute_consume (attr);
	if (!gkm_attributes_find_boolean (attrs, n_attrs, CKA_TOKEN, &is_token))
		collection = gkm_secret_collection_find (session, attr, m_manager, s_manager, NULL);
	else if (is_token)
		collection = gkm_secret_collection_find (session, attr, m_manager, NULL);
	else
		collection = gkm_secret_collection_find (session, attr, s_manager, NULL);

	if (!collection) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
		return NULL;
	}

	/* If an ID was specified, then try and see if that ID already exists */
	if (gkm_attributes_find_string (attrs, n_attrs, CKA_ID, &identifier)) {
		item = gkm_secret_collection_get_item (collection, identifier);
		if (item == NULL) {
			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
			return NULL;
		} else {
			gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (item),
			                                      FALSE, attrs, n_attrs);
			return g_object_ref (item);
		}
	}

	/* Create a new collection which will own the item */
	item = gkm_secret_collection_create_item (collection, transaction);
	gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (item),
	                                      TRUE, attrs, n_attrs);
	return g_object_ref (item);
}
コード例 #4
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;
}
コード例 #5
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 ();
}
コード例 #6
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);
}
コード例 #7
0
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);
}
コード例 #8
0
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);
}
コード例 #9
0
static GkmObject*
factory_create_credential (GkmSession *session, GkmTransaction *transaction,
                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
	CK_OBJECT_HANDLE handle;
	GkmCredential *cred;
	CK_ATTRIBUTE *attr;
	GkmManager *manager;
	GkmModule *module;
	GkmObject *object = NULL;
	CK_RV rv;

	g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
	g_return_val_if_fail (attrs || !n_attrs, NULL);

	/* The handle is optional */
	if (gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_OBJECT, &handle)) {
		rv = gkm_session_lookup_readable_object (session, handle, &object);
		if (rv != CKR_OK) {
			gkm_transaction_fail (transaction, rv);
			return NULL;
		}
	} else {
		object = NULL;
	}

	/* The value is optional */
	attr = gkm_attributes_find (attrs, n_attrs, CKA_VALUE);

	gkm_attributes_consume (attrs, n_attrs, CKA_VALUE, CKA_G_OBJECT, G_MAXULONG);

	module = gkm_session_get_module (session);
	manager = gkm_manager_for_template (attrs, n_attrs, session);
	rv = gkm_credential_create (module, manager, object,
	                            attr ? attr->pValue : NULL,
	                            attr ? attr->ulValueLen : 0, &cred);

	if (rv == CKR_OK) {
		gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (cred),
		                                      TRUE, attrs, n_attrs);
		return GKM_OBJECT (cred);
	} else {
		gkm_transaction_fail (transaction, rv);
		return NULL;
	}
}
コード例 #10
0
void
gkm_xdg_trust_remove_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
                                GkmTransaction *transaction)
{
	GBytes *key;

	g_return_if_fail (GKM_XDG_IS_TRUST (self));
	g_return_if_fail (GKM_IS_ASSERTION (assertion));
	g_return_if_fail (!transaction || GKM_IS_TRANSACTION (transaction));

	key = lookup_assertion_key (assertion);
	g_return_if_fail (key);

	/* Assertion needs to be from this trust object */
	g_return_if_fail (g_hash_table_lookup (self->pv->assertions, key) == assertion);
	remove_assertion_from_trust (self, assertion, transaction);
}
コード例 #11
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);
}
コード例 #12
0
void
gkm_xdg_trust_replace_assertion (GkmXdgTrust *self, GkmAssertion *assertion,
                             GkmTransaction *transaction)
{
	GkmAssertion *previous;
	GBytes *key;

	g_return_if_fail (GKM_XDG_IS_TRUST (self));
	g_return_if_fail (GKM_IS_ASSERTION (assertion));
	g_return_if_fail (!transaction || GKM_IS_TRANSACTION (transaction));

	/* Build up a key if we don't have one */
	key = lookup_or_create_assertion_key (assertion);

	/* Remove any previous assertion with this key */
	previous = g_hash_table_lookup (self->pv->assertions, key);
	if (previous != NULL)
		remove_assertion_from_trust (self, previous, transaction);
	add_assertion_to_trust (self, assertion, transaction);

}
コード例 #13
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;
}
コード例 #14
0
static GkmObject*
factory_create_certificate (GkmSession *session, GkmTransaction *transaction,
                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
	CK_ATTRIBUTE_PTR attr;
	GkmCertificate *cert;

	g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
	g_return_val_if_fail (attrs || !n_attrs, NULL);

	/* Dig out the value */
	attr = gkm_attributes_find (attrs, n_attrs, CKA_VALUE);
	if (attr == NULL) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
		return NULL;
	}

	cert = g_object_new (GKM_TYPE_CERTIFICATE,
	                     "module", gkm_session_get_module (session),
	                     "manager", gkm_manager_for_template (attrs, n_attrs, session),
	                     NULL);

	/* Load the certificate from the data specified */
	if (!gkm_serializable_load (GKM_SERIALIZABLE (cert), NULL, attr->pValue, attr->ulValueLen)) {
		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
		g_object_unref (cert);
		return NULL;
	}

	/* Note that we ignore the subject */
	gkm_attributes_consume (attrs, n_attrs, CKA_VALUE, CKA_SUBJECT, G_MAXULONG);

	gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (cert),
	                                      TRUE, attrs, n_attrs);
	return GKM_OBJECT (cert);
}
コード例 #15
0
static void
store_object_hash (GkmMate2Storage *self, GkmTransaction *transaction, const gchar *identifier,
                   const guchar *data, gsize n_data)
{
    GkmDataResult res;
    gchar *digest;

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

    digest = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, n_data);
    if (digest == NULL) {
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
        g_return_if_reached ();
    }

    res = gkm_mate2_file_write_value (self->file, identifier, CKA_MATE_INTERNAL_SHA1, digest, strlen (digest));
    g_free (digest);

    if (res != GKM_DATA_SUCCESS)
        gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
}
コード例 #16
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 ();
}
コード例 #17
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);

}
コード例 #18
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);
}
コード例 #19
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);
}