libnm/keyfile: merge branch 'th/keyfile-public-api'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/517
This commit is contained in:
Thomas Haller 2020-10-29 09:28:27 +01:00
commit 7616469df8
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
11 changed files with 365 additions and 102 deletions

View file

@ -925,6 +925,7 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-core-types.h \
libnm-core/nm-dbus-interface.h \
libnm-core/nm-errors.h \
libnm-core/nm-keyfile.h \
libnm-core/nm-setting-6lowpan.h \
libnm-core/nm-setting-8021x.h \
libnm-core/nm-setting-adsl.h \
@ -1480,6 +1481,7 @@ nodist_libnm_liblibnm_la_SOURCES = \
libnm_liblibnm_la_LIBADD = \
libnm-core/nm-libnm-core-aux/libnm-libnm-core-aux.la \
libnm-core/nm-keyfile/libnm-keyfile.la \
libnm-core/libnm-core.la \
$(libnm_crypto_lib) \
libnm-core/nm-libnm-core-intern/libnm-libnm-core-intern.la \
@ -1573,6 +1575,7 @@ libnm_NM_1_0_gir_FILES = \
$(libnm_core_lib_c_real) \
$(libnm_lib_h_pub_mkenums) \
$(libnm_lib_h_pub_real) \
libnm-core/nm-keyfile/nm-keyfile.c \
$(libnm_lib_c_mkenums) \
$(libnm_lib_c_real)
libnm_NM_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=NM --symbol-prefix=nm

View file

@ -178,6 +178,7 @@ EXTRA_DIST += \
examples/python/gi/list-connections.py \
examples/python/gi/nm-add-connection2.py \
examples/python/gi/nm-connection-update-stable-id.py \
examples/python/gi/nm-keyfile.py \
examples/python/gi/nm-update2.py \
examples/python/gi/nm-wg-set \
examples/python/gi/setting-user-data.py \

139
examples/python/gi/nm-keyfile.py Executable file
View file

@ -0,0 +1,139 @@
#!/usr/bin/env python
# SPDX-License-Identifier: LGPL-2.1+
import sys
import os
import gi
gi.require_version("NM", "1.0")
from gi.repository import NM, GLib
###############################################################################
def kf_load_from_file(filename):
kf = GLib.KeyFile.new()
kf.load_from_file(filename, GLib.KeyFileFlags.NONE)
return kf
def kf_to_string(kf):
d, l = kf.to_data()
return d
def debug(message):
if os.getenv("DEBUG") == "1":
print(">>> %s" % (message))
###############################################################################
filename = sys.argv[1]
base_dir = os.path.dirname(os.path.realpath(filename))
kf = kf_load_from_file(filename)
print('> keyfile "%s":' % (filename))
print(">>\n%s\n<<" % (kf_to_string(kf)))
###############################################################################
def kf_handler_read(keyfile, connection, handler_type, handler_data, user_data):
kf_handler_read_cnt = globals().get("kf_handler_read_cnt", 0) + 1
globals()["kf_handler_read_cnt"] = kf_handler_read_cnt
[kf_group, kf_key, cur_setting, cur_property] = handler_data.get_context()
debug("kf_handler_read(%s): keyfile=%r" % (kf_handler_read_cnt, keyfile))
debug("kf_handler_read(%s): connection=%r" % (kf_handler_read_cnt, connection))
debug("kf_handler_read(%s): handler-type=%r" % (kf_handler_read_cnt, handler_type))
debug("kf_handler_read(%s): handler-data=%r" % (kf_handler_read_cnt, handler_data))
debug("kf_handler_read(%s): user-data=%r" % (kf_handler_read_cnt, user_data))
debug("kf_handler_read(%s): kf-group=%r" % (kf_handler_read_cnt, kf_group))
debug("kf_handler_read(%s): kf-key=%r" % (kf_handler_read_cnt, kf_key))
debug("kf_handler_read(%s): kf-setting=%r" % (kf_handler_read_cnt, cur_setting))
debug("kf_handler_read(%s): kf-property=%r" % (kf_handler_read_cnt, cur_property))
if handler_type == NM.KeyfileHandlerType.WARN:
[message, severity] = handler_data.warn_get()
debug('parse-warning: <%s> = "%s"' % (severity, message))
print("> warning: %s" % (message))
return False
if handler_type == NM.KeyfileHandlerType.WRITE_CERT:
# just to show how to abort the parsing. This event won't happen
# for read.
handler_data.fail_with_error(
GLib.GError.new_literal(
NM.ConnectionError.quark(), "hallo1", NM.ConnectionError.MISSINGPROPERTY
)
)
# don't handle unknown handler types.
return False
try:
print("parse keyfile...")
c = NM.keyfile_read(kf, base_dir, NM.KeyfileHandlerFlags.NONE, kf_handler_read, 42)
except Exception as e:
print("parsing failed: %r" % (e))
raise
verify_failure = None
try:
c.verify()
except Exception as e:
verify_failure = e.message
print(
'parsing succeeded: "%s" (%s)%s'
% (
c.get_id(),
c.get_uuid(),
" (invalid: " + verify_failure + ")" if verify_failure is not None else "",
)
)
###############################################################################
def kf_handler_write(connection, keyfile, handler_type, handler_data, user_data):
kf_handler_write_cnt = globals().get("kf_handler_write_cnt", 0) + 1
globals()["kf_handler_write_cnt"] = kf_handler_write_cnt
[kf_group, kf_key, cur_setting, cur_property] = handler_data.get_context()
debug("kf_handler_write(%s): keyfile=%r" % (kf_handler_write_cnt, keyfile))
debug("kf_handler_write(%s): connection=%r" % (kf_handler_write_cnt, connection))
debug(
"kf_handler_write(%s): handler-type=%r" % (kf_handler_write_cnt, handler_type)
)
debug(
"kf_handler_write(%s): handler-data=%r" % (kf_handler_write_cnt, handler_data)
)
debug("kf_handler_write(%s): user-data=%r" % (kf_handler_write_cnt, user_data))
debug("kf_handler_write(%s): kf-group=%r" % (kf_handler_write_cnt, kf_group))
debug("kf_handler_write(%s): kf-key=%r" % (kf_handler_write_cnt, kf_key))
debug("kf_handler_write(%s): kf-setting=%r" % (kf_handler_write_cnt, cur_setting))
debug("kf_handler_write(%s): kf-property=%r" % (kf_handler_write_cnt, cur_property))
if handler_type == NM.KeyfileHandlerType.WRITE_CERT:
return False
return False
try:
print("")
print("write keyfile...")
kf2 = NM.keyfile_write(c, NM.KeyfileHandlerFlags.NONE, kf_handler_write, 43)
except Exception as e:
print("write failed: %r" % (e))
raise
print("persisted again:")
print(">>\n%s\n<<" % (kf_to_string(kf2)))

