mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 02:20:06 +01:00
core: add functions to read private files of connections
Add function nm_utils_read_private_files(). It can be used to read a list of paths as the given user. It spawns the daemon-helper to read each path and returns asynchronously a hash table containing the files content. Also add nm_utils_get_connection_private_files_paths() to return a list of file paths referenced in a connection. The function currently returns only 802.1x file paths for certificates and keys.
This commit is contained in:
parent
932b85f7e7
commit
9703305122
2 changed files with 210 additions and 0 deletions
|
|
@ -5664,3 +5664,202 @@ nm_utils_get_connection_first_permissions_user(NMConnection *connection)
|
|||
|
||||
return _nm_setting_connection_get_first_permissions_user(s_con);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
get_8021x_private_files(NMConnection *connection, GPtrArray *files)
|
||||
{
|
||||
const struct {
|
||||
NMSetting8021xCKScheme (*get_scheme_func)(NMSetting8021x *);
|
||||
const char *(*get_path_func)(NMSetting8021x *);
|
||||
} funcs[] = {
|
||||
{nm_setting_802_1x_get_ca_cert_scheme, nm_setting_802_1x_get_ca_cert_path},
|
||||
{nm_setting_802_1x_get_client_cert_scheme, nm_setting_802_1x_get_client_cert_path},
|
||||
{nm_setting_802_1x_get_private_key_scheme, nm_setting_802_1x_get_private_key_path},
|
||||
{nm_setting_802_1x_get_phase2_ca_cert_scheme, nm_setting_802_1x_get_phase2_ca_cert_path},
|
||||
{nm_setting_802_1x_get_phase2_client_cert_scheme,
|
||||
nm_setting_802_1x_get_phase2_client_cert_path},
|
||||
{nm_setting_802_1x_get_phase2_private_key_scheme,
|
||||
nm_setting_802_1x_get_phase2_private_key_path},
|
||||
};
|
||||
NMSetting8021x *s_8021x;
|
||||
const char *path;
|
||||
guint i;
|
||||
|
||||
s_8021x = nm_connection_get_setting_802_1x(connection);
|
||||
if (!s_8021x)
|
||||
return;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(funcs); i++) {
|
||||
if (funcs[i].get_scheme_func(s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
|
||||
path = funcs[i].get_path_func(s_8021x);
|
||||
if (path) {
|
||||
g_ptr_array_add(files, (gpointer) path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char **
|
||||
nm_utils_get_connection_private_files_paths(NMConnection *connection)
|
||||
{
|
||||
GPtrArray *files;
|
||||
|
||||
files = g_ptr_array_new();
|
||||
get_8021x_private_files(connection, files);
|
||||
g_ptr_array_add(files, NULL);
|
||||
|
||||
return (const char **) g_ptr_array_free(files, files->len == 1);
|
||||
}
|
||||
|
||||
typedef struct _ReadInfo ReadInfo;
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
ReadInfo *read_info;
|
||||
} FileInfo;
|
||||
|
||||
struct _ReadInfo {
|
||||
GTask *task;
|
||||
GHashTable *table;
|
||||
GPtrArray *file_infos; /* of FileInfo */
|
||||
GError *first_error;
|
||||
guint num_pending;
|
||||
};
|
||||
|
||||
static void
|
||||
read_file_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
FileInfo *file_info = user_data;
|
||||
ReadInfo *read_info = file_info->read_info;
|
||||
gs_unref_bytes GBytes *output = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
output = nm_utils_spawn_helper_finish_binary(result, &error);
|
||||
|
||||
nm_assert(read_info->num_pending > 0);
|
||||
read_info->num_pending--;
|
||||
|
||||
if (nm_utils_error_is_cancelled(error)) {
|
||||
/* nop */
|
||||
} else if (error) {
|
||||
nm_log_dbg(LOGD_CORE,
|
||||
"read-private-files: failed to read file '%s': %s",
|
||||
file_info->path,
|
||||
error->message);
|
||||
if (!read_info->first_error) {
|
||||
/* @error just says "helper process exited with status X".
|
||||
* Return a more human-friendly one. */
|
||||
read_info->first_error = g_error_new(NM_UTILS_ERROR,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"error reading file '%s'",
|
||||
file_info->path);
|
||||
}
|
||||
} else {
|
||||
nm_log_dbg(LOGD_SUPPLICANT,
|
||||
"read-private-files: successfully read file '%s'",
|
||||
file_info->path);
|
||||
|
||||
/* Store the file contents in the hash table */
|
||||
if (!read_info->table) {
|
||||
read_info->table = g_hash_table_new_full(nm_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
(GDestroyNotify) g_bytes_unref);
|
||||
}
|
||||
g_hash_table_insert(read_info->table,
|
||||
g_steal_pointer(&file_info->path),
|
||||
g_steal_pointer(&output));
|
||||
}
|
||||
|
||||
g_clear_pointer(&file_info->path, g_free);
|
||||
|
||||
/* If all operations are completed, return */
|
||||
if (read_info->num_pending == 0) {
|
||||
if (read_info->first_error) {
|
||||
g_task_return_error(read_info->task, g_steal_pointer(&read_info->first_error));
|
||||
} else {
|
||||
g_task_return_pointer(read_info->task,
|
||||
g_steal_pointer(&read_info->table),
|
||||
(GDestroyNotify) g_hash_table_unref);
|
||||
}
|
||||
|
||||
if (read_info->table)
|
||||
g_hash_table_unref(read_info->table);
|
||||
if (read_info->file_infos)
|
||||
g_ptr_array_unref(read_info->file_infos);
|
||||
|
||||
g_object_unref(read_info->task);
|
||||
g_free(read_info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_read_private_files:
|
||||
* @paths: array of file paths to be read
|
||||
* @user: name of the user to impersonate when reading the files
|
||||
* @cancellable: cancellable to cancel the operation
|
||||
* @callback: callback to invoke on completion
|
||||
* @cb_data: data for @callback
|
||||
*
|
||||
* Reads the given list of files @paths on behalf of user @user. Invokes
|
||||
* @callback asynchronously on completion. The callback must use
|
||||
* nm_utils_read_private_files_finish() to obtain the result.
|
||||
*/
|
||||
void
|
||||
nm_utils_read_private_files(const char *const *paths,
|
||||
const char *user,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data)
|
||||
{
|
||||
ReadInfo *read_info;
|
||||
FileInfo *file_info;
|
||||
guint i;
|
||||
|
||||
g_return_if_fail(paths && paths[0]);
|
||||
g_return_if_fail(cancellable);
|
||||
g_return_if_fail(callback);
|
||||
g_return_if_fail(cb_data);
|
||||
|
||||
read_info = g_new(ReadInfo, 1);
|
||||
*read_info = (ReadInfo) {
|
||||
.task = nm_g_task_new(NULL, cancellable, nm_utils_read_private_files, callback, cb_data),
|
||||
.file_infos = g_ptr_array_new_with_free_func(g_free),
|
||||
};
|
||||
|
||||
for (i = 0; paths[i]; i++) {
|
||||
file_info = g_new(FileInfo, 1);
|
||||
*file_info = (FileInfo) {
|
||||
.path = g_strdup(paths[i]),
|
||||
.read_info = read_info,
|
||||
};
|
||||
g_ptr_array_add(read_info->file_infos, file_info);
|
||||
read_info->num_pending++;
|
||||
|
||||
nm_utils_spawn_helper(NM_MAKE_STRV("read-file-as-user", user, paths[i]),
|
||||
TRUE,
|
||||
cancellable,
|
||||
read_file_helper_cb,
|
||||
file_info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_read_private_files_finish:
|
||||
* @result: the GAsyncResult
|
||||
* @error: on return, the error
|
||||
*
|
||||
* Returns the files read by nm_utils_read_private_files(). The return value
|
||||
* is a hash table {char * -> GBytes *}. Free it with g_hash_table_unref().
|
||||
*/
|
||||
GHashTable *
|
||||
nm_utils_read_private_files_finish(GAsyncResult *result, GError **error)
|
||||
{
|
||||
GTask *task = G_TASK(result);
|
||||
|
||||
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_read_private_files));
|
||||
|
||||
return g_task_propagate_pointer(task, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -509,4 +509,15 @@ gboolean nm_rate_limit_check(NMRateLimit *rate_limit, gint32 window_sec, gint32
|
|||
|
||||
const char *nm_utils_get_connection_first_permissions_user(NMConnection *connection);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const char **nm_utils_get_connection_private_files_paths(NMConnection *connection);
|
||||
|
||||
void nm_utils_read_private_files(const char *const *paths,
|
||||
const char *user,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data);
|
||||
GHashTable *nm_utils_read_private_files_finish(GAsyncResult *result, GError **error);
|
||||
|
||||
#endif /* __NM_CORE_UTILS_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue