Example #1
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);
}
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);
}
Example #3
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;
}
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;
}
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 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 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;
	}
}
Example #8
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 #9
0
static void
add_assertion_to_trust (GkmXdgTrust *self, GkmAssertion *assertion,
                        GkmTransaction *transaction)
{
	GBytes *key;

	key = lookup_or_create_assertion_key (assertion);
	g_assert (key != NULL);

	g_hash_table_insert (self->pv->assertions, g_bytes_ref (key), g_object_ref (assertion));
	gkm_object_expose (GKM_OBJECT (assertion), gkm_object_is_exposed (GKM_OBJECT (self)));

	if (transaction != NULL)
		gkm_transaction_add (transaction, self, complete_add_assertion, g_object_ref (assertion));
}
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);
	}
}
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 #12
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;
}
Example #13
0
static void
remove_assertion_from_trust (GkmXdgTrust *self, GkmAssertion *assertion,
                             GkmTransaction *transaction)
{
	GByteArray *key;

	key = lookup_assertion_key (assertion);
	g_assert (key);

	gkm_object_expose (GKM_OBJECT (assertion), FALSE);

	if (transaction == NULL) {
		if (!g_hash_table_remove (self->pv->assertions, key))
			g_return_if_reached ();
	} else {
		if (!g_hash_table_steal (self->pv->assertions, key))
			g_return_if_reached ();
		gkm_transaction_add (transaction, self, complete_remove_assertion, assertion);
	}
}
static void
add_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
{
	g_assert (GKM_IS_MODULE (self));
	g_assert (GKM_IS_OBJECT (object));

	/* Must not already be associated with a session or manager */
	g_return_if_fail (gkm_object_get_manager (object) == self->pv->token_manager);
	g_return_if_fail (g_hash_table_lookup (self->pv->transient_objects, object) == NULL);

	g_hash_table_insert (self->pv->transient_objects, object, g_object_ref (object));
	g_object_set (object, "store", self->pv->transient_store, NULL);
	gkm_object_expose (object, TRUE);

	if (transaction) {
		gkm_transaction_add (transaction, self,
		                     (GkmTransactionFunc)complete_transient_add,
		                     g_object_ref (object));
	}
}
static void
remove_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
{
	g_assert (GKM_IS_MODULE (self));
	g_assert (GKM_IS_OBJECT (object));

	g_object_ref (object);

	gkm_object_expose (object, FALSE);
	if (!g_hash_table_remove (self->pv->transient_objects, object))
		g_return_if_reached ();
	g_object_set (object, "store", NULL, NULL);

	if (transaction) {
		gkm_transaction_add (transaction, self,
		                     (GkmTransactionFunc)complete_transient_remove,
		                     g_object_ref (object));
	}

	g_object_unref (object);
}
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 ();
}