static void cert_writer (NMConnection *connection, GKeyFile *file, NMKeyfileWriteTypeDataCert *cert_data, WriteInfo *info, GError **error) { const char *setting_name = nm_setting_get_name (NM_SETTING (cert_data->setting)); NMSetting8021xCKScheme scheme; NMSetting8021xCKFormat format; const char *path = NULL, *ext = "pem"; scheme = cert_data->scheme_func (cert_data->setting); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { char *tmp = NULL; const char *accepted_path = NULL; path = cert_data->path_func (cert_data->setting); g_assert (path); if (g_str_has_prefix (path, info->keyfile_dir)) { const char *p = path + strlen (info->keyfile_dir); /* If the path is rooted in the keyfile directory, just use a * relative path instead of an absolute one. */ if (*p == '/') { while (*p == '/') p++; if (p[0]) { /* If @p looks like an integer list, the following detection will fail too and * we will file:// qualify the path below. We thus avoid writing a path string * that would be interpreted as legacy binary format by reader. */ tmp = nm_keyfile_detect_unqualified_path_scheme (info->keyfile_dir, p, -1, FALSE, NULL); if (tmp) { g_clear_pointer (&tmp, g_free); accepted_path = p; } } } } if (!accepted_path) { /* What we are about to write, must also be understood by the reader. * Otherwise, add a file:// prefix */ tmp = nm_keyfile_detect_unqualified_path_scheme (info->keyfile_dir, path, -1, FALSE, NULL); if (tmp) { g_clear_pointer (&tmp, g_free); accepted_path = path; } } if (!accepted_path) accepted_path = tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL); nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, accepted_path); g_free (tmp); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { GBytes *blob; const guint8 *blob_data; gsize blob_len; gboolean success; GError *local = NULL; char *new_path; blob = cert_data->blob_func (cert_data->setting); g_assert (blob); blob_data = g_bytes_get_data (blob, &blob_len); if (cert_data->format_func) { /* Get the extension for a private key */ format = cert_data->format_func (cert_data->setting); if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) ext = "p12"; } else { /* DER or PEM format certificate? */ if (blob_len > 2 && blob_data[0] == 0x30 && blob_data[1] == 0x82) ext = "der"; } /* Write the raw data out to the standard file so that we can use paths * from now on instead of pushing around the certificate data. */ new_path = g_strdup_printf ("%s/%s-%s.%s", info->keyfile_dir, nm_connection_get_uuid (connection), cert_data->suffix, ext); success = write_cert_key_file (new_path, blob_data, blob_len, &local); if (success) { /* Write the path value to the keyfile. * We know, that basename(new_path) starts with a UUID, hence no conflict with "data:;base64," */ nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, strrchr (new_path, '/') + 1); } else { nm_log_warn (LOGD_SETTINGS, "keyfile: %s.%s: failed to write certificate to file %s: %s", setting_name, cert_data->property_name, new_path, local->message); g_error_free (local); } g_free (new_path); } else { /* scheme_func() returns UNKNOWN in all other cases. The only valid case * where a scheme is allowed to be UNKNOWN, is unsetting the value. In this * case, we don't expect the writer to be called, because the default value * will not be serialized. * The only other reason for the scheme to be UNKNOWN is an invalid cert. * But our connection verifies, so that cannot happen either. */ g_return_if_reached (); } }
static void cert_writer (GKeyFile *file, const char *keyfile_dir, const char *uuid, NMSetting *setting, const char *key, const GValue *value) { const char *setting_name = nm_setting_get_name (setting); NMSetting8021xCKScheme scheme; NMSetting8021xCKFormat format; const char *path = NULL, *ext = "pem"; const ObjectType *objtype = NULL; int i; for (i = 0; i < G_N_ELEMENTS (objtypes) && objtypes[i].key; i++) { if (g_strcmp0 (objtypes[i].key, key) == 0) { objtype = &objtypes[i]; break; } } g_return_if_fail (objtype != NULL); scheme = objtypes->scheme_func (NM_SETTING_802_1X (setting)); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { path = objtype->path_func (NM_SETTING_802_1X (setting)); g_assert (path); /* If the path is rooted in the keyfile directory, just use a * relative path instead of an absolute one. */ if (g_str_has_prefix (path, keyfile_dir)) { path += strlen (keyfile_dir); while (*path == '/') path++; } g_key_file_set_string (file, setting_name, key, path); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { const GByteArray *blob; gboolean success; GError *error = NULL; char *new_path; blob = objtype->blob_func (NM_SETTING_802_1X (setting)); g_assert (blob); if (objtype->format_func) { /* Get the extension for a private key */ format = objtype->format_func (NM_SETTING_802_1X (setting)); if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) ext = "p12"; } else { /* DER or PEM format certificate? */ if (blob->len > 2 && blob->data[0] == 0x30 && blob->data[1] == 0x82) ext = "der"; } /* Write the raw data out to the standard file so that we can use paths * from now on instead of pushing around the certificate data. */ new_path = g_strdup_printf ("%s/%s-%s.%s", keyfile_dir, uuid, objtype->suffix, ext); g_assert (new_path); success = write_cert_key_file (new_path, blob, &error); if (success) { /* Write the path value to the keyfile */ g_key_file_set_string (file, setting_name, key, new_path); } else { g_warning ("Failed to write certificate/key %s: %s", new_path, error->message); g_error_free (error); } g_free (new_path); } else g_assert_not_reached (); }