static GkmObject*
factory_create_generic_key (GkmSession *session, GkmTransaction *transaction,
                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
	GkmGenericKey *key;
	GkmManager *manager;
	CK_ATTRIBUTE_PTR value;

	value = gkm_attributes_find (attrs, n_attrs, CKA_VALUE);
	if (value == NULL) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
		return NULL;
	}

	if (gkm_attributes_find (attrs, n_attrs, CKA_VALUE_LEN)) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
		return NULL;
	}

	manager = gkm_manager_for_template (attrs, n_attrs, session);
	key = g_object_new (GKM_TYPE_GENERIC_KEY,
	                    "module", gkm_session_get_module (session),
	                    "manager", manager,
	                    NULL);

	key->value = egg_secure_alloc (value->ulValueLen);
	key->n_value = value->ulValueLen;
	memcpy (key->value, value->pValue, key->n_value);

	gkm_attribute_consume (value);

	gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (key),
	                                      TRUE, attrs, n_attrs);
	return GKM_OBJECT (key);
}
Example #2
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);
}
Example #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);
}
Example #4
0
GkmXdgTrust*
gkm_xdg_trust_create_for_assertion (GkmModule *module, GkmManager *manager,
                                    GkmTransaction *transaction,
                                    CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{

	CK_ATTRIBUTE_PTR serial, issuer, cert;
	GkmXdgTrust *trust;

	g_return_val_if_fail (GKM_IS_MODULE (module), NULL);
	g_return_val_if_fail (GKM_IS_MANAGER (manager), NULL);
	g_return_val_if_fail (attrs || !n_attrs, NULL);

	serial = gkm_attributes_find (attrs, n_attrs, CKA_SERIAL_NUMBER);
	issuer = gkm_attributes_find (attrs, n_attrs, CKA_ISSUER);
	cert = gkm_attributes_find (attrs, n_attrs, CKA_X_CERTIFICATE_VALUE);

	/* A trust object with just serial + issuer */
	if (serial != NULL && issuer != NULL) {
		if (cert != NULL) {
			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
			return NULL;
		}
		if (!validate_der (issuer, "Name") || !validate_integer (serial)) {
			gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
			return NULL;
		}

		trust = create_trust_for_reference (module, manager, serial, issuer);

	/* A trust object with a full certificate */
	} else if (cert != NULL) {
		if (serial != NULL || issuer != NULL) {
			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
			return NULL;
		}
		if (!validate_der (cert, "Certificate")) {
			gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
			return NULL;
		}

		trust = create_trust_for_complete (module, manager, cert);

	/* Not sure what this is */
	} else {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
		return NULL;
	}

	gkm_attributes_consume (attrs, n_attrs, CKA_X_CERTIFICATE_VALUE, CKA_ISSUER,
	                        CKA_SERIAL_NUMBER, G_MAXULONG);

	return trust;
}
Example #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 ();
}
Example #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);
}
static void
gkm_object_real_create_attributes (GkmObject *self, GkmSession *session,
                                   GkmTransaction *transaction, CK_ATTRIBUTE *attrs, CK_ULONG n_attrs)
{
	CK_ATTRIBUTE_PTR transient_attr;
	gboolean transient = FALSE;
	gulong after = 0;
	gulong idle = 0;
	CK_RV rv;

	/* Parse the transient attribute */
	transient_attr = gkm_attributes_find (attrs, n_attrs, CKA_MATE_TRANSIENT);
	if (transient_attr) {
		rv = gkm_attribute_get_bool (transient_attr, &transient);
		if (rv != CKR_OK) {
			gkm_transaction_fail (transaction, rv);
			return;
		}
	}

	/* Parse the auto destruct attribute */
	if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_DESTRUCT_AFTER, &after))
		after = 0;
	if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_DESTRUCT_IDLE, &idle))
		idle = 0;
	/* Default for the transient attribute */
	if (!transient_attr && (idle || after))
		transient = TRUE;

	/* Used up these attributes */
	gkm_attributes_consume (attrs, n_attrs, CKA_G_DESTRUCT_AFTER,
	                        CKA_G_DESTRUCT_IDLE, CKA_MATE_TRANSIENT, G_MAXULONG);

	if (transient) {
		mark_object_transient (self);
		self->pv->transient->timed_after = after;
		self->pv->transient->timed_idle = idle;
	}

	if (after || idle) {
		if (!self->pv->transient) {
			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
			return;
		}

		gkm_transaction_add (transaction, self, start_callback, NULL);
	}
}
Example #8
0
static void
test_expose_transaction (Test* test, gconstpointer unused)
{
	CK_OBJECT_HANDLE handle;
	GkmManager *manager;
	GkmObject *check, *object;
	GkmTransaction *transaction;

	manager = gkm_session_get_manager (test->session);
	object = mock_module_object_new (test->session);

	handle = gkm_object_get_handle (object);
	transaction = gkm_transaction_new ();

	/* Should be hidden */
	gkm_object_expose (object, FALSE);
	check = gkm_manager_find_by_handle (manager, handle);
	g_assert (check == NULL);

	/* Now it should have a handle, and be visible */
	gkm_object_expose_full (object, transaction, TRUE);
	check = gkm_manager_find_by_handle (manager, handle);
	g_assert (check == object);

	gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
	gkm_transaction_complete (transaction);

	/* Now should be invisible */
	check = gkm_manager_find_by_handle (manager, handle);
	g_assert (check == NULL);

	g_object_unref (transaction);
}
static void
gkm_secret_object_set_attribute (GkmObject *base, GkmSession *session,
                                 GkmTransaction *transaction, CK_ATTRIBUTE_PTR attr)
{
	GkmSecretObject *self = GKM_SECRET_OBJECT (base);
	gchar *label;
	CK_RV rv;

	switch (attr->type) {

	case CKA_LABEL:
		/* Check that the object is not locked */
		if (gkm_secret_object_is_locked (self, session))
			rv = CKR_USER_NOT_LOGGED_IN;
		else
			rv = gkm_attribute_get_string (attr, &label);
		if (rv != CKR_OK)
			gkm_transaction_fail (transaction, rv);
		else
			begin_set_label (self, transaction, label);
		return;
	}

	GKM_OBJECT_CLASS (gkm_secret_object_parent_class)->set_attribute (base, session, transaction, attr);
}
Example #10
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;
}
Example #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);
}
Example #12
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;
	}
}
static void
gkm_object_real_set_attribute (GkmObject *self, GkmSession *session,
                               GkmTransaction* transaction, CK_ATTRIBUTE* attr)
{
	CK_ATTRIBUTE check;
	CK_RV rv;

	switch (attr->type) {
	case CKA_TOKEN:
	case CKA_PRIVATE:
	case CKA_MODIFIABLE:
	case CKA_CLASS:
		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
		return;
	case CKA_MATE_UNIQUE:
		gkm_transaction_fail (transaction, self->pv->unique ?
		                                       CKR_ATTRIBUTE_READ_ONLY :
		                                       CKR_ATTRIBUTE_TYPE_INVALID);
		return;
	};

	/* Give store a shot */
	if (self->pv->store) {
		gkm_store_set_attribute (self->pv->store, transaction, self, attr);
		return;
	}

	/* Now some more defaults */
	switch (attr->type) {
	case CKA_LABEL:
		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
		return;
	}

	/* Check if this attribute exists */
	check.type = attr->type;
	check.pValue = 0;
	check.ulValueLen = 0;
	rv = gkm_object_get_attribute (self, session, &check);
	if (rv == CKR_ATTRIBUTE_TYPE_INVALID)
		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
	else
		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
}
Example #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);
}
Example #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);
}
Example #16
0
static gboolean
begin_modification_state (GkmMate2Storage *self, GkmTransaction *transaction)
{
    GkmDataResult res;
    struct stat sb;
    CK_RV rv;

    if (!begin_write_state (self, transaction))
        return FALSE;

    /* See if file needs updating */
    if (fstat (self->read_fd, &sb) >= 0 && sb.st_mtime != self->last_mtime) {

        res = gkm_mate2_file_read_fd (self->file, self->read_fd, self->login);
        switch (res) {
        case GKM_DATA_FAILURE:
            g_message ("failure updating user store file: %s", self->filename);
            rv = CKR_FUNCTION_FAILED;
            break;
        case GKM_DATA_LOCKED:
            rv = CKR_USER_NOT_LOGGED_IN;
            break;
        case GKM_DATA_UNRECOGNIZED:
            g_message ("unrecognized or invalid user store file: %s", self->filename);
            rv = CKR_FUNCTION_FAILED;
            break;
        case GKM_DATA_SUCCESS:
            rv = CKR_OK;
            break;
        default:
            g_assert_not_reached ();
            break;
        }

        if (rv != CKR_OK) {
            gkm_transaction_fail (transaction, rv);
            return FALSE;
        }
    }

    /* Write out the data once completed with modifications */
    gkm_transaction_add (transaction, self, complete_modification_state, NULL);

    return TRUE;
}
static void
gkm_module_real_remove_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
{
	/* Derived classes should do something interesting */
	gkm_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
}
static GkmObject*
factory_create_assertion (GkmSession *session, GkmTransaction *transaction,
                          CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
	GkmAssertion *assertion;
	CK_X_ASSERTION_TYPE type;
	GkmManager *manager;
	gboolean created = FALSE;
	GkmXdgTrust *trust;
	gchar *purpose;
	gchar *peer;

	g_return_val_if_fail (attrs || !n_attrs, NULL);

	if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_X_ASSERTION_TYPE, &type)) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
		return NULL;
	}

	if (!gkm_attributes_find_string (attrs, n_attrs, CKA_X_PURPOSE, &purpose)) {
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
		return NULL;
	}

	if (!gkm_attributes_find_string (attrs, n_attrs, CKA_X_PEER, &peer))
		peer = NULL;

	/* Try to find or create an appropriate trust object for this assertion */
	manager = gkm_manager_for_template (attrs, n_attrs, session);
	trust = lookup_or_create_trust_object (session, manager, transaction,
	                                       type, attrs, n_attrs, &created);

	/* Creating the trust object failed */
	if (trust == NULL) {
		g_return_val_if_fail (gkm_transaction_get_failed (transaction), NULL);
		g_free (purpose);
		g_free (peer);
		return NULL;
	}

	assertion = g_object_new (GKM_XDG_TYPE_ASSERTION,
	                          "module", gkm_session_get_module (session),
	                          "manager", manager,
	                          "trust", trust,
	                          "type", type,
	                          "purpose", purpose,
	                          "peer", peer,
	                          NULL);
	g_free (purpose);
	g_free (peer);

	/* Add the assertion to the trust object */
	if (!gkm_transaction_get_failed (transaction)) {
		gkm_xdg_trust_replace_assertion (trust, GKM_ASSERTION (assertion), transaction);
		if (gkm_transaction_get_failed (transaction)) {
			gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);

		/* A new trust assertion */
		} else {
			gkm_attributes_consume (attrs, n_attrs, CKA_X_ASSERTION_TYPE, CKA_X_PURPOSE, G_MAXULONG);
			gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (assertion),
			                                      TRUE, attrs, n_attrs);
		}
	}

	g_object_unref (trust);
	return GKM_OBJECT (assertion);
}
static GkmXdgTrust*
lookup_or_create_trust_object (GkmSession *session, GkmManager *manager,
                               GkmTransaction *transaction, CK_X_ASSERTION_TYPE type,
                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gboolean *created)
{
	CK_ATTRIBUTE_PTR serial, issuer, value;
	CK_ATTRIBUTE lookups[3];
	CK_OBJECT_CLASS klass;
	CK_ULONG n_lookups;
	GList *objects;
	GkmXdgTrust *trust;
	GkmModule *module;

	klass = CKO_NETSCAPE_TRUST;
	lookups[0].type = CKA_CLASS;
	lookups[0].pValue = &klass;
	lookups[0].ulValueLen = sizeof (klass);

	switch (type) {
	case CKT_X_ANCHORED_CERTIFICATE:
	case CKT_X_PINNED_CERTIFICATE:
		value = gkm_attributes_find (attrs, n_attrs, CKA_X_CERTIFICATE_VALUE);
		if (!value) {
			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
			return NULL;
		}

		/* Attributes used for looking up trust object */
		memcpy (&lookups[1], value, sizeof (CK_ATTRIBUTE));
		n_lookups = 2;
		break;

	case CKT_X_DISTRUSTED_CERTIFICATE:
		serial = gkm_attributes_find (attrs, n_attrs, CKA_SERIAL_NUMBER);
		issuer = gkm_attributes_find (attrs, n_attrs, CKA_ISSUER);
		if (!serial || !issuer) {
			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
			return NULL;
		}

		/* Attributes used for looking up trust object */
		memcpy (&lookups[1], issuer, sizeof (CK_ATTRIBUTE));
		memcpy (&lookups[2], serial, sizeof (CK_ATTRIBUTE));
		n_lookups = 3;
		break;

	default:
		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
		return NULL;
	};

	objects = gkm_manager_find_by_attributes (manager, session, lookups, n_lookups);
	module = gkm_session_get_module (session);

	/* Found a matching trust object for this assertion */
	if (objects) {
		g_return_val_if_fail (GKM_XDG_IS_TRUST (objects->data), NULL);
		trust = g_object_ref (objects->data);
		g_list_free (objects);

	/* Create a trust object for this assertion */
	} else {
		trust = gkm_xdg_trust_create_for_assertion (module, manager, transaction,
		                                            lookups, n_lookups);

		gkm_attributes_consume (attrs, n_attrs, CKA_X_CERTIFICATE_VALUE,
		                        CKA_ISSUER, CKA_SERIAL_NUMBER, G_MAXULONG);
		gkm_attributes_consume (lookups, n_lookups, CKA_X_CERTIFICATE_VALUE,
		                        CKA_ISSUER, CKA_SERIAL_NUMBER, G_MAXULONG);

		if (!gkm_transaction_get_failed (transaction))
			gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (trust),
			                                      TRUE, lookups, n_lookups);
	}

	return trust;
}
Example #20
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);
}
Example #21
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);
}
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 ();
}
Example #23
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);

}