View file

@ -18,6 +18,7 @@ libnm_core_headers = files(
'nm-core-types.h',
'nm-dbus-interface.h',
'nm-errors.h',
'nm-keyfile.h',
'nm-setting-6lowpan.h',
'nm-setting-8021x.h',
'nm-setting-adsl.h',
@ -234,12 +235,14 @@ libnm_libnm_core_aux_dep = declare_dependency(
link_with: libnm_libnm_core_aux,
)
nm_keyfile_source = files(
'nm-keyfile/nm-keyfile-utils.c',
'nm-keyfile/nm-keyfile.c',
)
libnm_keyfile = static_library(
'nm-keyfile',
sources: files(
'nm-keyfile/nm-keyfile-utils.c',
'nm-keyfile/nm-keyfile.c',
) + [libnm_core_enum_sources[1]],
sources: nm_keyfile_source + [libnm_core_enum_sources[1]],
dependencies: libnm_utils_base_dep,
c_args: [
'-DG_LOG_DOMAIN="@0@"'.format(libnm_name),

165
libnm-core/nm-keyfile.h Normal file
View file

@ -0,0 +1,165 @@
// SPDX-License-Identifier: LGPL-2.1+
#ifndef __NM_KEYFILE_H__
#define __NM_KEYFILE_H__
#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION)
#error "Only <NetworkManager.h> can be included directly."
#endif
#include "nm-core-types.h"
G_BEGIN_DECLS
/**
* NMKeyfileHandlerFlags:
* @NM_KEYFILE_HANDLER_FLAGS_NONE: no flags set.
*
* Flags for customizing nm_keyfile_read() and nm_keyfile_write().
*
* Currently no flags are implemented.
*
* Since: 1.30
*/
typedef enum { /*< flags >*/
NM_KEYFILE_HANDLER_FLAGS_NONE = 0,
} NMKeyfileHandlerFlags;
/**
* NMKeyfileHandlerType:
* @NM_KEYFILE_HANDLER_TYPE_WARN: a warning.
* @NM_KEYFILE_HANDLER_TYPE_WRITE_CERT: for handling certificates while writing
* a connection to keyfile.
*
* The type of the callback for %NMKeyfileReadHandler and %NMKeyfileWriteHandler.
* Depending on the type, you can interpret %NMKeyfileHandlerData.
*
* Since: 1.30
*/
typedef enum {
NM_KEYFILE_HANDLER_TYPE_WARN = 1,
NM_KEYFILE_HANDLER_TYPE_WRITE_CERT = 2,
} NMKeyfileHandlerType;
/**
* NMKeyfileHandlerData:
*
* Opaque type with parameters for the callback. The actual content
* depends on the %NMKeyfileHandlerType.
*
* Since: 1.30
*/
typedef struct _NMKeyfileHandlerData NMKeyfileHandlerData;
/**
* NMKeyfileReadHandler:
* @keyfile: the #GKeyFile that is currently read
* @connection: the #NMConnection that is being constructed.
* @handler_type: the %NMKeyfileHandlerType that indicates which type
* the request is.
* @handler_data: the #NMKeyfileHandlerData. What you can do with it
* depends on the @handler_type.
* @user_data: the user-data argument to nm_keyfile_read().
*
* Hook to nm_keyfile_read().
*
* The callee may abort the reading by setting an error via nm_keyfile_handler_data_fail_with_error().
*
* Returns: the callee should return TRUE, if the event was handled and/or recognized.
* Otherwise, a default action will be performed that depends on the @type.
* For %NM_KEYFILE_HANDLER_TYPE_WARN type, the default action is doing nothing.
*
* Since: 1.30
*/
typedef gboolean (*NMKeyfileReadHandler)(GKeyFile * keyfile,
NMConnection * connection,
NMKeyfileHandlerType handler_type,
NMKeyfileHandlerData *handler_data,
void * user_data);
NM_AVAILABLE_IN_1_30
NMConnection *nm_keyfile_read(GKeyFile * keyfile,
const char * base_dir,
NMKeyfileHandlerFlags handler_flags,
NMKeyfileReadHandler handler,
void * user_data,
GError ** error);
/**
* NMKeyfileWriteHandler:
* @connection: the #NMConnection that is currently written.
* @keyfile: the #GKeyFile that is currently constructed.
* @handler_type: the %NMKeyfileHandlerType that indicates which type
* the request is.
* @handler_data: the #NMKeyfileHandlerData. What you can do with it
* depends on the @handler_type.
* @user_data: the user-data argument to nm_keyfile_read().
*
* This is a hook to tweak the serialization.
*
* Handler for certain properties or events that are not entirely contained
* within the keyfile or that might be serialized differently. The @type and
* @handler_data arguments tell which kind of argument we have at hand.
*
* Currently only the type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT is supported.
*
* The callee may call nm_keyfile_handler_data_fail_with_error() to abort
* the writing with error.
*
* Returns: the callee should return %TRUE if the event was handled. If the
* event was unhandled, a default action will be performed that depends on
* the @handler_type.
*
* Since: 1.30
*/
typedef gboolean (*NMKeyfileWriteHandler)(NMConnection * connection,
GKeyFile * keyfile,
NMKeyfileHandlerType handler_type,
NMKeyfileHandlerData *handler_data,
void * user_data);
NM_AVAILABLE_IN_1_30
GKeyFile *nm_keyfile_write(NMConnection * connection,
NMKeyfileHandlerFlags handler_flags,
NMKeyfileWriteHandler handler,
void * user_data,
GError ** error);
/*****************************************************************************/
NM_AVAILABLE_IN_1_30
void nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src);
NM_AVAILABLE_IN_1_30
void nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data,
const char ** out_kf_group_name,
const char ** out_kf_key_name,
NMSetting ** out_cur_setting,
const char ** out_cur_property_name);
/**
* NMKeyfileWarnSeverity:
* @NM_KEYFILE_WARN_SEVERITY_DEBUG: debug message
* @NM_KEYFILE_WARN_SEVERITY_INFO: info message
* @NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE: info message about a missing file
* @NM_KEYFILE_WARN_SEVERITY_WARN: a warning message
*
* The severity level of %NM_KEYFILE_HANDLER_TYPE_WARN events.
*
* Since: 1.30
*/
typedef enum {
NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000,
NM_KEYFILE_WARN_SEVERITY_INFO = 2000,
NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901,
NM_KEYFILE_WARN_SEVERITY_WARN = 3000,
} NMKeyfileWarnSeverity;
NM_AVAILABLE_IN_1_30
void nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data,
const char ** out_message,
NMKeyfileWarnSeverity * out_severity);
G_END_DECLS
#endif /* __NM_KEYFILE_H__ */

