mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 09:20:04 +01:00
Add a new public function nm_utils_copy_cert_as_user() to libnm. It reads a certificate or key file on behalf of the given user and writes it to a directory in /run/NetworkManager. It is useful for VPN plugins that run as root and need to verify that the user owning the connection (the one listed in the connection.permissions property) can access the file. (cherry picked from commit1a52bbe7c9) (cherry picked from commit3d85bace3d) (cherry picked from commit4587832735)
149 lines
4.5 KiB
Python
Executable file
149 lines
4.5 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
#
|
|
# Copyright (C) 2022 Red Hat, Inc.
|
|
#
|
|
|
|
from __future__ import print_function
|
|
import xml.etree.ElementTree as ET
|
|
import argparse
|
|
import re
|
|
import sys
|
|
|
|
C_NS = "http://www.gtk.org/introspection/c/1.0"
|
|
CORE_NS = "http://www.gtk.org/introspection/core/1.0"
|
|
GLIB_NS = "http://www.gtk.org/introspection/glib/1.0"
|
|
|
|
|
|
def syms_from_gir(girfile):
|
|
def xml_symbols(xml, types):
|
|
ret = []
|
|
for t in types:
|
|
ret += xml.findall("./{%s}namespace/{%s}%s" % (CORE_NS, CORE_NS, t))
|
|
ret += xml.findall("./{%s}namespace/*/{%s}%s" % (CORE_NS, CORE_NS, t))
|
|
return ret
|
|
|
|
girxml = ET.parse(girfile)
|
|
c_syms = {}
|
|
for sym in xml_symbols(girxml, ("constructor", "function", "method")):
|
|
c_syms[sym.get("{%s}identifier" % C_NS)] = sym.get("version")
|
|
|
|
for sym in xml_symbols(
|
|
girxml, ("bitfield", "class", "enumeration", "interface", "record")
|
|
):
|
|
get_type = sym.get("{%s}get-type" % GLIB_NS)
|
|
if get_type is None:
|
|
continue
|
|
version = sym.get("version")
|
|
|
|
if version is None:
|
|
# FIXME: The get_type() functions should be exported in the same
|
|
# version the type itself appeared. However, a large number of
|
|
# classes lack Since: tags in their doc blocks. Fall back to using
|
|
# the tag on _new() method for the test to be able to proceed
|
|
# reasonably. This should be fixed eventually.
|
|
constructor = sym.find("./{%s}constructor" % CORE_NS)
|
|
if constructor is not None:
|
|
version = constructor.get("version")
|
|
|
|
c_syms[get_type] = version
|
|
return c_syms
|
|
|
|
|
|
# Older Python doesn't have str.removesuffix()
|
|
def str_removesuffix(string, suffix):
|
|
try:
|
|
return string.removesuffix(suffix)
|
|
except AttributeError:
|
|
if string.endswith(suffix):
|
|
return string[: -len(suffix)]
|
|
else:
|
|
return string
|
|
|
|
|
|
def syms_from_ver(verfile):
|
|
c_syms = {}
|
|
for line in open(verfile).readlines():
|
|
line = line.strip()
|
|
|
|
if line.endswith("{"):
|
|
line = str_removesuffix(line, " {")
|
|
m = re.search(r"^libnm_([0-9]+)_([0-9]+)_([0-9]+)$", line)
|
|
if not m:
|
|
continue
|
|
(major, minor, micro) = m.groups()
|
|
if int(major) > 1 or int(minor) > 0:
|
|
if int(micro) > 0:
|
|
# Snap to next major version. Perhaps not
|
|
# exactly correct, but good for all symbols
|
|
# we export but nm_ethtool_optname_is_feature().
|
|
minor = str(int(minor) + 2)
|
|
version = major + "." + minor
|
|
else:
|
|
version = None
|
|
elif (
|
|
line.endswith(";")
|
|
and not line.startswith("}")
|
|
and not line.startswith("#")
|
|
and not line == "*;"
|
|
):
|
|
c_syms[str_removesuffix(line, ";")] = version
|
|
|
|
# These are exceptions and we cannot know the version for the symbol so we
|
|
# hardcode it.
|
|
c_syms["nm_ethtool_optname_is_feature"] = "1.20"
|
|
c_syms["nm_setting_bond_port_get_prio"] = "1.44"
|
|
c_syms["nm_utils_copy_cert_as_user"] = "1.56"
|
|
c_syms["nm_vpn_plugin_info_supports_safe_private_file_access"] = "1.56"
|
|
|
|
return c_syms
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"--gir",
|
|
metavar="FILE",
|
|
help="NM-1.0.gir file",
|
|
required=True,
|
|
)
|
|
parser.add_argument(
|
|
"--ver",
|
|
metavar="FILE",
|
|
help="libnm.ver file",
|
|
required=True,
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
gir_syms = syms_from_gir(args.gir)
|
|
ver_syms = syms_from_ver(args.ver)
|
|
|
|
exit_code = 0
|
|
|
|
for gir_sym, gir_ver in gir_syms.items():
|
|
if gir_sym not in ver_syms:
|
|
exit_code = 1
|
|
print(
|
|
'FAIL: "%s" found in "%s", but is not exported. Needs adding to "%s"?'
|
|
% (gir_sym, args.gir, args.ver),
|
|
file=sys.stderr,
|
|
)
|
|
continue
|
|
if gir_ver != ver_syms[gir_sym]:
|
|
exit_code = 1
|
|
print(
|
|
'FAIL: "%s" exported in version "%s" but documented as available since "%s"'
|
|
% (gir_sym, ver_syms[gir_sym], gir_ver),
|
|
file=sys.stderr,
|
|
)
|
|
|
|
# In python2, dict.keys() returns lists, not sets. Cast them.
|
|
for sym in set(ver_syms.keys()) - set(gir_syms.keys()):
|
|
exit_code = 1
|
|
print(
|
|
'FAIL: "%s" found in "%s", but not in "%s". Maybe the doc comment is wrong or g-ir-scanner messed up?'
|
|
% (sym, args.ver, args.gir),
|
|
file=sys.stderr,
|
|
)
|
|
|
|
sys.exit(exit_code)
|