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