View file

@ -13,6 +13,8 @@
#include <sys/types.h>
#include "nm-keyfile.h"
#include "nm-connection.h"
#include "nm-setting-8021x.h"
@ -31,95 +33,17 @@ char *nm_keyfile_detect_unqualified_path_scheme(const char * base_dir,
gboolean consider_exists,
gboolean * out_exists);
typedef enum { /*< flags >*/
NM_KEYFILE_HANDLER_FLAGS_NONE = 0,
} NMKeyfileHandlerFlags;
typedef enum {
NM_KEYFILE_HANDLER_TYPE_WARN = 1,
NM_KEYFILE_HANDLER_TYPE_WRITE_CERT = 2,
} NMKeyfileHandlerType;
typedef struct _NMKeyfileHandlerData NMKeyfileHandlerData;
/**
* NMKeyfileReadHandler:
*
* Hook to nm_keyfile_read(). The user might fail the reading by setting
* @error.
*
* Returns: should return TRUE, if the reading was handled. Otherwise,
* a default action will be performed that depends on the @handler_type.
* For %NM_KEYFILE_HANDLER_TYPE_WARN handler_type, the default action is doing nothing.
*/
typedef gboolean (*NMKeyfileReadHandler)(GKeyFile * keyfile,
NMConnection * connection,
NMKeyfileHandlerType handler_type,
NMKeyfileHandlerData *handler_data,
void * user_data);
typedef enum {
NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000,
NM_KEYFILE_WARN_SEVERITY_INFO = 2000,
NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901,
NM_KEYFILE_WARN_SEVERITY_WARN = 3000,
} NMKeyfileWarnSeverity;
NMConnection *nm_keyfile_read(GKeyFile * keyfile,
const char * base_dir,
NMKeyfileHandlerFlags handler_flags,
NMKeyfileReadHandler handler,
void * user_data,
GError ** error);
gboolean nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id);
gboolean nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed);
/*****************************************************************************/
/**
* NMKeyfileWriteHandler:
*
* This is a hook to tweak the serialization.
*
* Handler for certain properties or events that are not entirely contained
* within the keyfile or that might be serialized differently. The @handler_type and
* @handler_data arguments tell which kind of argument we have at hand.
*
* Currently only the handler_type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT is supported, which provides
* @handler_data as %NMKeyfileHandlerDataWriteCert. However, this handler should be generic enough
* to support other types as well.
*
* This don't have to be only "properties". For example, nm_keyfile_read() uses
* a similar handler to push warnings to the caller.
*
* If the handler raises an error, it should set the @error value. This causes
* the an overall failure.
*
* Returns: whether the issue was handled. If the type was unhandled,
* a default action will be performed. This might be raise an error,
* do some fallback parsing, or do nothing.
*/
typedef gboolean (*NMKeyfileWriteHandler)(NMConnection * connection,
GKeyFile * keyfile,
NMKeyfileHandlerType handler_type,
NMKeyfileHandlerData *handler_data,
void * user_data);
GKeyFile *nm_keyfile_write(NMConnection * connection,
NMKeyfileHandlerFlags handler_flags,
NMKeyfileWriteHandler handler,
void * user_data,
GError ** error);
/*****************************************************************************/
/**
* NMKeyfileHandlerDataWarn:
*
* this struct is passed as @handler_data for the @NMKeyfileReadHandler of
* handler_type %NM_KEYFILE_HANDLER_TYPE_WARN.
* type %NM_KEYFILE_HANDLER_TYPE_WARN.
*/
typedef struct {
NMKeyfileWarnSeverity severity;
@ -132,7 +56,7 @@ typedef struct {
* NMKeyfileHandlerDataWriteCert:
*
* this struct is passed as @handler_data for the @NMKeyfileWriteHandler of
* handler_type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT.
* type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT.
*/
typedef struct {
const NMSetting8021xSchemeVtable *vtable;
@ -157,18 +81,6 @@ struct _NMKeyfileHandlerData {
/*****************************************************************************/
void nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src);
void nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data,
const char ** out_kf_group_name,
const char ** out_kf_key_name,
NMSetting ** out_cur_setting,
const char ** out_cur_property_name);
void nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data,
const char ** out_message,
NMKeyfileWarnSeverity * out_severity);
const char *_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data);
/*****************************************************************************/

