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); }
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); }
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); }
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; }
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 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); } }
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); }
static gboolean begin_write_state (GkmMate2Storage *self, GkmTransaction *transaction) { g_assert (GKM_IS_MATE2_STORAGE (self)); g_assert (GKM_IS_TRANSACTION (transaction)); g_return_val_if_fail (!gkm_transaction_get_failed (transaction), FALSE); /* Already in write state for this transaction? */ if (self->transaction != NULL) { g_return_val_if_fail (self->transaction == transaction, FALSE); return TRUE; } /* Lock file for the transaction */ self->read_fd = begin_lock_file (self, transaction); if (self->read_fd == -1) return FALSE; gkm_transaction_add (transaction, self, complete_write_state, NULL); self->transaction = g_object_ref (transaction); /* Open the new file */ g_assert (self->write_fd == -1); self->write_path = g_strdup_printf ("%s.XXXXXX", self->filename); self->write_fd = g_mkstemp (self->write_path); if (self->write_fd == -1) { g_message ("couldn't open new temporary store file: %s: %s", self->write_path, g_strerror (errno)); gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED); return FALSE; } return TRUE; }
void gkm_mate2_storage_destroy (GkmMate2Storage *self, GkmTransaction *transaction, GkmObject *object) { GkmDataResult res; gchar *identifier; gchar *path; g_return_if_fail (GKM_IS_MATE2_STORAGE (self)); g_return_if_fail (GKM_IS_TRANSACTION (transaction)); g_return_if_fail (!gkm_transaction_get_failed (transaction)); g_return_if_fail (object); /* Lookup the object identifier */ identifier = g_hash_table_lookup (self->object_to_identifier, object); g_return_if_fail (identifier); if (!begin_modification_state (self, transaction)) return; /* First actually delete the file */ path = g_build_filename (self->directory, identifier, NULL); gkm_transaction_remove_file (transaction, path); g_free (path); if (gkm_transaction_get_failed (transaction)) return; /* Now delete the entry from our store */ res = gkm_mate2_file_destroy_entry (self->file, identifier); switch(res) { case GKM_DATA_FAILURE: case GKM_DATA_UNRECOGNIZED: gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED); return; case GKM_DATA_LOCKED: gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN); return; case GKM_DATA_SUCCESS: break; default: g_assert_not_reached (); } /* Actual removal of object happened as a callback above */ g_return_if_fail (g_hash_table_lookup (self->object_to_identifier, object) == NULL); }
static 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); }
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); }
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); }
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; }
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); }
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 (); }
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); }