View file

@ -11,11 +11,13 @@
#include "nm-glib-aux/nm-str-buf.h"
#include "nm-keyfile-internal.h"
#include "nm-keyfile.h"
#include "nm-setting-wired.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-keyfile-internal.h"
/*****************************************************************************/
/**

View file

@ -20,11 +20,13 @@
#include "nm-glib-aux/nm-secret-utils.h"
#include "systemd/nm-sd-utils-shared.h"
#include "nm-libnm-core-intern/nm-common-macros.h"
#include "nm-core-internal.h"
#include "nm-keyfile-utils.h"
#include "nm-core-internal.h"
#include "nm-keyfile.h"
#include "nm-setting-user.h"
#include "nm-keyfile-utils.h"
/*****************************************************************************/
typedef struct _ParseInfoProperty ParseInfoProperty;
@ -3600,14 +3602,16 @@ nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_
* the relative path is made absolute using @base_dir. This must
* be an absolute path.
* @handler_flags: the #NMKeyfileHandlerFlags.
* @handler: read handler
* @handler: (allow-none) (scope call): read handler
* @user_data: user data for read handler
* @error: error
* @error: (allow-none) (out): error
*
* Tries to create a NMConnection from a keyfile. The resulting keyfile is
* not normalized and might not even verify.
*
* Returns: (transfer full): on success, returns the created connection.
*
* Since: 1.30
*/
NMConnection *
nm_keyfile_read(GKeyFile * keyfile,
@ -3946,6 +3950,19 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info)
}
}
/**
* nm_keyfile_write:
* @connection: the #NMConnection to persist to keyfile.
* @handler_flags: the #NMKeyfileHandlerFlags.
* @handler: (allow-none) (scope call): optional handler for events and
* to override the default behavior.
* @user_data: argument for @handler.
* @error: the #GError in case writing fails.
*
* Returns: (transfer full): a new #GKeyFile or %NULL on error.
*
* Since: 1.30
*/
GKeyFile *
nm_keyfile_write(NMConnection * connection,
NMKeyfileHandlerFlags handler_flags,
@ -4211,6 +4228,8 @@ nm_keyfile_utils_create_filename(const char *name, gboolean with_extension)
* Note that @src is no longer valid after this call. If you want
* to keep using the same GError*, you need to set it to %NULL
* after calling this function on it.
*
* Since: 1.30
*/
void
nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src)
@ -4235,6 +4254,8 @@ nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GErr
*
* Get context information of the current event. This function can be called
* on all events, but the context information may be unset.
*
* Since: 1.30
*/
void
nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data,
@ -4276,6 +4297,8 @@ _nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_da
* event.
* @out_message: (out) (allow-none) (transfer none): the warning message.
* @out_severity: (out) (allow-none): the #NMKeyfileWarnSeverity warning severity.
*
* Since: 1.30
*/
void
nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data,

View file

@ -45,6 +45,7 @@
#include "nm-dhcp-config.h"
#include "nm-enum-types.h"
#include "nm-ip-config.h"
#include "nm-keyfile.h"
#include "nm-object.h"
#include "nm-remote-connection.h"
#include "nm-setting-6lowpan.h"

View file

@ -1755,3 +1755,15 @@ global:
nm_setting_ip_config_remove_dhcp_reject_server;
nm_setting_wireless_get_ap_isolation;
} libnm_1_26_4;
libnm_1_30_0 {
global:
nm_keyfile_handler_data_fail_with_error;
nm_keyfile_handler_data_get_context;
nm_keyfile_handler_data_warn_get;
nm_keyfile_handler_flags_get_type;
nm_keyfile_handler_type_get_type;
nm_keyfile_read;
nm_keyfile_warn_severity_get_type;
nm_keyfile_write;
} libnm_1_28_0;

View file

@ -138,6 +138,7 @@ deps = [
libnmdbus_dep,
libnm_libnm_core_intern_dep,
libnm_nm_default_dep,
libnm_keyfile_dep,
libnm_udev_aux_dep,
libudev_dep,
]
@ -153,6 +154,7 @@ liblibnm = static_library(
links = [
liblibnm,
libnm_core,
libnm_keyfile,
libnmdbus,
libnm_systemd_logging_stub,
libnm_utils_base,
@ -200,7 +202,7 @@ if enable_introspection
libnm_gir = gnome.generate_gir(
libnm,
sources: libnm_core_sources + libnm_core_headers + libnm_core_enum_sources + libnm_sources + libnm_headers + libnm_enum_sources + [nm_version_macro_header],
sources: libnm_core_sources + nm_keyfile_source + libnm_core_headers + libnm_core_enum_sources + libnm_sources + libnm_headers + libnm_enum_sources + [nm_version_macro_header],
includes: 'Gio-2.0',
nsversion: nm_gir_version,
namespace: 'NM',